diff --git a/.gitignore b/.gitignore index 0dbb4e9..097f085 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ __pycache__/ sim_build/ outflow/ -work*/ \ No newline at end of file +work*/ + +.lock \ No newline at end of file diff --git a/Ti375C529_devkit/.lock b/Ti375C529_devkit/.lock deleted file mode 100644 index 9518eff..0000000 --- a/Ti375C529_devkit/.lock +++ /dev/null @@ -1 +0,0 @@ -4176154 diff --git a/Ti375C529_devkit/EfxSapphireHpSoc_bootloader/default_bootloader.hex b/Ti375C529_devkit/EfxSapphireHpSoc_bootloader/default_bootloader.hex deleted file mode 100644 index 85ba367..0000000 --- a/Ti375C529_devkit/EfxSapphireHpSoc_bootloader/default_bootloader.hex +++ /dev/null @@ -1,50 +0,0 @@ -:02000004F90001 -:1000000097110000938181AC23A00182732540F1F8 -:1000100015C503A5018275DD0F0020020F10000039 -:1000200083A7C181014581450146828723AEA18016 -:100030000F001001054523A0A182828013818192C7 -:1000400013850181938501811386C18163FAC500FF -:100050008322050023A0550011059105E3EAC5FEA2 -:100060001385C181938581826377B50023200500C4 -:0E0070001105E36DB5FEDD2A192001A0828086 -:10007E00B70701E81307E01098C7B70701E81D4757 -:10008E00D8C771A8B70603E8416791067D179C4251 -:10009E00F98FF5DF856793870780370703E81CC361 -:1000AE008280B70603E8416791067D179C42F98F5F -:1000BE00F5DF13070020B70703E898C3370703E8F7 -:1000CE0011071C43C183F5DFB70703E88843137597 -:1000DE00F50F8280B70603E8416791067D179C42B3 -:1000EE00F98FF5DF13650510B70703E888C3828023 -:1000FE00B7C7B0F8E11794439386A60F984333879A -:10010E00E640E35D07FEB70603E8416791067D17FB -:10011E00130600109C42F98FE39EC7FE82804111A8 -:10012E0006C622C426C2B70703E823A40700094760 -:10013E00B70703E898D39546B70703E8D4D3B707B4 -:10014E0003E898D71D47B70703E8D8D755371D3FA3 -:10015E00B70603E8416791067D179C42F98FF5DFDC -:10016E00856793870788370703E81CC31305B00A12 -:10017E009537093FB53FB7C7B0F8E11794431967F4 -:10018E001307871ABA9698433387E640E35D07FE56 -:10019E00B70603E8416791067D179C42F98FF5DF9C -:1001AE00856793870788370703E81CC31305F00993 -:1001BE001537C53DB7C7B0F8E11794434967130724 -:1001CE00874F2A84BA9698433387E640E35D07FE4D -:1001DE00553D393FB70603E8416791067D179C42AE -:1001EE00F98FF5DF856793870788370703E81CC308 -:1001FE009307D009130590026304F4001305900EC3 -:10020E00D13D4935F535B70603E8416791067D17AF -:10021E009C42F98FF5DF856793870788370703E8D8 -:10022E001CC32D45453D130500046D3501455D3557 -:10023E0001454D350145793D0564B70402009535FC -:10024E00A2872380A7000504E31B94FE253D0565C8 -:10025E00F9332244B24092448567410182874111AD -:10026E0022C44AC097070000938747061704000070 -:10027E001304C40506C626C233898740638B8700E4 -:10028E001359294081441C40850411048297E3ECE4 -:10029E0024FF9707000093876703170400001304D9 -:1002AE00E4023389874013592940638987008144CA -:1002BE001C40850411048297E3EC24FFB2402244D3 -:0802CE009244024941018280C3 -:0C02D6000000000000000000000000001C -:04000005F9000000FE -:00000001FF diff --git a/Ti375C529_devkit/EfxSapphireHpSoc_slb.v b/Ti375C529_devkit/EfxSapphireHpSoc_slb.v new file mode 100644 index 0000000..f9c5dba --- /dev/null +++ b/Ti375C529_devkit/EfxSapphireHpSoc_slb.v @@ -0,0 +1,4972 @@ +// ============================================================================= +// Generated by efx_ipmgr +// Version: 2025.2.288.2.10 +// IP Version: 1.22.0 +// ============================================================================= + +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +//////////////////////////////////////////////////////////////////////////////// + +`define IP_UUID _86b7e1c47b934a8a97a62bda8ee6a75d +`define IP_NAME_CONCAT(a,b) a``b +`define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) +module EfxSapphireHpSoc_slb +( + input io_peripheralClk, + input io_peripheralReset, + output io_asyncReset, + input io_gpio_sw_n, + input pll_peripheral_locked, + input pll_system_locked, + output jtagCtrl_capture, + output jtagCtrl_enable, + output jtagCtrl_reset, + output jtagCtrl_shift, + output jtagCtrl_tdi, + input jtagCtrl_tdo, + output jtagCtrl_update, + input ut_jtagCtrl_capture, + input ut_jtagCtrl_enable, + input ut_jtagCtrl_reset, + input ut_jtagCtrl_shift, + input ut_jtagCtrl_tdi, + output ut_jtagCtrl_tdo, + input ut_jtagCtrl_update, + input system_spi_0_io_data_0_read, + output system_spi_0_io_data_0_write, + output system_spi_0_io_data_0_writeEnable, + input system_spi_0_io_data_1_read, + output system_spi_0_io_data_1_write, + output system_spi_0_io_data_1_writeEnable, + input system_spi_0_io_data_2_read, + output system_spi_0_io_data_2_write, + output system_spi_0_io_data_2_writeEnable, + input system_spi_0_io_data_3_read, + output system_spi_0_io_data_3_write, + output system_spi_0_io_data_3_writeEnable, + output system_spi_0_io_sclk_write, + output [3:0] system_spi_0_io_ss, + input system_uart_0_io_rxd, + output system_uart_0_io_txd, + input cfg_done, + output cfg_start, + output cfg_sel, + output cfg_reset, + output axiAInterrupt, + input [31:0] axiA_awaddr, + input [7:0] axiA_awlen, + input [2:0] axiA_awsize, + input [1:0] axiA_awburst, + input axiA_awlock, + input [3:0] axiA_awcache, + input [2:0] axiA_awprot, + input [3:0] axiA_awqos, + input [3:0] axiA_awregion, + input axiA_awvalid, + output axiA_awready, + input [31:0] axiA_wdata, + input [3:0] axiA_wstrb, + input axiA_wvalid, + input axiA_wlast, + output axiA_wready, + output [1:0] axiA_bresp, + output axiA_bvalid, + input axiA_bready, + input [31:0] axiA_araddr, + input [7:0] axiA_arlen, + input [2:0] axiA_arsize, + input [1:0] axiA_arburst, + input axiA_arlock, + input [3:0] axiA_arcache, + input [2:0] axiA_arprot, + input [3:0] axiA_arqos, + input [3:0] axiA_arregion, + input axiA_arvalid, + output axiA_arready, + output [31:0] axiA_rdata, + output [1:0] axiA_rresp, + output axiA_rlast, + output axiA_rvalid, + input axiA_rready, + output userInterruptA, + output userInterruptB +); +`IP_MODULE_NAME(Axi4Peripheral_wrapper) +#( + .PERI_FREQ (250) +) +u_Axi4Peripheral_wrapper +( + .io_peripheralClk ( io_peripheralClk ), + .io_peripheralReset ( io_peripheralReset ), + .io_asyncReset ( io_asyncReset ), + .io_gpio_sw_n ( io_gpio_sw_n ), + .pll_peripheral_locked ( pll_peripheral_locked ), + .pll_system_locked ( pll_system_locked ), + .jtagCtrl_capture ( jtagCtrl_capture ), + .jtagCtrl_enable ( jtagCtrl_enable ), + .jtagCtrl_reset ( jtagCtrl_reset ), + .jtagCtrl_shift ( jtagCtrl_shift ), + .jtagCtrl_tdi ( jtagCtrl_tdi ), + .jtagCtrl_tdo ( jtagCtrl_tdo ), + .jtagCtrl_update ( jtagCtrl_update ), + .ut_jtagCtrl_capture ( ut_jtagCtrl_capture ), + .ut_jtagCtrl_enable ( ut_jtagCtrl_enable ), + .ut_jtagCtrl_reset ( ut_jtagCtrl_reset ), + .ut_jtagCtrl_shift ( ut_jtagCtrl_shift ), + .ut_jtagCtrl_tdi ( ut_jtagCtrl_tdi ), + .ut_jtagCtrl_tdo ( ut_jtagCtrl_tdo ), + .ut_jtagCtrl_update ( ut_jtagCtrl_update ), + .system_spi_0_io_data_0_read ( system_spi_0_io_data_0_read ), + .system_spi_0_io_data_0_write ( system_spi_0_io_data_0_write ), + .system_spi_0_io_data_0_writeEnable ( system_spi_0_io_data_0_writeEnable ), + .system_spi_0_io_data_1_read ( system_spi_0_io_data_1_read ), + .system_spi_0_io_data_1_write ( system_spi_0_io_data_1_write ), + .system_spi_0_io_data_1_writeEnable ( system_spi_0_io_data_1_writeEnable ), + .system_spi_0_io_data_2_read ( system_spi_0_io_data_2_read ), + .system_spi_0_io_data_2_write ( system_spi_0_io_data_2_write ), + .system_spi_0_io_data_2_writeEnable ( system_spi_0_io_data_2_writeEnable ), + .system_spi_0_io_data_3_read ( system_spi_0_io_data_3_read ), + .system_spi_0_io_data_3_write ( system_spi_0_io_data_3_write ), + .system_spi_0_io_data_3_writeEnable ( system_spi_0_io_data_3_writeEnable ), + .system_spi_0_io_sclk_write ( system_spi_0_io_sclk_write ), + .system_spi_0_io_ss ( system_spi_0_io_ss ), + .system_uart_0_io_rxd ( system_uart_0_io_rxd ), + .system_uart_0_io_txd ( system_uart_0_io_txd ), + .cfg_done ( cfg_done ), + .cfg_start ( cfg_start ), + .cfg_sel ( cfg_sel ), + .cfg_reset ( cfg_reset ), + .axiAInterrupt ( axiAInterrupt ), + .axiA_awaddr ( axiA_awaddr ), + .axiA_awlen ( axiA_awlen ), + .axiA_awsize ( axiA_awsize ), + .axiA_awburst ( axiA_awburst ), + .axiA_awlock ( axiA_awlock ), + .axiA_awcache ( axiA_awcache ), + .axiA_awprot ( axiA_awprot ), + .axiA_awqos ( axiA_awqos ), + .axiA_awregion ( axiA_awregion ), + .axiA_awvalid ( axiA_awvalid ), + .axiA_awready ( axiA_awready ), + .axiA_wdata ( axiA_wdata ), + .axiA_wstrb ( axiA_wstrb ), + .axiA_wvalid ( axiA_wvalid ), + .axiA_wlast ( axiA_wlast ), + .axiA_wready ( axiA_wready ), + .axiA_bresp ( axiA_bresp ), + .axiA_bvalid ( axiA_bvalid ), + .axiA_bready ( axiA_bready ), + .axiA_araddr ( axiA_araddr ), + .axiA_arlen ( axiA_arlen ), + .axiA_arsize ( axiA_arsize ), + .axiA_arburst ( axiA_arburst ), + .axiA_arlock ( axiA_arlock ), + .axiA_arcache ( axiA_arcache ), + .axiA_arprot ( axiA_arprot ), + .axiA_arqos ( axiA_arqos ), + .axiA_arregion ( axiA_arregion ), + .axiA_arvalid ( axiA_arvalid ), + .axiA_arready ( axiA_arready ), + .axiA_rdata ( axiA_rdata ), + .axiA_rresp ( axiA_rresp ), + .axiA_rlast ( axiA_rlast ), + .axiA_rvalid ( axiA_rvalid ), + .axiA_rready ( axiA_rready ), + .userInterruptA ( userInterruptA ), + .userInterruptB ( userInterruptB ) +); +endmodule + +module `IP_MODULE_NAME(Axi4Peripheral_wrapper) #( +parameter PERI_FREQ=250 +)( +output system_spi_0_io_sclk_write, +output system_spi_0_io_data_0_writeEnable, +input system_spi_0_io_data_0_read, +output system_spi_0_io_data_0_write, +output system_spi_0_io_data_1_writeEnable, +input system_spi_0_io_data_1_read, +output system_spi_0_io_data_1_write, +output system_spi_0_io_data_2_writeEnable, +input system_spi_0_io_data_2_read, +output system_spi_0_io_data_2_write, +output system_spi_0_io_data_3_writeEnable, +input system_spi_0_io_data_3_read, +output system_spi_0_io_data_3_write, +output [3:0] system_spi_0_io_ss, +output userInterruptB, +output jtagCtrl_tdi, +input jtagCtrl_tdo, +output jtagCtrl_enable, +output jtagCtrl_capture, +output jtagCtrl_shift, +output jtagCtrl_update, +output jtagCtrl_reset, +input ut_jtagCtrl_tdi, +output ut_jtagCtrl_tdo, +input ut_jtagCtrl_enable, +input ut_jtagCtrl_capture, +input ut_jtagCtrl_shift, +input ut_jtagCtrl_update, +input ut_jtagCtrl_reset, +output userInterruptA, +output system_uart_0_io_txd, +input system_uart_0_io_rxd, +input [31:0] axiA_awaddr, +input [7:0] axiA_awlen, +input [2:0] axiA_awsize, +input [1:0] axiA_awburst, +input axiA_awlock, +input [3:0] axiA_awcache, +input [2:0] axiA_awprot, +input [3:0] axiA_awqos, +input [3:0] axiA_awregion, +input axiA_awvalid, +output axiA_awready, +input [31:0] axiA_wdata, +input [3:0] axiA_wstrb, +input axiA_wvalid, +input axiA_wlast, +output axiA_wready, +output [1:0] axiA_bresp, +output axiA_bvalid, +input axiA_bready, +input [31:0] axiA_araddr, +input [7:0] axiA_arlen, +input [2:0] axiA_arsize, +input [1:0] axiA_arburst, +input axiA_arlock, +input [3:0] axiA_arcache, +input [2:0] axiA_arprot, +input [3:0] axiA_arqos, +input [3:0] axiA_arregion, +input axiA_arvalid, +output axiA_arready, +output [31:0] axiA_rdata, +output [1:0] axiA_rresp, +output axiA_rlast, +output axiA_rvalid, +input axiA_rready, +output axiAInterrupt, +input cfg_done, +output cfg_start, +output cfg_sel, +output cfg_reset, +input io_peripheralClk, +input io_peripheralReset, +output io_asyncReset, +input io_gpio_sw_n, +input pll_peripheral_locked, +input pll_system_locked +); + +wire flag_ok; +wire system_spi_0_io_interrupt; +wire system_uart_0_io_interrupt; + + +`IP_MODULE_NAME(lppdr4_init) u_lppdr4_init ( +.io_peripheralClk (io_peripheralClk), +.io_peripheralReset (io_peripheralReset), +.io_gpio_sw_n (io_gpio_sw_n), +.flag_ok (flag_ok), +.cfg_done (cfg_done), +.cfg_start (cfg_start), +.cfg_sel (cfg_sel), +.cfg_reset (cfg_reset) +); + +assign io_asyncReset = ~(io_gpio_sw_n & + pll_peripheral_locked & + pll_system_locked & + flag_ok); + +assign userInterruptA = system_uart_0_io_interrupt; +assign userInterruptB = system_spi_0_io_interrupt; + +assign jtagCtrl_capture = ut_jtagCtrl_capture; +assign jtagCtrl_enable = ut_jtagCtrl_enable; +assign jtagCtrl_reset = ut_jtagCtrl_reset; +assign jtagCtrl_shift = ut_jtagCtrl_shift; +assign jtagCtrl_tdi = ut_jtagCtrl_tdi; +assign jtagCtrl_update = ut_jtagCtrl_update; +assign ut_jtagCtrl_tdo = jtagCtrl_tdo; + + + + +//axi4 bridge to various I/O +Axi4PeripheralTop_86b7e1c47b934a8a97a62bda8ee6a75d u_Axi4PeripheralTop( +.system_spi_0_io_interrupt(system_spi_0_io_interrupt), +.system_spi_0_io_sclk_write(system_spi_0_io_sclk_write), +.system_spi_0_io_data_0_writeEnable(system_spi_0_io_data_0_writeEnable), +.system_spi_0_io_data_0_read(system_spi_0_io_data_0_read), +.system_spi_0_io_data_0_write(system_spi_0_io_data_0_write), +.system_spi_0_io_data_1_writeEnable(system_spi_0_io_data_1_writeEnable), +.system_spi_0_io_data_1_read(system_spi_0_io_data_1_read), +.system_spi_0_io_data_1_write(system_spi_0_io_data_1_write), +.system_spi_0_io_data_2_writeEnable(system_spi_0_io_data_2_writeEnable), +.system_spi_0_io_data_2_read(system_spi_0_io_data_2_read), +.system_spi_0_io_data_2_write(system_spi_0_io_data_2_write), +.system_spi_0_io_data_3_writeEnable(system_spi_0_io_data_3_writeEnable), +.system_spi_0_io_data_3_read(system_spi_0_io_data_3_read), +.system_spi_0_io_data_3_write(system_spi_0_io_data_3_write), +.system_spi_0_io_ss(system_spi_0_io_ss), +.system_uart_0_io_interrupt(system_uart_0_io_interrupt), +.system_uart_0_io_txd(system_uart_0_io_txd), +.system_uart_0_io_rxd(system_uart_0_io_rxd), +.axi_awvalid(axiA_awvalid), +.axi_awready(axiA_awready), +.axi_awaddr(axiA_awaddr[23:0]), +.axi_awlen(axiA_awlen), +.axi_awsize(axiA_awsize), +.axi_awcache(axiA_awcache), +.axi_awprot(axiA_awprot), +.axi_wvalid(axiA_wvalid), +.axi_wready(axiA_wready), +.axi_wdata(axiA_wdata), +.axi_wstrb(axiA_wstrb), +.axi_wlast(axiA_wlast), +.axi_bvalid(axiA_bvalid), +.axi_bready(axiA_bready), +.axi_bresp(axiA_bresp), +.axi_arvalid(axiA_arvalid), +.axi_arready(axiA_arready), +.axi_araddr(axiA_araddr[23:0]), +.axi_arlen(axiA_arlen), +.axi_arsize(axiA_arsize), +.axi_arcache(axiA_arcache), +.axi_arprot(axiA_arprot), +.axi_rvalid(axiA_rvalid), +.axi_rready(axiA_rready), +.axi_rdata(axiA_rdata), +.axi_rresp(axiA_rresp), +.axi_rlast(axiA_rlast), +.clk(io_peripheralClk), +.reset(io_peripheralReset) +); +assign axiAInterrupt = 1'b0; + +endmodule + + +module `IP_MODULE_NAME(lppdr4_init) ( + input io_peripheralClk, + input io_peripheralReset, + input io_gpio_sw_n, + output reg flag_ok, + input cfg_done, + output cfg_start, + output cfg_sel, + output cfg_reset +); + +localparam [1:0] IDLE = 2'b00, + CFG_START = 2'b01, + CFG_DONE = 2'b11; + +reg [1:0] cfg_st, + cfg_next; +reg [7:0] cfg_count; +wire cfg_ok; +reg [1:0] buf_reset; +wire dmReset; + +always@(posedge io_peripheralClk) +begin + buf_reset[1] <= io_peripheralReset; + buf_reset[0] <= buf_reset[1]; +end + +assign dmReset = (~buf_reset[0] & buf_reset[1]); + +always@(posedge io_peripheralClk or negedge io_gpio_sw_n) +begin + if(!io_gpio_sw_n) + flag_ok <= 1'b0; + else + begin + if(cfg_st == CFG_DONE) + flag_ok <= 1'b1; + else + flag_ok <= flag_ok; + end +end + +always@(posedge io_peripheralClk or negedge io_gpio_sw_n) +begin + if(!io_gpio_sw_n || dmReset) + cfg_st <= IDLE; + else + cfg_st <= cfg_next; +end + +always@(*) +begin + cfg_next = cfg_st; + case(cfg_st) + IDLE: + begin + if(cfg_count == 'hff) + cfg_next = CFG_START; + else + cfg_next = IDLE; + end + CFG_START: + begin + if(cfg_done) + cfg_next = CFG_DONE; + else + cfg_next = CFG_START; + end + CFG_DONE: + cfg_next = CFG_DONE; + default: + cfg_next = IDLE; + endcase +end + +assign cfg_start = (cfg_st != IDLE); +assign cfg_ok = (cfg_st == CFG_DONE); +assign cfg_reset = (cfg_st == IDLE); +assign cfg_sel = 1'b0; + +always@(posedge io_peripheralClk) +begin + if(cfg_st == IDLE) + cfg_count <= cfg_count + 1'b1; + else + cfg_count <= 'h0; +end + +endmodule + + +// Generator : SpinalHDL dev git head : a69f4b9a329be784802c37cd8038b7dc9aec3094 +// Component : Axi4PeripheralTop_86b7e1c47b934a8a97a62bda8ee6a75d + +`timescale 1ns/1ps + +module Axi4PeripheralTop_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire axi_awvalid, + output wire axi_awready, + input wire [23:0] axi_awaddr, + input wire [7:0] axi_awlen, + input wire [2:0] axi_awsize, + input wire [3:0] axi_awcache, + input wire [2:0] axi_awprot, + input wire axi_wvalid, + output wire axi_wready, + input wire [31:0] axi_wdata, + input wire [3:0] axi_wstrb, + input wire axi_wlast, + output wire axi_bvalid, + input wire axi_bready, + output wire [1:0] axi_bresp, + input wire axi_arvalid, + output wire axi_arready, + input wire [23:0] axi_araddr, + input wire [7:0] axi_arlen, + input wire [2:0] axi_arsize, + input wire [3:0] axi_arcache, + input wire [2:0] axi_arprot, + output wire axi_rvalid, + input wire axi_rready, + output wire [31:0] axi_rdata, + output wire [1:0] axi_rresp, + output wire axi_rlast, + output wire system_uart_0_io_txd, + input wire system_uart_0_io_rxd, + output wire system_uart_0_io_interrupt, + output wire system_spi_0_io_interrupt, + output wire [0:0] system_spi_0_io_sclk_write, + output wire system_spi_0_io_data_0_writeEnable, + input wire [0:0] system_spi_0_io_data_0_read, + output wire [0:0] system_spi_0_io_data_0_write, + output wire system_spi_0_io_data_1_writeEnable, + input wire [0:0] system_spi_0_io_data_1_read, + output wire [0:0] system_spi_0_io_data_1_write, + output wire system_spi_0_io_data_2_writeEnable, + input wire [0:0] system_spi_0_io_data_2_read, + output wire [0:0] system_spi_0_io_data_2_write, + output wire system_spi_0_io_data_3_writeEnable, + input wire [0:0] system_spi_0_io_data_3_read, + output wire [0:0] system_spi_0_io_data_3_write, + output wire [3:0] system_spi_0_io_ss, + input wire clk, + input wire reset +); + + wire streamArbiter_io_inputs_0_ready; + wire streamArbiter_io_inputs_1_ready; + wire streamArbiter_io_output_valid; + wire [23:0] streamArbiter_io_output_payload_addr; + wire [7:0] streamArbiter_io_output_payload_len; + wire [2:0] streamArbiter_io_output_payload_size; + wire [3:0] streamArbiter_io_output_payload_cache; + wire [2:0] streamArbiter_io_output_payload_prot; + wire [0:0] streamArbiter_io_chosen; + wire [1:0] streamArbiter_io_chosenOH; + wire axiToBmb_io_axi_arw_ready; + wire axiToBmb_io_axi_w_ready; + wire axiToBmb_io_axi_b_valid; + wire [1:0] axiToBmb_io_axi_b_payload_resp; + wire axiToBmb_io_axi_r_valid; + wire [31:0] axiToBmb_io_axi_r_payload_data; + wire [1:0] axiToBmb_io_axi_r_payload_resp; + wire axiToBmb_io_axi_r_payload_last; + wire axiToBmb_io_bmb_cmd_valid; + wire axiToBmb_io_bmb_cmd_payload_last; + wire [0:0] axiToBmb_io_bmb_cmd_payload_fragment_source; + wire [0:0] axiToBmb_io_bmb_cmd_payload_fragment_opcode; + wire [23:0] axiToBmb_io_bmb_cmd_payload_fragment_address; + wire [9:0] axiToBmb_io_bmb_cmd_payload_fragment_length; + wire [31:0] axiToBmb_io_bmb_cmd_payload_fragment_data; + wire [3:0] axiToBmb_io_bmb_cmd_payload_fragment_mask; + wire axiToBmb_io_bmb_rsp_ready; + wire bmbHandle_decoder_io_input_cmd_ready; + wire bmbHandle_decoder_io_input_rsp_valid; + wire bmbHandle_decoder_io_input_rsp_payload_last; + wire [0:0] bmbHandle_decoder_io_input_rsp_payload_fragment_source; + wire [0:0] bmbHandle_decoder_io_input_rsp_payload_fragment_opcode; + wire [31:0] bmbHandle_decoder_io_input_rsp_payload_fragment_data; + wire bmbHandle_decoder_io_outputs_0_cmd_valid; + wire bmbHandle_decoder_io_outputs_0_cmd_payload_last; + wire [0:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_source; + wire [0:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_opcode; + wire [23:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_address; + wire [9:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_length; + wire [31:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_data; + wire [3:0] bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_mask; + wire bmbHandle_decoder_io_outputs_0_rsp_ready; + wire bmbHandle_unburstify_io_input_cmd_ready; + wire bmbHandle_unburstify_io_input_rsp_valid; + wire bmbHandle_unburstify_io_input_rsp_payload_last; + wire [0:0] bmbHandle_unburstify_io_input_rsp_payload_fragment_source; + wire [0:0] bmbHandle_unburstify_io_input_rsp_payload_fragment_opcode; + wire [31:0] bmbHandle_unburstify_io_input_rsp_payload_fragment_data; + wire bmbHandle_unburstify_io_output_cmd_valid; + wire bmbHandle_unburstify_io_output_cmd_payload_last; + wire [0:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_opcode; + wire [23:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_address; + wire [1:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_length; + wire [31:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_data; + wire [3:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_mask; + wire [2:0] bmbHandle_unburstify_io_output_cmd_payload_fragment_context; + wire bmbHandle_unburstify_io_output_rsp_ready; + wire bmbPeripheral_bmb_decoder_io_input_cmd_ready; + wire bmbPeripheral_bmb_decoder_io_input_rsp_valid; + wire bmbPeripheral_bmb_decoder_io_input_rsp_payload_last; + wire [0:0] bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_opcode; + wire [31:0] bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_data; + wire [2:0] bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_context; + wire bmbPeripheral_bmb_decoder_io_outputs_0_cmd_valid; + wire bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_last; + wire [0:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_opcode; + wire [23:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_address; + wire [1:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_length; + wire [31:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_data; + wire [3:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_mask; + wire [2:0] bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_context; + wire bmbPeripheral_bmb_decoder_io_outputs_0_rsp_ready; + wire bmbPeripheral_bmb_decoder_io_outputs_1_cmd_valid; + wire bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_last; + wire [0:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_opcode; + wire [23:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_address; + wire [1:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_length; + wire [31:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_data; + wire [3:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_mask; + wire [2:0] bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_context; + wire bmbPeripheral_bmb_decoder_io_outputs_1_rsp_ready; + wire system_uart_0_io_logic_io_bus_cmd_ready; + wire system_uart_0_io_logic_io_bus_rsp_valid; + wire system_uart_0_io_logic_io_bus_rsp_payload_last; + wire [0:0] system_uart_0_io_logic_io_bus_rsp_payload_fragment_opcode; + wire [31:0] system_uart_0_io_logic_io_bus_rsp_payload_fragment_data; + wire [2:0] system_uart_0_io_logic_io_bus_rsp_payload_fragment_context; + wire system_uart_0_io_logic_io_uart_txd; + wire system_uart_0_io_logic_system_uart_0_io_interrupt_source; + wire system_spi_0_io_logic_io_ctrl_cmd_ready; + wire system_spi_0_io_logic_io_ctrl_rsp_valid; + wire system_spi_0_io_logic_io_ctrl_rsp_payload_last; + wire [0:0] system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_opcode; + wire [31:0] system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_data; + wire [2:0] system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_context; + wire [0:0] system_spi_0_io_logic_io_spi_sclk_write; + wire [3:0] system_spi_0_io_logic_io_spi_ss; + wire [0:0] system_spi_0_io_logic_io_spi_data_0_write; + wire system_spi_0_io_logic_io_spi_data_0_writeEnable; + wire [0:0] system_spi_0_io_logic_io_spi_data_1_write; + wire system_spi_0_io_logic_io_spi_data_1_writeEnable; + wire [0:0] system_spi_0_io_logic_io_spi_data_2_write; + wire system_spi_0_io_logic_io_spi_data_2_writeEnable; + wire [0:0] system_spi_0_io_logic_io_spi_data_3_write; + wire system_spi_0_io_logic_io_spi_data_3_writeEnable; + wire system_spi_0_io_logic_system_spi_0_io_interrupt_source; + wire _zz_axiShared_b_ready; + wire _zz_axiShared_r_ready; + wire axi_aw_halfPipe_valid; + wire axi_aw_halfPipe_ready; + wire [23:0] axi_aw_halfPipe_payload_addr; + wire [7:0] axi_aw_halfPipe_payload_len; + wire [2:0] axi_aw_halfPipe_payload_size; + wire [3:0] axi_aw_halfPipe_payload_cache; + wire [2:0] axi_aw_halfPipe_payload_prot; + reg axi_aw_rValid; + wire axi_aw_halfPipe_fire; + reg [23:0] axi_aw_rData_addr; + reg [7:0] axi_aw_rData_len; + reg [2:0] axi_aw_rData_size; + reg [3:0] axi_aw_rData_cache; + reg [2:0] axi_aw_rData_prot; + wire axi_w_halfPipe_valid; + wire axi_w_halfPipe_ready; + wire [31:0] axi_w_halfPipe_payload_data; + wire [3:0] axi_w_halfPipe_payload_strb; + wire axi_w_halfPipe_payload_last; + reg axi_w_rValid; + wire axi_w_halfPipe_fire; + reg [31:0] axi_w_rData_data; + reg [3:0] axi_w_rData_strb; + reg axi_w_rData_last; + wire _zz_axi_bvalid; + reg _zz_axi_bvalid_1; + reg [1:0] _zz_axi_bresp; + wire axi_ar_halfPipe_valid; + wire axi_ar_halfPipe_ready; + wire [23:0] axi_ar_halfPipe_payload_addr; + wire [7:0] axi_ar_halfPipe_payload_len; + wire [2:0] axi_ar_halfPipe_payload_size; + wire [3:0] axi_ar_halfPipe_payload_cache; + wire [2:0] axi_ar_halfPipe_payload_prot; + reg axi_ar_rValid; + wire axi_ar_halfPipe_fire; + reg [23:0] axi_ar_rData_addr; + reg [7:0] axi_ar_rData_len; + reg [2:0] axi_ar_rData_size; + reg [3:0] axi_ar_rData_cache; + reg [2:0] axi_ar_rData_prot; + wire _zz_axi_rvalid; + reg _zz_axi_rvalid_1; + reg [31:0] _zz_axi_rdata; + reg [1:0] _zz_axi_rresp; + reg _zz_axi_rlast; + wire axiShared_arw_valid; + wire axiShared_arw_ready; + wire [23:0] axiShared_arw_payload_addr; + wire [7:0] axiShared_arw_payload_len; + wire [2:0] axiShared_arw_payload_size; + wire [3:0] axiShared_arw_payload_cache; + wire [2:0] axiShared_arw_payload_prot; + wire axiShared_arw_payload_write; + wire axiShared_w_valid; + wire axiShared_w_ready; + wire [31:0] axiShared_w_payload_data; + wire [3:0] axiShared_w_payload_strb; + wire axiShared_w_payload_last; + wire axiShared_b_valid; + wire axiShared_b_ready; + wire [1:0] axiShared_b_payload_resp; + wire axiShared_r_valid; + wire axiShared_r_ready; + wire [31:0] axiShared_r_payload_data; + wire [1:0] axiShared_r_payload_resp; + wire axiShared_r_payload_last; + wire bmbPeripheral_bmb_cmd_valid; + wire bmbPeripheral_bmb_cmd_ready; + wire bmbPeripheral_bmb_cmd_payload_last; + wire [0:0] bmbPeripheral_bmb_cmd_payload_fragment_opcode; + wire [23:0] bmbPeripheral_bmb_cmd_payload_fragment_address; + wire [1:0] bmbPeripheral_bmb_cmd_payload_fragment_length; + wire [31:0] bmbPeripheral_bmb_cmd_payload_fragment_data; + wire [3:0] bmbPeripheral_bmb_cmd_payload_fragment_mask; + wire [2:0] bmbPeripheral_bmb_cmd_payload_fragment_context; + wire bmbPeripheral_bmb_rsp_valid; + wire bmbPeripheral_bmb_rsp_ready; + wire bmbPeripheral_bmb_rsp_payload_last; + wire [0:0] bmbPeripheral_bmb_rsp_payload_fragment_opcode; + wire [31:0] bmbPeripheral_bmb_rsp_payload_fragment_data; + wire [2:0] bmbPeripheral_bmb_rsp_payload_fragment_context; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + wire [0:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + wire [23:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + wire [1:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + wire [31:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + wire [3:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_mask; + wire [2:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready; + wire bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + wire [0:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + wire [31:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + wire [2:0] bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + wire [0:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + wire [5:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + wire [1:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + wire [31:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + wire [2:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + wire [0:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + wire [31:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + wire [2:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + wire _zz_io_bus_rsp_ready; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last; + wire [0:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode; + wire [5:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address; + wire [1:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length; + wire [31:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data; + wire [2:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context; + reg system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid; + wire system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire; + reg system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last; + reg [0:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode; + reg [5:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address; + reg [1:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length; + reg [31:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data; + reg [2:0] system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context; + wire _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + reg _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1; + reg _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + reg [0:0] _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + reg [31:0] _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + reg [2:0] _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + wire [0:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + wire [11:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + wire [1:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + wire [31:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + wire [2:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + wire [0:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + wire [31:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + wire [2:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last; + wire [0:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode; + wire [11:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address; + wire [1:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length; + wire [31:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data; + wire [2:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context; + reg system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid; + wire system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire; + reg system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last; + reg [0:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode; + reg [11:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address; + reg [1:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length; + reg [31:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data; + reg [2:0] system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context; + wire bmbPeripheral_bmb_withoutMask_cmd_valid; + wire bmbPeripheral_bmb_withoutMask_cmd_ready; + wire bmbPeripheral_bmb_withoutMask_cmd_payload_last; + wire [0:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode; + wire [23:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address; + wire [1:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length; + wire [31:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data; + wire [2:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context; + wire bmbPeripheral_bmb_withoutMask_rsp_valid; + wire bmbPeripheral_bmb_withoutMask_rsp_ready; + wire bmbPeripheral_bmb_withoutMask_rsp_payload_last; + wire [0:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode; + wire [31:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data; + wire [2:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context; + wire bmbPeripheral_bmb_withoutMask_cmd_valid_1; + wire bmbPeripheral_bmb_withoutMask_cmd_ready_1; + wire bmbPeripheral_bmb_withoutMask_cmd_payload_last_1; + wire [0:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode_1; + wire [23:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address_1; + wire [1:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length_1; + wire [31:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data_1; + wire [2:0] bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context_1; + wire bmbPeripheral_bmb_withoutMask_rsp_valid_1; + wire bmbPeripheral_bmb_withoutMask_rsp_ready_1; + wire bmbPeripheral_bmb_withoutMask_rsp_payload_last_1; + wire [0:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode_1; + wire [31:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data_1; + wire [2:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context_1; + + Axi4PeripheralStreamArbiter_86b7e1c47b934a8a97a62bda8ee6a75d streamArbiter ( + .io_inputs_0_valid (axi_ar_halfPipe_valid ), //i + .io_inputs_0_ready (streamArbiter_io_inputs_0_ready ), //o + .io_inputs_0_payload_addr (axi_ar_halfPipe_payload_addr[23:0] ), //i + .io_inputs_0_payload_len (axi_ar_halfPipe_payload_len[7:0] ), //i + .io_inputs_0_payload_size (axi_ar_halfPipe_payload_size[2:0] ), //i + .io_inputs_0_payload_cache (axi_ar_halfPipe_payload_cache[3:0] ), //i + .io_inputs_0_payload_prot (axi_ar_halfPipe_payload_prot[2:0] ), //i + .io_inputs_1_valid (axi_aw_halfPipe_valid ), //i + .io_inputs_1_ready (streamArbiter_io_inputs_1_ready ), //o + .io_inputs_1_payload_addr (axi_aw_halfPipe_payload_addr[23:0] ), //i + .io_inputs_1_payload_len (axi_aw_halfPipe_payload_len[7:0] ), //i + .io_inputs_1_payload_size (axi_aw_halfPipe_payload_size[2:0] ), //i + .io_inputs_1_payload_cache (axi_aw_halfPipe_payload_cache[3:0] ), //i + .io_inputs_1_payload_prot (axi_aw_halfPipe_payload_prot[2:0] ), //i + .io_output_valid (streamArbiter_io_output_valid ), //o + .io_output_ready (axiShared_arw_ready ), //i + .io_output_payload_addr (streamArbiter_io_output_payload_addr[23:0]), //o + .io_output_payload_len (streamArbiter_io_output_payload_len[7:0] ), //o + .io_output_payload_size (streamArbiter_io_output_payload_size[2:0] ), //o + .io_output_payload_cache (streamArbiter_io_output_payload_cache[3:0]), //o + .io_output_payload_prot (streamArbiter_io_output_payload_prot[2:0] ), //o + .io_chosen (streamArbiter_io_chosen ), //o + .io_chosenOH (streamArbiter_io_chosenOH[1:0] ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralAxi4SharedToBmb_86b7e1c47b934a8a97a62bda8ee6a75d axiToBmb ( + .io_axi_arw_valid (axiShared_arw_valid ), //i + .io_axi_arw_ready (axiToBmb_io_axi_arw_ready ), //o + .io_axi_arw_payload_addr (axiShared_arw_payload_addr[23:0] ), //i + .io_axi_arw_payload_len (axiShared_arw_payload_len[7:0] ), //i + .io_axi_arw_payload_size (axiShared_arw_payload_size[2:0] ), //i + .io_axi_arw_payload_cache (axiShared_arw_payload_cache[3:0] ), //i + .io_axi_arw_payload_prot (axiShared_arw_payload_prot[2:0] ), //i + .io_axi_arw_payload_write (axiShared_arw_payload_write ), //i + .io_axi_w_valid (axiShared_w_valid ), //i + .io_axi_w_ready (axiToBmb_io_axi_w_ready ), //o + .io_axi_w_payload_data (axiShared_w_payload_data[31:0] ), //i + .io_axi_w_payload_strb (axiShared_w_payload_strb[3:0] ), //i + .io_axi_w_payload_last (axiShared_w_payload_last ), //i + .io_axi_b_valid (axiToBmb_io_axi_b_valid ), //o + .io_axi_b_ready (axiShared_b_ready ), //i + .io_axi_b_payload_resp (axiToBmb_io_axi_b_payload_resp[1:0] ), //o + .io_axi_r_valid (axiToBmb_io_axi_r_valid ), //o + .io_axi_r_ready (axiShared_r_ready ), //i + .io_axi_r_payload_data (axiToBmb_io_axi_r_payload_data[31:0] ), //o + .io_axi_r_payload_resp (axiToBmb_io_axi_r_payload_resp[1:0] ), //o + .io_axi_r_payload_last (axiToBmb_io_axi_r_payload_last ), //o + .io_bmb_cmd_valid (axiToBmb_io_bmb_cmd_valid ), //o + .io_bmb_cmd_ready (bmbHandle_decoder_io_input_cmd_ready ), //i + .io_bmb_cmd_payload_last (axiToBmb_io_bmb_cmd_payload_last ), //o + .io_bmb_cmd_payload_fragment_source (axiToBmb_io_bmb_cmd_payload_fragment_source ), //o + .io_bmb_cmd_payload_fragment_opcode (axiToBmb_io_bmb_cmd_payload_fragment_opcode ), //o + .io_bmb_cmd_payload_fragment_address (axiToBmb_io_bmb_cmd_payload_fragment_address[23:0] ), //o + .io_bmb_cmd_payload_fragment_length (axiToBmb_io_bmb_cmd_payload_fragment_length[9:0] ), //o + .io_bmb_cmd_payload_fragment_data (axiToBmb_io_bmb_cmd_payload_fragment_data[31:0] ), //o + .io_bmb_cmd_payload_fragment_mask (axiToBmb_io_bmb_cmd_payload_fragment_mask[3:0] ), //o + .io_bmb_rsp_valid (bmbHandle_decoder_io_input_rsp_valid ), //i + .io_bmb_rsp_ready (axiToBmb_io_bmb_rsp_ready ), //o + .io_bmb_rsp_payload_last (bmbHandle_decoder_io_input_rsp_payload_last ), //i + .io_bmb_rsp_payload_fragment_source (bmbHandle_decoder_io_input_rsp_payload_fragment_source ), //i + .io_bmb_rsp_payload_fragment_opcode (bmbHandle_decoder_io_input_rsp_payload_fragment_opcode ), //i + .io_bmb_rsp_payload_fragment_data (bmbHandle_decoder_io_input_rsp_payload_fragment_data[31:0]) //i + ); + Axi4PeripheralBmbDecoder_86b7e1c47b934a8a97a62bda8ee6a75d bmbHandle_decoder ( + .io_input_cmd_valid (axiToBmb_io_bmb_cmd_valid ), //i + .io_input_cmd_ready (bmbHandle_decoder_io_input_cmd_ready ), //o + .io_input_cmd_payload_last (axiToBmb_io_bmb_cmd_payload_last ), //i + .io_input_cmd_payload_fragment_source (axiToBmb_io_bmb_cmd_payload_fragment_source ), //i + .io_input_cmd_payload_fragment_opcode (axiToBmb_io_bmb_cmd_payload_fragment_opcode ), //i + .io_input_cmd_payload_fragment_address (axiToBmb_io_bmb_cmd_payload_fragment_address[23:0] ), //i + .io_input_cmd_payload_fragment_length (axiToBmb_io_bmb_cmd_payload_fragment_length[9:0] ), //i + .io_input_cmd_payload_fragment_data (axiToBmb_io_bmb_cmd_payload_fragment_data[31:0] ), //i + .io_input_cmd_payload_fragment_mask (axiToBmb_io_bmb_cmd_payload_fragment_mask[3:0] ), //i + .io_input_rsp_valid (bmbHandle_decoder_io_input_rsp_valid ), //o + .io_input_rsp_ready (axiToBmb_io_bmb_rsp_ready ), //i + .io_input_rsp_payload_last (bmbHandle_decoder_io_input_rsp_payload_last ), //o + .io_input_rsp_payload_fragment_source (bmbHandle_decoder_io_input_rsp_payload_fragment_source ), //o + .io_input_rsp_payload_fragment_opcode (bmbHandle_decoder_io_input_rsp_payload_fragment_opcode ), //o + .io_input_rsp_payload_fragment_data (bmbHandle_decoder_io_input_rsp_payload_fragment_data[31:0] ), //o + .io_outputs_0_cmd_valid (bmbHandle_decoder_io_outputs_0_cmd_valid ), //o + .io_outputs_0_cmd_ready (bmbHandle_unburstify_io_input_cmd_ready ), //i + .io_outputs_0_cmd_payload_last (bmbHandle_decoder_io_outputs_0_cmd_payload_last ), //o + .io_outputs_0_cmd_payload_fragment_source (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_source ), //o + .io_outputs_0_cmd_payload_fragment_opcode (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_opcode ), //o + .io_outputs_0_cmd_payload_fragment_address (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_address[23:0]), //o + .io_outputs_0_cmd_payload_fragment_length (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_length[9:0] ), //o + .io_outputs_0_cmd_payload_fragment_data (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_data[31:0] ), //o + .io_outputs_0_cmd_payload_fragment_mask (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_mask[3:0] ), //o + .io_outputs_0_rsp_valid (bmbHandle_unburstify_io_input_rsp_valid ), //i + .io_outputs_0_rsp_ready (bmbHandle_decoder_io_outputs_0_rsp_ready ), //o + .io_outputs_0_rsp_payload_last (bmbHandle_unburstify_io_input_rsp_payload_last ), //i + .io_outputs_0_rsp_payload_fragment_source (bmbHandle_unburstify_io_input_rsp_payload_fragment_source ), //i + .io_outputs_0_rsp_payload_fragment_opcode (bmbHandle_unburstify_io_input_rsp_payload_fragment_opcode ), //i + .io_outputs_0_rsp_payload_fragment_data (bmbHandle_unburstify_io_input_rsp_payload_fragment_data[31:0] ), //i + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralBmbUnburstify_86b7e1c47b934a8a97a62bda8ee6a75d bmbHandle_unburstify ( + .io_input_cmd_valid (bmbHandle_decoder_io_outputs_0_cmd_valid ), //i + .io_input_cmd_ready (bmbHandle_unburstify_io_input_cmd_ready ), //o + .io_input_cmd_payload_last (bmbHandle_decoder_io_outputs_0_cmd_payload_last ), //i + .io_input_cmd_payload_fragment_source (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_source ), //i + .io_input_cmd_payload_fragment_opcode (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_opcode ), //i + .io_input_cmd_payload_fragment_address (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_address[23:0] ), //i + .io_input_cmd_payload_fragment_length (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_length[9:0] ), //i + .io_input_cmd_payload_fragment_data (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_data[31:0] ), //i + .io_input_cmd_payload_fragment_mask (bmbHandle_decoder_io_outputs_0_cmd_payload_fragment_mask[3:0] ), //i + .io_input_rsp_valid (bmbHandle_unburstify_io_input_rsp_valid ), //o + .io_input_rsp_ready (bmbHandle_decoder_io_outputs_0_rsp_ready ), //i + .io_input_rsp_payload_last (bmbHandle_unburstify_io_input_rsp_payload_last ), //o + .io_input_rsp_payload_fragment_source (bmbHandle_unburstify_io_input_rsp_payload_fragment_source ), //o + .io_input_rsp_payload_fragment_opcode (bmbHandle_unburstify_io_input_rsp_payload_fragment_opcode ), //o + .io_input_rsp_payload_fragment_data (bmbHandle_unburstify_io_input_rsp_payload_fragment_data[31:0] ), //o + .io_output_cmd_valid (bmbHandle_unburstify_io_output_cmd_valid ), //o + .io_output_cmd_ready (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready ), //i + .io_output_cmd_payload_last (bmbHandle_unburstify_io_output_cmd_payload_last ), //o + .io_output_cmd_payload_fragment_opcode (bmbHandle_unburstify_io_output_cmd_payload_fragment_opcode ), //o + .io_output_cmd_payload_fragment_address (bmbHandle_unburstify_io_output_cmd_payload_fragment_address[23:0] ), //o + .io_output_cmd_payload_fragment_length (bmbHandle_unburstify_io_output_cmd_payload_fragment_length[1:0] ), //o + .io_output_cmd_payload_fragment_data (bmbHandle_unburstify_io_output_cmd_payload_fragment_data[31:0] ), //o + .io_output_cmd_payload_fragment_mask (bmbHandle_unburstify_io_output_cmd_payload_fragment_mask[3:0] ), //o + .io_output_cmd_payload_fragment_context (bmbHandle_unburstify_io_output_cmd_payload_fragment_context[2:0] ), //o + .io_output_rsp_valid (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid ), //i + .io_output_rsp_ready (bmbHandle_unburstify_io_output_rsp_ready ), //o + .io_output_rsp_payload_last (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last ), //i + .io_output_rsp_payload_fragment_opcode (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode ), //i + .io_output_rsp_payload_fragment_data (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data[31:0] ), //i + .io_output_rsp_payload_fragment_context (bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context[2:0]), //i + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralBmbDecoder_1_86b7e1c47b934a8a97a62bda8ee6a75d bmbPeripheral_bmb_decoder ( + .io_input_cmd_valid (bmbPeripheral_bmb_cmd_valid ), //i + .io_input_cmd_ready (bmbPeripheral_bmb_decoder_io_input_cmd_ready ), //o + .io_input_cmd_payload_last (bmbPeripheral_bmb_cmd_payload_last ), //i + .io_input_cmd_payload_fragment_opcode (bmbPeripheral_bmb_cmd_payload_fragment_opcode ), //i + .io_input_cmd_payload_fragment_address (bmbPeripheral_bmb_cmd_payload_fragment_address[23:0] ), //i + .io_input_cmd_payload_fragment_length (bmbPeripheral_bmb_cmd_payload_fragment_length[1:0] ), //i + .io_input_cmd_payload_fragment_data (bmbPeripheral_bmb_cmd_payload_fragment_data[31:0] ), //i + .io_input_cmd_payload_fragment_mask (bmbPeripheral_bmb_cmd_payload_fragment_mask[3:0] ), //i + .io_input_cmd_payload_fragment_context (bmbPeripheral_bmb_cmd_payload_fragment_context[2:0] ), //i + .io_input_rsp_valid (bmbPeripheral_bmb_decoder_io_input_rsp_valid ), //o + .io_input_rsp_ready (bmbPeripheral_bmb_rsp_ready ), //i + .io_input_rsp_payload_last (bmbPeripheral_bmb_decoder_io_input_rsp_payload_last ), //o + .io_input_rsp_payload_fragment_opcode (bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_opcode ), //o + .io_input_rsp_payload_fragment_data (bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_data[31:0] ), //o + .io_input_rsp_payload_fragment_context (bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_context[2:0] ), //o + .io_outputs_0_cmd_valid (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_valid ), //o + .io_outputs_0_cmd_ready (bmbPeripheral_bmb_withoutMask_cmd_ready ), //i + .io_outputs_0_cmd_payload_last (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_last ), //o + .io_outputs_0_cmd_payload_fragment_opcode (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_opcode ), //o + .io_outputs_0_cmd_payload_fragment_address (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_address[23:0]), //o + .io_outputs_0_cmd_payload_fragment_length (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_length[1:0] ), //o + .io_outputs_0_cmd_payload_fragment_data (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_data[31:0] ), //o + .io_outputs_0_cmd_payload_fragment_mask (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_mask[3:0] ), //o + .io_outputs_0_cmd_payload_fragment_context (bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_context[2:0] ), //o + .io_outputs_0_rsp_valid (bmbPeripheral_bmb_withoutMask_rsp_valid ), //i + .io_outputs_0_rsp_ready (bmbPeripheral_bmb_decoder_io_outputs_0_rsp_ready ), //o + .io_outputs_0_rsp_payload_last (bmbPeripheral_bmb_withoutMask_rsp_payload_last ), //i + .io_outputs_0_rsp_payload_fragment_opcode (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode ), //i + .io_outputs_0_rsp_payload_fragment_data (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data[31:0] ), //i + .io_outputs_0_rsp_payload_fragment_context (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context[2:0] ), //i + .io_outputs_1_cmd_valid (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_valid ), //o + .io_outputs_1_cmd_ready (bmbPeripheral_bmb_withoutMask_cmd_ready_1 ), //i + .io_outputs_1_cmd_payload_last (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_last ), //o + .io_outputs_1_cmd_payload_fragment_opcode (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_opcode ), //o + .io_outputs_1_cmd_payload_fragment_address (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_address[23:0]), //o + .io_outputs_1_cmd_payload_fragment_length (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_length[1:0] ), //o + .io_outputs_1_cmd_payload_fragment_data (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_data[31:0] ), //o + .io_outputs_1_cmd_payload_fragment_mask (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_mask[3:0] ), //o + .io_outputs_1_cmd_payload_fragment_context (bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_context[2:0] ), //o + .io_outputs_1_rsp_valid (bmbPeripheral_bmb_withoutMask_rsp_valid_1 ), //i + .io_outputs_1_rsp_ready (bmbPeripheral_bmb_decoder_io_outputs_1_rsp_ready ), //o + .io_outputs_1_rsp_payload_last (bmbPeripheral_bmb_withoutMask_rsp_payload_last_1 ), //i + .io_outputs_1_rsp_payload_fragment_opcode (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode_1 ), //i + .io_outputs_1_rsp_payload_fragment_data (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data_1[31:0] ), //i + .io_outputs_1_rsp_payload_fragment_context (bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context_1[2:0] ), //i + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralBmbUartCtrl_86b7e1c47b934a8a97a62bda8ee6a75d system_uart_0_io_logic ( + .io_bus_cmd_valid (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid ), //i + .io_bus_cmd_ready (system_uart_0_io_logic_io_bus_cmd_ready ), //o + .io_bus_cmd_payload_last (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last ), //i + .io_bus_cmd_payload_fragment_opcode (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode ), //i + .io_bus_cmd_payload_fragment_address (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address[5:0]), //i + .io_bus_cmd_payload_fragment_length (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length[1:0] ), //i + .io_bus_cmd_payload_fragment_data (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data[31:0] ), //i + .io_bus_cmd_payload_fragment_context (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context[2:0]), //i + .io_bus_rsp_valid (system_uart_0_io_logic_io_bus_rsp_valid ), //o + .io_bus_rsp_ready (_zz_io_bus_rsp_ready ), //i + .io_bus_rsp_payload_last (system_uart_0_io_logic_io_bus_rsp_payload_last ), //o + .io_bus_rsp_payload_fragment_opcode (system_uart_0_io_logic_io_bus_rsp_payload_fragment_opcode ), //o + .io_bus_rsp_payload_fragment_data (system_uart_0_io_logic_io_bus_rsp_payload_fragment_data[31:0] ), //o + .io_bus_rsp_payload_fragment_context (system_uart_0_io_logic_io_bus_rsp_payload_fragment_context[2:0] ), //o + .io_uart_txd (system_uart_0_io_logic_io_uart_txd ), //o + .io_uart_rxd (system_uart_0_io_rxd ), //i + .system_uart_0_io_interrupt_source (system_uart_0_io_logic_system_uart_0_io_interrupt_source ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralBmbSpiXdrMasterCtrl_86b7e1c47b934a8a97a62bda8ee6a75d system_spi_0_io_logic ( + .io_ctrl_cmd_valid (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid ), //i + .io_ctrl_cmd_ready (system_spi_0_io_logic_io_ctrl_cmd_ready ), //o + .io_ctrl_cmd_payload_last (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last ), //i + .io_ctrl_cmd_payload_fragment_opcode (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode ), //i + .io_ctrl_cmd_payload_fragment_address (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address[11:0]), //i + .io_ctrl_cmd_payload_fragment_length (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length[1:0] ), //i + .io_ctrl_cmd_payload_fragment_data (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data[31:0] ), //i + .io_ctrl_cmd_payload_fragment_context (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context[2:0] ), //i + .io_ctrl_rsp_valid (system_spi_0_io_logic_io_ctrl_rsp_valid ), //o + .io_ctrl_rsp_ready (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready ), //i + .io_ctrl_rsp_payload_last (system_spi_0_io_logic_io_ctrl_rsp_payload_last ), //o + .io_ctrl_rsp_payload_fragment_opcode (system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_opcode ), //o + .io_ctrl_rsp_payload_fragment_data (system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_data[31:0] ), //o + .io_ctrl_rsp_payload_fragment_context (system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_context[2:0] ), //o + .io_spi_sclk_write (system_spi_0_io_logic_io_spi_sclk_write ), //o + .io_spi_data_0_writeEnable (system_spi_0_io_logic_io_spi_data_0_writeEnable ), //o + .io_spi_data_0_read (system_spi_0_io_data_0_read ), //i + .io_spi_data_0_write (system_spi_0_io_logic_io_spi_data_0_write ), //o + .io_spi_data_1_writeEnable (system_spi_0_io_logic_io_spi_data_1_writeEnable ), //o + .io_spi_data_1_read (system_spi_0_io_data_1_read ), //i + .io_spi_data_1_write (system_spi_0_io_logic_io_spi_data_1_write ), //o + .io_spi_data_2_writeEnable (system_spi_0_io_logic_io_spi_data_2_writeEnable ), //o + .io_spi_data_2_read (system_spi_0_io_data_2_read ), //i + .io_spi_data_2_write (system_spi_0_io_logic_io_spi_data_2_write ), //o + .io_spi_data_3_writeEnable (system_spi_0_io_logic_io_spi_data_3_writeEnable ), //o + .io_spi_data_3_read (system_spi_0_io_data_3_read ), //i + .io_spi_data_3_write (system_spi_0_io_logic_io_spi_data_3_write ), //o + .io_spi_ss (system_spi_0_io_logic_io_spi_ss[3:0] ), //o + .system_spi_0_io_interrupt_source (system_spi_0_io_logic_system_spi_0_io_interrupt_source ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + assign axi_aw_halfPipe_fire = (axi_aw_halfPipe_valid && axi_aw_halfPipe_ready); + assign axi_awready = (! axi_aw_rValid); + assign axi_aw_halfPipe_valid = axi_aw_rValid; + assign axi_aw_halfPipe_payload_addr = axi_aw_rData_addr; + assign axi_aw_halfPipe_payload_len = axi_aw_rData_len; + assign axi_aw_halfPipe_payload_size = axi_aw_rData_size; + assign axi_aw_halfPipe_payload_cache = axi_aw_rData_cache; + assign axi_aw_halfPipe_payload_prot = axi_aw_rData_prot; + assign axi_aw_halfPipe_ready = streamArbiter_io_inputs_1_ready; + assign axi_w_halfPipe_fire = (axi_w_halfPipe_valid && axi_w_halfPipe_ready); + assign axi_wready = (! axi_w_rValid); + assign axi_w_halfPipe_valid = axi_w_rValid; + assign axi_w_halfPipe_payload_data = axi_w_rData_data; + assign axi_w_halfPipe_payload_strb = axi_w_rData_strb; + assign axi_w_halfPipe_payload_last = axi_w_rData_last; + assign axi_w_halfPipe_ready = axiShared_w_ready; + assign _zz_axiShared_b_ready = (! _zz_axi_bvalid_1); + assign _zz_axi_bvalid = _zz_axi_bvalid_1; + assign axi_bvalid = _zz_axi_bvalid; + assign axi_bresp = _zz_axi_bresp; + assign axi_ar_halfPipe_fire = (axi_ar_halfPipe_valid && axi_ar_halfPipe_ready); + assign axi_arready = (! axi_ar_rValid); + assign axi_ar_halfPipe_valid = axi_ar_rValid; + assign axi_ar_halfPipe_payload_addr = axi_ar_rData_addr; + assign axi_ar_halfPipe_payload_len = axi_ar_rData_len; + assign axi_ar_halfPipe_payload_size = axi_ar_rData_size; + assign axi_ar_halfPipe_payload_cache = axi_ar_rData_cache; + assign axi_ar_halfPipe_payload_prot = axi_ar_rData_prot; + assign axi_ar_halfPipe_ready = streamArbiter_io_inputs_0_ready; + assign _zz_axiShared_r_ready = (! _zz_axi_rvalid_1); + assign _zz_axi_rvalid = _zz_axi_rvalid_1; + assign axi_rvalid = _zz_axi_rvalid; + assign axi_rdata = _zz_axi_rdata; + assign axi_rresp = _zz_axi_rresp; + assign axi_rlast = _zz_axi_rlast; + assign axiShared_arw_valid = streamArbiter_io_output_valid; + assign axiShared_arw_payload_addr = streamArbiter_io_output_payload_addr; + assign axiShared_arw_payload_len = streamArbiter_io_output_payload_len; + assign axiShared_arw_payload_size = streamArbiter_io_output_payload_size; + assign axiShared_arw_payload_cache = streamArbiter_io_output_payload_cache; + assign axiShared_arw_payload_prot = streamArbiter_io_output_payload_prot; + assign axiShared_arw_payload_write = streamArbiter_io_chosenOH[1]; + assign axiShared_w_valid = axi_w_halfPipe_valid; + assign axiShared_w_payload_data = axi_w_halfPipe_payload_data; + assign axiShared_w_payload_strb = axi_w_halfPipe_payload_strb; + assign axiShared_w_payload_last = axi_w_halfPipe_payload_last; + assign axiShared_b_ready = _zz_axiShared_b_ready; + assign axiShared_r_ready = _zz_axiShared_r_ready; + assign axiShared_arw_ready = axiToBmb_io_axi_arw_ready; + assign axiShared_w_ready = axiToBmb_io_axi_w_ready; + assign axiShared_b_valid = axiToBmb_io_axi_b_valid; + assign axiShared_b_payload_resp = axiToBmb_io_axi_b_payload_resp; + assign axiShared_r_valid = axiToBmb_io_axi_r_valid; + assign axiShared_r_payload_data = axiToBmb_io_axi_r_payload_data; + assign axiShared_r_payload_last = axiToBmb_io_axi_r_payload_last; + assign axiShared_r_payload_resp = axiToBmb_io_axi_r_payload_resp; + assign bmbPeripheral_bmb_cmd_valid = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready = bmbPeripheral_bmb_cmd_ready; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid = bmbPeripheral_bmb_rsp_valid; + assign bmbPeripheral_bmb_rsp_ready = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready; + assign bmbPeripheral_bmb_cmd_payload_last = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last = bmbPeripheral_bmb_rsp_payload_last; + assign bmbPeripheral_bmb_cmd_payload_fragment_opcode = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + assign bmbPeripheral_bmb_cmd_payload_fragment_address = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + assign bmbPeripheral_bmb_cmd_payload_fragment_length = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + assign bmbPeripheral_bmb_cmd_payload_fragment_data = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + assign bmbPeripheral_bmb_cmd_payload_fragment_mask = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_mask; + assign bmbPeripheral_bmb_cmd_payload_fragment_context = bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode = bmbPeripheral_bmb_rsp_payload_fragment_opcode; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data = bmbPeripheral_bmb_rsp_payload_fragment_data; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context = bmbPeripheral_bmb_rsp_payload_fragment_context; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid = bmbHandle_unburstify_io_output_cmd_valid; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready = bmbHandle_unburstify_io_output_rsp_ready; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last = bmbHandle_unburstify_io_output_cmd_payload_last; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode = bmbHandle_unburstify_io_output_cmd_payload_fragment_opcode; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address = bmbHandle_unburstify_io_output_cmd_payload_fragment_address; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length = bmbHandle_unburstify_io_output_cmd_payload_fragment_length; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data = bmbHandle_unburstify_io_output_cmd_payload_fragment_data; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_mask = bmbHandle_unburstify_io_output_cmd_payload_fragment_mask; + assign bmbPeripheral_bmb_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context = bmbHandle_unburstify_io_output_cmd_payload_fragment_context; + assign bmbPeripheral_bmb_cmd_ready = bmbPeripheral_bmb_decoder_io_input_cmd_ready; + assign bmbPeripheral_bmb_rsp_valid = bmbPeripheral_bmb_decoder_io_input_rsp_valid; + assign bmbPeripheral_bmb_rsp_payload_last = bmbPeripheral_bmb_decoder_io_input_rsp_payload_last; + assign bmbPeripheral_bmb_rsp_payload_fragment_opcode = bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_opcode; + assign bmbPeripheral_bmb_rsp_payload_fragment_data = bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_data; + assign bmbPeripheral_bmb_rsp_payload_fragment_context = bmbPeripheral_bmb_decoder_io_input_rsp_payload_fragment_context; + assign system_uart_0_io_txd = system_uart_0_io_logic_io_uart_txd; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire = (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid && system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready); + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready = (! system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid); + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready = system_uart_0_io_logic_io_bus_cmd_ready; + assign _zz_io_bus_rsp_ready = (! _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1); + assign _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context = _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + assign system_uart_0_io_interrupt = system_uart_0_io_logic_system_uart_0_io_interrupt_source; + assign system_spi_0_io_interrupt = system_spi_0_io_logic_system_spi_0_io_interrupt_source; + assign system_spi_0_io_sclk_write = system_spi_0_io_logic_io_spi_sclk_write; + assign system_spi_0_io_data_0_writeEnable = system_spi_0_io_logic_io_spi_data_0_writeEnable; + assign system_spi_0_io_data_0_write = system_spi_0_io_logic_io_spi_data_0_write; + assign system_spi_0_io_data_1_writeEnable = system_spi_0_io_logic_io_spi_data_1_writeEnable; + assign system_spi_0_io_data_1_write = system_spi_0_io_logic_io_spi_data_1_write; + assign system_spi_0_io_data_2_writeEnable = system_spi_0_io_logic_io_spi_data_2_writeEnable; + assign system_spi_0_io_data_2_write = system_spi_0_io_logic_io_spi_data_2_write; + assign system_spi_0_io_data_3_writeEnable = system_spi_0_io_logic_io_spi_data_3_writeEnable; + assign system_spi_0_io_data_3_write = system_spi_0_io_logic_io_spi_data_3_write; + assign system_spi_0_io_ss = system_spi_0_io_logic_io_spi_ss; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire = (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid && system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready); + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready = (! system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid); + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_opcode = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_address = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_length = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_data = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_fragment_context = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_ready = system_spi_0_io_logic_io_ctrl_cmd_ready; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid = system_spi_0_io_logic_io_ctrl_rsp_valid; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last = system_spi_0_io_logic_io_ctrl_rsp_payload_last; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode = system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_opcode; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data = system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_data; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context = system_spi_0_io_logic_io_ctrl_rsp_payload_fragment_context; + assign bmbPeripheral_bmb_withoutMask_cmd_valid = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_valid; + assign bmbPeripheral_bmb_withoutMask_rsp_ready = bmbPeripheral_bmb_decoder_io_outputs_0_rsp_ready; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_last = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_last; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_opcode; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_address; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_length; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_data; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context = bmbPeripheral_bmb_decoder_io_outputs_0_cmd_payload_fragment_context; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid = bmbPeripheral_bmb_withoutMask_cmd_valid; + assign bmbPeripheral_bmb_withoutMask_cmd_ready = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready; + assign bmbPeripheral_bmb_withoutMask_rsp_valid = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready = bmbPeripheral_bmb_withoutMask_rsp_ready; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last = bmbPeripheral_bmb_withoutMask_cmd_payload_last; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_last = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address[5:0]; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data; + assign system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context = system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + assign bmbPeripheral_bmb_withoutMask_cmd_valid_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_valid; + assign bmbPeripheral_bmb_withoutMask_rsp_ready_1 = bmbPeripheral_bmb_decoder_io_outputs_1_rsp_ready; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_last_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_last; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_opcode; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_address; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_length; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_data; + assign bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context_1 = bmbPeripheral_bmb_decoder_io_outputs_1_cmd_payload_fragment_context; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid = bmbPeripheral_bmb_withoutMask_cmd_valid_1; + assign bmbPeripheral_bmb_withoutMask_cmd_ready_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready; + assign bmbPeripheral_bmb_withoutMask_rsp_valid_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready = bmbPeripheral_bmb_withoutMask_rsp_ready_1; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last = bmbPeripheral_bmb_withoutMask_cmd_payload_last_1; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_last_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_opcode_1; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_address_1[11:0]; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_length_1; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_data_1; + assign system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context = bmbPeripheral_bmb_withoutMask_cmd_payload_fragment_context_1; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_opcode_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data; + assign bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context_1 = system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context; + always @(posedge clk) begin + if(reset) begin + axi_aw_rValid <= 1'b0; + axi_w_rValid <= 1'b0; + _zz_axi_bvalid_1 <= 1'b0; + axi_ar_rValid <= 1'b0; + _zz_axi_rvalid_1 <= 1'b0; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b0; + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1 <= 1'b0; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b0; + end else begin + if(axi_awvalid) begin + axi_aw_rValid <= 1'b1; + end + if(axi_aw_halfPipe_fire) begin + axi_aw_rValid <= 1'b0; + end + if(axi_wvalid) begin + axi_w_rValid <= 1'b1; + end + if(axi_w_halfPipe_fire) begin + axi_w_rValid <= 1'b0; + end + if(axiShared_b_valid) begin + _zz_axi_bvalid_1 <= 1'b1; + end + if((_zz_axi_bvalid && axi_bready)) begin + _zz_axi_bvalid_1 <= 1'b0; + end + if(axi_arvalid) begin + axi_ar_rValid <= 1'b1; + end + if(axi_ar_halfPipe_fire) begin + axi_ar_rValid <= 1'b0; + end + if(axiShared_r_valid) begin + _zz_axi_rvalid_1 <= 1'b1; + end + if((_zz_axi_rvalid && axi_rready)) begin + _zz_axi_rvalid_1 <= 1'b0; + end + if(system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid) begin + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b1; + end + if(system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire) begin + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b0; + end + if(system_uart_0_io_logic_io_bus_rsp_valid) begin + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1 <= 1'b1; + end + if((_zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid && system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_ready)) begin + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_valid_1 <= 1'b0; + end + if(system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid) begin + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b1; + end + if(system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_fire) begin + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rValid <= 1'b0; + end + end + end + + always @(posedge clk) begin + if(axi_awready) begin + axi_aw_rData_addr <= axi_awaddr; + axi_aw_rData_len <= axi_awlen; + axi_aw_rData_size <= axi_awsize; + axi_aw_rData_cache <= axi_awcache; + axi_aw_rData_prot <= axi_awprot; + end + if(axi_wready) begin + axi_w_rData_data <= axi_wdata; + axi_w_rData_strb <= axi_wstrb; + axi_w_rData_last <= axi_wlast; + end + if(_zz_axiShared_b_ready) begin + _zz_axi_bresp <= axiShared_b_payload_resp; + end + if(axi_arready) begin + axi_ar_rData_addr <= axi_araddr; + axi_ar_rData_len <= axi_arlen; + axi_ar_rData_size <= axi_arsize; + axi_ar_rData_cache <= axi_arcache; + axi_ar_rData_prot <= axi_arprot; + end + if(_zz_axiShared_r_ready) begin + _zz_axi_rdata <= axiShared_r_payload_data; + _zz_axi_rresp <= axiShared_r_payload_resp; + _zz_axi_rlast <= axiShared_r_payload_last; + end + if(system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready) begin + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context <= system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + end + if(_zz_io_bus_rsp_ready) begin + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_last <= system_uart_0_io_logic_io_bus_rsp_payload_last; + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_opcode <= system_uart_0_io_logic_io_bus_rsp_payload_fragment_opcode; + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_data <= system_uart_0_io_logic_io_bus_rsp_payload_fragment_data; + _zz_system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_rsp_payload_fragment_context <= system_uart_0_io_logic_io_bus_rsp_payload_fragment_context; + end + if(system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_ready) begin + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_last <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_opcode <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_opcode; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_address <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_address; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_length <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_length; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_data <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_data; + system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_rData_fragment_context <= system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_fragment_context; + end + end + + +endmodule + +module Axi4PeripheralBmbSpiXdrMasterCtrl_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_ctrl_cmd_valid, + output wire io_ctrl_cmd_ready, + input wire io_ctrl_cmd_payload_last, + input wire [0:0] io_ctrl_cmd_payload_fragment_opcode, + input wire [11:0] io_ctrl_cmd_payload_fragment_address, + input wire [1:0] io_ctrl_cmd_payload_fragment_length, + input wire [31:0] io_ctrl_cmd_payload_fragment_data, + input wire [2:0] io_ctrl_cmd_payload_fragment_context, + output wire io_ctrl_rsp_valid, + input wire io_ctrl_rsp_ready, + output wire io_ctrl_rsp_payload_last, + output wire [0:0] io_ctrl_rsp_payload_fragment_opcode, + output wire [31:0] io_ctrl_rsp_payload_fragment_data, + output wire [2:0] io_ctrl_rsp_payload_fragment_context, + output wire [0:0] io_spi_sclk_write, + output wire io_spi_data_0_writeEnable, + input wire [0:0] io_spi_data_0_read, + output wire [0:0] io_spi_data_0_write, + output wire io_spi_data_1_writeEnable, + input wire [0:0] io_spi_data_1_read, + output wire [0:0] io_spi_data_1_write, + output wire io_spi_data_2_writeEnable, + input wire [0:0] io_spi_data_2_read, + output wire [0:0] io_spi_data_2_write, + output wire io_spi_data_3_writeEnable, + input wire [0:0] io_spi_data_3_read, + output wire [0:0] io_spi_data_3_write, + output wire [3:0] io_spi_ss, + output wire system_spi_0_io_interrupt_source, + input wire clk, + input wire reset +); + + wire ctrl_io_rsp_queueWithOccupancy_io_pop_ready; + wire ctrl_io_cmd_ready; + wire ctrl_io_rsp_valid; + wire [7:0] ctrl_io_rsp_payload_data; + wire [0:0] ctrl_io_spi_sclk_write; + wire [3:0] ctrl_io_spi_ss; + wire [0:0] ctrl_io_spi_data_0_write; + wire ctrl_io_spi_data_0_writeEnable; + wire [0:0] ctrl_io_spi_data_1_write; + wire ctrl_io_spi_data_1_writeEnable; + wire [0:0] ctrl_io_spi_data_2_write; + wire ctrl_io_spi_data_2_writeEnable; + wire [0:0] ctrl_io_spi_data_3_write; + wire ctrl_io_spi_data_3_writeEnable; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_push_ready; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_valid; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_kind; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_read; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_write; + wire [7:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_data; + wire [8:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_occupancy; + wire [8:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_availability; + wire ctrl_io_rsp_queueWithOccupancy_io_push_ready; + wire ctrl_io_rsp_queueWithOccupancy_io_pop_valid; + wire [7:0] ctrl_io_rsp_queueWithOccupancy_io_pop_payload_data; + wire [8:0] ctrl_io_rsp_queueWithOccupancy_io_occupancy; + wire [8:0] ctrl_io_rsp_queueWithOccupancy_io_availability; + wire factory_readErrorFlag; + wire factory_writeErrorFlag; + wire factory_readHaltTrigger; + wire factory_writeHaltTrigger; + wire factory_rsp_valid; + wire factory_rsp_ready; + wire factory_rsp_payload_last; + reg [0:0] factory_rsp_payload_fragment_opcode; + reg [31:0] factory_rsp_payload_fragment_data; + wire [2:0] factory_rsp_payload_fragment_context; + wire _zz_factory_rsp_ready; + reg _zz_factory_rsp_ready_1; + wire _zz_io_ctrl_rsp_valid; + reg _zz_io_ctrl_rsp_valid_1; + reg _zz_io_ctrl_rsp_payload_last; + reg [0:0] _zz_io_ctrl_rsp_payload_fragment_opcode; + reg [31:0] _zz_io_ctrl_rsp_payload_fragment_data; + reg [2:0] _zz_io_ctrl_rsp_payload_fragment_context; + wire when_Stream_l375; + wire factory_askWrite; + wire factory_askRead; + wire io_ctrl_cmd_fire; + wire factory_doWrite; + wire factory_doRead; + wire when_BmbSlaveFactory_l33; + wire when_BmbSlaveFactory_l35; + wire [31:0] mapping_cmdLogic_writeData; + reg mapping_cmdLogic_doRegular; + reg mapping_cmdLogic_doWriteLarge; + reg mapping_cmdLogic_doReadWriteLarge; + wire mapping_cmdLogic_streamUnbuffered_valid; + wire mapping_cmdLogic_streamUnbuffered_ready; + wire mapping_cmdLogic_streamUnbuffered_payload_kind; + wire mapping_cmdLogic_streamUnbuffered_payload_read; + wire mapping_cmdLogic_streamUnbuffered_payload_write; + wire [7:0] mapping_cmdLogic_streamUnbuffered_payload_data; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_valid; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_kind; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_read; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_write; + wire [7:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_data; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_kind; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_read; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_write; + reg [7:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_data; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_valid; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_ready; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_kind; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_read; + wire mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_write; + wire [7:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_data; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rValid; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_kind; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_read; + reg mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_write; + reg [7:0] mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_data; + wire when_Stream_l375_1; + wire ctrl_io_rsp_toStream_valid; + wire ctrl_io_rsp_toStream_ready; + wire [7:0] ctrl_io_rsp_toStream_payload_data; + reg _zz_io_pop_ready; + reg _zz_io_pop_ready_1; + reg mapping_interruptCtrl_cmdIntEnable; + reg mapping_interruptCtrl_rspIntEnable; + wire mapping_interruptCtrl_cmdInt; + wire mapping_interruptCtrl_rspInt; + wire mapping_interruptCtrl_interrupt; + reg _zz_io_config_kind_cpol; + reg _zz_io_config_kind_cpha; + reg [1:0] _zz_io_config_mod; + reg [11:0] _zz_io_config_sclkToggle; + reg [11:0] _zz_io_config_ss_setup; + reg [11:0] _zz_io_config_ss_hold; + reg [11:0] _zz_io_config_ss_disable; + reg [3:0] _zz_io_config_ss_activeHigh; + wire [1:0] _zz_io_config_kind_cpol_1; + + Axi4PeripheralTopLevel_86b7e1c47b934a8a97a62bda8ee6a75d ctrl ( + .io_config_kind_cpol (_zz_io_config_kind_cpol ), //i + .io_config_kind_cpha (_zz_io_config_kind_cpha ), //i + .io_config_sclkToggle (_zz_io_config_sclkToggle[11:0] ), //i + .io_config_mod (_zz_io_config_mod[1:0] ), //i + .io_config_ss_activeHigh (_zz_io_config_ss_activeHigh[3:0] ), //i + .io_config_ss_setup (_zz_io_config_ss_setup[11:0] ), //i + .io_config_ss_hold (_zz_io_config_ss_hold[11:0] ), //i + .io_config_ss_disable (_zz_io_config_ss_disable[11:0] ), //i + .io_cmd_valid (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_valid ), //i + .io_cmd_ready (ctrl_io_cmd_ready ), //o + .io_cmd_payload_kind (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_kind ), //i + .io_cmd_payload_read (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_read ), //i + .io_cmd_payload_write (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_write ), //i + .io_cmd_payload_data (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_data[7:0]), //i + .io_rsp_valid (ctrl_io_rsp_valid ), //o + .io_rsp_payload_data (ctrl_io_rsp_payload_data[7:0] ), //o + .io_spi_sclk_write (ctrl_io_spi_sclk_write ), //o + .io_spi_data_0_writeEnable (ctrl_io_spi_data_0_writeEnable ), //o + .io_spi_data_0_read (io_spi_data_0_read ), //i + .io_spi_data_0_write (ctrl_io_spi_data_0_write ), //o + .io_spi_data_1_writeEnable (ctrl_io_spi_data_1_writeEnable ), //o + .io_spi_data_1_read (io_spi_data_1_read ), //i + .io_spi_data_1_write (ctrl_io_spi_data_1_write ), //o + .io_spi_data_2_writeEnable (ctrl_io_spi_data_2_writeEnable ), //o + .io_spi_data_2_read (io_spi_data_2_read ), //i + .io_spi_data_2_write (ctrl_io_spi_data_2_write ), //o + .io_spi_data_3_writeEnable (ctrl_io_spi_data_3_writeEnable ), //o + .io_spi_data_3_read (io_spi_data_3_read ), //i + .io_spi_data_3_write (ctrl_io_spi_data_3_write ), //o + .io_spi_ss (ctrl_io_spi_ss[3:0] ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralStreamFifo_2_86b7e1c47b934a8a97a62bda8ee6a75d mapping_cmdLogic_streamUnbuffered_queueWithAvailability ( + .io_push_valid (mapping_cmdLogic_streamUnbuffered_valid ), //i + .io_push_ready (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_push_ready ), //o + .io_push_payload_kind (mapping_cmdLogic_streamUnbuffered_payload_kind ), //i + .io_push_payload_read (mapping_cmdLogic_streamUnbuffered_payload_read ), //i + .io_push_payload_write (mapping_cmdLogic_streamUnbuffered_payload_write ), //i + .io_push_payload_data (mapping_cmdLogic_streamUnbuffered_payload_data[7:0] ), //i + .io_pop_valid (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_valid ), //o + .io_pop_ready (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN ), //i + .io_pop_payload_kind (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_kind ), //o + .io_pop_payload_read (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_read ), //o + .io_pop_payload_write (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_write ), //o + .io_pop_payload_data (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_data[7:0]), //o + .io_flush (1'b0 ), //i + .io_occupancy (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_occupancy[8:0] ), //o + .io_availability (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_availability[8:0] ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralStreamFifo_3_86b7e1c47b934a8a97a62bda8ee6a75d ctrl_io_rsp_queueWithOccupancy ( + .io_push_valid (ctrl_io_rsp_toStream_valid ), //i + .io_push_ready (ctrl_io_rsp_queueWithOccupancy_io_push_ready ), //o + .io_push_payload_data (ctrl_io_rsp_toStream_payload_data[7:0] ), //i + .io_pop_valid (ctrl_io_rsp_queueWithOccupancy_io_pop_valid ), //o + .io_pop_ready (ctrl_io_rsp_queueWithOccupancy_io_pop_ready ), //i + .io_pop_payload_data (ctrl_io_rsp_queueWithOccupancy_io_pop_payload_data[7:0]), //o + .io_flush (1'b0 ), //i + .io_occupancy (ctrl_io_rsp_queueWithOccupancy_io_occupancy[8:0] ), //o + .io_availability (ctrl_io_rsp_queueWithOccupancy_io_availability[8:0] ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + assign factory_readErrorFlag = 1'b0; + assign factory_writeErrorFlag = 1'b0; + assign factory_readHaltTrigger = 1'b0; + assign factory_writeHaltTrigger = 1'b0; + assign _zz_factory_rsp_ready = (! (factory_readHaltTrigger || factory_writeHaltTrigger)); + assign factory_rsp_ready = (_zz_factory_rsp_ready_1 && _zz_factory_rsp_ready); + always @(*) begin + _zz_factory_rsp_ready_1 = io_ctrl_rsp_ready; + if(when_Stream_l375) begin + _zz_factory_rsp_ready_1 = 1'b1; + end + end + + assign when_Stream_l375 = (! _zz_io_ctrl_rsp_valid); + assign _zz_io_ctrl_rsp_valid = _zz_io_ctrl_rsp_valid_1; + assign io_ctrl_rsp_valid = _zz_io_ctrl_rsp_valid; + assign io_ctrl_rsp_payload_last = _zz_io_ctrl_rsp_payload_last; + assign io_ctrl_rsp_payload_fragment_opcode = _zz_io_ctrl_rsp_payload_fragment_opcode; + assign io_ctrl_rsp_payload_fragment_data = _zz_io_ctrl_rsp_payload_fragment_data; + assign io_ctrl_rsp_payload_fragment_context = _zz_io_ctrl_rsp_payload_fragment_context; + assign factory_askWrite = (io_ctrl_cmd_valid && (io_ctrl_cmd_payload_fragment_opcode == 1'b1)); + assign factory_askRead = (io_ctrl_cmd_valid && (io_ctrl_cmd_payload_fragment_opcode == 1'b0)); + assign io_ctrl_cmd_fire = (io_ctrl_cmd_valid && io_ctrl_cmd_ready); + assign factory_doWrite = (io_ctrl_cmd_fire && (io_ctrl_cmd_payload_fragment_opcode == 1'b1)); + assign factory_doRead = (io_ctrl_cmd_fire && (io_ctrl_cmd_payload_fragment_opcode == 1'b0)); + assign factory_rsp_valid = io_ctrl_cmd_valid; + assign io_ctrl_cmd_ready = factory_rsp_ready; + assign factory_rsp_payload_last = 1'b1; + assign when_BmbSlaveFactory_l33 = (factory_doWrite && factory_writeErrorFlag); + always @(*) begin + if(when_BmbSlaveFactory_l33) begin + factory_rsp_payload_fragment_opcode = 1'b1; + end else begin + if(when_BmbSlaveFactory_l35) begin + factory_rsp_payload_fragment_opcode = 1'b1; + end else begin + factory_rsp_payload_fragment_opcode = 1'b0; + end + end + end + + assign when_BmbSlaveFactory_l35 = (factory_doRead && factory_readErrorFlag); + always @(*) begin + factory_rsp_payload_fragment_data = 32'h0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h0 : begin + factory_rsp_payload_fragment_data[31 : 31] = (! ctrl_io_rsp_queueWithOccupancy_io_pop_valid); + factory_rsp_payload_fragment_data[7 : 0] = ctrl_io_rsp_queueWithOccupancy_io_pop_payload_data; + end + 12'h004 : begin + factory_rsp_payload_fragment_data[8 : 0] = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_availability; + factory_rsp_payload_fragment_data[24 : 16] = ctrl_io_rsp_queueWithOccupancy_io_occupancy; + end + 12'h00c : begin + factory_rsp_payload_fragment_data[16 : 16] = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_valid; + factory_rsp_payload_fragment_data[0 : 0] = mapping_interruptCtrl_cmdIntEnable; + factory_rsp_payload_fragment_data[1 : 1] = mapping_interruptCtrl_rspIntEnable; + factory_rsp_payload_fragment_data[8 : 8] = mapping_interruptCtrl_cmdInt; + factory_rsp_payload_fragment_data[9 : 9] = mapping_interruptCtrl_rspInt; + end + 12'h058 : begin + factory_rsp_payload_fragment_data[7 : 0] = ctrl_io_rsp_queueWithOccupancy_io_pop_payload_data; + end + default : begin + end + endcase + end + + assign factory_rsp_payload_fragment_context = io_ctrl_cmd_payload_fragment_context; + always @(*) begin + mapping_cmdLogic_doRegular = 1'b0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h0 : begin + if(factory_doWrite) begin + mapping_cmdLogic_doRegular = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + mapping_cmdLogic_doWriteLarge = 1'b0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h050 : begin + if(factory_doWrite) begin + mapping_cmdLogic_doWriteLarge = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + mapping_cmdLogic_doReadWriteLarge = 1'b0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h054 : begin + if(factory_doWrite) begin + mapping_cmdLogic_doReadWriteLarge = 1'b1; + end + end + default : begin + end + endcase + end + + assign mapping_cmdLogic_streamUnbuffered_valid = ((mapping_cmdLogic_doRegular || mapping_cmdLogic_doWriteLarge) || mapping_cmdLogic_doReadWriteLarge); + assign mapping_cmdLogic_streamUnbuffered_payload_write = (((mapping_cmdLogic_doRegular && mapping_cmdLogic_writeData[8]) || mapping_cmdLogic_doWriteLarge) || mapping_cmdLogic_doReadWriteLarge); + assign mapping_cmdLogic_streamUnbuffered_payload_read = ((mapping_cmdLogic_doRegular && mapping_cmdLogic_writeData[9]) || mapping_cmdLogic_doReadWriteLarge); + assign mapping_cmdLogic_streamUnbuffered_payload_kind = (mapping_cmdLogic_doRegular && mapping_cmdLogic_writeData[11]); + assign mapping_cmdLogic_streamUnbuffered_payload_data = mapping_cmdLogic_writeData[7:0]; + assign mapping_cmdLogic_streamUnbuffered_ready = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_push_ready; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_valid = (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_valid || (! mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN)); + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_kind = (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN ? mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_kind : mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_kind); + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_read = (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN ? mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_read : mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_read); + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_write = (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN ? mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_write : mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_write); + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_data = (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN ? mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_data : mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_data); + always @(*) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_ready; + if(when_Stream_l375_1) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready = 1'b1; + end + end + + assign when_Stream_l375_1 = (! mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_valid); + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_valid = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rValid; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_kind = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_kind; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_read = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_read; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_write = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_write; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_payload_data = mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_data; + assign mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_m2sPipe_ready = ctrl_io_cmd_ready; + assign ctrl_io_rsp_toStream_valid = ctrl_io_rsp_valid; + assign ctrl_io_rsp_toStream_payload_data = ctrl_io_rsp_payload_data; + assign ctrl_io_rsp_toStream_ready = ctrl_io_rsp_queueWithOccupancy_io_push_ready; + always @(*) begin + _zz_io_pop_ready = 1'b0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h0 : begin + if(factory_doRead) begin + _zz_io_pop_ready = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + _zz_io_pop_ready_1 = 1'b0; + case(io_ctrl_cmd_payload_fragment_address) + 12'h058 : begin + if(factory_doRead) begin + _zz_io_pop_ready_1 = 1'b1; + end + end + default : begin + end + endcase + end + + assign ctrl_io_rsp_queueWithOccupancy_io_pop_ready = (_zz_io_pop_ready || _zz_io_pop_ready_1); + assign mapping_interruptCtrl_cmdInt = (mapping_interruptCtrl_cmdIntEnable && (! mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_valid)); + assign mapping_interruptCtrl_rspInt = (mapping_interruptCtrl_rspIntEnable && ctrl_io_rsp_queueWithOccupancy_io_pop_valid); + assign mapping_interruptCtrl_interrupt = (mapping_interruptCtrl_rspInt || mapping_interruptCtrl_cmdInt); + assign io_spi_sclk_write = ctrl_io_spi_sclk_write; + assign io_spi_data_0_writeEnable = ctrl_io_spi_data_0_writeEnable; + assign io_spi_data_0_write = ctrl_io_spi_data_0_write; + assign io_spi_data_1_writeEnable = ctrl_io_spi_data_1_writeEnable; + assign io_spi_data_1_write = ctrl_io_spi_data_1_write; + assign io_spi_data_2_writeEnable = ctrl_io_spi_data_2_writeEnable; + assign io_spi_data_2_write = ctrl_io_spi_data_2_write; + assign io_spi_data_3_writeEnable = ctrl_io_spi_data_3_writeEnable; + assign io_spi_data_3_write = ctrl_io_spi_data_3_write; + assign io_spi_ss = ctrl_io_spi_ss; + assign system_spi_0_io_interrupt_source = mapping_interruptCtrl_interrupt; + assign mapping_cmdLogic_writeData = io_ctrl_cmd_payload_fragment_data[31 : 0]; + assign _zz_io_config_kind_cpol_1 = io_ctrl_cmd_payload_fragment_data[1 : 0]; + always @(posedge clk) begin + if(reset) begin + _zz_io_ctrl_rsp_valid_1 <= 1'b0; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN <= 1'b1; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rValid <= 1'b0; + mapping_interruptCtrl_cmdIntEnable <= 1'b0; + mapping_interruptCtrl_rspIntEnable <= 1'b0; + _zz_io_config_ss_activeHigh <= 4'b0000; + end else begin + if(_zz_factory_rsp_ready_1) begin + _zz_io_ctrl_rsp_valid_1 <= (factory_rsp_valid && _zz_factory_rsp_ready); + end + if(mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_valid) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN <= 1'b0; + end + if(mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN <= 1'b1; + end + if(mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rValid <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_valid; + end + case(io_ctrl_cmd_payload_fragment_address) + 12'h00c : begin + if(factory_doWrite) begin + mapping_interruptCtrl_cmdIntEnable <= io_ctrl_cmd_payload_fragment_data[0]; + mapping_interruptCtrl_rspIntEnable <= io_ctrl_cmd_payload_fragment_data[1]; + end + end + 12'h030 : begin + if(factory_doWrite) begin + _zz_io_config_ss_activeHigh <= io_ctrl_cmd_payload_fragment_data[3 : 0]; + end + end + default : begin + end + endcase + end + end + + always @(posedge clk) begin + if(_zz_factory_rsp_ready_1) begin + _zz_io_ctrl_rsp_payload_last <= factory_rsp_payload_last; + _zz_io_ctrl_rsp_payload_fragment_opcode <= factory_rsp_payload_fragment_opcode; + _zz_io_ctrl_rsp_payload_fragment_data <= factory_rsp_payload_fragment_data; + _zz_io_ctrl_rsp_payload_fragment_context <= factory_rsp_payload_fragment_context; + end + if(mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rValidN) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_kind <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_kind; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_read <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_read; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_write <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_write; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_rData_data <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_payload_data; + end + if(mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_ready) begin + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_kind <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_kind; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_read <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_read; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_write <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_write; + mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_rData_data <= mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_pop_s2mPipe_payload_data; + end + case(io_ctrl_cmd_payload_fragment_address) + 12'h008 : begin + if(factory_doWrite) begin + _zz_io_config_kind_cpol <= _zz_io_config_kind_cpol_1[0]; + _zz_io_config_kind_cpha <= _zz_io_config_kind_cpol_1[1]; + _zz_io_config_mod <= io_ctrl_cmd_payload_fragment_data[5 : 4]; + end + end + 12'h020 : begin + if(factory_doWrite) begin + _zz_io_config_sclkToggle <= io_ctrl_cmd_payload_fragment_data[11 : 0]; + end + end + 12'h024 : begin + if(factory_doWrite) begin + _zz_io_config_ss_setup <= io_ctrl_cmd_payload_fragment_data[11 : 0]; + end + end + 12'h028 : begin + if(factory_doWrite) begin + _zz_io_config_ss_hold <= io_ctrl_cmd_payload_fragment_data[11 : 0]; + end + end + 12'h02c : begin + if(factory_doWrite) begin + _zz_io_config_ss_disable <= io_ctrl_cmd_payload_fragment_data[11 : 0]; + end + end + default : begin + end + endcase + end + + +endmodule + +module Axi4PeripheralBmbUartCtrl_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_bus_cmd_valid, + output wire io_bus_cmd_ready, + input wire io_bus_cmd_payload_last, + input wire [0:0] io_bus_cmd_payload_fragment_opcode, + input wire [5:0] io_bus_cmd_payload_fragment_address, + input wire [1:0] io_bus_cmd_payload_fragment_length, + input wire [31:0] io_bus_cmd_payload_fragment_data, + input wire [2:0] io_bus_cmd_payload_fragment_context, + output wire io_bus_rsp_valid, + input wire io_bus_rsp_ready, + output wire io_bus_rsp_payload_last, + output wire [0:0] io_bus_rsp_payload_fragment_opcode, + output wire [31:0] io_bus_rsp_payload_fragment_data, + output wire [2:0] io_bus_rsp_payload_fragment_context, + output wire io_uart_txd, + input wire io_uart_rxd, + output wire system_uart_0_io_interrupt_source, + input wire clk, + input wire reset +); + localparam Axi4PeripheralUartStopType_ONE = 1'd0; + localparam Axi4PeripheralUartStopType_TWO = 1'd1; + localparam Axi4PeripheralUartParityType_NONE = 2'd0; + localparam Axi4PeripheralUartParityType_EVEN = 2'd1; + localparam Axi4PeripheralUartParityType_ODD = 2'd2; + + reg uartCtrl_io_read_queueWithOccupancy_io_pop_ready; + wire uartCtrl_io_write_ready; + wire uartCtrl_io_read_valid; + wire [7:0] uartCtrl_io_read_payload; + wire uartCtrl_io_uart_txd; + wire uartCtrl_io_readError; + wire uartCtrl_io_readBreak; + wire bridge_write_streamUnbuffered_queueWithOccupancy_io_push_ready; + wire bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_valid; + wire [7:0] bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_payload; + wire [7:0] bridge_write_streamUnbuffered_queueWithOccupancy_io_occupancy; + wire [7:0] bridge_write_streamUnbuffered_queueWithOccupancy_io_availability; + wire uartCtrl_io_read_queueWithOccupancy_io_push_ready; + wire uartCtrl_io_read_queueWithOccupancy_io_pop_valid; + wire [7:0] uartCtrl_io_read_queueWithOccupancy_io_pop_payload; + wire [7:0] uartCtrl_io_read_queueWithOccupancy_io_occupancy; + wire [7:0] uartCtrl_io_read_queueWithOccupancy_io_availability; + wire [0:0] _zz_bridge_misc_readError; + wire [0:0] _zz_bridge_misc_readOverflowError; + wire [0:0] _zz_bridge_misc_breakDetected; + wire [0:0] _zz_bridge_misc_doBreak; + wire [0:0] _zz_bridge_misc_doBreak_1; + wire [7:0] _zz_busCtrl_rsp_payload_fragment_data; + wire busCtrl_readErrorFlag; + wire busCtrl_writeErrorFlag; + wire busCtrl_readHaltTrigger; + wire busCtrl_writeHaltTrigger; + wire busCtrl_rsp_valid; + wire busCtrl_rsp_ready; + wire busCtrl_rsp_payload_last; + reg [0:0] busCtrl_rsp_payload_fragment_opcode; + reg [31:0] busCtrl_rsp_payload_fragment_data; + wire [2:0] busCtrl_rsp_payload_fragment_context; + wire _zz_busCtrl_rsp_ready; + reg _zz_busCtrl_rsp_ready_1; + wire _zz_io_bus_rsp_valid; + reg _zz_io_bus_rsp_valid_1; + reg _zz_io_bus_rsp_payload_last; + reg [0:0] _zz_io_bus_rsp_payload_fragment_opcode; + reg [31:0] _zz_io_bus_rsp_payload_fragment_data; + reg [2:0] _zz_io_bus_rsp_payload_fragment_context; + wire when_Stream_l375; + wire busCtrl_askWrite; + wire busCtrl_askRead; + wire io_bus_cmd_fire; + wire busCtrl_doWrite; + wire busCtrl_doRead; + wire when_BmbSlaveFactory_l33; + wire when_BmbSlaveFactory_l35; + wire bridge_busCtrlWrapped_readErrorFlag; + wire bridge_busCtrlWrapped_writeErrorFlag; + reg [2:0] bridge_uartConfigReg_frame_dataLength; + reg [0:0] bridge_uartConfigReg_frame_stop; + reg [1:0] bridge_uartConfigReg_frame_parity; + reg [19:0] bridge_uartConfigReg_clockDivider; + reg _zz_bridge_write_streamUnbuffered_valid; + wire bridge_write_streamUnbuffered_valid; + wire bridge_write_streamUnbuffered_ready; + wire [7:0] bridge_write_streamUnbuffered_payload; + reg bridge_read_streamBreaked_valid; + reg bridge_read_streamBreaked_ready; + wire [7:0] bridge_read_streamBreaked_payload; + reg bridge_interruptCtrl_writeIntEnable; + reg bridge_interruptCtrl_readIntEnable; + wire bridge_interruptCtrl_readInt; + wire bridge_interruptCtrl_writeInt; + wire bridge_interruptCtrl_interrupt; + reg bridge_misc_readError; + reg when_BusSlaveFactory_l341; + wire when_BusSlaveFactory_l347; + reg bridge_misc_readOverflowError; + reg when_BusSlaveFactory_l341_1; + wire when_BusSlaveFactory_l347_1; + wire uartCtrl_io_read_isStall; + reg bridge_misc_breakDetected; + reg uartCtrl_io_readBreak_regNext; + wire when_UartCtrl_l155; + reg when_BusSlaveFactory_l341_2; + wire when_BusSlaveFactory_l347_2; + reg bridge_misc_doBreak; + reg when_BusSlaveFactory_l377; + wire when_BusSlaveFactory_l379; + reg when_BusSlaveFactory_l341_3; + wire when_BusSlaveFactory_l347_3; + wire [1:0] _zz_bridge_uartConfigReg_frame_parity; + wire [0:0] _zz_bridge_uartConfigReg_frame_stop; + wire when_BmbSlaveFactory_l77; + `ifndef SYNTHESIS + reg [23:0] bridge_uartConfigReg_frame_stop_string; + reg [31:0] bridge_uartConfigReg_frame_parity_string; + reg [31:0] _zz_bridge_uartConfigReg_frame_parity_string; + reg [23:0] _zz_bridge_uartConfigReg_frame_stop_string; + `endif + + + assign _zz_bridge_misc_readError = 1'b0; + assign _zz_bridge_misc_readOverflowError = 1'b0; + assign _zz_bridge_misc_breakDetected = 1'b0; + assign _zz_bridge_misc_doBreak = 1'b1; + assign _zz_bridge_misc_doBreak_1 = 1'b0; + assign _zz_busCtrl_rsp_payload_fragment_data = (8'h80 - bridge_write_streamUnbuffered_queueWithOccupancy_io_occupancy); + Axi4PeripheralUartCtrl_86b7e1c47b934a8a97a62bda8ee6a75d uartCtrl ( + .io_config_frame_dataLength (bridge_uartConfigReg_frame_dataLength[2:0] ), //i + .io_config_frame_stop (bridge_uartConfigReg_frame_stop ), //i + .io_config_frame_parity (bridge_uartConfigReg_frame_parity[1:0] ), //i + .io_config_clockDivider (bridge_uartConfigReg_clockDivider[19:0] ), //i + .io_write_valid (bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_valid ), //i + .io_write_ready (uartCtrl_io_write_ready ), //o + .io_write_payload (bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_payload[7:0]), //i + .io_read_valid (uartCtrl_io_read_valid ), //o + .io_read_ready (uartCtrl_io_read_queueWithOccupancy_io_push_ready ), //i + .io_read_payload (uartCtrl_io_read_payload[7:0] ), //o + .io_uart_txd (uartCtrl_io_uart_txd ), //o + .io_uart_rxd (io_uart_rxd ), //i + .io_readError (uartCtrl_io_readError ), //o + .io_writeBreak (bridge_misc_doBreak ), //i + .io_readBreak (uartCtrl_io_readBreak ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralStreamFifo_86b7e1c47b934a8a97a62bda8ee6a75d bridge_write_streamUnbuffered_queueWithOccupancy ( + .io_push_valid (bridge_write_streamUnbuffered_valid ), //i + .io_push_ready (bridge_write_streamUnbuffered_queueWithOccupancy_io_push_ready ), //o + .io_push_payload (bridge_write_streamUnbuffered_payload[7:0] ), //i + .io_pop_valid (bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_valid ), //o + .io_pop_ready (uartCtrl_io_write_ready ), //i + .io_pop_payload (bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_payload[7:0] ), //o + .io_flush (1'b0 ), //i + .io_occupancy (bridge_write_streamUnbuffered_queueWithOccupancy_io_occupancy[7:0] ), //o + .io_availability (bridge_write_streamUnbuffered_queueWithOccupancy_io_availability[7:0]), //o + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralStreamFifo_86b7e1c47b934a8a97a62bda8ee6a75d uartCtrl_io_read_queueWithOccupancy ( + .io_push_valid (uartCtrl_io_read_valid ), //i + .io_push_ready (uartCtrl_io_read_queueWithOccupancy_io_push_ready ), //o + .io_push_payload (uartCtrl_io_read_payload[7:0] ), //i + .io_pop_valid (uartCtrl_io_read_queueWithOccupancy_io_pop_valid ), //o + .io_pop_ready (uartCtrl_io_read_queueWithOccupancy_io_pop_ready ), //i + .io_pop_payload (uartCtrl_io_read_queueWithOccupancy_io_pop_payload[7:0] ), //o + .io_flush (1'b0 ), //i + .io_occupancy (uartCtrl_io_read_queueWithOccupancy_io_occupancy[7:0] ), //o + .io_availability (uartCtrl_io_read_queueWithOccupancy_io_availability[7:0]), //o + .clk (clk ), //i + .reset (reset ) //i + ); + `ifndef SYNTHESIS + always @(*) begin + case(bridge_uartConfigReg_frame_stop) + Axi4PeripheralUartStopType_ONE : bridge_uartConfigReg_frame_stop_string = "ONE"; + Axi4PeripheralUartStopType_TWO : bridge_uartConfigReg_frame_stop_string = "TWO"; + default : bridge_uartConfigReg_frame_stop_string = "???"; + endcase + end + always @(*) begin + case(bridge_uartConfigReg_frame_parity) + Axi4PeripheralUartParityType_NONE : bridge_uartConfigReg_frame_parity_string = "NONE"; + Axi4PeripheralUartParityType_EVEN : bridge_uartConfigReg_frame_parity_string = "EVEN"; + Axi4PeripheralUartParityType_ODD : bridge_uartConfigReg_frame_parity_string = "ODD "; + default : bridge_uartConfigReg_frame_parity_string = "????"; + endcase + end + always @(*) begin + case(_zz_bridge_uartConfigReg_frame_parity) + Axi4PeripheralUartParityType_NONE : _zz_bridge_uartConfigReg_frame_parity_string = "NONE"; + Axi4PeripheralUartParityType_EVEN : _zz_bridge_uartConfigReg_frame_parity_string = "EVEN"; + Axi4PeripheralUartParityType_ODD : _zz_bridge_uartConfigReg_frame_parity_string = "ODD "; + default : _zz_bridge_uartConfigReg_frame_parity_string = "????"; + endcase + end + always @(*) begin + case(_zz_bridge_uartConfigReg_frame_stop) + Axi4PeripheralUartStopType_ONE : _zz_bridge_uartConfigReg_frame_stop_string = "ONE"; + Axi4PeripheralUartStopType_TWO : _zz_bridge_uartConfigReg_frame_stop_string = "TWO"; + default : _zz_bridge_uartConfigReg_frame_stop_string = "???"; + endcase + end + `endif + + assign io_uart_txd = uartCtrl_io_uart_txd; + assign busCtrl_readErrorFlag = 1'b0; + assign busCtrl_writeErrorFlag = 1'b0; + assign busCtrl_readHaltTrigger = 1'b0; + assign busCtrl_writeHaltTrigger = 1'b0; + assign _zz_busCtrl_rsp_ready = (! (busCtrl_readHaltTrigger || busCtrl_writeHaltTrigger)); + assign busCtrl_rsp_ready = (_zz_busCtrl_rsp_ready_1 && _zz_busCtrl_rsp_ready); + always @(*) begin + _zz_busCtrl_rsp_ready_1 = io_bus_rsp_ready; + if(when_Stream_l375) begin + _zz_busCtrl_rsp_ready_1 = 1'b1; + end + end + + assign when_Stream_l375 = (! _zz_io_bus_rsp_valid); + assign _zz_io_bus_rsp_valid = _zz_io_bus_rsp_valid_1; + assign io_bus_rsp_valid = _zz_io_bus_rsp_valid; + assign io_bus_rsp_payload_last = _zz_io_bus_rsp_payload_last; + assign io_bus_rsp_payload_fragment_opcode = _zz_io_bus_rsp_payload_fragment_opcode; + assign io_bus_rsp_payload_fragment_data = _zz_io_bus_rsp_payload_fragment_data; + assign io_bus_rsp_payload_fragment_context = _zz_io_bus_rsp_payload_fragment_context; + assign busCtrl_askWrite = (io_bus_cmd_valid && (io_bus_cmd_payload_fragment_opcode == 1'b1)); + assign busCtrl_askRead = (io_bus_cmd_valid && (io_bus_cmd_payload_fragment_opcode == 1'b0)); + assign io_bus_cmd_fire = (io_bus_cmd_valid && io_bus_cmd_ready); + assign busCtrl_doWrite = (io_bus_cmd_fire && (io_bus_cmd_payload_fragment_opcode == 1'b1)); + assign busCtrl_doRead = (io_bus_cmd_fire && (io_bus_cmd_payload_fragment_opcode == 1'b0)); + assign busCtrl_rsp_valid = io_bus_cmd_valid; + assign io_bus_cmd_ready = busCtrl_rsp_ready; + assign busCtrl_rsp_payload_last = 1'b1; + assign when_BmbSlaveFactory_l33 = (busCtrl_doWrite && busCtrl_writeErrorFlag); + always @(*) begin + if(when_BmbSlaveFactory_l33) begin + busCtrl_rsp_payload_fragment_opcode = 1'b1; + end else begin + if(when_BmbSlaveFactory_l35) begin + busCtrl_rsp_payload_fragment_opcode = 1'b1; + end else begin + busCtrl_rsp_payload_fragment_opcode = 1'b0; + end + end + end + + assign when_BmbSlaveFactory_l35 = (busCtrl_doRead && busCtrl_readErrorFlag); + always @(*) begin + busCtrl_rsp_payload_fragment_data = 32'h0; + case(io_bus_cmd_payload_fragment_address) + 6'h0 : begin + busCtrl_rsp_payload_fragment_data[16 : 16] = (bridge_read_streamBreaked_valid ^ 1'b0); + busCtrl_rsp_payload_fragment_data[7 : 0] = bridge_read_streamBreaked_payload; + end + 6'h04 : begin + busCtrl_rsp_payload_fragment_data[23 : 16] = _zz_busCtrl_rsp_payload_fragment_data; + busCtrl_rsp_payload_fragment_data[15 : 15] = bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_valid; + busCtrl_rsp_payload_fragment_data[31 : 24] = uartCtrl_io_read_queueWithOccupancy_io_occupancy; + busCtrl_rsp_payload_fragment_data[0 : 0] = bridge_interruptCtrl_writeIntEnable; + busCtrl_rsp_payload_fragment_data[1 : 1] = bridge_interruptCtrl_readIntEnable; + busCtrl_rsp_payload_fragment_data[8 : 8] = bridge_interruptCtrl_writeInt; + busCtrl_rsp_payload_fragment_data[9 : 9] = bridge_interruptCtrl_readInt; + end + 6'h10 : begin + busCtrl_rsp_payload_fragment_data[0 : 0] = bridge_misc_readError; + busCtrl_rsp_payload_fragment_data[1 : 1] = bridge_misc_readOverflowError; + busCtrl_rsp_payload_fragment_data[8 : 8] = uartCtrl_io_readBreak; + busCtrl_rsp_payload_fragment_data[9 : 9] = bridge_misc_breakDetected; + end + default : begin + end + endcase + end + + assign busCtrl_rsp_payload_fragment_context = io_bus_cmd_payload_fragment_context; + assign bridge_busCtrlWrapped_readErrorFlag = 1'b0; + assign bridge_busCtrlWrapped_writeErrorFlag = 1'b0; + always @(*) begin + _zz_bridge_write_streamUnbuffered_valid = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h0 : begin + if(busCtrl_doWrite) begin + _zz_bridge_write_streamUnbuffered_valid = 1'b1; + end + end + default : begin + end + endcase + end + + assign bridge_write_streamUnbuffered_valid = _zz_bridge_write_streamUnbuffered_valid; + assign bridge_write_streamUnbuffered_payload = io_bus_cmd_payload_fragment_data[7 : 0]; + assign bridge_write_streamUnbuffered_ready = bridge_write_streamUnbuffered_queueWithOccupancy_io_push_ready; + always @(*) begin + bridge_read_streamBreaked_valid = uartCtrl_io_read_queueWithOccupancy_io_pop_valid; + if(uartCtrl_io_readBreak) begin + bridge_read_streamBreaked_valid = 1'b0; + end + end + + always @(*) begin + uartCtrl_io_read_queueWithOccupancy_io_pop_ready = bridge_read_streamBreaked_ready; + if(uartCtrl_io_readBreak) begin + uartCtrl_io_read_queueWithOccupancy_io_pop_ready = 1'b1; + end + end + + assign bridge_read_streamBreaked_payload = uartCtrl_io_read_queueWithOccupancy_io_pop_payload; + always @(*) begin + bridge_read_streamBreaked_ready = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h0 : begin + if(busCtrl_doRead) begin + bridge_read_streamBreaked_ready = 1'b1; + end + end + default : begin + end + endcase + end + + assign bridge_interruptCtrl_readInt = (bridge_interruptCtrl_readIntEnable && bridge_read_streamBreaked_valid); + assign bridge_interruptCtrl_writeInt = (bridge_interruptCtrl_writeIntEnable && (! bridge_write_streamUnbuffered_queueWithOccupancy_io_pop_valid)); + assign bridge_interruptCtrl_interrupt = (bridge_interruptCtrl_readInt || bridge_interruptCtrl_writeInt); + always @(*) begin + when_BusSlaveFactory_l341 = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h10 : begin + if(busCtrl_doWrite) begin + when_BusSlaveFactory_l341 = 1'b1; + end + end + default : begin + end + endcase + end + + assign when_BusSlaveFactory_l347 = io_bus_cmd_payload_fragment_data[0]; + always @(*) begin + when_BusSlaveFactory_l341_1 = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h10 : begin + if(busCtrl_doWrite) begin + when_BusSlaveFactory_l341_1 = 1'b1; + end + end + default : begin + end + endcase + end + + assign when_BusSlaveFactory_l347_1 = io_bus_cmd_payload_fragment_data[1]; + assign uartCtrl_io_read_isStall = (uartCtrl_io_read_valid && (! uartCtrl_io_read_queueWithOccupancy_io_push_ready)); + assign when_UartCtrl_l155 = (uartCtrl_io_readBreak && (! uartCtrl_io_readBreak_regNext)); + always @(*) begin + when_BusSlaveFactory_l341_2 = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h10 : begin + if(busCtrl_doWrite) begin + when_BusSlaveFactory_l341_2 = 1'b1; + end + end + default : begin + end + endcase + end + + assign when_BusSlaveFactory_l347_2 = io_bus_cmd_payload_fragment_data[9]; + always @(*) begin + when_BusSlaveFactory_l377 = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h10 : begin + if(busCtrl_doWrite) begin + when_BusSlaveFactory_l377 = 1'b1; + end + end + default : begin + end + endcase + end + + assign when_BusSlaveFactory_l379 = io_bus_cmd_payload_fragment_data[10]; + always @(*) begin + when_BusSlaveFactory_l341_3 = 1'b0; + case(io_bus_cmd_payload_fragment_address) + 6'h10 : begin + if(busCtrl_doWrite) begin + when_BusSlaveFactory_l341_3 = 1'b1; + end + end + default : begin + end + endcase + end + + assign when_BusSlaveFactory_l347_3 = io_bus_cmd_payload_fragment_data[11]; + assign system_uart_0_io_interrupt_source = bridge_interruptCtrl_interrupt; + assign _zz_bridge_uartConfigReg_frame_parity = io_bus_cmd_payload_fragment_data[9 : 8]; + assign _zz_bridge_uartConfigReg_frame_stop = io_bus_cmd_payload_fragment_data[16 : 16]; + assign when_BmbSlaveFactory_l77 = ((io_bus_cmd_payload_fragment_address & (~ 6'h03)) == 6'h08); + always @(posedge clk) begin + if(reset) begin + _zz_io_bus_rsp_valid_1 <= 1'b0; + bridge_uartConfigReg_clockDivider <= 20'h0; + bridge_uartConfigReg_clockDivider <= 20'h0010e; + bridge_uartConfigReg_frame_dataLength <= 3'b111; + bridge_uartConfigReg_frame_parity <= Axi4PeripheralUartParityType_NONE; + bridge_uartConfigReg_frame_stop <= Axi4PeripheralUartStopType_ONE; + bridge_interruptCtrl_writeIntEnable <= 1'b0; + bridge_interruptCtrl_readIntEnable <= 1'b0; + bridge_misc_readError <= 1'b0; + bridge_misc_readOverflowError <= 1'b0; + bridge_misc_breakDetected <= 1'b0; + bridge_misc_doBreak <= 1'b0; + end else begin + if(_zz_busCtrl_rsp_ready_1) begin + _zz_io_bus_rsp_valid_1 <= (busCtrl_rsp_valid && _zz_busCtrl_rsp_ready); + end + if(when_BusSlaveFactory_l341) begin + if(when_BusSlaveFactory_l347) begin + bridge_misc_readError <= _zz_bridge_misc_readError[0]; + end + end + if(uartCtrl_io_readError) begin + bridge_misc_readError <= 1'b1; + end + if(when_BusSlaveFactory_l341_1) begin + if(when_BusSlaveFactory_l347_1) begin + bridge_misc_readOverflowError <= _zz_bridge_misc_readOverflowError[0]; + end + end + if(uartCtrl_io_read_isStall) begin + bridge_misc_readOverflowError <= 1'b1; + end + if(when_UartCtrl_l155) begin + bridge_misc_breakDetected <= 1'b1; + end + if(when_BusSlaveFactory_l341_2) begin + if(when_BusSlaveFactory_l347_2) begin + bridge_misc_breakDetected <= _zz_bridge_misc_breakDetected[0]; + end + end + if(when_BusSlaveFactory_l377) begin + if(when_BusSlaveFactory_l379) begin + bridge_misc_doBreak <= _zz_bridge_misc_doBreak[0]; + end + end + if(when_BusSlaveFactory_l341_3) begin + if(when_BusSlaveFactory_l347_3) begin + bridge_misc_doBreak <= _zz_bridge_misc_doBreak_1[0]; + end + end + case(io_bus_cmd_payload_fragment_address) + 6'h0c : begin + if(busCtrl_doWrite) begin + bridge_uartConfigReg_frame_dataLength <= io_bus_cmd_payload_fragment_data[2 : 0]; + bridge_uartConfigReg_frame_parity <= _zz_bridge_uartConfigReg_frame_parity; + bridge_uartConfigReg_frame_stop <= _zz_bridge_uartConfigReg_frame_stop; + end + end + 6'h04 : begin + if(busCtrl_doWrite) begin + bridge_interruptCtrl_writeIntEnable <= io_bus_cmd_payload_fragment_data[0]; + bridge_interruptCtrl_readIntEnable <= io_bus_cmd_payload_fragment_data[1]; + end + end + default : begin + end + endcase + if(when_BmbSlaveFactory_l77) begin + if(busCtrl_doWrite) begin + bridge_uartConfigReg_clockDivider[19 : 0] <= io_bus_cmd_payload_fragment_data[19 : 0]; + end + end + end + end + + always @(posedge clk) begin + if(_zz_busCtrl_rsp_ready_1) begin + _zz_io_bus_rsp_payload_last <= busCtrl_rsp_payload_last; + _zz_io_bus_rsp_payload_fragment_opcode <= busCtrl_rsp_payload_fragment_opcode; + _zz_io_bus_rsp_payload_fragment_data <= busCtrl_rsp_payload_fragment_data; + _zz_io_bus_rsp_payload_fragment_context <= busCtrl_rsp_payload_fragment_context; + end + uartCtrl_io_readBreak_regNext <= uartCtrl_io_readBreak; + end + + +endmodule + +module Axi4PeripheralBmbDecoder_1_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_input_cmd_valid, + output wire io_input_cmd_ready, + input wire io_input_cmd_payload_last, + input wire [0:0] io_input_cmd_payload_fragment_opcode, + input wire [23:0] io_input_cmd_payload_fragment_address, + input wire [1:0] io_input_cmd_payload_fragment_length, + input wire [31:0] io_input_cmd_payload_fragment_data, + input wire [3:0] io_input_cmd_payload_fragment_mask, + input wire [2:0] io_input_cmd_payload_fragment_context, + output reg io_input_rsp_valid, + input wire io_input_rsp_ready, + output reg io_input_rsp_payload_last, + output reg [0:0] io_input_rsp_payload_fragment_opcode, + output wire [31:0] io_input_rsp_payload_fragment_data, + output reg [2:0] io_input_rsp_payload_fragment_context, + output reg io_outputs_0_cmd_valid, + input wire io_outputs_0_cmd_ready, + output wire io_outputs_0_cmd_payload_last, + output wire [0:0] io_outputs_0_cmd_payload_fragment_opcode, + output wire [23:0] io_outputs_0_cmd_payload_fragment_address, + output wire [1:0] io_outputs_0_cmd_payload_fragment_length, + output wire [31:0] io_outputs_0_cmd_payload_fragment_data, + output wire [3:0] io_outputs_0_cmd_payload_fragment_mask, + output wire [2:0] io_outputs_0_cmd_payload_fragment_context, + input wire io_outputs_0_rsp_valid, + output wire io_outputs_0_rsp_ready, + input wire io_outputs_0_rsp_payload_last, + input wire [0:0] io_outputs_0_rsp_payload_fragment_opcode, + input wire [31:0] io_outputs_0_rsp_payload_fragment_data, + input wire [2:0] io_outputs_0_rsp_payload_fragment_context, + output reg io_outputs_1_cmd_valid, + input wire io_outputs_1_cmd_ready, + output wire io_outputs_1_cmd_payload_last, + output wire [0:0] io_outputs_1_cmd_payload_fragment_opcode, + output wire [23:0] io_outputs_1_cmd_payload_fragment_address, + output wire [1:0] io_outputs_1_cmd_payload_fragment_length, + output wire [31:0] io_outputs_1_cmd_payload_fragment_data, + output wire [3:0] io_outputs_1_cmd_payload_fragment_mask, + output wire [2:0] io_outputs_1_cmd_payload_fragment_context, + input wire io_outputs_1_rsp_valid, + output wire io_outputs_1_rsp_ready, + input wire io_outputs_1_rsp_payload_last, + input wire [0:0] io_outputs_1_rsp_payload_fragment_opcode, + input wire [31:0] io_outputs_1_rsp_payload_fragment_data, + input wire [2:0] io_outputs_1_rsp_payload_fragment_context, + input wire clk, + input wire reset +); + + wire [6:0] _zz_logic_rspPendingCounter; + wire [6:0] _zz_logic_rspPendingCounter_1; + wire [0:0] _zz_logic_rspPendingCounter_2; + wire [6:0] _zz_logic_rspPendingCounter_3; + wire [0:0] _zz_logic_rspPendingCounter_4; + reg _zz_io_input_rsp_payload_last_1; + reg [0:0] _zz_io_input_rsp_payload_fragment_opcode; + reg [31:0] _zz_io_input_rsp_payload_fragment_data; + reg [2:0] _zz_io_input_rsp_payload_fragment_context; + wire logic_input_valid; + reg logic_input_ready; + wire logic_input_payload_last; + wire [0:0] logic_input_payload_fragment_opcode; + wire [23:0] logic_input_payload_fragment_address; + wire [1:0] logic_input_payload_fragment_length; + wire [31:0] logic_input_payload_fragment_data; + wire [3:0] logic_input_payload_fragment_mask; + wire [2:0] logic_input_payload_fragment_context; + wire logic_hitsS0_0; + wire logic_hitsS0_1; + wire logic_noHitS0; + wire _zz_io_outputs_0_cmd_payload_last; + wire _zz_io_outputs_1_cmd_payload_last; + reg [6:0] logic_rspPendingCounter; + wire logic_input_fire; + wire io_input_rsp_fire; + wire logic_cmdWait; + wire when_BmbDecoder_l56; + reg logic_rspHits_0; + reg logic_rspHits_1; + wire logic_rspPending; + wire logic_rspNoHitValid; + reg logic_rspNoHit_doIt; + wire when_BmbDecoder_l60; + wire when_BmbDecoder_l60_1; + reg logic_rspNoHit_singleBeatRsp; + reg [2:0] logic_rspNoHit_context; + wire [0:0] _zz_io_input_rsp_payload_last; + + assign _zz_logic_rspPendingCounter = (logic_rspPendingCounter + _zz_logic_rspPendingCounter_1); + assign _zz_logic_rspPendingCounter_2 = (logic_input_fire && logic_input_payload_last); + assign _zz_logic_rspPendingCounter_1 = {6'd0, _zz_logic_rspPendingCounter_2}; + assign _zz_logic_rspPendingCounter_4 = (io_input_rsp_fire && io_input_rsp_payload_last); + assign _zz_logic_rspPendingCounter_3 = {6'd0, _zz_logic_rspPendingCounter_4}; + always @(*) begin + case(_zz_io_input_rsp_payload_last) + 1'b0 : begin + _zz_io_input_rsp_payload_last_1 = io_outputs_0_rsp_payload_last; + _zz_io_input_rsp_payload_fragment_opcode = io_outputs_0_rsp_payload_fragment_opcode; + _zz_io_input_rsp_payload_fragment_data = io_outputs_0_rsp_payload_fragment_data; + _zz_io_input_rsp_payload_fragment_context = io_outputs_0_rsp_payload_fragment_context; + end + default : begin + _zz_io_input_rsp_payload_last_1 = io_outputs_1_rsp_payload_last; + _zz_io_input_rsp_payload_fragment_opcode = io_outputs_1_rsp_payload_fragment_opcode; + _zz_io_input_rsp_payload_fragment_data = io_outputs_1_rsp_payload_fragment_data; + _zz_io_input_rsp_payload_fragment_context = io_outputs_1_rsp_payload_fragment_context; + end + endcase + end + + assign logic_input_valid = io_input_cmd_valid; + assign io_input_cmd_ready = logic_input_ready; + assign logic_input_payload_last = io_input_cmd_payload_last; + assign logic_input_payload_fragment_opcode = io_input_cmd_payload_fragment_opcode; + assign logic_input_payload_fragment_address = io_input_cmd_payload_fragment_address; + assign logic_input_payload_fragment_length = io_input_cmd_payload_fragment_length; + assign logic_input_payload_fragment_data = io_input_cmd_payload_fragment_data; + assign logic_input_payload_fragment_mask = io_input_cmd_payload_fragment_mask; + assign logic_input_payload_fragment_context = io_input_cmd_payload_fragment_context; + assign logic_noHitS0 = (! (|{logic_hitsS0_1,logic_hitsS0_0})); + assign logic_hitsS0_0 = ((io_input_cmd_payload_fragment_address & (~ 24'h00003f)) == 24'h010000); + always @(*) begin + io_outputs_0_cmd_valid = (logic_input_valid && logic_hitsS0_0); + if(logic_cmdWait) begin + io_outputs_0_cmd_valid = 1'b0; + end + end + + assign _zz_io_outputs_0_cmd_payload_last = logic_input_payload_last; + assign io_outputs_0_cmd_payload_last = _zz_io_outputs_0_cmd_payload_last; + assign io_outputs_0_cmd_payload_fragment_opcode = logic_input_payload_fragment_opcode; + assign io_outputs_0_cmd_payload_fragment_address = logic_input_payload_fragment_address; + assign io_outputs_0_cmd_payload_fragment_length = logic_input_payload_fragment_length; + assign io_outputs_0_cmd_payload_fragment_data = logic_input_payload_fragment_data; + assign io_outputs_0_cmd_payload_fragment_mask = logic_input_payload_fragment_mask; + assign io_outputs_0_cmd_payload_fragment_context = logic_input_payload_fragment_context; + assign logic_hitsS0_1 = ((io_input_cmd_payload_fragment_address & (~ 24'h000fff)) == 24'h030000); + always @(*) begin + io_outputs_1_cmd_valid = (logic_input_valid && logic_hitsS0_1); + if(logic_cmdWait) begin + io_outputs_1_cmd_valid = 1'b0; + end + end + + assign _zz_io_outputs_1_cmd_payload_last = logic_input_payload_last; + assign io_outputs_1_cmd_payload_last = _zz_io_outputs_1_cmd_payload_last; + assign io_outputs_1_cmd_payload_fragment_opcode = logic_input_payload_fragment_opcode; + assign io_outputs_1_cmd_payload_fragment_address = logic_input_payload_fragment_address; + assign io_outputs_1_cmd_payload_fragment_length = logic_input_payload_fragment_length; + assign io_outputs_1_cmd_payload_fragment_data = logic_input_payload_fragment_data; + assign io_outputs_1_cmd_payload_fragment_mask = logic_input_payload_fragment_mask; + assign io_outputs_1_cmd_payload_fragment_context = logic_input_payload_fragment_context; + always @(*) begin + logic_input_ready = ((|{(logic_hitsS0_1 && io_outputs_1_cmd_ready),(logic_hitsS0_0 && io_outputs_0_cmd_ready)}) || logic_noHitS0); + if(logic_cmdWait) begin + logic_input_ready = 1'b0; + end + end + + assign logic_input_fire = (logic_input_valid && logic_input_ready); + assign io_input_rsp_fire = (io_input_rsp_valid && io_input_rsp_ready); + assign when_BmbDecoder_l56 = (logic_input_valid && (! logic_cmdWait)); + assign logic_rspPending = (logic_rspPendingCounter != 7'h0); + assign logic_rspNoHitValid = (! (|{logic_rspHits_1,logic_rspHits_0})); + assign when_BmbDecoder_l60 = (io_input_rsp_fire && io_input_rsp_payload_last); + assign when_BmbDecoder_l60_1 = ((logic_input_fire && logic_noHitS0) && logic_input_payload_last); + always @(*) begin + io_input_rsp_valid = ((|{io_outputs_1_rsp_valid,io_outputs_0_rsp_valid}) || (logic_rspPending && logic_rspNoHitValid)); + if(logic_rspNoHit_doIt) begin + io_input_rsp_valid = 1'b1; + end + end + + assign _zz_io_input_rsp_payload_last = logic_rspHits_1; + always @(*) begin + io_input_rsp_payload_last = _zz_io_input_rsp_payload_last_1; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_last = 1'b1; + end + end + + always @(*) begin + io_input_rsp_payload_fragment_opcode = _zz_io_input_rsp_payload_fragment_opcode; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_fragment_opcode = 1'b1; + end + end + + assign io_input_rsp_payload_fragment_data = _zz_io_input_rsp_payload_fragment_data; + always @(*) begin + io_input_rsp_payload_fragment_context = _zz_io_input_rsp_payload_fragment_context; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_fragment_context = logic_rspNoHit_context; + end + end + + assign io_outputs_0_rsp_ready = io_input_rsp_ready; + assign io_outputs_1_rsp_ready = io_input_rsp_ready; + assign logic_cmdWait = ((logic_rspPending && (((logic_hitsS0_0 != logic_rspHits_0) || (logic_hitsS0_1 != logic_rspHits_1)) || logic_rspNoHitValid)) || (logic_rspPendingCounter == 7'h40)); + always @(posedge clk) begin + if(reset) begin + logic_rspPendingCounter <= 7'h0; + logic_rspNoHit_doIt <= 1'b0; + end else begin + logic_rspPendingCounter <= (_zz_logic_rspPendingCounter - _zz_logic_rspPendingCounter_3); + if(when_BmbDecoder_l60) begin + logic_rspNoHit_doIt <= 1'b0; + end + if(when_BmbDecoder_l60_1) begin + logic_rspNoHit_doIt <= 1'b1; + end + end + end + + always @(posedge clk) begin + if(when_BmbDecoder_l56) begin + logic_rspHits_0 <= logic_hitsS0_0; + logic_rspHits_1 <= logic_hitsS0_1; + end + if(logic_input_fire) begin + logic_rspNoHit_singleBeatRsp <= (logic_input_payload_fragment_opcode == 1'b1); + end + if(logic_input_fire) begin + logic_rspNoHit_context <= logic_input_payload_fragment_context; + end + end + + +endmodule + +module Axi4PeripheralBmbUnburstify_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_input_cmd_valid, + output reg io_input_cmd_ready, + input wire io_input_cmd_payload_last, + input wire [0:0] io_input_cmd_payload_fragment_source, + input wire [0:0] io_input_cmd_payload_fragment_opcode, + input wire [23:0] io_input_cmd_payload_fragment_address, + input wire [9:0] io_input_cmd_payload_fragment_length, + input wire [31:0] io_input_cmd_payload_fragment_data, + input wire [3:0] io_input_cmd_payload_fragment_mask, + output wire io_input_rsp_valid, + input wire io_input_rsp_ready, + output wire io_input_rsp_payload_last, + output wire [0:0] io_input_rsp_payload_fragment_source, + output wire [0:0] io_input_rsp_payload_fragment_opcode, + output wire [31:0] io_input_rsp_payload_fragment_data, + output reg io_output_cmd_valid, + input wire io_output_cmd_ready, + output wire io_output_cmd_payload_last, + output reg [0:0] io_output_cmd_payload_fragment_opcode, + output reg [23:0] io_output_cmd_payload_fragment_address, + output reg [1:0] io_output_cmd_payload_fragment_length, + output wire [31:0] io_output_cmd_payload_fragment_data, + output wire [3:0] io_output_cmd_payload_fragment_mask, + output wire [2:0] io_output_cmd_payload_fragment_context, + input wire io_output_rsp_valid, + output reg io_output_rsp_ready, + input wire io_output_rsp_payload_last, + input wire [0:0] io_output_rsp_payload_fragment_opcode, + input wire [31:0] io_output_rsp_payload_fragment_data, + input wire [2:0] io_output_rsp_payload_fragment_context, + input wire clk, + input wire reset +); + + wire [7:0] _zz_buffer_last; + wire [0:0] _zz_buffer_last_1; + wire [11:0] _zz_buffer_addressIncr; + wire doResult; + reg buffer_valid; + reg [0:0] buffer_opcode; + reg [0:0] buffer_source; + reg [23:0] buffer_address; + reg [7:0] buffer_beat; + wire buffer_last; + wire [23:0] buffer_addressIncr; + wire buffer_isWrite; + wire io_output_cmd_fire; + wire [7:0] cmdTransferBeatCount; + wire requireBuffer; + reg cmdContext_drop; + reg cmdContext_last; + reg [0:0] cmdContext_source; + wire rspContext_drop; + wire rspContext_last; + wire [0:0] rspContext_source; + wire [2:0] _zz_rspContext_drop; + wire when_Stream_l445; + reg io_output_rsp_thrown_valid; + wire io_output_rsp_thrown_ready; + wire io_output_rsp_thrown_payload_last; + wire [0:0] io_output_rsp_thrown_payload_fragment_opcode; + wire [31:0] io_output_rsp_thrown_payload_fragment_data; + wire [2:0] io_output_rsp_thrown_payload_fragment_context; + + assign _zz_buffer_last_1 = 1'b1; + assign _zz_buffer_last = {7'd0, _zz_buffer_last_1}; + assign _zz_buffer_addressIncr = (buffer_address[11 : 0] + 12'h004); + assign buffer_last = (buffer_beat == _zz_buffer_last); + assign buffer_addressIncr = {buffer_address[23 : 12],(_zz_buffer_addressIncr & (~ 12'h003))}; + assign buffer_isWrite = (buffer_opcode == 1'b1); + assign io_output_cmd_fire = (io_output_cmd_valid && io_output_cmd_ready); + assign cmdTransferBeatCount = io_input_cmd_payload_fragment_length[9 : 2]; + assign requireBuffer = (cmdTransferBeatCount != 8'h0); + assign io_output_cmd_payload_fragment_data = io_input_cmd_payload_fragment_data; + assign io_output_cmd_payload_fragment_mask = io_input_cmd_payload_fragment_mask; + assign io_output_cmd_payload_last = 1'b1; + assign io_output_cmd_payload_fragment_context = {cmdContext_source,{cmdContext_last,cmdContext_drop}}; + always @(*) begin + if(buffer_valid) begin + io_output_cmd_payload_fragment_address = buffer_addressIncr; + end else begin + io_output_cmd_payload_fragment_address = io_input_cmd_payload_fragment_address; + if(requireBuffer) begin + io_output_cmd_payload_fragment_address[1 : 0] = 2'b00; + end + end + end + + always @(*) begin + if(buffer_valid) begin + io_output_cmd_payload_fragment_opcode = buffer_opcode; + end else begin + io_output_cmd_payload_fragment_opcode = io_input_cmd_payload_fragment_opcode; + end + end + + always @(*) begin + if(buffer_valid) begin + io_output_cmd_payload_fragment_length = 2'b11; + end else begin + if(requireBuffer) begin + io_output_cmd_payload_fragment_length = 2'b11; + end else begin + io_output_cmd_payload_fragment_length = io_input_cmd_payload_fragment_length[1:0]; + end + end + end + + always @(*) begin + if(buffer_valid) begin + cmdContext_source = buffer_source; + end else begin + cmdContext_source = io_input_cmd_payload_fragment_source; + end + end + + always @(*) begin + io_input_cmd_ready = 1'b0; + if(buffer_valid) begin + io_input_cmd_ready = (buffer_isWrite && io_output_cmd_ready); + end else begin + io_input_cmd_ready = io_output_cmd_ready; + end + end + + always @(*) begin + if(buffer_valid) begin + io_output_cmd_valid = (! (buffer_isWrite && (! io_input_cmd_valid))); + end else begin + io_output_cmd_valid = io_input_cmd_valid; + end + end + + always @(*) begin + if(buffer_valid) begin + cmdContext_last = buffer_last; + end else begin + cmdContext_last = (! requireBuffer); + end + end + + always @(*) begin + if(buffer_valid) begin + cmdContext_drop = buffer_isWrite; + end else begin + cmdContext_drop = (io_input_cmd_payload_fragment_opcode == 1'b1); + end + end + + assign _zz_rspContext_drop = io_output_rsp_payload_fragment_context; + assign rspContext_drop = _zz_rspContext_drop[0]; + assign rspContext_last = _zz_rspContext_drop[1]; + assign rspContext_source = _zz_rspContext_drop[2 : 2]; + assign when_Stream_l445 = (! (rspContext_last || (! rspContext_drop))); + always @(*) begin + io_output_rsp_thrown_valid = io_output_rsp_valid; + if(when_Stream_l445) begin + io_output_rsp_thrown_valid = 1'b0; + end + end + + always @(*) begin + io_output_rsp_ready = io_output_rsp_thrown_ready; + if(when_Stream_l445) begin + io_output_rsp_ready = 1'b1; + end + end + + assign io_output_rsp_thrown_payload_last = io_output_rsp_payload_last; + assign io_output_rsp_thrown_payload_fragment_opcode = io_output_rsp_payload_fragment_opcode; + assign io_output_rsp_thrown_payload_fragment_data = io_output_rsp_payload_fragment_data; + assign io_output_rsp_thrown_payload_fragment_context = io_output_rsp_payload_fragment_context; + assign io_input_rsp_valid = io_output_rsp_thrown_valid; + assign io_output_rsp_thrown_ready = io_input_rsp_ready; + assign io_input_rsp_payload_last = rspContext_last; + assign io_input_rsp_payload_fragment_source = rspContext_source; + assign io_input_rsp_payload_fragment_opcode = io_output_rsp_payload_fragment_opcode; + assign io_input_rsp_payload_fragment_data = io_output_rsp_payload_fragment_data; + always @(posedge clk) begin + if(reset) begin + buffer_valid <= 1'b0; + end else begin + if(io_output_cmd_fire) begin + if(buffer_last) begin + buffer_valid <= 1'b0; + end + end + if(!buffer_valid) begin + buffer_valid <= (requireBuffer && io_output_cmd_fire); + end + end + end + + always @(posedge clk) begin + if(io_output_cmd_fire) begin + buffer_beat <= (buffer_beat - 8'h01); + buffer_address[11 : 0] <= buffer_addressIncr[11 : 0]; + end + if(!buffer_valid) begin + buffer_opcode <= io_input_cmd_payload_fragment_opcode; + buffer_source <= io_input_cmd_payload_fragment_source; + buffer_address <= io_input_cmd_payload_fragment_address; + buffer_beat <= cmdTransferBeatCount; + end + end + + +endmodule + +module Axi4PeripheralBmbDecoder_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_input_cmd_valid, + output wire io_input_cmd_ready, + input wire io_input_cmd_payload_last, + input wire [0:0] io_input_cmd_payload_fragment_source, + input wire [0:0] io_input_cmd_payload_fragment_opcode, + input wire [23:0] io_input_cmd_payload_fragment_address, + input wire [9:0] io_input_cmd_payload_fragment_length, + input wire [31:0] io_input_cmd_payload_fragment_data, + input wire [3:0] io_input_cmd_payload_fragment_mask, + output reg io_input_rsp_valid, + input wire io_input_rsp_ready, + output reg io_input_rsp_payload_last, + output reg [0:0] io_input_rsp_payload_fragment_source, + output reg [0:0] io_input_rsp_payload_fragment_opcode, + output wire [31:0] io_input_rsp_payload_fragment_data, + output reg io_outputs_0_cmd_valid, + input wire io_outputs_0_cmd_ready, + output wire io_outputs_0_cmd_payload_last, + output wire [0:0] io_outputs_0_cmd_payload_fragment_source, + output wire [0:0] io_outputs_0_cmd_payload_fragment_opcode, + output wire [23:0] io_outputs_0_cmd_payload_fragment_address, + output wire [9:0] io_outputs_0_cmd_payload_fragment_length, + output wire [31:0] io_outputs_0_cmd_payload_fragment_data, + output wire [3:0] io_outputs_0_cmd_payload_fragment_mask, + input wire io_outputs_0_rsp_valid, + output wire io_outputs_0_rsp_ready, + input wire io_outputs_0_rsp_payload_last, + input wire [0:0] io_outputs_0_rsp_payload_fragment_source, + input wire [0:0] io_outputs_0_rsp_payload_fragment_opcode, + input wire [31:0] io_outputs_0_rsp_payload_fragment_data, + input wire clk, + input wire reset +); + + wire [6:0] _zz_logic_rspPendingCounter; + wire [6:0] _zz_logic_rspPendingCounter_1; + wire [0:0] _zz_logic_rspPendingCounter_2; + wire [6:0] _zz_logic_rspPendingCounter_3; + wire [0:0] _zz_logic_rspPendingCounter_4; + wire logic_input_valid; + reg logic_input_ready; + wire logic_input_payload_last; + wire [0:0] logic_input_payload_fragment_source; + wire [0:0] logic_input_payload_fragment_opcode; + wire [23:0] logic_input_payload_fragment_address; + wire [9:0] logic_input_payload_fragment_length; + wire [31:0] logic_input_payload_fragment_data; + wire [3:0] logic_input_payload_fragment_mask; + wire logic_hitsS0_0; + wire logic_noHitS0; + wire _zz_io_outputs_0_cmd_payload_last; + reg [6:0] logic_rspPendingCounter; + wire logic_input_fire; + wire io_input_rsp_fire; + wire logic_cmdWait; + wire when_BmbDecoder_l56; + reg logic_rspHits_0; + wire logic_rspPending; + wire logic_rspNoHitValid; + reg logic_rspNoHit_doIt; + wire when_BmbDecoder_l60; + wire when_BmbDecoder_l60_1; + reg logic_rspNoHit_singleBeatRsp; + reg [0:0] logic_rspNoHit_source; + reg [7:0] logic_rspNoHit_counter; + wire when_BmbDecoder_l81; + + assign _zz_logic_rspPendingCounter = (logic_rspPendingCounter + _zz_logic_rspPendingCounter_1); + assign _zz_logic_rspPendingCounter_2 = (logic_input_fire && logic_input_payload_last); + assign _zz_logic_rspPendingCounter_1 = {6'd0, _zz_logic_rspPendingCounter_2}; + assign _zz_logic_rspPendingCounter_4 = (io_input_rsp_fire && io_input_rsp_payload_last); + assign _zz_logic_rspPendingCounter_3 = {6'd0, _zz_logic_rspPendingCounter_4}; + assign logic_input_valid = io_input_cmd_valid; + assign io_input_cmd_ready = logic_input_ready; + assign logic_input_payload_last = io_input_cmd_payload_last; + assign logic_input_payload_fragment_source = io_input_cmd_payload_fragment_source; + assign logic_input_payload_fragment_opcode = io_input_cmd_payload_fragment_opcode; + assign logic_input_payload_fragment_address = io_input_cmd_payload_fragment_address; + assign logic_input_payload_fragment_length = io_input_cmd_payload_fragment_length; + assign logic_input_payload_fragment_data = io_input_cmd_payload_fragment_data; + assign logic_input_payload_fragment_mask = io_input_cmd_payload_fragment_mask; + assign logic_noHitS0 = (! (|logic_hitsS0_0)); + assign logic_hitsS0_0 = ((io_input_cmd_payload_fragment_address & (~ 24'hffffff)) == 24'h0); + always @(*) begin + io_outputs_0_cmd_valid = (logic_input_valid && logic_hitsS0_0); + if(logic_cmdWait) begin + io_outputs_0_cmd_valid = 1'b0; + end + end + + assign _zz_io_outputs_0_cmd_payload_last = logic_input_payload_last; + assign io_outputs_0_cmd_payload_last = _zz_io_outputs_0_cmd_payload_last; + assign io_outputs_0_cmd_payload_fragment_source = logic_input_payload_fragment_source; + assign io_outputs_0_cmd_payload_fragment_opcode = logic_input_payload_fragment_opcode; + assign io_outputs_0_cmd_payload_fragment_address = logic_input_payload_fragment_address; + assign io_outputs_0_cmd_payload_fragment_length = logic_input_payload_fragment_length; + assign io_outputs_0_cmd_payload_fragment_data = logic_input_payload_fragment_data; + assign io_outputs_0_cmd_payload_fragment_mask = logic_input_payload_fragment_mask; + always @(*) begin + logic_input_ready = ((|(logic_hitsS0_0 && io_outputs_0_cmd_ready)) || logic_noHitS0); + if(logic_cmdWait) begin + logic_input_ready = 1'b0; + end + end + + assign logic_input_fire = (logic_input_valid && logic_input_ready); + assign io_input_rsp_fire = (io_input_rsp_valid && io_input_rsp_ready); + assign when_BmbDecoder_l56 = (logic_input_valid && (! logic_cmdWait)); + assign logic_rspPending = (logic_rspPendingCounter != 7'h0); + assign logic_rspNoHitValid = (! (|logic_rspHits_0)); + assign when_BmbDecoder_l60 = (io_input_rsp_fire && io_input_rsp_payload_last); + assign when_BmbDecoder_l60_1 = ((logic_input_fire && logic_noHitS0) && logic_input_payload_last); + always @(*) begin + io_input_rsp_valid = ((|io_outputs_0_rsp_valid) || (logic_rspPending && logic_rspNoHitValid)); + if(logic_rspNoHit_doIt) begin + io_input_rsp_valid = 1'b1; + end + end + + always @(*) begin + io_input_rsp_payload_last = io_outputs_0_rsp_payload_last; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_last = 1'b0; + if(when_BmbDecoder_l81) begin + io_input_rsp_payload_last = 1'b1; + end + if(logic_rspNoHit_singleBeatRsp) begin + io_input_rsp_payload_last = 1'b1; + end + end + end + + always @(*) begin + io_input_rsp_payload_fragment_source = io_outputs_0_rsp_payload_fragment_source; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_fragment_source = logic_rspNoHit_source; + end + end + + always @(*) begin + io_input_rsp_payload_fragment_opcode = io_outputs_0_rsp_payload_fragment_opcode; + if(logic_rspNoHit_doIt) begin + io_input_rsp_payload_fragment_opcode = 1'b1; + end + end + + assign io_input_rsp_payload_fragment_data = io_outputs_0_rsp_payload_fragment_data; + assign when_BmbDecoder_l81 = (logic_rspNoHit_counter == 8'h0); + assign io_outputs_0_rsp_ready = io_input_rsp_ready; + assign logic_cmdWait = ((logic_rspPending && ((logic_hitsS0_0 != logic_rspHits_0) || logic_rspNoHitValid)) || (logic_rspPendingCounter == 7'h40)); + always @(posedge clk) begin + if(reset) begin + logic_rspPendingCounter <= 7'h0; + logic_rspNoHit_doIt <= 1'b0; + end else begin + logic_rspPendingCounter <= (_zz_logic_rspPendingCounter - _zz_logic_rspPendingCounter_3); + if(when_BmbDecoder_l60) begin + logic_rspNoHit_doIt <= 1'b0; + end + if(when_BmbDecoder_l60_1) begin + logic_rspNoHit_doIt <= 1'b1; + end + end + end + + always @(posedge clk) begin + if(when_BmbDecoder_l56) begin + logic_rspHits_0 <= logic_hitsS0_0; + end + if(logic_input_fire) begin + logic_rspNoHit_singleBeatRsp <= (logic_input_payload_fragment_opcode == 1'b1); + end + if(logic_input_fire) begin + logic_rspNoHit_source <= logic_input_payload_fragment_source; + end + if(logic_input_fire) begin + logic_rspNoHit_counter <= logic_input_payload_fragment_length[9 : 2]; + end + if(logic_rspNoHit_doIt) begin + if(io_input_rsp_fire) begin + logic_rspNoHit_counter <= (logic_rspNoHit_counter - 8'h01); + end + end + end + + +endmodule + +module Axi4PeripheralAxi4SharedToBmb_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_axi_arw_valid, + output wire io_axi_arw_ready, + input wire [23:0] io_axi_arw_payload_addr, + input wire [7:0] io_axi_arw_payload_len, + input wire [2:0] io_axi_arw_payload_size, + input wire [3:0] io_axi_arw_payload_cache, + input wire [2:0] io_axi_arw_payload_prot, + input wire io_axi_arw_payload_write, + input wire io_axi_w_valid, + output wire io_axi_w_ready, + input wire [31:0] io_axi_w_payload_data, + input wire [3:0] io_axi_w_payload_strb, + input wire io_axi_w_payload_last, + output wire io_axi_b_valid, + input wire io_axi_b_ready, + output reg [1:0] io_axi_b_payload_resp, + output wire io_axi_r_valid, + input wire io_axi_r_ready, + output wire [31:0] io_axi_r_payload_data, + output reg [1:0] io_axi_r_payload_resp, + output wire io_axi_r_payload_last, + output wire io_bmb_cmd_valid, + input wire io_bmb_cmd_ready, + output wire io_bmb_cmd_payload_last, + output wire [0:0] io_bmb_cmd_payload_fragment_source, + output wire [0:0] io_bmb_cmd_payload_fragment_opcode, + output wire [23:0] io_bmb_cmd_payload_fragment_address, + output wire [9:0] io_bmb_cmd_payload_fragment_length, + output wire [31:0] io_bmb_cmd_payload_fragment_data, + output wire [3:0] io_bmb_cmd_payload_fragment_mask, + input wire io_bmb_rsp_valid, + output wire io_bmb_rsp_ready, + input wire io_bmb_rsp_payload_last, + input wire [0:0] io_bmb_rsp_payload_fragment_source, + input wire [0:0] io_bmb_rsp_payload_fragment_opcode, + input wire [31:0] io_bmb_rsp_payload_fragment_data +); + + wire [9:0] _zz_io_bmb_cmd_payload_fragment_length; + wire hazard; + wire io_bmb_cmd_fire; + wire rspIsWrite; + wire when_Axi4SharedToBmb_l42; + wire when_Axi4SharedToBmb_l49; + + assign _zz_io_bmb_cmd_payload_fragment_length = ({2'd0,io_axi_arw_payload_len} <<< 2'd2); + assign hazard = (io_axi_arw_payload_write && (! io_axi_w_valid)); + assign io_bmb_cmd_valid = (io_axi_arw_valid && (! hazard)); + assign io_bmb_cmd_payload_fragment_source = io_axi_arw_payload_write; + assign io_bmb_cmd_payload_fragment_opcode = io_axi_arw_payload_write; + assign io_bmb_cmd_payload_fragment_address = io_axi_arw_payload_addr; + assign io_bmb_cmd_payload_fragment_length = (_zz_io_bmb_cmd_payload_fragment_length | 10'h003); + assign io_bmb_cmd_payload_fragment_data = io_axi_w_payload_data; + assign io_bmb_cmd_payload_fragment_mask = io_axi_w_payload_strb; + assign io_bmb_cmd_payload_last = ((! io_axi_arw_payload_write) || io_axi_w_payload_last); + assign io_bmb_cmd_fire = (io_bmb_cmd_valid && io_bmb_cmd_ready); + assign io_axi_arw_ready = (io_bmb_cmd_fire && io_bmb_cmd_payload_last); + assign io_axi_w_ready = (io_bmb_cmd_fire && (io_bmb_cmd_payload_fragment_opcode == 1'b1)); + assign rspIsWrite = io_bmb_rsp_payload_fragment_source[0]; + assign io_axi_b_valid = (io_bmb_rsp_valid && rspIsWrite); + always @(*) begin + io_axi_b_payload_resp = 2'b00; + if(when_Axi4SharedToBmb_l42) begin + io_axi_b_payload_resp = 2'b11; + end + end + + assign when_Axi4SharedToBmb_l42 = (io_bmb_rsp_payload_fragment_opcode == 1'b1); + assign io_axi_r_valid = (io_bmb_rsp_valid && (! rspIsWrite)); + assign io_axi_r_payload_data = io_bmb_rsp_payload_fragment_data; + assign io_axi_r_payload_last = io_bmb_rsp_payload_last; + always @(*) begin + io_axi_r_payload_resp = 2'b00; + if(when_Axi4SharedToBmb_l49) begin + io_axi_r_payload_resp = 2'b11; + end + end + + assign when_Axi4SharedToBmb_l49 = (io_bmb_rsp_payload_fragment_opcode == 1'b1); + assign io_bmb_rsp_ready = (rspIsWrite ? io_axi_b_ready : io_axi_r_ready); + +endmodule + +module Axi4PeripheralStreamArbiter_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_inputs_0_valid, + output wire io_inputs_0_ready, + input wire [23:0] io_inputs_0_payload_addr, + input wire [7:0] io_inputs_0_payload_len, + input wire [2:0] io_inputs_0_payload_size, + input wire [3:0] io_inputs_0_payload_cache, + input wire [2:0] io_inputs_0_payload_prot, + input wire io_inputs_1_valid, + output wire io_inputs_1_ready, + input wire [23:0] io_inputs_1_payload_addr, + input wire [7:0] io_inputs_1_payload_len, + input wire [2:0] io_inputs_1_payload_size, + input wire [3:0] io_inputs_1_payload_cache, + input wire [2:0] io_inputs_1_payload_prot, + output wire io_output_valid, + input wire io_output_ready, + output wire [23:0] io_output_payload_addr, + output wire [7:0] io_output_payload_len, + output wire [2:0] io_output_payload_size, + output wire [3:0] io_output_payload_cache, + output wire [2:0] io_output_payload_prot, + output wire [0:0] io_chosen, + output wire [1:0] io_chosenOH, + input wire clk, + input wire reset +); + + wire [3:0] _zz__zz_maskProposal_0_2; + wire [3:0] _zz__zz_maskProposal_0_2_1; + wire [1:0] _zz__zz_maskProposal_0_2_2; + reg locked; + wire maskProposal_0; + wire maskProposal_1; + reg maskLocked_0; + reg maskLocked_1; + wire maskRouted_0; + wire maskRouted_1; + wire [1:0] _zz_maskProposal_0; + wire [3:0] _zz_maskProposal_0_1; + wire [3:0] _zz_maskProposal_0_2; + wire [1:0] _zz_maskProposal_0_3; + wire io_output_fire; + wire _zz_io_chosen; + + assign _zz__zz_maskProposal_0_2 = (_zz_maskProposal_0_1 - _zz__zz_maskProposal_0_2_1); + assign _zz__zz_maskProposal_0_2_2 = {maskLocked_0,maskLocked_1}; + assign _zz__zz_maskProposal_0_2_1 = {2'd0, _zz__zz_maskProposal_0_2_2}; + assign maskRouted_0 = (locked ? maskLocked_0 : maskProposal_0); + assign maskRouted_1 = (locked ? maskLocked_1 : maskProposal_1); + assign _zz_maskProposal_0 = {io_inputs_1_valid,io_inputs_0_valid}; + assign _zz_maskProposal_0_1 = {_zz_maskProposal_0,_zz_maskProposal_0}; + assign _zz_maskProposal_0_2 = (_zz_maskProposal_0_1 & (~ _zz__zz_maskProposal_0_2)); + assign _zz_maskProposal_0_3 = (_zz_maskProposal_0_2[3 : 2] | _zz_maskProposal_0_2[1 : 0]); + assign maskProposal_0 = _zz_maskProposal_0_3[0]; + assign maskProposal_1 = _zz_maskProposal_0_3[1]; + assign io_output_fire = (io_output_valid && io_output_ready); + assign io_output_valid = ((io_inputs_0_valid && maskRouted_0) || (io_inputs_1_valid && maskRouted_1)); + assign io_output_payload_addr = (maskRouted_0 ? io_inputs_0_payload_addr : io_inputs_1_payload_addr); + assign io_output_payload_len = (maskRouted_0 ? io_inputs_0_payload_len : io_inputs_1_payload_len); + assign io_output_payload_size = (maskRouted_0 ? io_inputs_0_payload_size : io_inputs_1_payload_size); + assign io_output_payload_cache = (maskRouted_0 ? io_inputs_0_payload_cache : io_inputs_1_payload_cache); + assign io_output_payload_prot = (maskRouted_0 ? io_inputs_0_payload_prot : io_inputs_1_payload_prot); + assign io_inputs_0_ready = (maskRouted_0 && io_output_ready); + assign io_inputs_1_ready = (maskRouted_1 && io_output_ready); + assign io_chosenOH = {maskRouted_1,maskRouted_0}; + assign _zz_io_chosen = io_chosenOH[1]; + assign io_chosen = _zz_io_chosen; + always @(posedge clk) begin + if(reset) begin + locked <= 1'b0; + maskLocked_0 <= 1'b0; + maskLocked_1 <= 1'b1; + end else begin + if(io_output_valid) begin + maskLocked_0 <= maskRouted_0; + maskLocked_1 <= maskRouted_1; + end + if(io_output_valid) begin + locked <= 1'b1; + end + if(io_output_fire) begin + locked <= 1'b0; + end + end + end + + +endmodule + +module Axi4PeripheralStreamFifo_3_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_push_valid, + output wire io_push_ready, + input wire [7:0] io_push_payload_data, + output wire io_pop_valid, + input wire io_pop_ready, + output wire [7:0] io_pop_payload_data, + input wire io_flush, + output wire [8:0] io_occupancy, + output wire [8:0] io_availability, + input wire clk, + input wire reset +); + + reg [7:0] logic_ram_spinal_port1; + reg _zz_1; + wire logic_ptr_doPush; + wire logic_ptr_doPop; + wire logic_ptr_full; + wire logic_ptr_empty; + reg [8:0] logic_ptr_push; + reg [8:0] logic_ptr_pop; + wire [8:0] logic_ptr_occupancy; + wire [8:0] logic_ptr_popOnIo; + wire when_Stream_l1248; + reg logic_ptr_wentUp; + wire io_push_fire; + wire logic_push_onRam_write_valid; + wire [7:0] logic_push_onRam_write_payload_address; + wire [7:0] logic_push_onRam_write_payload_data_data; + wire logic_pop_addressGen_valid; + reg logic_pop_addressGen_ready; + wire [7:0] logic_pop_addressGen_payload; + wire logic_pop_addressGen_fire; + wire logic_pop_sync_readArbitation_valid; + wire logic_pop_sync_readArbitation_ready; + wire [7:0] logic_pop_sync_readArbitation_payload; + reg logic_pop_addressGen_rValid; + reg [7:0] logic_pop_addressGen_rData; + wire when_Stream_l375; + wire logic_pop_sync_readPort_cmd_valid; + wire [7:0] logic_pop_sync_readPort_cmd_payload; + wire [7:0] logic_pop_sync_readPort_rsp_data; + wire logic_pop_sync_readArbitation_translated_valid; + wire logic_pop_sync_readArbitation_translated_ready; + wire [7:0] logic_pop_sync_readArbitation_translated_payload_data; + wire logic_pop_sync_readArbitation_fire; + reg [8:0] logic_pop_sync_popReg; + reg [7:0] logic_ram [0:255]; + + always @(posedge clk) begin + if(_zz_1) begin + logic_ram[logic_push_onRam_write_payload_address] <= logic_push_onRam_write_payload_data_data; + end + end + + always @(posedge clk) begin + if(logic_pop_sync_readPort_cmd_valid) begin + logic_ram_spinal_port1 <= logic_ram[logic_pop_sync_readPort_cmd_payload]; + end + end + + always @(*) begin + _zz_1 = 1'b0; + if(logic_push_onRam_write_valid) begin + _zz_1 = 1'b1; + end + end + + assign when_Stream_l1248 = (logic_ptr_doPush != logic_ptr_doPop); + assign logic_ptr_full = (((logic_ptr_push ^ logic_ptr_popOnIo) ^ 9'h100) == 9'h0); + assign logic_ptr_empty = (logic_ptr_push == logic_ptr_pop); + assign logic_ptr_occupancy = (logic_ptr_push - logic_ptr_popOnIo); + assign io_push_ready = (! logic_ptr_full); + assign io_push_fire = (io_push_valid && io_push_ready); + assign logic_ptr_doPush = io_push_fire; + assign logic_push_onRam_write_valid = io_push_fire; + assign logic_push_onRam_write_payload_address = logic_ptr_push[7:0]; + assign logic_push_onRam_write_payload_data_data = io_push_payload_data; + assign logic_pop_addressGen_valid = (! logic_ptr_empty); + assign logic_pop_addressGen_payload = logic_ptr_pop[7:0]; + assign logic_pop_addressGen_fire = (logic_pop_addressGen_valid && logic_pop_addressGen_ready); + assign logic_ptr_doPop = logic_pop_addressGen_fire; + always @(*) begin + logic_pop_addressGen_ready = logic_pop_sync_readArbitation_ready; + if(when_Stream_l375) begin + logic_pop_addressGen_ready = 1'b1; + end + end + + assign when_Stream_l375 = (! logic_pop_sync_readArbitation_valid); + assign logic_pop_sync_readArbitation_valid = logic_pop_addressGen_rValid; + assign logic_pop_sync_readArbitation_payload = logic_pop_addressGen_rData; + assign logic_pop_sync_readPort_rsp_data = logic_ram_spinal_port1[7 : 0]; + assign logic_pop_sync_readPort_cmd_valid = logic_pop_addressGen_fire; + assign logic_pop_sync_readPort_cmd_payload = logic_pop_addressGen_payload; + assign logic_pop_sync_readArbitation_translated_valid = logic_pop_sync_readArbitation_valid; + assign logic_pop_sync_readArbitation_ready = logic_pop_sync_readArbitation_translated_ready; + assign logic_pop_sync_readArbitation_translated_payload_data = logic_pop_sync_readPort_rsp_data; + assign io_pop_valid = logic_pop_sync_readArbitation_translated_valid; + assign logic_pop_sync_readArbitation_translated_ready = io_pop_ready; + assign io_pop_payload_data = logic_pop_sync_readArbitation_translated_payload_data; + assign logic_pop_sync_readArbitation_fire = (logic_pop_sync_readArbitation_valid && logic_pop_sync_readArbitation_ready); + assign logic_ptr_popOnIo = logic_pop_sync_popReg; + assign io_occupancy = logic_ptr_occupancy; + assign io_availability = (9'h100 - logic_ptr_occupancy); + always @(posedge clk) begin + if(reset) begin + logic_ptr_push <= 9'h0; + logic_ptr_pop <= 9'h0; + logic_ptr_wentUp <= 1'b0; + logic_pop_addressGen_rValid <= 1'b0; + logic_pop_sync_popReg <= 9'h0; + end else begin + if(when_Stream_l1248) begin + logic_ptr_wentUp <= logic_ptr_doPush; + end + if(io_flush) begin + logic_ptr_wentUp <= 1'b0; + end + if(logic_ptr_doPush) begin + logic_ptr_push <= (logic_ptr_push + 9'h001); + end + if(logic_ptr_doPop) begin + logic_ptr_pop <= (logic_ptr_pop + 9'h001); + end + if(io_flush) begin + logic_ptr_push <= 9'h0; + logic_ptr_pop <= 9'h0; + end + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rValid <= logic_pop_addressGen_valid; + end + if(io_flush) begin + logic_pop_addressGen_rValid <= 1'b0; + end + if(logic_pop_sync_readArbitation_fire) begin + logic_pop_sync_popReg <= logic_ptr_pop; + end + if(io_flush) begin + logic_pop_sync_popReg <= 9'h0; + end + end + end + + always @(posedge clk) begin + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rData <= logic_pop_addressGen_payload; + end + end + + +endmodule + +module Axi4PeripheralStreamFifo_2_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_push_valid, + output wire io_push_ready, + input wire io_push_payload_kind, + input wire io_push_payload_read, + input wire io_push_payload_write, + input wire [7:0] io_push_payload_data, + output wire io_pop_valid, + input wire io_pop_ready, + output wire io_pop_payload_kind, + output wire io_pop_payload_read, + output wire io_pop_payload_write, + output wire [7:0] io_pop_payload_data, + input wire io_flush, + output wire [8:0] io_occupancy, + output wire [8:0] io_availability, + input wire clk, + input wire reset +); + + reg [10:0] logic_ram_spinal_port1; + wire [10:0] _zz_logic_ram_port; + reg _zz_1; + wire logic_ptr_doPush; + wire logic_ptr_doPop; + wire logic_ptr_full; + wire logic_ptr_empty; + reg [8:0] logic_ptr_push; + reg [8:0] logic_ptr_pop; + wire [8:0] logic_ptr_occupancy; + wire [8:0] logic_ptr_popOnIo; + wire when_Stream_l1248; + reg logic_ptr_wentUp; + wire io_push_fire; + wire logic_push_onRam_write_valid; + wire [7:0] logic_push_onRam_write_payload_address; + wire logic_push_onRam_write_payload_data_kind; + wire logic_push_onRam_write_payload_data_read; + wire logic_push_onRam_write_payload_data_write; + wire [7:0] logic_push_onRam_write_payload_data_data; + wire logic_pop_addressGen_valid; + reg logic_pop_addressGen_ready; + wire [7:0] logic_pop_addressGen_payload; + wire logic_pop_addressGen_fire; + wire logic_pop_sync_readArbitation_valid; + wire logic_pop_sync_readArbitation_ready; + wire [7:0] logic_pop_sync_readArbitation_payload; + reg logic_pop_addressGen_rValid; + reg [7:0] logic_pop_addressGen_rData; + wire when_Stream_l375; + wire logic_pop_sync_readPort_cmd_valid; + wire [7:0] logic_pop_sync_readPort_cmd_payload; + wire logic_pop_sync_readPort_rsp_kind; + wire logic_pop_sync_readPort_rsp_read; + wire logic_pop_sync_readPort_rsp_write; + wire [7:0] logic_pop_sync_readPort_rsp_data; + wire [10:0] _zz_logic_pop_sync_readPort_rsp_kind; + wire logic_pop_sync_readArbitation_translated_valid; + wire logic_pop_sync_readArbitation_translated_ready; + wire logic_pop_sync_readArbitation_translated_payload_kind; + wire logic_pop_sync_readArbitation_translated_payload_read; + wire logic_pop_sync_readArbitation_translated_payload_write; + wire [7:0] logic_pop_sync_readArbitation_translated_payload_data; + wire logic_pop_sync_readArbitation_fire; + reg [8:0] logic_pop_sync_popReg; + reg [10:0] logic_ram [0:255]; + + assign _zz_logic_ram_port = {logic_push_onRam_write_payload_data_data,{logic_push_onRam_write_payload_data_write,{logic_push_onRam_write_payload_data_read,logic_push_onRam_write_payload_data_kind}}}; + always @(posedge clk) begin + if(_zz_1) begin + logic_ram[logic_push_onRam_write_payload_address] <= _zz_logic_ram_port; + end + end + + always @(posedge clk) begin + if(logic_pop_sync_readPort_cmd_valid) begin + logic_ram_spinal_port1 <= logic_ram[logic_pop_sync_readPort_cmd_payload]; + end + end + + always @(*) begin + _zz_1 = 1'b0; + if(logic_push_onRam_write_valid) begin + _zz_1 = 1'b1; + end + end + + assign when_Stream_l1248 = (logic_ptr_doPush != logic_ptr_doPop); + assign logic_ptr_full = (((logic_ptr_push ^ logic_ptr_popOnIo) ^ 9'h100) == 9'h0); + assign logic_ptr_empty = (logic_ptr_push == logic_ptr_pop); + assign logic_ptr_occupancy = (logic_ptr_push - logic_ptr_popOnIo); + assign io_push_ready = (! logic_ptr_full); + assign io_push_fire = (io_push_valid && io_push_ready); + assign logic_ptr_doPush = io_push_fire; + assign logic_push_onRam_write_valid = io_push_fire; + assign logic_push_onRam_write_payload_address = logic_ptr_push[7:0]; + assign logic_push_onRam_write_payload_data_kind = io_push_payload_kind; + assign logic_push_onRam_write_payload_data_read = io_push_payload_read; + assign logic_push_onRam_write_payload_data_write = io_push_payload_write; + assign logic_push_onRam_write_payload_data_data = io_push_payload_data; + assign logic_pop_addressGen_valid = (! logic_ptr_empty); + assign logic_pop_addressGen_payload = logic_ptr_pop[7:0]; + assign logic_pop_addressGen_fire = (logic_pop_addressGen_valid && logic_pop_addressGen_ready); + assign logic_ptr_doPop = logic_pop_addressGen_fire; + always @(*) begin + logic_pop_addressGen_ready = logic_pop_sync_readArbitation_ready; + if(when_Stream_l375) begin + logic_pop_addressGen_ready = 1'b1; + end + end + + assign when_Stream_l375 = (! logic_pop_sync_readArbitation_valid); + assign logic_pop_sync_readArbitation_valid = logic_pop_addressGen_rValid; + assign logic_pop_sync_readArbitation_payload = logic_pop_addressGen_rData; + assign _zz_logic_pop_sync_readPort_rsp_kind = logic_ram_spinal_port1; + assign logic_pop_sync_readPort_rsp_kind = _zz_logic_pop_sync_readPort_rsp_kind[0]; + assign logic_pop_sync_readPort_rsp_read = _zz_logic_pop_sync_readPort_rsp_kind[1]; + assign logic_pop_sync_readPort_rsp_write = _zz_logic_pop_sync_readPort_rsp_kind[2]; + assign logic_pop_sync_readPort_rsp_data = _zz_logic_pop_sync_readPort_rsp_kind[10 : 3]; + assign logic_pop_sync_readPort_cmd_valid = logic_pop_addressGen_fire; + assign logic_pop_sync_readPort_cmd_payload = logic_pop_addressGen_payload; + assign logic_pop_sync_readArbitation_translated_valid = logic_pop_sync_readArbitation_valid; + assign logic_pop_sync_readArbitation_ready = logic_pop_sync_readArbitation_translated_ready; + assign logic_pop_sync_readArbitation_translated_payload_kind = logic_pop_sync_readPort_rsp_kind; + assign logic_pop_sync_readArbitation_translated_payload_read = logic_pop_sync_readPort_rsp_read; + assign logic_pop_sync_readArbitation_translated_payload_write = logic_pop_sync_readPort_rsp_write; + assign logic_pop_sync_readArbitation_translated_payload_data = logic_pop_sync_readPort_rsp_data; + assign io_pop_valid = logic_pop_sync_readArbitation_translated_valid; + assign logic_pop_sync_readArbitation_translated_ready = io_pop_ready; + assign io_pop_payload_kind = logic_pop_sync_readArbitation_translated_payload_kind; + assign io_pop_payload_read = logic_pop_sync_readArbitation_translated_payload_read; + assign io_pop_payload_write = logic_pop_sync_readArbitation_translated_payload_write; + assign io_pop_payload_data = logic_pop_sync_readArbitation_translated_payload_data; + assign logic_pop_sync_readArbitation_fire = (logic_pop_sync_readArbitation_valid && logic_pop_sync_readArbitation_ready); + assign logic_ptr_popOnIo = logic_pop_sync_popReg; + assign io_occupancy = logic_ptr_occupancy; + assign io_availability = (9'h100 - logic_ptr_occupancy); + always @(posedge clk) begin + if(reset) begin + logic_ptr_push <= 9'h0; + logic_ptr_pop <= 9'h0; + logic_ptr_wentUp <= 1'b0; + logic_pop_addressGen_rValid <= 1'b0; + logic_pop_sync_popReg <= 9'h0; + end else begin + if(when_Stream_l1248) begin + logic_ptr_wentUp <= logic_ptr_doPush; + end + if(io_flush) begin + logic_ptr_wentUp <= 1'b0; + end + if(logic_ptr_doPush) begin + logic_ptr_push <= (logic_ptr_push + 9'h001); + end + if(logic_ptr_doPop) begin + logic_ptr_pop <= (logic_ptr_pop + 9'h001); + end + if(io_flush) begin + logic_ptr_push <= 9'h0; + logic_ptr_pop <= 9'h0; + end + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rValid <= logic_pop_addressGen_valid; + end + if(io_flush) begin + logic_pop_addressGen_rValid <= 1'b0; + end + if(logic_pop_sync_readArbitation_fire) begin + logic_pop_sync_popReg <= logic_ptr_pop; + end + if(io_flush) begin + logic_pop_sync_popReg <= 9'h0; + end + end + end + + always @(posedge clk) begin + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rData <= logic_pop_addressGen_payload; + end + end + + +endmodule + +module Axi4PeripheralTopLevel_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_config_kind_cpol, + input wire io_config_kind_cpha, + input wire [11:0] io_config_sclkToggle, + input wire [1:0] io_config_mod, + input wire [3:0] io_config_ss_activeHigh, + input wire [11:0] io_config_ss_setup, + input wire [11:0] io_config_ss_hold, + input wire [11:0] io_config_ss_disable, + input wire io_cmd_valid, + output reg io_cmd_ready, + input wire io_cmd_payload_kind, + input wire io_cmd_payload_read, + input wire io_cmd_payload_write, + input wire [7:0] io_cmd_payload_data, + output wire io_rsp_valid, + output wire [7:0] io_rsp_payload_data, + output wire [0:0] io_spi_sclk_write, + output reg io_spi_data_0_writeEnable, + input wire [0:0] io_spi_data_0_read, + output reg [0:0] io_spi_data_0_write, + output reg io_spi_data_1_writeEnable, + input wire [0:0] io_spi_data_1_read, + output reg [0:0] io_spi_data_1_write, + output reg io_spi_data_2_writeEnable, + input wire [0:0] io_spi_data_2_read, + output reg [0:0] io_spi_data_2_write, + output reg io_spi_data_3_writeEnable, + input wire [0:0] io_spi_data_3_read, + output reg [0:0] io_spi_data_3_write, + output wire [3:0] io_spi_ss, + input wire clk, + input wire reset +); + + reg [0:0] _zz_outputPhy_dataWrite_3; + wire [2:0] _zz_outputPhy_dataWrite_4; + reg [1:0] _zz_outputPhy_dataWrite_5; + wire [1:0] _zz_outputPhy_dataWrite_6; + wire [2:0] _zz_outputPhy_dataWrite_7; + reg [3:0] _zz_outputPhy_dataWrite_8; + wire [0:0] _zz_outputPhy_dataWrite_9; + wire [2:0] _zz_outputPhy_dataWrite_10; + wire [3:0] _zz_inputPhy_dataRead; + wire [3:0] _zz_inputPhy_dataRead_1; + wire [3:0] _zz_inputPhy_dataRead_2; + wire [3:0] _zz_inputPhy_dataRead_3; + wire [3:0] _zz_inputPhy_dataRead_4; + wire [3:0] _zz_inputPhy_dataRead_5; + wire [3:0] _zz_inputPhy_dataRead_6; + wire [8:0] _zz_inputPhy_bufferNext; + wire [10:0] _zz_inputPhy_bufferNext_1; + reg [11:0] timer_counter; + reg timer_reset; + wire timer_ss_setupHit; + wire timer_ss_holdHit; + wire timer_ss_disableHit; + wire timer_sclkToggleHit; + reg fsm_state; + reg [2:0] fsm_counter; + reg [2:0] _zz_fsm_counterPlus; + wire [2:0] fsm_counterPlus; + reg fsm_fastRate; + reg fsm_isDdr; + reg [2:0] fsm_counterMax; + reg fsm_lateSampling; + reg fsm_readFill; + reg fsm_readDone; + reg [3:0] fsm_ss; + wire when_SpiXdrMasterCtrl_l741; + wire when_SpiXdrMasterCtrl_l744; + wire when_SpiXdrMasterCtrl_l751; + wire when_SpiXdrMasterCtrl_l753; + wire when_SpiXdrMasterCtrl_l760; + wire when_SpiXdrMasterCtrl_l766; + wire when_SpiXdrMasterCtrl_l783; + reg [0:0] outputPhy_sclkWrite; + wire [0:0] _zz_io_spi_sclk_write; + wire when_SpiXdrMasterCtrl_l798; + reg [3:0] outputPhy_dataWrite; + reg [2:0] outputPhy_widthSel; + reg [2:0] outputPhy_offset; + wire [7:0] _zz_outputPhy_dataWrite; + wire [7:0] _zz_outputPhy_dataWrite_1; + wire [7:0] _zz_outputPhy_dataWrite_2; + wire when_SpiXdrMasterCtrl_l841; + wire when_SpiXdrMasterCtrl_l841_1; + reg [1:0] io_config_mod_delay_1; + reg [1:0] inputPhy_mod; + reg fsm_readFill_delay_1; + reg inputPhy_readFill; + reg fsm_readDone_delay_1; + reg inputPhy_readDone; + reg [6:0] inputPhy_buffer; + reg [7:0] inputPhy_bufferNext; + reg [2:0] inputPhy_widthSel; + wire [3:0] inputPhy_dataWrite; + reg [3:0] inputPhy_dataRead; + reg fsm_state_delay_1; + reg fsm_state_delay_2; + wire when_SpiXdrMasterCtrl_l863; + reg [3:0] inputPhy_dataReadBuffer; + + assign _zz_outputPhy_dataWrite_4 = (outputPhy_offset - fsm_counter); + assign _zz_outputPhy_dataWrite_6 = (_zz_outputPhy_dataWrite_7 >>> 1'd1); + assign _zz_outputPhy_dataWrite_7 = (outputPhy_offset - fsm_counter); + assign _zz_outputPhy_dataWrite_9 = (_zz_outputPhy_dataWrite_10 >>> 2'd2); + assign _zz_outputPhy_dataWrite_10 = (outputPhy_offset - fsm_counter); + assign _zz_inputPhy_dataRead = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_1 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_2 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_3 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_4 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_5 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_dataRead_6 = {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + assign _zz_inputPhy_bufferNext = {inputPhy_buffer,inputPhy_dataRead[1 : 0]}; + assign _zz_inputPhy_bufferNext_1 = {inputPhy_buffer,inputPhy_dataRead[3 : 0]}; + always @(*) begin + case(_zz_outputPhy_dataWrite_4) + 3'b000 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[0 : 0]; + 3'b001 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[1 : 1]; + 3'b010 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[2 : 2]; + 3'b011 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[3 : 3]; + 3'b100 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[4 : 4]; + 3'b101 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[5 : 5]; + 3'b110 : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[6 : 6]; + default : _zz_outputPhy_dataWrite_3 = _zz_outputPhy_dataWrite[7 : 7]; + endcase + end + + always @(*) begin + case(_zz_outputPhy_dataWrite_6) + 2'b00 : _zz_outputPhy_dataWrite_5 = _zz_outputPhy_dataWrite_1[1 : 0]; + 2'b01 : _zz_outputPhy_dataWrite_5 = _zz_outputPhy_dataWrite_1[3 : 2]; + 2'b10 : _zz_outputPhy_dataWrite_5 = _zz_outputPhy_dataWrite_1[5 : 4]; + default : _zz_outputPhy_dataWrite_5 = _zz_outputPhy_dataWrite_1[7 : 6]; + endcase + end + + always @(*) begin + case(_zz_outputPhy_dataWrite_9) + 1'b0 : _zz_outputPhy_dataWrite_8 = _zz_outputPhy_dataWrite_2[3 : 0]; + default : _zz_outputPhy_dataWrite_8 = _zz_outputPhy_dataWrite_2[7 : 4]; + endcase + end + + always @(*) begin + timer_reset = 1'b0; + if(io_cmd_valid) begin + if(when_SpiXdrMasterCtrl_l741) begin + timer_reset = timer_sclkToggleHit; + end else begin + if(!when_SpiXdrMasterCtrl_l760) begin + if(when_SpiXdrMasterCtrl_l766) begin + if(timer_ss_holdHit) begin + timer_reset = 1'b1; + end + end + end + end + end + if(when_SpiXdrMasterCtrl_l783) begin + timer_reset = 1'b1; + end + end + + assign timer_ss_setupHit = (timer_counter == io_config_ss_setup); + assign timer_ss_holdHit = (timer_counter == io_config_ss_hold); + assign timer_ss_disableHit = (timer_counter == io_config_ss_disable); + assign timer_sclkToggleHit = (timer_counter == io_config_sclkToggle); + always @(*) begin + _zz_fsm_counterPlus = 3'bxxx; + case(io_config_mod) + 2'b00 : begin + _zz_fsm_counterPlus = 3'b001; + end + 2'b01 : begin + _zz_fsm_counterPlus = 3'b010; + end + 2'b10 : begin + _zz_fsm_counterPlus = 3'b100; + end + default : begin + end + endcase + end + + assign fsm_counterPlus = (fsm_counter + _zz_fsm_counterPlus); + always @(*) begin + fsm_fastRate = 1'bx; + case(io_config_mod) + 2'b00 : begin + fsm_fastRate = 1'b0; + end + 2'b01 : begin + fsm_fastRate = 1'b0; + end + 2'b10 : begin + fsm_fastRate = 1'b0; + end + default : begin + end + endcase + end + + always @(*) begin + fsm_isDdr = 1'bx; + case(io_config_mod) + 2'b00 : begin + fsm_isDdr = 1'b0; + end + 2'b01 : begin + fsm_isDdr = 1'b0; + end + 2'b10 : begin + fsm_isDdr = 1'b0; + end + default : begin + end + endcase + end + + always @(*) begin + fsm_counterMax = 3'bxxx; + case(io_config_mod) + 2'b00 : begin + fsm_counterMax = 3'b111; + end + 2'b01 : begin + fsm_counterMax = 3'b110; + end + 2'b10 : begin + fsm_counterMax = 3'b100; + end + default : begin + end + endcase + end + + always @(*) begin + fsm_lateSampling = 1'bx; + case(io_config_mod) + 2'b00 : begin + fsm_lateSampling = 1'b1; + end + 2'b01 : begin + fsm_lateSampling = 1'b1; + end + 2'b10 : begin + fsm_lateSampling = 1'b1; + end + default : begin + end + endcase + end + + always @(*) begin + fsm_readFill = 1'b0; + if(io_cmd_valid) begin + if(when_SpiXdrMasterCtrl_l741) begin + if(when_SpiXdrMasterCtrl_l744) begin + fsm_readFill = 1'b1; + end + end + end + end + + always @(*) begin + fsm_readDone = 1'b0; + if(io_cmd_valid) begin + if(when_SpiXdrMasterCtrl_l741) begin + if(when_SpiXdrMasterCtrl_l744) begin + fsm_readDone = (io_cmd_payload_read && (fsm_counter == fsm_counterMax)); + end + end + end + end + + assign io_spi_ss = (~ (fsm_ss ^ io_config_ss_activeHigh)); + always @(*) begin + io_cmd_ready = 1'b0; + if(io_cmd_valid) begin + if(when_SpiXdrMasterCtrl_l741) begin + if(when_SpiXdrMasterCtrl_l751) begin + if(when_SpiXdrMasterCtrl_l753) begin + io_cmd_ready = 1'b1; + end + end + end else begin + if(when_SpiXdrMasterCtrl_l760) begin + if(timer_ss_setupHit) begin + io_cmd_ready = 1'b1; + end + end else begin + if(!when_SpiXdrMasterCtrl_l766) begin + if(timer_ss_disableHit) begin + io_cmd_ready = 1'b1; + end + end + end + end + end + end + + assign when_SpiXdrMasterCtrl_l741 = (! io_cmd_payload_kind); + assign when_SpiXdrMasterCtrl_l744 = ((timer_sclkToggleHit && (((! fsm_state) ^ fsm_lateSampling) || fsm_isDdr)) || fsm_fastRate); + assign when_SpiXdrMasterCtrl_l751 = ((timer_sclkToggleHit && (fsm_state || fsm_isDdr)) || fsm_fastRate); + assign when_SpiXdrMasterCtrl_l753 = (fsm_counter == fsm_counterMax); + assign when_SpiXdrMasterCtrl_l760 = io_cmd_payload_data[7]; + assign when_SpiXdrMasterCtrl_l766 = (! fsm_state); + assign when_SpiXdrMasterCtrl_l783 = ((! io_cmd_valid) || io_cmd_ready); + always @(*) begin + outputPhy_sclkWrite = 1'b0; + if(when_SpiXdrMasterCtrl_l798) begin + case(io_config_mod) + 2'b00 : begin + outputPhy_sclkWrite = ((fsm_state ^ io_config_kind_cpha) ? 1'b1 : 1'b0); + end + 2'b01 : begin + outputPhy_sclkWrite = ((fsm_state ^ io_config_kind_cpha) ? 1'b1 : 1'b0); + end + 2'b10 : begin + outputPhy_sclkWrite = ((fsm_state ^ io_config_kind_cpha) ? 1'b1 : 1'b0); + end + default : begin + end + endcase + end + end + + assign _zz_io_spi_sclk_write[0] = io_config_kind_cpol; + assign io_spi_sclk_write = (outputPhy_sclkWrite ^ _zz_io_spi_sclk_write); + assign when_SpiXdrMasterCtrl_l798 = (io_cmd_valid && (! io_cmd_payload_kind)); + always @(*) begin + outputPhy_widthSel = 3'bxxx; + case(io_config_mod) + 2'b00 : begin + outputPhy_widthSel = 3'b000; + end + 2'b01 : begin + outputPhy_widthSel = 3'b001; + end + 2'b10 : begin + outputPhy_widthSel = 3'b010; + end + default : begin + end + endcase + end + + always @(*) begin + outputPhy_offset = 3'bxxx; + case(io_config_mod) + 2'b00 : begin + outputPhy_offset = 3'b111; + end + 2'b01 : begin + outputPhy_offset = 3'b111; + end + 2'b10 : begin + outputPhy_offset = 3'b111; + end + default : begin + end + endcase + end + + always @(*) begin + outputPhy_dataWrite = 4'bxxxx; + case(outputPhy_widthSel) + 3'b000 : begin + outputPhy_dataWrite[0 : 0] = _zz_outputPhy_dataWrite_3; + end + 3'b001 : begin + outputPhy_dataWrite[1 : 0] = _zz_outputPhy_dataWrite_5; + end + 3'b010 : begin + outputPhy_dataWrite[3 : 0] = _zz_outputPhy_dataWrite_8; + end + default : begin + end + endcase + end + + assign _zz_outputPhy_dataWrite = io_cmd_payload_data; + assign _zz_outputPhy_dataWrite_1 = io_cmd_payload_data; + assign _zz_outputPhy_dataWrite_2 = io_cmd_payload_data; + always @(*) begin + io_spi_data_0_writeEnable = 1'b0; + case(io_config_mod) + 2'b00 : begin + io_spi_data_0_writeEnable = 1'b1; + end + 2'b01 : begin + if(when_SpiXdrMasterCtrl_l841) begin + io_spi_data_0_writeEnable = 1'b1; + end + end + 2'b10 : begin + if(when_SpiXdrMasterCtrl_l841_1) begin + io_spi_data_0_writeEnable = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_1_writeEnable = 1'b0; + case(io_config_mod) + 2'b01 : begin + if(when_SpiXdrMasterCtrl_l841) begin + io_spi_data_1_writeEnable = 1'b1; + end + end + 2'b10 : begin + if(when_SpiXdrMasterCtrl_l841_1) begin + io_spi_data_1_writeEnable = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_2_writeEnable = 1'b0; + case(io_config_mod) + 2'b10 : begin + if(when_SpiXdrMasterCtrl_l841_1) begin + io_spi_data_2_writeEnable = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_3_writeEnable = 1'b0; + case(io_config_mod) + 2'b10 : begin + if(when_SpiXdrMasterCtrl_l841_1) begin + io_spi_data_3_writeEnable = 1'b1; + end + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_0_write = 1'bx; + case(io_config_mod) + 2'b00 : begin + io_spi_data_0_write[0] = (outputPhy_dataWrite[0] || (! (io_cmd_valid && io_cmd_payload_write))); + end + 2'b01 : begin + io_spi_data_0_write[0] = outputPhy_dataWrite[0]; + end + 2'b10 : begin + io_spi_data_0_write[0] = outputPhy_dataWrite[0]; + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_1_write = 1'bx; + case(io_config_mod) + 2'b01 : begin + io_spi_data_1_write[0] = outputPhy_dataWrite[1]; + end + 2'b10 : begin + io_spi_data_1_write[0] = outputPhy_dataWrite[1]; + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_2_write = 1'bx; + case(io_config_mod) + 2'b10 : begin + io_spi_data_2_write[0] = outputPhy_dataWrite[2]; + end + default : begin + end + endcase + end + + always @(*) begin + io_spi_data_3_write = 1'bx; + case(io_config_mod) + 2'b10 : begin + io_spi_data_3_write[0] = outputPhy_dataWrite[3]; + end + default : begin + end + endcase + end + + assign when_SpiXdrMasterCtrl_l841 = (io_cmd_valid && io_cmd_payload_write); + assign when_SpiXdrMasterCtrl_l841_1 = (io_cmd_valid && io_cmd_payload_write); + always @(*) begin + inputPhy_bufferNext = 8'bxxxxxxxx; + case(inputPhy_widthSel) + 3'b000 : begin + inputPhy_bufferNext = {inputPhy_buffer,inputPhy_dataRead[0 : 0]}; + end + 3'b001 : begin + inputPhy_bufferNext = _zz_inputPhy_bufferNext[7:0]; + end + 3'b010 : begin + inputPhy_bufferNext = _zz_inputPhy_bufferNext_1[7:0]; + end + default : begin + end + endcase + end + + always @(*) begin + inputPhy_widthSel = 3'bxxx; + case(inputPhy_mod) + 2'b00 : begin + inputPhy_widthSel = 3'b000; + end + 2'b01 : begin + inputPhy_widthSel = 3'b001; + end + 2'b10 : begin + inputPhy_widthSel = 3'b010; + end + default : begin + end + endcase + end + + assign when_SpiXdrMasterCtrl_l863 = (! fsm_state_delay_2); + always @(*) begin + inputPhy_dataRead = 4'bxxxx; + case(inputPhy_mod) + 2'b00 : begin + inputPhy_dataRead[0] = _zz_inputPhy_dataRead[1]; + end + 2'b01 : begin + inputPhy_dataRead[0] = _zz_inputPhy_dataRead_1[0]; + inputPhy_dataRead[1] = _zz_inputPhy_dataRead_2[1]; + end + 2'b10 : begin + inputPhy_dataRead[0] = _zz_inputPhy_dataRead_3[0]; + inputPhy_dataRead[1] = _zz_inputPhy_dataRead_4[1]; + inputPhy_dataRead[2] = _zz_inputPhy_dataRead_5[2]; + inputPhy_dataRead[3] = _zz_inputPhy_dataRead_6[3]; + end + default : begin + end + endcase + end + + assign io_rsp_valid = inputPhy_readDone; + assign io_rsp_payload_data = inputPhy_bufferNext; + always @(posedge clk) begin + timer_counter <= (timer_counter + 12'h001); + if(timer_reset) begin + timer_counter <= 12'h0; + end + io_config_mod_delay_1 <= io_config_mod; + inputPhy_mod <= io_config_mod_delay_1; + fsm_state_delay_1 <= fsm_state; + fsm_state_delay_2 <= fsm_state_delay_1; + if(when_SpiXdrMasterCtrl_l863) begin + inputPhy_dataReadBuffer <= {io_spi_data_3_read[0],{io_spi_data_2_read[0],{io_spi_data_1_read[0],io_spi_data_0_read[0]}}}; + end + case(inputPhy_widthSel) + 3'b000 : begin + if(inputPhy_readFill) begin + inputPhy_buffer <= inputPhy_bufferNext[6:0]; + end + end + 3'b001 : begin + if(inputPhy_readFill) begin + inputPhy_buffer <= inputPhy_bufferNext[6:0]; + end + end + 3'b010 : begin + if(inputPhy_readFill) begin + inputPhy_buffer <= inputPhy_bufferNext[6:0]; + end + end + default : begin + end + endcase + end + + always @(posedge clk) begin + if(reset) begin + fsm_state <= 1'b0; + fsm_counter <= 3'b000; + fsm_ss <= 4'b0000; + fsm_readFill_delay_1 <= 1'b0; + inputPhy_readFill <= 1'b0; + fsm_readDone_delay_1 <= 1'b0; + inputPhy_readDone <= 1'b0; + end else begin + if(io_cmd_valid) begin + if(when_SpiXdrMasterCtrl_l741) begin + if(timer_sclkToggleHit) begin + fsm_state <= (! fsm_state); + end + if(when_SpiXdrMasterCtrl_l751) begin + fsm_counter <= fsm_counterPlus; + if(when_SpiXdrMasterCtrl_l753) begin + fsm_state <= 1'b0; + end + end + end else begin + if(when_SpiXdrMasterCtrl_l760) begin + fsm_ss[io_cmd_payload_data[1 : 0]] <= 1'b1; + end else begin + if(when_SpiXdrMasterCtrl_l766) begin + if(timer_ss_holdHit) begin + fsm_state <= 1'b1; + end + end else begin + fsm_ss[io_cmd_payload_data[1 : 0]] <= 1'b0; + end + end + end + end + if(when_SpiXdrMasterCtrl_l783) begin + fsm_state <= 1'b0; + fsm_counter <= 3'b000; + end + fsm_readFill_delay_1 <= fsm_readFill; + inputPhy_readFill <= fsm_readFill_delay_1; + fsm_readDone_delay_1 <= fsm_readDone; + inputPhy_readDone <= fsm_readDone_delay_1; + end + end + + +endmodule + +//Axi4PeripheralStreamFifo_1 replaced by Axi4PeripheralStreamFifo_86b7e1c47b934a8a97a62bda8ee6a75d + +module Axi4PeripheralStreamFifo_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_push_valid, + output wire io_push_ready, + input wire [7:0] io_push_payload, + output wire io_pop_valid, + input wire io_pop_ready, + output wire [7:0] io_pop_payload, + input wire io_flush, + output wire [7:0] io_occupancy, + output wire [7:0] io_availability, + input wire clk, + input wire reset +); + + reg [7:0] logic_ram_spinal_port1; + reg _zz_1; + wire logic_ptr_doPush; + wire logic_ptr_doPop; + wire logic_ptr_full; + wire logic_ptr_empty; + reg [7:0] logic_ptr_push; + reg [7:0] logic_ptr_pop; + wire [7:0] logic_ptr_occupancy; + wire [7:0] logic_ptr_popOnIo; + wire when_Stream_l1248; + reg logic_ptr_wentUp; + wire io_push_fire; + wire logic_push_onRam_write_valid; + wire [6:0] logic_push_onRam_write_payload_address; + wire [7:0] logic_push_onRam_write_payload_data; + wire logic_pop_addressGen_valid; + reg logic_pop_addressGen_ready; + wire [6:0] logic_pop_addressGen_payload; + wire logic_pop_addressGen_fire; + wire logic_pop_sync_readArbitation_valid; + wire logic_pop_sync_readArbitation_ready; + wire [6:0] logic_pop_sync_readArbitation_payload; + reg logic_pop_addressGen_rValid; + reg [6:0] logic_pop_addressGen_rData; + wire when_Stream_l375; + wire logic_pop_sync_readPort_cmd_valid; + wire [6:0] logic_pop_sync_readPort_cmd_payload; + wire [7:0] logic_pop_sync_readPort_rsp; + wire logic_pop_sync_readArbitation_translated_valid; + wire logic_pop_sync_readArbitation_translated_ready; + wire [7:0] logic_pop_sync_readArbitation_translated_payload; + wire logic_pop_sync_readArbitation_fire; + reg [7:0] logic_pop_sync_popReg; + reg [7:0] logic_ram [0:127]; + + always @(posedge clk) begin + if(_zz_1) begin + logic_ram[logic_push_onRam_write_payload_address] <= logic_push_onRam_write_payload_data; + end + end + + always @(posedge clk) begin + if(logic_pop_sync_readPort_cmd_valid) begin + logic_ram_spinal_port1 <= logic_ram[logic_pop_sync_readPort_cmd_payload]; + end + end + + always @(*) begin + _zz_1 = 1'b0; + if(logic_push_onRam_write_valid) begin + _zz_1 = 1'b1; + end + end + + assign when_Stream_l1248 = (logic_ptr_doPush != logic_ptr_doPop); + assign logic_ptr_full = (((logic_ptr_push ^ logic_ptr_popOnIo) ^ 8'h80) == 8'h0); + assign logic_ptr_empty = (logic_ptr_push == logic_ptr_pop); + assign logic_ptr_occupancy = (logic_ptr_push - logic_ptr_popOnIo); + assign io_push_ready = (! logic_ptr_full); + assign io_push_fire = (io_push_valid && io_push_ready); + assign logic_ptr_doPush = io_push_fire; + assign logic_push_onRam_write_valid = io_push_fire; + assign logic_push_onRam_write_payload_address = logic_ptr_push[6:0]; + assign logic_push_onRam_write_payload_data = io_push_payload; + assign logic_pop_addressGen_valid = (! logic_ptr_empty); + assign logic_pop_addressGen_payload = logic_ptr_pop[6:0]; + assign logic_pop_addressGen_fire = (logic_pop_addressGen_valid && logic_pop_addressGen_ready); + assign logic_ptr_doPop = logic_pop_addressGen_fire; + always @(*) begin + logic_pop_addressGen_ready = logic_pop_sync_readArbitation_ready; + if(when_Stream_l375) begin + logic_pop_addressGen_ready = 1'b1; + end + end + + assign when_Stream_l375 = (! logic_pop_sync_readArbitation_valid); + assign logic_pop_sync_readArbitation_valid = logic_pop_addressGen_rValid; + assign logic_pop_sync_readArbitation_payload = logic_pop_addressGen_rData; + assign logic_pop_sync_readPort_rsp = logic_ram_spinal_port1; + assign logic_pop_sync_readPort_cmd_valid = logic_pop_addressGen_fire; + assign logic_pop_sync_readPort_cmd_payload = logic_pop_addressGen_payload; + assign logic_pop_sync_readArbitation_translated_valid = logic_pop_sync_readArbitation_valid; + assign logic_pop_sync_readArbitation_ready = logic_pop_sync_readArbitation_translated_ready; + assign logic_pop_sync_readArbitation_translated_payload = logic_pop_sync_readPort_rsp; + assign io_pop_valid = logic_pop_sync_readArbitation_translated_valid; + assign logic_pop_sync_readArbitation_translated_ready = io_pop_ready; + assign io_pop_payload = logic_pop_sync_readArbitation_translated_payload; + assign logic_pop_sync_readArbitation_fire = (logic_pop_sync_readArbitation_valid && logic_pop_sync_readArbitation_ready); + assign logic_ptr_popOnIo = logic_pop_sync_popReg; + assign io_occupancy = logic_ptr_occupancy; + assign io_availability = (8'h80 - logic_ptr_occupancy); + always @(posedge clk) begin + if(reset) begin + logic_ptr_push <= 8'h0; + logic_ptr_pop <= 8'h0; + logic_ptr_wentUp <= 1'b0; + logic_pop_addressGen_rValid <= 1'b0; + logic_pop_sync_popReg <= 8'h0; + end else begin + if(when_Stream_l1248) begin + logic_ptr_wentUp <= logic_ptr_doPush; + end + if(io_flush) begin + logic_ptr_wentUp <= 1'b0; + end + if(logic_ptr_doPush) begin + logic_ptr_push <= (logic_ptr_push + 8'h01); + end + if(logic_ptr_doPop) begin + logic_ptr_pop <= (logic_ptr_pop + 8'h01); + end + if(io_flush) begin + logic_ptr_push <= 8'h0; + logic_ptr_pop <= 8'h0; + end + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rValid <= logic_pop_addressGen_valid; + end + if(io_flush) begin + logic_pop_addressGen_rValid <= 1'b0; + end + if(logic_pop_sync_readArbitation_fire) begin + logic_pop_sync_popReg <= logic_ptr_pop; + end + if(io_flush) begin + logic_pop_sync_popReg <= 8'h0; + end + end + end + + always @(posedge clk) begin + if(logic_pop_addressGen_ready) begin + logic_pop_addressGen_rData <= logic_pop_addressGen_payload; + end + end + + +endmodule + +module Axi4PeripheralUartCtrl_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire [2:0] io_config_frame_dataLength, + input wire [0:0] io_config_frame_stop, + input wire [1:0] io_config_frame_parity, + input wire [19:0] io_config_clockDivider, + input wire io_write_valid, + output reg io_write_ready, + input wire [7:0] io_write_payload, + output wire io_read_valid, + input wire io_read_ready, + output wire [7:0] io_read_payload, + output wire io_uart_txd, + input wire io_uart_rxd, + output wire io_readError, + input wire io_writeBreak, + output wire io_readBreak, + input wire clk, + input wire reset +); + localparam Axi4PeripheralUartStopType_ONE = 1'd0; + localparam Axi4PeripheralUartStopType_TWO = 1'd1; + localparam Axi4PeripheralUartParityType_NONE = 2'd0; + localparam Axi4PeripheralUartParityType_EVEN = 2'd1; + localparam Axi4PeripheralUartParityType_ODD = 2'd2; + + wire tx_io_write_ready; + wire tx_io_txd; + wire rx_io_read_valid; + wire [7:0] rx_io_read_payload; + wire rx_io_rts; + wire rx_io_error; + wire rx_io_break; + reg [19:0] clockDivider_counter; + wire clockDivider_tick; + reg clockDivider_tickReg; + reg io_write_thrown_valid; + wire io_write_thrown_ready; + wire [7:0] io_write_thrown_payload; + `ifndef SYNTHESIS + reg [23:0] io_config_frame_stop_string; + reg [31:0] io_config_frame_parity_string; + `endif + + + Axi4PeripheralUartCtrlTx_86b7e1c47b934a8a97a62bda8ee6a75d tx ( + .io_configFrame_dataLength (io_config_frame_dataLength[2:0]), //i + .io_configFrame_stop (io_config_frame_stop ), //i + .io_configFrame_parity (io_config_frame_parity[1:0] ), //i + .io_samplingTick (clockDivider_tickReg ), //i + .io_write_valid (io_write_thrown_valid ), //i + .io_write_ready (tx_io_write_ready ), //o + .io_write_payload (io_write_thrown_payload[7:0] ), //i + .io_cts (1'b0 ), //i + .io_txd (tx_io_txd ), //o + .io_break (io_writeBreak ), //i + .clk (clk ), //i + .reset (reset ) //i + ); + Axi4PeripheralUartCtrlRx_86b7e1c47b934a8a97a62bda8ee6a75d rx ( + .io_configFrame_dataLength (io_config_frame_dataLength[2:0]), //i + .io_configFrame_stop (io_config_frame_stop ), //i + .io_configFrame_parity (io_config_frame_parity[1:0] ), //i + .io_samplingTick (clockDivider_tickReg ), //i + .io_read_valid (rx_io_read_valid ), //o + .io_read_ready (io_read_ready ), //i + .io_read_payload (rx_io_read_payload[7:0] ), //o + .io_rxd (io_uart_rxd ), //i + .io_rts (rx_io_rts ), //o + .io_error (rx_io_error ), //o + .io_break (rx_io_break ), //o + .clk (clk ), //i + .reset (reset ) //i + ); + `ifndef SYNTHESIS + always @(*) begin + case(io_config_frame_stop) + Axi4PeripheralUartStopType_ONE : io_config_frame_stop_string = "ONE"; + Axi4PeripheralUartStopType_TWO : io_config_frame_stop_string = "TWO"; + default : io_config_frame_stop_string = "???"; + endcase + end + always @(*) begin + case(io_config_frame_parity) + Axi4PeripheralUartParityType_NONE : io_config_frame_parity_string = "NONE"; + Axi4PeripheralUartParityType_EVEN : io_config_frame_parity_string = "EVEN"; + Axi4PeripheralUartParityType_ODD : io_config_frame_parity_string = "ODD "; + default : io_config_frame_parity_string = "????"; + endcase + end + `endif + + assign clockDivider_tick = (clockDivider_counter == 20'h0); + always @(*) begin + io_write_thrown_valid = io_write_valid; + if(rx_io_break) begin + io_write_thrown_valid = 1'b0; + end + end + + always @(*) begin + io_write_ready = io_write_thrown_ready; + if(rx_io_break) begin + io_write_ready = 1'b1; + end + end + + assign io_write_thrown_payload = io_write_payload; + assign io_write_thrown_ready = tx_io_write_ready; + assign io_read_valid = rx_io_read_valid; + assign io_read_payload = rx_io_read_payload; + assign io_uart_txd = tx_io_txd; + assign io_readError = rx_io_error; + assign io_readBreak = rx_io_break; + always @(posedge clk) begin + if(reset) begin + clockDivider_counter <= 20'h0; + clockDivider_tickReg <= 1'b0; + end else begin + clockDivider_tickReg <= clockDivider_tick; + clockDivider_counter <= (clockDivider_counter - 20'h00001); + if(clockDivider_tick) begin + clockDivider_counter <= io_config_clockDivider; + end + end + end + + +endmodule + +module Axi4PeripheralUartCtrlRx_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire [2:0] io_configFrame_dataLength, + input wire [0:0] io_configFrame_stop, + input wire [1:0] io_configFrame_parity, + input wire io_samplingTick, + output wire io_read_valid, + input wire io_read_ready, + output wire [7:0] io_read_payload, + input wire io_rxd, + output wire io_rts, + output reg io_error, + output wire io_break, + input wire clk, + input wire reset +); + localparam Axi4PeripheralUartStopType_ONE = 1'd0; + localparam Axi4PeripheralUartStopType_TWO = 1'd1; + localparam Axi4PeripheralUartParityType_NONE = 2'd0; + localparam Axi4PeripheralUartParityType_EVEN = 2'd1; + localparam Axi4PeripheralUartParityType_ODD = 2'd2; + localparam Axi4PeripheralUartCtrlRxState_IDLE = 3'd0; + localparam Axi4PeripheralUartCtrlRxState_START = 3'd1; + localparam Axi4PeripheralUartCtrlRxState_DATA = 3'd2; + localparam Axi4PeripheralUartCtrlRxState_PARITY = 3'd3; + localparam Axi4PeripheralUartCtrlRxState_STOP = 3'd4; + + wire io_rxd_buffercc_io_dataOut; + wire _zz_sampler_value; + wire _zz_sampler_value_1; + wire _zz_sampler_value_2; + wire _zz_sampler_value_3; + wire _zz_sampler_value_4; + wire _zz_sampler_value_5; + wire _zz_sampler_value_6; + wire [2:0] _zz_when_UartCtrlRx_l139; + wire [0:0] _zz_when_UartCtrlRx_l139_1; + reg _zz_io_rts; + wire sampler_synchroniser; + wire sampler_samples_0; + reg sampler_samples_1; + reg sampler_samples_2; + reg sampler_samples_3; + reg sampler_samples_4; + reg sampler_value; + reg sampler_tick; + reg [2:0] bitTimer_counter; + reg bitTimer_tick; + wire when_UartCtrlRx_l43; + reg [2:0] bitCounter_value; + reg [6:0] break_counter; + wire break_valid; + wire when_UartCtrlRx_l69; + reg [2:0] stateMachine_state; + reg stateMachine_parity; + reg [7:0] stateMachine_shifter; + reg stateMachine_validReg; + wire when_UartCtrlRx_l93; + wire when_UartCtrlRx_l103; + wire when_UartCtrlRx_l111; + wire when_UartCtrlRx_l113; + wire when_UartCtrlRx_l125; + wire when_UartCtrlRx_l136; + wire when_UartCtrlRx_l139; + `ifndef SYNTHESIS + reg [23:0] io_configFrame_stop_string; + reg [31:0] io_configFrame_parity_string; + reg [47:0] stateMachine_state_string; + `endif + + + assign _zz_when_UartCtrlRx_l139_1 = ((io_configFrame_stop == Axi4PeripheralUartStopType_ONE) ? 1'b0 : 1'b1); + assign _zz_when_UartCtrlRx_l139 = {2'd0, _zz_when_UartCtrlRx_l139_1}; + assign _zz_sampler_value = ((((1'b0 || ((_zz_sampler_value_1 && sampler_samples_1) && sampler_samples_2)) || (((_zz_sampler_value_2 && sampler_samples_0) && sampler_samples_1) && sampler_samples_3)) || (((1'b1 && sampler_samples_0) && sampler_samples_2) && sampler_samples_3)) || (((1'b1 && sampler_samples_1) && sampler_samples_2) && sampler_samples_3)); + assign _zz_sampler_value_3 = (((1'b1 && sampler_samples_0) && sampler_samples_1) && sampler_samples_4); + assign _zz_sampler_value_4 = ((1'b1 && sampler_samples_0) && sampler_samples_2); + assign _zz_sampler_value_5 = (1'b1 && sampler_samples_1); + assign _zz_sampler_value_6 = 1'b1; + assign _zz_sampler_value_1 = (1'b1 && sampler_samples_0); + assign _zz_sampler_value_2 = 1'b1; + (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_86b7e1c47b934a8a97a62bda8ee6a75d io_rxd_buffercc ( + .io_dataIn (io_rxd ), //i + .io_dataOut (io_rxd_buffercc_io_dataOut), //o + .clk (clk ), //i + .reset (reset ) //i + ); + `ifndef SYNTHESIS + always @(*) begin + case(io_configFrame_stop) + Axi4PeripheralUartStopType_ONE : io_configFrame_stop_string = "ONE"; + Axi4PeripheralUartStopType_TWO : io_configFrame_stop_string = "TWO"; + default : io_configFrame_stop_string = "???"; + endcase + end + always @(*) begin + case(io_configFrame_parity) + Axi4PeripheralUartParityType_NONE : io_configFrame_parity_string = "NONE"; + Axi4PeripheralUartParityType_EVEN : io_configFrame_parity_string = "EVEN"; + Axi4PeripheralUartParityType_ODD : io_configFrame_parity_string = "ODD "; + default : io_configFrame_parity_string = "????"; + endcase + end + always @(*) begin + case(stateMachine_state) + Axi4PeripheralUartCtrlRxState_IDLE : stateMachine_state_string = "IDLE "; + Axi4PeripheralUartCtrlRxState_START : stateMachine_state_string = "START "; + Axi4PeripheralUartCtrlRxState_DATA : stateMachine_state_string = "DATA "; + Axi4PeripheralUartCtrlRxState_PARITY : stateMachine_state_string = "PARITY"; + Axi4PeripheralUartCtrlRxState_STOP : stateMachine_state_string = "STOP "; + default : stateMachine_state_string = "??????"; + endcase + end + `endif + + always @(*) begin + io_error = 1'b0; + case(stateMachine_state) + Axi4PeripheralUartCtrlRxState_IDLE : begin + end + Axi4PeripheralUartCtrlRxState_START : begin + end + Axi4PeripheralUartCtrlRxState_DATA : begin + end + Axi4PeripheralUartCtrlRxState_PARITY : begin + if(bitTimer_tick) begin + if(!when_UartCtrlRx_l125) begin + io_error = 1'b1; + end + end + end + default : begin + if(bitTimer_tick) begin + if(when_UartCtrlRx_l136) begin + io_error = 1'b1; + end + end + end + endcase + end + + assign io_rts = _zz_io_rts; + assign sampler_synchroniser = io_rxd_buffercc_io_dataOut; + assign sampler_samples_0 = sampler_synchroniser; + always @(*) begin + bitTimer_tick = 1'b0; + if(sampler_tick) begin + if(when_UartCtrlRx_l43) begin + bitTimer_tick = 1'b1; + end + end + end + + assign when_UartCtrlRx_l43 = (bitTimer_counter == 3'b000); + assign break_valid = (break_counter == 7'h68); + assign when_UartCtrlRx_l69 = (io_samplingTick && (! break_valid)); + assign io_break = break_valid; + assign io_read_valid = stateMachine_validReg; + assign when_UartCtrlRx_l93 = ((sampler_tick && (! sampler_value)) && (! break_valid)); + assign when_UartCtrlRx_l103 = (sampler_value == 1'b1); + assign when_UartCtrlRx_l111 = (bitCounter_value == io_configFrame_dataLength); + assign when_UartCtrlRx_l113 = (io_configFrame_parity == Axi4PeripheralUartParityType_NONE); + assign when_UartCtrlRx_l125 = (stateMachine_parity == sampler_value); + assign when_UartCtrlRx_l136 = (! sampler_value); + assign when_UartCtrlRx_l139 = (bitCounter_value == _zz_when_UartCtrlRx_l139); + assign io_read_payload = stateMachine_shifter; + always @(posedge clk) begin + if(reset) begin + _zz_io_rts <= 1'b0; + sampler_samples_1 <= 1'b1; + sampler_samples_2 <= 1'b1; + sampler_samples_3 <= 1'b1; + sampler_samples_4 <= 1'b1; + sampler_value <= 1'b1; + sampler_tick <= 1'b0; + break_counter <= 7'h0; + stateMachine_state <= Axi4PeripheralUartCtrlRxState_IDLE; + stateMachine_validReg <= 1'b0; + end else begin + _zz_io_rts <= (! io_read_ready); + if(io_samplingTick) begin + sampler_samples_1 <= sampler_samples_0; + end + if(io_samplingTick) begin + sampler_samples_2 <= sampler_samples_1; + end + if(io_samplingTick) begin + sampler_samples_3 <= sampler_samples_2; + end + if(io_samplingTick) begin + sampler_samples_4 <= sampler_samples_3; + end + sampler_value <= ((((((_zz_sampler_value || _zz_sampler_value_3) || (_zz_sampler_value_4 && sampler_samples_4)) || ((_zz_sampler_value_5 && sampler_samples_2) && sampler_samples_4)) || (((_zz_sampler_value_6 && sampler_samples_0) && sampler_samples_3) && sampler_samples_4)) || (((1'b1 && sampler_samples_1) && sampler_samples_3) && sampler_samples_4)) || (((1'b1 && sampler_samples_2) && sampler_samples_3) && sampler_samples_4)); + sampler_tick <= io_samplingTick; + if(sampler_value) begin + break_counter <= 7'h0; + end else begin + if(when_UartCtrlRx_l69) begin + break_counter <= (break_counter + 7'h01); + end + end + stateMachine_validReg <= 1'b0; + case(stateMachine_state) + Axi4PeripheralUartCtrlRxState_IDLE : begin + if(when_UartCtrlRx_l93) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_START; + end + end + Axi4PeripheralUartCtrlRxState_START : begin + if(bitTimer_tick) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_DATA; + if(when_UartCtrlRx_l103) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_IDLE; + end + end + end + Axi4PeripheralUartCtrlRxState_DATA : begin + if(bitTimer_tick) begin + if(when_UartCtrlRx_l111) begin + if(when_UartCtrlRx_l113) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_STOP; + stateMachine_validReg <= 1'b1; + end else begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_PARITY; + end + end + end + end + Axi4PeripheralUartCtrlRxState_PARITY : begin + if(bitTimer_tick) begin + if(when_UartCtrlRx_l125) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_STOP; + stateMachine_validReg <= 1'b1; + end else begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_IDLE; + end + end + end + default : begin + if(bitTimer_tick) begin + if(when_UartCtrlRx_l136) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_IDLE; + end else begin + if(when_UartCtrlRx_l139) begin + stateMachine_state <= Axi4PeripheralUartCtrlRxState_IDLE; + end + end + end + end + endcase + end + end + + always @(posedge clk) begin + if(sampler_tick) begin + bitTimer_counter <= (bitTimer_counter - 3'b001); + end + if(bitTimer_tick) begin + bitCounter_value <= (bitCounter_value + 3'b001); + end + if(bitTimer_tick) begin + stateMachine_parity <= (stateMachine_parity ^ sampler_value); + end + case(stateMachine_state) + Axi4PeripheralUartCtrlRxState_IDLE : begin + if(when_UartCtrlRx_l93) begin + bitTimer_counter <= 3'b010; + end + end + Axi4PeripheralUartCtrlRxState_START : begin + if(bitTimer_tick) begin + bitCounter_value <= 3'b000; + stateMachine_parity <= (io_configFrame_parity == Axi4PeripheralUartParityType_ODD); + end + end + Axi4PeripheralUartCtrlRxState_DATA : begin + if(bitTimer_tick) begin + stateMachine_shifter[bitCounter_value] <= sampler_value; + if(when_UartCtrlRx_l111) begin + bitCounter_value <= 3'b000; + end + end + end + Axi4PeripheralUartCtrlRxState_PARITY : begin + if(bitTimer_tick) begin + bitCounter_value <= 3'b000; + end + end + default : begin + end + endcase + end + + +endmodule + +module Axi4PeripheralUartCtrlTx_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire [2:0] io_configFrame_dataLength, + input wire [0:0] io_configFrame_stop, + input wire [1:0] io_configFrame_parity, + input wire io_samplingTick, + input wire io_write_valid, + output reg io_write_ready, + input wire [7:0] io_write_payload, + input wire io_cts, + output wire io_txd, + input wire io_break, + input wire clk, + input wire reset +); + localparam Axi4PeripheralUartStopType_ONE = 1'd0; + localparam Axi4PeripheralUartStopType_TWO = 1'd1; + localparam Axi4PeripheralUartParityType_NONE = 2'd0; + localparam Axi4PeripheralUartParityType_EVEN = 2'd1; + localparam Axi4PeripheralUartParityType_ODD = 2'd2; + localparam Axi4PeripheralUartCtrlTxState_IDLE = 3'd0; + localparam Axi4PeripheralUartCtrlTxState_START = 3'd1; + localparam Axi4PeripheralUartCtrlTxState_DATA = 3'd2; + localparam Axi4PeripheralUartCtrlTxState_PARITY = 3'd3; + localparam Axi4PeripheralUartCtrlTxState_STOP = 3'd4; + + wire [2:0] _zz_clockDivider_counter_valueNext; + wire [0:0] _zz_clockDivider_counter_valueNext_1; + wire [2:0] _zz_when_UartCtrlTx_l93; + wire [0:0] _zz_when_UartCtrlTx_l93_1; + reg clockDivider_counter_willIncrement; + wire clockDivider_counter_willClear; + reg [2:0] clockDivider_counter_valueNext; + reg [2:0] clockDivider_counter_value; + wire clockDivider_counter_willOverflowIfInc; + wire clockDivider_counter_willOverflow; + reg [2:0] tickCounter_value; + reg [2:0] stateMachine_state; + reg stateMachine_parity; + reg stateMachine_txd; + wire when_UartCtrlTx_l58; + wire when_UartCtrlTx_l73; + wire when_UartCtrlTx_l76; + wire when_UartCtrlTx_l93; + wire [2:0] _zz_stateMachine_state; + reg _zz_io_txd; + `ifndef SYNTHESIS + reg [23:0] io_configFrame_stop_string; + reg [31:0] io_configFrame_parity_string; + reg [47:0] stateMachine_state_string; + reg [47:0] _zz_stateMachine_state_string; + `endif + + + assign _zz_clockDivider_counter_valueNext_1 = clockDivider_counter_willIncrement; + assign _zz_clockDivider_counter_valueNext = {2'd0, _zz_clockDivider_counter_valueNext_1}; + assign _zz_when_UartCtrlTx_l93_1 = ((io_configFrame_stop == Axi4PeripheralUartStopType_ONE) ? 1'b0 : 1'b1); + assign _zz_when_UartCtrlTx_l93 = {2'd0, _zz_when_UartCtrlTx_l93_1}; + `ifndef SYNTHESIS + always @(*) begin + case(io_configFrame_stop) + Axi4PeripheralUartStopType_ONE : io_configFrame_stop_string = "ONE"; + Axi4PeripheralUartStopType_TWO : io_configFrame_stop_string = "TWO"; + default : io_configFrame_stop_string = "???"; + endcase + end + always @(*) begin + case(io_configFrame_parity) + Axi4PeripheralUartParityType_NONE : io_configFrame_parity_string = "NONE"; + Axi4PeripheralUartParityType_EVEN : io_configFrame_parity_string = "EVEN"; + Axi4PeripheralUartParityType_ODD : io_configFrame_parity_string = "ODD "; + default : io_configFrame_parity_string = "????"; + endcase + end + always @(*) begin + case(stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : stateMachine_state_string = "IDLE "; + Axi4PeripheralUartCtrlTxState_START : stateMachine_state_string = "START "; + Axi4PeripheralUartCtrlTxState_DATA : stateMachine_state_string = "DATA "; + Axi4PeripheralUartCtrlTxState_PARITY : stateMachine_state_string = "PARITY"; + Axi4PeripheralUartCtrlTxState_STOP : stateMachine_state_string = "STOP "; + default : stateMachine_state_string = "??????"; + endcase + end + always @(*) begin + case(_zz_stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : _zz_stateMachine_state_string = "IDLE "; + Axi4PeripheralUartCtrlTxState_START : _zz_stateMachine_state_string = "START "; + Axi4PeripheralUartCtrlTxState_DATA : _zz_stateMachine_state_string = "DATA "; + Axi4PeripheralUartCtrlTxState_PARITY : _zz_stateMachine_state_string = "PARITY"; + Axi4PeripheralUartCtrlTxState_STOP : _zz_stateMachine_state_string = "STOP "; + default : _zz_stateMachine_state_string = "??????"; + endcase + end + `endif + + always @(*) begin + clockDivider_counter_willIncrement = 1'b0; + if(io_samplingTick) begin + clockDivider_counter_willIncrement = 1'b1; + end + end + + assign clockDivider_counter_willClear = 1'b0; + assign clockDivider_counter_willOverflowIfInc = (clockDivider_counter_value == 3'b111); + assign clockDivider_counter_willOverflow = (clockDivider_counter_willOverflowIfInc && clockDivider_counter_willIncrement); + always @(*) begin + clockDivider_counter_valueNext = (clockDivider_counter_value + _zz_clockDivider_counter_valueNext); + if(clockDivider_counter_willClear) begin + clockDivider_counter_valueNext = 3'b000; + end + end + + always @(*) begin + stateMachine_txd = 1'b1; + case(stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : begin + end + Axi4PeripheralUartCtrlTxState_START : begin + stateMachine_txd = 1'b0; + end + Axi4PeripheralUartCtrlTxState_DATA : begin + stateMachine_txd = io_write_payload[tickCounter_value]; + end + Axi4PeripheralUartCtrlTxState_PARITY : begin + stateMachine_txd = stateMachine_parity; + end + default : begin + end + endcase + end + + always @(*) begin + io_write_ready = io_break; + case(stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : begin + end + Axi4PeripheralUartCtrlTxState_START : begin + end + Axi4PeripheralUartCtrlTxState_DATA : begin + if(clockDivider_counter_willOverflow) begin + if(when_UartCtrlTx_l73) begin + io_write_ready = 1'b1; + end + end + end + Axi4PeripheralUartCtrlTxState_PARITY : begin + end + default : begin + end + endcase + end + + assign when_UartCtrlTx_l58 = ((io_write_valid && (! io_cts)) && clockDivider_counter_willOverflow); + assign when_UartCtrlTx_l73 = (tickCounter_value == io_configFrame_dataLength); + assign when_UartCtrlTx_l76 = (io_configFrame_parity == Axi4PeripheralUartParityType_NONE); + assign when_UartCtrlTx_l93 = (tickCounter_value == _zz_when_UartCtrlTx_l93); + assign _zz_stateMachine_state = (io_write_valid ? Axi4PeripheralUartCtrlTxState_START : Axi4PeripheralUartCtrlTxState_IDLE); + assign io_txd = _zz_io_txd; + always @(posedge clk) begin + if(reset) begin + clockDivider_counter_value <= 3'b000; + stateMachine_state <= Axi4PeripheralUartCtrlTxState_IDLE; + _zz_io_txd <= 1'b1; + end else begin + clockDivider_counter_value <= clockDivider_counter_valueNext; + case(stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : begin + if(when_UartCtrlTx_l58) begin + stateMachine_state <= Axi4PeripheralUartCtrlTxState_START; + end + end + Axi4PeripheralUartCtrlTxState_START : begin + if(clockDivider_counter_willOverflow) begin + stateMachine_state <= Axi4PeripheralUartCtrlTxState_DATA; + end + end + Axi4PeripheralUartCtrlTxState_DATA : begin + if(clockDivider_counter_willOverflow) begin + if(when_UartCtrlTx_l73) begin + if(when_UartCtrlTx_l76) begin + stateMachine_state <= Axi4PeripheralUartCtrlTxState_STOP; + end else begin + stateMachine_state <= Axi4PeripheralUartCtrlTxState_PARITY; + end + end + end + end + Axi4PeripheralUartCtrlTxState_PARITY : begin + if(clockDivider_counter_willOverflow) begin + stateMachine_state <= Axi4PeripheralUartCtrlTxState_STOP; + end + end + default : begin + if(clockDivider_counter_willOverflow) begin + if(when_UartCtrlTx_l93) begin + stateMachine_state <= _zz_stateMachine_state; + end + end + end + endcase + _zz_io_txd <= (stateMachine_txd && (! io_break)); + end + end + + always @(posedge clk) begin + if(clockDivider_counter_willOverflow) begin + tickCounter_value <= (tickCounter_value + 3'b001); + end + if(clockDivider_counter_willOverflow) begin + stateMachine_parity <= (stateMachine_parity ^ stateMachine_txd); + end + case(stateMachine_state) + Axi4PeripheralUartCtrlTxState_IDLE : begin + end + Axi4PeripheralUartCtrlTxState_START : begin + if(clockDivider_counter_willOverflow) begin + stateMachine_parity <= (io_configFrame_parity == Axi4PeripheralUartParityType_ODD); + tickCounter_value <= 3'b000; + end + end + Axi4PeripheralUartCtrlTxState_DATA : begin + if(clockDivider_counter_willOverflow) begin + if(when_UartCtrlTx_l73) begin + tickCounter_value <= 3'b000; + end + end + end + Axi4PeripheralUartCtrlTxState_PARITY : begin + if(clockDivider_counter_willOverflow) begin + tickCounter_value <= 3'b000; + end + end + default : begin + end + endcase + end + + +endmodule + +module Axi4PeripheralBufferCC_86b7e1c47b934a8a97a62bda8ee6a75d ( + input wire io_dataIn, + output wire io_dataOut, + input wire clk, + input wire reset +); + + (* async_reg = "true" *) reg buffers_0; + (* async_reg = "true" *) reg buffers_1; + + assign io_dataOut = buffers_1; + always @(posedge clk) begin + if(reset) begin + buffers_0 <= 1'b0; + buffers_1 <= 1'b0; + end else begin + buffers_0 <= io_dataIn; + buffers_1 <= buffers_0; + end + end + + +endmodule + +`undef IP_UUID +`undef IP_NAME_CONCAT +`undef IP_MODULE_NAME diff --git a/Ti375C529_devkit/EfxSapphireHpSoc_slb_define.vh b/Ti375C529_devkit/EfxSapphireHpSoc_slb_define.vh new file mode 100644 index 0000000..7d939b0 --- /dev/null +++ b/Ti375C529_devkit/EfxSapphireHpSoc_slb_define.vh @@ -0,0 +1,46 @@ +// ============================================================================= +// Generated by efx_ipmgr +// Version: 2025.2.288.2.10 +// IP Version: 1.22.0 +// ============================================================================= + +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +//////////////////////////////////////////////////////////////////////////////// + +localparam PERI_FREQ = 250; diff --git a/Ti375C529_devkit/Ti375C529_devkit.isf b/Ti375C529_devkit/Ti375C529_devkit.isf index f47d39d..4f3d790 100644 --- a/Ti375C529_devkit/Ti375C529_devkit.isf +++ b/Ti375C529_devkit/Ti375C529_devkit.isf @@ -1,8 +1,8 @@ # Efinity Interface Configuration -# Version: 2026.1.132 -# Date: 2026-08-08 20:48 +# Version: 2025.2.288.2.10 +# Date: 2026-08-09 19:10 # -# Copyright (C) 2013 - 2026 Efinix Inc. All rights reserved. +# Copyright (C) 2013 - 2025 Efinix Inc. All rights reserved. # # Device: Ti375C529 # Package: 529-ball FBGA (final) @@ -90,7 +90,6 @@ design.set_device_property("Top","CORE2_PIN","","CLKMUX") design.set_device_property("Top","CORE3_PIN","","CLKMUX") design.set_device_property("Top","DYN_MUX0_EN","0","CLKMUX") design.set_device_property("Top","DYN_MUX7_EN","0","CLKMUX") -design.set_gpio_unused_state("INPUT_WEAK_PULLUP") # Create instance design.create_block("soc_jtag_inst1","JTAG") @@ -251,7 +250,7 @@ design.set_property("qcrv32_inst1","JTAGCTRL_TDO_PIN","jtagCtrl_tdo","SOC") design.set_property("qcrv32_inst1","JTAGCTRL_UPDATE_PIN","jtagCtrl_update","SOC") design.set_property("qcrv32_inst1","JTAG_TYPE","FPGA","SOC") design.set_property("qcrv32_inst1","MEM_CLK_SOURCE","Clock 0","SOC") -design.set_property("qcrv32_inst1","OCR_FILE_PATH","EfxSapphireHpSoc_bootloader/default_bootloader.hex","SOC") +design.set_property("qcrv32_inst1","OCR_FILE_PATH","","SOC") design.set_property("qcrv32_inst1","PIPELINE_SOC_AXI_MEM_INTERFACE_EN","0","SOC") design.set_property("qcrv32_inst1","SYS_CLK_SOURCE","Clock 0","SOC") design.set_property("qcrv32_inst1","USERINTERRUPTA_PIN","userInterruptA","SOC") diff --git a/Ti375C529_devkit/Ti375C529_devkit.peri.xml b/Ti375C529_devkit/Ti375C529_devkit.peri.xml index 7e3cac2..7017750 100644 --- a/Ti375C529_devkit/Ti375C529_devkit.peri.xml +++ b/Ti375C529_devkit/Ti375C529_devkit.peri.xml @@ -1,5 +1,5 @@ - + @@ -248,13 +248,13 @@ - + @@ -295,13 +295,13 @@ - + @@ -346,13 +346,13 @@ - + @@ -559,7 +559,6 @@ - @@ -665,7 +664,7 @@ - + diff --git a/Ti375C529_devkit/Ti375C529_devkit.xml b/Ti375C529_devkit/Ti375C529_devkit.xml index 287b280..8434420 100644 --- a/Ti375C529_devkit/Ti375C529_devkit.xml +++ b/Ti375C529_devkit/Ti375C529_devkit.xml @@ -1,11 +1,11 @@ - + - + @@ -13,14 +13,7 @@ - - - - - - - diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00history.txt b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00history.txt new file mode 100644 index 0000000..7a153a2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00history.txt @@ -0,0 +1,369 @@ +---------------------------------------------------------------------------- + Revision history of FatFs module +---------------------------------------------------------------------------- + +R0.00 (February 26, 2006) + + Prototype. + + + +R0.01 (April 29, 2006) + + The first release. + + + +R0.02 (June 01, 2006) + + Added FAT12 support. + Removed unbuffered mode. + Fixed a problem on small (<32M) partition. + + + +R0.02a (June 10, 2006) + + Added a configuration option (_FS_MINIMUM). + + + +R0.03 (September 22, 2006) + + Added f_rename(). + Changed option _FS_MINIMUM to _FS_MINIMIZE. + + + +R0.03a (December 11, 2006) + + Improved cluster scan algorithm to write files fast. + Fixed f_mkdir() creates incorrect directory on FAT32. + + + +R0.04 (February 04, 2007) + + Added f_mkfs(). + Supported multiple drive system. + Changed some interfaces for multiple drive system. + Changed f_mountdrv() to f_mount(). + + + +R0.04a (April 01, 2007) + + Supported multiple partitions on a physical drive. + Added a capability of extending file size to f_lseek(). + Added minimization level 3. + Fixed an endian sensitive code in f_mkfs(). + + + +R0.04b (May 05, 2007) + + Added a configuration option _USE_NTFLAG. + Added FSINFO support. + Fixed DBCS name can result FR_INVALID_NAME. + Fixed short seek (<= csize) collapses the file object. + + + +R0.05 (August 25, 2007) + + Changed arguments of f_read(), f_write() and f_mkfs(). + Fixed f_mkfs() on FAT32 creates incorrect FSINFO. + Fixed f_mkdir() on FAT32 creates incorrect directory. + + + +R0.05a (February 03, 2008) + + Added f_truncate() and f_utime(). + Fixed off by one error at FAT sub-type determination. + Fixed btr in f_read() can be mistruncated. + Fixed cached sector is not flushed when create and close without write. + + + +R0.06 (April 01, 2008) + + Added fputc(), fputs(), fprintf() and fgets(). + Improved performance of f_lseek() on moving to the same or following cluster. + + + +R0.07 (April 01, 2009) + + Merged Tiny-FatFs as a configuration option. (_FS_TINY) + Added long file name feature. (_USE_LFN) + Added multiple code page feature. (_CODE_PAGE) + Added re-entrancy for multitask operation. (_FS_REENTRANT) + Added auto cluster size selection to f_mkfs(). + Added rewind option to f_readdir(). + Changed result code of critical errors. + Renamed string functions to avoid name collision. + + + +R0.07a (April 14, 2009) + + Septemberarated out OS dependent code on reentrant cfg. + Added multiple sector size feature. + + + +R0.07c (June 21, 2009) + + Fixed f_unlink() can return FR_OK on error. + Fixed wrong cache control in f_lseek(). + Added relative path feature. + Added f_chdir() and f_chdrive(). + Added proper case conversion to extended character. + + + +R0.07e (November 03, 2009) + + Septemberarated out configuration options from ff.h to ffconf.h. + Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. + Fixed name matching error on the 13 character boundary. + Added a configuration option, _LFN_UNICODE. + Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. + + + +R0.08 (May 15, 2010) + + Added a memory configuration option. (_USE_LFN = 3) + Added file lock feature. (_FS_SHARE) + Added fast seek feature. (_USE_FASTSEEK) + Changed some types on the API, XCHAR->TCHAR. + Changed .fname in the FILINFO structure on Unicode cfg. + String functions support UTF-8 encoding files on Unicode cfg. + + + +R0.08a (August 16, 2010) + + Added f_getcwd(). (_FS_RPATH = 2) + Added sector erase feature. (_USE_ERASE) + Moved file lock semaphore table from fs object to the bss. + Fixed f_mkfs() creates wrong FAT32 volume. + + + +R0.08b (January 15, 2011) + + Fast seek feature is also applied to f_read() and f_write(). + f_lseek() reports required table size on creating CLMP. + Extended format syntax of f_printf(). + Ignores duplicated directory separators in given path name. + + + +R0.09 (September 06, 2011) + + f_mkfs() supports multiple partition to complete the multiple partition feature. + Added f_fdisk(). + + + +R0.09a (August 27, 2012) + + Changed f_open() and f_opendir() reject null object pointer to avoid crash. + Changed option name _FS_SHARE to _FS_LOCK. + Fixed assertion failure due to OS/2 EA on FAT12/16 volume. + + + +R0.09b (January 24, 2013) + + Added f_setlabel() and f_getlabel(). + + + +R0.10 (October 02, 2013) + + Added selection of character encoding on the file. (_STRF_ENCODE) + Added f_closedir(). + Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) + Added forced mount feature with changes of f_mount(). + Improved behavior of volume auto detection. + Improved write throughput of f_puts() and f_printf(). + Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). + Fixed f_write() can be truncated when the file size is close to 4GB. + Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. + + + +R0.10a (January 15, 2014) + + Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) + Added a configuration option of minimum sector size. (_MIN_SS) + 2nd argument of f_rename() can have a drive number and it will be ignored. + Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) + Fixed f_close() invalidates the file object without volume lock. + Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) + Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) + + + +R0.10b (May 19, 2014) + + Fixed a hard error in the disk I/O layer can collapse the directory entry. + Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) + + + +R0.10c (November 09, 2014) + + Added a configuration option for the platforms without RTC. (_FS_NORTC) + Changed option name _USE_ERASE to _USE_TRIM. + Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) + Fixed a potential problem of FAT access that can appear on disk error. + Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) + + + +R0.11 (February 09, 2015) + + Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) + Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) + Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) + + + +R0.11a (September 05, 2015) + + Fixed wrong media change can lead a deadlock at thread-safe configuration. + Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) + Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) + Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). + Fixed errors in the case conversion teble of Unicode (cc*.c). + + + +R0.12 (April 12, 2016) + + Added support for exFAT file system. (_FS_EXFAT) + Added f_expand(). (_USE_EXPAND) + Changed some members in FINFO structure and behavior of f_readdir(). + Added an option _USE_CHMOD. + Removed an option _WORD_ACCESS. + Fixed errors in the case conversion table of Unicode (cc*.c). + + + +R0.12a (July 10, 2016) + + Added support for creating exFAT volume with some changes of f_mkfs(). + Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. + f_forward() is available regardless of _FS_TINY. + Fixed f_mkfs() creates wrong volume. (appeared at R0.12) + Fixed wrong memory read in create_name(). (appeared at R0.12) + Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. + + + +R0.12b (September 04, 2016) + + Made f_rename() be able to rename objects with the same name but case. + Fixed an error in the case conversion teble of code page 866. (ff.c) + Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) + Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) + Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) + Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) + Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) + Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) + + + +R0.12c (March 04, 2017) + + Improved write throughput at the fragmented file on the exFAT volume. + Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. + Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) + Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) + + + +R0.13 (May 21, 2017) + + Changed heading character of configuration keywords "_" to "FF_". + Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead. + Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0) + Improved cluster allocation time on stretch a deep buried cluster chain. + Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3. + Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous. + Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12) + Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) + Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) + + + +R0.13a (October 14, 2017) + + Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2) + Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF). + Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk(). + Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09) + Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c) + Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) + + + +R0.13b (April 07, 2018) + + Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3) + Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2) + Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c) + Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b) + + + +R0.13c (October 14, 2018) + Supported stdint.h for C99 and later. (integer.h was included in ff.h) + Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12) + Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12) + Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b) + + + +R0.14 (October 14, 2019) + Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1) + Changed some API functions, f_mkfs() and f_fdisk(). + Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. + Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. + Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12) + Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12) + + +R0.14a (December 5, 2020) + Limited number of recursive calls in f_findnext(). + Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted. + Fixed some compiler warnings. + + + +R0.14b (April 17, 2021) + Made FatFs uses standard library for copy, compare and search instead of built-in string functions. + Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP) + Made path name parser ignore the terminating separator to allow "dir/". + Improved the compatibility in Unix style path name feature. + Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a) + Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12) + Fixed code page 855 cannot be set by f_setcp(). + Fixed some compiler warnings. + + + +R0.15 (November 6, 2022) + Changed user provided synchronization functions in order to completely eliminate the platform dependency from FatFs code. + FF_SYNC_t is removed from the configuration options. + Fixed a potential error in f_mount when FF_FS_REENTRANT. + Fixed file lock control FF_FS_LOCK is not mutal excluded when FF_FS_REENTRANT && FF_VOLUMES > 1 is true. + Fixed f_mkfs() creates broken exFAT volume when the size of volume is >= 2^32 sectors. + Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8). + Fixed a compatibility issue in identification of GPT header. + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00readme.txt b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00readme.txt new file mode 100644 index 0000000..3de3aea --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/00readme.txt @@ -0,0 +1,21 @@ +FatFs Module Source Files R0.15 + + +FILES + + 00readme.txt This file. + 00history.txt Revision history. + ff.c FatFs module. + ffconf.h Configuration file of FatFs module. + ff.h Common include file for FatFs and application module. + diskio.h Common include file for FatFs and disk I/O module. + diskio.c An example of glue function to attach existing disk I/O module to FatFs. + ffunicode.c Optional Unicode utility functions. + ffsystem.c An example of optional O/S related functions. + + + Low level disk I/O module is not included in this archive because the FatFs + module is only a generic file system layer and it does not depend on any specific + storage device. You need to provide a low level disk I/O module written to + control the storage device that attached to the target system. + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.c new file mode 100644 index 0000000..7408349 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.c @@ -0,0 +1,444 @@ +#include "diskio.h" + +extern BYTE interface_selector; +uint8_t buffer [20]; +static volatile DSTATUS Stat = STA_NOINIT; /* Physical drive status */ + +static void deselect(void); +static int xmit_datablock( /* 1:OK, 0:Failed */ +const BYTE *buff, /* 512 byte data block to be transmitted */ +BYTE token /* Data/Stop token */ +); +static int rcvr_datablock( /* 1:OK, 0:Failed */ +BYTE *buff, /* Data buffer to store received data */ +UINT btr /* Byte count */ +); +static int select(void); +static void rcvr_mmc(BYTE *buff, /* Pointer to read buffer */ +UINT bc /* Number of bytes to receive */ +); +static void xmit_mmc(const BYTE *buff, /* Data to be sent */ +UINT bc /* Number of bytes to send */ +); +static BYTE spi_send_cmd( /* Returns command response (bit7==1:Send failed)*/ +BYTE cmd, /* Command byte */ +DWORD arg /* Argument */ +); +static void dly_us(UINT n); + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + +static void sd_read_csd(struct mmc *mmc, struct mmc_cmd *cmd) +{ + sd_send_cmd(mmc,cmd,MMC_CMD_SEND_CSD,MMC_RSP_R2,(mmc->rca<<16)); // CMD9 // get card specific data (CSD) + mmc->csd[0]= cmd->response[0]; + mmc->csd[1]= cmd->response[1]; + mmc->csd[2]= cmd->response[2]; + mmc->csd[3]= cmd->response[3]; + + mmc->capacity = (((mmc->csd[1]>>8) &0x3FFFFF)+1)*512; + mmc->capacity *=1024; + mmc->tran_speed = multipliers[(mmc->csd[2]>>27) &0x07] * fbase[(mmc->csd[2]>>24) &0x03]; + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("CSD 0x%x 0x%x 0x%x 0x%x\r\n",mmc->csd[0],mmc->csd[1],mmc->csd[2],mmc->csd[3]); + bsp_printf("FILE_FORMAT = %d\r\n",(mmc->csd[0]>>2) &0x03); //[11:10] + bsp_printf("TMP_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>4) &0x01);//[12] + bsp_printf("PERM_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>5) &0x01);//[13] + bsp_printf("COPY = %d\r\n",(mmc->csd[0]>>6) &0x01); //[14] + bsp_printf("FILE_FORMAT_GRP = %d\r\n",(mmc->csd[0]>>7) &0x01);//[15] + //[20:16] + bsp_printf("WRITE_BL_PARTIAL = %d\r\n",(mmc->csd[0]>>13) &0x01);//[21] + bsp_printf("WRITE_BL_LEN = %d\r\n",(mmc->csd[0]>>14) &0x0F);//[25:22] + bsp_printf("R2W_FACTOR = %d\r\n",(mmc->csd[0]>>18) &0x07);//[28:26] + //[30:29] + bsp_printf("WP_GRP_ENABLE = %d\r\n",(mmc->csd[0]>>23) &0x01);//[31] + + bsp_printf("WP_GRP_SIZE = %d\r\n",(mmc->csd[0]>>24) &0x7F);//[38:32] + + bsp_printf("SECTOR_SIZE = %d\r\n",((mmc->csd[1] & 0x3F)<<1)|((mmc->csd[0])>>31 &0x1));//[45:39] + bsp_printf("ERASE_BLK_EN = %d\r\n",(mmc->csd[1]>>6) &0x01);//[46] + //[47] + bsp_printf("C_SIZE = %d\r\n",(mmc->csd[1]>>8) &0x3FFFFF);//[69:48] + //[75:70] + bsp_printf("DSR_IMP = %d\r\n",(mmc->csd[2]>>4) &0x01);//[76] + bsp_printf("READ_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>5) &0x01);//[77] + bsp_printf("WRITE_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>6) &0x01);//[78] + bsp_printf("READ_BL_PARTIAL = %d\r\n",(mmc->csd[2]>>7) &0x01);//[79] + bsp_printf("READ_BL_LEN = %d\r\n",(mmc->csd[2]>>8) &0x0F);//[83:80] + bsp_printf("CCC = %d\r\n",(mmc->csd[2]>>12) &0x0FFF);//[95:84] + bsp_printf("TRAN_SPEED = 0x%x\r\n",(mmc->csd[2]>>24) &0x0FF);//[103:96] + bsp_printf("NSAC = 0x%x\r\n",(mmc->csd[3]) &0x0FF);//[111:104] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>8) &0x0FF);//[119:112] + //[125:120] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>22) &0x03);//[127:126] + bsp_printf("mmc->capacity = %d\r\n",(((mmc->csd[1]>>8) &0x3FFFFF)+1)*512); + bsp_printf("mmc->tran_speed = %d\r\n",mmc->tran_speed); +#endif //(DEBUG_PRINTF_EN == 1) +} + + +u32 getdata_fatfs() { + getdata(&myConfig); + u8 seconds, minutes, hours, dayOfWeek, days, months, years, timesystem; + //READ TIME FROM RTC + seconds = get_seconds(&myConfig); + minutes = get_minutes(&myConfig); + if (myConfig.timesystem && myConfig.PM) + hours = myConfig.hours +12; + else + hours = myConfig.hours; + dayOfWeek = get_weekdays(&myConfig); + days = get_days(&myConfig); + months = get_months(&myConfig); + years = get_years(&myConfig); + seconds = seconds/2; + years = ((years + 2000) - 1980); + + u32 ret = (((years & 0x7F) << 25) | ((months & 0x0F) << 21) | ((days & 0x1F) << 16) | ((hours & 0x1F) << 11) |((minutes & 0x3F) << 5) |(seconds & 0x1F)); + return ret; +} + +/*-----------------------------------------------------------------------*/ +/* Initialize disk drive */ +/*-----------------------------------------------------------------------*/ +DSTATUS disk_initialize ( + BYTE drv /* Physical drive number (0) */ +) +{ + + u8 busy = 0; + u32 Value; + u32 rca=0; + u8 wait_busy_count; + +#if(DEBUG_PRINTF_EN) + bsp_printf("disk_initialize started\r\n"); +#endif //(DEBUG_PRINTF_EN) + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + data = malloc(sizeof(struct mmc_data)); + + memset(data,0,sizeof(struct mmc_data)); + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_GO_IDLE_STATE,MMC_RSP_NONE,0); // Send CMD0 to reset the SD Card + bsp_uDelay(1000); + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SEND_EXT_CSD,MMC_RSP_R7,0x01AA); //CMD8 + if (xmmc_cmd -> response[0] != 0x01AA){ + return RES_ERROR; + } + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SPI_READ_OCR,MMC_RSP_R3,0); // CMD58 + mmc->ocr=xmmc_cmd->response[0]; + + bsp_uDelay(50000);//delay 50ms + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); // CMD55 + + while (busy==0) + { + Value = 0; + Value |= 0x1<<30; //HCS + Value |= 0x0<<28; //XPC + Value |= 0x0<<24; //S18R - this is to switch to 1.8V operating voltage. our FPGA dont support switching to 1.8v + Value |= 0x100000; //VDD VOLTAGE - indicate the voltage range to be 3.2 to 3.3 (Refer to the OCR Register) + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); //make the card accept acmd command so that we can send ACMD41 to set the operating condition + bsp_uDelay(1000);//delay 50ms + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_APP_SEND_OP_COND,MMC_RSP_R3,Value); // send ACMD41 to set operating condition + busy = (xmmc_cmd->response[0]>>31)&0x1; // need to shift right 31 as the response format is R3. R1 return will be located at bit 32:39 + bsp_uDelay(50000); //delay 50ms + + wait_busy_count++; + if (wait_busy_count >=10) + { + return STA_NOINIT; + } + } + + mmc->ocr=xmmc_cmd->response[0]; // get back OCR value and put into mmc structure + + bsp_uDelay(1000000); + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_ALL_SEND_CID,MMC_RSP_R2,0); + mmc->cid[0]=xmmc_cmd->response[0]; + mmc->cid[1]=xmmc_cmd->response[1]; + mmc->cid[2]=xmmc_cmd->response[2]; + mmc->cid[3]=xmmc_cmd->response[3]; + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SET_RELATIVE_ADDR,MMC_RSP_R6,0); + + mmc->rca = (xmmc_cmd->response[0]&0xffff0000)>>16; + sd_read_csd(mmc,xmmc_cmd); + // End of standby State + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SELECT_CARD,MMC_RSP_R1b,(mmc->rca<<16)); // CMD7 // going to transfer state + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,(mmc->rca<<16)); + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_APP_SET_BUS_WIDTH,MMC_RSP_R1,DATA_WIDTH); + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SET_BLOCKLEN,MMC_RSP_R1,BLOCK_SIZE); + +#if(DEBUG_PRINTF_EN) + bsp_printf("disk_initialize done\r\n"); +#endif //(DEBUG_PRINTF_EN) + free(data); + Stat &= ~STA_NOINIT; + return Stat; + +} + +/*-----------------------------------------------------------------------*/ +/* Get disk status */ +/*-----------------------------------------------------------------------*/ +DSTATUS disk_status ( + BYTE drv /* Physical drive number (0) */ +) +{ + if (drv) return STA_NOINIT; /* Supports only drive 0 */ + + return Stat; /* Return disk status */ +} + +void printBuffer(BYTE *buffer, size_t bufferSize); +/*-----------------------------------------------------------------------*/ +/* Write sector(s) */ +/*-----------------------------------------------------------------------*/ + +void printBuffer(BYTE *buffer, size_t bufferSize) { + for (size_t i = 0; i < bufferSize; i++) { + bsp_printf("%02X ", buffer[i]); + if ((i + 1) % 16 == 0) // Print a newline every 16 bytes for clarity + bsp_printf("\n"); + } + bsp_printf("\n\r"); +} + + +/*-----------------------------------------------------------------------*/ +/* Read sector(s) */ +/*-----------------------------------------------------------------------*/ +DRESULT disk_read ( + BYTE drv, /* Physical drive number (0) */ + BYTE *buff, /* Pointer to the data buffer to store read data */ + LBA_t sector, /* Start sector number (LBA) */ + UINT count /* Number of sectors to read (1..128) */ +) +{ + if (drv || !count) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = count*MAX_BLK_BUF; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_READ_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_READ_MULTIPLE_BLOCK; + + cmd->cmdarg =sector; + cmd->resp_type=MMC_RSP_R1; + data->dest=buff; + data->flags = MMC_DATA_READ; + + + mmc->cfg->ops->send_cmd(mmc,cmd,data); + + data_cache_invalidate_all(); + + free(cmd); + free(data); + return RES_OK; + +} + + +#if FF_FS_READONLY == 0 +DRESULT disk_write ( + BYTE drv, /* Physical drive number (0) */ + const BYTE *buff, /* Ponter to the data to write */ + LBA_t sector, /* Start sector number (LBA) */ + UINT count /* Number of sectors to write (1..128) */ +) +{ + if (drv || !count) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */ + + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + if (cmd == NULL){ + bsp_printf("Error cmd \r\n"); + while(1); + } + data = malloc(sizeof(struct mmc_data)); + if (data == NULL){ + bsp_printf("Error data\r\n"); + while(1); + } + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = count; //*MAX_BLK_BUF; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_WRITE_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_WRITE_MULTIPLE_BLOCK; + + cmd->cmdarg =sector; + cmd->resp_type=MMC_RSP_R1; + + data->src=buff; + data->flags = MMC_DATA_WRITE; + + ops->send_cmd(mmc,cmd,data); + + data_cache_invalidate_all(); + + free(cmd); + free(data); + return RES_OK; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous drive controls other than data read/write */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_ioctl ( + BYTE drv, /* Physical drive number (0) */ + BYTE cmd, /* Control command code */ + void *buff /* Pointer to the conrtol data */ +) +{ + DRESULT res; + BYTE n, csd[16]; + DWORD st, ed, csize; + LBA_t *dp; + DWORD blk_size = BLOCK_SIZE; + DWORD sector_cnt = 0; + + if (drv) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ + + res = RES_ERROR; + + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + data = malloc(sizeof(struct mmc_data)); + memset(data,0,sizeof(struct mmc_data)); + + + switch (cmd) { + case CTRL_SYNC : /* Wait for end of internal write process of the drive */ + //TO DO: Enable sometime to check the internal process + // Makes sure that the device has finished pending write process. If the disk I/O layer or storage device has a write-back cache, the dirty cache data must be committed to the medium immediately. Nothing to do for this command if each write operation to the medium is completed in the disk_write function. + // For Efinix, all our transaction completed in disk_write function + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */ + // Card specific data + // switch back to Standby state using CMD7 -> call CMD9 -> switch back to transfer state using CMD7 + sector_cnt = mmc->capacity/blk_size; + memcpy(buff, §or_cnt, sizeof(sector_cnt)); +#if(DEBUG_PRINTF_EN) + bsp_printf("Get sector count done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + memcpy(buff, &blk_size, sizeof(blk_size)); + res = RES_OK; +#if(DEBUG_PRINTF_EN) + bsp_printf("Get block size done\r\n"); +#endif //(DEBUG_PRINTF_EN) + break; + + case CTRL_TRIM : /* Erase a block of sectors (used when _USE_ERASE == 1) */ + dp = buff; st = (DWORD)dp[0]; ed = (DWORD)dp[1]; /* Load sector block */ + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_ERASE_WR_BLK_START,MMC_RSP_R1,st); //cmd32 + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_ERASE_WR_BLK_END,MMC_RSP_R1,ed); //cmd33 + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_ERASE,MMC_RSP_R1b,0); //cmd38 +#if(DEBUG_PRINTF_EN) + bsp_printf("Delete done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + /* Following commands are never used by FatFs module */ + + case MMC_GET_TYPE: /* Get MMC/SDC type (BYTE) */ + //TO DO: see if we can support MMC + *(BYTE*)buff = CT_SDC; +#if(DEBUG_PRINTF_EN) + bsp_printf("Get Type done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + case MMC_GET_CSD: /* Read CSD (16 bytes) */ + memcpy(buff, mmc->csd, sizeof(mmc->csd)); +#if(DEBUG_PRINTF_EN) + bsp_printf("Get CSD done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + case MMC_GET_CID: /* Read CID (16 bytes) */ + memcpy(buff, mmc->cid, sizeof(mmc->cid)); +#if(DEBUG_PRINTF_EN) + bsp_printf("Get CID done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + case MMC_GET_OCR: /* Read OCR (4 bytes) */ + memcpy(buff, &mmc->ocr, sizeof(mmc->ocr)); +#if(DEBUG_PRINTF_EN) + bsp_printf("Get OCR done\r\n"); +#endif //(DEBUG_PRINTF_EN) + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + + free(data); + return res; +} + +DWORD get_fattime (void){ +// bit31:25 +// Year origin from the 1980 (0..127, e.g. 37 for 2017) +// bit24:21 +// Month (1..12) +// bit20:16 +// Day of the month (1..31) +// bit15:11 +// Hour (0..23) +// bit10:5 +// Minute (0..59) +// bit4:0 +// Second / 2 (0..29, e.g. 25 for 50) + return getdata_fatfs(); +} + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.h new file mode 100644 index 0000000..ea4e449 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/diskio.h @@ -0,0 +1,144 @@ +/*-----------------------------------------------------------------------/ +/ Low level disk interface modlue include file (C)ChaN, 2019 / +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +#include "ff.h" +#include "mmc.h" +#include "userDef.h" +#include "diskio.h" +#include "type.h" +#include "bsp.h" +#include "vexriscv.h" +#include "efx_mmc_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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; + +static const int fbase[] = { + 10000, + 100000, + 1000000, + 10000000, +}; + +static const int multipliers[] = { + 0, /* reserved */ + 10, + 12, + 13, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 70, + 80, +}; +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +DWORD get_fattime (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 FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ + +/* Generic command (Not used by FatFs) */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ +#define ISDIO_READ 55 /* Read data form SD iSDIO register */ +#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ +#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC3 0x01 /* MMC ver 3 */ +#define CT_MMC4 0x02 /* MMC ver 4+ */ +#define CT_MMC 0x03 /* MMC */ +#define CT_SDC1 0x02 /* SDC ver 1 */ +#define CT_SDC2 0x04 /* SDC ver 2+ */ +#define CT_SDC 0x0C /* SDC */ +#define CT_BLOCK 0x10 /* Block addressing */ + +/* MMC/SD command (SPI mode) */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) /* SEND_STATUS */ +#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLOCK_COUNT */ +#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define CMD55 (55) /* APP_CMD */ +#define CMD58 (58) /* READ_OCR */ + +static BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.c new file mode 100644 index 0000000..b23a683 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.c @@ -0,0 +1,7083 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT Filesystem Module R0.15 w/patch1 / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2022, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 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 +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of device I/O functions */ + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if FF_DEFINED != 80286 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ + + +/* 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') +#define IsSeparator(c) ((c) == '/' || (c) == '\\') +#define IsTerminator(c) ((UINT)(c) < (FF_USE_LFN ? ' ' : '!')) +#define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) +#define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) +#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) + + +/* Additional file access control and file status flags for internal use */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits in FAT */ +#define AM_MASKX 0x37 /* Mask of defined bits in exFAT */ + + +/* Name status flags in fn[11] */ +#define NSFLAG 11 /* Index of the name status byte */ +#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 */ +#define NS_NOLFN 0x40 /* Do not find LFN */ +#define NS_NONAME 0x80 /* Not followed */ + + +/* exFAT directory entry types */ +#define ET_BITMAP 0x81 /* Allocation bitmap */ +#define ET_UPCASE 0x82 /* Up-case table */ +#define ET_VLABEL 0x83 /* Volume label */ +#define ET_FILEDIR 0x85 /* File and directory */ +#define ET_STREAM 0xC0 /* Stream extension */ +#define ET_FILENAME 0xC1 /* Name extension */ + + +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ + +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* WindowsNT error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* Filesystem type string (8-byte) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ + +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ +#define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + +#define GPTH_Sign 0 /* GPT HDR: Signature (8-byte) */ +#define GPTH_Rev 8 /* GPT HDR: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT HDR: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT HDR: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT HDR: This header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT HDR: Another header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT HDR: First LBA for partition data (QWORD) */ +#define GPTH_LstLba 48 /* GPT HDR: Last LBA for partition data (QWORD) */ +#define GPTH_DskGuid 56 /* GPT HDR: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT HDR: Partition table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT PTE: Size of partition table entry */ +#define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ +#define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA of partition (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA of partition (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Partition flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Partition name */ + + +/* Post process on fatal error in the file operations */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Re-entrancy related */ +#if FF_FS_REENTRANT +#if FF_USE_LFN == 1 +#error Static LFN work area cannot be used in thread-safe configuration +#endif +#define LEAVE_FF(fs, res) { unlock_volume(fs, res); return res; } +#else +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of logical drive - physical location conversion */ +#if FF_MULTI_PARTITION +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition number (0:auto search, 1..:forced partition number) */ +#else +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ +#define LD2PT(vol) 0 /* Auto partition search */ +#endif + + +/* Definitions of sector size */ +#if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if FF_MAX_SS == FF_MIN_SS +#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if FF_FS_NORTC == 1 +#if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 +#error Invalid FF_FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if FF_FS_LOCK +#if FF_FS_READONLY +#error FF_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, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + UINT ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* SBCS up-case tables (\x80-\xFF) */ +#define TBL_CT437 {0x80,0x9A,0x45,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,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} +#define TBL_CT720 {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} +#define TBL_CT737 {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,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT771 {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,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT775 {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} +#define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT852 {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,0xAC, \ + 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} +#define TBL_CT855 {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} +#define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,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,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,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,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} +#define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,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} +#define TBL_CT862 {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,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} +#define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,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} +#define TBL_CT864 {0x80,0x9A,0x45,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,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} +#define TBL_CT865 {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,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} +#define TBL_CT866 {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,0x94,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} +#define TBL_CT869 {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,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,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,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + + +/* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ +/* <------> <------> <------> <------> <------> */ +#define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} +#define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} +#define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} +#define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} + + +/* Macros for table definitions */ +#define MERGE_2STR(a, b) a ## b +#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) + + + + +/*-------------------------------------------------------------------------- + + Module Private Work Area + +---------------------------------------------------------------------------*/ +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is +/ not compliance with C standard. */ + +/*--------------------------------*/ +/* File/Volume controls */ +/*--------------------------------*/ + +#if FF_VOLUMES < 1 || FF_VOLUMES > 10 +#error Wrong FF_VOLUMES setting +#endif +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static WORD Fsid; /* Filesystem mount ID */ + +#if FF_FS_RPATH != 0 +static BYTE CurrVol; /* Current drive set by f_chdrive() */ +#endif + +#if FF_FS_LOCK != 0 +static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#if FF_FS_REENTRANT +static BYTE SysLock; /* System lock flag (0:no mutex, 1:unlocked, 2:locked) */ +#endif +#endif + +#if FF_STR_VOLUME_ID +#ifdef FF_VOLUME_STRS +static const char *const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +#endif +#endif + +#if FF_LBA64 +#if FF_MIN_GPT > 0x100000000 +#error Wrong FF_MIN_GPT setting +#endif +static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7}; +#endif + + + +/*--------------------------------*/ +/* LFN/Directory working buffer */ +/*--------------------------------*/ + +#if FF_USE_LFN == 0 /* Non-LFN configuration */ +#if FF_FS_EXFAT +#error LFN must be enabled when enable exFAT +#endif +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res + +#else /* LFN configurations */ +#if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 +#error Wrong setting of FF_MAX_LFN +#endif +#if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 +#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF +#endif +#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 +#error Wrong setting of FF_LFN_UNICODE +#endif +static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ + +#if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ +#if FF_FS_EXFAT +static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ +#endif +static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res + +#elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMBUF() +#else +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMBUF() +#endif +#define LEAVE_MKFS(res) return res + +#elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#else +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#endif +#define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } +#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ + +#else +#error Wrong setting of FF_USE_LFN + +#endif /* FF_USE_LFN == 1 */ +#endif /* FF_USE_LFN == 0 */ + + + +/*--------------------------------*/ +/* Code conversion tables */ +/*--------------------------------*/ + +#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ +#define CODEPAGE CodePage +static WORD CodePage; /* Current code page */ +static const BYTE* ExCvt; /* Ptr to SBCS up-case table Ct???[] (null:not used) */ +static const BYTE* DbcTbl; /* Ptr to DBCS code range table Dc???[] (null:not used) */ + +static const BYTE Ct437[] = TBL_CT437; +static const BYTE Ct720[] = TBL_CT720; +static const BYTE Ct737[] = TBL_CT737; +static const BYTE Ct771[] = TBL_CT771; +static const BYTE Ct775[] = TBL_CT775; +static const BYTE Ct850[] = TBL_CT850; +static const BYTE Ct852[] = TBL_CT852; +static const BYTE Ct855[] = TBL_CT855; +static const BYTE Ct857[] = TBL_CT857; +static const BYTE Ct860[] = TBL_CT860; +static const BYTE Ct861[] = TBL_CT861; +static const BYTE Ct862[] = TBL_CT862; +static const BYTE Ct863[] = TBL_CT863; +static const BYTE Ct864[] = TBL_CT864; +static const BYTE Ct865[] = TBL_CT865; +static const BYTE Ct866[] = TBL_CT866; +static const BYTE Ct869[] = TBL_CT869; +static const BYTE Dc932[] = TBL_DC932; +static const BYTE Dc936[] = TBL_DC936; +static const BYTE Dc949[] = TBL_DC949; +static const BYTE Dc950[] = TBL_DC950; + +#elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); + +#else /* Static code page configuration (DBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); + +#endif + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if FF_FS_EXFAT +static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !FF_FS_READONLY +static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if FF_FS_EXFAT +static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !FF_FS_READONLY */ + + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Test if the byte is DBC 1st byte */ +static int dbc_1st (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +/* Test if the byte is DBC 2nd byte */ +static int dbc_2nd (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +#if FF_USE_LFN + +/* Get a Unicode code point from the TCHAR string in defined API encodeing */ +static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */ + const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ +) +{ + DWORD uc; + const TCHAR *p = *str; + +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ + WCHAR wc; + + uc = *p++; /* Get a unit */ + if (IsSurrogate(uc)) { /* Surrogate? */ + wc = *p++; /* Get low surrogate */ + if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ + uc = uc << 16 | wc; + } + +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ + BYTE b; + int nf; + + uc = (BYTE)*p++; /* Get an encoding unit */ + if (uc & 0x80) { /* Multiple byte code? */ + if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + uc &= 0x1F; nf = 1; + } else if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + uc &= 0x0F; nf = 2; + } else if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + uc &= 0x07; nf = 3; + } else { /* Wrong sequence */ + return 0xFFFFFFFF; + } + do { /* Get trailing bytes */ + b = (BYTE)*p++; + if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (b & 0x3F); + } while (--nf != 0); + if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + } + +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + uc = (TCHAR)*p++; /* Get a unit */ + if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + +#else /* ANSI/OEM input */ + BYTE b; + WCHAR wc; + + wc = (BYTE)*p++; /* Get a byte */ + if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ + b = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + b; /* Make a DBC */ + } + if (wc != 0) { + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ + if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ + } + uc = wc; + +#endif + *str = p; /* Next read pointer */ + return uc; +} + + +/* Store a Unicode char in defined API encoding */ +static UINT put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ + DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ + TCHAR* buf, /* Output buffer */ + UINT szb /* Size of the buffer */ +) +{ +#if FF_LFN_UNICODE == 1 /* UTF-16 output */ + WCHAR hs, wc; + + hs = (WCHAR)(chr >> 16); + wc = (WCHAR)chr; + if (hs == 0) { /* Single encoding unit? */ + if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ + *buf = wc; + return 1; + } + if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ + *buf++ = hs; + *buf++ = wc; + return 2; + +#elif FF_LFN_UNICODE == 2 /* UTF-8 output */ + DWORD hc; + + if (chr < 0x80) { /* Single byte code? */ + if (szb < 1) return 0; /* Buffer overflow? */ + *buf = (TCHAR)chr; + return 1; + } + if (chr < 0x800) { /* 2-byte sequence? */ + if (szb < 2) return 0; /* Buffer overflow? */ + *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 2; + } + if (chr < 0x10000) { /* 3-byte sequence? */ + if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ + *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 3; + } + /* 4-byte sequence */ + if (szb < 4) return 0; /* Buffer overflow? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); + *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 4; + +#elif FF_LFN_UNICODE == 3 /* UTF-32 output */ + DWORD hc; + + if (szb < 1) return 0; /* Buffer overflow? */ + if (chr >= 0x10000) { /* Out of BMP? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + } + *buf++ = (TCHAR)chr; + return 1; + +#else /* ANSI/OEM output */ + WCHAR wc; + + wc = ff_uni2oem(chr, CODEPAGE); + if (wc >= 0x100) { /* Is this a DBC? */ + if (szb < 2) return 0; + *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ + *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ + return 2; + } + if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + *buf++ = (TCHAR)wc; /* Store the character */ + return 1; +#endif +} +#endif /* FF_USE_LFN */ + + +#if FF_FS_REENTRANT +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ + +static int lock_volume ( /* 1:Ok, 0:timeout */ + FATFS* fs, /* Filesystem object to lock */ + int syslock /* System lock required */ +) +{ + int rv; + + +#if FF_FS_LOCK + rv = ff_mutex_take(fs->ldrv); /* Lock the volume */ + if (rv && syslock) { /* System lock reqiered? */ + rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ + if (rv) { + SysLock = 2; /* System lock succeeded */ + } else { + ff_mutex_give(fs->ldrv); /* Failed system lock */ + } + } +#else + rv = syslock ? ff_mutex_take(fs->ldrv) : ff_mutex_take(fs->ldrv); /* Lock the volume (this is to prevent compiler warning) */ +#endif + return rv; +} + + +static void unlock_volume ( + FATFS* fs, /* Filesystem object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { +#if FF_FS_LOCK + if (SysLock == 2) { /* Is the system locked? */ + SysLock = 1; + ff_mutex_give(FF_VOLUMES); + } +#endif + ff_mutex_give(fs->ldrv); /* Unlock the volume */ + } +} + +#endif + + + +#if FF_FS_LOCK +/*-----------------------------------------------------------------------*/ +/* File shareing control functions */ +/*-----------------------------------------------------------------------*/ + +static FRESULT chk_share ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ +) +{ + UINT i, be; + + /* Search open object table for the object */ + be = 0; + for (i = 0; i < FF_FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == FF_FS_LOCK) { /* The object has not been opened */ + return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ + } + + /* The object was opened. Reject any open against writing file and all write mode open */ + return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static int enq_share (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ + return (i == FF_FS_LOCK) ? 0 : 1; +} + + +static UINT inc_share ( /* 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 < FF_FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->obj.fs + && Files[i].clu == dp->obj.sclust + && Files[i].ofs == dp->dptr) break; + } + + if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ + if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; + Files[i].ctr = 0; + } + + if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; /* Index number origin from 1 */ +} + + +static FRESULT dec_share ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + UINT n; + FRESULT res; + + + if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the object semaphore */ + if (n > 0) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (n == 0) { /* Delete the object semaphore if open count becomes zero */ + Files[i].fs = 0; /* Free the entry << 1, there is a potential error in this process >>> */ + } + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index number */ + } + return res; +} + + +static void clear_share ( /* Clear all lock entries of the volume */ + FATFS* fs +) +{ + UINT i; + + for (i = 0; i < FF_FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} + +#endif /* FF_FS_LOCK */ + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the filesystem object */ +/*-----------------------------------------------------------------------*/ +#if !FF_FS_READONLY +static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ +) +{ + FRESULT res = FR_OK; + + + if (fs->wflag) { /* Is the disk access window dirty? */ + if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write it back into the volume */ + fs->wflag = 0; /* Clear window dirty flag */ + if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ + if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ + } + } else { + res = FR_DISK_ERR; + } + } + return res; +} +#endif + + +static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs, /* Filesystem object */ + LBA_t sect /* Sector LBA to make appearance in the fs->win[] */ +) +{ + FRESULT res = FR_OK; + + + if (sect != fs->winsect) { /* Window offset changed? */ +#if !FF_FS_READONLY + res = sync_window(fs); /* Flush the window */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) { + sect = (LBA_t)0 - 1; /* Invalidate window if read data is not valid */ + res = FR_DISK_ERR; + } + fs->winsect = sect; + } + } + return res; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize filesystem and data on the storage */ +/*-----------------------------------------------------------------------*/ + +static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ + /* Create FSInfo structure */ + memset(fs->win, 0, sizeof fs->win); + st_word(fs->win + BS_55AA, 0xAA55); /* Boot signature */ + st_dword(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ + st_dword(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ + st_dword(fs->win + FSI_Free_Count, fs->free_clst); /* Number of free clusters */ + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Last allocated culuster */ + fs->winsect = fs->volbase + 1; /* Write it into the FSInfo sector (Next to VBR) */ + disk_write(fs->pdrv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the lower layer */ + if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; + } + + return res; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Get physical sector number from cluster number */ +/*-----------------------------------------------------------------------*/ + +static LBA_t clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* Filesystem object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; /* Cluster number is origin from 2 */ + if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ + return fs->database + (LBA_t)fs->csize * clst; /* Start sector number of the cluster */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of an FAT entry */ +/*-----------------------------------------------------------------------*/ + +static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ +) +{ + UINT wc, bc; + DWORD val; + FATFS *fs = obj->fs; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid 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)]; /* Get 1st byte of the entry */ + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ + break; + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; + val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ + break; + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ + break; +#if FF_FS_EXFAT + case FS_EXFAT : + if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((LBA_t)((obj->objsize - 1) / SS(fs)) / fs->csize); /* Number of clusters - 1 */ + + if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ + break; + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } + break; + } + } + val = 1; /* Internal error */ + break; +#endif + default: + val = 1; /* Internal error */ + } + } + + return val; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of an FAT entry */ +/*-----------------------------------------------------------------------*/ + +static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding filesystem 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 = FR_INT_ERR; + + + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ + switch (fs->fs_type) { + case FS_FAT12: + bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ + 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; /* Update 1st byte */ + 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)); /* Update 2nd byte */ + fs->wflag = 1; + break; + + case FS_FAT16: + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ + fs->wflag = 1; + break; + + case FS_FAT32: +#if FF_FS_EXFAT + case FS_EXFAT: +#endif + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); + fs->wflag = 1; + break; + } + } + return res; +} + +#endif /* !FF_FS_READONLY */ + + + + +#if FF_FS_EXFAT && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* exFAT: Accessing FAT and Allocation Bitmap */ +/*-----------------------------------------------------------------------*/ + +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ + +static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; + i = val / 8 % SS(fs); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = SS(fs); + } + if (bv == 0) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ + } else { + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm != 0); + bm = 1; + } while (++i < SS(fs)); + } +} + + +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ + +static FRESULT change_bitmap ( + FATFS* fs, /* Filesystem object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + LBA_t sect; + + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + i = 0; + } +} + + +/*---------------------------------------------*/ +/* Fill the first fragment of the FAT chain */ +/*---------------------------------------------*/ + +static FRESULT fill_first_frag ( + FFOBJID* obj /* Pointer to the corresponding object */ +) +{ + FRESULT res; + DWORD cl, n; + + + if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; + } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static FRESULT fill_last_frag ( + FFOBJID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + + while (obj->n_frag > 0) { /* Create the chain of last fragment */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* FF_FS_EXFAT && !FF_FS_READONLY */ + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ + +static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0 if entire chain) */ +) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; +#if FF_FS_EXFAT || FF_USE_TRIM + DWORD scl = clst, ecl = clst; +#endif +#if FF_USE_TRIM + LBA_t rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ + + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; + } + + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if FF_FS_EXFAT || FF_USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; + } +#endif +#if FF_USE_TRIM + rt[0] = clst2sect(fs, scl); /* Start of data area to be freed */ + rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area to be freed */ + disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform storage device that the data in the block may be erased */ +#endif + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ + +#if FF_FS_EXFAT + /* Some post processes for chain status */ + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Has the entire chain been removed? */ + obj->stat = 0; /* Change the chain status 'initial' */ + } else { + if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ + clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ + while (clst != pclst) { + nxt = get_fat(obj, clst); + if (nxt < 2) return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; + if (nxt != clst + 1) break; /* Not contiguous? */ + clst++; + } + if (clst == pclst) { /* Has the chain got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } + } + } +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch a chain or Create a new chain */ +/*-----------------------------------------------------------------------*/ + +static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster# to stretch, 0:Create a new chain */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + FATFS *fs = obj->fs; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Suggested cluster to start to find */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch a chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Test for insanity */ + if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; /* Cluster to start to find */ + } + if (fs->free_clst == 0) return 0; /* No free cluster */ + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } + } else +#endif + { /* On the FAT/FAT32 volume */ + ncl = 0; + if (scl == clst) { /* Stretching an existing chain? */ + ncl = scl + 1; /* Test if next cluster is free */ + if (ncl >= fs->n_fatent) ncl = 2; + cs = get_fat(obj, ncl); /* Get next cluster status */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (cs != 0) { /* Not free? */ + cs = fs->last_clst; /* Start at suggested cluster if it is valid */ + if (cs >= 2 && cs < fs->n_fatent) scl = cs; + ncl = 0; + } + } + if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ + 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 found? */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster? */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (ncl == scl) return 0; /* No free cluster found? */ + } + } + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + } + } + + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ + } + + return ncl; /* Return new cluster number or error status */ +} + +#endif /* !FF_FS_READONLY */ + + + + +#if FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl; + DWORD *tbl; + FATFS *fs = fp->obj.fs; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (ncl == 0) 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 /* FF_USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Fill a cluster with zeros */ +/*-----------------------------------------------------------------------*/ + +#if !FF_FS_READONLY +static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS *fs, /* Filesystem object */ + DWORD clst /* Directory table to clear */ +) +{ + LBA_t sect; + UINT n, szb; + BYTE *ibuf; + + + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + sect = clst2sect(fs, clst); /* Top of the cluster */ + fs->winsect = sect; /* Set window to top of the cluster */ + memset(fs->win, 0, sizeof fs->win); /* Clear window buffer */ +#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ + /* Allocate a temporary buffer */ + for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; + if (szb > SS(fs)) { /* Buffer allocated? */ + memset(ibuf, 0, szb); + szb /= SS(fs); /* Bytes -> Sectors */ + for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + ff_memfree(ibuf); + } else +#endif + { + ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ + for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + } + return (n == fs->csize) ? FR_OK : FR_DISK_ERR; +} +#endif /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to directory object */ + DWORD ofs /* Offset of directory table */ +) +{ + DWORD csz, clst; + FATFS *fs = dp->obj.fs; + + + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + return FR_INT_ERR; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = (DWORD)fs->dirbase; + if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } + + if (clst == 0) { /* Static table (root-directory on the FAT volume) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; + } + dp->sect = clst2sect(fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (dp->sect == 0) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_next ( /* FR_OK(0):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 ofs, clst; + FATFS *fs = dp->obj.fs; + + + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ + if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ + + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (dp->clust == 0) { /* Static table */ + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } + } + else { /* Dynamic table */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ +#if !FF_FS_READONLY + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ + if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ +#else + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clst2sect(fs, clst); + } + } + } + dp->dptr = ofs; /* Current entry */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve a block of directory entries */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT n_ent /* Number of contiguous entries to allocate */ +) +{ + FRESULT res; + UINT n; + FATFS *fs = dp->obj.fs; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; +#if FF_FS_EXFAT + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { /* Is the entry free? */ +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { /* Is the entry free? */ +#endif + if (++n == n_ent) break; /* Is a block of contiguous free entries found? */ + } else { + n = 0; /* Not a free 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 /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT: Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key 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 !FF_FS_READONLY +static void st_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ + DWORD cl /* Value to be set */ +) +{ + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } +} +#endif + + + +#if FF_USE_LFN +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ + +static int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + return 0; /* Not matched */ + } + wc = uc; + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + + return 1; /* The part of LFN matched */ +} + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ + +static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ + BYTE* dir /* Pointer to the LFN entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ + + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; /* The part of LFN is valid */ +} +#endif + + +#if !FF_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ + +static void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set checksum */ + 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 working buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ + } while (++s < 13); + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LFN */ + + + +#if FF_USE_LFN && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Create a Numbered SFN */ +/*-----------------------------------------------------------------------*/ + +static void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN in directory form */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sreg; + + + memcpy(dst, src, 11); /* Prepare the SFN to be modified */ + + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ + sreg = seq; + while (*lfn) { /* Create a CRC as hash value */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sreg = (sreg << 1) + (wc & 1); + wc >>= 1; + if (sreg & 0x10000) sreg ^= 0x11021; + } + } + seq = (UINT)sreg; + } + + /* Make suffix (~ + hexadecimal) */ + i = 7; + do { + c = (BYTE)((seq % 16) + '0'); seq /= 16; + if (c > '9') c += 7; + ns[i--] = c; + } while (i && seq); + ns[i] = '~'; + + /* Append the suffix to the SFN body */ + for (j = 0; j < i && dst[j] != ' '; j++) { /* Find the offset to append */ + if (dbc_1st(dst[j])) { /* To avoid DBC break up */ + if (j == i - 1) break; + j++; + } + } + do { /* Append the suffix */ + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif /* FF_USE_LFN && !FF_FS_READONLY */ + + + +#if FF_USE_LFN +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Calculate checksum of an SFN entry */ +/*-----------------------------------------------------------------------*/ + +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 /* FF_USE_LFN */ + + + +#if FF_FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* exFAT: Checksum */ +/*-----------------------------------------------------------------------*/ + +static WORD xdir_sum ( /* Get checksum of the directoly entry block */ + const BYTE* dir /* Directory entry block to be calculated */ +) +{ + UINT i, szblk; + WORD sum; + + + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ + i++; + } else { + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; + } + } + return sum; +} + + + +static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +#if !FF_FS_READONLY && FF_USE_MKFS +static DWORD xsum32 ( /* Returns 32-bit checksum */ + BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ + DWORD sum /* Previous sum value */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} +#endif + + + +/*------------------------------------*/ +/* exFAT: Get a directory entry block */ +/*------------------------------------*/ + +static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Reading directory object pointing top of the entry block to load */ +) +{ + FRESULT res; + UINT i, sz_ent; + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ + + + /* Load file directory entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ + memcpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; + + /* Load stream extension entry */ + res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ + memcpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; + + /* Load file name entries */ + i = 2 * SZDIRE; /* Name offset to load */ + do { + res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ + if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + + /* Sanity check (do it for only accessible object) */ + if (i <= MAXDIRB(FF_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } + return FR_OK; +} + + +/*------------------------------------------------------------------*/ +/* exFAT: Initialize object allocation info with loaded entry block */ +/*------------------------------------------------------------------*/ + +static void init_alloc_info ( + FATFS* fs, /* Filesystem object */ + FFOBJID* obj /* Object allocation information to be initialized */ +) +{ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + obj->n_frag = 0; /* No last fragment info */ +} + + + +#if !FF_FS_READONLY || FF_FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ + +static FRESULT load_obj_xdir ( + DIR* dp, /* Blank directory object to be used to access containing directory */ + const FFOBJID* obj /* Object with its containing directory information */ +) +{ + FRESULT res; + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->obj.n_frag = 0; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } + return res; +} +#endif + + +#if !FF_FS_READONLY +/*----------------------------------------*/ +/* exFAT: Store the directory entry block */ +/*----------------------------------------*/ + +static FRESULT store_xdir ( + DIR* dp /* Pointer to the directory object */ +) +{ + FRESULT res; + UINT nent; + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the directory entry block 85+C0+C1s */ + + /* Create set sum */ + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); + nent = dirb[XDIR_NumSec] + 1; + + /* Store the directory entry block to the directory */ + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + memcpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory entry block */ +/*-------------------------------------------*/ + +static void create_xdir ( + BYTE* dirb, /* Pointer to the directory entry block buffer */ + const WCHAR* lfn /* Pointer to the object name */ +) +{ + UINT i; + BYTE nc1, nlen; + WCHAR wc; + + + /* Create file-directory and stream-extension entry */ + memset(dirb, 0, 2 * SZDIRE); + dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; + dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; + + /* Create file-name entries */ + i = SZDIRE * 2; /* Top of file_name entries */ + nlen = nc1 = 0; wc = 1; + do { + dirb[i++] = ET_FILENAME; dirb[i++] = 0; + do { /* Fill name field */ + if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_word(dirb + i, wc); /* Store it */ + i += 2; + } while (i % SZDIRE != 0); + nc1++; + } while (lfn[nlen]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nlen; /* Set name length */ + dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_EXFAT */ + + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ + +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) + +static FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE attr, b; +#if FF_USE_LFN + BYTE ord = 0xFF, sum = 0xFF; +#endif + + while (dp->sect) { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + b = dp->dir[DIR_Name]; /* Test for the entry type */ + if (b == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (FF_USE_LABEL && vol) { + if (b == ET_VLABEL) break; /* Volume label entry? */ + } else { + if (b == ET_FILEDIR) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* On the FAT/FAT32 volume */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if FF_USE_LFN /* LFN configuration */ + if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (attr == AM_LFN) { /* An LFN entry is found */ + if (b & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + b &= (BYTE)~LLEF; ord = b; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~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; /* Terminate the read operation on error or EOT */ + return res; +} + +#endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; +#if FF_USE_LFN + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ + + while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ +#if FF_MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + } + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* On the FAT/FAT32 volume */ +#if FF_USE_LFN + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if FF_USE_LFN /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !memcmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !memcmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_register ( /* FR_OK:succeeded, 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; + FATFS *fs = dp->obj.fs; +#if FF_USE_LFN /* LFN configuration */ + UINT n, len, n_ent; + BYTE sn[12], sum; + + + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (len = 0; fs->lfnbuf[len]; len++) ; /* Get lfn length */ + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + n_ent = (len + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, n_ent); /* Allocate directory entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (n_ent - 1); /* Set the allocated entry block offset */ + + if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ + dp->obj.stat &= ~4; + res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ + if (res != FR_OK) return res; + if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ + DIR dj; + + res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + } + + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* On the FAT/FAT32 volume */ + memcpy(sn, dp->fn, 12); + if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(dp->fn, sn, fs->lfnbuf, 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' */ + dp->fn[NSFLAG] = sn[NSFLAG]; + } + + /* Create an SFN with/without LFNs. */ + n_ent = (sn[NSFLAG] & NS_LFN) ? (len + 12) / 13 + 1 : 1; /* Number of entries to allocate */ + res = dir_alloc(dp, n_ent); /* Allocate entries */ + if (res == FR_OK && --n_ent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->dptr - n_ent * SZDIRE); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + put_lfn(fs->lfnbuf, dp->dir, (BYTE)n_ent, sum); + fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --n_ent); + } + } + +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + +#endif + + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); + if (res == FR_OK) { + memset(dp->dir, 0, SZDIRE); /* Clean the entry */ + memcpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if FF_USE_LFN + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + fs->wflag = 1; + } + } + + return res; +} + +#endif /* !FF_FS_READONLY */ + + + +#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if FF_USE_LFN /* LFN configuration */ + DWORD last = dp->dptr; + + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ + if (res == FR_OK) { + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ + } else { /* On the FAT/FAT32 volume */ + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then 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 = move_window(fs, dp->sect); + if (res == FR_OK) { + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ + fs->wflag = 1; + } +#endif + + return res; +} + +#endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ + + + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ + +static void get_fileinfo ( + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT si, di; +#if FF_USE_LFN + BYTE lcf; + WCHAR wc, hs; + FATFS *fs = dp->obj.fs; + UINT nw; +#else + TCHAR c; +#endif + + + fno->fname[0] = 0; /* Invaidate file info */ + if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ + +#if FF_USE_LFN /* LFN configuration */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT volume */ + UINT nc = 0; + + si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ + hs = 0; + while (nc < fs->dirbuf[XDIR_NumName]) { + if (si >= MAXDIRB(FF_MAX_LFN)) { /* Truncated directory block? */ + di = 0; break; + } + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ + } + nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } + di += nw; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + if (di == 0) fno->fname[di++] = '\?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate the name */ + fno->altname[0] = 0; /* exFAT does not support SFN */ + + fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(fs->dirbuf + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(fs->dirbuf + XDIR_ModTime + 2); /* Date */ + return; + } else +#endif + { /* FAT/FAT32 volume */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + si = di = 0; + hs = 0; + while (fs->lfnbuf[si] != 0) { + wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ + } + nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } + di += nw; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ + } + } + + si = di = 0; + while (si < 11) { /* Get SFN from SFN entry */ + wc = dp->dir[si++]; /* Get a char */ + if (wc == ' ') continue; /* Skip padding spaces */ + if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ + if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ +#if FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ + wc = wc << 8 | dp->dir[si++]; + } + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ + if (wc == 0) { /* Wrong char in the current code page? */ + di = 0; break; + } + nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { /* Buffer overflow? */ + di = 0; break; + } + di += nw; +#else /* ANSI/OEM output */ + fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ +#endif + } + fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ + + if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccessible */ + fno->fname[di++] = '\?'; + } else { + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + wc = (WCHAR)fno->altname[si]; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; + fno->fname[di] = (TCHAR)wc; + } + } + fno->fname[di] = 0; /* Terminate the LFN */ + if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ + } + +#else /* Non-LFN configuration */ + si = di = 0; + while (si < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[si++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ + if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ + fno->fname[di++] = c; + } + fno->fname[di] = 0; /* Terminate the SFN */ +#endif + + fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ +} + +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ + + + +#if FF_USE_FIND && FF_FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Pattern matching */ +/*-----------------------------------------------------------------------*/ + +#define FIND_RECURS 4 /* Maximum number of wildcard terms in the pattern to limit recursion */ + + +static DWORD get_achar ( /* Get a character and advance ptr */ + const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ +) +{ + DWORD chr; + + +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ + chr = tchar2uni(ptr); + if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ + chr = ff_wtoupper(chr); + +#else /* ANSI/OEM input */ + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#if FF_CODE_PAGE == 0 + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#elif FF_CODE_PAGE < 900 + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#endif +#if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 + if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ + chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; + } +#endif + +#endif + return chr; +} + + +static int pattern_match ( /* 0:mismatched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + UINT skip, /* Number of pre-skip chars (number of ?s, b8:infinite (* specified)) */ + UINT recur /* Recursion count */ +) +{ + const TCHAR *pptr; + const TCHAR *nptr; + DWORD pchr, nchr; + UINT sk; + + + while ((skip & 0xFF) != 0) { /* Pre-skip name chars */ + if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ + skip--; + } + if (*pat == 0 && skip) return 1; /* Matched? (short circuit) */ + + do { + pptr = pat; nptr = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pptr == '\?' || *pptr == '*') { /* Wildcard term? */ + if (recur == 0) return 0; /* Too many wildcard terms? */ + sk = 0; + do { /* Analyze the wildcard term */ + if (*pptr++ == '\?') { + sk++; + } else { + sk |= 0x100; + } + } while (*pptr == '\?' || *pptr == '*'); + if (pattern_match(pptr, nptr, sk, recur - 1)) return 1; /* Test new branch (recursive call) */ + nchr = *nptr; break; /* Branch mismatched */ + } + pchr = get_achar(&pptr); /* Get a pattern char */ + nchr = get_achar(&nptr); /* Get a name char */ + if (pchr != nchr) break; /* Branch mismatched? */ + if (pchr == 0) return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (skip && nchr); /* Retry until end of name if infinite search is specified */ + + return 0; +} + +#endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ + + + +/*-----------------------------------------------------------------------*/ +/* Pick a top segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if FF_USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR wc; + WCHAR *lfn; + const TCHAR* p; + DWORD uc; + UINT i, ni, si, di; + + + /* Create LFN into LFN working buffer */ + p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; + for (;;) { + uc = tchar2uni(&p); /* Get a character */ + if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ + if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ + wc = (WCHAR)uc; + if (wc < ' ' || IsSeparator(wc)) break; /* Break if end of the path or a separator is found */ + if (wc < 0x80 && strchr("*:<>|\"\?\x7F", (int)wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ + lfn[di++] = wc; /* Store the Unicode character */ + } + if (wc < ' ') { /* Stopped at end of the path? */ + cf = NS_LAST; /* Last segment */ + } else { /* Stopped at a separator */ + while (IsSeparator(*p)) p++; /* Skip duplicated separators if exist */ + cf = 0; /* Next segment may follow */ + if (IsTerminator(*p)) cf = NS_LAST; /* Ignore terminating separator */ + } + *path = p; /* Return pointer to the next segment */ + +#if FF_FS_RPATH != 0 + if ((di == 1 && lfn[di - 1] == '.') || + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ + lfn[di] = 0; + for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ + dp->fn[i] = (i < di) ? '.' : ' '; + } + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Snip off trailing spaces and dots if exist */ + wc = lfn[di - 1]; + if (wc != ' ' && wc != '.') break; + di--; + } + lfn[di] = 0; /* LFN is created into the working buffer */ + if (di == 0) return FR_INVALID_NAME; /* Reject null name */ + + /* Create SFN in directory form */ + for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ + if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ + while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ + + memset(dp->fn, ' ', 11); + i = b = 0; ni = 8; + for (;;) { + wc = lfn[si++]; /* Get an LFN character */ + if (wc == 0) break; /* Break on end of the LFN */ + if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ + cf |= NS_LOSS | NS_LFN; + continue; + } + + if (i >= ni || si == di) { /* End of field? */ + if (ni == 11) { /* Name extension overflow? */ + cf |= NS_LOSS | NS_LFN; + break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ + if (si > di) break; /* No name extension? */ + si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ + continue; + } + + if (wc >= 0x80) { /* Is this an extended character? */ + cf |= NS_LFN; /* LFN entry needs to be created */ +#if FF_CODE_PAGE == 0 + if (ExCvt) { /* In SBCS cfg */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ + } else { /* In DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Up-convert ==> ANSI/OEM code */ + } +#elif FF_CODE_PAGE < 900 /* In SBCS cfg */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ +#else /* In DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Up-convert ==> ANSI/OEM code */ +#endif + } + + if (wc >= 0x100) { /* Is this a DBC? */ + if (i >= ni - 1) { /* Field overflow? */ + cf |= NS_LOSS | NS_LFN; + i = ni; continue; /* Next field */ + } + dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ + } else { /* SBC */ + if (wc == 0 || strchr("+,;=[]", (int)wc)) { /* Replace illegal characters for SFN */ + wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(wc)) { /* ASCII upper case? */ + b |= 2; + } + if (IsLower(wc)) { /* ASCII lower case? */ + b |= 1; wc -= 0x20; + } + } + } + dp->fn[i++] = (BYTE)wc; + } + + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + + if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ + if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ + + return FR_OK; + + +#else /* FF_USE_LFN : Non-LFN configuration */ + BYTE c, d; + BYTE *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + p = *path; sfn = dp->fn; + memset(sfn, ' ', 11); + si = i = 0; ni = 8; +#if FF_FS_RPATH != 0 + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (!IsSeparator(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 the path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; /* Get a byte */ + if (c <= ' ') break; /* Break if end of the path name */ + if (IsSeparator(c)) { /* Break if a separator is found */ + while (IsSeparator(p[si])) si++; /* Skip duplicated separator if exist */ + break; + } + if (c == '.' || i >= ni) { /* End of body or field overflow? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ + i = 8; ni = 11; /* Enter file extension field */ + continue; + } +#if FF_CODE_PAGE == 0 + if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#elif FF_CODE_PAGE < 900 + if (c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#endif + if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (strchr("*+,:;<=>[]|\"\?\x7F", (int)c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (IsLower(c)) c -= 0x20; /* To upper */ + sfn[i++] = c; + } + } + *path = &p[si]; /* Return pointer to the next segment */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ + + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ' || p[si] <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + + return FR_OK; +#endif /* FF_USE_LFN */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* 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 ns; + FATFS *fs = dp->obj.fs; + + +#if FF_FS_RPATH != 0 + if (!IsSeparator(*path) && (FF_STR_VOLUME_ID != 2 || !IsTerminator(*path))) { /* Without heading separator */ + dp->obj.sclust = fs->cdir; /* Start at the current directory */ + } else +#endif + { /* With heading separator */ + while (IsSeparator(*path)) path++; /* Strip separators */ + dp->obj.sclust = 0; /* Start from the root directory */ + } +#if FF_FS_EXFAT + dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ +#if FF_FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ + DIR dj; + + dp->obj.c_scl = fs->cdc_scl; + dp->obj.c_size = fs->cdc_size; + dp->obj.c_ofs = fs->cdc_ofs; + res = load_obj_xdir(&dj, &dp->obj); + if (res != FR_OK) return res; + dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } +#endif +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; + res = dir_sdi(dp, 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 segment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; + } 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. */ + /* Get into the sub-directory */ + if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + dp->obj.c_scl = dp->obj.sclust; + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Open next directory */ + } else +#endif + { + dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + } + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get logical drive number from path name */ +/*-----------------------------------------------------------------------*/ + +static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ + const TCHAR** path /* Pointer to pointer to the path name */ +) +{ + const TCHAR *tp; + const TCHAR *tt; + TCHAR tc; + int i; + int vol = -1; +#if FF_STR_VOLUME_ID /* Find string volume ID */ + const char *sp; + char c; +#endif + + tt = tp = *path; + if (!tp) return vol; /* Invalid path name? */ + do { /* Find a colon in the path */ + tc = *tt++; + } while (!IsTerminator(tc) && tc != ':'); + + if (tc == ':') { /* DOS/Windows style volume ID? */ + i = FF_VOLUMES; + if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ + i = (int)*tp - '0'; /* Get the LD number */ + } +#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ + else { + i = 0; + do { + sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ + do { /* Compare the volume ID with path name */ + c = *sp++; tc = *tp++; + if (IsLower(c)) c -= 0x20; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ + } +#endif + if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ + vol = i; /* Drive number */ + *path = tt; /* Snip the drive prefix off */ + } + return vol; + } +#if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ + if (*tp == '/') { /* Is there a volume ID? */ + while (*(tp + 1) == '/') tp++; /* Skip duplicated separator */ + i = 0; + do { + tt = tp; sp = VolumeStr[i]; /* Path name and this string volume ID */ + do { /* Compare the volume ID with path name */ + c = *sp++; tc = *(++tt); + if (IsLower(c)) c -= 0x20; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ + if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ + vol = i; /* Drive number */ + *path = tt; /* Snip the drive prefix off */ + } + return vol; + } +#endif + /* No drive prefix is found */ +#if FF_FS_RPATH != 0 + vol = CurrVol; /* Default drive is current drive */ +#else + vol = 0; /* Default drive is 0 */ +#endif + return vol; /* Return the default drive */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* GPT support functions */ +/*-----------------------------------------------------------------------*/ + +#if FF_LBA64 + +/* Calculate CRC32 in byte-by-byte */ + +static DWORD crc32 ( /* Returns next CRC value */ + DWORD crc, /* Current CRC value */ + BYTE d /* A byte to be processed */ +) +{ + BYTE b; + + + for (b = 1; b; b <<= 1) { + crc ^= (d & b) ? 1 : 0; + crc = (crc & 1) ? crc >> 1 ^ 0xEDB88320 : crc >> 1; + } + return crc; +} + + +/* Check validity of GPT header */ + +static int test_gpt_header ( /* 0:Invalid, 1:Valid */ + const BYTE* gpth /* Pointer to the GPT header */ +) +{ + UINT i; + DWORD bcc, hlen; + + + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ + hlen = ld_dword(gpth + GPTH_Size); /* Check header size */ + if (hlen < 92 || hlen > FF_MIN_SS) return 0; + for (i = 0, bcc = 0xFFFFFFFF; i < hlen; i++) { /* Check header BCC */ + bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); + } + if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; + if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ + if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ + + return 1; +} + +#if !FF_FS_READONLY && FF_USE_MKFS + +/* Generate random value */ +static DWORD make_rand ( + DWORD seed, /* Seed value */ + BYTE *buff, /* Output buffer */ + UINT n /* Data length */ +) +{ + UINT r; + + + if (seed == 0) seed = 1; + do { + for (r = 0; r < 8; r++) seed = seed & 1 ? seed >> 1 ^ 0xA3000000 : seed >> 1; /* Shift 8 bits the 32-bit LFSR */ + *buff++ = (BYTE)seed; + } while (--n); + return seed; +} + +#endif +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT VBR */ +/*-----------------------------------------------------------------------*/ + +/* Check what the sector is */ + +static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not FAT and invalid BS, 4:Disk error */ + FATFS* fs, /* Filesystem object */ + LBA_t sect /* Sector to load and check if it is an FAT-VBR or not */ +) +{ + WORD w, sign; + BYTE b; + + + fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ + sign = ld_word(fs->win + BS_55AA); +#if FF_FS_EXFAT + if (sign == 0xAA55 && !memcmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ +#endif + b = fs->win[BS_JmpBoot]; + if (b == 0xEB || b == 0xE9 || b == 0xE8) { /* Valid JumpBoot code? (short jump, near jump or near call) */ + if (sign == 0xAA55 && !memcmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) { + return 0; /* It is an FAT32 VBR */ + } + /* FAT volumes formatted with early MS-DOS lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ + w = ld_word(fs->win + BPB_BytsPerSec); + b = fs->win[BPB_SecPerClus]; + if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS /* Properness of sector size (512-4096 and 2^n) */ + && b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size (2^n) */ + && ld_word(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of reserved sectors (MNBZ) */ + && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of FATs (1 or 2) */ + && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir entries (MNBZ) */ + && (ld_word(fs->win + BPB_TotSec16) >= 128 || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=128) */ + && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ + return 0; /* It can be presumed an FAT VBR */ + } + } + return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ +} + + +/* Find an FAT volume */ +/* (It supports only generic partitioning rules, MBR, GPT and SFD) */ + +static UINT find_volume ( /* Returns BS status found in the hosting drive */ + FATFS* fs, /* Filesystem object */ + UINT part /* Partition to fined = 0:find as SFD and partitions, >0:forced partition number */ +) +{ + UINT fmt, i; + DWORD mbr_pt[4]; + + + fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD format */ + if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is an FAT VBR as auto scan, not a BS or disk error */ + + /* Sector 0 is not an FAT VBR or forced partition number wants a partition */ + +#if FF_LBA64 + if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ + DWORD n_ent, v_ent, ofs; + QWORD pt_lba; + + if (move_window(fs, 1) != FR_OK) return 4; /* Load GPT header sector (next to MBR) */ + if (!test_gpt_header(fs->win)) return 3; /* Check if GPT header is valid */ + n_ent = ld_dword(fs->win + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_qword(fs->win + GPTH_PtOfs); /* Table location */ + for (v_ent = i = 0; i < n_ent; i++) { /* Find FAT partition */ + if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4; /* PT sector */ + ofs = i * SZ_GPTE % SS(fs); /* Offset in the sector */ + if (!memcmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ + v_ent++; + fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba)); /* Load VBR and check status */ + if (part == 0 && fmt <= 1) return fmt; /* Auto search (valid FAT volume found first) */ + if (part != 0 && v_ent == part) return fmt; /* Forced partition order (regardless of it is valid or not) */ + } + } + return 3; /* Not found */ + } +#endif + if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ + for (i = 0; i < 4; i++) { /* Load partition offset in the MBR */ + mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); + } + i = part ? part - 1 : 0; /* Table index to find first */ + do { /* Find an FAT volume */ + fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; /* Check if the partition is FAT */ + } while (part == 0 && fmt >= 2 && ++i < 4); + return fmt; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Determine logical drive number and mount the volume if needed */ +/*-----------------------------------------------------------------------*/ + +static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + FATFS** rfs, /* Pointer to pointer to the found filesystem object */ + BYTE mode /* Desiered access mode to check write protection */ +) +{ + int vol; + FATFS *fs; + DSTATUS stat; + LBA_t bsect; + DWORD tsect, sysect, fasize, nclst, szbfat; + WORD nrsv; + UINT fmt; + + + /* Get logical drive number */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) return FR_INVALID_DRIVE; + + /* Check if the filesystem object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the filesystem object */ + if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ +#if FF_FS_REENTRANT + if (!lock_volume(fs, 1)) return FR_TIMEOUT; /* Lock the volume, and system if needed */ +#endif + *rfs = fs; /* Return pointer to the filesystem object */ + + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ + if (fs->fs_type != 0) { /* If the volume has been mounted */ + stat = disk_status(fs->pdrv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + } + return FR_OK; /* The filesystem object is already valid */ + } + } + + /* The filesystem object is not valid. */ + /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ + + fs->fs_type = 0; /* Invalidate the filesystem object */ + stat = disk_initialize(fs->pdrv); /* Initialize the volume hosting 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 (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; + } +#if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; +#endif + + /* Find an FAT volume on the hosting drive */ + fmt = find_volume(fs, LD2PT(vol)); + if (fmt == 4) return FR_DISK_ERR; /* An error occurred in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + bsect = fs->winsect; /* Volume offset in the hosting physical drive */ + + /* An FAT volume is found (bsect). Following code initializes the filesystem object */ + +#if FF_FS_EXFAT + if (fmt == 1) { + QWORD maxlba; + DWORD so, cv, bcl, i; + + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; + + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ + + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + } + + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ + if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be accessed in 32-bit LBA) */ + + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ + + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768 sectors) */ + + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = nclst + 2; + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + + /* Get bitmap location and check if it is contiguous (implementation assumption) */ + so = i = 0; + for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ + if (i == 0) { + if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ + if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; + so++; + } + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + i = (i + SZDIRE) % SS(fs); /* Next entry */ + } + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; /* (Wrong cluster#) */ + fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ + for (;;) { /* Check if bitmap is contiguous */ + if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; + cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + if (cv == 0xFFFFFFFF) break; /* Last link? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ + } + +#if !FF_FS_READONLY + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif /* FF_FS_EXFAT */ + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = 0; + if (nclst <= MAX_FAT32) fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; + if (fmt == 0) return FR_NO_FILESYSTEM; + + /* 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 (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) 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)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ + +#if !FF_FS_READONLY + /* Get FSInfo if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->fsi_flag = 0x80; +#if (FF_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 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 (FF_FS_NOFSINFO & 1) == 0 + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#endif +#if (FF_FS_NOFSINFO & 2) == 0 + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif /* (FF_FS_NOFSINFO & 3) != 3 */ +#endif /* !FF_FS_READONLY */ + } + + fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ + fs->id = ++Fsid; /* Volume mount ID */ +#if FF_USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if FF_FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ +#endif +#endif +#if FF_FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ +#endif +#if FF_FS_LOCK /* Clear file lock semaphores */ + clear_share(fs); +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR structure, to check validity */ + FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ +) +{ + FRESULT res = FR_INVALID_OBJECT; + + + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ +#if FF_FS_REENTRANT + if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ + res = FR_OK; + } else { + unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ + } + } else { /* Could not take */ + res = FR_TIMEOUT; + } +#else + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ + res = FR_OK; + } +#endif + } + *rfs = (res == FR_OK) ? obj->fs : 0; /* Return corresponding filesystem object if it is valid */ + return res; +} + + + + +/*--------------------------------------------------------------------------- + + Public Functions (FatFs API) + +----------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs, /* Pointer to the filesystem object to be registered (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* Mount option: 0=Do not mount (delayed mount), 1=Mount immediately */ +) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + + /* Get volume ID (logical drive number) */ + vol = get_ldnumber(&rp); + if (vol < 0) return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ + + if (cfs) { /* Unregister current filesystem object if regsitered */ + FatFs[vol] = 0; +#if FF_FS_LOCK + clear_share(cfs); +#endif +#if FF_FS_REENTRANT /* Discard mutex of the current volume */ + ff_mutex_delete(vol); +#endif + cfs->fs_type = 0; /* Invalidate the filesystem object to be unregistered */ + } + + if (fs) { /* Register new filesystem object */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ +#if FF_FS_REENTRANT /* Create a volume mutex */ + fs->ldrv = (BYTE)vol; /* Owner volume ID */ + if (!ff_mutex_create(vol)) return FR_INT_ERR; +#if FF_FS_LOCK + if (SysLock == 0) { /* Create a system mutex if needed */ + if (!ff_mutex_create(FF_VOLUMES)) { + ff_mutex_delete(vol); + return FR_INT_ERR; + } + SysLock = 1; /* System mutex is ready */ + } +#endif +#endif + fs->fs_type = 0; /* Invalidate the new filesystem object */ + FatFs[vol] = fs; /* Register new fs object */ + } + + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ + + res = mount_volume(&path, &fs, 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 open mode flags */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; +#if !FF_FS_READONLY + DWORD cl, bcs, clst, tm; + LBA_t sc; + FSIZE_t ofs; +#endif + DEF_NAMBUF + + + if (!fp) return FR_INVALID_OBJECT; + + /* Get logical drive number */ + mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; + res = mount_volume(&path, &fs, mode); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ +#if !FF_FS_READONLY /* Read/Write configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } +#if FF_FS_LOCK + else { + res = chk_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + } +#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 FF_FS_LOCK + res = enq_share() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + } + mode |= FA_CREATE_ALWAYS; /* File is created */ + } + else { /* Any object with the same name is already existing */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + init_alloc_info(fs, &fp->obj); + /* Set directory entry block initial state */ + memset(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ + memset(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ + fs->dirbuf[XDIR_Attr] = AM_ARC; + st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Set directory entry initial state */ + tm = GET_FATTIME(); /* Set created time */ + st_dword(dj.dir + DIR_CrtTime, tm); + st_dword(dj.dir + DIR_ModTime, tm); + cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + if (cl != 0) { /* Remove the cluster chain if exist */ + sc = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, sc); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Is the object exsiting? */ + if (dj.obj.attr & AM_DIR) { /* File open against a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ + res = FR_DENIED; + } + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if FF_FS_LOCK + fp->obj.lockid = inc_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ + if (fp->obj.lockid == 0) res = FR_INT_ERR; +#endif + } +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ + res = FR_INVALID_NAME; + } else { + if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ + res = FR_NO_FILE; + } + } + } +#endif + + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + init_alloc_info(fs, &fp->obj); + } else +#endif + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } +#if FF_USE_FASTSEEK + fp->cltbl = 0; /* Disable fast seek mode */ +#endif + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !FF_FS_READONLY +#if !FF_FS_TINY + memset(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + sc = clst2sect(fs, clst); + if (sc == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !FF_FS_TINY + if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } +#if FF_FS_LOCK + if (res != FR_OK) dec_share(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#endif + } +#endif + } + + FREE_NAMBUF(); + } + + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Open file to be read */ + void* buff, /* Data buffer to store the read data */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Number of bytes read */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst; + LBA_t sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr > 0; btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { /* Repeat until btr bytes read */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ + } else { /* Middle or end of the file */ +#if FF_USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } + } + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ + if (cc > 0) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if FF_FS_TINY + if (fs->wflag && fs->winsect - sect < cc) { + memcpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } +#else + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { + memcpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } +#endif +#endif + rcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !FF_FS_TINY + if (fp->sect != sect) { /* Load data sector if not in cache */ +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + } +#endif + fp->sect = sect; + } + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ +#if FF_FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + memcpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#else + memcpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#endif + } + + LEAVE_FF(fs, FR_OK); +} + + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Open file to be written */ + const void* buff, /* Data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Number of bytes written */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst; + LBA_t sect; + UINT wcnt, cc, csect; + const BYTE *wbuff = (const BYTE*)buff; + + + *bw = 0; /* Clear write byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + for ( ; btw > 0; btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { /* Repeat until all data written */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ +#if FF_USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = create_chain(&fp->obj, 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(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ + } +#if FF_FS_TINY + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ +#else + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ + if (cc > 0) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if FF_FS_MINIMIZE <= 2 +#if FF_FS_TINY + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + memcpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; + } +#else + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + memcpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif +#endif + wcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if FF_FS_TINY + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; + } +#else + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } +#endif + fp->sect = sect; + } + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ +#if FF_FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + memcpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fs->wflag = 1; +#else + memcpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; +#endif + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Open file to be synced */ +) +{ + FRESULT res; + FATFS *fs; + DWORD tm; + BYTE *dir; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ +#if !FF_FS_TINY + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + /* Update the directory entry */ + tm = GET_FATTIME(); /* Modified time */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } + if (res == FR_OK) { + DIR dj; + DEF_NAMBUF + + INIT_NAMBUF(fs); + res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + FREE_NAMBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL* fp /* Open file to be closed */ +) +{ + FRESULT res; + FATFS *fs; + +#if !FF_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(&fp->obj, &fs); /* Lock volume */ + if (res == FR_OK) { +#if FF_FS_LOCK + res = dec_share(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ +#else + fp->obj.fs = 0; /* Invalidate file object */ +#endif +#if FF_FS_REENTRANT + unlock_volume(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +#if FF_FS_RPATH >= 1 +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chdrive ( + const TCHAR* path /* Drive number to set */ +) +{ + int vol; + + + /* Get logical drive number */ + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + CurrVol = (BYTE)vol; /* Set it as current volume */ + + return FR_OK; +} + + + +FRESULT f_chdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ +#if FF_STR_VOLUME_ID == 2 + UINT i; +#endif + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + + /* Get logical drive */ + res = mount_volume(&path, &fs, 0); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ + fs->cdir = dj.obj.sclust; +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif + } else { + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { + res = FR_NO_PATH; /* Reached but a file */ + } + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; +#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed if in Unix style volume ID */ + if (res == FR_OK) { + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ + CurrVol = (BYTE)i; + } +#endif + } + + LEAVE_FF(fs, res); +} + + +#if FF_FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of buff in unit of TCHAR */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + UINT i, n; + DWORD ccl; + TCHAR *tp = buff; +#if FF_VOLUMES >= 2 + UINT vl; +#if FF_STR_VOLUME_ID + const char *vp; +#endif +#endif + FILINFO fno; + DEF_NAMBUF + + + /* Get logical drive */ + buff[0] = 0; /* Set null string to get current volume */ + res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + + /* Follow parent directories and create the path */ + i = len; /* Bottom of buffer (directory stack base) */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + if (res != FR_OK) break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(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_FILE(&dj); + if (res != FR_OK) break; + if (ccl == ld_clust(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; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; /* Name length */ + if (i < n + 1) { /* Insufficient space to store the path name? */ + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ + buff[--i] = '/'; + } + } + if (res == FR_OK) { + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ +#if FF_VOLUMES >= 2 /* Put drive prefix */ + vl = 0; +#if FF_STR_VOLUME_ID >= 1 /* String volume ID */ + for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; + if (i >= n + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; + for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; + vl++; + } +#else /* Numeric volume ID */ + if (i >= 3) { + *tp++ = (TCHAR)'0' + CurrVol; + *tp++ = (TCHAR)':'; + vl = 2; + } +#endif + if (vl == 0) res = FR_NOT_ENOUGH_CORE; +#endif + /* Add current directory path */ + if (res == FR_OK) { + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); + } + } + FREE_NAMBUF(); + } + + *tp = 0; + LEAVE_FF(fs, res); +} + +#endif /* FF_FS_RPATH >= 2 */ +#endif /* FF_FS_RPATH >= 1 */ + + + +#if FF_FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File Read/Write Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, bcs; + LBA_t nsect; + FSIZE_t ifptr; +#if FF_USE_FASTSEEK + DWORD cl, pcl, ncl, tcl, tlen, ulen; + DWORD *tbl; + LBA_t dsc; +#endif + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) res = (FRESULT)fp->err; +#if FF_FS_EXFAT && !FF_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_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->obj.sclust; /* Origin of the chain */ + if (cl != 0) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(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 < 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->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ + fp->fptr = ofs; /* Set file pointer */ + if (ofs > 0) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clst2sect(fs, fp->clust); + if (dsc == 0) ABORT(fs, FR_INT_ERR); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ +#if !FF_FS_TINY +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ +#endif + fp->sect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ +#endif + if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs > 0) { + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->obj.sclust; /* start from the first cluster */ +#if !FF_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; +#if !FF_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; + } + } else +#endif + { + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); + fp->clust = clst; + } + fp->fptr += ofs; + if (ofs % SS(fs)) { + nsect = clst2sect(fs, clst); /* Current sector */ + if (nsect == 0) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); + } + } + } + if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ +#if !FF_FS_TINY +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ +#endif + fp->sect = nsect; + } + } + + LEAVE_FF(fs, res); +} + + + +#if FF_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; + DEF_NAMBUF + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + res = mount_volume(&path, &fs, 0); + if (res == FR_OK) { + dp->obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(dp, path); /* Follow the path to the directory */ + if (res == FR_OK) { /* Follow completed */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Get object allocation info */ + } else +#endif + { + dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ + } + } else { /* This object is a file */ + res = FR_NO_PATH; + } + } + if (res == FR_OK) { + dp->obj.id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if FF_FS_LOCK + if (res == FR_OK) { + if (dp->obj.sclust != 0) { + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub directory */ + if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; + } else { + dp->obj.lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + + + res = validate(&dp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { +#if FF_FS_LOCK + if (dp->obj.lockid) res = dec_share(dp->obj.lockid); /* Decrement sub-directory open counter */ + if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ +#else + dp->obj.fs = 0; /* Invalidate directory object */ +#endif +#if FF_FS_REENTRANT + unlock_volume(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; + FATFS *fs; + DEF_NAMBUF + + + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_NAMBUF(fs); + res = DIR_READ_FILE(dp); /* Read an item */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ + 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) res = FR_OK; /* Ignore end of directory now */ + } + FREE_NAMBUF(); + } + } + LEAVE_FF(fs, res); +} + + + +#if FF_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 (pattern_match(dp->pat, fno->fname, 0, FIND_RECURS)) break; /* Test for the file name */ +#if FF_USE_LFN && FF_USE_FIND == 2 + if (pattern_match(dp->pat, fno->altname, 0, FIND_RECURS)) break; /* Test for alternative name if exist */ +#endif + } + 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 /* FF_USE_FIND */ + + + +#if FF_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; + DEF_NAMBUF + + + /* Get logical drive */ + res = mount_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) { + INIT_NAMBUF(dj.obj.fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ + res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(dj.obj.fs, res); +} + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR* path, /* Logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD nfree, clst, stat; + LBA_t sect; + UINT i; + FFOBJID obj; + + + /* Get logical drive */ + res = mount_volume(&path, &fs, 0); + if (res == FR_OK) { + *fatfs = fs; /* Return ptr to the fs object */ + /* If free_clst is valid, return it without full FAT scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; + } else { + /* Scan FAT to obtain number of free clusters */ + nfree = 0; + if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ + clst = 2; obj.fs = fs; + do { + stat = get_fat(&obj, clst); + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (stat == 1) { + res = FR_INT_ERR; break; + } + if (stat == 0) nfree++; + } while (++clst < fs->n_fatent); + } else { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; /* Number of clusters */ + sect = fs->bitbase; /* Bitmap sector */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of bits with zero in the bitmap */ + if (i == 0) { /* New sector? */ + res = move_window(fs, sect++); + if (res != FR_OK) break; + } + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { + nfree += bm & 1; + bm >>= 1; + } + i = (i + 1) % SS(fs); + } while (clst); + } else +#endif + { /* FAT16/32: Scan WORD/DWORD FAT entries */ + clst = fs->n_fatent; /* Number of entries */ + sect = fs->fatbase; /* Top of the FAT */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of entries with zero in the FAT */ + if (i == 0) { /* New sector? */ + res = move_window(fs, sect++); + if (res != FR_OK) break; + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(fs->win + i) == 0) nfree++; + i += 2; + } else { + if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; + i += 4; + } + i %= SS(fs); + } while (--clst); + } + } + if (res == FR_OK) { /* Update parameters if succeeded */ + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + } + } + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD ncl; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); + } + } + fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ + fp->flag |= FA_MODIFIED; +#if !FF_FS_TINY + if (res == FR_OK && (fp->flag & FA_DIRTY)) { + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= (BYTE)~FA_DIRTY; + } + } +#endif + if (res != FR_OK) ABORT(fs, res); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + FATFS *fs; + DIR dj, sdj; + DWORD dclst = 0; +#if FF_FS_EXFAT + FFOBJID obj; +#endif + DEF_NAMBUF + + + /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; /* Cannot remove dot entry */ + } +#if FF_FS_LOCK + if (res == FR_OK) res = chk_share(&dj, 2); /* Check if it is an open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + if (dj.fn[NSFLAG] & NS_NONAME) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* Cannot remove R/O object */ + } + } + if (res == FR_OK) { +#if FF_FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(fs, &obj); + dclst = obj.sclust; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ +#if FF_FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ +#if FF_FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + FATFS *fs; + DIR dj; + FFOBJID sobj; + DWORD dcl, pcl, tm; + DEF_NAMBUF + + + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Name collision? */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ + res = FR_INVALID_NAME; + } + if (res == FR_NO_FILE) { /* It is clear to create a new directory */ + sobj.fs = fs; /* New object id to create a new chain */ + dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ + if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ + tm = GET_FATTIME(); + if (res == FR_OK) { + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ + memset(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ + fs->win[DIR_Name] = '.'; + fs->win[DIR_Attr] = AM_DIR; + st_dword(fs->win + DIR_ModTime, tm); + st_clust(fs, fs->win, dcl); + memcpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ + fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, fs->win + SZDIRE, pcl); + fs->wflag = 1; + } + res = dir_register(&dj); /* Register the object to the parent directoy */ + } + } + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dj.dir, dcl); /* Table start cluster */ + dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } else { + remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object name to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + FATFS *fs; + DIR djo, djn; + BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; + LBA_t sect; + DEF_NAMBUF + + + get_ldnumber(&path_new); /* Snip the drive number of new name off */ + res = mount_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ + if (res == FR_OK) { + djo.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&djo, path_old); /* Check old object */ + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if FF_FS_LOCK + if (res == FR_OK) { + res = chk_share(&djo, 2); + } +#endif + if (res == FR_OK) { /* Object to be renamed is found */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ + BYTE nf, nn; + WORD nh; + + memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + memcpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + 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) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + memcpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); + if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ +/* Start of critical section where an interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT/FAT32 volume */ + memcpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ + memcpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + 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) { + dir = djn.dir; /* Copy directory entry of the object except name */ + memcpy(dir + 13, buf + 13, SZDIRE - 13); + dir[DIR_Attr] = buf[DIR_Attr]; + if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + sect = clst2sect(fs, ld_clust(fs, dir)); + if (sect == 0) { + res = FR_INT_ERR; + } else { +/* Start of critical section where an interruption can cause a cross-link */ + res = move_window(fs, sect); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; + } + } + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of the critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_MINIMIZE == 0 */ +#endif /* FF_FS_MINIMIZE <= 1 */ +#endif /* FF_FS_MINIMIZE <= 2 */ + + + +#if FF_USE_CHMOD && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* 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; + FATFS *fs; + DIR dj; + DEF_NAMBUF + + + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else +#endif + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the timestamp to be set */ +) +{ + FRESULT res; + FATFS *fs; + DIR dj; + DEF_NAMBUF + + + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* FF_USE_CHMOD && !FF_FS_READONLY */ + + + +#if FF_USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + const TCHAR* path, /* Logical drive number */ + TCHAR* label, /* Buffer to store the volume label */ + DWORD* vsn /* Variable to store the volume serial number */ +) +{ + FRESULT res; + FATFS *fs; + DIR dj; + UINT si, di; + WCHAR wc; + + /* Get logical drive */ + res = mount_volume(&path, &fs, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ + if (res == FR_OK) { +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + WCHAR hs; + UINT nw; + + for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + wc = ld_word(dj.dir + XDIR_Label + si * 2); + if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ + hs = wc; continue; + } + nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ + if (nw == 0) { /* Encode error? */ + di = 0; break; + } + di += nw; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry */ + while (si < 11) { + wc = dj.dir[si++]; +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ + wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ + if (wc == 0) { /* Invalid char in current code page? */ + di = 0; break; + } + di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ +#else /* ANSI/OEM output */ + label[di++] = (TCHAR)wc; +#endif + } + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } + } + } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(fs, fs->volbase); + if (res == FR_OK) { + switch (fs->fs_type) { + case FS_EXFAT: + di = BPB_VolIDEx; + break; + + case FS_FAT32: + di = BS_VolID32; + break; + + default: + di = BS_VolID; + } + *vsn = ld_dword(fs->win + di); + } + } + + LEAVE_FF(fs, res); +} + + + +#if !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + const TCHAR* label /* Volume label to set with heading logical drive number */ +) +{ + FRESULT res; + FATFS *fs; + DIR dj; + BYTE dirvn[22]; + UINT di; + WCHAR wc; + static const char badchr[18] = "+.,;=[]" "/*:<>|\\\"\?\x7F"; /* [0..16] for FAT, [7..16] for exFAT */ +#if FF_USE_LFN + DWORD dc; +#endif + + /* Get logical drive */ + res = mount_volume(&label, &fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + memset(dirvn, 0, 22); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ + dc = tchar2uni(&label); /* Get a Unicode character */ + if (dc >= 0x10000) { + if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ + dc = 0; + } else { + st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + } + } + if (dc == 0 || strchr(&badchr[7], (int)dc) || di >= 11) { /* Check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + di * 2, (WCHAR)dc); di++; + } + } else +#endif + { /* On the FAT/FAT32 volume */ + memset(dirvn, ' ', 11); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ +#if FF_USE_LFN + dc = tchar2uni(&label); + wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; +#else /* ANSI/OEM input */ + wc = (BYTE)*label++; + if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; + if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ +#if FF_CODE_PAGE == 0 + if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#elif FF_CODE_PAGE < 900 + if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#endif +#endif + if (wc == 0 || strchr(&badchr[0], (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); + dirvn[di++] = (BYTE)wc; + } + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ + } + + /* Set volume label */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = DIR_READ_LABEL(&dj); /* Get volume label entry */ + if (res == FR_OK) { + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ + memcpy(dj.dir + XDIR_Label, dirvn, 22); + } else { + if (di != 0) { + memcpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } + } + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry or an error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (di != 0) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ + if (res == FR_OK) { + memset(dj.dir, 0, SZDIRE); /* Clean the entry */ + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ + dj.dir[XDIR_NumLabel] = (BYTE)di; + memcpy(dj.dir + XDIR_Label, dirvn, 22); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + memcpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); + } + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LABEL */ + + + +#if FF_USE_EXPAND && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + lclst = scl + tcl - 1; + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + n = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (n == 1) { + res = FR_INT_ERR; break; + } + if (n == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { /* No contiguous cluster? */ + res = FR_DENIED; break; + } + } + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); + if (res != FR_OK) break; + lclst = clst; + } + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } + + if (res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + if (opt) { /* Is it allocated now? */ + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* FF_USE_EXPAND && !FF_FS_READONLY */ + + + +#if FF_USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward Data to the Stream Directly */ +/*-----------------------------------------------------------------------*/ + +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; + FATFS *fs; + DWORD clst; + LBA_t sect; + FSIZE_t remain; + UINT rcnt, csect; + BYTE *dbuf; + + + *bf = 0; /* Clear transfer byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + remain = fp->obj.objsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf > 0 && (*func)(0, 0); fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { /* Repeat until all data transferred or stream goes busy */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clst2sect(fs, fp->clust); /* Get current data sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); + sect += csect; +#if FF_FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !FF_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (rcnt == 0) ABORT(fs, FR_INT_ERR); + } + + LEAVE_FF(fs, FR_OK); +} +#endif /* FF_USE_FORWARD */ + + + +#if !FF_FS_READONLY && FF_USE_MKFS +/*-----------------------------------------------------------------------*/ +/* Create FAT/exFAT volume (with sub-functions) */ +/*-----------------------------------------------------------------------*/ + +#define N_SEC_TRACK 63 /* Sectors per track for determination of drive CHS */ +#define GPT_ALIGN 0x100000 /* Alignment of partitions in GPT [byte] (>=128KB) */ +#define GPT_ITEMS 128 /* Number of GPT table size (>=128, sector aligned) */ + + +/* Create partitions on the physical drive in format of MBR or GPT */ + +static FRESULT create_partition ( + BYTE drv, /* Physical drive number */ + const LBA_t plst[], /* Partition list */ + BYTE sys, /* System ID for each partition (for only MBR) */ + BYTE *buf /* Working buffer for a sector */ +) +{ + UINT i, cy; + LBA_t sz_drv; + DWORD sz_drv32, nxt_alloc32, sz_part32; + BYTE *pte; + BYTE hd, n_hd, sc, n_sc; + + /* Get physical drive size */ + if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR; + +#if FF_LBA64 + if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT format */ + WORD ss; + UINT sz_ptbl, pi, si, ofs; + DWORD bcc, rnd, align; + QWORD nxt_alloc, sz_part, sz_pool, top_bpt; + static const BYTE gpt_mbr[16] = {0x00, 0x00, 0x02, 0x00, 0xEE, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; + +#if FF_MAX_SS != FF_MIN_SS + if (disk_ioctl(drv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; /* Get sector size */ + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = FF_MAX_SS; +#endif + rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ + align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ + sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start sector */ + nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ + sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ + bcc = 0xFFFFFFFF; sz_part = 1; + pi = si = 0; /* partition table index, size table index */ + do { + if (pi * SZ_GPTE % ss == 0) memset(buf, 0, ss); /* Clean the buffer if needed */ + if (sz_part != 0) { /* Is the size table not termintated? */ + nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start */ + sz_part = plst[si++]; /* Get a partition size */ + if (sz_part <= 100) { /* Is the size in percentage? */ + sz_part = sz_pool * sz_part / 100; + sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ + } + if (nxt_alloc + sz_part > top_bpt) { /* Clip the size at end of the pool */ + sz_part = (nxt_alloc < top_bpt) ? top_bpt - nxt_alloc : 0; + } + } + if (sz_part != 0) { /* Add a partition? */ + ofs = pi * SZ_GPTE % ss; + memcpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Set partition GUID (Microsoft Basic Data) */ + rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Set unique partition GUID */ + st_qword(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start sector */ + st_qword(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end sector */ + nxt_alloc += sz_part; /* Next allocatable sector */ + } + if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ + for (i = 0; i < ss; bcc = crc32(bcc, buf[i++])) ; /* Calculate table check sum */ + if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to primary table */ + if (disk_write(drv, buf, top_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to secondary table */ + } + } while (++pi < GPT_ITEMS); + + /* Create primary GPT header */ + memset(buf, 0, ss); + memcpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ + st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ + st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of secondary header */ + st_qword(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ + st_qword(buf + GPTH_LstLba, top_bpt - 1); /* LBA of last allocatable sector */ + st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ + st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ + st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ + rnd = make_rand(rnd, buf + GPTH_DskGuid, 16); /* Disk GUID */ + for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + if (disk_write(drv, buf, 1, 1) != RES_OK) return FR_DISK_ERR; + + /* Create secondary GPT header */ + st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, 1); /* LBA of primary header */ + st_qword(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ + st_dword(buf + GPTH_Bcc, 0); + for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + if (disk_write(drv, buf, sz_drv - 1, 1) != RES_OK) return FR_DISK_ERR; + + /* Create protective MBR */ + memset(buf, 0, ss); + memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ + st_word(buf + BS_55AA, 0xAA55); + if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; + + } else +#endif + { /* Create partitions in MBR format */ + sz_drv32 = (DWORD)sz_drv; + n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ + for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ; + if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ + + memset(buf, 0, FF_MAX_SS); /* Clear MBR */ + pte = buf + MBR_Table; /* Partition table in the MBR */ + for (i = 0, nxt_alloc32 = n_sc; i < 4 && nxt_alloc32 != 0 && nxt_alloc32 < sz_drv32; i++, nxt_alloc32 += sz_part32) { + sz_part32 = (DWORD)plst[i]; /* Get partition size */ + if (sz_part32 <= 100) sz_part32 = (sz_part32 == 100) ? sz_drv32 : sz_drv32 / 100 * sz_part32; /* Size in percentage? */ + if (nxt_alloc32 + sz_part32 > sz_drv32 || nxt_alloc32 + sz_part32 < nxt_alloc32) sz_part32 = sz_drv32 - nxt_alloc32; /* Clip at drive size */ + if (sz_part32 == 0) break; /* End of table or no sector to allocate? */ + + st_dword(pte + PTE_StLba, nxt_alloc32); /* Start LBA */ + st_dword(pte + PTE_SizLba, sz_part32); /* Number of sectors */ + pte[PTE_System] = sys; /* System type */ + + cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Start cylinder */ + hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Start head */ + sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Start sector */ + pte[PTE_StHead] = hd; + pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); + pte[PTE_StCyl] = (BYTE)cy; + + cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* End cylinder */ + hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* End head */ + sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* End sector */ + pte[PTE_EdHead] = hd; + pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); + pte[PTE_EdCyl] = (BYTE)cy; + + pte += SZ_PTE; /* Next entry */ + } + + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + } + + return FR_OK; +} + + + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + const MKFS_PARM* opt, /* Format options */ + void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ + UINT len /* Size of working buffer [byte] */ +) +{ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ + static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ + BYTE fsopt, fsty, sys, pdrv, ipart; + BYTE *buf; + BYTE *pte; + WORD ss; /* Sector size */ + DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; + LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ + LBA_t sect, lba[2]; + DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ + UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ + int vol; + DSTATUS ds; + FRESULT res; + + + /* Check mounted drive and clear work area */ + vol = get_ldnumber(&path); /* Get target logical drive */ + if (vol < 0) return FR_INVALID_DRIVE; + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ + pdrv = LD2PD(vol); /* Hosting physical drive */ + ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) */ + + /* Initialize the hosting physical drive */ + ds = disk_initialize(pdrv); + if (ds & STA_NOINIT) return FR_NOT_READY; + if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + + /* Get physical drive parameters (sz_drv, sz_blk and ss) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ + sz_blk = opt->align; + if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the paramter or lower layer */ + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ +#if FF_MAX_SS != FF_MIN_SS + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = FF_MAX_SS; +#endif + + /* Options for FAT sub-type and FAT parameters */ + fsopt = opt->fmt & (FM_ANY | FM_SFD); + n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; + n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512; + sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0; + sz_au /= ss; /* Byte --> Sector */ + + /* Get working buffer */ + sz_buf = len / ss; /* Size of working buffer [sector] */ + if (sz_buf == 0) return FR_NOT_ENOUGH_CORE; + buf = (BYTE*)work; /* Working buffer */ +#if FF_USE_LFN == 3 + if (!buf) buf = ff_memalloc(sz_buf * ss); /* Use heap memory for working buffer */ +#endif + if (!buf) return FR_NOT_ENOUGH_CORE; + + /* Determine where the volume to be located (b_vol, sz_vol) */ + b_vol = sz_vol = 0; + if (FF_MULTI_PARTITION && ipart != 0) { /* Is the volume associated with any specific partition? */ + /* Get partition location from the existing partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ +#if FF_LBA64 + if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ + DWORD n_ent, ofs; + QWORD pt_lba; + + /* Get the partition location from GPT */ + if (disk_read(pdrv, buf, 1, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load GPT header sector (next to MBR) */ + if (!test_gpt_header(buf)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if GPT header is valid */ + n_ent = ld_dword(buf + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_qword(buf + GPTH_PtOfs); /* Table start sector */ + ofs = i = 0; + while (n_ent) { /* Find MS Basic partition with order of ipart */ + if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */ + if (!memcmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ + b_vol = ld_qword(buf + ofs + GPTE_FstLba); + sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1; + break; + } + n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ + } + if (n_ent == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* Partition not found */ + fsopt |= 0x80; /* Partitioning is in GPT */ + } else +#endif + { /* Get the partition location from MBR partition table */ + pte = buf + (MBR_Table + (ipart - 1) * SZ_PTE); + if (ipart > 4 || pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ + } + } else { /* The volume is associated with a physical drive */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + if (!(fsopt & FM_SFD)) { /* To be partitioned? */ + /* Create a single-partition on the drive in this function */ +#if FF_LBA64 + if (sz_vol >= FF_MIN_GPT) { /* Which partition type to create, MBR or GPT? */ + fsopt |= 0x80; /* Partitioning is in GPT */ + b_vol = GPT_ALIGN / ss; sz_vol -= b_vol + GPT_ITEMS * SZ_GPTE / ss + 1; /* Estimated partition offset and size */ + } else +#endif + { /* Partitioning is in MBR */ + if (sz_vol > N_SEC_TRACK) { + b_vol = N_SEC_TRACK; sz_vol -= b_vol; /* Estimated partition offset and size */ + } + } + } + } + if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ + + /* Now start to create an FAT volume at b_vol and sz_vol */ + + do { /* Pre-determine the FAT type */ + if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? */ + if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64MS or sz_au > 128S ? */ + fsty = FS_EXFAT; break; + } + } +#if FF_LBA64 + if (sz_vol >= 0x100000000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too large volume for FAT/FAT32 */ +#endif + if (sz_au > 128) sz_au = 128; /* Invalid AU for FAT/FAT32? */ + if (fsopt & FM_FAT32) { /* FAT32 possible? */ + if (!(fsopt & FM_FAT)) { /* no-FAT? */ + fsty = FS_FAT32; break; + } + } + if (!(fsopt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ + fsty = FS_FAT16; + } while (0); + + vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partitiion size */ + +#if FF_FS_EXFAT + if (fsty == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nbit, clu, clen[3]; + WCHAR ch, si; + UINT j, st; + + if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume for exFAT? */ +#if FF_USE_TRIM + lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, lba); +#endif + /* Determine FAT location, data location and number of clusters */ + if (sz_au == 0) { /* AU auto-selection */ + sz_au = 8; + if (sz_vol >= 0x80000) sz_au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) sz_au = 256; /* >= 64Ms */ + } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + n_clst = (DWORD)((sz_vol - (b_data - b_vol)) / sz_au); /* Number of clusters */ + if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ + if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + clen[0] = (szb_bit + sz_au * ss - 1) / (sz_au * ss); /* Number of allocation bitmap clusters */ + + /* Create a compressed up-case table */ + sect = b_data + sz_au * clen[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = 0; si = 0; i = 0; j = 0; szb_case = 0; + do { + switch (st) { + case 0: + ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 chars */ + } + st = 1; /* Do not compress short run */ + /* FALLTHROUGH */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; + + default: + ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (si == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */ + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; i = 0; + } + } while (si); + clen[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ + clen[2] = 1; /* Number of root dir clusters */ + + /* Initialize the allocation bitmap */ + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of bitmap sectors */ + nbit = clen[0] + clen[1] + clen[2]; /* Number of clusters in-use by system (bitmap, up-case and root-dir) */ + do { + memset(buf, 0, sz_buf * ss); /* Initialize bitmap buffer */ + for (i = 0; nbit != 0 && i / 8 < sz_buf * ss; buf[i / 8] |= 1 << (i % 8), i++, nbit--) ; /* Mark used clusters */ + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the FAT */ + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nbit = clu = 0; + do { + memset(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */ + if (clu == 0) { /* Initialize FAT [0] and FAT[1] */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; clu++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; clu++; + } + do { /* Create chains of bitmap, up-case and root dir */ + while (nbit != 0 && i < sz_buf * ss) { /* Create a chain */ + st_dword(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF); + i += 4; clu++; nbit--; + } + if (nbit == 0 && j < 3) nbit = clen[j++]; /* Get next chain length */ + } while (nbit != 0 && i < sz_buf * ss); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the root directory */ + memset(buf, 0, sz_buf * ss); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ + sect = b_data + sz_au * (clen[0] + clen[1]); nsect = sz_au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + memset(buf, 0, ss); /* Rest of entries are filled with zero */ + sect += n; nsect -= n; + } while (nsect); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + memset(buf, 0, ss); + memcpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, vsn); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = sz_au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + /* Extended bootstrap record (+1..+8) */ + memset(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + /* OEM/Reserved record (+9..+10) */ + memset(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + } + + } else +#endif /* FF_FS_EXFAT */ + { /* Create an FAT/FAT32 volume */ + do { + pau = sz_au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fsty == FS_FAT32) { /* FAT32 volume */ + if (pau == 0) { /* AU auto-selection */ + n = (DWORD)sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = (DWORD)sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); + } else { /* FAT volume */ + if (pau == 0) { /* au auto-selection */ + n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = (DWORD)sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fsty = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ + + /* Align data area to erase block boundary (for flash memory media) */ + n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base */ + if (fsty == FS_FAT32) { /* FAT32: Move FAT */ + sz_rsv += n; b_fat += n; + } else { /* FAT: Expand FAT */ + if (n % n_fat) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } + sz_fat += n / n_fat; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau; + if (fsty == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */ + if (sz_au == 0 && (sz_au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + } + if (fsty == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (sz_au == 0 && (pau * 2) <= 64) { + sz_au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((fsopt & FM_FAT32)) { + fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); + } + } + if (fsty == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); + +#if FF_USE_TRIM + lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, lba); +#endif + /* Create FAT VBR */ + memset(buf, 0, ss); + memcpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11); /* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = (BYTE)n_fat; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ + if (fsty == FS_FAT32) { + st_dword(buf + BS_VolID32, vsn); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + st_dword(buf + BS_VolID, vsn); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + memcpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fsty == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + memset(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ + } + + /* Initialize FAT area */ + memset(buf, 0, sz_buf * ss); + sect = b_fat; /* FAT start sector */ + for (i = 0; i < n_fat; i++) { /* Initialize FATs each */ + if (fsty == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */ + st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */ + st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory) */ + } else { + st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ + } + nsect = sz_fat; /* Number of FAT sectors */ + do { /* Fill FAT sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + memset(buf, 0, ss); /* Rest of FAT all are cleared */ + sect += n; nsect -= n; + } while (nsect); + } + + /* Initialize root directory (fill with zero) */ + nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + do { + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + sect += n; nsect -= n; + } while (nsect); + } + + /* A FAT volume has been created here */ + + /* Determine system ID in the MBR partition table */ + if (FF_FS_EXFAT && fsty == FS_EXFAT) { + sys = 0x07; /* exFAT */ + } else if (fsty == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else if (fsty == FS_FAT16) { + sys = 0x04; /* FAT16 */ + } else { + sys = 0x01; /* FAT12 */ + } + + /* Update partition information */ + if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ + if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */ + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ + buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ + } + } else { /* Volume as a new single partition */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format */ + lba[0] = sz_vol; lba[1] = 0; + res = create_partition(pdrv, lba, sys, buf); + if (res != FR_OK) LEAVE_MKFS(res); + } + } + + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + + LEAVE_MKFS(FR_OK); +} + + + + +#if FF_MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Create Partition Table on the Physical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + BYTE pdrv, /* Physical drive number */ + const LBA_t ptbl[], /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer (null: use heap memory) */ +) +{ + BYTE *buf = (BYTE*)work; + DSTATUS stat; + FRESULT res; + + + /* Initialize the physical drive */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + +#if FF_USE_LFN == 3 + if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ +#endif + if (!buf) return FR_NOT_ENOUGH_CORE; + + res = create_partition(pdrv, ptbl, 0x07, buf); /* Create partitions (system ID is temporary setting and determined by f_mkfs) */ + + LEAVE_MKFS(res); +} + +#endif /* FF_MULTI_PARTITION */ +#endif /* !FF_FS_READONLY && FF_USE_MKFS */ + + + + +#if FF_USE_STRFUNC +#if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) +#error Wrong FF_STRF_ENCODE setting +#endif +/*-----------------------------------------------------------------------*/ +/* Get a String from the File */ +/*-----------------------------------------------------------------------*/ + +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the buffer to store read string */ + int len, /* Size of string buffer (items) */ + FIL* fp /* Pointer to the file object */ +) +{ + int nc = 0; + TCHAR *p = buff; + BYTE s[4]; + UINT rc; + DWORD dc; +#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 + WCHAR wc; +#endif +#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 + UINT ct; +#endif + +#if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ + /* Make a room for the character and terminator */ + if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; + if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; + if (FF_LFN_UNICODE == 3) len -= 1; + while (nc < len) { +#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); /* Get a code unit */ + if (rc != 1) break; /* EOF? */ + wc = s[0]; + if (dbc_1st((BYTE)wc)) { /* DBC 1st byte? */ + f_read(fp, s, 1, &rc); /* Get 2nd byte */ + if (rc != 1 || !dbc_2nd(s[0])) continue; /* Wrong code? */ + wc = wc << 8 | s[0]; + } + dc = ff_oem2uni(wc, CODEPAGE); /* Convert ANSI/OEM into Unicode */ + if (dc == 0) continue; /* Conversion error? */ +#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ + f_read(fp, s, 2, &rc); /* Get a code unit */ + if (rc != 2) break; /* EOF? */ + dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; + if (IsSurrogateL(dc)) continue; /* Broken surrogate pair? */ + if (IsSurrogateH(dc)) { /* High surrogate? */ + f_read(fp, s, 2, &rc); /* Get low surrogate */ + if (rc != 2) break; /* EOF? */ + wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; + if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ + dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ + } +#else /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); /* Get a code unit */ + if (rc != 1) break; /* EOF? */ + dc = s[0]; + if (dc >= 0x80) { /* Multi-byte sequence? */ + ct = 0; + if ((dc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + dc &= 0x1F; ct = 1; + } + if ((dc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + dc &= 0x0F; ct = 2; + } + if ((dc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + dc &= 0x07; ct = 3; + } + if (ct == 0) continue; + f_read(fp, s, ct, &rc); /* Get trailing bytes */ + if (rc != ct) break; + rc = 0; + do { /* Merge the byte sequence */ + if ((s[rc] & 0xC0) != 0x80) break; + dc = dc << 6 | (s[rc] & 0x3F); + } while (++rc < ct); + if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ + } +#endif + /* A code point is avaialble in dc to be output */ + + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ +#if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ + if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ + *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ + dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ + } + *p++ = (TCHAR)dc; nc++; + if (dc == '\n') break; /* End of line? */ +#elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ + if (dc < 0x80) { /* Single byte? */ + *p++ = (TCHAR)dc; + nc++; + if (dc == '\n') break; /* End of line? */ + } else if (dc < 0x800) { /* 2-byte sequence? */ + *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 2; + } else if (dc < 0x10000) { /* 3-byte sequence? */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte sequence */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; + } +#endif + } + +#else /* Byte-by-byte read without any conversion (ANSI/OEM API) */ + len -= 1; /* Make a room for the terminator */ + while (nc < len) { + f_read(fp, s, 1, &rc); /* Get a byte */ + if (rc != 1) break; /* EOF? */ + dc = s[0]; + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; + *p++ = (TCHAR)dc; nc++; + if (dc == '\n') break; + } +#endif + + *p = 0; /* Terminate the string */ + return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ +} + + + + +#if !FF_FS_READONLY +#include +#define SZ_PUTC_BUF 64 +#define SZ_NUM_BUF 32 + +/*-----------------------------------------------------------------------*/ +/* Put a Character to the File (with sub-functions) */ +/*-----------------------------------------------------------------------*/ + +/* Output buffer and work area */ + +typedef struct { + FIL *fp; /* Ptr to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ +#if FF_USE_LFN && FF_LFN_UNICODE == 1 + WCHAR hs; +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 + BYTE bs[4]; + UINT wi, ct; +#endif + BYTE buf[SZ_PUTC_BUF]; /* Write buffer */ +} putbuff; + + +/* Buffered file write with code conversion */ + +static void putc_bfd (putbuff* pb, TCHAR c) +{ + UINT n; + int i, nc; +#if FF_USE_LFN && FF_LFN_UNICODE + WCHAR hs, wc; +#if FF_LFN_UNICODE == 2 + DWORD dc; + const TCHAR* tp; +#endif +#endif + + if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); + } + + i = pb->idx; /* Write index of pb->buf[] */ + if (i < 0) return; /* In write error? */ + nc = pb->nchr; /* Write unit counter */ + +#if FF_USE_LFN && FF_LFN_UNICODE +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ + if (IsSurrogateH(c)) { /* Is this a high-surrogate? */ + pb->hs = c; return; /* Save it for next */ + } + hs = pb->hs; pb->hs = 0; + if (hs != 0) { /* Is there a leading high-surrogate? */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if not a surrogate pair */ + } else { + if (IsSurrogateL(c)) return; /* Discard stray low-surrogate */ + } + wc = c; +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ + for (;;) { + if (pb->ct == 0) { /* Out of multi-byte sequence? */ + pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ + if ((BYTE)c < 0x80) break; /* Single byte code? */ + if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ + if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ + if (((BYTE)c & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ + return; /* Wrong leading byte (discard it) */ + } else { /* In the multi-byte sequence */ + if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ + pb->ct = 0; continue; /* Discard the sequense */ + } + pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ + if (--pb->ct == 0) break; /* End of the sequence? */ + return; + } + } + tp = (const TCHAR*)pb->bs; + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + if (dc == 0xFFFFFFFF) return; /* Wrong code? */ + hs = (WCHAR)(dc >> 16); + wc = (WCHAR)dc; +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ + if (c >= 0x10000) { /* Out of BMP? */ + hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ + wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ + } else { + hs = 0; + wc = (WCHAR)c; + } +#endif + /* A code point in UTF-16 is available in hs and wc */ + +#if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ + if (hs != 0) { /* Surrogate pair? */ + st_word(&pb->buf[i], hs); + i += 2; + nc++; + } + st_word(&pb->buf[i], wc); + i += 2; +#elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ + if (hs != 0) { /* Surrogate pair? */ + pb->buf[i++] = (BYTE)(hs >> 8); + pb->buf[i++] = (BYTE)hs; + nc++; + } + pb->buf[i++] = (BYTE)(wc >> 8); + pb->buf[i++] = (BYTE)wc; +#elif FF_STRF_ENCODE == 3 /* Write a code point in UTF-8 */ + if (hs != 0) { /* 4-byte sequence? */ + nc += 3; + hs = (hs & 0x3FF) + 0x40; + pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); + pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); + pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } else { + if (wc < 0x80) { /* Single byte? */ + pb->buf[i++] = (BYTE)wc; + } else { + if (wc < 0x800) { /* 2-byte sequence? */ + nc += 1; + pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); + } else { /* 3-byte sequence */ + nc += 2; + pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); + pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } + } +#else /* Write a code point in ANSI/OEM */ + if (hs != 0) return; + wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ + if (wc == 0) return; + if (wc >= 0x100) { + pb->buf[i++] = (BYTE)(wc >> 8); nc++; + } + pb->buf[i++] = (BYTE)wc; +#endif + +#else /* ANSI/OEM input (without re-encoding) */ + pb->buf[i++] = (BYTE)c; +#endif + + if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &n); + i = (n == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr = nc + 1; +} + + +/* Flush remaining characters in the buffer */ + +static int putc_flush (putbuff* pb) +{ + UINT nw; + + 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 -1; +} + + +/* Initialize write buffer */ + +static void putc_init (putbuff* pb, FIL* fp) +{ + memset(pb, 0, sizeof (putbuff)); + pb->fp = fp; +} + + + +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + + + putc_init(&pb, fp); + putc_bfd(&pb, c); /* Put the character */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* 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; + + + putc_init(&pb, fp); + while (*str) putc_bfd(&pb, *str++); /* Put the string */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a Formatted String to the File (with sub-functions) */ +/*-----------------------------------------------------------------------*/ +#if FF_PRINT_FLOAT && FF_INTDEF == 2 +#include + +static int ilog10 (double n) /* Calculate log10(n) in integer output */ +{ + int rv = 0; + + while (n >= 10) { /* Decimate digit in right shift */ + if (n >= 100000) { + n /= 100000; rv += 5; + } else { + n /= 10; rv++; + } + } + while (n < 1) { /* Decimate digit in left shift */ + if (n < 0.00001) { + n *= 100000; rv -= 5; + } else { + n *= 10; rv--; + } + } + return rv; +} + + +static double i10x (int n) /* Calculate 10^n in integer input */ +{ + double rv = 1; + + while (n > 0) { /* Left shift */ + if (n >= 5) { + rv *= 100000; n -= 5; + } else { + rv *= 10; n--; + } + } + while (n < 0) { /* Right shift */ + if (n <= -5) { + rv /= 100000; n += 5; + } else { + rv /= 10; n++; + } + } + return rv; +} + + +static void ftoa ( + char* buf, /* Buffer to output the floating point string */ + double val, /* Value to output */ + int prec, /* Number of fractional digits */ + TCHAR fmt /* Notation */ +) +{ + int d; + int e = 0, m = 0; + char sign = 0; + double w; + const char *er = 0; + const char ds = FF_PRINT_FLOAT == 2 ? ',' : '.'; + + + if (isnan(val)) { /* Not a number? */ + er = "NaN"; + } else { + if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ + if (val < 0) { /* Negative? */ + val = 0 - val; sign = '-'; + } else { + sign = '+'; + } + if (isinf(val)) { /* Infinite? */ + er = "INF"; + } else { + if (fmt == 'f') { /* Decimal notation? */ + val += i10x(0 - prec) / 2; /* Round (nearest) */ + m = ilog10(val); + if (m < 0) m = 0; + if (m + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ + } else { /* E notation */ + if (val != 0) { /* Not a true zero? */ + val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */ + e = ilog10(val); + if (e > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ + er = "OV"; + } else { + if (e < -99) e = -99; + val /= i10x(e); /* Normalize */ + } + } + } + } + if (!er) { /* Not error condition */ + if (sign == '-') *buf++ = sign; /* Add a - if negative value */ + do { /* Put decimal number */ + if (m == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ + w = i10x(m); /* Snip the highest digit d */ + d = (int)(val / w); val -= d * w; + *buf++ = (char)('0' + d); /* Put the digit */ + } while (--m >= -prec); /* Output all digits specified by prec */ + if (fmt != 'f') { /* Put exponent if needed */ + *buf++ = (char)fmt; + if (e < 0) { + e = 0 - e; *buf++ = '-'; + } else { + *buf++ = '+'; + } + *buf++ = (char)('0' + e / 10); + *buf++ = (char)('0' + e % 10); + } + } + } + if (er) { /* Error condition */ + if (sign) *buf++ = sign; /* Add sign if needed */ + do { /* Put error symbol */ + *buf++ = *er++; + } while (*er); + } + *buf = 0; /* Term */ +} +#endif /* FF_PRINT_FLOAT && FF_INTDEF == 2 */ + + + +int f_printf ( + FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + putbuff pb; + UINT i, j, w, f, r; + int prec; +#if FF_PRINT_LLI && FF_INTDEF == 2 + QWORD v; +#else + DWORD v; +#endif + TCHAR *tp; + TCHAR tc, pad; + TCHAR nul = 0; + char d, str[SZ_NUM_BUF]; + + + putc_init(&pb, fp); + + va_start(arp, fmt); + + for (;;) { + tc = *fmt++; + if (tc == 0) break; /* End of format string */ + if (tc != '%') { /* Not an escape character (pass-through) */ + putc_bfd(&pb, tc); + continue; + } + f = w = 0; pad = ' '; prec = -1; /* Initialize parms */ + tc = *fmt++; + if (tc == '0') { /* Flag: '0' padded */ + pad = '0'; tc = *fmt++; + } else if (tc == '-') { /* Flag: Left aligned */ + f = 2; tc = *fmt++; + } + if (tc == '*') { /* Minimum width from an argument */ + w = va_arg(arp, int); + tc = *fmt++; + } else { + while (IsDigit(tc)) { /* Minimum width */ + w = w * 10 + tc - '0'; + tc = *fmt++; + } + } + if (tc == '.') { /* Precision */ + tc = *fmt++; + if (tc == '*') { /* Precision from an argument */ + prec = va_arg(arp, int); + tc = *fmt++; + } else { + prec = 0; + while (IsDigit(tc)) { /* Precision */ + prec = prec * 10 + tc - '0'; + tc = *fmt++; + } + } + } + if (tc == 'l') { /* Size: long int */ + f |= 4; tc = *fmt++; +#if FF_PRINT_LLI && FF_INTDEF == 2 + if (tc == 'l') { /* Size: long long int */ + f |= 8; tc = *fmt++; + } +#endif + } + if (tc == 0) break; /* End of format string */ + switch (tc) { /* Atgument type is... */ + case 'b': /* Unsigned binary */ + r = 2; break; + + case 'o': /* Unsigned octal */ + r = 8; break; + + case 'd': /* Signed decimal */ + case 'u': /* Unsigned decimal */ + r = 10; break; + + case 'x': /* Unsigned hexadecimal (lower case) */ + case 'X': /* Unsigned hexadecimal (upper case) */ + r = 16; break; + + case 'c': /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); + continue; + + case 's': /* String */ + tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ + if (!tp) tp = &nul; /* Null ptr generates a null string */ + for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */ + if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */ + for ( ; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ + while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + continue; +#if FF_PRINT_FLOAT && FF_INTDEF == 2 + case 'f': /* Floating point (decimal) */ + case 'e': /* Floating point (e) */ + case 'E': /* Floating point (E) */ + ftoa(str, va_arg(arp, double), prec, tc); /* Make a floating point string */ + for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ + while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + continue; +#endif + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, tc); continue; + } + + /* Get an integer argument and put it in numeral */ +#if FF_PRINT_LLI && FF_INTDEF == 2 + if (f & 8) { /* long long argument? */ + v = (QWORD)va_arg(arp, long long); + } else if (f & 4) { /* long argument? */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); + } + if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ + v = 0 - v; f |= 1; + } +#else + if (f & 4) { /* long argument? */ + v = (DWORD)va_arg(arp, long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); + } + if (tc == 'd' && (v & 0x80000000)) { /* Negative value? */ + v = 0 - v; f |= 1; + } +#endif + i = 0; + do { /* Make an integer number string */ + d = (char)(v % r); v /= r; + if (d > 9) d += (tc == 'x') ? 0x27 : 0x07; + str[i++] = d + '0'; + } while (v && i < SZ_NUM_BUF); + if (f & 1) str[i++] = '-'; /* Sign */ + /* Write it */ + for (j = i; !(f & 2) && j < w; j++) { /* Left pads */ + putc_bfd(&pb, pad); + } + do { /* Body */ + putc_bfd(&pb, (TCHAR)str[--i]); + } while (i); + while (j++ < w) { /* Right pads */ + putc_bfd(&pb, ' '); + } + } + + va_end(arp); + + return putc_flush(&pb); +} + +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_STRFUNC */ + + + +#if FF_CODE_PAGE == 0 +/*-----------------------------------------------------------------------*/ +/* Set Active Codepage for the Path Name */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setcp ( + WORD cp /* Value to be set as active code page */ +) +{ + static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; + static const BYTE *const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + UINT i; + + + for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + + CodePage = cp; + if (cp >= 900) { /* DBCS */ + ExCvt = 0; + DbcTbl = tables[i]; + } else { /* SBCS */ + ExCvt = tables[i]; + DbcTbl = 0; + } + return FR_OK; +} +#endif /* FF_CODE_PAGE == 0 */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.h new file mode 100644 index 0000000..5a62928 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ff.h @@ -0,0 +1,429 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT Filesystem module R0.15 / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2022, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 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 FF_DEFINED +#define FF_DEFINED 80286 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ffconf.h" /* FatFs configuration options */ + +#if FF_DEFINED != FFCONF_DEF +#error Wrong configuration file (ffconf.h). +#endif + + +/* Integer types used for FatFs API */ + +#if defined(_WIN32) /* Windows VC++ (for development only) */ +#define FF_INTDEF 2 +#include +typedef unsigned __int64 QWORD; +#include +#define isnan(v) _isnan(v) +#define isinf(v) (!_finite(v)) + +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ +#define FF_INTDEF 2 +#include +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef uint16_t WORD; /* 16-bit unsigned integer */ +typedef uint32_t DWORD; /* 32-bit unsigned integer */ +typedef uint64_t QWORD; /* 64-bit unsigned integer */ +typedef WORD WCHAR; /* UTF-16 character type */ + +#else /* Earlier than C99 */ +#define FF_INTDEF 1 +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef unsigned short WORD; /* 16-bit unsigned integer */ +typedef unsigned long DWORD; /* 32-bit unsigned integer */ +typedef WORD WCHAR; /* UTF-16 character type */ +#endif + + +/* Type of file size and LBA variables */ + +#if FF_FS_EXFAT +#if FF_INTDEF != 2 +#error exFAT feature wants C99 or later +#endif +typedef QWORD FSIZE_t; +#if FF_LBA64 +typedef QWORD LBA_t; +#else +typedef DWORD LBA_t; +#endif +#else +#if FF_LBA64 +#error exFAT needs to be enabled when enable 64-bit LBA +#endif +typedef DWORD FSIZE_t; +typedef DWORD LBA_t; +#endif + + + +/* Type of path name strings on FatFs API (TCHAR) */ + +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ +typedef char TCHAR; +#define _T(x) u8 ## x +#define _TEXT(x) u8 ## x +#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ +typedef DWORD TCHAR; +#define _T(x) U ## x +#define _TEXT(x) U ## x +#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) +#error Wrong FF_LFN_UNICODE setting +#else /* ANSI/OEM code in SBCS/DBCS */ +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif + + + +/* Definitions of volume management */ + +#if FF_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 mapping table */ +#endif + +#if FF_STR_VOLUME_ID +#ifndef FF_VOLUME_STRS +extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +#endif +#endif + + + +/* Filesystem object structure (FATFS) */ +#include "userDef.h" +typedef struct { + BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE pdrv; /* Volume hosting physical drive */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */ + WORD id; /* Volume mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ +#if FF_MAX_SS != FF_MIN_SS + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if FF_USE_LFN + WCHAR* lfnbuf; /* LFN working buffer */ +#endif +#if FF_FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ +#endif +#if !FF_FS_READONLY + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ +#endif +#if FF_FS_RPATH + DWORD cdir; /* Current directory start cluster (0:root) */ +#if FF_FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ +#endif +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Number of sectors per FAT */ + LBA_t volbase; /* Volume base sector */ + LBA_t fatbase; /* FAT base sector */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ + LBA_t database; /* Data base sector */ +#if FF_FS_EXFAT + LBA_t bitbase; /* Allocation bitmap base sector */ +#endif + LBA_t winsect; /* Current sector appearing in the win[] */ + BYTE win[FF_MAX_SS*MAX_BLK_BUF]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ // change for testing 24/11 +} FATFS; + + + +/* Object ID and allocation information (FFOBJID) */ + +typedef struct { + FATFS* fs; /* Pointer to the hosting volume of this object */ + WORD id; /* Hosting volume's mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if FF_FS_EXFAT + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ +#endif +#if FF_FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} FFOBJID; + + + +/* File object structure (FIL) */ + +typedef struct { + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ + LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ +#if !FF_FS_READONLY + LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ +#endif +#if FF_USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ +#endif +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ +#endif +} FIL; + + + +/* Directory object structure (DIR) */ + +typedef struct { + FFOBJID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + LBA_t sect; /* Current sector (0:Read operation has terminated) */ + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ +#if FF_USE_LFN + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ +#endif +#if FF_USE_FIND + const TCHAR* pat; /* Pointer to the name matching pattern */ +#endif +} DIR; + + + +/* File information structure (FILINFO) */ + +typedef struct { + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if FF_USE_LFN + TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ +#else + TCHAR fname[12 + 1]; /* File name */ +#endif +} FILINFO; + + + +/* Format parameter structure (MKFS_PARM) */ + +typedef struct { + BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ + BYTE n_fat; /* Number of FATs */ + UINT align; /* Data area alignment (sector) */ + UINT n_root; /* Number of root directory entries */ + DWORD au_size; /* Cluster size (byte) */ +} MKFS_PARM; + + + +/* 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 problem */ + 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 > FF_FS_LOCK */ + 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 the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the 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 a file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a 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_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ +FRESULT f_setcp (WORD cp); /* Set current code page */ +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 */ + +/* Some API fucntions are implemented as macro */ + +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) +#define f_error(fp) ((fp)->err) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->obj.objsize) +#define f_rewind(fp) f_lseek((fp), 0) +#define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) +#define f_unmount(path) f_mount(0, path, 0) + + + + +/*--------------------------------------------------------------*/ +/* Additional Functions */ +/*--------------------------------------------------------------*/ + +/* RTC function (provided by user) */ +#if !FF_FS_READONLY && !FF_FS_NORTC +DWORD get_fattime (void); /* Get current time */ +#endif + + +/* LFN support functions (defined in ffunicode.c) */ + +#if FF_USE_LFN >= 1 +WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ +WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ +DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ +#endif + + +/* O/S dependent functions (samples available in ffsystem.c) */ + +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#if FF_FS_REENTRANT /* Sync functions */ +int ff_mutex_create (int vol); /* Create a sync object */ +void ff_mutex_delete (int vol); /* Delete a sync object */ +int ff_mutex_take (int vol); /* Lock sync object */ +void ff_mutex_give (int vol); /* Unlock sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and Offset Address */ +/*--------------------------------------------------------------*/ + +/* File access mode and open method flags (3rd argument of f_open) */ +#define FA_READ 0x01 +#define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA_OPEN_APPEND 0x30 + +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) + +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 + +/* Filesystem type (FATFS.fs_type) */ +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 +#define FS_EXFAT 4 + +/* File attribute bits for directory entry (FILINFO.fattrib) */ +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ + + +#ifdef __cplusplus +} +#endif + +#endif /* FF_DEFINED */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffconf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffconf.h new file mode 100644 index 0000000..1f8d7ec --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffconf.h @@ -0,0 +1,296 @@ +/*---------------------------------------------------------------------------/ +/ Configurations of FatFs Module +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 80286 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* 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 FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ 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 FF_USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 1 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 1 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_STRFUNC 0 +#define FF_PRINT_LLI 1 +#define FF_PRINT_FLOAT 1 +#define FF_STRF_ENCODE 3 +/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. +/ +/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 +/ makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE +/ to be read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 932 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 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 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 0 +#define FF_MAX_LFN 255 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_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. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN +/ specification. +/ 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() exemplified in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_FS_RPATH 2 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table is needed as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ 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 this function is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ function will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and +/ harddisk, but a larger value may be required for on-board flash memory and some +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_LBA64 0 +/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) +/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ + + +#define FF_MIN_GPT 0x10000000 +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and +/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 0 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2022 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_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 the 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. +*/ + + +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +/* The option FF_FS_REENTRANT 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 featuer. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() +/ function, must be added to the project. Samples are available in ffsystem.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ + + + +/*--- End of configuration options ---*/ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffsystem.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffsystem.c new file mode 100644 index 0000000..d5c5134 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffsystem.c @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------*/ +/* A Sample Code of User Provided OS Dependent Functions for FatFs */ +/*------------------------------------------------------------------------*/ + +#include "ff.h" + + +#if FF_USE_LFN == 3 /* Use dynamic memory allocation */ + +/*------------------------------------------------------------------------*/ +/* Allocate/Free a Memory Block */ +/*------------------------------------------------------------------------*/ + +#include /* with POSIX API */ + + +void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ + UINT msize /* Number of bytes to allocate */ +) +{ + return malloc((size_t)msize); /* Allocate a new memory block */ +} + + +void ff_memfree ( + void* mblock /* Pointer to the memory block to free (no effect if null) */ +) +{ + free(mblock); /* Free the memory block */ +} + +#endif + + + + +#if FF_FS_REENTRANT /* Mutal exclusion */ +/*------------------------------------------------------------------------*/ +/* Definitions of Mutex */ +/*------------------------------------------------------------------------*/ + +#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */ + + +#if OS_TYPE == 0 /* Win32 */ +#include +static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ + +#elif OS_TYPE == 1 /* uITRON */ +#include "itron.h" +#include "kernel.h" +static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ + +#elif OS_TYPE == 2 /* uc/OS-II */ +#include "includes.h" +static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */ + +#elif OS_TYPE == 3 /* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" +static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ +#include "cmsis_os.h" +static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ + +#endif + + + +/*------------------------------------------------------------------------*/ +/* Create a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to create a new mutex +/ or semaphore for the volume. When a 0 is returned, the f_mount function +/ fails with FR_INT_ERR. +*/ + +int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + Mutex[vol] = CreateMutex(NULL, FALSE, NULL); + return (int)(Mutex[vol] != INVALID_HANDLE_VALUE); + +#elif OS_TYPE == 1 /* uITRON */ + T_CMTX cmtx = {TA_TPRI,1}; + + Mutex[vol] = acre_mtx(&cmtx); + return (int)(Mutex[vol] > 0); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + Mutex[vol] = OSMutexCreate(0, &err); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + Mutex[vol] = xSemaphoreCreateMutex(); + return (int)(Mutex[vol] != NULL); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDef(cmsis_os_mutex); + + Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex)); + return (int)(Mutex[vol] != NULL); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Delete a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to delete a mutex or +/ semaphore of the volume created with ff_mutex_create function. +*/ + +void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + CloseHandle(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + del_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err); + +#elif OS_TYPE == 3 /* FreeRTOS */ + vSemaphoreDelete(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDelete(Mutex[vol]); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Request a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on enter file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0); + +#elif OS_TYPE == 1 /* uITRON */ + return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err)); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK); + +#endif +} + + + +/*------------------------------------------------------------------------*/ +/* Release a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leave file functions to unlock the volume. +*/ + +void ff_mutex_give ( + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + ReleaseMutex(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + unl_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OSMutexPost(Mutex[vol]); + +#elif OS_TYPE == 3 /* FreeRTOS */ + xSemaphoreGive(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexRelease(Mutex[vol]); + +#endif +} + +#endif /* FF_FS_REENTRANT */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffunicode.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffunicode.c new file mode 100644 index 0000000..e6bcaca --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/ffunicode.c @@ -0,0 +1,15593 @@ +/*------------------------------------------------------------------------*/ +/* Unicode Handling Functions for FatFs R0.13 and Later */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .rodata section when the */ +/* FatFs is configured for LFN with DBCS. If the system has a Unicode */ +/* library for the code conversion, this module should be modified to use */ +/* it to avoid silly memory consumption. */ +/*------------------------------------------------------------------------*/ +/* +/ Copyright (C) 2022, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 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" + +#if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ + +#define MERGE2(a, b) a ## b +#define CVTBL(tbl, cp) MERGE2(tbl, cp) + + +/*------------------------------------------------------------------------*/ +/* Code Conversion Tables */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */ +static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ + 0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180, + 0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6, + 0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE, + 0x03A1, 0x83AF, 0x03A3, 0x83B0, 0x03A4, 0x83B1, 0x03A5, 0x83B2, 0x03A6, 0x83B3, 0x03A7, 0x83B4, 0x03A8, 0x83B5, 0x03A9, 0x83B6, + 0x03B1, 0x83BF, 0x03B2, 0x83C0, 0x03B3, 0x83C1, 0x03B4, 0x83C2, 0x03B5, 0x83C3, 0x03B6, 0x83C4, 0x03B7, 0x83C5, 0x03B8, 0x83C6, + 0x03B9, 0x83C7, 0x03BA, 0x83C8, 0x03BB, 0x83C9, 0x03BC, 0x83CA, 0x03BD, 0x83CB, 0x03BE, 0x83CC, 0x03BF, 0x83CD, 0x03C0, 0x83CE, + 0x03C1, 0x83CF, 0x03C3, 0x83D0, 0x03C4, 0x83D1, 0x03C5, 0x83D2, 0x03C6, 0x83D3, 0x03C7, 0x83D4, 0x03C8, 0x83D5, 0x03C9, 0x83D6, + 0x0401, 0x8446, 0x0410, 0x8440, 0x0411, 0x8441, 0x0412, 0x8442, 0x0413, 0x8443, 0x0414, 0x8444, 0x0415, 0x8445, 0x0416, 0x8447, + 0x0417, 0x8448, 0x0418, 0x8449, 0x0419, 0x844A, 0x041A, 0x844B, 0x041B, 0x844C, 0x041C, 0x844D, 0x041D, 0x844E, 0x041E, 0x844F, + 0x041F, 0x8450, 0x0420, 0x8451, 0x0421, 0x8452, 0x0422, 0x8453, 0x0423, 0x8454, 0x0424, 0x8455, 0x0425, 0x8456, 0x0426, 0x8457, + 0x0427, 0x8458, 0x0428, 0x8459, 0x0429, 0x845A, 0x042A, 0x845B, 0x042B, 0x845C, 0x042C, 0x845D, 0x042D, 0x845E, 0x042E, 0x845F, + 0x042F, 0x8460, 0x0430, 0x8470, 0x0431, 0x8471, 0x0432, 0x8472, 0x0433, 0x8473, 0x0434, 0x8474, 0x0435, 0x8475, 0x0436, 0x8477, + 0x0437, 0x8478, 0x0438, 0x8479, 0x0439, 0x847A, 0x043A, 0x847B, 0x043B, 0x847C, 0x043C, 0x847D, 0x043D, 0x847E, 0x043E, 0x8480, + 0x043F, 0x8481, 0x0440, 0x8482, 0x0441, 0x8483, 0x0442, 0x8484, 0x0443, 0x8485, 0x0444, 0x8486, 0x0445, 0x8487, 0x0446, 0x8488, + 0x0447, 0x8489, 0x0448, 0x848A, 0x0449, 0x848B, 0x044A, 0x848C, 0x044B, 0x848D, 0x044C, 0x848E, 0x044D, 0x848F, 0x044E, 0x8490, + 0x044F, 0x8491, 0x0451, 0x8476, 0x2010, 0x815D, 0x2015, 0x815C, 0x2018, 0x8165, 0x2019, 0x8166, 0x201C, 0x8167, 0x201D, 0x8168, + 0x2020, 0x81F5, 0x2021, 0x81F6, 0x2025, 0x8164, 0x2026, 0x8163, 0x2030, 0x81F1, 0x2032, 0x818C, 0x2033, 0x818D, 0x203B, 0x81A6, + 0x2103, 0x818E, 0x2116, 0x8782, 0x2121, 0x8784, 0x212B, 0x81F0, 0x2160, 0x8754, 0x2161, 0x8755, 0x2162, 0x8756, 0x2163, 0x8757, + 0x2164, 0x8758, 0x2165, 0x8759, 0x2166, 0x875A, 0x2167, 0x875B, 0x2168, 0x875C, 0x2169, 0x875D, 0x2170, 0xFA40, 0x2171, 0xFA41, + 0x2172, 0xFA42, 0x2173, 0xFA43, 0x2174, 0xFA44, 0x2175, 0xFA45, 0x2176, 0xFA46, 0x2177, 0xFA47, 0x2178, 0xFA48, 0x2179, 0xFA49, + 0x2190, 0x81A9, 0x2191, 0x81AA, 0x2192, 0x81A8, 0x2193, 0x81AB, 0x21D2, 0x81CB, 0x21D4, 0x81CC, 0x2200, 0x81CD, 0x2202, 0x81DD, + 0x2203, 0x81CE, 0x2207, 0x81DE, 0x2208, 0x81B8, 0x220B, 0x81B9, 0x2211, 0x8794, 0x221A, 0x81E3, 0x221D, 0x81E5, 0x221E, 0x8187, + 0x221F, 0x8798, 0x2220, 0x81DA, 0x2225, 0x8161, 0x2227, 0x81C8, 0x2228, 0x81C9, 0x2229, 0x81BF, 0x222A, 0x81BE, 0x222B, 0x81E7, + 0x222C, 0x81E8, 0x222E, 0x8793, 0x2234, 0x8188, 0x2235, 0x81E6, 0x223D, 0x81E4, 0x2252, 0x81E0, 0x2260, 0x8182, 0x2261, 0x81DF, + 0x2266, 0x8185, 0x2267, 0x8186, 0x226A, 0x81E1, 0x226B, 0x81E2, 0x2282, 0x81BC, 0x2283, 0x81BD, 0x2286, 0x81BA, 0x2287, 0x81BB, + 0x22A5, 0x81DB, 0x22BF, 0x8799, 0x2312, 0x81DC, 0x2460, 0x8740, 0x2461, 0x8741, 0x2462, 0x8742, 0x2463, 0x8743, 0x2464, 0x8744, + 0x2465, 0x8745, 0x2466, 0x8746, 0x2467, 0x8747, 0x2468, 0x8748, 0x2469, 0x8749, 0x246A, 0x874A, 0x246B, 0x874B, 0x246C, 0x874C, + 0x246D, 0x874D, 0x246E, 0x874E, 0x246F, 0x874F, 0x2470, 0x8750, 0x2471, 0x8751, 0x2472, 0x8752, 0x2473, 0x8753, 0x2500, 0x849F, + 0x2501, 0x84AA, 0x2502, 0x84A0, 0x2503, 0x84AB, 0x250C, 0x84A1, 0x250F, 0x84AC, 0x2510, 0x84A2, 0x2513, 0x84AD, 0x2514, 0x84A4, + 0x2517, 0x84AF, 0x2518, 0x84A3, 0x251B, 0x84AE, 0x251C, 0x84A5, 0x251D, 0x84BA, 0x2520, 0x84B5, 0x2523, 0x84B0, 0x2524, 0x84A7, + 0x2525, 0x84BC, 0x2528, 0x84B7, 0x252B, 0x84B2, 0x252C, 0x84A6, 0x252F, 0x84B6, 0x2530, 0x84BB, 0x2533, 0x84B1, 0x2534, 0x84A8, + 0x2537, 0x84B8, 0x2538, 0x84BD, 0x253B, 0x84B3, 0x253C, 0x84A9, 0x253F, 0x84B9, 0x2542, 0x84BE, 0x254B, 0x84B4, 0x25A0, 0x81A1, + 0x25A1, 0x81A0, 0x25B2, 0x81A3, 0x25B3, 0x81A2, 0x25BC, 0x81A5, 0x25BD, 0x81A4, 0x25C6, 0x819F, 0x25C7, 0x819E, 0x25CB, 0x819B, + 0x25CE, 0x819D, 0x25CF, 0x819C, 0x25EF, 0x81FC, 0x2605, 0x819A, 0x2606, 0x8199, 0x2640, 0x818A, 0x2642, 0x8189, 0x266A, 0x81F4, + 0x266D, 0x81F3, 0x266F, 0x81F2, 0x3000, 0x8140, 0x3001, 0x8141, 0x3002, 0x8142, 0x3003, 0x8156, 0x3005, 0x8158, 0x3006, 0x8159, + 0x3007, 0x815A, 0x3008, 0x8171, 0x3009, 0x8172, 0x300A, 0x8173, 0x300B, 0x8174, 0x300C, 0x8175, 0x300D, 0x8176, 0x300E, 0x8177, + 0x300F, 0x8178, 0x3010, 0x8179, 0x3011, 0x817A, 0x3012, 0x81A7, 0x3013, 0x81AC, 0x3014, 0x816B, 0x3015, 0x816C, 0x301D, 0x8780, + 0x301F, 0x8781, 0x3041, 0x829F, 0x3042, 0x82A0, 0x3043, 0x82A1, 0x3044, 0x82A2, 0x3045, 0x82A3, 0x3046, 0x82A4, 0x3047, 0x82A5, + 0x3048, 0x82A6, 0x3049, 0x82A7, 0x304A, 0x82A8, 0x304B, 0x82A9, 0x304C, 0x82AA, 0x304D, 0x82AB, 0x304E, 0x82AC, 0x304F, 0x82AD, + 0x3050, 0x82AE, 0x3051, 0x82AF, 0x3052, 0x82B0, 0x3053, 0x82B1, 0x3054, 0x82B2, 0x3055, 0x82B3, 0x3056, 0x82B4, 0x3057, 0x82B5, + 0x3058, 0x82B6, 0x3059, 0x82B7, 0x305A, 0x82B8, 0x305B, 0x82B9, 0x305C, 0x82BA, 0x305D, 0x82BB, 0x305E, 0x82BC, 0x305F, 0x82BD, + 0x3060, 0x82BE, 0x3061, 0x82BF, 0x3062, 0x82C0, 0x3063, 0x82C1, 0x3064, 0x82C2, 0x3065, 0x82C3, 0x3066, 0x82C4, 0x3067, 0x82C5, + 0x3068, 0x82C6, 0x3069, 0x82C7, 0x306A, 0x82C8, 0x306B, 0x82C9, 0x306C, 0x82CA, 0x306D, 0x82CB, 0x306E, 0x82CC, 0x306F, 0x82CD, + 0x3070, 0x82CE, 0x3071, 0x82CF, 0x3072, 0x82D0, 0x3073, 0x82D1, 0x3074, 0x82D2, 0x3075, 0x82D3, 0x3076, 0x82D4, 0x3077, 0x82D5, + 0x3078, 0x82D6, 0x3079, 0x82D7, 0x307A, 0x82D8, 0x307B, 0x82D9, 0x307C, 0x82DA, 0x307D, 0x82DB, 0x307E, 0x82DC, 0x307F, 0x82DD, + 0x3080, 0x82DE, 0x3081, 0x82DF, 0x3082, 0x82E0, 0x3083, 0x82E1, 0x3084, 0x82E2, 0x3085, 0x82E3, 0x3086, 0x82E4, 0x3087, 0x82E5, + 0x3088, 0x82E6, 0x3089, 0x82E7, 0x308A, 0x82E8, 0x308B, 0x82E9, 0x308C, 0x82EA, 0x308D, 0x82EB, 0x308E, 0x82EC, 0x308F, 0x82ED, + 0x3090, 0x82EE, 0x3091, 0x82EF, 0x3092, 0x82F0, 0x3093, 0x82F1, 0x309B, 0x814A, 0x309C, 0x814B, 0x309D, 0x8154, 0x309E, 0x8155, + 0x30A1, 0x8340, 0x30A2, 0x8341, 0x30A3, 0x8342, 0x30A4, 0x8343, 0x30A5, 0x8344, 0x30A6, 0x8345, 0x30A7, 0x8346, 0x30A8, 0x8347, + 0x30A9, 0x8348, 0x30AA, 0x8349, 0x30AB, 0x834A, 0x30AC, 0x834B, 0x30AD, 0x834C, 0x30AE, 0x834D, 0x30AF, 0x834E, 0x30B0, 0x834F, + 0x30B1, 0x8350, 0x30B2, 0x8351, 0x30B3, 0x8352, 0x30B4, 0x8353, 0x30B5, 0x8354, 0x30B6, 0x8355, 0x30B7, 0x8356, 0x30B8, 0x8357, + 0x30B9, 0x8358, 0x30BA, 0x8359, 0x30BB, 0x835A, 0x30BC, 0x835B, 0x30BD, 0x835C, 0x30BE, 0x835D, 0x30BF, 0x835E, 0x30C0, 0x835F, + 0x30C1, 0x8360, 0x30C2, 0x8361, 0x30C3, 0x8362, 0x30C4, 0x8363, 0x30C5, 0x8364, 0x30C6, 0x8365, 0x30C7, 0x8366, 0x30C8, 0x8367, + 0x30C9, 0x8368, 0x30CA, 0x8369, 0x30CB, 0x836A, 0x30CC, 0x836B, 0x30CD, 0x836C, 0x30CE, 0x836D, 0x30CF, 0x836E, 0x30D0, 0x836F, + 0x30D1, 0x8370, 0x30D2, 0x8371, 0x30D3, 0x8372, 0x30D4, 0x8373, 0x30D5, 0x8374, 0x30D6, 0x8375, 0x30D7, 0x8376, 0x30D8, 0x8377, + 0x30D9, 0x8378, 0x30DA, 0x8379, 0x30DB, 0x837A, 0x30DC, 0x837B, 0x30DD, 0x837C, 0x30DE, 0x837D, 0x30DF, 0x837E, 0x30E0, 0x8380, + 0x30E1, 0x8381, 0x30E2, 0x8382, 0x30E3, 0x8383, 0x30E4, 0x8384, 0x30E5, 0x8385, 0x30E6, 0x8386, 0x30E7, 0x8387, 0x30E8, 0x8388, + 0x30E9, 0x8389, 0x30EA, 0x838A, 0x30EB, 0x838B, 0x30EC, 0x838C, 0x30ED, 0x838D, 0x30EE, 0x838E, 0x30EF, 0x838F, 0x30F0, 0x8390, + 0x30F1, 0x8391, 0x30F2, 0x8392, 0x30F3, 0x8393, 0x30F4, 0x8394, 0x30F5, 0x8395, 0x30F6, 0x8396, 0x30FB, 0x8145, 0x30FC, 0x815B, + 0x30FD, 0x8152, 0x30FE, 0x8153, 0x3231, 0x878A, 0x3232, 0x878B, 0x3239, 0x878C, 0x32A4, 0x8785, 0x32A5, 0x8786, 0x32A6, 0x8787, + 0x32A7, 0x8788, 0x32A8, 0x8789, 0x3303, 0x8765, 0x330D, 0x8769, 0x3314, 0x8760, 0x3318, 0x8763, 0x3322, 0x8761, 0x3323, 0x876B, + 0x3326, 0x876A, 0x3327, 0x8764, 0x332B, 0x876C, 0x3336, 0x8766, 0x333B, 0x876E, 0x3349, 0x875F, 0x334A, 0x876D, 0x334D, 0x8762, + 0x3351, 0x8767, 0x3357, 0x8768, 0x337B, 0x877E, 0x337C, 0x878F, 0x337D, 0x878E, 0x337E, 0x878D, 0x338E, 0x8772, 0x338F, 0x8773, + 0x339C, 0x876F, 0x339D, 0x8770, 0x339E, 0x8771, 0x33A1, 0x8775, 0x33C4, 0x8774, 0x33CD, 0x8783, 0x4E00, 0x88EA, 0x4E01, 0x929A, + 0x4E03, 0x8EB5, 0x4E07, 0x969C, 0x4E08, 0x8FE4, 0x4E09, 0x8E4F, 0x4E0A, 0x8FE3, 0x4E0B, 0x89BA, 0x4E0D, 0x9573, 0x4E0E, 0x975E, + 0x4E10, 0x98A0, 0x4E11, 0x894E, 0x4E14, 0x8A8E, 0x4E15, 0x98A1, 0x4E16, 0x90A2, 0x4E17, 0x99C0, 0x4E18, 0x8B75, 0x4E19, 0x95B8, + 0x4E1E, 0x8FE5, 0x4E21, 0x97BC, 0x4E26, 0x95C0, 0x4E28, 0xFA68, 0x4E2A, 0x98A2, 0x4E2D, 0x9286, 0x4E31, 0x98A3, 0x4E32, 0x8BF8, + 0x4E36, 0x98A4, 0x4E38, 0x8ADB, 0x4E39, 0x924F, 0x4E3B, 0x8EE5, 0x4E3C, 0x98A5, 0x4E3F, 0x98A6, 0x4E42, 0x98A7, 0x4E43, 0x9454, + 0x4E45, 0x8B76, 0x4E4B, 0x9456, 0x4E4D, 0x93E1, 0x4E4E, 0x8CC1, 0x4E4F, 0x9652, 0x4E55, 0xE568, 0x4E56, 0x98A8, 0x4E57, 0x8FE6, + 0x4E58, 0x98A9, 0x4E59, 0x89B3, 0x4E5D, 0x8BE3, 0x4E5E, 0x8CEE, 0x4E5F, 0x96E7, 0x4E62, 0x9BA4, 0x4E71, 0x9790, 0x4E73, 0x93FB, + 0x4E7E, 0x8AA3, 0x4E80, 0x8B54, 0x4E82, 0x98AA, 0x4E85, 0x98AB, 0x4E86, 0x97B9, 0x4E88, 0x975C, 0x4E89, 0x9188, 0x4E8A, 0x98AD, + 0x4E8B, 0x8E96, 0x4E8C, 0x93F1, 0x4E8E, 0x98B0, 0x4E91, 0x895D, 0x4E92, 0x8CDD, 0x4E94, 0x8CDC, 0x4E95, 0x88E4, 0x4E98, 0x986A, + 0x4E99, 0x9869, 0x4E9B, 0x8DB1, 0x4E9C, 0x889F, 0x4E9E, 0x98B1, 0x4E9F, 0x98B2, 0x4EA0, 0x98B3, 0x4EA1, 0x9653, 0x4EA2, 0x98B4, + 0x4EA4, 0x8CF0, 0x4EA5, 0x88E5, 0x4EA6, 0x9692, 0x4EA8, 0x8B9C, 0x4EAB, 0x8B9D, 0x4EAC, 0x8B9E, 0x4EAD, 0x92E0, 0x4EAE, 0x97BA, + 0x4EB0, 0x98B5, 0x4EB3, 0x98B6, 0x4EB6, 0x98B7, 0x4EBA, 0x906C, 0x4EC0, 0x8F59, 0x4EC1, 0x906D, 0x4EC2, 0x98BC, 0x4EC4, 0x98BA, + 0x4EC6, 0x98BB, 0x4EC7, 0x8B77, 0x4ECA, 0x8DA1, 0x4ECB, 0x89EE, 0x4ECD, 0x98B9, 0x4ECE, 0x98B8, 0x4ECF, 0x95A7, 0x4ED4, 0x8E65, + 0x4ED5, 0x8E64, 0x4ED6, 0x91BC, 0x4ED7, 0x98BD, 0x4ED8, 0x9574, 0x4ED9, 0x90E5, 0x4EDD, 0x8157, 0x4EDE, 0x98BE, 0x4EDF, 0x98C0, + 0x4EE1, 0xFA69, 0x4EE3, 0x91E3, 0x4EE4, 0x97DF, 0x4EE5, 0x88C8, 0x4EED, 0x98BF, 0x4EEE, 0x89BC, 0x4EF0, 0x8BC2, 0x4EF2, 0x9287, + 0x4EF6, 0x8C8F, 0x4EF7, 0x98C1, 0x4EFB, 0x9443, 0x4EFC, 0xFA6A, 0x4F00, 0xFA6B, 0x4F01, 0x8AE9, 0x4F03, 0xFA6C, 0x4F09, 0x98C2, + 0x4F0A, 0x88C9, 0x4F0D, 0x8CDE, 0x4F0E, 0x8AEA, 0x4F0F, 0x959A, 0x4F10, 0x94B0, 0x4F11, 0x8B78, 0x4F1A, 0x89EF, 0x4F1C, 0x98E5, + 0x4F1D, 0x9360, 0x4F2F, 0x948C, 0x4F30, 0x98C4, 0x4F34, 0x94BA, 0x4F36, 0x97E0, 0x4F38, 0x904C, 0x4F39, 0xFA6D, 0x4F3A, 0x8E66, + 0x4F3C, 0x8E97, 0x4F3D, 0x89BE, 0x4F43, 0x92CF, 0x4F46, 0x9241, 0x4F47, 0x98C8, 0x4F4D, 0x88CA, 0x4F4E, 0x92E1, 0x4F4F, 0x8F5A, + 0x4F50, 0x8DB2, 0x4F51, 0x9743, 0x4F53, 0x91CC, 0x4F55, 0x89BD, 0x4F56, 0xFA6E, 0x4F57, 0x98C7, 0x4F59, 0x975D, 0x4F5A, 0x98C3, + 0x4F5B, 0x98C5, 0x4F5C, 0x8DEC, 0x4F5D, 0x98C6, 0x4F5E, 0x9B43, 0x4F69, 0x98CE, 0x4F6F, 0x98D1, 0x4F70, 0x98CF, 0x4F73, 0x89C0, + 0x4F75, 0x95B9, 0x4F76, 0x98C9, 0x4F7B, 0x98CD, 0x4F7C, 0x8CF1, 0x4F7F, 0x8E67, 0x4F83, 0x8AA4, 0x4F86, 0x98D2, 0x4F88, 0x98CA, + 0x4F8A, 0xFA70, 0x4F8B, 0x97E1, 0x4F8D, 0x8E98, 0x4F8F, 0x98CB, 0x4F91, 0x98D0, 0x4F92, 0xFA6F, 0x4F94, 0xFA72, 0x4F96, 0x98D3, + 0x4F98, 0x98CC, 0x4F9A, 0xFA71, 0x4F9B, 0x8B9F, 0x4F9D, 0x88CB, 0x4FA0, 0x8BA0, 0x4FA1, 0x89BF, 0x4FAB, 0x9B44, 0x4FAD, 0x9699, + 0x4FAE, 0x958E, 0x4FAF, 0x8CF2, 0x4FB5, 0x904E, 0x4FB6, 0x97B5, 0x4FBF, 0x95D6, 0x4FC2, 0x8C57, 0x4FC3, 0x91A3, 0x4FC4, 0x89E2, + 0x4FC9, 0xFA61, 0x4FCA, 0x8F72, 0x4FCD, 0xFA73, 0x4FCE, 0x98D7, 0x4FD0, 0x98DC, 0x4FD1, 0x98DA, 0x4FD4, 0x98D5, 0x4FD7, 0x91AD, + 0x4FD8, 0x98D8, 0x4FDA, 0x98DB, 0x4FDB, 0x98D9, 0x4FDD, 0x95DB, 0x4FDF, 0x98D6, 0x4FE1, 0x904D, 0x4FE3, 0x9693, 0x4FE4, 0x98DD, + 0x4FE5, 0x98DE, 0x4FEE, 0x8F43, 0x4FEF, 0x98EB, 0x4FF3, 0x946F, 0x4FF5, 0x9555, 0x4FF6, 0x98E6, 0x4FF8, 0x95EE, 0x4FFA, 0x89B4, + 0x4FFE, 0x98EA, 0x4FFF, 0xFA76, 0x5005, 0x98E4, 0x5006, 0x98ED, 0x5009, 0x9171, 0x500B, 0x8CC2, 0x500D, 0x947B, 0x500F, 0xE0C5, + 0x5011, 0x98EC, 0x5012, 0x937C, 0x5014, 0x98E1, 0x5016, 0x8CF4, 0x5019, 0x8CF3, 0x501A, 0x98DF, 0x501E, 0xFA77, 0x501F, 0x8ED8, + 0x5021, 0x98E7, 0x5022, 0xFA75, 0x5023, 0x95ED, 0x5024, 0x926C, 0x5025, 0x98E3, 0x5026, 0x8C91, 0x5028, 0x98E0, 0x5029, 0x98E8, + 0x502A, 0x98E2, 0x502B, 0x97CF, 0x502C, 0x98E9, 0x502D, 0x9860, 0x5036, 0x8BE4, 0x5039, 0x8C90, 0x5040, 0xFA74, 0x5042, 0xFA7A, + 0x5043, 0x98EE, 0x5046, 0xFA78, 0x5047, 0x98EF, 0x5048, 0x98F3, 0x5049, 0x88CC, 0x504F, 0x95CE, 0x5050, 0x98F2, 0x5055, 0x98F1, + 0x5056, 0x98F5, 0x505A, 0x98F4, 0x505C, 0x92E2, 0x5065, 0x8C92, 0x506C, 0x98F6, 0x5070, 0xFA79, 0x5072, 0x8EC3, 0x5074, 0x91A4, + 0x5075, 0x92E3, 0x5076, 0x8BF4, 0x5078, 0x98F7, 0x507D, 0x8B55, 0x5080, 0x98F8, 0x5085, 0x98FA, 0x508D, 0x9654, 0x5091, 0x8C86, + 0x5094, 0xFA7B, 0x5098, 0x8E50, 0x5099, 0x94F5, 0x509A, 0x98F9, 0x50AC, 0x8DC3, 0x50AD, 0x9762, 0x50B2, 0x98FC, 0x50B3, 0x9942, + 0x50B4, 0x98FB, 0x50B5, 0x8DC2, 0x50B7, 0x8F9D, 0x50BE, 0x8C58, 0x50C2, 0x9943, 0x50C5, 0x8BCD, 0x50C9, 0x9940, 0x50CA, 0x9941, + 0x50CD, 0x93AD, 0x50CF, 0x919C, 0x50D1, 0x8BA1, 0x50D5, 0x966C, 0x50D6, 0x9944, 0x50D8, 0xFA7D, 0x50DA, 0x97BB, 0x50DE, 0x9945, + 0x50E3, 0x9948, 0x50E5, 0x9946, 0x50E7, 0x916D, 0x50ED, 0x9947, 0x50EE, 0x9949, 0x50F4, 0xFA7C, 0x50F5, 0x994B, 0x50F9, 0x994A, + 0x50FB, 0x95C6, 0x5100, 0x8B56, 0x5101, 0x994D, 0x5102, 0x994E, 0x5104, 0x89AD, 0x5109, 0x994C, 0x5112, 0x8EF2, 0x5114, 0x9951, + 0x5115, 0x9950, 0x5116, 0x994F, 0x5118, 0x98D4, 0x511A, 0x9952, 0x511F, 0x8F9E, 0x5121, 0x9953, 0x512A, 0x9744, 0x5132, 0x96D7, + 0x5137, 0x9955, 0x513A, 0x9954, 0x513B, 0x9957, 0x513C, 0x9956, 0x513F, 0x9958, 0x5140, 0x9959, 0x5141, 0x88F2, 0x5143, 0x8CB3, + 0x5144, 0x8C5A, 0x5145, 0x8F5B, 0x5146, 0x929B, 0x5147, 0x8BA2, 0x5148, 0x90E6, 0x5149, 0x8CF5, 0x514A, 0xFA7E, 0x514B, 0x8D8E, + 0x514C, 0x995B, 0x514D, 0x96C6, 0x514E, 0x9365, 0x5150, 0x8E99, 0x5152, 0x995A, 0x5154, 0x995C, 0x515A, 0x937D, 0x515C, 0x8A95, + 0x5162, 0x995D, 0x5164, 0xFA80, 0x5165, 0x93FC, 0x5168, 0x9153, 0x5169, 0x995F, 0x516A, 0x9960, 0x516B, 0x94AA, 0x516C, 0x8CF6, + 0x516D, 0x985A, 0x516E, 0x9961, 0x5171, 0x8BA4, 0x5175, 0x95BA, 0x5176, 0x91B4, 0x5177, 0x8BEF, 0x5178, 0x9354, 0x517C, 0x8C93, + 0x5180, 0x9962, 0x5182, 0x9963, 0x5185, 0x93E0, 0x5186, 0x897E, 0x5189, 0x9966, 0x518A, 0x8DFB, 0x518C, 0x9965, 0x518D, 0x8DC4, + 0x518F, 0x9967, 0x5190, 0xE3EC, 0x5191, 0x9968, 0x5192, 0x9660, 0x5193, 0x9969, 0x5195, 0x996A, 0x5196, 0x996B, 0x5197, 0x8FE7, + 0x5199, 0x8ECA, 0x519D, 0xFA81, 0x51A0, 0x8AA5, 0x51A2, 0x996E, 0x51A4, 0x996C, 0x51A5, 0x96BB, 0x51A6, 0x996D, 0x51A8, 0x9579, + 0x51A9, 0x996F, 0x51AA, 0x9970, 0x51AB, 0x9971, 0x51AC, 0x937E, 0x51B0, 0x9975, 0x51B1, 0x9973, 0x51B2, 0x9974, 0x51B3, 0x9972, + 0x51B4, 0x8DE1, 0x51B5, 0x9976, 0x51B6, 0x96E8, 0x51B7, 0x97E2, 0x51BD, 0x9977, 0x51BE, 0xFA82, 0x51C4, 0x90A6, 0x51C5, 0x9978, + 0x51C6, 0x8F79, 0x51C9, 0x9979, 0x51CB, 0x929C, 0x51CC, 0x97BD, 0x51CD, 0x9380, 0x51D6, 0x99C3, 0x51DB, 0x997A, 0x51DC, 0xEAA3, + 0x51DD, 0x8BC3, 0x51E0, 0x997B, 0x51E1, 0x967D, 0x51E6, 0x8F88, 0x51E7, 0x91FA, 0x51E9, 0x997D, 0x51EA, 0x93E2, 0x51EC, 0xFA83, + 0x51ED, 0x997E, 0x51F0, 0x9980, 0x51F1, 0x8A4D, 0x51F5, 0x9981, 0x51F6, 0x8BA5, 0x51F8, 0x93CA, 0x51F9, 0x899A, 0x51FA, 0x8F6F, + 0x51FD, 0x949F, 0x51FE, 0x9982, 0x5200, 0x9381, 0x5203, 0x906E, 0x5204, 0x9983, 0x5206, 0x95AA, 0x5207, 0x90D8, 0x5208, 0x8AA0, + 0x520A, 0x8AA7, 0x520B, 0x9984, 0x520E, 0x9986, 0x5211, 0x8C59, 0x5214, 0x9985, 0x5215, 0xFA84, 0x5217, 0x97F1, 0x521D, 0x8F89, + 0x5224, 0x94BB, 0x5225, 0x95CA, 0x5227, 0x9987, 0x5229, 0x9798, 0x522A, 0x9988, 0x522E, 0x9989, 0x5230, 0x939E, 0x5233, 0x998A, + 0x5236, 0x90A7, 0x5237, 0x8DFC, 0x5238, 0x8C94, 0x5239, 0x998B, 0x523A, 0x8E68, 0x523B, 0x8D8F, 0x5243, 0x92E4, 0x5244, 0x998D, + 0x5247, 0x91A5, 0x524A, 0x8DED, 0x524B, 0x998E, 0x524C, 0x998F, 0x524D, 0x914F, 0x524F, 0x998C, 0x5254, 0x9991, 0x5256, 0x9655, + 0x525B, 0x8D84, 0x525E, 0x9990, 0x5263, 0x8C95, 0x5264, 0x8DDC, 0x5265, 0x948D, 0x5269, 0x9994, 0x526A, 0x9992, 0x526F, 0x959B, + 0x5270, 0x8FE8, 0x5271, 0x999B, 0x5272, 0x8A84, 0x5273, 0x9995, 0x5274, 0x9993, 0x5275, 0x916E, 0x527D, 0x9997, 0x527F, 0x9996, + 0x5283, 0x8A63, 0x5287, 0x8C80, 0x5288, 0x999C, 0x5289, 0x97AB, 0x528D, 0x9998, 0x5291, 0x999D, 0x5292, 0x999A, 0x5294, 0x9999, + 0x529B, 0x97CD, 0x529C, 0xFA85, 0x529F, 0x8CF7, 0x52A0, 0x89C1, 0x52A3, 0x97F2, 0x52A6, 0xFA86, 0x52A9, 0x8F95, 0x52AA, 0x9377, + 0x52AB, 0x8D85, 0x52AC, 0x99A0, 0x52AD, 0x99A1, 0x52AF, 0xFB77, 0x52B1, 0x97E3, 0x52B4, 0x984A, 0x52B5, 0x99A3, 0x52B9, 0x8CF8, + 0x52BC, 0x99A2, 0x52BE, 0x8A4E, 0x52C0, 0xFA87, 0x52C1, 0x99A4, 0x52C3, 0x9675, 0x52C5, 0x92BA, 0x52C7, 0x9745, 0x52C9, 0x95D7, + 0x52CD, 0x99A5, 0x52D2, 0xE8D3, 0x52D5, 0x93AE, 0x52D7, 0x99A6, 0x52D8, 0x8AA8, 0x52D9, 0x96B1, 0x52DB, 0xFA88, 0x52DD, 0x8F9F, + 0x52DE, 0x99A7, 0x52DF, 0x95E5, 0x52E0, 0x99AB, 0x52E2, 0x90A8, 0x52E3, 0x99A8, 0x52E4, 0x8BCE, 0x52E6, 0x99A9, 0x52E7, 0x8AA9, + 0x52F2, 0x8C4D, 0x52F3, 0x99AC, 0x52F5, 0x99AD, 0x52F8, 0x99AE, 0x52F9, 0x99AF, 0x52FA, 0x8ED9, 0x52FE, 0x8CF9, 0x52FF, 0x96DC, + 0x5300, 0xFA89, 0x5301, 0x96E6, 0x5302, 0x93F5, 0x5305, 0x95EF, 0x5306, 0x99B0, 0x5307, 0xFA8A, 0x5308, 0x99B1, 0x530D, 0x99B3, + 0x530F, 0x99B5, 0x5310, 0x99B4, 0x5315, 0x99B6, 0x5316, 0x89BB, 0x5317, 0x966B, 0x5319, 0x8DFA, 0x531A, 0x99B7, 0x531D, 0x9178, + 0x5320, 0x8FA0, 0x5321, 0x8BA7, 0x5323, 0x99B8, 0x5324, 0xFA8B, 0x532A, 0x94D9, 0x532F, 0x99B9, 0x5331, 0x99BA, 0x5333, 0x99BB, + 0x5338, 0x99BC, 0x5339, 0x9543, 0x533A, 0x8BE6, 0x533B, 0x88E3, 0x533F, 0x93BD, 0x5340, 0x99BD, 0x5341, 0x8F5C, 0x5343, 0x90E7, + 0x5345, 0x99BF, 0x5346, 0x99BE, 0x5347, 0x8FA1, 0x5348, 0x8CDF, 0x5349, 0x99C1, 0x534A, 0x94BC, 0x534D, 0x99C2, 0x5351, 0x94DA, + 0x5352, 0x91B2, 0x5353, 0x91EC, 0x5354, 0x8BA6, 0x5357, 0x93EC, 0x5358, 0x9250, 0x535A, 0x948E, 0x535C, 0x966D, 0x535E, 0x99C4, + 0x5360, 0x90E8, 0x5366, 0x8C54, 0x5369, 0x99C5, 0x536E, 0x99C6, 0x536F, 0x894B, 0x5370, 0x88F3, 0x5371, 0x8AEB, 0x5372, 0xFA8C, + 0x5373, 0x91A6, 0x5374, 0x8B70, 0x5375, 0x9791, 0x5377, 0x99C9, 0x5378, 0x89B5, 0x537B, 0x99C8, 0x537F, 0x8BA8, 0x5382, 0x99CA, + 0x5384, 0x96EF, 0x5393, 0xFA8D, 0x5396, 0x99CB, 0x5398, 0x97D0, 0x539A, 0x8CFA, 0x539F, 0x8CB4, 0x53A0, 0x99CC, 0x53A5, 0x99CE, + 0x53A6, 0x99CD, 0x53A8, 0x907E, 0x53A9, 0x8958, 0x53AD, 0x897D, 0x53AE, 0x99CF, 0x53B0, 0x99D0, 0x53B2, 0xFA8E, 0x53B3, 0x8CB5, + 0x53B6, 0x99D1, 0x53BB, 0x8B8E, 0x53C2, 0x8E51, 0x53C3, 0x99D2, 0x53C8, 0x9694, 0x53C9, 0x8DB3, 0x53CA, 0x8B79, 0x53CB, 0x9746, + 0x53CC, 0x916F, 0x53CD, 0x94BD, 0x53CE, 0x8EFB, 0x53D4, 0x8F66, 0x53D6, 0x8EE6, 0x53D7, 0x8EF3, 0x53D9, 0x8F96, 0x53DB, 0x94BE, + 0x53DD, 0xFA8F, 0x53DF, 0x99D5, 0x53E1, 0x8962, 0x53E2, 0x9170, 0x53E3, 0x8CFB, 0x53E4, 0x8CC3, 0x53E5, 0x8BE5, 0x53E8, 0x99D9, + 0x53E9, 0x9240, 0x53EA, 0x91FC, 0x53EB, 0x8BA9, 0x53EC, 0x8FA2, 0x53ED, 0x99DA, 0x53EE, 0x99D8, 0x53EF, 0x89C2, 0x53F0, 0x91E4, + 0x53F1, 0x8EB6, 0x53F2, 0x8E6A, 0x53F3, 0x8945, 0x53F6, 0x8A90, 0x53F7, 0x8D86, 0x53F8, 0x8E69, 0x53FA, 0x99DB, 0x5401, 0x99DC, + 0x5403, 0x8B68, 0x5404, 0x8A65, 0x5408, 0x8D87, 0x5409, 0x8B67, 0x540A, 0x92DD, 0x540B, 0x8944, 0x540C, 0x93AF, 0x540D, 0x96BC, + 0x540E, 0x8D40, 0x540F, 0x9799, 0x5410, 0x9366, 0x5411, 0x8CFC, 0x541B, 0x8C4E, 0x541D, 0x99E5, 0x541F, 0x8BE1, 0x5420, 0x9669, + 0x5426, 0x94DB, 0x5429, 0x99E4, 0x542B, 0x8ADC, 0x542C, 0x99DF, 0x542D, 0x99E0, 0x542E, 0x99E2, 0x5436, 0x99E3, 0x5438, 0x8B7A, + 0x5439, 0x9081, 0x543B, 0x95AB, 0x543C, 0x99E1, 0x543D, 0x99DD, 0x543E, 0x8CE1, 0x5440, 0x99DE, 0x5442, 0x9843, 0x5446, 0x95F0, + 0x5448, 0x92E6, 0x5449, 0x8CE0, 0x544A, 0x8D90, 0x544E, 0x99E6, 0x5451, 0x93DB, 0x545F, 0x99EA, 0x5468, 0x8EFC, 0x546A, 0x8EF4, + 0x5470, 0x99ED, 0x5471, 0x99EB, 0x5473, 0x96A1, 0x5475, 0x99E8, 0x5476, 0x99F1, 0x5477, 0x99EC, 0x547B, 0x99EF, 0x547C, 0x8CC4, + 0x547D, 0x96BD, 0x5480, 0x99F0, 0x5484, 0x99F2, 0x5486, 0x99F4, 0x548A, 0xFA92, 0x548B, 0x8DEE, 0x548C, 0x9861, 0x548E, 0x99E9, + 0x548F, 0x99E7, 0x5490, 0x99F3, 0x5492, 0x99EE, 0x549C, 0xFA91, 0x54A2, 0x99F6, 0x54A4, 0x9A42, 0x54A5, 0x99F8, 0x54A8, 0x99FC, + 0x54A9, 0xFA93, 0x54AB, 0x9A40, 0x54AC, 0x99F9, 0x54AF, 0x9A5D, 0x54B2, 0x8DE7, 0x54B3, 0x8A50, 0x54B8, 0x99F7, 0x54BC, 0x9A44, + 0x54BD, 0x88F4, 0x54BE, 0x9A43, 0x54C0, 0x88A3, 0x54C1, 0x9569, 0x54C2, 0x9A41, 0x54C4, 0x99FA, 0x54C7, 0x99F5, 0x54C8, 0x99FB, + 0x54C9, 0x8DC6, 0x54D8, 0x9A45, 0x54E1, 0x88F5, 0x54E2, 0x9A4E, 0x54E5, 0x9A46, 0x54E6, 0x9A47, 0x54E8, 0x8FA3, 0x54E9, 0x9689, + 0x54ED, 0x9A4C, 0x54EE, 0x9A4B, 0x54F2, 0x934E, 0x54FA, 0x9A4D, 0x54FD, 0x9A4A, 0x54FF, 0xFA94, 0x5504, 0x8953, 0x5506, 0x8DB4, + 0x5507, 0x904F, 0x550F, 0x9A48, 0x5510, 0x9382, 0x5514, 0x9A49, 0x5516, 0x88A0, 0x552E, 0x9A53, 0x552F, 0x9742, 0x5531, 0x8FA5, + 0x5533, 0x9A59, 0x5538, 0x9A58, 0x5539, 0x9A4F, 0x553E, 0x91C1, 0x5540, 0x9A50, 0x5544, 0x91ED, 0x5545, 0x9A55, 0x5546, 0x8FA4, + 0x554C, 0x9A52, 0x554F, 0x96E2, 0x5553, 0x8C5B, 0x5556, 0x9A56, 0x5557, 0x9A57, 0x555C, 0x9A54, 0x555D, 0x9A5A, 0x5563, 0x9A51, + 0x557B, 0x9A60, 0x557C, 0x9A65, 0x557E, 0x9A61, 0x5580, 0x9A5C, 0x5583, 0x9A66, 0x5584, 0x9150, 0x5586, 0xFA95, 0x5587, 0x9A68, + 0x5589, 0x8D41, 0x558A, 0x9A5E, 0x558B, 0x929D, 0x5598, 0x9A62, 0x5599, 0x9A5B, 0x559A, 0x8AAB, 0x559C, 0x8AEC, 0x559D, 0x8A85, + 0x559E, 0x9A63, 0x559F, 0x9A5F, 0x55A7, 0x8C96, 0x55A8, 0x9A69, 0x55A9, 0x9A67, 0x55AA, 0x9172, 0x55AB, 0x8B69, 0x55AC, 0x8BAA, + 0x55AE, 0x9A64, 0x55B0, 0x8BF2, 0x55B6, 0x8963, 0x55C4, 0x9A6D, 0x55C5, 0x9A6B, 0x55C7, 0x9AA5, 0x55D4, 0x9A70, 0x55DA, 0x9A6A, + 0x55DC, 0x9A6E, 0x55DF, 0x9A6C, 0x55E3, 0x8E6B, 0x55E4, 0x9A6F, 0x55F7, 0x9A72, 0x55F9, 0x9A77, 0x55FD, 0x9A75, 0x55FE, 0x9A74, + 0x5606, 0x9251, 0x5609, 0x89C3, 0x5614, 0x9A71, 0x5616, 0x9A73, 0x5617, 0x8FA6, 0x5618, 0x8952, 0x561B, 0x9A76, 0x5629, 0x89DC, + 0x562F, 0x9A82, 0x5631, 0x8FFA, 0x5632, 0x9A7D, 0x5634, 0x9A7B, 0x5636, 0x9A7C, 0x5638, 0x9A7E, 0x5642, 0x895C, 0x564C, 0x9158, + 0x564E, 0x9A78, 0x5650, 0x9A79, 0x565B, 0x8A9A, 0x5664, 0x9A81, 0x5668, 0x8AED, 0x566A, 0x9A84, 0x566B, 0x9A80, 0x566C, 0x9A83, + 0x5674, 0x95AC, 0x5678, 0x93D3, 0x567A, 0x94B6, 0x5680, 0x9A86, 0x5686, 0x9A85, 0x5687, 0x8A64, 0x568A, 0x9A87, 0x568F, 0x9A8A, + 0x5694, 0x9A89, 0x56A0, 0x9A88, 0x56A2, 0x9458, 0x56A5, 0x9A8B, 0x56AE, 0x9A8C, 0x56B4, 0x9A8E, 0x56B6, 0x9A8D, 0x56BC, 0x9A90, + 0x56C0, 0x9A93, 0x56C1, 0x9A91, 0x56C2, 0x9A8F, 0x56C3, 0x9A92, 0x56C8, 0x9A94, 0x56CE, 0x9A95, 0x56D1, 0x9A96, 0x56D3, 0x9A97, + 0x56D7, 0x9A98, 0x56D8, 0x9964, 0x56DA, 0x8EFA, 0x56DB, 0x8E6C, 0x56DE, 0x89F1, 0x56E0, 0x88F6, 0x56E3, 0x9263, 0x56EE, 0x9A99, + 0x56F0, 0x8DA2, 0x56F2, 0x88CD, 0x56F3, 0x907D, 0x56F9, 0x9A9A, 0x56FA, 0x8CC5, 0x56FD, 0x8D91, 0x56FF, 0x9A9C, 0x5700, 0x9A9B, + 0x5703, 0x95DE, 0x5704, 0x9A9D, 0x5708, 0x9A9F, 0x5709, 0x9A9E, 0x570B, 0x9AA0, 0x570D, 0x9AA1, 0x570F, 0x8C97, 0x5712, 0x8980, + 0x5713, 0x9AA2, 0x5716, 0x9AA4, 0x5718, 0x9AA3, 0x571C, 0x9AA6, 0x571F, 0x9379, 0x5726, 0x9AA7, 0x5727, 0x88B3, 0x5728, 0x8DDD, + 0x572D, 0x8C5C, 0x5730, 0x926E, 0x5737, 0x9AA8, 0x5738, 0x9AA9, 0x573B, 0x9AAB, 0x5740, 0x9AAC, 0x5742, 0x8DE2, 0x5747, 0x8BCF, + 0x574A, 0x9656, 0x574E, 0x9AAA, 0x574F, 0x9AAD, 0x5750, 0x8DBF, 0x5751, 0x8D42, 0x5759, 0xFA96, 0x5761, 0x9AB1, 0x5764, 0x8DA3, + 0x5765, 0xFA97, 0x5766, 0x9252, 0x5769, 0x9AAE, 0x576A, 0x92D8, 0x577F, 0x9AB2, 0x5782, 0x9082, 0x5788, 0x9AB0, 0x5789, 0x9AB3, + 0x578B, 0x8C5E, 0x5793, 0x9AB4, 0x57A0, 0x9AB5, 0x57A2, 0x8D43, 0x57A3, 0x8A5F, 0x57A4, 0x9AB7, 0x57AA, 0x9AB8, 0x57AC, 0xFA98, + 0x57B0, 0x9AB9, 0x57B3, 0x9AB6, 0x57C0, 0x9AAF, 0x57C3, 0x9ABA, 0x57C6, 0x9ABB, 0x57C7, 0xFA9A, 0x57C8, 0xFA99, 0x57CB, 0x9684, + 0x57CE, 0x8FE9, 0x57D2, 0x9ABD, 0x57D3, 0x9ABE, 0x57D4, 0x9ABC, 0x57D6, 0x9AC0, 0x57DC, 0x9457, 0x57DF, 0x88E6, 0x57E0, 0x9575, + 0x57E3, 0x9AC1, 0x57F4, 0x8FFB, 0x57F7, 0x8EB7, 0x57F9, 0x947C, 0x57FA, 0x8AEE, 0x57FC, 0x8DE9, 0x5800, 0x9678, 0x5802, 0x93B0, + 0x5805, 0x8C98, 0x5806, 0x91CD, 0x580A, 0x9ABF, 0x580B, 0x9AC2, 0x5815, 0x91C2, 0x5819, 0x9AC3, 0x581D, 0x9AC4, 0x5821, 0x9AC6, + 0x5824, 0x92E7, 0x582A, 0x8AAC, 0x582F, 0xEA9F, 0x5830, 0x8981, 0x5831, 0x95F1, 0x5834, 0x8FEA, 0x5835, 0x9367, 0x583A, 0x8DE4, + 0x583D, 0x9ACC, 0x5840, 0x95BB, 0x5841, 0x97DB, 0x584A, 0x89F2, 0x584B, 0x9AC8, 0x5851, 0x9159, 0x5852, 0x9ACB, 0x5854, 0x9383, + 0x5857, 0x9368, 0x5858, 0x9384, 0x5859, 0x94B7, 0x585A, 0x92CB, 0x585E, 0x8DC7, 0x5862, 0x9AC7, 0x5869, 0x8996, 0x586B, 0x9355, + 0x5870, 0x9AC9, 0x5872, 0x9AC5, 0x5875, 0x906F, 0x5879, 0x9ACD, 0x587E, 0x8F6D, 0x5883, 0x8BAB, 0x5885, 0x9ACE, 0x5893, 0x95E6, + 0x5897, 0x919D, 0x589C, 0x92C4, 0x589E, 0xFA9D, 0x589F, 0x9AD0, 0x58A8, 0x966E, 0x58AB, 0x9AD1, 0x58AE, 0x9AD6, 0x58B2, 0xFA9E, + 0x58B3, 0x95AD, 0x58B8, 0x9AD5, 0x58B9, 0x9ACF, 0x58BA, 0x9AD2, 0x58BB, 0x9AD4, 0x58BE, 0x8DA4, 0x58C1, 0x95C7, 0x58C5, 0x9AD7, + 0x58C7, 0x9264, 0x58CA, 0x89F3, 0x58CC, 0x8FEB, 0x58D1, 0x9AD9, 0x58D3, 0x9AD8, 0x58D5, 0x8D88, 0x58D7, 0x9ADA, 0x58D8, 0x9ADC, + 0x58D9, 0x9ADB, 0x58DC, 0x9ADE, 0x58DE, 0x9AD3, 0x58DF, 0x9AE0, 0x58E4, 0x9ADF, 0x58E5, 0x9ADD, 0x58EB, 0x8E6D, 0x58EC, 0x9070, + 0x58EE, 0x9173, 0x58EF, 0x9AE1, 0x58F0, 0x90BA, 0x58F1, 0x88EB, 0x58F2, 0x9484, 0x58F7, 0x92D9, 0x58F9, 0x9AE3, 0x58FA, 0x9AE2, + 0x58FB, 0x9AE4, 0x58FC, 0x9AE5, 0x58FD, 0x9AE6, 0x5902, 0x9AE7, 0x5909, 0x95CF, 0x590A, 0x9AE8, 0x590B, 0xFA9F, 0x590F, 0x89C4, + 0x5910, 0x9AE9, 0x5915, 0x975B, 0x5916, 0x8A4F, 0x5918, 0x99C7, 0x5919, 0x8F67, 0x591A, 0x91BD, 0x591B, 0x9AEA, 0x591C, 0x96E9, + 0x5922, 0x96B2, 0x5925, 0x9AEC, 0x5927, 0x91E5, 0x5929, 0x9356, 0x592A, 0x91BE, 0x592B, 0x9576, 0x592C, 0x9AED, 0x592D, 0x9AEE, + 0x592E, 0x899B, 0x5931, 0x8EB8, 0x5932, 0x9AEF, 0x5937, 0x88CE, 0x5938, 0x9AF0, 0x593E, 0x9AF1, 0x5944, 0x8982, 0x5947, 0x8AEF, + 0x5948, 0x93DE, 0x5949, 0x95F2, 0x594E, 0x9AF5, 0x594F, 0x9174, 0x5950, 0x9AF4, 0x5951, 0x8C5F, 0x5953, 0xFAA0, 0x5954, 0x967A, + 0x5955, 0x9AF3, 0x5957, 0x9385, 0x5958, 0x9AF7, 0x595A, 0x9AF6, 0x595B, 0xFAA1, 0x595D, 0xFAA2, 0x5960, 0x9AF9, 0x5962, 0x9AF8, + 0x5963, 0xFAA3, 0x5965, 0x899C, 0x5967, 0x9AFA, 0x5968, 0x8FA7, 0x5969, 0x9AFC, 0x596A, 0x9244, 0x596C, 0x9AFB, 0x596E, 0x95B1, + 0x5973, 0x8F97, 0x5974, 0x937A, 0x5978, 0x9B40, 0x597D, 0x8D44, 0x5981, 0x9B41, 0x5982, 0x9440, 0x5983, 0x94DC, 0x5984, 0x96CF, + 0x598A, 0x9444, 0x598D, 0x9B4A, 0x5993, 0x8B57, 0x5996, 0x9764, 0x5999, 0x96AD, 0x599B, 0x9BAA, 0x599D, 0x9B42, 0x59A3, 0x9B45, + 0x59A4, 0xFAA4, 0x59A5, 0x91C3, 0x59A8, 0x9657, 0x59AC, 0x9369, 0x59B2, 0x9B46, 0x59B9, 0x9685, 0x59BA, 0xFAA5, 0x59BB, 0x8DC8, + 0x59BE, 0x8FA8, 0x59C6, 0x9B47, 0x59C9, 0x8E6F, 0x59CB, 0x8E6E, 0x59D0, 0x88B7, 0x59D1, 0x8CC6, 0x59D3, 0x90A9, 0x59D4, 0x88CF, + 0x59D9, 0x9B4B, 0x59DA, 0x9B4C, 0x59DC, 0x9B49, 0x59E5, 0x8957, 0x59E6, 0x8AAD, 0x59E8, 0x9B48, 0x59EA, 0x96C3, 0x59EB, 0x9550, + 0x59F6, 0x88A6, 0x59FB, 0x88F7, 0x59FF, 0x8E70, 0x5A01, 0x88D0, 0x5A03, 0x88A1, 0x5A09, 0x9B51, 0x5A11, 0x9B4F, 0x5A18, 0x96BA, + 0x5A1A, 0x9B52, 0x5A1C, 0x9B50, 0x5A1F, 0x9B4E, 0x5A20, 0x9050, 0x5A25, 0x9B4D, 0x5A29, 0x95D8, 0x5A2F, 0x8CE2, 0x5A35, 0x9B56, + 0x5A36, 0x9B57, 0x5A3C, 0x8FA9, 0x5A40, 0x9B53, 0x5A41, 0x984B, 0x5A46, 0x946B, 0x5A49, 0x9B55, 0x5A5A, 0x8DA5, 0x5A62, 0x9B58, + 0x5A66, 0x9577, 0x5A6A, 0x9B59, 0x5A6C, 0x9B54, 0x5A7F, 0x96B9, 0x5A92, 0x947D, 0x5A9A, 0x9B5A, 0x5A9B, 0x9551, 0x5ABC, 0x9B5B, + 0x5ABD, 0x9B5F, 0x5ABE, 0x9B5C, 0x5AC1, 0x89C5, 0x5AC2, 0x9B5E, 0x5AC9, 0x8EB9, 0x5ACB, 0x9B5D, 0x5ACC, 0x8C99, 0x5AD0, 0x9B6B, + 0x5AD6, 0x9B64, 0x5AD7, 0x9B61, 0x5AE1, 0x9284, 0x5AE3, 0x9B60, 0x5AE6, 0x9B62, 0x5AE9, 0x9B63, 0x5AFA, 0x9B65, 0x5AFB, 0x9B66, + 0x5B09, 0x8AF0, 0x5B0B, 0x9B68, 0x5B0C, 0x9B67, 0x5B16, 0x9B69, 0x5B22, 0x8FEC, 0x5B2A, 0x9B6C, 0x5B2C, 0x92DA, 0x5B30, 0x8964, + 0x5B32, 0x9B6A, 0x5B36, 0x9B6D, 0x5B3E, 0x9B6E, 0x5B40, 0x9B71, 0x5B43, 0x9B6F, 0x5B45, 0x9B70, 0x5B50, 0x8E71, 0x5B51, 0x9B72, + 0x5B54, 0x8D45, 0x5B55, 0x9B73, 0x5B56, 0xFAA6, 0x5B57, 0x8E9A, 0x5B58, 0x91B6, 0x5B5A, 0x9B74, 0x5B5B, 0x9B75, 0x5B5C, 0x8E79, + 0x5B5D, 0x8D46, 0x5B5F, 0x96D0, 0x5B63, 0x8B47, 0x5B64, 0x8CC7, 0x5B65, 0x9B76, 0x5B66, 0x8A77, 0x5B69, 0x9B77, 0x5B6B, 0x91B7, + 0x5B70, 0x9B78, 0x5B71, 0x9BA1, 0x5B73, 0x9B79, 0x5B75, 0x9B7A, 0x5B78, 0x9B7B, 0x5B7A, 0x9B7D, 0x5B80, 0x9B7E, 0x5B83, 0x9B80, + 0x5B85, 0x91EE, 0x5B87, 0x8946, 0x5B88, 0x8EE7, 0x5B89, 0x88C0, 0x5B8B, 0x9176, 0x5B8C, 0x8AAE, 0x5B8D, 0x8EB3, 0x5B8F, 0x8D47, + 0x5B95, 0x9386, 0x5B97, 0x8F40, 0x5B98, 0x8AAF, 0x5B99, 0x9288, 0x5B9A, 0x92E8, 0x5B9B, 0x88B6, 0x5B9C, 0x8B58, 0x5B9D, 0x95F3, + 0x5B9F, 0x8EC0, 0x5BA2, 0x8B71, 0x5BA3, 0x90E9, 0x5BA4, 0x8EBA, 0x5BA5, 0x9747, 0x5BA6, 0x9B81, 0x5BAE, 0x8B7B, 0x5BB0, 0x8DC9, + 0x5BB3, 0x8A51, 0x5BB4, 0x8983, 0x5BB5, 0x8FAA, 0x5BB6, 0x89C6, 0x5BB8, 0x9B82, 0x5BB9, 0x9765, 0x5BBF, 0x8F68, 0x5BC0, 0xFAA7, + 0x5BC2, 0x8EE2, 0x5BC3, 0x9B83, 0x5BC4, 0x8AF1, 0x5BC5, 0x93D0, 0x5BC6, 0x96A7, 0x5BC7, 0x9B84, 0x5BC9, 0x9B85, 0x5BCC, 0x9578, + 0x5BD0, 0x9B87, 0x5BD2, 0x8AA6, 0x5BD3, 0x8BF5, 0x5BD4, 0x9B86, 0x5BD8, 0xFAA9, 0x5BDB, 0x8AB0, 0x5BDD, 0x9051, 0x5BDE, 0x9B8B, + 0x5BDF, 0x8E40, 0x5BE1, 0x89C7, 0x5BE2, 0x9B8A, 0x5BE4, 0x9B88, 0x5BE5, 0x9B8C, 0x5BE6, 0x9B89, 0x5BE7, 0x944A, 0x5BE8, 0x9ECB, + 0x5BE9, 0x9052, 0x5BEB, 0x9B8D, 0x5BEC, 0xFAAA, 0x5BEE, 0x97BE, 0x5BF0, 0x9B8E, 0x5BF3, 0x9B90, 0x5BF5, 0x929E, 0x5BF6, 0x9B8F, + 0x5BF8, 0x90A1, 0x5BFA, 0x8E9B, 0x5BFE, 0x91CE, 0x5BFF, 0x8EF5, 0x5C01, 0x9595, 0x5C02, 0x90EA, 0x5C04, 0x8ECB, 0x5C05, 0x9B91, + 0x5C06, 0x8FAB, 0x5C07, 0x9B92, 0x5C08, 0x9B93, 0x5C09, 0x88D1, 0x5C0A, 0x91B8, 0x5C0B, 0x9071, 0x5C0D, 0x9B94, 0x5C0E, 0x93B1, + 0x5C0F, 0x8FAC, 0x5C11, 0x8FAD, 0x5C13, 0x9B95, 0x5C16, 0x90EB, 0x5C1A, 0x8FAE, 0x5C1E, 0xFAAB, 0x5C20, 0x9B96, 0x5C22, 0x9B97, + 0x5C24, 0x96DE, 0x5C28, 0x9B98, 0x5C2D, 0x8BC4, 0x5C31, 0x8F41, 0x5C38, 0x9B99, 0x5C39, 0x9B9A, 0x5C3A, 0x8EDA, 0x5C3B, 0x904B, + 0x5C3C, 0x93F2, 0x5C3D, 0x9073, 0x5C3E, 0x94F6, 0x5C3F, 0x9441, 0x5C40, 0x8BC7, 0x5C41, 0x9B9B, 0x5C45, 0x8B8F, 0x5C46, 0x9B9C, + 0x5C48, 0x8BFC, 0x5C4A, 0x93CD, 0x5C4B, 0x89AE, 0x5C4D, 0x8E72, 0x5C4E, 0x9B9D, 0x5C4F, 0x9BA0, 0x5C50, 0x9B9F, 0x5C51, 0x8BFB, + 0x5C53, 0x9B9E, 0x5C55, 0x9357, 0x5C5E, 0x91AE, 0x5C60, 0x936A, 0x5C61, 0x8EC6, 0x5C64, 0x9177, 0x5C65, 0x979A, 0x5C6C, 0x9BA2, + 0x5C6E, 0x9BA3, 0x5C6F, 0x93D4, 0x5C71, 0x8E52, 0x5C76, 0x9BA5, 0x5C79, 0x9BA6, 0x5C8C, 0x9BA7, 0x5C90, 0x8AF2, 0x5C91, 0x9BA8, + 0x5C94, 0x9BA9, 0x5CA1, 0x89AA, 0x5CA6, 0xFAAC, 0x5CA8, 0x915A, 0x5CA9, 0x8AE2, 0x5CAB, 0x9BAB, 0x5CAC, 0x96A6, 0x5CB1, 0x91D0, + 0x5CB3, 0x8A78, 0x5CB6, 0x9BAD, 0x5CB7, 0x9BAF, 0x5CB8, 0x8ADD, 0x5CBA, 0xFAAD, 0x5CBB, 0x9BAC, 0x5CBC, 0x9BAE, 0x5CBE, 0x9BB1, + 0x5CC5, 0x9BB0, 0x5CC7, 0x9BB2, 0x5CD9, 0x9BB3, 0x5CE0, 0x93BB, 0x5CE1, 0x8BAC, 0x5CE8, 0x89E3, 0x5CE9, 0x9BB4, 0x5CEA, 0x9BB9, + 0x5CED, 0x9BB7, 0x5CEF, 0x95F5, 0x5CF0, 0x95F4, 0x5CF5, 0xFAAE, 0x5CF6, 0x9387, 0x5CFA, 0x9BB6, 0x5CFB, 0x8F73, 0x5CFD, 0x9BB5, + 0x5D07, 0x9092, 0x5D0B, 0x9BBA, 0x5D0E, 0x8DE8, 0x5D11, 0x9BC0, 0x5D14, 0x9BC1, 0x5D15, 0x9BBB, 0x5D16, 0x8A52, 0x5D17, 0x9BBC, + 0x5D18, 0x9BC5, 0x5D19, 0x9BC4, 0x5D1A, 0x9BC3, 0x5D1B, 0x9BBF, 0x5D1F, 0x9BBE, 0x5D22, 0x9BC2, 0x5D27, 0xFAAF, 0x5D29, 0x95F6, + 0x5D42, 0xFAB2, 0x5D4B, 0x9BC9, 0x5D4C, 0x9BC6, 0x5D4E, 0x9BC8, 0x5D50, 0x9792, 0x5D52, 0x9BC7, 0x5D53, 0xFAB0, 0x5D5C, 0x9BBD, + 0x5D69, 0x9093, 0x5D6C, 0x9BCA, 0x5D6D, 0xFAB3, 0x5D6F, 0x8DB5, 0x5D73, 0x9BCB, 0x5D76, 0x9BCC, 0x5D82, 0x9BCF, 0x5D84, 0x9BCE, + 0x5D87, 0x9BCD, 0x5D8B, 0x9388, 0x5D8C, 0x9BB8, 0x5D90, 0x9BD5, 0x5D9D, 0x9BD1, 0x5DA2, 0x9BD0, 0x5DAC, 0x9BD2, 0x5DAE, 0x9BD3, + 0x5DB7, 0x9BD6, 0x5DB8, 0xFAB4, 0x5DB9, 0xFAB5, 0x5DBA, 0x97E4, 0x5DBC, 0x9BD7, 0x5DBD, 0x9BD4, 0x5DC9, 0x9BD8, 0x5DCC, 0x8ADE, + 0x5DCD, 0x9BD9, 0x5DD0, 0xFAB6, 0x5DD2, 0x9BDB, 0x5DD3, 0x9BDA, 0x5DD6, 0x9BDC, 0x5DDB, 0x9BDD, 0x5DDD, 0x90EC, 0x5DDE, 0x8F42, + 0x5DE1, 0x8F84, 0x5DE3, 0x9183, 0x5DE5, 0x8D48, 0x5DE6, 0x8DB6, 0x5DE7, 0x8D49, 0x5DE8, 0x8B90, 0x5DEB, 0x9BDE, 0x5DEE, 0x8DB7, + 0x5DF1, 0x8CC8, 0x5DF2, 0x9BDF, 0x5DF3, 0x96A4, 0x5DF4, 0x9462, 0x5DF5, 0x9BE0, 0x5DF7, 0x8D4A, 0x5DFB, 0x8AAA, 0x5DFD, 0x9246, + 0x5DFE, 0x8BD0, 0x5E02, 0x8E73, 0x5E03, 0x957A, 0x5E06, 0x94BF, 0x5E0B, 0x9BE1, 0x5E0C, 0x8AF3, 0x5E11, 0x9BE4, 0x5E16, 0x929F, + 0x5E19, 0x9BE3, 0x5E1A, 0x9BE2, 0x5E1B, 0x9BE5, 0x5E1D, 0x92E9, 0x5E25, 0x9083, 0x5E2B, 0x8E74, 0x5E2D, 0x90C8, 0x5E2F, 0x91D1, + 0x5E30, 0x8B41, 0x5E33, 0x92A0, 0x5E36, 0x9BE6, 0x5E37, 0x9BE7, 0x5E38, 0x8FED, 0x5E3D, 0x9658, 0x5E40, 0x9BEA, 0x5E43, 0x9BE9, + 0x5E44, 0x9BE8, 0x5E45, 0x959D, 0x5E47, 0x9BF1, 0x5E4C, 0x9679, 0x5E4E, 0x9BEB, 0x5E54, 0x9BED, 0x5E55, 0x968B, 0x5E57, 0x9BEC, + 0x5E5F, 0x9BEE, 0x5E61, 0x94A6, 0x5E62, 0x9BEF, 0x5E63, 0x95BC, 0x5E64, 0x9BF0, 0x5E72, 0x8AB1, 0x5E73, 0x95BD, 0x5E74, 0x944E, + 0x5E75, 0x9BF2, 0x5E76, 0x9BF3, 0x5E78, 0x8D4B, 0x5E79, 0x8AB2, 0x5E7A, 0x9BF4, 0x5E7B, 0x8CB6, 0x5E7C, 0x9763, 0x5E7D, 0x9748, + 0x5E7E, 0x8AF4, 0x5E7F, 0x9BF6, 0x5E81, 0x92A1, 0x5E83, 0x8D4C, 0x5E84, 0x8FAF, 0x5E87, 0x94DD, 0x5E8A, 0x8FB0, 0x5E8F, 0x8F98, + 0x5E95, 0x92EA, 0x5E96, 0x95F7, 0x5E97, 0x9358, 0x5E9A, 0x8D4D, 0x5E9C, 0x957B, 0x5EA0, 0x9BF7, 0x5EA6, 0x9378, 0x5EA7, 0x8DC0, + 0x5EAB, 0x8CC9, 0x5EAD, 0x92EB, 0x5EB5, 0x88C1, 0x5EB6, 0x8F8E, 0x5EB7, 0x8D4E, 0x5EB8, 0x9766, 0x5EC1, 0x9BF8, 0x5EC2, 0x9BF9, + 0x5EC3, 0x9470, 0x5EC8, 0x9BFA, 0x5EC9, 0x97F5, 0x5ECA, 0x984C, 0x5ECF, 0x9BFC, 0x5ED0, 0x9BFB, 0x5ED3, 0x8A66, 0x5ED6, 0x9C40, + 0x5EDA, 0x9C43, 0x5EDB, 0x9C44, 0x5EDD, 0x9C42, 0x5EDF, 0x955F, 0x5EE0, 0x8FB1, 0x5EE1, 0x9C46, 0x5EE2, 0x9C45, 0x5EE3, 0x9C41, + 0x5EE8, 0x9C47, 0x5EE9, 0x9C48, 0x5EEC, 0x9C49, 0x5EF0, 0x9C4C, 0x5EF1, 0x9C4A, 0x5EF3, 0x9C4B, 0x5EF4, 0x9C4D, 0x5EF6, 0x8984, + 0x5EF7, 0x92EC, 0x5EF8, 0x9C4E, 0x5EFA, 0x8C9A, 0x5EFB, 0x89F4, 0x5EFC, 0x9455, 0x5EFE, 0x9C4F, 0x5EFF, 0x93F9, 0x5F01, 0x95D9, + 0x5F03, 0x9C50, 0x5F04, 0x984D, 0x5F09, 0x9C51, 0x5F0A, 0x95BE, 0x5F0B, 0x9C54, 0x5F0C, 0x989F, 0x5F0D, 0x98AF, 0x5F0F, 0x8EAE, + 0x5F10, 0x93F3, 0x5F11, 0x9C55, 0x5F13, 0x8B7C, 0x5F14, 0x92A2, 0x5F15, 0x88F8, 0x5F16, 0x9C56, 0x5F17, 0x95A4, 0x5F18, 0x8D4F, + 0x5F1B, 0x926F, 0x5F1F, 0x92ED, 0x5F21, 0xFAB7, 0x5F25, 0x96ED, 0x5F26, 0x8CB7, 0x5F27, 0x8CCA, 0x5F29, 0x9C57, 0x5F2D, 0x9C58, + 0x5F2F, 0x9C5E, 0x5F31, 0x8EE3, 0x5F34, 0xFAB8, 0x5F35, 0x92A3, 0x5F37, 0x8BAD, 0x5F38, 0x9C59, 0x5F3C, 0x954A, 0x5F3E, 0x9265, + 0x5F41, 0x9C5A, 0x5F45, 0xFA67, 0x5F48, 0x9C5B, 0x5F4A, 0x8BAE, 0x5F4C, 0x9C5C, 0x5F4E, 0x9C5D, 0x5F51, 0x9C5F, 0x5F53, 0x9396, + 0x5F56, 0x9C60, 0x5F57, 0x9C61, 0x5F59, 0x9C62, 0x5F5C, 0x9C53, 0x5F5D, 0x9C52, 0x5F61, 0x9C63, 0x5F62, 0x8C60, 0x5F66, 0x9546, + 0x5F67, 0xFAB9, 0x5F69, 0x8DCA, 0x5F6A, 0x9556, 0x5F6B, 0x92A4, 0x5F6C, 0x956A, 0x5F6D, 0x9C64, 0x5F70, 0x8FB2, 0x5F71, 0x8965, + 0x5F73, 0x9C65, 0x5F77, 0x9C66, 0x5F79, 0x96F0, 0x5F7C, 0x94DE, 0x5F7F, 0x9C69, 0x5F80, 0x899D, 0x5F81, 0x90AA, 0x5F82, 0x9C68, + 0x5F83, 0x9C67, 0x5F84, 0x8C61, 0x5F85, 0x91D2, 0x5F87, 0x9C6D, 0x5F88, 0x9C6B, 0x5F8A, 0x9C6A, 0x5F8B, 0x97A5, 0x5F8C, 0x8CE3, + 0x5F90, 0x8F99, 0x5F91, 0x9C6C, 0x5F92, 0x936B, 0x5F93, 0x8F5D, 0x5F97, 0x93BE, 0x5F98, 0x9C70, 0x5F99, 0x9C6F, 0x5F9E, 0x9C6E, + 0x5FA0, 0x9C71, 0x5FA1, 0x8CE4, 0x5FA8, 0x9C72, 0x5FA9, 0x959C, 0x5FAA, 0x8F7A, 0x5FAD, 0x9C73, 0x5FAE, 0x94F7, 0x5FB3, 0x93BF, + 0x5FB4, 0x92A5, 0x5FB7, 0xFABA, 0x5FB9, 0x934F, 0x5FBC, 0x9C74, 0x5FBD, 0x8B4A, 0x5FC3, 0x9053, 0x5FC5, 0x954B, 0x5FCC, 0x8AF5, + 0x5FCD, 0x9445, 0x5FD6, 0x9C75, 0x5FD7, 0x8E75, 0x5FD8, 0x9659, 0x5FD9, 0x965A, 0x5FDC, 0x899E, 0x5FDD, 0x9C7A, 0x5FDE, 0xFABB, + 0x5FE0, 0x9289, 0x5FE4, 0x9C77, 0x5FEB, 0x89F5, 0x5FF0, 0x9CAB, 0x5FF1, 0x9C79, 0x5FF5, 0x944F, 0x5FF8, 0x9C78, 0x5FFB, 0x9C76, + 0x5FFD, 0x8D9A, 0x5FFF, 0x9C7C, 0x600E, 0x9C83, 0x600F, 0x9C89, 0x6010, 0x9C81, 0x6012, 0x937B, 0x6015, 0x9C86, 0x6016, 0x957C, + 0x6019, 0x9C80, 0x601B, 0x9C85, 0x601C, 0x97E5, 0x601D, 0x8E76, 0x6020, 0x91D3, 0x6021, 0x9C7D, 0x6025, 0x8B7D, 0x6026, 0x9C88, + 0x6027, 0x90AB, 0x6028, 0x8985, 0x6029, 0x9C82, 0x602A, 0x89F6, 0x602B, 0x9C87, 0x602F, 0x8BAF, 0x6031, 0x9C84, 0x603A, 0x9C8A, + 0x6041, 0x9C8C, 0x6042, 0x9C96, 0x6043, 0x9C94, 0x6046, 0x9C91, 0x604A, 0x9C90, 0x604B, 0x97F6, 0x604D, 0x9C92, 0x6050, 0x8BB0, + 0x6052, 0x8D50, 0x6055, 0x8F9A, 0x6059, 0x9C99, 0x605A, 0x9C8B, 0x605D, 0xFABC, 0x605F, 0x9C8F, 0x6060, 0x9C7E, 0x6062, 0x89F8, + 0x6063, 0x9C93, 0x6064, 0x9C95, 0x6065, 0x9270, 0x6068, 0x8DA6, 0x6069, 0x89B6, 0x606A, 0x9C8D, 0x606B, 0x9C98, 0x606C, 0x9C97, + 0x606D, 0x8BB1, 0x606F, 0x91A7, 0x6070, 0x8A86, 0x6075, 0x8C62, 0x6077, 0x9C8E, 0x6081, 0x9C9A, 0x6083, 0x9C9D, 0x6084, 0x9C9F, + 0x6085, 0xFABD, 0x6089, 0x8EBB, 0x608A, 0xFABE, 0x608B, 0x9CA5, 0x608C, 0x92EE, 0x608D, 0x9C9B, 0x6092, 0x9CA3, 0x6094, 0x89F7, + 0x6096, 0x9CA1, 0x6097, 0x9CA2, 0x609A, 0x9C9E, 0x609B, 0x9CA0, 0x609F, 0x8CE5, 0x60A0, 0x9749, 0x60A3, 0x8AB3, 0x60A6, 0x8978, + 0x60A7, 0x9CA4, 0x60A9, 0x9459, 0x60AA, 0x88AB, 0x60B2, 0x94DF, 0x60B3, 0x9C7B, 0x60B4, 0x9CAA, 0x60B5, 0x9CAE, 0x60B6, 0x96E3, + 0x60B8, 0x9CA7, 0x60BC, 0x9389, 0x60BD, 0x9CAC, 0x60C5, 0x8FEE, 0x60C6, 0x9CAD, 0x60C7, 0x93D5, 0x60D1, 0x9866, 0x60D3, 0x9CA9, + 0x60D5, 0xFAC0, 0x60D8, 0x9CAF, 0x60DA, 0x8D9B, 0x60DC, 0x90C9, 0x60DE, 0xFABF, 0x60DF, 0x88D2, 0x60E0, 0x9CA8, 0x60E1, 0x9CA6, + 0x60E3, 0x9179, 0x60E7, 0x9C9C, 0x60E8, 0x8E53, 0x60F0, 0x91C4, 0x60F1, 0x9CBB, 0x60F2, 0xFAC2, 0x60F3, 0x917A, 0x60F4, 0x9CB6, + 0x60F6, 0x9CB3, 0x60F7, 0x9CB4, 0x60F9, 0x8EE4, 0x60FA, 0x9CB7, 0x60FB, 0x9CBA, 0x6100, 0x9CB5, 0x6101, 0x8F44, 0x6103, 0x9CB8, + 0x6106, 0x9CB2, 0x6108, 0x96FA, 0x6109, 0x96F9, 0x610D, 0x9CBC, 0x610E, 0x9CBD, 0x610F, 0x88D3, 0x6111, 0xFAC3, 0x6115, 0x9CB1, + 0x611A, 0x8BF0, 0x611B, 0x88A4, 0x611F, 0x8AB4, 0x6120, 0xFAC1, 0x6121, 0x9CB9, 0x6127, 0x9CC1, 0x6128, 0x9CC0, 0x612C, 0x9CC5, + 0x6130, 0xFAC5, 0x6134, 0x9CC6, 0x6137, 0xFAC4, 0x613C, 0x9CC4, 0x613D, 0x9CC7, 0x613E, 0x9CBF, 0x613F, 0x9CC3, 0x6142, 0x9CC8, + 0x6144, 0x9CC9, 0x6147, 0x9CBE, 0x6148, 0x8E9C, 0x614A, 0x9CC2, 0x614B, 0x91D4, 0x614C, 0x8D51, 0x614D, 0x9CB0, 0x614E, 0x9054, + 0x6153, 0x9CD6, 0x6155, 0x95E7, 0x6158, 0x9CCC, 0x6159, 0x9CCD, 0x615A, 0x9CCE, 0x615D, 0x9CD5, 0x615F, 0x9CD4, 0x6162, 0x969D, + 0x6163, 0x8AB5, 0x6165, 0x9CD2, 0x6167, 0x8C64, 0x6168, 0x8A53, 0x616B, 0x9CCF, 0x616E, 0x97B6, 0x616F, 0x9CD1, 0x6170, 0x88D4, + 0x6171, 0x9CD3, 0x6173, 0x9CCA, 0x6174, 0x9CD0, 0x6175, 0x9CD7, 0x6176, 0x8C63, 0x6177, 0x9CCB, 0x617E, 0x977C, 0x6182, 0x974A, + 0x6187, 0x9CDA, 0x618A, 0x9CDE, 0x618E, 0x919E, 0x6190, 0x97F7, 0x6191, 0x9CDF, 0x6194, 0x9CDC, 0x6196, 0x9CD9, 0x6198, 0xFAC6, + 0x6199, 0x9CD8, 0x619A, 0x9CDD, 0x61A4, 0x95AE, 0x61A7, 0x93B2, 0x61A9, 0x8C65, 0x61AB, 0x9CE0, 0x61AC, 0x9CDB, 0x61AE, 0x9CE1, + 0x61B2, 0x8C9B, 0x61B6, 0x89AF, 0x61BA, 0x9CE9, 0x61BE, 0x8AB6, 0x61C3, 0x9CE7, 0x61C6, 0x9CE8, 0x61C7, 0x8DA7, 0x61C8, 0x9CE6, + 0x61C9, 0x9CE4, 0x61CA, 0x9CE3, 0x61CB, 0x9CEA, 0x61CC, 0x9CE2, 0x61CD, 0x9CEC, 0x61D0, 0x89F9, 0x61E3, 0x9CEE, 0x61E6, 0x9CED, + 0x61F2, 0x92A6, 0x61F4, 0x9CF1, 0x61F6, 0x9CEF, 0x61F7, 0x9CE5, 0x61F8, 0x8C9C, 0x61FA, 0x9CF0, 0x61FC, 0x9CF4, 0x61FD, 0x9CF3, + 0x61FE, 0x9CF5, 0x61FF, 0x9CF2, 0x6200, 0x9CF6, 0x6208, 0x9CF7, 0x6209, 0x9CF8, 0x620A, 0x95E8, 0x620C, 0x9CFA, 0x620D, 0x9CF9, + 0x620E, 0x8F5E, 0x6210, 0x90AC, 0x6211, 0x89E4, 0x6212, 0x89FA, 0x6213, 0xFAC7, 0x6214, 0x9CFB, 0x6216, 0x88BD, 0x621A, 0x90CA, + 0x621B, 0x9CFC, 0x621D, 0xE6C1, 0x621E, 0x9D40, 0x621F, 0x8C81, 0x6221, 0x9D41, 0x6226, 0x90ED, 0x622A, 0x9D42, 0x622E, 0x9D43, + 0x622F, 0x8B59, 0x6230, 0x9D44, 0x6232, 0x9D45, 0x6233, 0x9D46, 0x6234, 0x91D5, 0x6238, 0x8CCB, 0x623B, 0x96DF, 0x623F, 0x965B, + 0x6240, 0x8F8A, 0x6241, 0x9D47, 0x6247, 0x90EE, 0x6248, 0xE7BB, 0x6249, 0x94E0, 0x624B, 0x8EE8, 0x624D, 0x8DCB, 0x624E, 0x9D48, + 0x6253, 0x91C5, 0x6255, 0x95A5, 0x6258, 0x91EF, 0x625B, 0x9D4B, 0x625E, 0x9D49, 0x6260, 0x9D4C, 0x6263, 0x9D4A, 0x6268, 0x9D4D, + 0x626E, 0x95AF, 0x6271, 0x88B5, 0x6276, 0x957D, 0x6279, 0x94E1, 0x627C, 0x9D4E, 0x627E, 0x9D51, 0x627F, 0x8FB3, 0x6280, 0x8B5A, + 0x6282, 0x9D4F, 0x6283, 0x9D56, 0x6284, 0x8FB4, 0x6289, 0x9D50, 0x628A, 0x9463, 0x6291, 0x977D, 0x6292, 0x9D52, 0x6293, 0x9D53, + 0x6294, 0x9D57, 0x6295, 0x938A, 0x6296, 0x9D54, 0x6297, 0x8D52, 0x6298, 0x90DC, 0x629B, 0x9D65, 0x629C, 0x94B2, 0x629E, 0x91F0, + 0x62A6, 0xFAC8, 0x62AB, 0x94E2, 0x62AC, 0x9DAB, 0x62B1, 0x95F8, 0x62B5, 0x92EF, 0x62B9, 0x9695, 0x62BB, 0x9D5A, 0x62BC, 0x899F, + 0x62BD, 0x928A, 0x62C2, 0x9D63, 0x62C5, 0x9253, 0x62C6, 0x9D5D, 0x62C7, 0x9D64, 0x62C8, 0x9D5F, 0x62C9, 0x9D66, 0x62CA, 0x9D62, + 0x62CC, 0x9D61, 0x62CD, 0x948F, 0x62CF, 0x9D5B, 0x62D0, 0x89FB, 0x62D1, 0x9D59, 0x62D2, 0x8B91, 0x62D3, 0x91F1, 0x62D4, 0x9D55, + 0x62D7, 0x9D58, 0x62D8, 0x8D53, 0x62D9, 0x90D9, 0x62DB, 0x8FB5, 0x62DC, 0x9D60, 0x62DD, 0x9471, 0x62E0, 0x8B92, 0x62E1, 0x8A67, + 0x62EC, 0x8A87, 0x62ED, 0x9040, 0x62EE, 0x9D68, 0x62EF, 0x9D6D, 0x62F1, 0x9D69, 0x62F3, 0x8C9D, 0x62F5, 0x9D6E, 0x62F6, 0x8E41, + 0x62F7, 0x8D89, 0x62FE, 0x8F45, 0x62FF, 0x9D5C, 0x6301, 0x8E9D, 0x6302, 0x9D6B, 0x6307, 0x8E77, 0x6308, 0x9D6C, 0x6309, 0x88C2, + 0x630C, 0x9D67, 0x6311, 0x92A7, 0x6319, 0x8B93, 0x631F, 0x8BB2, 0x6327, 0x9D6A, 0x6328, 0x88A5, 0x632B, 0x8DC1, 0x632F, 0x9055, + 0x633A, 0x92F0, 0x633D, 0x94D2, 0x633E, 0x9D70, 0x633F, 0x917D, 0x6349, 0x91A8, 0x634C, 0x8E4A, 0x634D, 0x9D71, 0x634F, 0x9D73, + 0x6350, 0x9D6F, 0x6355, 0x95DF, 0x6357, 0x92BB, 0x635C, 0x917B, 0x6367, 0x95F9, 0x6368, 0x8ECC, 0x6369, 0x9D80, 0x636B, 0x9D7E, + 0x636E, 0x9098, 0x6372, 0x8C9E, 0x6376, 0x9D78, 0x6377, 0x8FB7, 0x637A, 0x93E6, 0x637B, 0x9450, 0x6380, 0x9D76, 0x6383, 0x917C, + 0x6388, 0x8EF6, 0x6389, 0x9D7B, 0x638C, 0x8FB6, 0x638E, 0x9D75, 0x638F, 0x9D7A, 0x6392, 0x9472, 0x6396, 0x9D74, 0x6398, 0x8C40, + 0x639B, 0x8A7C, 0x639F, 0x9D7C, 0x63A0, 0x97A9, 0x63A1, 0x8DCC, 0x63A2, 0x9254, 0x63A3, 0x9D79, 0x63A5, 0x90DA, 0x63A7, 0x8D54, + 0x63A8, 0x9084, 0x63A9, 0x8986, 0x63AA, 0x915B, 0x63AB, 0x9D77, 0x63AC, 0x8B64, 0x63B2, 0x8C66, 0x63B4, 0x92CD, 0x63B5, 0x9D7D, + 0x63BB, 0x917E, 0x63BE, 0x9D81, 0x63C0, 0x9D83, 0x63C3, 0x91B5, 0x63C4, 0x9D89, 0x63C6, 0x9D84, 0x63C9, 0x9D86, 0x63CF, 0x9560, + 0x63D0, 0x92F1, 0x63D2, 0x9D87, 0x63D6, 0x974B, 0x63DA, 0x9767, 0x63DB, 0x8AB7, 0x63E1, 0x88AC, 0x63E3, 0x9D85, 0x63E9, 0x9D82, + 0x63EE, 0x8AF6, 0x63F4, 0x8987, 0x63F5, 0xFAC9, 0x63F6, 0x9D88, 0x63FA, 0x9768, 0x6406, 0x9D8C, 0x640D, 0x91B9, 0x640F, 0x9D93, + 0x6413, 0x9D8D, 0x6416, 0x9D8A, 0x6417, 0x9D91, 0x641C, 0x9D72, 0x6426, 0x9D8E, 0x6428, 0x9D92, 0x642C, 0x94C0, 0x642D, 0x938B, + 0x6434, 0x9D8B, 0x6436, 0x9D8F, 0x643A, 0x8C67, 0x643E, 0x8DEF, 0x6442, 0x90DB, 0x644E, 0x9D97, 0x6458, 0x9345, 0x6460, 0xFACA, + 0x6467, 0x9D94, 0x6469, 0x9680, 0x646F, 0x9D95, 0x6476, 0x9D96, 0x6478, 0x96CC, 0x647A, 0x90A0, 0x6483, 0x8C82, 0x6488, 0x9D9D, + 0x6492, 0x8E54, 0x6493, 0x9D9A, 0x6495, 0x9D99, 0x649A, 0x9451, 0x649D, 0xFACB, 0x649E, 0x93B3, 0x64A4, 0x9350, 0x64A5, 0x9D9B, + 0x64A9, 0x9D9C, 0x64AB, 0x958F, 0x64AD, 0x9464, 0x64AE, 0x8E42, 0x64B0, 0x90EF, 0x64B2, 0x966F, 0x64B9, 0x8A68, 0x64BB, 0x9DA3, + 0x64BC, 0x9D9E, 0x64C1, 0x9769, 0x64C2, 0x9DA5, 0x64C5, 0x9DA1, 0x64C7, 0x9DA2, 0x64CD, 0x9180, 0x64CE, 0xFACC, 0x64D2, 0x9DA0, + 0x64D4, 0x9D5E, 0x64D8, 0x9DA4, 0x64DA, 0x9D9F, 0x64E0, 0x9DA9, 0x64E1, 0x9DAA, 0x64E2, 0x9346, 0x64E3, 0x9DAC, 0x64E6, 0x8E43, + 0x64E7, 0x9DA7, 0x64EC, 0x8B5B, 0x64EF, 0x9DAD, 0x64F1, 0x9DA6, 0x64F2, 0x9DB1, 0x64F4, 0x9DB0, 0x64F6, 0x9DAF, 0x64FA, 0x9DB2, + 0x64FD, 0x9DB4, 0x64FE, 0x8FEF, 0x6500, 0x9DB3, 0x6505, 0x9DB7, 0x6518, 0x9DB5, 0x651C, 0x9DB6, 0x651D, 0x9D90, 0x6523, 0x9DB9, + 0x6524, 0x9DB8, 0x652A, 0x9D98, 0x652B, 0x9DBA, 0x652C, 0x9DAE, 0x652F, 0x8E78, 0x6534, 0x9DBB, 0x6535, 0x9DBC, 0x6536, 0x9DBE, + 0x6537, 0x9DBD, 0x6538, 0x9DBF, 0x6539, 0x89FC, 0x653B, 0x8D55, 0x653E, 0x95FA, 0x653F, 0x90AD, 0x6545, 0x8CCC, 0x6548, 0x9DC1, + 0x654D, 0x9DC4, 0x654E, 0xFACD, 0x654F, 0x9571, 0x6551, 0x8B7E, 0x6555, 0x9DC3, 0x6556, 0x9DC2, 0x6557, 0x9473, 0x6558, 0x9DC5, + 0x6559, 0x8BB3, 0x655D, 0x9DC7, 0x655E, 0x9DC6, 0x6562, 0x8AB8, 0x6563, 0x8E55, 0x6566, 0x93D6, 0x656C, 0x8C68, 0x6570, 0x9094, + 0x6572, 0x9DC8, 0x6574, 0x90AE, 0x6575, 0x9347, 0x6577, 0x957E, 0x6578, 0x9DC9, 0x6582, 0x9DCA, 0x6583, 0x9DCB, 0x6587, 0x95B6, + 0x6588, 0x9B7C, 0x6589, 0x90C4, 0x658C, 0x956B, 0x658E, 0x8DD6, 0x6590, 0x94E3, 0x6591, 0x94C1, 0x6597, 0x936C, 0x6599, 0x97BF, + 0x659B, 0x9DCD, 0x659C, 0x8ECE, 0x659F, 0x9DCE, 0x65A1, 0x88B4, 0x65A4, 0x8BD2, 0x65A5, 0x90CB, 0x65A7, 0x9580, 0x65AB, 0x9DCF, + 0x65AC, 0x8E61, 0x65AD, 0x9266, 0x65AF, 0x8E7A, 0x65B0, 0x9056, 0x65B7, 0x9DD0, 0x65B9, 0x95FB, 0x65BC, 0x8997, 0x65BD, 0x8E7B, + 0x65C1, 0x9DD3, 0x65C3, 0x9DD1, 0x65C4, 0x9DD4, 0x65C5, 0x97B7, 0x65C6, 0x9DD2, 0x65CB, 0x90F9, 0x65CC, 0x9DD5, 0x65CF, 0x91B0, + 0x65D2, 0x9DD6, 0x65D7, 0x8AF8, 0x65D9, 0x9DD8, 0x65DB, 0x9DD7, 0x65E0, 0x9DD9, 0x65E1, 0x9DDA, 0x65E2, 0x8AF9, 0x65E5, 0x93FA, + 0x65E6, 0x9255, 0x65E7, 0x8B8C, 0x65E8, 0x8E7C, 0x65E9, 0x9181, 0x65EC, 0x8F7B, 0x65ED, 0x88AE, 0x65F1, 0x9DDB, 0x65FA, 0x89A0, + 0x65FB, 0x9DDF, 0x6600, 0xFACE, 0x6602, 0x8D56, 0x6603, 0x9DDE, 0x6606, 0x8DA9, 0x6607, 0x8FB8, 0x6609, 0xFAD1, 0x660A, 0x9DDD, + 0x660C, 0x8FB9, 0x660E, 0x96BE, 0x660F, 0x8DA8, 0x6613, 0x88D5, 0x6614, 0x90CC, 0x6615, 0xFACF, 0x661C, 0x9DE4, 0x661E, 0xFAD3, + 0x661F, 0x90AF, 0x6620, 0x8966, 0x6624, 0xFAD4, 0x6625, 0x8F74, 0x6627, 0x9686, 0x6628, 0x8DF0, 0x662D, 0x8FBA, 0x662E, 0xFAD2, + 0x662F, 0x90A5, 0x6631, 0xFA63, 0x6634, 0x9DE3, 0x6635, 0x9DE1, 0x6636, 0x9DE2, 0x663B, 0xFAD0, 0x663C, 0x928B, 0x663F, 0x9E45, + 0x6641, 0x9DE8, 0x6642, 0x8E9E, 0x6643, 0x8D57, 0x6644, 0x9DE6, 0x6649, 0x9DE7, 0x664B, 0x9057, 0x664F, 0x9DE5, 0x6652, 0x8E4E, + 0x6657, 0xFAD6, 0x6659, 0xFAD7, 0x665D, 0x9DEA, 0x665E, 0x9DE9, 0x665F, 0x9DEE, 0x6662, 0x9DEF, 0x6664, 0x9DEB, 0x6665, 0xFAD5, + 0x6666, 0x8A41, 0x6667, 0x9DEC, 0x6668, 0x9DED, 0x6669, 0x94D3, 0x666E, 0x9581, 0x666F, 0x8C69, 0x6670, 0x9DF0, 0x6673, 0xFAD9, + 0x6674, 0x90B0, 0x6676, 0x8FBB, 0x667A, 0x9271, 0x6681, 0x8BC5, 0x6683, 0x9DF1, 0x6684, 0x9DF5, 0x6687, 0x89C9, 0x6688, 0x9DF2, + 0x6689, 0x9DF4, 0x668E, 0x9DF3, 0x6691, 0x8F8B, 0x6696, 0x9267, 0x6697, 0x88C3, 0x6698, 0x9DF6, 0x6699, 0xFADA, 0x669D, 0x9DF7, + 0x66A0, 0xFADB, 0x66A2, 0x92A8, 0x66A6, 0x97EF, 0x66AB, 0x8E62, 0x66AE, 0x95E9, 0x66B2, 0xFADC, 0x66B4, 0x965C, 0x66B8, 0x9E41, + 0x66B9, 0x9DF9, 0x66BC, 0x9DFC, 0x66BE, 0x9DFB, 0x66BF, 0xFADD, 0x66C1, 0x9DF8, 0x66C4, 0x9E40, 0x66C7, 0x93DC, 0x66C9, 0x9DFA, + 0x66D6, 0x9E42, 0x66D9, 0x8F8C, 0x66DA, 0x9E43, 0x66DC, 0x976A, 0x66DD, 0x9498, 0x66E0, 0x9E44, 0x66E6, 0x9E46, 0x66E9, 0x9E47, + 0x66F0, 0x9E48, 0x66F2, 0x8BC8, 0x66F3, 0x8967, 0x66F4, 0x8D58, 0x66F5, 0x9E49, 0x66F7, 0x9E4A, 0x66F8, 0x8F91, 0x66F9, 0x9182, + 0x66FA, 0xFADE, 0x66FB, 0xFA66, 0x66FC, 0x99D6, 0x66FD, 0x915D, 0x66FE, 0x915C, 0x66FF, 0x91D6, 0x6700, 0x8DC5, 0x6703, 0x98F0, + 0x6708, 0x8C8E, 0x6709, 0x974C, 0x670B, 0x95FC, 0x670D, 0x959E, 0x670E, 0xFADF, 0x670F, 0x9E4B, 0x6714, 0x8DF1, 0x6715, 0x92BD, + 0x6716, 0x9E4C, 0x6717, 0x984E, 0x671B, 0x965D, 0x671D, 0x92A9, 0x671E, 0x9E4D, 0x671F, 0x8AFA, 0x6726, 0x9E4E, 0x6727, 0x9E4F, + 0x6728, 0x96D8, 0x672A, 0x96A2, 0x672B, 0x9696, 0x672C, 0x967B, 0x672D, 0x8E44, 0x672E, 0x9E51, 0x6731, 0x8EE9, 0x6734, 0x9670, + 0x6736, 0x9E53, 0x6737, 0x9E56, 0x6738, 0x9E55, 0x673A, 0x8AF7, 0x673D, 0x8B80, 0x673F, 0x9E52, 0x6741, 0x9E54, 0x6746, 0x9E57, + 0x6749, 0x9099, 0x674E, 0x979B, 0x674F, 0x88C7, 0x6750, 0x8DDE, 0x6751, 0x91BA, 0x6753, 0x8EDB, 0x6756, 0x8FF1, 0x6759, 0x9E5A, + 0x675C, 0x936D, 0x675E, 0x9E58, 0x675F, 0x91A9, 0x6760, 0x9E59, 0x6761, 0x8FF0, 0x6762, 0x96DB, 0x6763, 0x9E5B, 0x6764, 0x9E5C, + 0x6765, 0x9788, 0x6766, 0xFAE1, 0x676A, 0x9E61, 0x676D, 0x8D59, 0x676F, 0x9474, 0x6770, 0x9E5E, 0x6771, 0x938C, 0x6772, 0x9DDC, + 0x6773, 0x9DE0, 0x6775, 0x8B6E, 0x6777, 0x9466, 0x677C, 0x9E60, 0x677E, 0x8FBC, 0x677F, 0x94C2, 0x6785, 0x9E66, 0x6787, 0x94F8, + 0x6789, 0x9E5D, 0x678B, 0x9E63, 0x678C, 0x9E62, 0x6790, 0x90CD, 0x6795, 0x968D, 0x6797, 0x97D1, 0x679A, 0x9687, 0x679C, 0x89CA, + 0x679D, 0x8E7D, 0x67A0, 0x9867, 0x67A1, 0x9E65, 0x67A2, 0x9095, 0x67A6, 0x9E64, 0x67A9, 0x9E5F, 0x67AF, 0x8CCD, 0x67B3, 0x9E6B, + 0x67B4, 0x9E69, 0x67B6, 0x89CB, 0x67B7, 0x9E67, 0x67B8, 0x9E6D, 0x67B9, 0x9E73, 0x67BB, 0xFAE2, 0x67C0, 0xFAE4, 0x67C1, 0x91C6, + 0x67C4, 0x95BF, 0x67C6, 0x9E75, 0x67CA, 0x9541, 0x67CE, 0x9E74, 0x67CF, 0x9490, 0x67D0, 0x965E, 0x67D1, 0x8AB9, 0x67D3, 0x90F5, + 0x67D4, 0x8F5F, 0x67D8, 0x92D1, 0x67DA, 0x974D, 0x67DD, 0x9E70, 0x67DE, 0x9E6F, 0x67E2, 0x9E71, 0x67E4, 0x9E6E, 0x67E7, 0x9E76, + 0x67E9, 0x9E6C, 0x67EC, 0x9E6A, 0x67EE, 0x9E72, 0x67EF, 0x9E68, 0x67F1, 0x928C, 0x67F3, 0x96F6, 0x67F4, 0x8EC4, 0x67F5, 0x8DF2, + 0x67FB, 0x8DB8, 0x67FE, 0x968F, 0x67FF, 0x8A60, 0x6801, 0xFAE5, 0x6802, 0x92CC, 0x6803, 0x93C8, 0x6804, 0x8968, 0x6813, 0x90F0, + 0x6816, 0x90B2, 0x6817, 0x8C49, 0x681E, 0x9E78, 0x6821, 0x8D5A, 0x6822, 0x8A9C, 0x6829, 0x9E7A, 0x682A, 0x8A94, 0x682B, 0x9E81, + 0x6832, 0x9E7D, 0x6834, 0x90F1, 0x6838, 0x8A6A, 0x6839, 0x8DAA, 0x683C, 0x8A69, 0x683D, 0x8DCD, 0x6840, 0x9E7B, 0x6841, 0x8C85, + 0x6842, 0x8C6A, 0x6843, 0x938D, 0x6844, 0xFAE6, 0x6846, 0x9E79, 0x6848, 0x88C4, 0x684D, 0x9E7C, 0x684E, 0x9E7E, 0x6850, 0x8BCB, + 0x6851, 0x8C4B, 0x6852, 0xFAE3, 0x6853, 0x8ABA, 0x6854, 0x8B6A, 0x6859, 0x9E82, 0x685C, 0x8DF7, 0x685D, 0x9691, 0x685F, 0x8E56, + 0x6863, 0x9E83, 0x6867, 0x954F, 0x6874, 0x9E8F, 0x6876, 0x89B1, 0x6877, 0x9E84, 0x687E, 0x9E95, 0x687F, 0x9E85, 0x6881, 0x97C0, + 0x6883, 0x9E8C, 0x6885, 0x947E, 0x688D, 0x9E94, 0x688F, 0x9E87, 0x6893, 0x88B2, 0x6894, 0x9E89, 0x6897, 0x8D5B, 0x689B, 0x9E8B, + 0x689D, 0x9E8A, 0x689F, 0x9E86, 0x68A0, 0x9E91, 0x68A2, 0x8FBD, 0x68A6, 0x9AEB, 0x68A7, 0x8CE6, 0x68A8, 0x979C, 0x68AD, 0x9E88, + 0x68AF, 0x92F2, 0x68B0, 0x8A42, 0x68B1, 0x8DAB, 0x68B3, 0x9E80, 0x68B5, 0x9E90, 0x68B6, 0x8A81, 0x68B9, 0x9E8E, 0x68BA, 0x9E92, + 0x68BC, 0x938E, 0x68C4, 0x8AFC, 0x68C6, 0x9EB0, 0x68C8, 0xFA64, 0x68C9, 0x96C7, 0x68CA, 0x9E97, 0x68CB, 0x8AFB, 0x68CD, 0x9E9E, + 0x68CF, 0xFAE7, 0x68D2, 0x965F, 0x68D4, 0x9E9F, 0x68D5, 0x9EA1, 0x68D7, 0x9EA5, 0x68D8, 0x9E99, 0x68DA, 0x9249, 0x68DF, 0x938F, + 0x68E0, 0x9EA9, 0x68E1, 0x9E9C, 0x68E3, 0x9EA6, 0x68E7, 0x9EA0, 0x68EE, 0x9058, 0x68EF, 0x9EAA, 0x68F2, 0x90B1, 0x68F9, 0x9EA8, + 0x68FA, 0x8ABB, 0x6900, 0x986F, 0x6901, 0x9E96, 0x6904, 0x9EA4, 0x6905, 0x88D6, 0x6908, 0x9E98, 0x690B, 0x96B8, 0x690C, 0x9E9D, + 0x690D, 0x9041, 0x690E, 0x92C5, 0x690F, 0x9E93, 0x6912, 0x9EA3, 0x6919, 0x909A, 0x691A, 0x9EAD, 0x691B, 0x8A91, 0x691C, 0x8C9F, + 0x6921, 0x9EAF, 0x6922, 0x9E9A, 0x6923, 0x9EAE, 0x6925, 0x9EA7, 0x6926, 0x9E9B, 0x6928, 0x9EAB, 0x692A, 0x9EAC, 0x6930, 0x9EBD, + 0x6934, 0x93CC, 0x6936, 0x9EA2, 0x6939, 0x9EB9, 0x693D, 0x9EBB, 0x693F, 0x92D6, 0x694A, 0x976B, 0x6953, 0x9596, 0x6954, 0x9EB6, + 0x6955, 0x91C8, 0x6959, 0x9EBC, 0x695A, 0x915E, 0x695C, 0x9EB3, 0x695D, 0x9EC0, 0x695E, 0x9EBF, 0x6960, 0x93ED, 0x6961, 0x9EBE, + 0x6962, 0x93E8, 0x6968, 0xFAE9, 0x696A, 0x9EC2, 0x696B, 0x9EB5, 0x696D, 0x8BC6, 0x696E, 0x9EB8, 0x696F, 0x8F7C, 0x6973, 0x9480, + 0x6974, 0x9EBA, 0x6975, 0x8BC9, 0x6977, 0x9EB2, 0x6978, 0x9EB4, 0x6979, 0x9EB1, 0x697C, 0x984F, 0x697D, 0x8A79, 0x697E, 0x9EB7, + 0x6981, 0x9EC1, 0x6982, 0x8A54, 0x698A, 0x8DE5, 0x698E, 0x897C, 0x6991, 0x9ED2, 0x6994, 0x9850, 0x6995, 0x9ED5, 0x6998, 0xFAEB, + 0x699B, 0x9059, 0x699C, 0x9ED4, 0x69A0, 0x9ED3, 0x69A7, 0x9ED0, 0x69AE, 0x9EC4, 0x69B1, 0x9EE1, 0x69B2, 0x9EC3, 0x69B4, 0x9ED6, + 0x69BB, 0x9ECE, 0x69BE, 0x9EC9, 0x69BF, 0x9EC6, 0x69C1, 0x9EC7, 0x69C3, 0x9ECF, 0x69C7, 0xEAA0, 0x69CA, 0x9ECC, 0x69CB, 0x8D5C, + 0x69CC, 0x92C6, 0x69CD, 0x9184, 0x69CE, 0x9ECA, 0x69D0, 0x9EC5, 0x69D3, 0x9EC8, 0x69D8, 0x976C, 0x69D9, 0x968A, 0x69DD, 0x9ECD, + 0x69DE, 0x9ED7, 0x69E2, 0xFAEC, 0x69E7, 0x9EDF, 0x69E8, 0x9ED8, 0x69EB, 0x9EE5, 0x69ED, 0x9EE3, 0x69F2, 0x9EDE, 0x69F9, 0x9EDD, + 0x69FB, 0x92CE, 0x69FD, 0x9185, 0x69FF, 0x9EDB, 0x6A02, 0x9ED9, 0x6A05, 0x9EE0, 0x6A0A, 0x9EE6, 0x6A0B, 0x94F3, 0x6A0C, 0x9EEC, + 0x6A12, 0x9EE7, 0x6A13, 0x9EEA, 0x6A14, 0x9EE4, 0x6A17, 0x9294, 0x6A19, 0x9557, 0x6A1B, 0x9EDA, 0x6A1E, 0x9EE2, 0x6A1F, 0x8FBE, + 0x6A21, 0x96CD, 0x6A22, 0x9EF6, 0x6A23, 0x9EE9, 0x6A29, 0x8CA0, 0x6A2A, 0x89A1, 0x6A2B, 0x8A7E, 0x6A2E, 0x9ED1, 0x6A30, 0xFAED, + 0x6A35, 0x8FBF, 0x6A36, 0x9EEE, 0x6A38, 0x9EF5, 0x6A39, 0x8EF7, 0x6A3A, 0x8A92, 0x6A3D, 0x924D, 0x6A44, 0x9EEB, 0x6A46, 0xFAEF, + 0x6A47, 0x9EF0, 0x6A48, 0x9EF4, 0x6A4B, 0x8BB4, 0x6A58, 0x8B6B, 0x6A59, 0x9EF2, 0x6A5F, 0x8B40, 0x6A61, 0x93C9, 0x6A62, 0x9EF1, + 0x6A66, 0x9EF3, 0x6A6B, 0xFAEE, 0x6A72, 0x9EED, 0x6A73, 0xFAF0, 0x6A78, 0x9EEF, 0x6A7E, 0xFAF1, 0x6A7F, 0x8A80, 0x6A80, 0x9268, + 0x6A84, 0x9EFA, 0x6A8D, 0x9EF8, 0x6A8E, 0x8CE7, 0x6A90, 0x9EF7, 0x6A97, 0x9F40, 0x6A9C, 0x9E77, 0x6AA0, 0x9EF9, 0x6AA2, 0x9EFB, + 0x6AA3, 0x9EFC, 0x6AAA, 0x9F4B, 0x6AAC, 0x9F47, 0x6AAE, 0x9E8D, 0x6AB3, 0x9F46, 0x6AB8, 0x9F45, 0x6ABB, 0x9F42, 0x6AC1, 0x9EE8, + 0x6AC2, 0x9F44, 0x6AC3, 0x9F43, 0x6AD1, 0x9F49, 0x6AD3, 0x9845, 0x6ADA, 0x9F4C, 0x6ADB, 0x8BF9, 0x6ADE, 0x9F48, 0x6ADF, 0x9F4A, + 0x6AE2, 0xFAF2, 0x6AE4, 0xFAF3, 0x6AE8, 0x94A5, 0x6AEA, 0x9F4D, 0x6AFA, 0x9F51, 0x6AFB, 0x9F4E, 0x6B04, 0x9793, 0x6B05, 0x9F4F, + 0x6B0A, 0x9EDC, 0x6B12, 0x9F52, 0x6B16, 0x9F53, 0x6B1D, 0x8954, 0x6B1F, 0x9F55, 0x6B20, 0x8C87, 0x6B21, 0x8E9F, 0x6B23, 0x8BD3, + 0x6B27, 0x89A2, 0x6B32, 0x977E, 0x6B37, 0x9F57, 0x6B38, 0x9F56, 0x6B39, 0x9F59, 0x6B3A, 0x8B5C, 0x6B3D, 0x8BD4, 0x6B3E, 0x8ABC, + 0x6B43, 0x9F5C, 0x6B47, 0x9F5B, 0x6B49, 0x9F5D, 0x6B4C, 0x89CC, 0x6B4E, 0x9256, 0x6B50, 0x9F5E, 0x6B53, 0x8ABD, 0x6B54, 0x9F60, + 0x6B59, 0x9F5F, 0x6B5B, 0x9F61, 0x6B5F, 0x9F62, 0x6B61, 0x9F63, 0x6B62, 0x8E7E, 0x6B63, 0x90B3, 0x6B64, 0x8D9F, 0x6B66, 0x9590, + 0x6B69, 0x95E0, 0x6B6A, 0x9863, 0x6B6F, 0x8E95, 0x6B73, 0x8DCE, 0x6B74, 0x97F0, 0x6B78, 0x9F64, 0x6B79, 0x9F65, 0x6B7B, 0x8E80, + 0x6B7F, 0x9F66, 0x6B80, 0x9F67, 0x6B83, 0x9F69, 0x6B84, 0x9F68, 0x6B86, 0x9677, 0x6B89, 0x8F7D, 0x6B8A, 0x8EEA, 0x6B8B, 0x8E63, + 0x6B8D, 0x9F6A, 0x6B95, 0x9F6C, 0x6B96, 0x9042, 0x6B98, 0x9F6B, 0x6B9E, 0x9F6D, 0x6BA4, 0x9F6E, 0x6BAA, 0x9F6F, 0x6BAB, 0x9F70, + 0x6BAF, 0x9F71, 0x6BB1, 0x9F73, 0x6BB2, 0x9F72, 0x6BB3, 0x9F74, 0x6BB4, 0x89A3, 0x6BB5, 0x9269, 0x6BB7, 0x9F75, 0x6BBA, 0x8E45, + 0x6BBB, 0x8A6B, 0x6BBC, 0x9F76, 0x6BBF, 0x9361, 0x6BC0, 0x9ACA, 0x6BC5, 0x8B42, 0x6BC6, 0x9F77, 0x6BCB, 0x9F78, 0x6BCD, 0x95EA, + 0x6BCE, 0x9688, 0x6BD2, 0x93C5, 0x6BD3, 0x9F79, 0x6BD4, 0x94E4, 0x6BD6, 0xFAF4, 0x6BD8, 0x94F9, 0x6BDB, 0x96D1, 0x6BDF, 0x9F7A, + 0x6BEB, 0x9F7C, 0x6BEC, 0x9F7B, 0x6BEF, 0x9F7E, 0x6BF3, 0x9F7D, 0x6C08, 0x9F81, 0x6C0F, 0x8E81, 0x6C11, 0x96AF, 0x6C13, 0x9F82, + 0x6C14, 0x9F83, 0x6C17, 0x8B43, 0x6C1B, 0x9F84, 0x6C23, 0x9F86, 0x6C24, 0x9F85, 0x6C34, 0x9085, 0x6C37, 0x9558, 0x6C38, 0x8969, + 0x6C3E, 0x94C3, 0x6C3F, 0xFAF5, 0x6C40, 0x92F3, 0x6C41, 0x8F60, 0x6C42, 0x8B81, 0x6C4E, 0x94C4, 0x6C50, 0x8EAC, 0x6C55, 0x9F88, + 0x6C57, 0x8ABE, 0x6C5A, 0x8998, 0x6C5C, 0xFAF6, 0x6C5D, 0x93F0, 0x6C5E, 0x9F87, 0x6C5F, 0x8D5D, 0x6C60, 0x9272, 0x6C62, 0x9F89, + 0x6C68, 0x9F91, 0x6C6A, 0x9F8A, 0x6C6F, 0xFAF8, 0x6C70, 0x91BF, 0x6C72, 0x8B82, 0x6C73, 0x9F92, 0x6C7A, 0x8C88, 0x6C7D, 0x8B44, + 0x6C7E, 0x9F90, 0x6C81, 0x9F8E, 0x6C82, 0x9F8B, 0x6C83, 0x9780, 0x6C86, 0xFAF7, 0x6C88, 0x92BE, 0x6C8C, 0x93D7, 0x6C8D, 0x9F8C, + 0x6C90, 0x9F94, 0x6C92, 0x9F93, 0x6C93, 0x8C42, 0x6C96, 0x89AB, 0x6C99, 0x8DB9, 0x6C9A, 0x9F8D, 0x6C9B, 0x9F8F, 0x6CA1, 0x9676, + 0x6CA2, 0x91F2, 0x6CAB, 0x9697, 0x6CAE, 0x9F9C, 0x6CB1, 0x9F9D, 0x6CB3, 0x89CD, 0x6CB8, 0x95A6, 0x6CB9, 0x96FB, 0x6CBA, 0x9F9F, + 0x6CBB, 0x8EA1, 0x6CBC, 0x8FC0, 0x6CBD, 0x9F98, 0x6CBE, 0x9F9E, 0x6CBF, 0x8988, 0x6CC1, 0x8BB5, 0x6CC4, 0x9F95, 0x6CC5, 0x9F9A, + 0x6CC9, 0x90F2, 0x6CCA, 0x9491, 0x6CCC, 0x94E5, 0x6CD3, 0x9F97, 0x6CD5, 0x9640, 0x6CD7, 0x9F99, 0x6CD9, 0x9FA2, 0x6CDA, 0xFAF9, + 0x6CDB, 0x9FA0, 0x6CDD, 0x9F9B, 0x6CE1, 0x9641, 0x6CE2, 0x9467, 0x6CE3, 0x8B83, 0x6CE5, 0x9344, 0x6CE8, 0x928D, 0x6CEA, 0x9FA3, + 0x6CEF, 0x9FA1, 0x6CF0, 0x91D7, 0x6CF1, 0x9F96, 0x6CF3, 0x896A, 0x6D04, 0xFAFA, 0x6D0B, 0x976D, 0x6D0C, 0x9FAE, 0x6D12, 0x9FAD, + 0x6D17, 0x90F4, 0x6D19, 0x9FAA, 0x6D1B, 0x978C, 0x6D1E, 0x93B4, 0x6D1F, 0x9FA4, 0x6D25, 0x92C3, 0x6D29, 0x896B, 0x6D2A, 0x8D5E, + 0x6D2B, 0x9FA7, 0x6D32, 0x8F46, 0x6D33, 0x9FAC, 0x6D35, 0x9FAB, 0x6D36, 0x9FA6, 0x6D38, 0x9FA9, 0x6D3B, 0x8A88, 0x6D3D, 0x9FA8, + 0x6D3E, 0x9468, 0x6D41, 0x97AC, 0x6D44, 0x8FF2, 0x6D45, 0x90F3, 0x6D59, 0x9FB4, 0x6D5A, 0x9FB2, 0x6D5C, 0x956C, 0x6D63, 0x9FAF, + 0x6D64, 0x9FB1, 0x6D66, 0x8959, 0x6D69, 0x8D5F, 0x6D6A, 0x9851, 0x6D6C, 0x8A5C, 0x6D6E, 0x9582, 0x6D6F, 0xFAFC, 0x6D74, 0x9781, + 0x6D77, 0x8A43, 0x6D78, 0x905A, 0x6D79, 0x9FB3, 0x6D85, 0x9FB8, 0x6D87, 0xFAFB, 0x6D88, 0x8FC1, 0x6D8C, 0x974F, 0x6D8E, 0x9FB5, + 0x6D93, 0x9FB0, 0x6D95, 0x9FB6, 0x6D96, 0xFB40, 0x6D99, 0x97DC, 0x6D9B, 0x9393, 0x6D9C, 0x93C0, 0x6DAC, 0xFB41, 0x6DAF, 0x8A55, + 0x6DB2, 0x8974, 0x6DB5, 0x9FBC, 0x6DB8, 0x9FBF, 0x6DBC, 0x97C1, 0x6DC0, 0x9784, 0x6DC5, 0x9FC6, 0x6DC6, 0x9FC0, 0x6DC7, 0x9FBD, + 0x6DCB, 0x97D2, 0x6DCC, 0x9FC3, 0x6DCF, 0xFB42, 0x6DD1, 0x8F69, 0x6DD2, 0x9FC5, 0x6DD5, 0x9FCA, 0x6DD8, 0x9391, 0x6DD9, 0x9FC8, + 0x6DDE, 0x9FC2, 0x6DE1, 0x9257, 0x6DE4, 0x9FC9, 0x6DE6, 0x9FBE, 0x6DE8, 0x9FC4, 0x6DEA, 0x9FCB, 0x6DEB, 0x88FA, 0x6DEC, 0x9FC1, + 0x6DEE, 0x9FCC, 0x6DF1, 0x905B, 0x6DF2, 0xFB44, 0x6DF3, 0x8F7E, 0x6DF5, 0x95A3, 0x6DF7, 0x8DAC, 0x6DF8, 0xFB43, 0x6DF9, 0x9FB9, + 0x6DFA, 0x9FC7, 0x6DFB, 0x9359, 0x6DFC, 0xFB45, 0x6E05, 0x90B4, 0x6E07, 0x8A89, 0x6E08, 0x8DCF, 0x6E09, 0x8FC2, 0x6E0A, 0x9FBB, + 0x6E0B, 0x8F61, 0x6E13, 0x8C6B, 0x6E15, 0x9FBA, 0x6E19, 0x9FD0, 0x6E1A, 0x8F8D, 0x6E1B, 0x8CB8, 0x6E1D, 0x9FDF, 0x6E1F, 0x9FD9, + 0x6E20, 0x8B94, 0x6E21, 0x936E, 0x6E23, 0x9FD4, 0x6E24, 0x9FDD, 0x6E25, 0x88AD, 0x6E26, 0x8951, 0x6E27, 0xFB48, 0x6E29, 0x89B7, + 0x6E2B, 0x9FD6, 0x6E2C, 0x91AA, 0x6E2D, 0x9FCD, 0x6E2E, 0x9FCF, 0x6E2F, 0x8D60, 0x6E38, 0x9FE0, 0x6E39, 0xFB46, 0x6E3A, 0x9FDB, + 0x6E3C, 0xFB49, 0x6E3E, 0x9FD3, 0x6E43, 0x9FDA, 0x6E4A, 0x96A9, 0x6E4D, 0x9FD8, 0x6E4E, 0x9FDC, 0x6E56, 0x8CCE, 0x6E58, 0x8FC3, + 0x6E5B, 0x9258, 0x6E5C, 0xFB47, 0x6E5F, 0x9FD2, 0x6E67, 0x974E, 0x6E6B, 0x9FD5, 0x6E6E, 0x9FCE, 0x6E6F, 0x9392, 0x6E72, 0x9FD1, + 0x6E76, 0x9FD7, 0x6E7E, 0x9870, 0x6E7F, 0x8EBC, 0x6E80, 0x969E, 0x6E82, 0x9FE1, 0x6E8C, 0x94AC, 0x6E8F, 0x9FED, 0x6E90, 0x8CB9, + 0x6E96, 0x8F80, 0x6E98, 0x9FE3, 0x6E9C, 0x97AD, 0x6E9D, 0x8D61, 0x6E9F, 0x9FF0, 0x6EA2, 0x88EC, 0x6EA5, 0x9FEE, 0x6EAA, 0x9FE2, + 0x6EAF, 0x9FE8, 0x6EB2, 0x9FEA, 0x6EB6, 0x976E, 0x6EB7, 0x9FE5, 0x6EBA, 0x934D, 0x6EBD, 0x9FE7, 0x6EBF, 0xFB4A, 0x6EC2, 0x9FEF, + 0x6EC4, 0x9FE9, 0x6EC5, 0x96C5, 0x6EC9, 0x9FE4, 0x6ECB, 0x8EA0, 0x6ECC, 0x9FFC, 0x6ED1, 0x8A8A, 0x6ED3, 0x9FE6, 0x6ED4, 0x9FEB, + 0x6ED5, 0x9FEC, 0x6EDD, 0x91EA, 0x6EDE, 0x91D8, 0x6EEC, 0x9FF4, 0x6EEF, 0x9FFA, 0x6EF2, 0x9FF8, 0x6EF4, 0x9348, 0x6EF7, 0xE042, + 0x6EF8, 0x9FF5, 0x6EFE, 0x9FF6, 0x6EFF, 0x9FDE, 0x6F01, 0x8B99, 0x6F02, 0x9559, 0x6F06, 0x8EBD, 0x6F09, 0x8D97, 0x6F0F, 0x9852, + 0x6F11, 0x9FF2, 0x6F13, 0xE041, 0x6F14, 0x8989, 0x6F15, 0x9186, 0x6F20, 0x9499, 0x6F22, 0x8ABF, 0x6F23, 0x97F8, 0x6F2B, 0x969F, + 0x6F2C, 0x92D0, 0x6F31, 0x9FF9, 0x6F32, 0x9FFB, 0x6F38, 0x9151, 0x6F3E, 0xE040, 0x6F3F, 0x9FF7, 0x6F41, 0x9FF1, 0x6F45, 0x8AC1, + 0x6F54, 0x8C89, 0x6F58, 0xE04E, 0x6F5B, 0xE049, 0x6F5C, 0x90F6, 0x6F5F, 0x8A83, 0x6F64, 0x8F81, 0x6F66, 0xE052, 0x6F6D, 0xE04B, + 0x6F6E, 0x92AA, 0x6F6F, 0xE048, 0x6F70, 0x92D7, 0x6F74, 0xE06B, 0x6F78, 0xE045, 0x6F7A, 0xE044, 0x6F7C, 0xE04D, 0x6F80, 0xE047, + 0x6F81, 0xE046, 0x6F82, 0xE04C, 0x6F84, 0x909F, 0x6F86, 0xE043, 0x6F88, 0xFB4B, 0x6F8E, 0xE04F, 0x6F91, 0xE050, 0x6F97, 0x8AC0, + 0x6FA1, 0xE055, 0x6FA3, 0xE054, 0x6FA4, 0xE056, 0x6FAA, 0xE059, 0x6FB1, 0x9362, 0x6FB3, 0xE053, 0x6FB5, 0xFB4C, 0x6FB9, 0xE057, + 0x6FC0, 0x8C83, 0x6FC1, 0x91F7, 0x6FC2, 0xE051, 0x6FC3, 0x945A, 0x6FC6, 0xE058, 0x6FD4, 0xE05D, 0x6FD5, 0xE05B, 0x6FD8, 0xE05E, + 0x6FDB, 0xE061, 0x6FDF, 0xE05A, 0x6FE0, 0x8D8A, 0x6FE1, 0x9447, 0x6FE4, 0x9FB7, 0x6FEB, 0x9794, 0x6FEC, 0xE05C, 0x6FEE, 0xE060, + 0x6FEF, 0x91F3, 0x6FF1, 0xE05F, 0x6FF3, 0xE04A, 0x6FF5, 0xFB4D, 0x6FF6, 0xE889, 0x6FFA, 0xE064, 0x6FFE, 0xE068, 0x7001, 0xE066, + 0x7005, 0xFB4E, 0x7007, 0xFB4F, 0x7009, 0xE062, 0x700B, 0xE063, 0x700F, 0xE067, 0x7011, 0xE065, 0x7015, 0x956D, 0x7018, 0xE06D, + 0x701A, 0xE06A, 0x701B, 0xE069, 0x701D, 0xE06C, 0x701E, 0x93D2, 0x701F, 0xE06E, 0x7026, 0x9295, 0x7027, 0x91EB, 0x7028, 0xFB50, + 0x702C, 0x90A3, 0x7030, 0xE06F, 0x7032, 0xE071, 0x703E, 0xE070, 0x704C, 0x9FF3, 0x7051, 0xE072, 0x7058, 0x93E5, 0x7063, 0xE073, + 0x706B, 0x89CE, 0x706F, 0x9394, 0x7070, 0x8A44, 0x7078, 0x8B84, 0x707C, 0x8EDC, 0x707D, 0x8DD0, 0x7085, 0xFB51, 0x7089, 0x9846, + 0x708A, 0x9086, 0x708E, 0x898A, 0x7092, 0xE075, 0x7099, 0xE074, 0x70AB, 0xFB52, 0x70AC, 0xE078, 0x70AD, 0x9259, 0x70AE, 0xE07B, + 0x70AF, 0xE076, 0x70B3, 0xE07A, 0x70B8, 0xE079, 0x70B9, 0x935F, 0x70BA, 0x88D7, 0x70BB, 0xFA62, 0x70C8, 0x97F3, 0x70CB, 0xE07D, + 0x70CF, 0x8947, 0x70D9, 0xE080, 0x70DD, 0xE07E, 0x70DF, 0xE07C, 0x70F1, 0xE077, 0x70F9, 0x9642, 0x70FD, 0xE082, 0x7104, 0xFB54, + 0x7109, 0xE081, 0x710F, 0xFB53, 0x7114, 0x898B, 0x7119, 0xE084, 0x711A, 0x95B0, 0x711C, 0xE083, 0x7121, 0x96B3, 0x7126, 0x8FC5, + 0x7136, 0x9152, 0x713C, 0x8FC4, 0x7146, 0xFB56, 0x7147, 0xFB57, 0x7149, 0x97F9, 0x714C, 0xE08A, 0x714E, 0x90F7, 0x7155, 0xE086, + 0x7156, 0xE08B, 0x7159, 0x898C, 0x715C, 0xFB55, 0x7162, 0xE089, 0x7164, 0x9481, 0x7165, 0xE085, 0x7166, 0xE088, 0x7167, 0x8FC6, + 0x7169, 0x94CF, 0x716C, 0xE08C, 0x716E, 0x8ECF, 0x717D, 0x90F8, 0x7184, 0xE08F, 0x7188, 0xE087, 0x718A, 0x8C46, 0x718F, 0xE08D, + 0x7194, 0x976F, 0x7195, 0xE090, 0x7199, 0xEAA4, 0x719F, 0x8F6E, 0x71A8, 0xE091, 0x71AC, 0xE092, 0x71B1, 0x944D, 0x71B9, 0xE094, + 0x71BE, 0xE095, 0x71C1, 0xFB59, 0x71C3, 0x9452, 0x71C8, 0x9395, 0x71C9, 0xE097, 0x71CE, 0xE099, 0x71D0, 0x97D3, 0x71D2, 0xE096, + 0x71D4, 0xE098, 0x71D5, 0x898D, 0x71D7, 0xE093, 0x71DF, 0x9A7A, 0x71E0, 0xE09A, 0x71E5, 0x9187, 0x71E6, 0x8E57, 0x71E7, 0xE09C, + 0x71EC, 0xE09B, 0x71ED, 0x9043, 0x71EE, 0x99D7, 0x71F5, 0xE09D, 0x71F9, 0xE09F, 0x71FB, 0xE08E, 0x71FC, 0xE09E, 0x71FE, 0xFB5A, + 0x71FF, 0xE0A0, 0x7206, 0x949A, 0x720D, 0xE0A1, 0x7210, 0xE0A2, 0x721B, 0xE0A3, 0x7228, 0xE0A4, 0x722A, 0x92DC, 0x722C, 0xE0A6, + 0x722D, 0xE0A5, 0x7230, 0xE0A7, 0x7232, 0xE0A8, 0x7235, 0x8EDD, 0x7236, 0x9583, 0x723A, 0x96EA, 0x723B, 0xE0A9, 0x723C, 0xE0AA, + 0x723D, 0x9175, 0x723E, 0x8EA2, 0x723F, 0xE0AB, 0x7240, 0xE0AC, 0x7246, 0xE0AD, 0x7247, 0x95D0, 0x7248, 0x94C5, 0x724B, 0xE0AE, + 0x724C, 0x9476, 0x7252, 0x92AB, 0x7258, 0xE0AF, 0x7259, 0x89E5, 0x725B, 0x8B8D, 0x725D, 0x96C4, 0x725F, 0x96B4, 0x7261, 0x89B2, + 0x7262, 0x9853, 0x7267, 0x9671, 0x7269, 0x95A8, 0x7272, 0x90B5, 0x7274, 0xE0B0, 0x7279, 0x93C1, 0x727D, 0x8CA1, 0x727E, 0xE0B1, + 0x7280, 0x8DD2, 0x7281, 0xE0B3, 0x7282, 0xE0B2, 0x7287, 0xE0B4, 0x7292, 0xE0B5, 0x7296, 0xE0B6, 0x72A0, 0x8B5D, 0x72A2, 0xE0B7, + 0x72A7, 0xE0B8, 0x72AC, 0x8CA2, 0x72AF, 0x94C6, 0x72B1, 0xFB5B, 0x72B2, 0xE0BA, 0x72B6, 0x8FF3, 0x72B9, 0xE0B9, 0x72BE, 0xFB5C, + 0x72C2, 0x8BB6, 0x72C3, 0xE0BB, 0x72C4, 0xE0BD, 0x72C6, 0xE0BC, 0x72CE, 0xE0BE, 0x72D0, 0x8CCF, 0x72D2, 0xE0BF, 0x72D7, 0x8BE7, + 0x72D9, 0x915F, 0x72DB, 0x8D9D, 0x72E0, 0xE0C1, 0x72E1, 0xE0C2, 0x72E2, 0xE0C0, 0x72E9, 0x8EEB, 0x72EC, 0x93C6, 0x72ED, 0x8BB7, + 0x72F7, 0xE0C4, 0x72F8, 0x924B, 0x72F9, 0xE0C3, 0x72FC, 0x9854, 0x72FD, 0x9482, 0x730A, 0xE0C7, 0x7316, 0xE0C9, 0x7317, 0xE0C6, + 0x731B, 0x96D2, 0x731C, 0xE0C8, 0x731D, 0xE0CA, 0x731F, 0x97C2, 0x7324, 0xFB5D, 0x7325, 0xE0CE, 0x7329, 0xE0CD, 0x732A, 0x9296, + 0x732B, 0x944C, 0x732E, 0x8CA3, 0x732F, 0xE0CC, 0x7334, 0xE0CB, 0x7336, 0x9750, 0x7337, 0x9751, 0x733E, 0xE0CF, 0x733F, 0x898E, + 0x7344, 0x8D96, 0x7345, 0x8E82, 0x734E, 0xE0D0, 0x734F, 0xE0D1, 0x7357, 0xE0D3, 0x7363, 0x8F62, 0x7368, 0xE0D5, 0x736A, 0xE0D4, + 0x7370, 0xE0D6, 0x7372, 0x8A6C, 0x7375, 0xE0D8, 0x7377, 0xFB5F, 0x7378, 0xE0D7, 0x737A, 0xE0DA, 0x737B, 0xE0D9, 0x7384, 0x8CBA, + 0x7387, 0x97A6, 0x7389, 0x8BCA, 0x738B, 0x89A4, 0x7396, 0x8BE8, 0x73A9, 0x8ADF, 0x73B2, 0x97E6, 0x73B3, 0xE0DC, 0x73BB, 0xE0DE, + 0x73BD, 0xFB60, 0x73C0, 0xE0DF, 0x73C2, 0x89CF, 0x73C8, 0xE0DB, 0x73C9, 0xFB61, 0x73CA, 0x8E58, 0x73CD, 0x92BF, 0x73CE, 0xE0DD, + 0x73D2, 0xFB64, 0x73D6, 0xFB62, 0x73DE, 0xE0E2, 0x73E0, 0x8EEC, 0x73E3, 0xFB63, 0x73E5, 0xE0E0, 0x73EA, 0x8C5D, 0x73ED, 0x94C7, + 0x73EE, 0xE0E1, 0x73F1, 0xE0FC, 0x73F5, 0xFB66, 0x73F8, 0xE0E7, 0x73FE, 0x8CBB, 0x7403, 0x8B85, 0x7405, 0xE0E4, 0x7406, 0x979D, + 0x7407, 0xFB65, 0x7409, 0x97AE, 0x7422, 0x91F4, 0x7425, 0xE0E6, 0x7426, 0xFB67, 0x7429, 0xFB69, 0x742A, 0xFB68, 0x742E, 0xFB6A, + 0x7432, 0xE0E8, 0x7433, 0x97D4, 0x7434, 0x8BD5, 0x7435, 0x94FA, 0x7436, 0x9469, 0x743A, 0xE0E9, 0x743F, 0xE0EB, 0x7441, 0xE0EE, + 0x7455, 0xE0EA, 0x7459, 0xE0ED, 0x745A, 0x8CE8, 0x745B, 0x896C, 0x745C, 0xE0EF, 0x745E, 0x9090, 0x745F, 0xE0EC, 0x7460, 0x97DA, + 0x7462, 0xFB6B, 0x7463, 0xE0F2, 0x7464, 0xEAA2, 0x7469, 0xE0F0, 0x746A, 0xE0F3, 0x746F, 0xE0E5, 0x7470, 0xE0F1, 0x7473, 0x8DBA, + 0x7476, 0xE0F4, 0x747E, 0xE0F5, 0x7483, 0x979E, 0x7489, 0xFB6C, 0x748B, 0xE0F6, 0x749E, 0xE0F7, 0x749F, 0xFB6D, 0x74A2, 0xE0E3, + 0x74A7, 0xE0F8, 0x74B0, 0x8AC2, 0x74BD, 0x8EA3, 0x74CA, 0xE0F9, 0x74CF, 0xE0FA, 0x74D4, 0xE0FB, 0x74DC, 0x895A, 0x74E0, 0xE140, + 0x74E2, 0x955A, 0x74E3, 0xE141, 0x74E6, 0x8AA2, 0x74E7, 0xE142, 0x74E9, 0xE143, 0x74EE, 0xE144, 0x74F0, 0xE146, 0x74F1, 0xE147, + 0x74F2, 0xE145, 0x74F6, 0x9572, 0x74F7, 0xE149, 0x74F8, 0xE148, 0x7501, 0xFB6E, 0x7503, 0xE14B, 0x7504, 0xE14A, 0x7505, 0xE14C, + 0x750C, 0xE14D, 0x750D, 0xE14F, 0x750E, 0xE14E, 0x7511, 0x8D99, 0x7513, 0xE151, 0x7515, 0xE150, 0x7518, 0x8AC3, 0x751A, 0x9072, + 0x751C, 0x935B, 0x751E, 0xE152, 0x751F, 0x90B6, 0x7523, 0x8E59, 0x7525, 0x8999, 0x7526, 0xE153, 0x7528, 0x9770, 0x752B, 0x95E1, + 0x752C, 0xE154, 0x752F, 0xFAA8, 0x7530, 0x9363, 0x7531, 0x9752, 0x7532, 0x8D62, 0x7533, 0x905C, 0x7537, 0x926A, 0x7538, 0x99B2, + 0x753A, 0x92AC, 0x753B, 0x89E6, 0x753C, 0xE155, 0x7544, 0xE156, 0x7546, 0xE15B, 0x7549, 0xE159, 0x754A, 0xE158, 0x754B, 0x9DC0, + 0x754C, 0x8A45, 0x754D, 0xE157, 0x754F, 0x88D8, 0x7551, 0x94A8, 0x7554, 0x94C8, 0x7559, 0x97AF, 0x755A, 0xE15C, 0x755B, 0xE15A, + 0x755C, 0x927B, 0x755D, 0x90A4, 0x7560, 0x94A9, 0x7562, 0x954C, 0x7564, 0xE15E, 0x7565, 0x97AA, 0x7566, 0x8C6C, 0x7567, 0xE15F, + 0x7569, 0xE15D, 0x756A, 0x94D4, 0x756B, 0xE160, 0x756D, 0xE161, 0x756F, 0xFB6F, 0x7570, 0x88D9, 0x7573, 0x8FF4, 0x7574, 0xE166, + 0x7576, 0xE163, 0x7577, 0x93EB, 0x7578, 0xE162, 0x757F, 0x8B45, 0x7582, 0xE169, 0x7586, 0xE164, 0x7587, 0xE165, 0x7589, 0xE168, + 0x758A, 0xE167, 0x758B, 0x9544, 0x758E, 0x9161, 0x758F, 0x9160, 0x7591, 0x8B5E, 0x7594, 0xE16A, 0x759A, 0xE16B, 0x759D, 0xE16C, + 0x75A3, 0xE16E, 0x75A5, 0xE16D, 0x75AB, 0x8975, 0x75B1, 0xE176, 0x75B2, 0x94E6, 0x75B3, 0xE170, 0x75B5, 0xE172, 0x75B8, 0xE174, + 0x75B9, 0x905D, 0x75BC, 0xE175, 0x75BD, 0xE173, 0x75BE, 0x8EBE, 0x75C2, 0xE16F, 0x75C3, 0xE171, 0x75C5, 0x9561, 0x75C7, 0x8FC7, + 0x75CA, 0xE178, 0x75CD, 0xE177, 0x75D2, 0xE179, 0x75D4, 0x8EA4, 0x75D5, 0x8DAD, 0x75D8, 0x9397, 0x75D9, 0xE17A, 0x75DB, 0x92C9, + 0x75DE, 0xE17C, 0x75E2, 0x979F, 0x75E3, 0xE17B, 0x75E9, 0x9189, 0x75F0, 0xE182, 0x75F2, 0xE184, 0x75F3, 0xE185, 0x75F4, 0x9273, + 0x75FA, 0xE183, 0x75FC, 0xE180, 0x75FE, 0xE17D, 0x75FF, 0xE17E, 0x7601, 0xE181, 0x7609, 0xE188, 0x760B, 0xE186, 0x760D, 0xE187, + 0x761F, 0xE189, 0x7620, 0xE18B, 0x7621, 0xE18C, 0x7622, 0xE18D, 0x7624, 0xE18E, 0x7627, 0xE18A, 0x7630, 0xE190, 0x7634, 0xE18F, + 0x763B, 0xE191, 0x7642, 0x97C3, 0x7646, 0xE194, 0x7647, 0xE192, 0x7648, 0xE193, 0x764C, 0x8AE0, 0x7652, 0x96FC, 0x7656, 0x95C8, + 0x7658, 0xE196, 0x765C, 0xE195, 0x7661, 0xE197, 0x7662, 0xE198, 0x7667, 0xE19C, 0x7668, 0xE199, 0x7669, 0xE19A, 0x766A, 0xE19B, + 0x766C, 0xE19D, 0x7670, 0xE19E, 0x7672, 0xE19F, 0x7676, 0xE1A0, 0x7678, 0xE1A1, 0x767A, 0x94AD, 0x767B, 0x936F, 0x767C, 0xE1A2, + 0x767D, 0x9492, 0x767E, 0x9553, 0x7680, 0xE1A3, 0x7682, 0xFB70, 0x7683, 0xE1A4, 0x7684, 0x9349, 0x7686, 0x8A46, 0x7687, 0x8D63, + 0x7688, 0xE1A5, 0x768B, 0xE1A6, 0x768E, 0xE1A7, 0x7690, 0x8E48, 0x7693, 0xE1A9, 0x7696, 0xE1A8, 0x7699, 0xE1AA, 0x769A, 0xE1AB, + 0x769B, 0xFB73, 0x769C, 0xFB71, 0x769E, 0xFB72, 0x76A6, 0xFB74, 0x76AE, 0x94E7, 0x76B0, 0xE1AC, 0x76B4, 0xE1AD, 0x76B7, 0xEA89, + 0x76B8, 0xE1AE, 0x76B9, 0xE1AF, 0x76BA, 0xE1B0, 0x76BF, 0x8E4D, 0x76C2, 0xE1B1, 0x76C3, 0x9475, 0x76C6, 0x967E, 0x76C8, 0x896D, + 0x76CA, 0x8976, 0x76CD, 0xE1B2, 0x76D2, 0xE1B4, 0x76D6, 0xE1B3, 0x76D7, 0x9390, 0x76DB, 0x90B7, 0x76DC, 0x9F58, 0x76DE, 0xE1B5, + 0x76DF, 0x96BF, 0x76E1, 0xE1B6, 0x76E3, 0x8AC4, 0x76E4, 0x94D5, 0x76E5, 0xE1B7, 0x76E7, 0xE1B8, 0x76EA, 0xE1B9, 0x76EE, 0x96DA, + 0x76F2, 0x96D3, 0x76F4, 0x92BC, 0x76F8, 0x918A, 0x76FB, 0xE1BB, 0x76FE, 0x8F82, 0x7701, 0x8FC8, 0x7704, 0xE1BE, 0x7707, 0xE1BD, + 0x7708, 0xE1BC, 0x7709, 0x94FB, 0x770B, 0x8AC5, 0x770C, 0x8CA7, 0x771B, 0xE1C4, 0x771E, 0xE1C1, 0x771F, 0x905E, 0x7720, 0x96B0, + 0x7724, 0xE1C0, 0x7725, 0xE1C2, 0x7726, 0xE1C3, 0x7729, 0xE1BF, 0x7737, 0xE1C5, 0x7738, 0xE1C6, 0x773A, 0x92AD, 0x773C, 0x8AE1, + 0x7740, 0x9285, 0x7746, 0xFB76, 0x7747, 0xE1C7, 0x775A, 0xE1C8, 0x775B, 0xE1CB, 0x7761, 0x9087, 0x7763, 0x93C2, 0x7765, 0xE1CC, + 0x7766, 0x9672, 0x7768, 0xE1C9, 0x776B, 0xE1CA, 0x7779, 0xE1CF, 0x777E, 0xE1CE, 0x777F, 0xE1CD, 0x778B, 0xE1D1, 0x778E, 0xE1D0, + 0x7791, 0xE1D2, 0x779E, 0xE1D4, 0x77A0, 0xE1D3, 0x77A5, 0x95CB, 0x77AC, 0x8F75, 0x77AD, 0x97C4, 0x77B0, 0xE1D5, 0x77B3, 0x93B5, + 0x77B6, 0xE1D6, 0x77B9, 0xE1D7, 0x77BB, 0xE1DB, 0x77BC, 0xE1D9, 0x77BD, 0xE1DA, 0x77BF, 0xE1D8, 0x77C7, 0xE1DC, 0x77CD, 0xE1DD, + 0x77D7, 0xE1DE, 0x77DA, 0xE1DF, 0x77DB, 0x96B5, 0x77DC, 0xE1E0, 0x77E2, 0x96EE, 0x77E3, 0xE1E1, 0x77E5, 0x926D, 0x77E7, 0x948A, + 0x77E9, 0x8BE9, 0x77ED, 0x925A, 0x77EE, 0xE1E2, 0x77EF, 0x8BB8, 0x77F3, 0x90CE, 0x77FC, 0xE1E3, 0x7802, 0x8DBB, 0x780C, 0xE1E4, + 0x7812, 0xE1E5, 0x7814, 0x8CA4, 0x7815, 0x8DD3, 0x7820, 0xE1E7, 0x7821, 0xFB78, 0x7825, 0x9375, 0x7826, 0x8DD4, 0x7827, 0x8B6D, + 0x7832, 0x9643, 0x7834, 0x946A, 0x783A, 0x9376, 0x783F, 0x8D7B, 0x7845, 0xE1E9, 0x784E, 0xFB79, 0x785D, 0x8FC9, 0x7864, 0xFB7A, + 0x786B, 0x97B0, 0x786C, 0x8D64, 0x786F, 0x8CA5, 0x7872, 0x94A1, 0x7874, 0xE1EB, 0x787A, 0xFB7B, 0x787C, 0xE1ED, 0x7881, 0x8CE9, + 0x7886, 0xE1EC, 0x7887, 0x92F4, 0x788C, 0xE1EF, 0x788D, 0x8A56, 0x788E, 0xE1EA, 0x7891, 0x94E8, 0x7893, 0x894F, 0x7895, 0x8DEA, + 0x7897, 0x9871, 0x789A, 0xE1EE, 0x78A3, 0xE1F0, 0x78A7, 0x95C9, 0x78A9, 0x90D7, 0x78AA, 0xE1F2, 0x78AF, 0xE1F3, 0x78B5, 0xE1F1, + 0x78BA, 0x8A6D, 0x78BC, 0xE1F9, 0x78BE, 0xE1F8, 0x78C1, 0x8EA5, 0x78C5, 0xE1FA, 0x78C6, 0xE1F5, 0x78CA, 0xE1FB, 0x78CB, 0xE1F6, + 0x78D0, 0x94D6, 0x78D1, 0xE1F4, 0x78D4, 0xE1F7, 0x78DA, 0xE241, 0x78E7, 0xE240, 0x78E8, 0x9681, 0x78EC, 0xE1FC, 0x78EF, 0x88E9, + 0x78F4, 0xE243, 0x78FD, 0xE242, 0x7901, 0x8FCA, 0x7907, 0xE244, 0x790E, 0x9162, 0x7911, 0xE246, 0x7912, 0xE245, 0x7919, 0xE247, + 0x7926, 0xE1E6, 0x792A, 0xE1E8, 0x792B, 0xE249, 0x792C, 0xE248, 0x7930, 0xFB7C, 0x793A, 0x8EA6, 0x793C, 0x97E7, 0x793E, 0x8ED0, + 0x7940, 0xE24A, 0x7941, 0x8C56, 0x7947, 0x8B5F, 0x7948, 0x8B46, 0x7949, 0x8E83, 0x7950, 0x9753, 0x7953, 0xE250, 0x7955, 0xE24F, + 0x7956, 0x9163, 0x7957, 0xE24C, 0x795A, 0xE24E, 0x795D, 0x8F6A, 0x795E, 0x905F, 0x795F, 0xE24D, 0x7960, 0xE24B, 0x7962, 0x9449, + 0x7965, 0x8FCB, 0x7968, 0x955B, 0x796D, 0x8DD5, 0x7977, 0x9398, 0x797A, 0xE251, 0x797F, 0xE252, 0x7980, 0xE268, 0x7981, 0x8BD6, + 0x7984, 0x985C, 0x7985, 0x9154, 0x798A, 0xE253, 0x798D, 0x89D0, 0x798E, 0x92F5, 0x798F, 0x959F, 0x7994, 0xFB81, 0x799B, 0xFB83, + 0x799D, 0xE254, 0x79A6, 0x8B9A, 0x79A7, 0xE255, 0x79AA, 0xE257, 0x79AE, 0xE258, 0x79B0, 0x9448, 0x79B3, 0xE259, 0x79B9, 0xE25A, + 0x79BA, 0xE25B, 0x79BD, 0x8BD7, 0x79BE, 0x89D1, 0x79BF, 0x93C3, 0x79C0, 0x8F47, 0x79C1, 0x8E84, 0x79C9, 0xE25C, 0x79CB, 0x8F48, + 0x79D1, 0x89C8, 0x79D2, 0x9562, 0x79D5, 0xE25D, 0x79D8, 0x94E9, 0x79DF, 0x9164, 0x79E1, 0xE260, 0x79E3, 0xE261, 0x79E4, 0x9489, + 0x79E6, 0x9060, 0x79E7, 0xE25E, 0x79E9, 0x9281, 0x79EC, 0xE25F, 0x79F0, 0x8FCC, 0x79FB, 0x88DA, 0x7A00, 0x8B48, 0x7A08, 0xE262, + 0x7A0B, 0x92F6, 0x7A0D, 0xE263, 0x7A0E, 0x90C5, 0x7A14, 0x96AB, 0x7A17, 0x9542, 0x7A18, 0xE264, 0x7A19, 0xE265, 0x7A1A, 0x9274, + 0x7A1C, 0x97C5, 0x7A1F, 0xE267, 0x7A20, 0xE266, 0x7A2E, 0x8EED, 0x7A31, 0xE269, 0x7A32, 0x88EE, 0x7A37, 0xE26C, 0x7A3B, 0xE26A, + 0x7A3C, 0x89D2, 0x7A3D, 0x8C6D, 0x7A3E, 0xE26B, 0x7A3F, 0x8D65, 0x7A40, 0x8D92, 0x7A42, 0x95E4, 0x7A43, 0xE26D, 0x7A46, 0x9673, + 0x7A49, 0xE26F, 0x7A4D, 0x90CF, 0x7A4E, 0x896E, 0x7A4F, 0x89B8, 0x7A50, 0x88AA, 0x7A57, 0xE26E, 0x7A61, 0xE270, 0x7A62, 0xE271, + 0x7A63, 0x8FF5, 0x7A69, 0xE272, 0x7A6B, 0x8A6E, 0x7A70, 0xE274, 0x7A74, 0x8C8A, 0x7A76, 0x8B86, 0x7A79, 0xE275, 0x7A7A, 0x8BF3, + 0x7A7D, 0xE276, 0x7A7F, 0x90FA, 0x7A81, 0x93CB, 0x7A83, 0x90DE, 0x7A84, 0x8DF3, 0x7A88, 0xE277, 0x7A92, 0x9282, 0x7A93, 0x918B, + 0x7A95, 0xE279, 0x7A96, 0xE27B, 0x7A97, 0xE278, 0x7A98, 0xE27A, 0x7A9F, 0x8C41, 0x7AA9, 0xE27C, 0x7AAA, 0x8C45, 0x7AAE, 0x8B87, + 0x7AAF, 0x9771, 0x7AB0, 0xE27E, 0x7AB6, 0xE280, 0x7ABA, 0x894D, 0x7ABF, 0xE283, 0x7AC3, 0x8A96, 0x7AC4, 0xE282, 0x7AC5, 0xE281, + 0x7AC7, 0xE285, 0x7AC8, 0xE27D, 0x7ACA, 0xE286, 0x7ACB, 0x97A7, 0x7ACD, 0xE287, 0x7ACF, 0xE288, 0x7AD1, 0xFB84, 0x7AD2, 0x9AF2, + 0x7AD3, 0xE28A, 0x7AD5, 0xE289, 0x7AD9, 0xE28B, 0x7ADA, 0xE28C, 0x7ADC, 0x97B3, 0x7ADD, 0xE28D, 0x7ADF, 0xE8ED, 0x7AE0, 0x8FCD, + 0x7AE1, 0xE28E, 0x7AE2, 0xE28F, 0x7AE3, 0x8F76, 0x7AE5, 0x93B6, 0x7AE6, 0xE290, 0x7AE7, 0xFB85, 0x7AEA, 0x9247, 0x7AEB, 0xFB87, + 0x7AED, 0xE291, 0x7AEF, 0x925B, 0x7AF0, 0xE292, 0x7AF6, 0x8BA3, 0x7AF8, 0x995E, 0x7AF9, 0x927C, 0x7AFA, 0x8EB1, 0x7AFF, 0x8AC6, + 0x7B02, 0xE293, 0x7B04, 0xE2A0, 0x7B06, 0xE296, 0x7B08, 0x8B88, 0x7B0A, 0xE295, 0x7B0B, 0xE2A2, 0x7B0F, 0xE294, 0x7B11, 0x8FCE, + 0x7B18, 0xE298, 0x7B19, 0xE299, 0x7B1B, 0x934A, 0x7B1E, 0xE29A, 0x7B20, 0x8A7D, 0x7B25, 0x9079, 0x7B26, 0x9584, 0x7B28, 0xE29C, + 0x7B2C, 0x91E6, 0x7B33, 0xE297, 0x7B35, 0xE29B, 0x7B36, 0xE29D, 0x7B39, 0x8DF9, 0x7B45, 0xE2A4, 0x7B46, 0x954D, 0x7B48, 0x94A4, + 0x7B49, 0x9399, 0x7B4B, 0x8BD8, 0x7B4C, 0xE2A3, 0x7B4D, 0xE2A1, 0x7B4F, 0x94B3, 0x7B50, 0xE29E, 0x7B51, 0x927D, 0x7B52, 0x939B, + 0x7B54, 0x939A, 0x7B56, 0x8DF4, 0x7B5D, 0xE2B6, 0x7B65, 0xE2A6, 0x7B67, 0xE2A8, 0x7B6C, 0xE2AB, 0x7B6E, 0xE2AC, 0x7B70, 0xE2A9, + 0x7B71, 0xE2AA, 0x7B74, 0xE2A7, 0x7B75, 0xE2A5, 0x7B7A, 0xE29F, 0x7B86, 0x95CD, 0x7B87, 0x89D3, 0x7B8B, 0xE2B3, 0x7B8D, 0xE2B0, + 0x7B8F, 0xE2B5, 0x7B92, 0xE2B4, 0x7B94, 0x9493, 0x7B95, 0x96A5, 0x7B97, 0x8E5A, 0x7B98, 0xE2AE, 0x7B99, 0xE2B7, 0x7B9A, 0xE2B2, + 0x7B9C, 0xE2B1, 0x7B9D, 0xE2AD, 0x7B9E, 0xFB88, 0x7B9F, 0xE2AF, 0x7BA1, 0x8AC7, 0x7BAA, 0x925C, 0x7BAD, 0x90FB, 0x7BB1, 0x94A0, + 0x7BB4, 0xE2BC, 0x7BB8, 0x94A2, 0x7BC0, 0x90DF, 0x7BC1, 0xE2B9, 0x7BC4, 0x94CD, 0x7BC6, 0xE2BD, 0x7BC7, 0x95D1, 0x7BC9, 0x927A, + 0x7BCB, 0xE2B8, 0x7BCC, 0xE2BA, 0x7BCF, 0xE2BB, 0x7BDD, 0xE2BE, 0x7BE0, 0x8EC2, 0x7BE4, 0x93C4, 0x7BE5, 0xE2C3, 0x7BE6, 0xE2C2, + 0x7BE9, 0xE2BF, 0x7BED, 0x9855, 0x7BF3, 0xE2C8, 0x7BF6, 0xE2CC, 0x7BF7, 0xE2C9, 0x7C00, 0xE2C5, 0x7C07, 0xE2C6, 0x7C0D, 0xE2CB, + 0x7C11, 0xE2C0, 0x7C12, 0x99D3, 0x7C13, 0xE2C7, 0x7C14, 0xE2C1, 0x7C17, 0xE2CA, 0x7C1F, 0xE2D0, 0x7C21, 0x8AC8, 0x7C23, 0xE2CD, + 0x7C27, 0xE2CE, 0x7C2A, 0xE2CF, 0x7C2B, 0xE2D2, 0x7C37, 0xE2D1, 0x7C38, 0x94F4, 0x7C3D, 0xE2D3, 0x7C3E, 0x97FA, 0x7C3F, 0x95EB, + 0x7C40, 0xE2D8, 0x7C43, 0xE2D5, 0x7C4C, 0xE2D4, 0x7C4D, 0x90D0, 0x7C4F, 0xE2D7, 0x7C50, 0xE2D9, 0x7C54, 0xE2D6, 0x7C56, 0xE2DD, + 0x7C58, 0xE2DA, 0x7C5F, 0xE2DB, 0x7C60, 0xE2C4, 0x7C64, 0xE2DC, 0x7C65, 0xE2DE, 0x7C6C, 0xE2DF, 0x7C73, 0x95C4, 0x7C75, 0xE2E0, + 0x7C7E, 0x96E0, 0x7C81, 0x8BCC, 0x7C82, 0x8C48, 0x7C83, 0xE2E1, 0x7C89, 0x95B2, 0x7C8B, 0x9088, 0x7C8D, 0x96AE, 0x7C90, 0xE2E2, + 0x7C92, 0x97B1, 0x7C95, 0x9494, 0x7C97, 0x9165, 0x7C98, 0x9453, 0x7C9B, 0x8F6C, 0x7C9F, 0x88BE, 0x7CA1, 0xE2E7, 0x7CA2, 0xE2E5, + 0x7CA4, 0xE2E3, 0x7CA5, 0x8A9F, 0x7CA7, 0x8FCF, 0x7CA8, 0xE2E8, 0x7CAB, 0xE2E6, 0x7CAD, 0xE2E4, 0x7CAE, 0xE2EC, 0x7CB1, 0xE2EB, + 0x7CB2, 0xE2EA, 0x7CB3, 0xE2E9, 0x7CB9, 0xE2ED, 0x7CBD, 0xE2EE, 0x7CBE, 0x90B8, 0x7CC0, 0xE2EF, 0x7CC2, 0xE2F1, 0x7CC5, 0xE2F0, + 0x7CCA, 0x8CD0, 0x7CCE, 0x9157, 0x7CD2, 0xE2F3, 0x7CD6, 0x939C, 0x7CD8, 0xE2F2, 0x7CDC, 0xE2F4, 0x7CDE, 0x95B3, 0x7CDF, 0x918C, + 0x7CE0, 0x8D66, 0x7CE2, 0xE2F5, 0x7CE7, 0x97C6, 0x7CEF, 0xE2F7, 0x7CF2, 0xE2F8, 0x7CF4, 0xE2F9, 0x7CF6, 0xE2FA, 0x7CF8, 0x8E85, + 0x7CFA, 0xE2FB, 0x7CFB, 0x8C6E, 0x7CFE, 0x8B8A, 0x7D00, 0x8B49, 0x7D02, 0xE340, 0x7D04, 0x96F1, 0x7D05, 0x8D67, 0x7D06, 0xE2FC, + 0x7D0A, 0xE343, 0x7D0B, 0x96E4, 0x7D0D, 0x945B, 0x7D10, 0x9552, 0x7D14, 0x8F83, 0x7D15, 0xE342, 0x7D17, 0x8ED1, 0x7D18, 0x8D68, + 0x7D19, 0x8E86, 0x7D1A, 0x8B89, 0x7D1B, 0x95B4, 0x7D1C, 0xE341, 0x7D20, 0x9166, 0x7D21, 0x9661, 0x7D22, 0x8DF5, 0x7D2B, 0x8E87, + 0x7D2C, 0x92DB, 0x7D2E, 0xE346, 0x7D2F, 0x97DD, 0x7D30, 0x8DD7, 0x7D32, 0xE347, 0x7D33, 0x9061, 0x7D35, 0xE349, 0x7D39, 0x8FD0, + 0x7D3A, 0x8DAE, 0x7D3F, 0xE348, 0x7D42, 0x8F49, 0x7D43, 0x8CBC, 0x7D44, 0x9167, 0x7D45, 0xE344, 0x7D46, 0xE34A, 0x7D48, 0xFB8A, + 0x7D4B, 0xE345, 0x7D4C, 0x8C6F, 0x7D4E, 0xE34D, 0x7D4F, 0xE351, 0x7D50, 0x8C8B, 0x7D56, 0xE34C, 0x7D5B, 0xE355, 0x7D5C, 0xFB8B, + 0x7D5E, 0x8D69, 0x7D61, 0x978D, 0x7D62, 0x88BA, 0x7D63, 0xE352, 0x7D66, 0x8B8B, 0x7D68, 0xE34F, 0x7D6E, 0xE350, 0x7D71, 0x939D, + 0x7D72, 0xE34E, 0x7D73, 0xE34B, 0x7D75, 0x8A47, 0x7D76, 0x90E2, 0x7D79, 0x8CA6, 0x7D7D, 0xE357, 0x7D89, 0xE354, 0x7D8F, 0xE356, + 0x7D93, 0xE353, 0x7D99, 0x8C70, 0x7D9A, 0x91B1, 0x7D9B, 0xE358, 0x7D9C, 0x918E, 0x7D9F, 0xE365, 0x7DA0, 0xFB8D, 0x7DA2, 0xE361, + 0x7DA3, 0xE35B, 0x7DAB, 0xE35F, 0x7DAC, 0x8EF8, 0x7DAD, 0x88DB, 0x7DAE, 0xE35A, 0x7DAF, 0xE362, 0x7DB0, 0xE366, 0x7DB1, 0x8D6A, + 0x7DB2, 0x96D4, 0x7DB4, 0x92D4, 0x7DB5, 0xE35C, 0x7DB7, 0xFB8C, 0x7DB8, 0xE364, 0x7DBA, 0xE359, 0x7DBB, 0x925D, 0x7DBD, 0xE35E, + 0x7DBE, 0x88BB, 0x7DBF, 0x96C8, 0x7DC7, 0xE35D, 0x7DCA, 0x8BD9, 0x7DCB, 0x94EA, 0x7DCF, 0x918D, 0x7DD1, 0x97CE, 0x7DD2, 0x8F8F, + 0x7DD5, 0xE38E, 0x7DD6, 0xFB8E, 0x7DD8, 0xE367, 0x7DDA, 0x90FC, 0x7DDC, 0xE363, 0x7DDD, 0xE368, 0x7DDE, 0xE36A, 0x7DE0, 0x92F7, + 0x7DE1, 0xE36D, 0x7DE4, 0xE369, 0x7DE8, 0x95D2, 0x7DE9, 0x8AC9, 0x7DEC, 0x96C9, 0x7DEF, 0x88DC, 0x7DF2, 0xE36C, 0x7DF4, 0x97FB, + 0x7DFB, 0xE36B, 0x7E01, 0x898F, 0x7E04, 0x93EA, 0x7E05, 0xE36E, 0x7E09, 0xE375, 0x7E0A, 0xE36F, 0x7E0B, 0xE376, 0x7E12, 0xE372, + 0x7E1B, 0x949B, 0x7E1E, 0x8EC8, 0x7E1F, 0xE374, 0x7E21, 0xE371, 0x7E22, 0xE377, 0x7E23, 0xE370, 0x7E26, 0x8F63, 0x7E2B, 0x9644, + 0x7E2E, 0x8F6B, 0x7E31, 0xE373, 0x7E32, 0xE380, 0x7E35, 0xE37B, 0x7E37, 0xE37E, 0x7E39, 0xE37C, 0x7E3A, 0xE381, 0x7E3B, 0xE37A, + 0x7E3D, 0xE360, 0x7E3E, 0x90D1, 0x7E41, 0x94C9, 0x7E43, 0xE37D, 0x7E46, 0xE378, 0x7E4A, 0x9140, 0x7E4B, 0x8C71, 0x7E4D, 0x8F4A, + 0x7E52, 0xFB8F, 0x7E54, 0x9044, 0x7E55, 0x9155, 0x7E56, 0xE384, 0x7E59, 0xE386, 0x7E5A, 0xE387, 0x7E5D, 0xE383, 0x7E5E, 0xE385, + 0x7E66, 0xE379, 0x7E67, 0xE382, 0x7E69, 0xE38A, 0x7E6A, 0xE389, 0x7E6D, 0x969A, 0x7E70, 0x8C4A, 0x7E79, 0xE388, 0x7E7B, 0xE38C, + 0x7E7C, 0xE38B, 0x7E7D, 0xE38F, 0x7E7F, 0xE391, 0x7E82, 0x8E5B, 0x7E83, 0xE38D, 0x7E88, 0xE392, 0x7E89, 0xE393, 0x7E8A, 0xFA5C, + 0x7E8C, 0xE394, 0x7E8E, 0xE39A, 0x7E8F, 0x935A, 0x7E90, 0xE396, 0x7E92, 0xE395, 0x7E93, 0xE397, 0x7E94, 0xE398, 0x7E96, 0xE399, + 0x7E9B, 0xE39B, 0x7E9C, 0xE39C, 0x7F36, 0x8ACA, 0x7F38, 0xE39D, 0x7F3A, 0xE39E, 0x7F45, 0xE39F, 0x7F47, 0xFB90, 0x7F4C, 0xE3A0, + 0x7F4D, 0xE3A1, 0x7F4E, 0xE3A2, 0x7F50, 0xE3A3, 0x7F51, 0xE3A4, 0x7F54, 0xE3A6, 0x7F55, 0xE3A5, 0x7F58, 0xE3A7, 0x7F5F, 0xE3A8, + 0x7F60, 0xE3A9, 0x7F67, 0xE3AC, 0x7F68, 0xE3AA, 0x7F69, 0xE3AB, 0x7F6A, 0x8DDF, 0x7F6B, 0x8C72, 0x7F6E, 0x9275, 0x7F70, 0x94B1, + 0x7F72, 0x8F90, 0x7F75, 0x946C, 0x7F77, 0x94EB, 0x7F78, 0xE3AD, 0x7F79, 0x9CEB, 0x7F82, 0xE3AE, 0x7F83, 0xE3B0, 0x7F85, 0x9785, + 0x7F86, 0xE3AF, 0x7F87, 0xE3B2, 0x7F88, 0xE3B1, 0x7F8A, 0x9772, 0x7F8C, 0xE3B3, 0x7F8E, 0x94FC, 0x7F94, 0xE3B4, 0x7F9A, 0xE3B7, + 0x7F9D, 0xE3B6, 0x7F9E, 0xE3B5, 0x7FA1, 0xFB91, 0x7FA3, 0xE3B8, 0x7FA4, 0x8C51, 0x7FA8, 0x9141, 0x7FA9, 0x8B60, 0x7FAE, 0xE3BC, + 0x7FAF, 0xE3B9, 0x7FB2, 0xE3BA, 0x7FB6, 0xE3BD, 0x7FB8, 0xE3BE, 0x7FB9, 0xE3BB, 0x7FBD, 0x8948, 0x7FC1, 0x89A5, 0x7FC5, 0xE3C0, + 0x7FC6, 0xE3C1, 0x7FCA, 0xE3C2, 0x7FCC, 0x9782, 0x7FD2, 0x8F4B, 0x7FD4, 0xE3C4, 0x7FD5, 0xE3C3, 0x7FE0, 0x9089, 0x7FE1, 0xE3C5, + 0x7FE6, 0xE3C6, 0x7FE9, 0xE3C7, 0x7FEB, 0x8AE3, 0x7FF0, 0x8ACB, 0x7FF3, 0xE3C8, 0x7FF9, 0xE3C9, 0x7FFB, 0x967C, 0x7FFC, 0x9783, + 0x8000, 0x9773, 0x8001, 0x9856, 0x8003, 0x8D6C, 0x8004, 0xE3CC, 0x8005, 0x8ED2, 0x8006, 0xE3CB, 0x800B, 0xE3CD, 0x800C, 0x8EA7, + 0x8010, 0x91CF, 0x8012, 0xE3CE, 0x8015, 0x8D6B, 0x8017, 0x96D5, 0x8018, 0xE3CF, 0x8019, 0xE3D0, 0x801C, 0xE3D1, 0x8021, 0xE3D2, + 0x8028, 0xE3D3, 0x8033, 0x8EA8, 0x8036, 0x96EB, 0x803B, 0xE3D5, 0x803D, 0x925E, 0x803F, 0xE3D4, 0x8046, 0xE3D7, 0x804A, 0xE3D6, + 0x8052, 0xE3D8, 0x8056, 0x90B9, 0x8058, 0xE3D9, 0x805A, 0xE3DA, 0x805E, 0x95B7, 0x805F, 0xE3DB, 0x8061, 0x918F, 0x8062, 0xE3DC, + 0x8068, 0xE3DD, 0x806F, 0x97FC, 0x8070, 0xE3E0, 0x8072, 0xE3DF, 0x8073, 0xE3DE, 0x8074, 0x92AE, 0x8076, 0xE3E1, 0x8077, 0x9045, + 0x8079, 0xE3E2, 0x807D, 0xE3E3, 0x807E, 0x9857, 0x807F, 0xE3E4, 0x8084, 0xE3E5, 0x8085, 0xE3E7, 0x8086, 0xE3E6, 0x8087, 0x94A3, + 0x8089, 0x93F7, 0x808B, 0x985D, 0x808C, 0x94A7, 0x8093, 0xE3E9, 0x8096, 0x8FD1, 0x8098, 0x9549, 0x809A, 0xE3EA, 0x809B, 0xE3E8, + 0x809D, 0x8ACC, 0x80A1, 0x8CD2, 0x80A2, 0x8E88, 0x80A5, 0x94EC, 0x80A9, 0x8CA8, 0x80AA, 0x9662, 0x80AC, 0xE3ED, 0x80AD, 0xE3EB, + 0x80AF, 0x8D6D, 0x80B1, 0x8D6E, 0x80B2, 0x88E7, 0x80B4, 0x8DE6, 0x80BA, 0x9478, 0x80C3, 0x88DD, 0x80C4, 0xE3F2, 0x80C6, 0x925F, + 0x80CC, 0x9477, 0x80CE, 0x91D9, 0x80D6, 0xE3F4, 0x80D9, 0xE3F0, 0x80DA, 0xE3F3, 0x80DB, 0xE3EE, 0x80DD, 0xE3F1, 0x80DE, 0x9645, + 0x80E1, 0x8CD3, 0x80E4, 0x88FB, 0x80E5, 0xE3EF, 0x80EF, 0xE3F6, 0x80F1, 0xE3F7, 0x80F4, 0x93B7, 0x80F8, 0x8BB9, 0x80FC, 0xE445, + 0x80FD, 0x945C, 0x8102, 0x8E89, 0x8105, 0x8BBA, 0x8106, 0x90C6, 0x8107, 0x9865, 0x8108, 0x96AC, 0x8109, 0xE3F5, 0x810A, 0x90D2, + 0x811A, 0x8B72, 0x811B, 0xE3F8, 0x8123, 0xE3FA, 0x8129, 0xE3F9, 0x812F, 0xE3FB, 0x8131, 0x9245, 0x8133, 0x945D, 0x8139, 0x92AF, + 0x813E, 0xE442, 0x8146, 0xE441, 0x814B, 0xE3FC, 0x814E, 0x9074, 0x8150, 0x9585, 0x8151, 0xE444, 0x8153, 0xE443, 0x8154, 0x8D6F, + 0x8155, 0x9872, 0x815F, 0xE454, 0x8165, 0xE448, 0x8166, 0xE449, 0x816B, 0x8EEE, 0x816E, 0xE447, 0x8170, 0x8D98, 0x8171, 0xE446, + 0x8174, 0xE44A, 0x8178, 0x92B0, 0x8179, 0x95A0, 0x817A, 0x9142, 0x817F, 0x91DA, 0x8180, 0xE44E, 0x8182, 0xE44F, 0x8183, 0xE44B, + 0x8188, 0xE44C, 0x818A, 0xE44D, 0x818F, 0x8D70, 0x8193, 0xE455, 0x8195, 0xE451, 0x819A, 0x9586, 0x819C, 0x968C, 0x819D, 0x9547, + 0x81A0, 0xE450, 0x81A3, 0xE453, 0x81A4, 0xE452, 0x81A8, 0x9663, 0x81A9, 0xE456, 0x81B0, 0xE457, 0x81B3, 0x9156, 0x81B5, 0xE458, + 0x81B8, 0xE45A, 0x81BA, 0xE45E, 0x81BD, 0xE45B, 0x81BE, 0xE459, 0x81BF, 0x945E, 0x81C0, 0xE45C, 0x81C2, 0xE45D, 0x81C6, 0x89B0, + 0x81C8, 0xE464, 0x81C9, 0xE45F, 0x81CD, 0xE460, 0x81D1, 0xE461, 0x81D3, 0x919F, 0x81D8, 0xE463, 0x81D9, 0xE462, 0x81DA, 0xE465, + 0x81DF, 0xE466, 0x81E0, 0xE467, 0x81E3, 0x9062, 0x81E5, 0x89E7, 0x81E7, 0xE468, 0x81E8, 0x97D5, 0x81EA, 0x8EA9, 0x81ED, 0x8F4C, + 0x81F3, 0x8E8A, 0x81F4, 0x9276, 0x81FA, 0xE469, 0x81FB, 0xE46A, 0x81FC, 0x8950, 0x81FE, 0xE46B, 0x8201, 0xE46C, 0x8202, 0xE46D, + 0x8205, 0xE46E, 0x8207, 0xE46F, 0x8208, 0x8BBB, 0x8209, 0x9DA8, 0x820A, 0xE470, 0x820C, 0x90E3, 0x820D, 0xE471, 0x820E, 0x8EC9, + 0x8210, 0xE472, 0x8212, 0x98AE, 0x8216, 0xE473, 0x8217, 0x95DC, 0x8218, 0x8ADA, 0x821B, 0x9143, 0x821C, 0x8F77, 0x821E, 0x9591, + 0x821F, 0x8F4D, 0x8229, 0xE474, 0x822A, 0x8D71, 0x822B, 0xE475, 0x822C, 0x94CA, 0x822E, 0xE484, 0x8233, 0xE477, 0x8235, 0x91C7, + 0x8236, 0x9495, 0x8237, 0x8CBD, 0x8238, 0xE476, 0x8239, 0x9144, 0x8240, 0xE478, 0x8247, 0x92F8, 0x8258, 0xE47A, 0x8259, 0xE479, + 0x825A, 0xE47C, 0x825D, 0xE47B, 0x825F, 0xE47D, 0x8262, 0xE480, 0x8264, 0xE47E, 0x8266, 0x8ACD, 0x8268, 0xE481, 0x826A, 0xE482, + 0x826B, 0xE483, 0x826E, 0x8DAF, 0x826F, 0x97C7, 0x8271, 0xE485, 0x8272, 0x9046, 0x8276, 0x8990, 0x8277, 0xE486, 0x8278, 0xE487, + 0x827E, 0xE488, 0x828B, 0x88F0, 0x828D, 0xE489, 0x8292, 0xE48A, 0x8299, 0x9587, 0x829D, 0x8EC5, 0x829F, 0xE48C, 0x82A5, 0x8A48, + 0x82A6, 0x88B0, 0x82AB, 0xE48B, 0x82AC, 0xE48E, 0x82AD, 0x946D, 0x82AF, 0x9063, 0x82B1, 0x89D4, 0x82B3, 0x9646, 0x82B8, 0x8C7C, + 0x82B9, 0x8BDA, 0x82BB, 0xE48D, 0x82BD, 0x89E8, 0x82C5, 0x8AA1, 0x82D1, 0x8991, 0x82D2, 0xE492, 0x82D3, 0x97E8, 0x82D4, 0x91DB, + 0x82D7, 0x9563, 0x82D9, 0xE49E, 0x82DB, 0x89D5, 0x82DC, 0xE49C, 0x82DE, 0xE49A, 0x82DF, 0xE491, 0x82E1, 0xE48F, 0x82E3, 0xE490, + 0x82E5, 0x8EE1, 0x82E6, 0x8BEA, 0x82E7, 0x9297, 0x82EB, 0x93CF, 0x82F1, 0x8970, 0x82F3, 0xE494, 0x82F4, 0xE493, 0x82F9, 0xE499, + 0x82FA, 0xE495, 0x82FB, 0xE498, 0x8301, 0xFB93, 0x8302, 0x96CE, 0x8303, 0xE497, 0x8304, 0x89D6, 0x8305, 0x8A9D, 0x8306, 0xE49B, + 0x8309, 0xE49D, 0x830E, 0x8C73, 0x8316, 0xE4A1, 0x8317, 0xE4AA, 0x8318, 0xE4AB, 0x831C, 0x88A9, 0x8323, 0xE4B2, 0x8328, 0x88EF, + 0x832B, 0xE4A9, 0x832F, 0xE4A8, 0x8331, 0xE4A3, 0x8332, 0xE4A2, 0x8334, 0xE4A0, 0x8335, 0xE49F, 0x8336, 0x9283, 0x8338, 0x91F9, + 0x8339, 0xE4A5, 0x8340, 0xE4A4, 0x8345, 0xE4A7, 0x8349, 0x9190, 0x834A, 0x8C74, 0x834F, 0x8960, 0x8350, 0xE4A6, 0x8352, 0x8D72, + 0x8358, 0x9191, 0x8362, 0xFB94, 0x8373, 0xE4B8, 0x8375, 0xE4B9, 0x8377, 0x89D7, 0x837B, 0x89AC, 0x837C, 0xE4B6, 0x837F, 0xFB95, + 0x8385, 0xE4AC, 0x8387, 0xE4B4, 0x8389, 0xE4BB, 0x838A, 0xE4B5, 0x838E, 0xE4B3, 0x8393, 0xE496, 0x8396, 0xE4B1, 0x839A, 0xE4AD, + 0x839E, 0x8ACE, 0x839F, 0xE4AF, 0x83A0, 0xE4BA, 0x83A2, 0xE4B0, 0x83A8, 0xE4BC, 0x83AA, 0xE4AE, 0x83AB, 0x949C, 0x83B1, 0x9789, + 0x83B5, 0xE4B7, 0x83BD, 0xE4CD, 0x83C1, 0xE4C5, 0x83C5, 0x909B, 0x83C7, 0xFB96, 0x83CA, 0x8B65, 0x83CC, 0x8BDB, 0x83CE, 0xE4C0, + 0x83D3, 0x89D9, 0x83D6, 0x8FD2, 0x83D8, 0xE4C3, 0x83DC, 0x8DD8, 0x83DF, 0x9370, 0x83E0, 0xE4C8, 0x83E9, 0x95EC, 0x83EB, 0xE4BF, + 0x83EF, 0x89D8, 0x83F0, 0x8CD4, 0x83F1, 0x9548, 0x83F2, 0xE4C9, 0x83F4, 0xE4BD, 0x83F6, 0xFB97, 0x83F7, 0xE4C6, 0x83FB, 0xE4D0, + 0x83FD, 0xE4C1, 0x8403, 0xE4C2, 0x8404, 0x93B8, 0x8407, 0xE4C7, 0x840B, 0xE4C4, 0x840C, 0x9647, 0x840D, 0xE4CA, 0x840E, 0x88DE, + 0x8413, 0xE4BE, 0x8420, 0xE4CC, 0x8422, 0xE4CB, 0x8429, 0x948B, 0x842A, 0xE4D2, 0x842C, 0xE4DD, 0x8431, 0x8A9E, 0x8435, 0xE4E0, + 0x8438, 0xE4CE, 0x843C, 0xE4D3, 0x843D, 0x978E, 0x8446, 0xE4DC, 0x8448, 0xFB98, 0x8449, 0x9774, 0x844E, 0x97A8, 0x8457, 0x9298, + 0x845B, 0x8A8B, 0x8461, 0x9592, 0x8462, 0xE4E2, 0x8463, 0x939F, 0x8466, 0x88AF, 0x8469, 0xE4DB, 0x846B, 0xE4D7, 0x846C, 0x9192, + 0x846D, 0xE4D1, 0x846E, 0xE4D9, 0x846F, 0xE4DE, 0x8471, 0x944B, 0x8475, 0x88A8, 0x8477, 0xE4D6, 0x8479, 0xE4DF, 0x847A, 0x9598, + 0x8482, 0xE4DA, 0x8484, 0xE4D5, 0x848B, 0x8FD3, 0x8490, 0x8F4E, 0x8494, 0x8EAA, 0x8499, 0x96D6, 0x849C, 0x9566, 0x849F, 0xE4E5, + 0x84A1, 0xE4EE, 0x84AD, 0xE4D8, 0x84B2, 0x8A97, 0x84B4, 0xFB99, 0x84B8, 0x8FF6, 0x84B9, 0xE4E3, 0x84BB, 0xE4E8, 0x84BC, 0x9193, + 0x84BF, 0xE4E4, 0x84C1, 0xE4EB, 0x84C4, 0x927E, 0x84C6, 0xE4EC, 0x84C9, 0x9775, 0x84CA, 0xE4E1, 0x84CB, 0x8A57, 0x84CD, 0xE4E7, + 0x84D0, 0xE4EA, 0x84D1, 0x96AA, 0x84D6, 0xE4ED, 0x84D9, 0xE4E6, 0x84DA, 0xE4E9, 0x84DC, 0xFA60, 0x84EC, 0x9648, 0x84EE, 0x9840, + 0x84F4, 0xE4F1, 0x84FC, 0xE4F8, 0x84FF, 0xE4F0, 0x8500, 0x8EC1, 0x8506, 0xE4CF, 0x8511, 0x95CC, 0x8513, 0x96A0, 0x8514, 0xE4F7, + 0x8515, 0xE4F6, 0x8517, 0xE4F2, 0x8518, 0xE4F3, 0x851A, 0x8955, 0x851F, 0xE4F5, 0x8521, 0xE4EF, 0x8526, 0x92D3, 0x852C, 0xE4F4, + 0x852D, 0x88FC, 0x8535, 0x91A0, 0x853D, 0x95C1, 0x8540, 0xE4F9, 0x8541, 0xE540, 0x8543, 0x94D7, 0x8548, 0xE4FC, 0x8549, 0x8FD4, + 0x854A, 0x8EC7, 0x854B, 0xE542, 0x854E, 0x8BBC, 0x8553, 0xFB9A, 0x8555, 0xE543, 0x8557, 0x9599, 0x8558, 0xE4FB, 0x8559, 0xFB9B, + 0x855A, 0xE4D4, 0x8563, 0xE4FA, 0x8568, 0x986E, 0x8569, 0x93A0, 0x856A, 0x9593, 0x856B, 0xFB9C, 0x856D, 0xE54A, 0x8577, 0xE550, + 0x857E, 0xE551, 0x8580, 0xE544, 0x8584, 0x9496, 0x8587, 0xE54E, 0x8588, 0xE546, 0x858A, 0xE548, 0x8590, 0xE552, 0x8591, 0xE547, + 0x8594, 0xE54B, 0x8597, 0x8992, 0x8599, 0x93E3, 0x859B, 0xE54C, 0x859C, 0xE54F, 0x85A4, 0xE545, 0x85A6, 0x9145, 0x85A8, 0xE549, + 0x85A9, 0x8E46, 0x85AA, 0x9064, 0x85AB, 0x8C4F, 0x85AC, 0x96F2, 0x85AE, 0x96F7, 0x85AF, 0x8F92, 0x85B0, 0xFB9E, 0x85B9, 0xE556, + 0x85BA, 0xE554, 0x85C1, 0x986D, 0x85C9, 0xE553, 0x85CD, 0x9795, 0x85CF, 0xE555, 0x85D0, 0xE557, 0x85D5, 0xE558, 0x85DC, 0xE55B, + 0x85DD, 0xE559, 0x85E4, 0x93A1, 0x85E5, 0xE55A, 0x85E9, 0x94CB, 0x85EA, 0xE54D, 0x85F7, 0x8F93, 0x85F9, 0xE55C, 0x85FA, 0xE561, + 0x85FB, 0x9194, 0x85FE, 0xE560, 0x8602, 0xE541, 0x8606, 0xE562, 0x8607, 0x9168, 0x860A, 0xE55D, 0x860B, 0xE55F, 0x8613, 0xE55E, + 0x8616, 0x9F50, 0x8617, 0x9F41, 0x861A, 0xE564, 0x8622, 0xE563, 0x862D, 0x9796, 0x862F, 0xE1BA, 0x8630, 0xE565, 0x863F, 0xE566, + 0x864D, 0xE567, 0x864E, 0x8CD5, 0x8650, 0x8B73, 0x8654, 0xE569, 0x8655, 0x997C, 0x865A, 0x8B95, 0x865C, 0x97B8, 0x865E, 0x8BF1, + 0x865F, 0xE56A, 0x8667, 0xE56B, 0x866B, 0x928E, 0x8671, 0xE56C, 0x8679, 0x93F8, 0x867B, 0x88B8, 0x868A, 0x89E1, 0x868B, 0xE571, + 0x868C, 0xE572, 0x8693, 0xE56D, 0x8695, 0x8E5C, 0x86A3, 0xE56E, 0x86A4, 0x9461, 0x86A9, 0xE56F, 0x86AA, 0xE570, 0x86AB, 0xE57A, + 0x86AF, 0xE574, 0x86B0, 0xE577, 0x86B6, 0xE573, 0x86C4, 0xE575, 0x86C6, 0xE576, 0x86C7, 0x8ED6, 0x86C9, 0xE578, 0x86CB, 0x9260, + 0x86CD, 0x8C75, 0x86CE, 0x8A61, 0x86D4, 0xE57B, 0x86D9, 0x8A5E, 0x86DB, 0xE581, 0x86DE, 0xE57C, 0x86DF, 0xE580, 0x86E4, 0x94B8, + 0x86E9, 0xE57D, 0x86EC, 0xE57E, 0x86ED, 0x9567, 0x86EE, 0x94D8, 0x86EF, 0xE582, 0x86F8, 0x91FB, 0x86F9, 0xE58C, 0x86FB, 0xE588, + 0x86FE, 0x89E9, 0x8700, 0xE586, 0x8702, 0x9649, 0x8703, 0xE587, 0x8706, 0xE584, 0x8708, 0xE585, 0x8709, 0xE58A, 0x870A, 0xE58D, + 0x870D, 0xE58B, 0x8711, 0xE589, 0x8712, 0xE583, 0x8718, 0x9277, 0x871A, 0xE594, 0x871C, 0x96A8, 0x8725, 0xE592, 0x8729, 0xE593, + 0x8734, 0xE58E, 0x8737, 0xE590, 0x873B, 0xE591, 0x873F, 0xE58F, 0x8749, 0x90E4, 0x874B, 0x9858, 0x874C, 0xE598, 0x874E, 0xE599, + 0x8753, 0xE59F, 0x8755, 0x9049, 0x8757, 0xE59B, 0x8759, 0xE59E, 0x875F, 0xE596, 0x8760, 0xE595, 0x8763, 0xE5A0, 0x8766, 0x89DA, + 0x8768, 0xE59C, 0x876A, 0xE5A1, 0x876E, 0xE59D, 0x8774, 0xE59A, 0x8776, 0x92B1, 0x8778, 0xE597, 0x877F, 0x9488, 0x8782, 0xE5A5, + 0x878D, 0x975A, 0x879F, 0xE5A4, 0x87A2, 0xE5A3, 0x87AB, 0xE5AC, 0x87AF, 0xE5A6, 0x87B3, 0xE5AE, 0x87BA, 0x9786, 0x87BB, 0xE5B1, + 0x87BD, 0xE5A8, 0x87C0, 0xE5A9, 0x87C4, 0xE5AD, 0x87C6, 0xE5B0, 0x87C7, 0xE5AF, 0x87CB, 0xE5A7, 0x87D0, 0xE5AA, 0x87D2, 0xE5BB, + 0x87E0, 0xE5B4, 0x87EF, 0xE5B2, 0x87F2, 0xE5B3, 0x87F6, 0xE5B8, 0x87F7, 0xE5B9, 0x87F9, 0x8A49, 0x87FB, 0x8B61, 0x87FE, 0xE5B7, + 0x8805, 0xE5A2, 0x8807, 0xFBA1, 0x880D, 0xE5B6, 0x880E, 0xE5BA, 0x880F, 0xE5B5, 0x8811, 0xE5BC, 0x8815, 0xE5BE, 0x8816, 0xE5BD, + 0x8821, 0xE5C0, 0x8822, 0xE5BF, 0x8823, 0xE579, 0x8827, 0xE5C4, 0x8831, 0xE5C1, 0x8836, 0xE5C2, 0x8839, 0xE5C3, 0x883B, 0xE5C5, + 0x8840, 0x8C8C, 0x8842, 0xE5C7, 0x8844, 0xE5C6, 0x8846, 0x8F4F, 0x884C, 0x8D73, 0x884D, 0x9FA5, 0x8852, 0xE5C8, 0x8853, 0x8F70, + 0x8857, 0x8A58, 0x8859, 0xE5C9, 0x885B, 0x8971, 0x885D, 0x8FD5, 0x885E, 0xE5CA, 0x8861, 0x8D74, 0x8862, 0xE5CB, 0x8863, 0x88DF, + 0x8868, 0x955C, 0x886B, 0xE5CC, 0x8870, 0x908A, 0x8872, 0xE5D3, 0x8875, 0xE5D0, 0x8877, 0x928F, 0x887D, 0xE5D1, 0x887E, 0xE5CE, + 0x887F, 0x8BDC, 0x8881, 0xE5CD, 0x8882, 0xE5D4, 0x8888, 0x8C55, 0x888B, 0x91DC, 0x888D, 0xE5DA, 0x8892, 0xE5D6, 0x8896, 0x91B3, + 0x8897, 0xE5D5, 0x8899, 0xE5D8, 0x889E, 0xE5CF, 0x88A2, 0xE5D9, 0x88A4, 0xE5DB, 0x88AB, 0x94ED, 0x88AE, 0xE5D7, 0x88B0, 0xE5DC, + 0x88B1, 0xE5DE, 0x88B4, 0x8CD1, 0x88B5, 0xE5D2, 0x88B7, 0x88BF, 0x88BF, 0xE5DD, 0x88C1, 0x8DD9, 0x88C2, 0x97F4, 0x88C3, 0xE5DF, + 0x88C4, 0xE5E0, 0x88C5, 0x9195, 0x88CF, 0x97A0, 0x88D4, 0xE5E1, 0x88D5, 0x9754, 0x88D8, 0xE5E2, 0x88D9, 0xE5E3, 0x88DC, 0x95E2, + 0x88DD, 0xE5E4, 0x88DF, 0x8DBE, 0x88E1, 0x97A1, 0x88E8, 0xE5E9, 0x88F2, 0xE5EA, 0x88F3, 0x8FD6, 0x88F4, 0xE5E8, 0x88F5, 0xFBA2, + 0x88F8, 0x9787, 0x88F9, 0xE5E5, 0x88FC, 0xE5E7, 0x88FD, 0x90BB, 0x88FE, 0x909E, 0x8902, 0xE5E6, 0x8904, 0xE5EB, 0x8907, 0x95A1, + 0x890A, 0xE5ED, 0x890C, 0xE5EC, 0x8910, 0x8A8C, 0x8912, 0x964A, 0x8913, 0xE5EE, 0x891C, 0xFA5D, 0x891D, 0xE5FA, 0x891E, 0xE5F0, + 0x8925, 0xE5F1, 0x892A, 0xE5F2, 0x892B, 0xE5F3, 0x8936, 0xE5F7, 0x8938, 0xE5F8, 0x893B, 0xE5F6, 0x8941, 0xE5F4, 0x8943, 0xE5EF, + 0x8944, 0xE5F5, 0x894C, 0xE5F9, 0x894D, 0xE8B5, 0x8956, 0x89A6, 0x895E, 0xE5FC, 0x895F, 0x8BDD, 0x8960, 0xE5FB, 0x8964, 0xE641, + 0x8966, 0xE640, 0x896A, 0xE643, 0x896D, 0xE642, 0x896F, 0xE644, 0x8972, 0x8F50, 0x8974, 0xE645, 0x8977, 0xE646, 0x897E, 0xE647, + 0x897F, 0x90BC, 0x8981, 0x9776, 0x8983, 0xE648, 0x8986, 0x95A2, 0x8987, 0x9465, 0x8988, 0xE649, 0x898A, 0xE64A, 0x898B, 0x8CA9, + 0x898F, 0x8B4B, 0x8993, 0xE64B, 0x8996, 0x8E8B, 0x8997, 0x9460, 0x8998, 0xE64C, 0x899A, 0x8A6F, 0x89A1, 0xE64D, 0x89A6, 0xE64F, + 0x89A7, 0x9797, 0x89A9, 0xE64E, 0x89AA, 0x9065, 0x89AC, 0xE650, 0x89AF, 0xE651, 0x89B2, 0xE652, 0x89B3, 0x8ACF, 0x89BA, 0xE653, + 0x89BD, 0xE654, 0x89BF, 0xE655, 0x89C0, 0xE656, 0x89D2, 0x8A70, 0x89DA, 0xE657, 0x89DC, 0xE658, 0x89DD, 0xE659, 0x89E3, 0x89F0, + 0x89E6, 0x9047, 0x89E7, 0xE65A, 0x89F4, 0xE65B, 0x89F8, 0xE65C, 0x8A00, 0x8CBE, 0x8A02, 0x92F9, 0x8A03, 0xE65D, 0x8A08, 0x8C76, + 0x8A0A, 0x9075, 0x8A0C, 0xE660, 0x8A0E, 0x93A2, 0x8A10, 0xE65F, 0x8A12, 0xFBA3, 0x8A13, 0x8C50, 0x8A16, 0xE65E, 0x8A17, 0x91F5, + 0x8A18, 0x8B4C, 0x8A1B, 0xE661, 0x8A1D, 0xE662, 0x8A1F, 0x8FD7, 0x8A23, 0x8C8D, 0x8A25, 0xE663, 0x8A2A, 0x964B, 0x8A2D, 0x90DD, + 0x8A31, 0x8B96, 0x8A33, 0x96F3, 0x8A34, 0x9169, 0x8A36, 0xE664, 0x8A37, 0xFBA4, 0x8A3A, 0x9066, 0x8A3B, 0x9290, 0x8A3C, 0x8FD8, + 0x8A41, 0xE665, 0x8A46, 0xE668, 0x8A48, 0xE669, 0x8A50, 0x8DBC, 0x8A51, 0x91C0, 0x8A52, 0xE667, 0x8A54, 0x8FD9, 0x8A55, 0x955D, + 0x8A5B, 0xE666, 0x8A5E, 0x8E8C, 0x8A60, 0x8972, 0x8A62, 0xE66D, 0x8A63, 0x8C77, 0x8A66, 0x8E8E, 0x8A69, 0x8E8D, 0x8A6B, 0x986C, + 0x8A6C, 0xE66C, 0x8A6D, 0xE66B, 0x8A6E, 0x9146, 0x8A70, 0x8B6C, 0x8A71, 0x9862, 0x8A72, 0x8A59, 0x8A73, 0x8FDA, 0x8A79, 0xFBA5, + 0x8A7C, 0xE66A, 0x8A82, 0xE66F, 0x8A84, 0xE670, 0x8A85, 0xE66E, 0x8A87, 0x8CD6, 0x8A89, 0x975F, 0x8A8C, 0x8E8F, 0x8A8D, 0x9446, + 0x8A91, 0xE673, 0x8A93, 0x90BE, 0x8A95, 0x9261, 0x8A98, 0x9755, 0x8A9A, 0xE676, 0x8A9E, 0x8CEA, 0x8AA0, 0x90BD, 0x8AA1, 0xE672, + 0x8AA3, 0xE677, 0x8AA4, 0x8CEB, 0x8AA5, 0xE674, 0x8AA6, 0xE675, 0x8AA7, 0xFBA6, 0x8AA8, 0xE671, 0x8AAC, 0x90E0, 0x8AAD, 0x93C7, + 0x8AB0, 0x924E, 0x8AB2, 0x89DB, 0x8AB9, 0x94EE, 0x8ABC, 0x8B62, 0x8ABE, 0xFBA7, 0x8ABF, 0x92B2, 0x8AC2, 0xE67A, 0x8AC4, 0xE678, + 0x8AC7, 0x926B, 0x8ACB, 0x90BF, 0x8ACC, 0x8AD0, 0x8ACD, 0xE679, 0x8ACF, 0x907A, 0x8AD2, 0x97C8, 0x8AD6, 0x985F, 0x8ADA, 0xE67B, + 0x8ADB, 0xE687, 0x8ADC, 0x92B3, 0x8ADE, 0xE686, 0x8ADF, 0xFBA8, 0x8AE0, 0xE683, 0x8AE1, 0xE68B, 0x8AE2, 0xE684, 0x8AE4, 0xE680, + 0x8AE6, 0x92FA, 0x8AE7, 0xE67E, 0x8AEB, 0xE67C, 0x8AED, 0x9740, 0x8AEE, 0x8E90, 0x8AF1, 0xE681, 0x8AF3, 0xE67D, 0x8AF6, 0xFBAA, + 0x8AF7, 0xE685, 0x8AF8, 0x8F94, 0x8AFA, 0x8CBF, 0x8AFE, 0x91F8, 0x8B00, 0x9664, 0x8B01, 0x8979, 0x8B02, 0x88E0, 0x8B04, 0x93A3, + 0x8B07, 0xE689, 0x8B0C, 0xE688, 0x8B0E, 0x93E4, 0x8B10, 0xE68D, 0x8B14, 0xE682, 0x8B16, 0xE68C, 0x8B17, 0xE68E, 0x8B19, 0x8CAA, + 0x8B1A, 0xE68A, 0x8B1B, 0x8D75, 0x8B1D, 0x8ED3, 0x8B20, 0xE68F, 0x8B21, 0x9777, 0x8B26, 0xE692, 0x8B28, 0xE695, 0x8B2B, 0xE693, + 0x8B2C, 0x9554, 0x8B33, 0xE690, 0x8B39, 0x8BDE, 0x8B3E, 0xE694, 0x8B41, 0xE696, 0x8B49, 0xE69A, 0x8B4C, 0xE697, 0x8B4E, 0xE699, + 0x8B4F, 0xE698, 0x8B53, 0xFBAB, 0x8B56, 0xE69B, 0x8B58, 0x8EAF, 0x8B5A, 0xE69D, 0x8B5B, 0xE69C, 0x8B5C, 0x9588, 0x8B5F, 0xE69F, + 0x8B66, 0x8C78, 0x8B6B, 0xE69E, 0x8B6C, 0xE6A0, 0x8B6F, 0xE6A1, 0x8B70, 0x8B63, 0x8B71, 0xE3BF, 0x8B72, 0x8FF7, 0x8B74, 0xE6A2, + 0x8B77, 0x8CEC, 0x8B7D, 0xE6A3, 0x8B7F, 0xFBAC, 0x8B80, 0xE6A4, 0x8B83, 0x8E5D, 0x8B8A, 0x9DCC, 0x8B8C, 0xE6A5, 0x8B8E, 0xE6A6, + 0x8B90, 0x8F51, 0x8B92, 0xE6A7, 0x8B93, 0xE6A8, 0x8B96, 0xE6A9, 0x8B99, 0xE6AA, 0x8B9A, 0xE6AB, 0x8C37, 0x924A, 0x8C3A, 0xE6AC, + 0x8C3F, 0xE6AE, 0x8C41, 0xE6AD, 0x8C46, 0x93A4, 0x8C48, 0xE6AF, 0x8C4A, 0x964C, 0x8C4C, 0xE6B0, 0x8C4E, 0xE6B1, 0x8C50, 0xE6B2, + 0x8C55, 0xE6B3, 0x8C5A, 0x93D8, 0x8C61, 0x8FDB, 0x8C62, 0xE6B4, 0x8C6A, 0x8D8B, 0x8C6B, 0x98AC, 0x8C6C, 0xE6B5, 0x8C78, 0xE6B6, + 0x8C79, 0x955E, 0x8C7A, 0xE6B7, 0x8C7C, 0xE6BF, 0x8C82, 0xE6B8, 0x8C85, 0xE6BA, 0x8C89, 0xE6B9, 0x8C8A, 0xE6BB, 0x8C8C, 0x9665, + 0x8C8D, 0xE6BC, 0x8C8E, 0xE6BD, 0x8C94, 0xE6BE, 0x8C98, 0xE6C0, 0x8C9D, 0x8A4C, 0x8C9E, 0x92E5, 0x8CA0, 0x9589, 0x8CA1, 0x8DE0, + 0x8CA2, 0x8D76, 0x8CA7, 0x956E, 0x8CA8, 0x89DD, 0x8CA9, 0x94CC, 0x8CAA, 0xE6C3, 0x8CAB, 0x8AD1, 0x8CAC, 0x90D3, 0x8CAD, 0xE6C2, + 0x8CAE, 0xE6C7, 0x8CAF, 0x9299, 0x8CB0, 0x96E1, 0x8CB2, 0xE6C5, 0x8CB3, 0xE6C6, 0x8CB4, 0x8B4D, 0x8CB6, 0xE6C8, 0x8CB7, 0x9483, + 0x8CB8, 0x91DD, 0x8CBB, 0x94EF, 0x8CBC, 0x935C, 0x8CBD, 0xE6C4, 0x8CBF, 0x9666, 0x8CC0, 0x89EA, 0x8CC1, 0xE6CA, 0x8CC2, 0x9847, + 0x8CC3, 0x92C0, 0x8CC4, 0x9864, 0x8CC7, 0x8E91, 0x8CC8, 0xE6C9, 0x8CCA, 0x91AF, 0x8CCD, 0xE6DA, 0x8CCE, 0x9147, 0x8CD1, 0x93F6, + 0x8CD3, 0x956F, 0x8CDA, 0xE6CD, 0x8CDB, 0x8E5E, 0x8CDC, 0x8E92, 0x8CDE, 0x8FDC, 0x8CE0, 0x9485, 0x8CE2, 0x8CAB, 0x8CE3, 0xE6CC, + 0x8CE4, 0xE6CB, 0x8CE6, 0x958A, 0x8CEA, 0x8EBF, 0x8CED, 0x9371, 0x8CF0, 0xFBAD, 0x8CF4, 0xFBAE, 0x8CFA, 0xE6CF, 0x8CFB, 0xE6D0, + 0x8CFC, 0x8D77, 0x8CFD, 0xE6CE, 0x8D04, 0xE6D1, 0x8D05, 0xE6D2, 0x8D07, 0xE6D4, 0x8D08, 0x91A1, 0x8D0A, 0xE6D3, 0x8D0B, 0x8AE4, + 0x8D0D, 0xE6D6, 0x8D0F, 0xE6D5, 0x8D10, 0xE6D7, 0x8D12, 0xFBAF, 0x8D13, 0xE6D9, 0x8D14, 0xE6DB, 0x8D16, 0xE6DC, 0x8D64, 0x90D4, + 0x8D66, 0x8ECD, 0x8D67, 0xE6DD, 0x8D6B, 0x8A71, 0x8D6D, 0xE6DE, 0x8D70, 0x9196, 0x8D71, 0xE6DF, 0x8D73, 0xE6E0, 0x8D74, 0x958B, + 0x8D76, 0xFBB0, 0x8D77, 0x8B4E, 0x8D81, 0xE6E1, 0x8D85, 0x92B4, 0x8D8A, 0x897A, 0x8D99, 0xE6E2, 0x8DA3, 0x8EEF, 0x8DA8, 0x9096, + 0x8DB3, 0x91AB, 0x8DBA, 0xE6E5, 0x8DBE, 0xE6E4, 0x8DC2, 0xE6E3, 0x8DCB, 0xE6EB, 0x8DCC, 0xE6E9, 0x8DCF, 0xE6E6, 0x8DD6, 0xE6E8, + 0x8DDA, 0xE6E7, 0x8DDB, 0xE6EA, 0x8DDD, 0x8B97, 0x8DDF, 0xE6EE, 0x8DE1, 0x90D5, 0x8DE3, 0xE6EF, 0x8DE8, 0x8CD7, 0x8DEA, 0xE6EC, + 0x8DEB, 0xE6ED, 0x8DEF, 0x9848, 0x8DF3, 0x92B5, 0x8DF5, 0x9148, 0x8DFC, 0xE6F0, 0x8DFF, 0xE6F3, 0x8E08, 0xE6F1, 0x8E09, 0xE6F2, + 0x8E0A, 0x9778, 0x8E0F, 0x93A5, 0x8E10, 0xE6F6, 0x8E1D, 0xE6F4, 0x8E1E, 0xE6F5, 0x8E1F, 0xE6F7, 0x8E2A, 0xE748, 0x8E30, 0xE6FA, + 0x8E34, 0xE6FB, 0x8E35, 0xE6F9, 0x8E42, 0xE6F8, 0x8E44, 0x92FB, 0x8E47, 0xE740, 0x8E48, 0xE744, 0x8E49, 0xE741, 0x8E4A, 0xE6FC, + 0x8E4C, 0xE742, 0x8E50, 0xE743, 0x8E55, 0xE74A, 0x8E59, 0xE745, 0x8E5F, 0x90D6, 0x8E60, 0xE747, 0x8E63, 0xE749, 0x8E64, 0xE746, + 0x8E72, 0xE74C, 0x8E74, 0x8F52, 0x8E76, 0xE74B, 0x8E7C, 0xE74D, 0x8E81, 0xE74E, 0x8E84, 0xE751, 0x8E85, 0xE750, 0x8E87, 0xE74F, + 0x8E8A, 0xE753, 0x8E8B, 0xE752, 0x8E8D, 0x96F4, 0x8E91, 0xE755, 0x8E93, 0xE754, 0x8E94, 0xE756, 0x8E99, 0xE757, 0x8EA1, 0xE759, + 0x8EAA, 0xE758, 0x8EAB, 0x9067, 0x8EAC, 0xE75A, 0x8EAF, 0x8BEB, 0x8EB0, 0xE75B, 0x8EB1, 0xE75D, 0x8EBE, 0xE75E, 0x8EC5, 0xE75F, + 0x8EC6, 0xE75C, 0x8EC8, 0xE760, 0x8ECA, 0x8ED4, 0x8ECB, 0xE761, 0x8ECC, 0x8B4F, 0x8ECD, 0x8C52, 0x8ECF, 0xFBB2, 0x8ED2, 0x8CAC, + 0x8EDB, 0xE762, 0x8EDF, 0x93EE, 0x8EE2, 0x935D, 0x8EE3, 0xE763, 0x8EEB, 0xE766, 0x8EF8, 0x8EB2, 0x8EFB, 0xE765, 0x8EFC, 0xE764, + 0x8EFD, 0x8C79, 0x8EFE, 0xE767, 0x8F03, 0x8A72, 0x8F05, 0xE769, 0x8F09, 0x8DDA, 0x8F0A, 0xE768, 0x8F0C, 0xE771, 0x8F12, 0xE76B, + 0x8F13, 0xE76D, 0x8F14, 0x95E3, 0x8F15, 0xE76A, 0x8F19, 0xE76C, 0x8F1B, 0xE770, 0x8F1C, 0xE76E, 0x8F1D, 0x8B50, 0x8F1F, 0xE76F, + 0x8F26, 0xE772, 0x8F29, 0x9479, 0x8F2A, 0x97D6, 0x8F2F, 0x8F53, 0x8F33, 0xE773, 0x8F38, 0x9741, 0x8F39, 0xE775, 0x8F3B, 0xE774, + 0x8F3E, 0xE778, 0x8F3F, 0x9760, 0x8F42, 0xE777, 0x8F44, 0x8A8D, 0x8F45, 0xE776, 0x8F46, 0xE77B, 0x8F49, 0xE77A, 0x8F4C, 0xE779, + 0x8F4D, 0x9351, 0x8F4E, 0xE77C, 0x8F57, 0xE77D, 0x8F5C, 0xE77E, 0x8F5F, 0x8D8C, 0x8F61, 0x8C44, 0x8F62, 0xE780, 0x8F63, 0xE781, + 0x8F64, 0xE782, 0x8F9B, 0x9068, 0x8F9C, 0xE783, 0x8F9E, 0x8EAB, 0x8F9F, 0xE784, 0x8FA3, 0xE785, 0x8FA7, 0x999F, 0x8FA8, 0x999E, + 0x8FAD, 0xE786, 0x8FAE, 0xE390, 0x8FAF, 0xE787, 0x8FB0, 0x9243, 0x8FB1, 0x904A, 0x8FB2, 0x945F, 0x8FB7, 0xE788, 0x8FBA, 0x95D3, + 0x8FBB, 0x92D2, 0x8FBC, 0x8D9E, 0x8FBF, 0x9248, 0x8FC2, 0x8949, 0x8FC4, 0x9698, 0x8FC5, 0x9076, 0x8FCE, 0x8C7D, 0x8FD1, 0x8BDF, + 0x8FD4, 0x95D4, 0x8FDA, 0xE789, 0x8FE2, 0xE78B, 0x8FE5, 0xE78A, 0x8FE6, 0x89DE, 0x8FE9, 0x93F4, 0x8FEA, 0xE78C, 0x8FEB, 0x9497, + 0x8FED, 0x9352, 0x8FEF, 0xE78D, 0x8FF0, 0x8F71, 0x8FF4, 0xE78F, 0x8FF7, 0x96C0, 0x8FF8, 0xE79E, 0x8FF9, 0xE791, 0x8FFA, 0xE792, + 0x8FFD, 0x92C7, 0x9000, 0x91DE, 0x9001, 0x9197, 0x9003, 0x93A6, 0x9005, 0xE790, 0x9006, 0x8B74, 0x900B, 0xE799, 0x900D, 0xE796, + 0x900E, 0xE7A3, 0x900F, 0x93A7, 0x9010, 0x9280, 0x9011, 0xE793, 0x9013, 0x92FC, 0x9014, 0x9372, 0x9015, 0xE794, 0x9016, 0xE798, + 0x9017, 0x9080, 0x9019, 0x9487, 0x901A, 0x92CA, 0x901D, 0x90C0, 0x901E, 0xE797, 0x901F, 0x91AC, 0x9020, 0x91A2, 0x9021, 0xE795, + 0x9022, 0x88A7, 0x9023, 0x9841, 0x9027, 0xE79A, 0x902E, 0x91DF, 0x9031, 0x8F54, 0x9032, 0x9069, 0x9035, 0xE79C, 0x9036, 0xE79B, + 0x9038, 0x88ED, 0x9039, 0xE79D, 0x903C, 0x954E, 0x903E, 0xE7A5, 0x9041, 0x93D9, 0x9042, 0x908B, 0x9045, 0x9278, 0x9047, 0x8BF6, + 0x9049, 0xE7A4, 0x904A, 0x9756, 0x904B, 0x895E, 0x904D, 0x95D5, 0x904E, 0x89DF, 0x904F, 0xE79F, 0x9050, 0xE7A0, 0x9051, 0xE7A1, + 0x9052, 0xE7A2, 0x9053, 0x93B9, 0x9054, 0x9242, 0x9055, 0x88E1, 0x9056, 0xE7A6, 0x9058, 0xE7A7, 0x9059, 0xEAA1, 0x905C, 0x91BB, + 0x905E, 0xE7A8, 0x9060, 0x8993, 0x9061, 0x916B, 0x9063, 0x8CAD, 0x9065, 0x9779, 0x9067, 0xFBB5, 0x9068, 0xE7A9, 0x9069, 0x934B, + 0x906D, 0x9198, 0x906E, 0x8ED5, 0x906F, 0xE7AA, 0x9072, 0xE7AD, 0x9075, 0x8F85, 0x9076, 0xE7AB, 0x9077, 0x914A, 0x9078, 0x9149, + 0x907A, 0x88E2, 0x907C, 0x97C9, 0x907D, 0xE7AF, 0x907F, 0x94F0, 0x9080, 0xE7B1, 0x9081, 0xE7B0, 0x9082, 0xE7AE, 0x9083, 0xE284, + 0x9084, 0x8AD2, 0x9087, 0xE78E, 0x9089, 0xE7B3, 0x908A, 0xE7B2, 0x908F, 0xE7B4, 0x9091, 0x9757, 0x90A3, 0x93DF, 0x90A6, 0x964D, + 0x90A8, 0xE7B5, 0x90AA, 0x8ED7, 0x90AF, 0xE7B6, 0x90B1, 0xE7B7, 0x90B5, 0xE7B8, 0x90B8, 0x9340, 0x90C1, 0x88E8, 0x90CA, 0x8D78, + 0x90CE, 0x9859, 0x90DB, 0xE7BC, 0x90DE, 0xFBB6, 0x90E1, 0x8C53, 0x90E2, 0xE7B9, 0x90E4, 0xE7BA, 0x90E8, 0x9594, 0x90ED, 0x8A73, + 0x90F5, 0x9758, 0x90F7, 0x8BBD, 0x90FD, 0x9373, 0x9102, 0xE7BD, 0x9112, 0xE7BE, 0x9115, 0xFBB8, 0x9119, 0xE7BF, 0x9127, 0xFBB9, + 0x912D, 0x9341, 0x9130, 0xE7C1, 0x9132, 0xE7C0, 0x9149, 0x93D1, 0x914A, 0xE7C2, 0x914B, 0x8F55, 0x914C, 0x8EDE, 0x914D, 0x947A, + 0x914E, 0x9291, 0x9152, 0x8EF0, 0x9154, 0x908C, 0x9156, 0xE7C3, 0x9158, 0xE7C4, 0x9162, 0x907C, 0x9163, 0xE7C5, 0x9165, 0xE7C6, + 0x9169, 0xE7C7, 0x916A, 0x978F, 0x916C, 0x8F56, 0x9172, 0xE7C9, 0x9173, 0xE7C8, 0x9175, 0x8D79, 0x9177, 0x8D93, 0x9178, 0x8E5F, + 0x9182, 0xE7CC, 0x9187, 0x8F86, 0x9189, 0xE7CB, 0x918B, 0xE7CA, 0x918D, 0x91E7, 0x9190, 0x8CED, 0x9192, 0x90C1, 0x9197, 0x94AE, + 0x919C, 0x8F58, 0x91A2, 0xE7CD, 0x91A4, 0x8FDD, 0x91AA, 0xE7D0, 0x91AB, 0xE7CE, 0x91AF, 0xE7CF, 0x91B4, 0xE7D2, 0x91B5, 0xE7D1, + 0x91B8, 0x8FF8, 0x91BA, 0xE7D3, 0x91C0, 0xE7D4, 0x91C1, 0xE7D5, 0x91C6, 0x94CE, 0x91C7, 0x8DD1, 0x91C8, 0x8EDF, 0x91C9, 0xE7D6, + 0x91CB, 0xE7D7, 0x91CC, 0x97A2, 0x91CD, 0x8F64, 0x91CE, 0x96EC, 0x91CF, 0x97CA, 0x91D0, 0xE7D8, 0x91D1, 0x8BE0, 0x91D6, 0xE7D9, + 0x91D7, 0xFBBB, 0x91D8, 0x9342, 0x91DA, 0xFBBA, 0x91DB, 0xE7DC, 0x91DC, 0x8A98, 0x91DD, 0x906A, 0x91DE, 0xFBBC, 0x91DF, 0xE7DA, + 0x91E1, 0xE7DB, 0x91E3, 0x92DE, 0x91E4, 0xFBBF, 0x91E5, 0xFBC0, 0x91E6, 0x9674, 0x91E7, 0x8BFA, 0x91ED, 0xFBBD, 0x91EE, 0xFBBE, + 0x91F5, 0xE7DE, 0x91F6, 0xE7DF, 0x91FC, 0xE7DD, 0x91FF, 0xE7E1, 0x9206, 0xFBC1, 0x920A, 0xFBC3, 0x920D, 0x93DD, 0x920E, 0x8A62, + 0x9210, 0xFBC2, 0x9211, 0xE7E5, 0x9214, 0xE7E2, 0x9215, 0xE7E4, 0x921E, 0xE7E0, 0x9229, 0xE86E, 0x922C, 0xE7E3, 0x9234, 0x97E9, + 0x9237, 0x8CD8, 0x9239, 0xFBCA, 0x923A, 0xFBC4, 0x923C, 0xFBC6, 0x923F, 0xE7ED, 0x9240, 0xFBC5, 0x9244, 0x9353, 0x9245, 0xE7E8, + 0x9248, 0xE7EB, 0x9249, 0xE7E9, 0x924B, 0xE7EE, 0x924E, 0xFBC7, 0x9250, 0xE7EF, 0x9251, 0xFBC9, 0x9257, 0xE7E7, 0x9259, 0xFBC8, + 0x925A, 0xE7F4, 0x925B, 0x8994, 0x925E, 0xE7E6, 0x9262, 0x94AB, 0x9264, 0xE7EA, 0x9266, 0x8FDE, 0x9267, 0xFBCB, 0x9271, 0x8D7A, + 0x9277, 0xFBCD, 0x9278, 0xFBCE, 0x927E, 0x9667, 0x9280, 0x8BE2, 0x9283, 0x8F65, 0x9285, 0x93BA, 0x9288, 0xFA5F, 0x9291, 0x914C, + 0x9293, 0xE7F2, 0x9295, 0xE7EC, 0x9296, 0xE7F1, 0x9298, 0x96C1, 0x929A, 0x92B6, 0x929B, 0xE7F3, 0x929C, 0xE7F0, 0x92A7, 0xFBCC, + 0x92AD, 0x914B, 0x92B7, 0xE7F7, 0x92B9, 0xE7F6, 0x92CF, 0xE7F5, 0x92D0, 0xFBD2, 0x92D2, 0x964E, 0x92D3, 0xFBD6, 0x92D5, 0xFBD4, + 0x92D7, 0xFBD0, 0x92D9, 0xFBD1, 0x92E0, 0xFBD5, 0x92E4, 0x8F9B, 0x92E7, 0xFBCF, 0x92E9, 0xE7F8, 0x92EA, 0x95DD, 0x92ED, 0x8973, + 0x92F2, 0x9565, 0x92F3, 0x9292, 0x92F8, 0x8B98, 0x92F9, 0xFA65, 0x92FA, 0xE7FA, 0x92FB, 0xFBD9, 0x92FC, 0x8D7C, 0x92FF, 0xFBDC, + 0x9302, 0xFBDE, 0x9306, 0x8E4B, 0x930F, 0xE7F9, 0x9310, 0x908D, 0x9318, 0x908E, 0x9319, 0xE840, 0x931A, 0xE842, 0x931D, 0xFBDD, + 0x931E, 0xFBDB, 0x9320, 0x8FF9, 0x9321, 0xFBD8, 0x9322, 0xE841, 0x9323, 0xE843, 0x9325, 0xFBD7, 0x9326, 0x8BD1, 0x9328, 0x9564, + 0x932B, 0x8EE0, 0x932C, 0x9842, 0x932E, 0xE7FC, 0x932F, 0x8DF6, 0x9332, 0x985E, 0x9335, 0xE845, 0x933A, 0xE844, 0x933B, 0xE846, + 0x9344, 0xE7FB, 0x9348, 0xFA5E, 0x934B, 0x93E7, 0x934D, 0x9374, 0x9354, 0x92D5, 0x9356, 0xE84B, 0x9357, 0xFBE0, 0x935B, 0x9262, + 0x935C, 0xE847, 0x9360, 0xE848, 0x936C, 0x8C4C, 0x936E, 0xE84A, 0x9370, 0xFBDF, 0x9375, 0x8CAE, 0x937C, 0xE849, 0x937E, 0x8FDF, + 0x938C, 0x8A99, 0x9394, 0xE84F, 0x9396, 0x8DBD, 0x9397, 0x9199, 0x939A, 0x92C8, 0x93A4, 0xFBE1, 0x93A7, 0x8A5A, 0x93AC, 0xE84D, + 0x93AD, 0xE84E, 0x93AE, 0x92C1, 0x93B0, 0xE84C, 0x93B9, 0xE850, 0x93C3, 0xE856, 0x93C6, 0xFBE2, 0x93C8, 0xE859, 0x93D0, 0xE858, + 0x93D1, 0x934C, 0x93D6, 0xE851, 0x93D7, 0xE852, 0x93D8, 0xE855, 0x93DD, 0xE857, 0x93DE, 0xFBE3, 0x93E1, 0x8BBE, 0x93E4, 0xE85A, + 0x93E5, 0xE854, 0x93E8, 0xE853, 0x93F8, 0xFBE4, 0x9403, 0xE85E, 0x9407, 0xE85F, 0x9410, 0xE860, 0x9413, 0xE85D, 0x9414, 0xE85C, + 0x9418, 0x8FE0, 0x9419, 0x93A8, 0x941A, 0xE85B, 0x9421, 0xE864, 0x942B, 0xE862, 0x9431, 0xFBE5, 0x9435, 0xE863, 0x9436, 0xE861, + 0x9438, 0x91F6, 0x943A, 0xE865, 0x9441, 0xE866, 0x9444, 0xE868, 0x9445, 0xFBE6, 0x9448, 0xFBE7, 0x9451, 0x8AD3, 0x9452, 0xE867, + 0x9453, 0x96F8, 0x945A, 0xE873, 0x945B, 0xE869, 0x945E, 0xE86C, 0x9460, 0xE86A, 0x9462, 0xE86B, 0x946A, 0xE86D, 0x9470, 0xE86F, + 0x9475, 0xE870, 0x9477, 0xE871, 0x947C, 0xE874, 0x947D, 0xE872, 0x947E, 0xE875, 0x947F, 0xE877, 0x9481, 0xE876, 0x9577, 0x92B7, + 0x9580, 0x96E5, 0x9582, 0xE878, 0x9583, 0x914D, 0x9587, 0xE879, 0x9589, 0x95C2, 0x958A, 0xE87A, 0x958B, 0x8A4A, 0x958F, 0x895B, + 0x9591, 0x8AD5, 0x9592, 0xFBE8, 0x9593, 0x8AD4, 0x9594, 0xE87B, 0x9596, 0xE87C, 0x9598, 0xE87D, 0x9599, 0xE87E, 0x95A0, 0xE880, + 0x95A2, 0x8AD6, 0x95A3, 0x8A74, 0x95A4, 0x8D7D, 0x95A5, 0x94B4, 0x95A7, 0xE882, 0x95A8, 0xE881, 0x95AD, 0xE883, 0x95B2, 0x897B, + 0x95B9, 0xE886, 0x95BB, 0xE885, 0x95BC, 0xE884, 0x95BE, 0xE887, 0x95C3, 0xE88A, 0x95C7, 0x88C5, 0x95CA, 0xE888, 0x95CC, 0xE88C, + 0x95CD, 0xE88B, 0x95D4, 0xE88E, 0x95D5, 0xE88D, 0x95D6, 0xE88F, 0x95D8, 0x93AC, 0x95DC, 0xE890, 0x95E1, 0xE891, 0x95E2, 0xE893, + 0x95E5, 0xE892, 0x961C, 0x958C, 0x9621, 0xE894, 0x9628, 0xE895, 0x962A, 0x8DE3, 0x962E, 0xE896, 0x962F, 0xE897, 0x9632, 0x9668, + 0x963B, 0x916A, 0x963F, 0x88A2, 0x9640, 0x91C9, 0x9642, 0xE898, 0x9644, 0x958D, 0x964B, 0xE89B, 0x964C, 0xE899, 0x964D, 0x8D7E, + 0x964F, 0xE89A, 0x9650, 0x8CC0, 0x965B, 0x95C3, 0x965C, 0xE89D, 0x965D, 0xE89F, 0x965E, 0xE89E, 0x965F, 0xE8A0, 0x9662, 0x8940, + 0x9663, 0x9077, 0x9664, 0x8F9C, 0x9665, 0x8AD7, 0x9666, 0xE8A1, 0x966A, 0x9486, 0x966C, 0xE8A3, 0x9670, 0x8941, 0x9672, 0xE8A2, + 0x9673, 0x92C2, 0x9675, 0x97CB, 0x9676, 0x93A9, 0x9677, 0xE89C, 0x9678, 0x97A4, 0x967A, 0x8CAF, 0x967D, 0x977A, 0x9685, 0x8BF7, + 0x9686, 0x97B2, 0x9688, 0x8C47, 0x968A, 0x91E0, 0x968B, 0xE440, 0x968D, 0xE8A4, 0x968E, 0x8A4B, 0x968F, 0x908F, 0x9694, 0x8A75, + 0x9695, 0xE8A6, 0x9697, 0xE8A7, 0x9698, 0xE8A5, 0x9699, 0x8C84, 0x969B, 0x8DDB, 0x969C, 0x8FE1, 0x969D, 0xFBEB, 0x96A0, 0x8942, + 0x96A3, 0x97D7, 0x96A7, 0xE8A9, 0x96A8, 0xE7AC, 0x96AA, 0xE8A8, 0x96AF, 0xFBEC, 0x96B0, 0xE8AC, 0x96B1, 0xE8AA, 0x96B2, 0xE8AB, + 0x96B4, 0xE8AD, 0x96B6, 0xE8AE, 0x96B7, 0x97EA, 0x96B8, 0xE8AF, 0x96B9, 0xE8B0, 0x96BB, 0x90C7, 0x96BC, 0x94B9, 0x96C0, 0x909D, + 0x96C1, 0x8AE5, 0x96C4, 0x9759, 0x96C5, 0x89EB, 0x96C6, 0x8F57, 0x96C7, 0x8CD9, 0x96C9, 0xE8B3, 0x96CB, 0xE8B2, 0x96CC, 0x8E93, + 0x96CD, 0xE8B4, 0x96CE, 0xE8B1, 0x96D1, 0x8E47, 0x96D5, 0xE8B8, 0x96D6, 0xE5AB, 0x96D9, 0x99D4, 0x96DB, 0x9097, 0x96DC, 0xE8B6, + 0x96E2, 0x97A3, 0x96E3, 0x93EF, 0x96E8, 0x894A, 0x96EA, 0x90E1, 0x96EB, 0x8EB4, 0x96F0, 0x95B5, 0x96F2, 0x895F, 0x96F6, 0x97EB, + 0x96F7, 0x978B, 0x96F9, 0xE8B9, 0x96FB, 0x9364, 0x9700, 0x8EF9, 0x9704, 0xE8BA, 0x9706, 0xE8BB, 0x9707, 0x906B, 0x9708, 0xE8BC, + 0x970A, 0x97EC, 0x970D, 0xE8B7, 0x970E, 0xE8BE, 0x970F, 0xE8C0, 0x9711, 0xE8BF, 0x9713, 0xE8BD, 0x9716, 0xE8C1, 0x9719, 0xE8C2, + 0x971C, 0x919A, 0x971E, 0x89E0, 0x9724, 0xE8C3, 0x9727, 0x96B6, 0x972A, 0xE8C4, 0x9730, 0xE8C5, 0x9732, 0x9849, 0x9733, 0xFBED, + 0x9738, 0x9E50, 0x9739, 0xE8C6, 0x973B, 0xFBEE, 0x973D, 0xE8C7, 0x973E, 0xE8C8, 0x9742, 0xE8CC, 0x9743, 0xFBEF, 0x9744, 0xE8C9, + 0x9746, 0xE8CA, 0x9748, 0xE8CB, 0x9749, 0xE8CD, 0x974D, 0xFBF0, 0x974F, 0xFBF1, 0x9751, 0xFBF2, 0x9752, 0x90C2, 0x9755, 0xFBF3, + 0x9756, 0x96F5, 0x9759, 0x90C3, 0x975C, 0xE8CE, 0x975E, 0x94F1, 0x9760, 0xE8CF, 0x9761, 0xEA72, 0x9762, 0x96CA, 0x9764, 0xE8D0, + 0x9766, 0xE8D1, 0x9768, 0xE8D2, 0x9769, 0x8A76, 0x976B, 0xE8D4, 0x976D, 0x9078, 0x9771, 0xE8D5, 0x9774, 0x8C43, 0x9779, 0xE8D6, + 0x977A, 0xE8DA, 0x977C, 0xE8D8, 0x9781, 0xE8D9, 0x9784, 0x8A93, 0x9785, 0xE8D7, 0x9786, 0xE8DB, 0x978B, 0xE8DC, 0x978D, 0x88C6, + 0x978F, 0xE8DD, 0x9790, 0xE8DE, 0x9798, 0x8FE2, 0x979C, 0xE8DF, 0x97A0, 0x8B66, 0x97A3, 0xE8E2, 0x97A6, 0xE8E1, 0x97A8, 0xE8E0, + 0x97AB, 0xE691, 0x97AD, 0x95DA, 0x97B3, 0xE8E3, 0x97B4, 0xE8E4, 0x97C3, 0xE8E5, 0x97C6, 0xE8E6, 0x97C8, 0xE8E7, 0x97CB, 0xE8E8, + 0x97D3, 0x8AD8, 0x97DC, 0xE8E9, 0x97ED, 0xE8EA, 0x97EE, 0x9442, 0x97F2, 0xE8EC, 0x97F3, 0x89B9, 0x97F5, 0xE8EF, 0x97F6, 0xE8EE, + 0x97FB, 0x8943, 0x97FF, 0x8BBF, 0x9801, 0x95C5, 0x9802, 0x92B8, 0x9803, 0x8DA0, 0x9805, 0x8D80, 0x9806, 0x8F87, 0x9808, 0x907B, + 0x980C, 0xE8F1, 0x980F, 0xE8F0, 0x9810, 0x9761, 0x9811, 0x8AE6, 0x9812, 0x94D0, 0x9813, 0x93DA, 0x9817, 0x909C, 0x9818, 0x97CC, + 0x981A, 0x8C7A, 0x9821, 0xE8F4, 0x9824, 0xE8F3, 0x982C, 0x966A, 0x982D, 0x93AA, 0x9834, 0x896F, 0x9837, 0xE8F5, 0x9838, 0xE8F2, + 0x983B, 0x9570, 0x983C, 0x978A, 0x983D, 0xE8F6, 0x9846, 0xE8F7, 0x984B, 0xE8F9, 0x984C, 0x91E8, 0x984D, 0x8A7A, 0x984E, 0x8A7B, + 0x984F, 0xE8F8, 0x9854, 0x8AE7, 0x9855, 0x8CB0, 0x9857, 0xFBF4, 0x9858, 0x8AE8, 0x985B, 0x935E, 0x985E, 0x97DE, 0x9865, 0xFBF5, + 0x9867, 0x8CDA, 0x986B, 0xE8FA, 0x986F, 0xE8FB, 0x9870, 0xE8FC, 0x9871, 0xE940, 0x9873, 0xE942, 0x9874, 0xE941, 0x98A8, 0x9597, + 0x98AA, 0xE943, 0x98AF, 0xE944, 0x98B1, 0xE945, 0x98B6, 0xE946, 0x98C3, 0xE948, 0x98C4, 0xE947, 0x98C6, 0xE949, 0x98DB, 0x94F2, + 0x98DC, 0xE3CA, 0x98DF, 0x9048, 0x98E2, 0x8B51, 0x98E9, 0xE94A, 0x98EB, 0xE94B, 0x98ED, 0x99AA, 0x98EE, 0x9F5A, 0x98EF, 0x94D1, + 0x98F2, 0x88F9, 0x98F4, 0x88B9, 0x98FC, 0x8E94, 0x98FD, 0x964F, 0x98FE, 0x8FFC, 0x9903, 0xE94C, 0x9905, 0x96DD, 0x9909, 0xE94D, + 0x990A, 0x977B, 0x990C, 0x8961, 0x9910, 0x8E60, 0x9912, 0xE94E, 0x9913, 0x89EC, 0x9914, 0xE94F, 0x9918, 0xE950, 0x991D, 0xE952, + 0x991E, 0xE953, 0x9920, 0xE955, 0x9921, 0xE951, 0x9924, 0xE954, 0x9927, 0xFBF8, 0x9928, 0x8AD9, 0x992C, 0xE956, 0x992E, 0xE957, + 0x993D, 0xE958, 0x993E, 0xE959, 0x9942, 0xE95A, 0x9945, 0xE95C, 0x9949, 0xE95B, 0x994B, 0xE95E, 0x994C, 0xE961, 0x9950, 0xE95D, + 0x9951, 0xE95F, 0x9952, 0xE960, 0x9955, 0xE962, 0x9957, 0x8BC0, 0x9996, 0x8EF1, 0x9997, 0xE963, 0x9998, 0xE964, 0x9999, 0x8D81, + 0x999E, 0xFBFA, 0x99A5, 0xE965, 0x99A8, 0x8A5D, 0x99AC, 0x946E, 0x99AD, 0xE966, 0x99AE, 0xE967, 0x99B3, 0x9279, 0x99B4, 0x93E9, + 0x99BC, 0xE968, 0x99C1, 0x949D, 0x99C4, 0x91CA, 0x99C5, 0x8977, 0x99C6, 0x8BEC, 0x99C8, 0x8BED, 0x99D0, 0x9293, 0x99D1, 0xE96D, + 0x99D2, 0x8BEE, 0x99D5, 0x89ED, 0x99D8, 0xE96C, 0x99DB, 0xE96A, 0x99DD, 0xE96B, 0x99DF, 0xE969, 0x99E2, 0xE977, 0x99ED, 0xE96E, + 0x99EE, 0xE96F, 0x99F1, 0xE970, 0x99F2, 0xE971, 0x99F8, 0xE973, 0x99FB, 0xE972, 0x99FF, 0x8F78, 0x9A01, 0xE974, 0x9A05, 0xE976, + 0x9A0E, 0x8B52, 0x9A0F, 0xE975, 0x9A12, 0x919B, 0x9A13, 0x8CB1, 0x9A19, 0xE978, 0x9A28, 0x91CB, 0x9A2B, 0xE979, 0x9A30, 0x93AB, + 0x9A37, 0xE97A, 0x9A3E, 0xE980, 0x9A40, 0xE97D, 0x9A42, 0xE97C, 0x9A43, 0xE97E, 0x9A45, 0xE97B, 0x9A4D, 0xE982, 0x9A4E, 0xFBFB, + 0x9A55, 0xE981, 0x9A57, 0xE984, 0x9A5A, 0x8BC1, 0x9A5B, 0xE983, 0x9A5F, 0xE985, 0x9A62, 0xE986, 0x9A64, 0xE988, 0x9A65, 0xE987, + 0x9A69, 0xE989, 0x9A6A, 0xE98B, 0x9A6B, 0xE98A, 0x9AA8, 0x8D9C, 0x9AAD, 0xE98C, 0x9AB0, 0xE98D, 0x9AB8, 0x8A5B, 0x9ABC, 0xE98E, + 0x9AC0, 0xE98F, 0x9AC4, 0x9091, 0x9ACF, 0xE990, 0x9AD1, 0xE991, 0x9AD3, 0xE992, 0x9AD4, 0xE993, 0x9AD8, 0x8D82, 0x9AD9, 0xFBFC, + 0x9ADC, 0xFC40, 0x9ADE, 0xE994, 0x9ADF, 0xE995, 0x9AE2, 0xE996, 0x9AE3, 0xE997, 0x9AE6, 0xE998, 0x9AEA, 0x94AF, 0x9AEB, 0xE99A, + 0x9AED, 0x9545, 0x9AEE, 0xE99B, 0x9AEF, 0xE999, 0x9AF1, 0xE99D, 0x9AF4, 0xE99C, 0x9AF7, 0xE99E, 0x9AFB, 0xE99F, 0x9B06, 0xE9A0, + 0x9B18, 0xE9A1, 0x9B1A, 0xE9A2, 0x9B1F, 0xE9A3, 0x9B22, 0xE9A4, 0x9B23, 0xE9A5, 0x9B25, 0xE9A6, 0x9B27, 0xE9A7, 0x9B28, 0xE9A8, + 0x9B29, 0xE9A9, 0x9B2A, 0xE9AA, 0x9B2E, 0xE9AB, 0x9B2F, 0xE9AC, 0x9B31, 0x9F54, 0x9B32, 0xE9AD, 0x9B3B, 0xE2F6, 0x9B3C, 0x8B53, + 0x9B41, 0x8A40, 0x9B42, 0x8DB0, 0x9B43, 0xE9AF, 0x9B44, 0xE9AE, 0x9B45, 0x96A3, 0x9B4D, 0xE9B1, 0x9B4E, 0xE9B2, 0x9B4F, 0xE9B0, + 0x9B51, 0xE9B3, 0x9B54, 0x9682, 0x9B58, 0xE9B4, 0x9B5A, 0x8B9B, 0x9B6F, 0x9844, 0x9B72, 0xFC42, 0x9B74, 0xE9B5, 0x9B75, 0xFC41, + 0x9B83, 0xE9B7, 0x9B8E, 0x88BC, 0x9B8F, 0xFC43, 0x9B91, 0xE9B8, 0x9B92, 0x95A9, 0x9B93, 0xE9B6, 0x9B96, 0xE9B9, 0x9B97, 0xE9BA, + 0x9B9F, 0xE9BB, 0x9BA0, 0xE9BC, 0x9BA8, 0xE9BD, 0x9BAA, 0x968E, 0x9BAB, 0x8E4C, 0x9BAD, 0x8DF8, 0x9BAE, 0x914E, 0x9BB1, 0xFC44, + 0x9BB4, 0xE9BE, 0x9BB9, 0xE9C1, 0x9BBB, 0xFC45, 0x9BC0, 0xE9BF, 0x9BC6, 0xE9C2, 0x9BC9, 0x8CEF, 0x9BCA, 0xE9C0, 0x9BCF, 0xE9C3, + 0x9BD1, 0xE9C4, 0x9BD2, 0xE9C5, 0x9BD4, 0xE9C9, 0x9BD6, 0x8E49, 0x9BDB, 0x91E2, 0x9BE1, 0xE9CA, 0x9BE2, 0xE9C7, 0x9BE3, 0xE9C6, + 0x9BE4, 0xE9C8, 0x9BE8, 0x8C7E, 0x9BF0, 0xE9CE, 0x9BF1, 0xE9CD, 0x9BF2, 0xE9CC, 0x9BF5, 0x88B1, 0x9C00, 0xFC46, 0x9C04, 0xE9D8, + 0x9C06, 0xE9D4, 0x9C08, 0xE9D5, 0x9C09, 0xE9D1, 0x9C0A, 0xE9D7, 0x9C0C, 0xE9D3, 0x9C0D, 0x8A82, 0x9C10, 0x986B, 0x9C12, 0xE9D6, + 0x9C13, 0xE9D2, 0x9C14, 0xE9D0, 0x9C15, 0xE9CF, 0x9C1B, 0xE9DA, 0x9C21, 0xE9DD, 0x9C24, 0xE9DC, 0x9C25, 0xE9DB, 0x9C2D, 0x9568, + 0x9C2E, 0xE9D9, 0x9C2F, 0x88F1, 0x9C30, 0xE9DE, 0x9C32, 0xE9E0, 0x9C39, 0x8A8F, 0x9C3A, 0xE9CB, 0x9C3B, 0x8956, 0x9C3E, 0xE9E2, + 0x9C46, 0xE9E1, 0x9C47, 0xE9DF, 0x9C48, 0x924C, 0x9C52, 0x9690, 0x9C57, 0x97D8, 0x9C5A, 0xE9E3, 0x9C60, 0xE9E4, 0x9C67, 0xE9E5, + 0x9C76, 0xE9E6, 0x9C78, 0xE9E7, 0x9CE5, 0x92B9, 0x9CE7, 0xE9E8, 0x9CE9, 0x94B5, 0x9CEB, 0xE9ED, 0x9CEC, 0xE9E9, 0x9CF0, 0xE9EA, + 0x9CF3, 0x9650, 0x9CF4, 0x96C2, 0x9CF6, 0x93CE, 0x9D03, 0xE9EE, 0x9D06, 0xE9EF, 0x9D07, 0x93BC, 0x9D08, 0xE9EC, 0x9D09, 0xE9EB, + 0x9D0E, 0x89A8, 0x9D12, 0xE9F7, 0x9D15, 0xE9F6, 0x9D1B, 0x8995, 0x9D1F, 0xE9F4, 0x9D23, 0xE9F3, 0x9D26, 0xE9F1, 0x9D28, 0x8A9B, + 0x9D2A, 0xE9F0, 0x9D2B, 0x8EB0, 0x9D2C, 0x89A7, 0x9D3B, 0x8D83, 0x9D3E, 0xE9FA, 0x9D3F, 0xE9F9, 0x9D41, 0xE9F8, 0x9D44, 0xE9F5, + 0x9D46, 0xE9FB, 0x9D48, 0xE9FC, 0x9D50, 0xEA44, 0x9D51, 0xEA43, 0x9D59, 0xEA45, 0x9D5C, 0x894C, 0x9D5D, 0xEA40, 0x9D5E, 0xEA41, + 0x9D60, 0x8D94, 0x9D61, 0x96B7, 0x9D64, 0xEA42, 0x9D6B, 0xFC48, 0x9D6C, 0x9651, 0x9D6F, 0xEA4A, 0x9D70, 0xFC47, 0x9D72, 0xEA46, + 0x9D7A, 0xEA4B, 0x9D87, 0xEA48, 0x9D89, 0xEA47, 0x9D8F, 0x8C7B, 0x9D9A, 0xEA4C, 0x9DA4, 0xEA4D, 0x9DA9, 0xEA4E, 0x9DAB, 0xEA49, + 0x9DAF, 0xE9F2, 0x9DB2, 0xEA4F, 0x9DB4, 0x92DF, 0x9DB8, 0xEA53, 0x9DBA, 0xEA54, 0x9DBB, 0xEA52, 0x9DC1, 0xEA51, 0x9DC2, 0xEA57, + 0x9DC4, 0xEA50, 0x9DC6, 0xEA55, 0x9DCF, 0xEA56, 0x9DD3, 0xEA59, 0x9DD9, 0xEA58, 0x9DE6, 0xEA5B, 0x9DED, 0xEA5C, 0x9DEF, 0xEA5D, + 0x9DF2, 0x9868, 0x9DF8, 0xEA5A, 0x9DF9, 0x91E9, 0x9DFA, 0x8DEB, 0x9DFD, 0xEA5E, 0x9E19, 0xFC4A, 0x9E1A, 0xEA5F, 0x9E1B, 0xEA60, + 0x9E1E, 0xEA61, 0x9E75, 0xEA62, 0x9E78, 0x8CB2, 0x9E79, 0xEA63, 0x9E7D, 0xEA64, 0x9E7F, 0x8EAD, 0x9E81, 0xEA65, 0x9E88, 0xEA66, + 0x9E8B, 0xEA67, 0x9E8C, 0xEA68, 0x9E91, 0xEA6B, 0x9E92, 0xEA69, 0x9E93, 0x985B, 0x9E95, 0xEA6A, 0x9E97, 0x97ED, 0x9E9D, 0xEA6C, + 0x9E9F, 0x97D9, 0x9EA5, 0xEA6D, 0x9EA6, 0x949E, 0x9EA9, 0xEA6E, 0x9EAA, 0xEA70, 0x9EAD, 0xEA71, 0x9EB8, 0xEA6F, 0x9EB9, 0x8D8D, + 0x9EBA, 0x96CB, 0x9EBB, 0x9683, 0x9EBC, 0x9BF5, 0x9EBE, 0x9F80, 0x9EBF, 0x969B, 0x9EC4, 0x89A9, 0x9ECC, 0xEA73, 0x9ECD, 0x8B6F, + 0x9ECE, 0xEA74, 0x9ECF, 0xEA75, 0x9ED0, 0xEA76, 0x9ED1, 0xFC4B, 0x9ED2, 0x8D95, 0x9ED4, 0xEA77, 0x9ED8, 0xE0D2, 0x9ED9, 0x96D9, + 0x9EDB, 0x91E1, 0x9EDC, 0xEA78, 0x9EDD, 0xEA7A, 0x9EDE, 0xEA79, 0x9EE0, 0xEA7B, 0x9EE5, 0xEA7C, 0x9EE8, 0xEA7D, 0x9EEF, 0xEA7E, + 0x9EF4, 0xEA80, 0x9EF6, 0xEA81, 0x9EF7, 0xEA82, 0x9EF9, 0xEA83, 0x9EFB, 0xEA84, 0x9EFC, 0xEA85, 0x9EFD, 0xEA86, 0x9F07, 0xEA87, + 0x9F08, 0xEA88, 0x9F0E, 0x9343, 0x9F13, 0x8CDB, 0x9F15, 0xEA8A, 0x9F20, 0x916C, 0x9F21, 0xEA8B, 0x9F2C, 0xEA8C, 0x9F3B, 0x9540, + 0x9F3E, 0xEA8D, 0x9F4A, 0xEA8E, 0x9F4B, 0xE256, 0x9F4E, 0xE6D8, 0x9F4F, 0xE8EB, 0x9F52, 0xEA8F, 0x9F54, 0xEA90, 0x9F5F, 0xEA92, + 0x9F60, 0xEA93, 0x9F61, 0xEA94, 0x9F62, 0x97EE, 0x9F63, 0xEA91, 0x9F66, 0xEA95, 0x9F67, 0xEA96, 0x9F6A, 0xEA98, 0x9F6C, 0xEA97, + 0x9F72, 0xEA9A, 0x9F76, 0xEA9B, 0x9F77, 0xEA99, 0x9F8D, 0x97B4, 0x9F95, 0xEA9C, 0x9F9C, 0xEA9D, 0x9F9D, 0xE273, 0x9FA0, 0xEA9E, + 0xF929, 0xFAE0, 0xF9DC, 0xFBE9, 0xFA0E, 0xFA90, 0xFA0F, 0xFA9B, 0xFA10, 0xFA9C, 0xFA11, 0xFAB1, 0xFA12, 0xFAD8, 0xFA13, 0xFAE8, + 0xFA14, 0xFAEA, 0xFA15, 0xFB58, 0xFA16, 0xFB5E, 0xFA17, 0xFB75, 0xFA18, 0xFB7D, 0xFA19, 0xFB7E, 0xFA1A, 0xFB80, 0xFA1B, 0xFB82, + 0xFA1C, 0xFB86, 0xFA1D, 0xFB89, 0xFA1E, 0xFB92, 0xFA1F, 0xFB9D, 0xFA20, 0xFB9F, 0xFA21, 0xFBA0, 0xFA22, 0xFBA9, 0xFA23, 0xFBB1, + 0xFA24, 0xFBB3, 0xFA25, 0xFBB4, 0xFA26, 0xFBB7, 0xFA27, 0xFBD3, 0xFA28, 0xFBDA, 0xFA29, 0xFBEA, 0xFA2A, 0xFBF6, 0xFA2B, 0xFBF7, + 0xFA2C, 0xFBF9, 0xFA2D, 0xFC49, 0xFF01, 0x8149, 0xFF02, 0xFA57, 0xFF03, 0x8194, 0xFF04, 0x8190, 0xFF05, 0x8193, 0xFF06, 0x8195, + 0xFF07, 0xFA56, 0xFF08, 0x8169, 0xFF09, 0x816A, 0xFF0A, 0x8196, 0xFF0B, 0x817B, 0xFF0C, 0x8143, 0xFF0D, 0x817C, 0xFF0E, 0x8144, + 0xFF0F, 0x815E, 0xFF10, 0x824F, 0xFF11, 0x8250, 0xFF12, 0x8251, 0xFF13, 0x8252, 0xFF14, 0x8253, 0xFF15, 0x8254, 0xFF16, 0x8255, + 0xFF17, 0x8256, 0xFF18, 0x8257, 0xFF19, 0x8258, 0xFF1A, 0x8146, 0xFF1B, 0x8147, 0xFF1C, 0x8183, 0xFF1D, 0x8181, 0xFF1E, 0x8184, + 0xFF1F, 0x8148, 0xFF20, 0x8197, 0xFF21, 0x8260, 0xFF22, 0x8261, 0xFF23, 0x8262, 0xFF24, 0x8263, 0xFF25, 0x8264, 0xFF26, 0x8265, + 0xFF27, 0x8266, 0xFF28, 0x8267, 0xFF29, 0x8268, 0xFF2A, 0x8269, 0xFF2B, 0x826A, 0xFF2C, 0x826B, 0xFF2D, 0x826C, 0xFF2E, 0x826D, + 0xFF2F, 0x826E, 0xFF30, 0x826F, 0xFF31, 0x8270, 0xFF32, 0x8271, 0xFF33, 0x8272, 0xFF34, 0x8273, 0xFF35, 0x8274, 0xFF36, 0x8275, + 0xFF37, 0x8276, 0xFF38, 0x8277, 0xFF39, 0x8278, 0xFF3A, 0x8279, 0xFF3B, 0x816D, 0xFF3C, 0x815F, 0xFF3D, 0x816E, 0xFF3E, 0x814F, + 0xFF3F, 0x8151, 0xFF40, 0x814D, 0xFF41, 0x8281, 0xFF42, 0x8282, 0xFF43, 0x8283, 0xFF44, 0x8284, 0xFF45, 0x8285, 0xFF46, 0x8286, + 0xFF47, 0x8287, 0xFF48, 0x8288, 0xFF49, 0x8289, 0xFF4A, 0x828A, 0xFF4B, 0x828B, 0xFF4C, 0x828C, 0xFF4D, 0x828D, 0xFF4E, 0x828E, + 0xFF4F, 0x828F, 0xFF50, 0x8290, 0xFF51, 0x8291, 0xFF52, 0x8292, 0xFF53, 0x8293, 0xFF54, 0x8294, 0xFF55, 0x8295, 0xFF56, 0x8296, + 0xFF57, 0x8297, 0xFF58, 0x8298, 0xFF59, 0x8299, 0xFF5A, 0x829A, 0xFF5B, 0x816F, 0xFF5C, 0x8162, 0xFF5D, 0x8170, 0xFF5E, 0x8160, + 0xFF61, 0x00A1, 0xFF62, 0x00A2, 0xFF63, 0x00A3, 0xFF64, 0x00A4, 0xFF65, 0x00A5, 0xFF66, 0x00A6, 0xFF67, 0x00A7, 0xFF68, 0x00A8, + 0xFF69, 0x00A9, 0xFF6A, 0x00AA, 0xFF6B, 0x00AB, 0xFF6C, 0x00AC, 0xFF6D, 0x00AD, 0xFF6E, 0x00AE, 0xFF6F, 0x00AF, 0xFF70, 0x00B0, + 0xFF71, 0x00B1, 0xFF72, 0x00B2, 0xFF73, 0x00B3, 0xFF74, 0x00B4, 0xFF75, 0x00B5, 0xFF76, 0x00B6, 0xFF77, 0x00B7, 0xFF78, 0x00B8, + 0xFF79, 0x00B9, 0xFF7A, 0x00BA, 0xFF7B, 0x00BB, 0xFF7C, 0x00BC, 0xFF7D, 0x00BD, 0xFF7E, 0x00BE, 0xFF7F, 0x00BF, 0xFF80, 0x00C0, + 0xFF81, 0x00C1, 0xFF82, 0x00C2, 0xFF83, 0x00C3, 0xFF84, 0x00C4, 0xFF85, 0x00C5, 0xFF86, 0x00C6, 0xFF87, 0x00C7, 0xFF88, 0x00C8, + 0xFF89, 0x00C9, 0xFF8A, 0x00CA, 0xFF8B, 0x00CB, 0xFF8C, 0x00CC, 0xFF8D, 0x00CD, 0xFF8E, 0x00CE, 0xFF8F, 0x00CF, 0xFF90, 0x00D0, + 0xFF91, 0x00D1, 0xFF92, 0x00D2, 0xFF93, 0x00D3, 0xFF94, 0x00D4, 0xFF95, 0x00D5, 0xFF96, 0x00D6, 0xFF97, 0x00D7, 0xFF98, 0x00D8, + 0xFF99, 0x00D9, 0xFF9A, 0x00DA, 0xFF9B, 0x00DB, 0xFF9C, 0x00DC, 0xFF9D, 0x00DD, 0xFF9E, 0x00DE, 0xFF9F, 0x00DF, 0xFFE0, 0x8191, + 0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0 +}; + +static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ + 0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68, + 0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70, + 0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78, + 0x00B9, 0xFF79, 0x00BA, 0xFF7A, 0x00BB, 0xFF7B, 0x00BC, 0xFF7C, 0x00BD, 0xFF7D, 0x00BE, 0xFF7E, 0x00BF, 0xFF7F, 0x00C0, 0xFF80, + 0x00C1, 0xFF81, 0x00C2, 0xFF82, 0x00C3, 0xFF83, 0x00C4, 0xFF84, 0x00C5, 0xFF85, 0x00C6, 0xFF86, 0x00C7, 0xFF87, 0x00C8, 0xFF88, + 0x00C9, 0xFF89, 0x00CA, 0xFF8A, 0x00CB, 0xFF8B, 0x00CC, 0xFF8C, 0x00CD, 0xFF8D, 0x00CE, 0xFF8E, 0x00CF, 0xFF8F, 0x00D0, 0xFF90, + 0x00D1, 0xFF91, 0x00D2, 0xFF92, 0x00D3, 0xFF93, 0x00D4, 0xFF94, 0x00D5, 0xFF95, 0x00D6, 0xFF96, 0x00D7, 0xFF97, 0x00D8, 0xFF98, + 0x00D9, 0xFF99, 0x00DA, 0xFF9A, 0x00DB, 0xFF9B, 0x00DC, 0xFF9C, 0x00DD, 0xFF9D, 0x00DE, 0xFF9E, 0x00DF, 0xFF9F, 0x8140, 0x3000, + 0x8141, 0x3001, 0x8142, 0x3002, 0x8143, 0xFF0C, 0x8144, 0xFF0E, 0x8145, 0x30FB, 0x8146, 0xFF1A, 0x8147, 0xFF1B, 0x8148, 0xFF1F, + 0x8149, 0xFF01, 0x814A, 0x309B, 0x814B, 0x309C, 0x814C, 0x00B4, 0x814D, 0xFF40, 0x814E, 0x00A8, 0x814F, 0xFF3E, 0x8150, 0xFFE3, + 0x8151, 0xFF3F, 0x8152, 0x30FD, 0x8153, 0x30FE, 0x8154, 0x309D, 0x8155, 0x309E, 0x8156, 0x3003, 0x8157, 0x4EDD, 0x8158, 0x3005, + 0x8159, 0x3006, 0x815A, 0x3007, 0x815B, 0x30FC, 0x815C, 0x2015, 0x815D, 0x2010, 0x815E, 0xFF0F, 0x815F, 0xFF3C, 0x8160, 0xFF5E, + 0x8161, 0x2225, 0x8162, 0xFF5C, 0x8163, 0x2026, 0x8164, 0x2025, 0x8165, 0x2018, 0x8166, 0x2019, 0x8167, 0x201C, 0x8168, 0x201D, + 0x8169, 0xFF08, 0x816A, 0xFF09, 0x816B, 0x3014, 0x816C, 0x3015, 0x816D, 0xFF3B, 0x816E, 0xFF3D, 0x816F, 0xFF5B, 0x8170, 0xFF5D, + 0x8171, 0x3008, 0x8172, 0x3009, 0x8173, 0x300A, 0x8174, 0x300B, 0x8175, 0x300C, 0x8176, 0x300D, 0x8177, 0x300E, 0x8178, 0x300F, + 0x8179, 0x3010, 0x817A, 0x3011, 0x817B, 0xFF0B, 0x817C, 0xFF0D, 0x817D, 0x00B1, 0x817E, 0x00D7, 0x8180, 0x00F7, 0x8181, 0xFF1D, + 0x8182, 0x2260, 0x8183, 0xFF1C, 0x8184, 0xFF1E, 0x8185, 0x2266, 0x8186, 0x2267, 0x8187, 0x221E, 0x8188, 0x2234, 0x8189, 0x2642, + 0x818A, 0x2640, 0x818B, 0x00B0, 0x818C, 0x2032, 0x818D, 0x2033, 0x818E, 0x2103, 0x818F, 0xFFE5, 0x8190, 0xFF04, 0x8191, 0xFFE0, + 0x8192, 0xFFE1, 0x8193, 0xFF05, 0x8194, 0xFF03, 0x8195, 0xFF06, 0x8196, 0xFF0A, 0x8197, 0xFF20, 0x8198, 0x00A7, 0x8199, 0x2606, + 0x819A, 0x2605, 0x819B, 0x25CB, 0x819C, 0x25CF, 0x819D, 0x25CE, 0x819E, 0x25C7, 0x819F, 0x25C6, 0x81A0, 0x25A1, 0x81A1, 0x25A0, + 0x81A2, 0x25B3, 0x81A3, 0x25B2, 0x81A4, 0x25BD, 0x81A5, 0x25BC, 0x81A6, 0x203B, 0x81A7, 0x3012, 0x81A8, 0x2192, 0x81A9, 0x2190, + 0x81AA, 0x2191, 0x81AB, 0x2193, 0x81AC, 0x3013, 0x81B8, 0x2208, 0x81B9, 0x220B, 0x81BA, 0x2286, 0x81BB, 0x2287, 0x81BC, 0x2282, + 0x81BD, 0x2283, 0x81BE, 0x222A, 0x81BF, 0x2229, 0x81C8, 0x2227, 0x81C9, 0x2228, 0x81CA, 0xFFE2, 0x81CB, 0x21D2, 0x81CC, 0x21D4, + 0x81CD, 0x2200, 0x81CE, 0x2203, 0x81DA, 0x2220, 0x81DB, 0x22A5, 0x81DC, 0x2312, 0x81DD, 0x2202, 0x81DE, 0x2207, 0x81DF, 0x2261, + 0x81E0, 0x2252, 0x81E1, 0x226A, 0x81E2, 0x226B, 0x81E3, 0x221A, 0x81E4, 0x223D, 0x81E5, 0x221D, 0x81E6, 0x2235, 0x81E7, 0x222B, + 0x81E8, 0x222C, 0x81F0, 0x212B, 0x81F1, 0x2030, 0x81F2, 0x266F, 0x81F3, 0x266D, 0x81F4, 0x266A, 0x81F5, 0x2020, 0x81F6, 0x2021, + 0x81F7, 0x00B6, 0x81FC, 0x25EF, 0x824F, 0xFF10, 0x8250, 0xFF11, 0x8251, 0xFF12, 0x8252, 0xFF13, 0x8253, 0xFF14, 0x8254, 0xFF15, + 0x8255, 0xFF16, 0x8256, 0xFF17, 0x8257, 0xFF18, 0x8258, 0xFF19, 0x8260, 0xFF21, 0x8261, 0xFF22, 0x8262, 0xFF23, 0x8263, 0xFF24, + 0x8264, 0xFF25, 0x8265, 0xFF26, 0x8266, 0xFF27, 0x8267, 0xFF28, 0x8268, 0xFF29, 0x8269, 0xFF2A, 0x826A, 0xFF2B, 0x826B, 0xFF2C, + 0x826C, 0xFF2D, 0x826D, 0xFF2E, 0x826E, 0xFF2F, 0x826F, 0xFF30, 0x8270, 0xFF31, 0x8271, 0xFF32, 0x8272, 0xFF33, 0x8273, 0xFF34, + 0x8274, 0xFF35, 0x8275, 0xFF36, 0x8276, 0xFF37, 0x8277, 0xFF38, 0x8278, 0xFF39, 0x8279, 0xFF3A, 0x8281, 0xFF41, 0x8282, 0xFF42, + 0x8283, 0xFF43, 0x8284, 0xFF44, 0x8285, 0xFF45, 0x8286, 0xFF46, 0x8287, 0xFF47, 0x8288, 0xFF48, 0x8289, 0xFF49, 0x828A, 0xFF4A, + 0x828B, 0xFF4B, 0x828C, 0xFF4C, 0x828D, 0xFF4D, 0x828E, 0xFF4E, 0x828F, 0xFF4F, 0x8290, 0xFF50, 0x8291, 0xFF51, 0x8292, 0xFF52, + 0x8293, 0xFF53, 0x8294, 0xFF54, 0x8295, 0xFF55, 0x8296, 0xFF56, 0x8297, 0xFF57, 0x8298, 0xFF58, 0x8299, 0xFF59, 0x829A, 0xFF5A, + 0x829F, 0x3041, 0x82A0, 0x3042, 0x82A1, 0x3043, 0x82A2, 0x3044, 0x82A3, 0x3045, 0x82A4, 0x3046, 0x82A5, 0x3047, 0x82A6, 0x3048, + 0x82A7, 0x3049, 0x82A8, 0x304A, 0x82A9, 0x304B, 0x82AA, 0x304C, 0x82AB, 0x304D, 0x82AC, 0x304E, 0x82AD, 0x304F, 0x82AE, 0x3050, + 0x82AF, 0x3051, 0x82B0, 0x3052, 0x82B1, 0x3053, 0x82B2, 0x3054, 0x82B3, 0x3055, 0x82B4, 0x3056, 0x82B5, 0x3057, 0x82B6, 0x3058, + 0x82B7, 0x3059, 0x82B8, 0x305A, 0x82B9, 0x305B, 0x82BA, 0x305C, 0x82BB, 0x305D, 0x82BC, 0x305E, 0x82BD, 0x305F, 0x82BE, 0x3060, + 0x82BF, 0x3061, 0x82C0, 0x3062, 0x82C1, 0x3063, 0x82C2, 0x3064, 0x82C3, 0x3065, 0x82C4, 0x3066, 0x82C5, 0x3067, 0x82C6, 0x3068, + 0x82C7, 0x3069, 0x82C8, 0x306A, 0x82C9, 0x306B, 0x82CA, 0x306C, 0x82CB, 0x306D, 0x82CC, 0x306E, 0x82CD, 0x306F, 0x82CE, 0x3070, + 0x82CF, 0x3071, 0x82D0, 0x3072, 0x82D1, 0x3073, 0x82D2, 0x3074, 0x82D3, 0x3075, 0x82D4, 0x3076, 0x82D5, 0x3077, 0x82D6, 0x3078, + 0x82D7, 0x3079, 0x82D8, 0x307A, 0x82D9, 0x307B, 0x82DA, 0x307C, 0x82DB, 0x307D, 0x82DC, 0x307E, 0x82DD, 0x307F, 0x82DE, 0x3080, + 0x82DF, 0x3081, 0x82E0, 0x3082, 0x82E1, 0x3083, 0x82E2, 0x3084, 0x82E3, 0x3085, 0x82E4, 0x3086, 0x82E5, 0x3087, 0x82E6, 0x3088, + 0x82E7, 0x3089, 0x82E8, 0x308A, 0x82E9, 0x308B, 0x82EA, 0x308C, 0x82EB, 0x308D, 0x82EC, 0x308E, 0x82ED, 0x308F, 0x82EE, 0x3090, + 0x82EF, 0x3091, 0x82F0, 0x3092, 0x82F1, 0x3093, 0x8340, 0x30A1, 0x8341, 0x30A2, 0x8342, 0x30A3, 0x8343, 0x30A4, 0x8344, 0x30A5, + 0x8345, 0x30A6, 0x8346, 0x30A7, 0x8347, 0x30A8, 0x8348, 0x30A9, 0x8349, 0x30AA, 0x834A, 0x30AB, 0x834B, 0x30AC, 0x834C, 0x30AD, + 0x834D, 0x30AE, 0x834E, 0x30AF, 0x834F, 0x30B0, 0x8350, 0x30B1, 0x8351, 0x30B2, 0x8352, 0x30B3, 0x8353, 0x30B4, 0x8354, 0x30B5, + 0x8355, 0x30B6, 0x8356, 0x30B7, 0x8357, 0x30B8, 0x8358, 0x30B9, 0x8359, 0x30BA, 0x835A, 0x30BB, 0x835B, 0x30BC, 0x835C, 0x30BD, + 0x835D, 0x30BE, 0x835E, 0x30BF, 0x835F, 0x30C0, 0x8360, 0x30C1, 0x8361, 0x30C2, 0x8362, 0x30C3, 0x8363, 0x30C4, 0x8364, 0x30C5, + 0x8365, 0x30C6, 0x8366, 0x30C7, 0x8367, 0x30C8, 0x8368, 0x30C9, 0x8369, 0x30CA, 0x836A, 0x30CB, 0x836B, 0x30CC, 0x836C, 0x30CD, + 0x836D, 0x30CE, 0x836E, 0x30CF, 0x836F, 0x30D0, 0x8370, 0x30D1, 0x8371, 0x30D2, 0x8372, 0x30D3, 0x8373, 0x30D4, 0x8374, 0x30D5, + 0x8375, 0x30D6, 0x8376, 0x30D7, 0x8377, 0x30D8, 0x8378, 0x30D9, 0x8379, 0x30DA, 0x837A, 0x30DB, 0x837B, 0x30DC, 0x837C, 0x30DD, + 0x837D, 0x30DE, 0x837E, 0x30DF, 0x8380, 0x30E0, 0x8381, 0x30E1, 0x8382, 0x30E2, 0x8383, 0x30E3, 0x8384, 0x30E4, 0x8385, 0x30E5, + 0x8386, 0x30E6, 0x8387, 0x30E7, 0x8388, 0x30E8, 0x8389, 0x30E9, 0x838A, 0x30EA, 0x838B, 0x30EB, 0x838C, 0x30EC, 0x838D, 0x30ED, + 0x838E, 0x30EE, 0x838F, 0x30EF, 0x8390, 0x30F0, 0x8391, 0x30F1, 0x8392, 0x30F2, 0x8393, 0x30F3, 0x8394, 0x30F4, 0x8395, 0x30F5, + 0x8396, 0x30F6, 0x839F, 0x0391, 0x83A0, 0x0392, 0x83A1, 0x0393, 0x83A2, 0x0394, 0x83A3, 0x0395, 0x83A4, 0x0396, 0x83A5, 0x0397, + 0x83A6, 0x0398, 0x83A7, 0x0399, 0x83A8, 0x039A, 0x83A9, 0x039B, 0x83AA, 0x039C, 0x83AB, 0x039D, 0x83AC, 0x039E, 0x83AD, 0x039F, + 0x83AE, 0x03A0, 0x83AF, 0x03A1, 0x83B0, 0x03A3, 0x83B1, 0x03A4, 0x83B2, 0x03A5, 0x83B3, 0x03A6, 0x83B4, 0x03A7, 0x83B5, 0x03A8, + 0x83B6, 0x03A9, 0x83BF, 0x03B1, 0x83C0, 0x03B2, 0x83C1, 0x03B3, 0x83C2, 0x03B4, 0x83C3, 0x03B5, 0x83C4, 0x03B6, 0x83C5, 0x03B7, + 0x83C6, 0x03B8, 0x83C7, 0x03B9, 0x83C8, 0x03BA, 0x83C9, 0x03BB, 0x83CA, 0x03BC, 0x83CB, 0x03BD, 0x83CC, 0x03BE, 0x83CD, 0x03BF, + 0x83CE, 0x03C0, 0x83CF, 0x03C1, 0x83D0, 0x03C3, 0x83D1, 0x03C4, 0x83D2, 0x03C5, 0x83D3, 0x03C6, 0x83D4, 0x03C7, 0x83D5, 0x03C8, + 0x83D6, 0x03C9, 0x8440, 0x0410, 0x8441, 0x0411, 0x8442, 0x0412, 0x8443, 0x0413, 0x8444, 0x0414, 0x8445, 0x0415, 0x8446, 0x0401, + 0x8447, 0x0416, 0x8448, 0x0417, 0x8449, 0x0418, 0x844A, 0x0419, 0x844B, 0x041A, 0x844C, 0x041B, 0x844D, 0x041C, 0x844E, 0x041D, + 0x844F, 0x041E, 0x8450, 0x041F, 0x8451, 0x0420, 0x8452, 0x0421, 0x8453, 0x0422, 0x8454, 0x0423, 0x8455, 0x0424, 0x8456, 0x0425, + 0x8457, 0x0426, 0x8458, 0x0427, 0x8459, 0x0428, 0x845A, 0x0429, 0x845B, 0x042A, 0x845C, 0x042B, 0x845D, 0x042C, 0x845E, 0x042D, + 0x845F, 0x042E, 0x8460, 0x042F, 0x8470, 0x0430, 0x8471, 0x0431, 0x8472, 0x0432, 0x8473, 0x0433, 0x8474, 0x0434, 0x8475, 0x0435, + 0x8476, 0x0451, 0x8477, 0x0436, 0x8478, 0x0437, 0x8479, 0x0438, 0x847A, 0x0439, 0x847B, 0x043A, 0x847C, 0x043B, 0x847D, 0x043C, + 0x847E, 0x043D, 0x8480, 0x043E, 0x8481, 0x043F, 0x8482, 0x0440, 0x8483, 0x0441, 0x8484, 0x0442, 0x8485, 0x0443, 0x8486, 0x0444, + 0x8487, 0x0445, 0x8488, 0x0446, 0x8489, 0x0447, 0x848A, 0x0448, 0x848B, 0x0449, 0x848C, 0x044A, 0x848D, 0x044B, 0x848E, 0x044C, + 0x848F, 0x044D, 0x8490, 0x044E, 0x8491, 0x044F, 0x849F, 0x2500, 0x84A0, 0x2502, 0x84A1, 0x250C, 0x84A2, 0x2510, 0x84A3, 0x2518, + 0x84A4, 0x2514, 0x84A5, 0x251C, 0x84A6, 0x252C, 0x84A7, 0x2524, 0x84A8, 0x2534, 0x84A9, 0x253C, 0x84AA, 0x2501, 0x84AB, 0x2503, + 0x84AC, 0x250F, 0x84AD, 0x2513, 0x84AE, 0x251B, 0x84AF, 0x2517, 0x84B0, 0x2523, 0x84B1, 0x2533, 0x84B2, 0x252B, 0x84B3, 0x253B, + 0x84B4, 0x254B, 0x84B5, 0x2520, 0x84B6, 0x252F, 0x84B7, 0x2528, 0x84B8, 0x2537, 0x84B9, 0x253F, 0x84BA, 0x251D, 0x84BB, 0x2530, + 0x84BC, 0x2525, 0x84BD, 0x2538, 0x84BE, 0x2542, 0x8740, 0x2460, 0x8741, 0x2461, 0x8742, 0x2462, 0x8743, 0x2463, 0x8744, 0x2464, + 0x8745, 0x2465, 0x8746, 0x2466, 0x8747, 0x2467, 0x8748, 0x2468, 0x8749, 0x2469, 0x874A, 0x246A, 0x874B, 0x246B, 0x874C, 0x246C, + 0x874D, 0x246D, 0x874E, 0x246E, 0x874F, 0x246F, 0x8750, 0x2470, 0x8751, 0x2471, 0x8752, 0x2472, 0x8753, 0x2473, 0x8754, 0x2160, + 0x8755, 0x2161, 0x8756, 0x2162, 0x8757, 0x2163, 0x8758, 0x2164, 0x8759, 0x2165, 0x875A, 0x2166, 0x875B, 0x2167, 0x875C, 0x2168, + 0x875D, 0x2169, 0x875F, 0x3349, 0x8760, 0x3314, 0x8761, 0x3322, 0x8762, 0x334D, 0x8763, 0x3318, 0x8764, 0x3327, 0x8765, 0x3303, + 0x8766, 0x3336, 0x8767, 0x3351, 0x8768, 0x3357, 0x8769, 0x330D, 0x876A, 0x3326, 0x876B, 0x3323, 0x876C, 0x332B, 0x876D, 0x334A, + 0x876E, 0x333B, 0x876F, 0x339C, 0x8770, 0x339D, 0x8771, 0x339E, 0x8772, 0x338E, 0x8773, 0x338F, 0x8774, 0x33C4, 0x8775, 0x33A1, + 0x877E, 0x337B, 0x8780, 0x301D, 0x8781, 0x301F, 0x8782, 0x2116, 0x8783, 0x33CD, 0x8784, 0x2121, 0x8785, 0x32A4, 0x8786, 0x32A5, + 0x8787, 0x32A6, 0x8788, 0x32A7, 0x8789, 0x32A8, 0x878A, 0x3231, 0x878B, 0x3232, 0x878C, 0x3239, 0x878D, 0x337E, 0x878E, 0x337D, + 0x878F, 0x337C, 0x8793, 0x222E, 0x8794, 0x2211, 0x8798, 0x221F, 0x8799, 0x22BF, 0x889F, 0x4E9C, 0x88A0, 0x5516, 0x88A1, 0x5A03, + 0x88A2, 0x963F, 0x88A3, 0x54C0, 0x88A4, 0x611B, 0x88A5, 0x6328, 0x88A6, 0x59F6, 0x88A7, 0x9022, 0x88A8, 0x8475, 0x88A9, 0x831C, + 0x88AA, 0x7A50, 0x88AB, 0x60AA, 0x88AC, 0x63E1, 0x88AD, 0x6E25, 0x88AE, 0x65ED, 0x88AF, 0x8466, 0x88B0, 0x82A6, 0x88B1, 0x9BF5, + 0x88B2, 0x6893, 0x88B3, 0x5727, 0x88B4, 0x65A1, 0x88B5, 0x6271, 0x88B6, 0x5B9B, 0x88B7, 0x59D0, 0x88B8, 0x867B, 0x88B9, 0x98F4, + 0x88BA, 0x7D62, 0x88BB, 0x7DBE, 0x88BC, 0x9B8E, 0x88BD, 0x6216, 0x88BE, 0x7C9F, 0x88BF, 0x88B7, 0x88C0, 0x5B89, 0x88C1, 0x5EB5, + 0x88C2, 0x6309, 0x88C3, 0x6697, 0x88C4, 0x6848, 0x88C5, 0x95C7, 0x88C6, 0x978D, 0x88C7, 0x674F, 0x88C8, 0x4EE5, 0x88C9, 0x4F0A, + 0x88CA, 0x4F4D, 0x88CB, 0x4F9D, 0x88CC, 0x5049, 0x88CD, 0x56F2, 0x88CE, 0x5937, 0x88CF, 0x59D4, 0x88D0, 0x5A01, 0x88D1, 0x5C09, + 0x88D2, 0x60DF, 0x88D3, 0x610F, 0x88D4, 0x6170, 0x88D5, 0x6613, 0x88D6, 0x6905, 0x88D7, 0x70BA, 0x88D8, 0x754F, 0x88D9, 0x7570, + 0x88DA, 0x79FB, 0x88DB, 0x7DAD, 0x88DC, 0x7DEF, 0x88DD, 0x80C3, 0x88DE, 0x840E, 0x88DF, 0x8863, 0x88E0, 0x8B02, 0x88E1, 0x9055, + 0x88E2, 0x907A, 0x88E3, 0x533B, 0x88E4, 0x4E95, 0x88E5, 0x4EA5, 0x88E6, 0x57DF, 0x88E7, 0x80B2, 0x88E8, 0x90C1, 0x88E9, 0x78EF, + 0x88EA, 0x4E00, 0x88EB, 0x58F1, 0x88EC, 0x6EA2, 0x88ED, 0x9038, 0x88EE, 0x7A32, 0x88EF, 0x8328, 0x88F0, 0x828B, 0x88F1, 0x9C2F, + 0x88F2, 0x5141, 0x88F3, 0x5370, 0x88F4, 0x54BD, 0x88F5, 0x54E1, 0x88F6, 0x56E0, 0x88F7, 0x59FB, 0x88F8, 0x5F15, 0x88F9, 0x98F2, + 0x88FA, 0x6DEB, 0x88FB, 0x80E4, 0x88FC, 0x852D, 0x8940, 0x9662, 0x8941, 0x9670, 0x8942, 0x96A0, 0x8943, 0x97FB, 0x8944, 0x540B, + 0x8945, 0x53F3, 0x8946, 0x5B87, 0x8947, 0x70CF, 0x8948, 0x7FBD, 0x8949, 0x8FC2, 0x894A, 0x96E8, 0x894B, 0x536F, 0x894C, 0x9D5C, + 0x894D, 0x7ABA, 0x894E, 0x4E11, 0x894F, 0x7893, 0x8950, 0x81FC, 0x8951, 0x6E26, 0x8952, 0x5618, 0x8953, 0x5504, 0x8954, 0x6B1D, + 0x8955, 0x851A, 0x8956, 0x9C3B, 0x8957, 0x59E5, 0x8958, 0x53A9, 0x8959, 0x6D66, 0x895A, 0x74DC, 0x895B, 0x958F, 0x895C, 0x5642, + 0x895D, 0x4E91, 0x895E, 0x904B, 0x895F, 0x96F2, 0x8960, 0x834F, 0x8961, 0x990C, 0x8962, 0x53E1, 0x8963, 0x55B6, 0x8964, 0x5B30, + 0x8965, 0x5F71, 0x8966, 0x6620, 0x8967, 0x66F3, 0x8968, 0x6804, 0x8969, 0x6C38, 0x896A, 0x6CF3, 0x896B, 0x6D29, 0x896C, 0x745B, + 0x896D, 0x76C8, 0x896E, 0x7A4E, 0x896F, 0x9834, 0x8970, 0x82F1, 0x8971, 0x885B, 0x8972, 0x8A60, 0x8973, 0x92ED, 0x8974, 0x6DB2, + 0x8975, 0x75AB, 0x8976, 0x76CA, 0x8977, 0x99C5, 0x8978, 0x60A6, 0x8979, 0x8B01, 0x897A, 0x8D8A, 0x897B, 0x95B2, 0x897C, 0x698E, + 0x897D, 0x53AD, 0x897E, 0x5186, 0x8980, 0x5712, 0x8981, 0x5830, 0x8982, 0x5944, 0x8983, 0x5BB4, 0x8984, 0x5EF6, 0x8985, 0x6028, + 0x8986, 0x63A9, 0x8987, 0x63F4, 0x8988, 0x6CBF, 0x8989, 0x6F14, 0x898A, 0x708E, 0x898B, 0x7114, 0x898C, 0x7159, 0x898D, 0x71D5, + 0x898E, 0x733F, 0x898F, 0x7E01, 0x8990, 0x8276, 0x8991, 0x82D1, 0x8992, 0x8597, 0x8993, 0x9060, 0x8994, 0x925B, 0x8995, 0x9D1B, + 0x8996, 0x5869, 0x8997, 0x65BC, 0x8998, 0x6C5A, 0x8999, 0x7525, 0x899A, 0x51F9, 0x899B, 0x592E, 0x899C, 0x5965, 0x899D, 0x5F80, + 0x899E, 0x5FDC, 0x899F, 0x62BC, 0x89A0, 0x65FA, 0x89A1, 0x6A2A, 0x89A2, 0x6B27, 0x89A3, 0x6BB4, 0x89A4, 0x738B, 0x89A5, 0x7FC1, + 0x89A6, 0x8956, 0x89A7, 0x9D2C, 0x89A8, 0x9D0E, 0x89A9, 0x9EC4, 0x89AA, 0x5CA1, 0x89AB, 0x6C96, 0x89AC, 0x837B, 0x89AD, 0x5104, + 0x89AE, 0x5C4B, 0x89AF, 0x61B6, 0x89B0, 0x81C6, 0x89B1, 0x6876, 0x89B2, 0x7261, 0x89B3, 0x4E59, 0x89B4, 0x4FFA, 0x89B5, 0x5378, + 0x89B6, 0x6069, 0x89B7, 0x6E29, 0x89B8, 0x7A4F, 0x89B9, 0x97F3, 0x89BA, 0x4E0B, 0x89BB, 0x5316, 0x89BC, 0x4EEE, 0x89BD, 0x4F55, + 0x89BE, 0x4F3D, 0x89BF, 0x4FA1, 0x89C0, 0x4F73, 0x89C1, 0x52A0, 0x89C2, 0x53EF, 0x89C3, 0x5609, 0x89C4, 0x590F, 0x89C5, 0x5AC1, + 0x89C6, 0x5BB6, 0x89C7, 0x5BE1, 0x89C8, 0x79D1, 0x89C9, 0x6687, 0x89CA, 0x679C, 0x89CB, 0x67B6, 0x89CC, 0x6B4C, 0x89CD, 0x6CB3, + 0x89CE, 0x706B, 0x89CF, 0x73C2, 0x89D0, 0x798D, 0x89D1, 0x79BE, 0x89D2, 0x7A3C, 0x89D3, 0x7B87, 0x89D4, 0x82B1, 0x89D5, 0x82DB, + 0x89D6, 0x8304, 0x89D7, 0x8377, 0x89D8, 0x83EF, 0x89D9, 0x83D3, 0x89DA, 0x8766, 0x89DB, 0x8AB2, 0x89DC, 0x5629, 0x89DD, 0x8CA8, + 0x89DE, 0x8FE6, 0x89DF, 0x904E, 0x89E0, 0x971E, 0x89E1, 0x868A, 0x89E2, 0x4FC4, 0x89E3, 0x5CE8, 0x89E4, 0x6211, 0x89E5, 0x7259, + 0x89E6, 0x753B, 0x89E7, 0x81E5, 0x89E8, 0x82BD, 0x89E9, 0x86FE, 0x89EA, 0x8CC0, 0x89EB, 0x96C5, 0x89EC, 0x9913, 0x89ED, 0x99D5, + 0x89EE, 0x4ECB, 0x89EF, 0x4F1A, 0x89F0, 0x89E3, 0x89F1, 0x56DE, 0x89F2, 0x584A, 0x89F3, 0x58CA, 0x89F4, 0x5EFB, 0x89F5, 0x5FEB, + 0x89F6, 0x602A, 0x89F7, 0x6094, 0x89F8, 0x6062, 0x89F9, 0x61D0, 0x89FA, 0x6212, 0x89FB, 0x62D0, 0x89FC, 0x6539, 0x8A40, 0x9B41, + 0x8A41, 0x6666, 0x8A42, 0x68B0, 0x8A43, 0x6D77, 0x8A44, 0x7070, 0x8A45, 0x754C, 0x8A46, 0x7686, 0x8A47, 0x7D75, 0x8A48, 0x82A5, + 0x8A49, 0x87F9, 0x8A4A, 0x958B, 0x8A4B, 0x968E, 0x8A4C, 0x8C9D, 0x8A4D, 0x51F1, 0x8A4E, 0x52BE, 0x8A4F, 0x5916, 0x8A50, 0x54B3, + 0x8A51, 0x5BB3, 0x8A52, 0x5D16, 0x8A53, 0x6168, 0x8A54, 0x6982, 0x8A55, 0x6DAF, 0x8A56, 0x788D, 0x8A57, 0x84CB, 0x8A58, 0x8857, + 0x8A59, 0x8A72, 0x8A5A, 0x93A7, 0x8A5B, 0x9AB8, 0x8A5C, 0x6D6C, 0x8A5D, 0x99A8, 0x8A5E, 0x86D9, 0x8A5F, 0x57A3, 0x8A60, 0x67FF, + 0x8A61, 0x86CE, 0x8A62, 0x920E, 0x8A63, 0x5283, 0x8A64, 0x5687, 0x8A65, 0x5404, 0x8A66, 0x5ED3, 0x8A67, 0x62E1, 0x8A68, 0x64B9, + 0x8A69, 0x683C, 0x8A6A, 0x6838, 0x8A6B, 0x6BBB, 0x8A6C, 0x7372, 0x8A6D, 0x78BA, 0x8A6E, 0x7A6B, 0x8A6F, 0x899A, 0x8A70, 0x89D2, + 0x8A71, 0x8D6B, 0x8A72, 0x8F03, 0x8A73, 0x90ED, 0x8A74, 0x95A3, 0x8A75, 0x9694, 0x8A76, 0x9769, 0x8A77, 0x5B66, 0x8A78, 0x5CB3, + 0x8A79, 0x697D, 0x8A7A, 0x984D, 0x8A7B, 0x984E, 0x8A7C, 0x639B, 0x8A7D, 0x7B20, 0x8A7E, 0x6A2B, 0x8A80, 0x6A7F, 0x8A81, 0x68B6, + 0x8A82, 0x9C0D, 0x8A83, 0x6F5F, 0x8A84, 0x5272, 0x8A85, 0x559D, 0x8A86, 0x6070, 0x8A87, 0x62EC, 0x8A88, 0x6D3B, 0x8A89, 0x6E07, + 0x8A8A, 0x6ED1, 0x8A8B, 0x845B, 0x8A8C, 0x8910, 0x8A8D, 0x8F44, 0x8A8E, 0x4E14, 0x8A8F, 0x9C39, 0x8A90, 0x53F6, 0x8A91, 0x691B, + 0x8A92, 0x6A3A, 0x8A93, 0x9784, 0x8A94, 0x682A, 0x8A95, 0x515C, 0x8A96, 0x7AC3, 0x8A97, 0x84B2, 0x8A98, 0x91DC, 0x8A99, 0x938C, + 0x8A9A, 0x565B, 0x8A9B, 0x9D28, 0x8A9C, 0x6822, 0x8A9D, 0x8305, 0x8A9E, 0x8431, 0x8A9F, 0x7CA5, 0x8AA0, 0x5208, 0x8AA1, 0x82C5, + 0x8AA2, 0x74E6, 0x8AA3, 0x4E7E, 0x8AA4, 0x4F83, 0x8AA5, 0x51A0, 0x8AA6, 0x5BD2, 0x8AA7, 0x520A, 0x8AA8, 0x52D8, 0x8AA9, 0x52E7, + 0x8AAA, 0x5DFB, 0x8AAB, 0x559A, 0x8AAC, 0x582A, 0x8AAD, 0x59E6, 0x8AAE, 0x5B8C, 0x8AAF, 0x5B98, 0x8AB0, 0x5BDB, 0x8AB1, 0x5E72, + 0x8AB2, 0x5E79, 0x8AB3, 0x60A3, 0x8AB4, 0x611F, 0x8AB5, 0x6163, 0x8AB6, 0x61BE, 0x8AB7, 0x63DB, 0x8AB8, 0x6562, 0x8AB9, 0x67D1, + 0x8ABA, 0x6853, 0x8ABB, 0x68FA, 0x8ABC, 0x6B3E, 0x8ABD, 0x6B53, 0x8ABE, 0x6C57, 0x8ABF, 0x6F22, 0x8AC0, 0x6F97, 0x8AC1, 0x6F45, + 0x8AC2, 0x74B0, 0x8AC3, 0x7518, 0x8AC4, 0x76E3, 0x8AC5, 0x770B, 0x8AC6, 0x7AFF, 0x8AC7, 0x7BA1, 0x8AC8, 0x7C21, 0x8AC9, 0x7DE9, + 0x8ACA, 0x7F36, 0x8ACB, 0x7FF0, 0x8ACC, 0x809D, 0x8ACD, 0x8266, 0x8ACE, 0x839E, 0x8ACF, 0x89B3, 0x8AD0, 0x8ACC, 0x8AD1, 0x8CAB, + 0x8AD2, 0x9084, 0x8AD3, 0x9451, 0x8AD4, 0x9593, 0x8AD5, 0x9591, 0x8AD6, 0x95A2, 0x8AD7, 0x9665, 0x8AD8, 0x97D3, 0x8AD9, 0x9928, + 0x8ADA, 0x8218, 0x8ADB, 0x4E38, 0x8ADC, 0x542B, 0x8ADD, 0x5CB8, 0x8ADE, 0x5DCC, 0x8ADF, 0x73A9, 0x8AE0, 0x764C, 0x8AE1, 0x773C, + 0x8AE2, 0x5CA9, 0x8AE3, 0x7FEB, 0x8AE4, 0x8D0B, 0x8AE5, 0x96C1, 0x8AE6, 0x9811, 0x8AE7, 0x9854, 0x8AE8, 0x9858, 0x8AE9, 0x4F01, + 0x8AEA, 0x4F0E, 0x8AEB, 0x5371, 0x8AEC, 0x559C, 0x8AED, 0x5668, 0x8AEE, 0x57FA, 0x8AEF, 0x5947, 0x8AF0, 0x5B09, 0x8AF1, 0x5BC4, + 0x8AF2, 0x5C90, 0x8AF3, 0x5E0C, 0x8AF4, 0x5E7E, 0x8AF5, 0x5FCC, 0x8AF6, 0x63EE, 0x8AF7, 0x673A, 0x8AF8, 0x65D7, 0x8AF9, 0x65E2, + 0x8AFA, 0x671F, 0x8AFB, 0x68CB, 0x8AFC, 0x68C4, 0x8B40, 0x6A5F, 0x8B41, 0x5E30, 0x8B42, 0x6BC5, 0x8B43, 0x6C17, 0x8B44, 0x6C7D, + 0x8B45, 0x757F, 0x8B46, 0x7948, 0x8B47, 0x5B63, 0x8B48, 0x7A00, 0x8B49, 0x7D00, 0x8B4A, 0x5FBD, 0x8B4B, 0x898F, 0x8B4C, 0x8A18, + 0x8B4D, 0x8CB4, 0x8B4E, 0x8D77, 0x8B4F, 0x8ECC, 0x8B50, 0x8F1D, 0x8B51, 0x98E2, 0x8B52, 0x9A0E, 0x8B53, 0x9B3C, 0x8B54, 0x4E80, + 0x8B55, 0x507D, 0x8B56, 0x5100, 0x8B57, 0x5993, 0x8B58, 0x5B9C, 0x8B59, 0x622F, 0x8B5A, 0x6280, 0x8B5B, 0x64EC, 0x8B5C, 0x6B3A, + 0x8B5D, 0x72A0, 0x8B5E, 0x7591, 0x8B5F, 0x7947, 0x8B60, 0x7FA9, 0x8B61, 0x87FB, 0x8B62, 0x8ABC, 0x8B63, 0x8B70, 0x8B64, 0x63AC, + 0x8B65, 0x83CA, 0x8B66, 0x97A0, 0x8B67, 0x5409, 0x8B68, 0x5403, 0x8B69, 0x55AB, 0x8B6A, 0x6854, 0x8B6B, 0x6A58, 0x8B6C, 0x8A70, + 0x8B6D, 0x7827, 0x8B6E, 0x6775, 0x8B6F, 0x9ECD, 0x8B70, 0x5374, 0x8B71, 0x5BA2, 0x8B72, 0x811A, 0x8B73, 0x8650, 0x8B74, 0x9006, + 0x8B75, 0x4E18, 0x8B76, 0x4E45, 0x8B77, 0x4EC7, 0x8B78, 0x4F11, 0x8B79, 0x53CA, 0x8B7A, 0x5438, 0x8B7B, 0x5BAE, 0x8B7C, 0x5F13, + 0x8B7D, 0x6025, 0x8B7E, 0x6551, 0x8B80, 0x673D, 0x8B81, 0x6C42, 0x8B82, 0x6C72, 0x8B83, 0x6CE3, 0x8B84, 0x7078, 0x8B85, 0x7403, + 0x8B86, 0x7A76, 0x8B87, 0x7AAE, 0x8B88, 0x7B08, 0x8B89, 0x7D1A, 0x8B8A, 0x7CFE, 0x8B8B, 0x7D66, 0x8B8C, 0x65E7, 0x8B8D, 0x725B, + 0x8B8E, 0x53BB, 0x8B8F, 0x5C45, 0x8B90, 0x5DE8, 0x8B91, 0x62D2, 0x8B92, 0x62E0, 0x8B93, 0x6319, 0x8B94, 0x6E20, 0x8B95, 0x865A, + 0x8B96, 0x8A31, 0x8B97, 0x8DDD, 0x8B98, 0x92F8, 0x8B99, 0x6F01, 0x8B9A, 0x79A6, 0x8B9B, 0x9B5A, 0x8B9C, 0x4EA8, 0x8B9D, 0x4EAB, + 0x8B9E, 0x4EAC, 0x8B9F, 0x4F9B, 0x8BA0, 0x4FA0, 0x8BA1, 0x50D1, 0x8BA2, 0x5147, 0x8BA3, 0x7AF6, 0x8BA4, 0x5171, 0x8BA5, 0x51F6, + 0x8BA6, 0x5354, 0x8BA7, 0x5321, 0x8BA8, 0x537F, 0x8BA9, 0x53EB, 0x8BAA, 0x55AC, 0x8BAB, 0x5883, 0x8BAC, 0x5CE1, 0x8BAD, 0x5F37, + 0x8BAE, 0x5F4A, 0x8BAF, 0x602F, 0x8BB0, 0x6050, 0x8BB1, 0x606D, 0x8BB2, 0x631F, 0x8BB3, 0x6559, 0x8BB4, 0x6A4B, 0x8BB5, 0x6CC1, + 0x8BB6, 0x72C2, 0x8BB7, 0x72ED, 0x8BB8, 0x77EF, 0x8BB9, 0x80F8, 0x8BBA, 0x8105, 0x8BBB, 0x8208, 0x8BBC, 0x854E, 0x8BBD, 0x90F7, + 0x8BBE, 0x93E1, 0x8BBF, 0x97FF, 0x8BC0, 0x9957, 0x8BC1, 0x9A5A, 0x8BC2, 0x4EF0, 0x8BC3, 0x51DD, 0x8BC4, 0x5C2D, 0x8BC5, 0x6681, + 0x8BC6, 0x696D, 0x8BC7, 0x5C40, 0x8BC8, 0x66F2, 0x8BC9, 0x6975, 0x8BCA, 0x7389, 0x8BCB, 0x6850, 0x8BCC, 0x7C81, 0x8BCD, 0x50C5, + 0x8BCE, 0x52E4, 0x8BCF, 0x5747, 0x8BD0, 0x5DFE, 0x8BD1, 0x9326, 0x8BD2, 0x65A4, 0x8BD3, 0x6B23, 0x8BD4, 0x6B3D, 0x8BD5, 0x7434, + 0x8BD6, 0x7981, 0x8BD7, 0x79BD, 0x8BD8, 0x7B4B, 0x8BD9, 0x7DCA, 0x8BDA, 0x82B9, 0x8BDB, 0x83CC, 0x8BDC, 0x887F, 0x8BDD, 0x895F, + 0x8BDE, 0x8B39, 0x8BDF, 0x8FD1, 0x8BE0, 0x91D1, 0x8BE1, 0x541F, 0x8BE2, 0x9280, 0x8BE3, 0x4E5D, 0x8BE4, 0x5036, 0x8BE5, 0x53E5, + 0x8BE6, 0x533A, 0x8BE7, 0x72D7, 0x8BE8, 0x7396, 0x8BE9, 0x77E9, 0x8BEA, 0x82E6, 0x8BEB, 0x8EAF, 0x8BEC, 0x99C6, 0x8BED, 0x99C8, + 0x8BEE, 0x99D2, 0x8BEF, 0x5177, 0x8BF0, 0x611A, 0x8BF1, 0x865E, 0x8BF2, 0x55B0, 0x8BF3, 0x7A7A, 0x8BF4, 0x5076, 0x8BF5, 0x5BD3, + 0x8BF6, 0x9047, 0x8BF7, 0x9685, 0x8BF8, 0x4E32, 0x8BF9, 0x6ADB, 0x8BFA, 0x91E7, 0x8BFB, 0x5C51, 0x8BFC, 0x5C48, 0x8C40, 0x6398, + 0x8C41, 0x7A9F, 0x8C42, 0x6C93, 0x8C43, 0x9774, 0x8C44, 0x8F61, 0x8C45, 0x7AAA, 0x8C46, 0x718A, 0x8C47, 0x9688, 0x8C48, 0x7C82, + 0x8C49, 0x6817, 0x8C4A, 0x7E70, 0x8C4B, 0x6851, 0x8C4C, 0x936C, 0x8C4D, 0x52F2, 0x8C4E, 0x541B, 0x8C4F, 0x85AB, 0x8C50, 0x8A13, + 0x8C51, 0x7FA4, 0x8C52, 0x8ECD, 0x8C53, 0x90E1, 0x8C54, 0x5366, 0x8C55, 0x8888, 0x8C56, 0x7941, 0x8C57, 0x4FC2, 0x8C58, 0x50BE, + 0x8C59, 0x5211, 0x8C5A, 0x5144, 0x8C5B, 0x5553, 0x8C5C, 0x572D, 0x8C5D, 0x73EA, 0x8C5E, 0x578B, 0x8C5F, 0x5951, 0x8C60, 0x5F62, + 0x8C61, 0x5F84, 0x8C62, 0x6075, 0x8C63, 0x6176, 0x8C64, 0x6167, 0x8C65, 0x61A9, 0x8C66, 0x63B2, 0x8C67, 0x643A, 0x8C68, 0x656C, + 0x8C69, 0x666F, 0x8C6A, 0x6842, 0x8C6B, 0x6E13, 0x8C6C, 0x7566, 0x8C6D, 0x7A3D, 0x8C6E, 0x7CFB, 0x8C6F, 0x7D4C, 0x8C70, 0x7D99, + 0x8C71, 0x7E4B, 0x8C72, 0x7F6B, 0x8C73, 0x830E, 0x8C74, 0x834A, 0x8C75, 0x86CD, 0x8C76, 0x8A08, 0x8C77, 0x8A63, 0x8C78, 0x8B66, + 0x8C79, 0x8EFD, 0x8C7A, 0x981A, 0x8C7B, 0x9D8F, 0x8C7C, 0x82B8, 0x8C7D, 0x8FCE, 0x8C7E, 0x9BE8, 0x8C80, 0x5287, 0x8C81, 0x621F, + 0x8C82, 0x6483, 0x8C83, 0x6FC0, 0x8C84, 0x9699, 0x8C85, 0x6841, 0x8C86, 0x5091, 0x8C87, 0x6B20, 0x8C88, 0x6C7A, 0x8C89, 0x6F54, + 0x8C8A, 0x7A74, 0x8C8B, 0x7D50, 0x8C8C, 0x8840, 0x8C8D, 0x8A23, 0x8C8E, 0x6708, 0x8C8F, 0x4EF6, 0x8C90, 0x5039, 0x8C91, 0x5026, + 0x8C92, 0x5065, 0x8C93, 0x517C, 0x8C94, 0x5238, 0x8C95, 0x5263, 0x8C96, 0x55A7, 0x8C97, 0x570F, 0x8C98, 0x5805, 0x8C99, 0x5ACC, + 0x8C9A, 0x5EFA, 0x8C9B, 0x61B2, 0x8C9C, 0x61F8, 0x8C9D, 0x62F3, 0x8C9E, 0x6372, 0x8C9F, 0x691C, 0x8CA0, 0x6A29, 0x8CA1, 0x727D, + 0x8CA2, 0x72AC, 0x8CA3, 0x732E, 0x8CA4, 0x7814, 0x8CA5, 0x786F, 0x8CA6, 0x7D79, 0x8CA7, 0x770C, 0x8CA8, 0x80A9, 0x8CA9, 0x898B, + 0x8CAA, 0x8B19, 0x8CAB, 0x8CE2, 0x8CAC, 0x8ED2, 0x8CAD, 0x9063, 0x8CAE, 0x9375, 0x8CAF, 0x967A, 0x8CB0, 0x9855, 0x8CB1, 0x9A13, + 0x8CB2, 0x9E78, 0x8CB3, 0x5143, 0x8CB4, 0x539F, 0x8CB5, 0x53B3, 0x8CB6, 0x5E7B, 0x8CB7, 0x5F26, 0x8CB8, 0x6E1B, 0x8CB9, 0x6E90, + 0x8CBA, 0x7384, 0x8CBB, 0x73FE, 0x8CBC, 0x7D43, 0x8CBD, 0x8237, 0x8CBE, 0x8A00, 0x8CBF, 0x8AFA, 0x8CC0, 0x9650, 0x8CC1, 0x4E4E, + 0x8CC2, 0x500B, 0x8CC3, 0x53E4, 0x8CC4, 0x547C, 0x8CC5, 0x56FA, 0x8CC6, 0x59D1, 0x8CC7, 0x5B64, 0x8CC8, 0x5DF1, 0x8CC9, 0x5EAB, + 0x8CCA, 0x5F27, 0x8CCB, 0x6238, 0x8CCC, 0x6545, 0x8CCD, 0x67AF, 0x8CCE, 0x6E56, 0x8CCF, 0x72D0, 0x8CD0, 0x7CCA, 0x8CD1, 0x88B4, + 0x8CD2, 0x80A1, 0x8CD3, 0x80E1, 0x8CD4, 0x83F0, 0x8CD5, 0x864E, 0x8CD6, 0x8A87, 0x8CD7, 0x8DE8, 0x8CD8, 0x9237, 0x8CD9, 0x96C7, + 0x8CDA, 0x9867, 0x8CDB, 0x9F13, 0x8CDC, 0x4E94, 0x8CDD, 0x4E92, 0x8CDE, 0x4F0D, 0x8CDF, 0x5348, 0x8CE0, 0x5449, 0x8CE1, 0x543E, + 0x8CE2, 0x5A2F, 0x8CE3, 0x5F8C, 0x8CE4, 0x5FA1, 0x8CE5, 0x609F, 0x8CE6, 0x68A7, 0x8CE7, 0x6A8E, 0x8CE8, 0x745A, 0x8CE9, 0x7881, + 0x8CEA, 0x8A9E, 0x8CEB, 0x8AA4, 0x8CEC, 0x8B77, 0x8CED, 0x9190, 0x8CEE, 0x4E5E, 0x8CEF, 0x9BC9, 0x8CF0, 0x4EA4, 0x8CF1, 0x4F7C, + 0x8CF2, 0x4FAF, 0x8CF3, 0x5019, 0x8CF4, 0x5016, 0x8CF5, 0x5149, 0x8CF6, 0x516C, 0x8CF7, 0x529F, 0x8CF8, 0x52B9, 0x8CF9, 0x52FE, + 0x8CFA, 0x539A, 0x8CFB, 0x53E3, 0x8CFC, 0x5411, 0x8D40, 0x540E, 0x8D41, 0x5589, 0x8D42, 0x5751, 0x8D43, 0x57A2, 0x8D44, 0x597D, + 0x8D45, 0x5B54, 0x8D46, 0x5B5D, 0x8D47, 0x5B8F, 0x8D48, 0x5DE5, 0x8D49, 0x5DE7, 0x8D4A, 0x5DF7, 0x8D4B, 0x5E78, 0x8D4C, 0x5E83, + 0x8D4D, 0x5E9A, 0x8D4E, 0x5EB7, 0x8D4F, 0x5F18, 0x8D50, 0x6052, 0x8D51, 0x614C, 0x8D52, 0x6297, 0x8D53, 0x62D8, 0x8D54, 0x63A7, + 0x8D55, 0x653B, 0x8D56, 0x6602, 0x8D57, 0x6643, 0x8D58, 0x66F4, 0x8D59, 0x676D, 0x8D5A, 0x6821, 0x8D5B, 0x6897, 0x8D5C, 0x69CB, + 0x8D5D, 0x6C5F, 0x8D5E, 0x6D2A, 0x8D5F, 0x6D69, 0x8D60, 0x6E2F, 0x8D61, 0x6E9D, 0x8D62, 0x7532, 0x8D63, 0x7687, 0x8D64, 0x786C, + 0x8D65, 0x7A3F, 0x8D66, 0x7CE0, 0x8D67, 0x7D05, 0x8D68, 0x7D18, 0x8D69, 0x7D5E, 0x8D6A, 0x7DB1, 0x8D6B, 0x8015, 0x8D6C, 0x8003, + 0x8D6D, 0x80AF, 0x8D6E, 0x80B1, 0x8D6F, 0x8154, 0x8D70, 0x818F, 0x8D71, 0x822A, 0x8D72, 0x8352, 0x8D73, 0x884C, 0x8D74, 0x8861, + 0x8D75, 0x8B1B, 0x8D76, 0x8CA2, 0x8D77, 0x8CFC, 0x8D78, 0x90CA, 0x8D79, 0x9175, 0x8D7A, 0x9271, 0x8D7B, 0x783F, 0x8D7C, 0x92FC, + 0x8D7D, 0x95A4, 0x8D7E, 0x964D, 0x8D80, 0x9805, 0x8D81, 0x9999, 0x8D82, 0x9AD8, 0x8D83, 0x9D3B, 0x8D84, 0x525B, 0x8D85, 0x52AB, + 0x8D86, 0x53F7, 0x8D87, 0x5408, 0x8D88, 0x58D5, 0x8D89, 0x62F7, 0x8D8A, 0x6FE0, 0x8D8B, 0x8C6A, 0x8D8C, 0x8F5F, 0x8D8D, 0x9EB9, + 0x8D8E, 0x514B, 0x8D8F, 0x523B, 0x8D90, 0x544A, 0x8D91, 0x56FD, 0x8D92, 0x7A40, 0x8D93, 0x9177, 0x8D94, 0x9D60, 0x8D95, 0x9ED2, + 0x8D96, 0x7344, 0x8D97, 0x6F09, 0x8D98, 0x8170, 0x8D99, 0x7511, 0x8D9A, 0x5FFD, 0x8D9B, 0x60DA, 0x8D9C, 0x9AA8, 0x8D9D, 0x72DB, + 0x8D9E, 0x8FBC, 0x8D9F, 0x6B64, 0x8DA0, 0x9803, 0x8DA1, 0x4ECA, 0x8DA2, 0x56F0, 0x8DA3, 0x5764, 0x8DA4, 0x58BE, 0x8DA5, 0x5A5A, + 0x8DA6, 0x6068, 0x8DA7, 0x61C7, 0x8DA8, 0x660F, 0x8DA9, 0x6606, 0x8DAA, 0x6839, 0x8DAB, 0x68B1, 0x8DAC, 0x6DF7, 0x8DAD, 0x75D5, + 0x8DAE, 0x7D3A, 0x8DAF, 0x826E, 0x8DB0, 0x9B42, 0x8DB1, 0x4E9B, 0x8DB2, 0x4F50, 0x8DB3, 0x53C9, 0x8DB4, 0x5506, 0x8DB5, 0x5D6F, + 0x8DB6, 0x5DE6, 0x8DB7, 0x5DEE, 0x8DB8, 0x67FB, 0x8DB9, 0x6C99, 0x8DBA, 0x7473, 0x8DBB, 0x7802, 0x8DBC, 0x8A50, 0x8DBD, 0x9396, + 0x8DBE, 0x88DF, 0x8DBF, 0x5750, 0x8DC0, 0x5EA7, 0x8DC1, 0x632B, 0x8DC2, 0x50B5, 0x8DC3, 0x50AC, 0x8DC4, 0x518D, 0x8DC5, 0x6700, + 0x8DC6, 0x54C9, 0x8DC7, 0x585E, 0x8DC8, 0x59BB, 0x8DC9, 0x5BB0, 0x8DCA, 0x5F69, 0x8DCB, 0x624D, 0x8DCC, 0x63A1, 0x8DCD, 0x683D, + 0x8DCE, 0x6B73, 0x8DCF, 0x6E08, 0x8DD0, 0x707D, 0x8DD1, 0x91C7, 0x8DD2, 0x7280, 0x8DD3, 0x7815, 0x8DD4, 0x7826, 0x8DD5, 0x796D, + 0x8DD6, 0x658E, 0x8DD7, 0x7D30, 0x8DD8, 0x83DC, 0x8DD9, 0x88C1, 0x8DDA, 0x8F09, 0x8DDB, 0x969B, 0x8DDC, 0x5264, 0x8DDD, 0x5728, + 0x8DDE, 0x6750, 0x8DDF, 0x7F6A, 0x8DE0, 0x8CA1, 0x8DE1, 0x51B4, 0x8DE2, 0x5742, 0x8DE3, 0x962A, 0x8DE4, 0x583A, 0x8DE5, 0x698A, + 0x8DE6, 0x80B4, 0x8DE7, 0x54B2, 0x8DE8, 0x5D0E, 0x8DE9, 0x57FC, 0x8DEA, 0x7895, 0x8DEB, 0x9DFA, 0x8DEC, 0x4F5C, 0x8DED, 0x524A, + 0x8DEE, 0x548B, 0x8DEF, 0x643E, 0x8DF0, 0x6628, 0x8DF1, 0x6714, 0x8DF2, 0x67F5, 0x8DF3, 0x7A84, 0x8DF4, 0x7B56, 0x8DF5, 0x7D22, + 0x8DF6, 0x932F, 0x8DF7, 0x685C, 0x8DF8, 0x9BAD, 0x8DF9, 0x7B39, 0x8DFA, 0x5319, 0x8DFB, 0x518A, 0x8DFC, 0x5237, 0x8E40, 0x5BDF, + 0x8E41, 0x62F6, 0x8E42, 0x64AE, 0x8E43, 0x64E6, 0x8E44, 0x672D, 0x8E45, 0x6BBA, 0x8E46, 0x85A9, 0x8E47, 0x96D1, 0x8E48, 0x7690, + 0x8E49, 0x9BD6, 0x8E4A, 0x634C, 0x8E4B, 0x9306, 0x8E4C, 0x9BAB, 0x8E4D, 0x76BF, 0x8E4E, 0x6652, 0x8E4F, 0x4E09, 0x8E50, 0x5098, + 0x8E51, 0x53C2, 0x8E52, 0x5C71, 0x8E53, 0x60E8, 0x8E54, 0x6492, 0x8E55, 0x6563, 0x8E56, 0x685F, 0x8E57, 0x71E6, 0x8E58, 0x73CA, + 0x8E59, 0x7523, 0x8E5A, 0x7B97, 0x8E5B, 0x7E82, 0x8E5C, 0x8695, 0x8E5D, 0x8B83, 0x8E5E, 0x8CDB, 0x8E5F, 0x9178, 0x8E60, 0x9910, + 0x8E61, 0x65AC, 0x8E62, 0x66AB, 0x8E63, 0x6B8B, 0x8E64, 0x4ED5, 0x8E65, 0x4ED4, 0x8E66, 0x4F3A, 0x8E67, 0x4F7F, 0x8E68, 0x523A, + 0x8E69, 0x53F8, 0x8E6A, 0x53F2, 0x8E6B, 0x55E3, 0x8E6C, 0x56DB, 0x8E6D, 0x58EB, 0x8E6E, 0x59CB, 0x8E6F, 0x59C9, 0x8E70, 0x59FF, + 0x8E71, 0x5B50, 0x8E72, 0x5C4D, 0x8E73, 0x5E02, 0x8E74, 0x5E2B, 0x8E75, 0x5FD7, 0x8E76, 0x601D, 0x8E77, 0x6307, 0x8E78, 0x652F, + 0x8E79, 0x5B5C, 0x8E7A, 0x65AF, 0x8E7B, 0x65BD, 0x8E7C, 0x65E8, 0x8E7D, 0x679D, 0x8E7E, 0x6B62, 0x8E80, 0x6B7B, 0x8E81, 0x6C0F, + 0x8E82, 0x7345, 0x8E83, 0x7949, 0x8E84, 0x79C1, 0x8E85, 0x7CF8, 0x8E86, 0x7D19, 0x8E87, 0x7D2B, 0x8E88, 0x80A2, 0x8E89, 0x8102, + 0x8E8A, 0x81F3, 0x8E8B, 0x8996, 0x8E8C, 0x8A5E, 0x8E8D, 0x8A69, 0x8E8E, 0x8A66, 0x8E8F, 0x8A8C, 0x8E90, 0x8AEE, 0x8E91, 0x8CC7, + 0x8E92, 0x8CDC, 0x8E93, 0x96CC, 0x8E94, 0x98FC, 0x8E95, 0x6B6F, 0x8E96, 0x4E8B, 0x8E97, 0x4F3C, 0x8E98, 0x4F8D, 0x8E99, 0x5150, + 0x8E9A, 0x5B57, 0x8E9B, 0x5BFA, 0x8E9C, 0x6148, 0x8E9D, 0x6301, 0x8E9E, 0x6642, 0x8E9F, 0x6B21, 0x8EA0, 0x6ECB, 0x8EA1, 0x6CBB, + 0x8EA2, 0x723E, 0x8EA3, 0x74BD, 0x8EA4, 0x75D4, 0x8EA5, 0x78C1, 0x8EA6, 0x793A, 0x8EA7, 0x800C, 0x8EA8, 0x8033, 0x8EA9, 0x81EA, + 0x8EAA, 0x8494, 0x8EAB, 0x8F9E, 0x8EAC, 0x6C50, 0x8EAD, 0x9E7F, 0x8EAE, 0x5F0F, 0x8EAF, 0x8B58, 0x8EB0, 0x9D2B, 0x8EB1, 0x7AFA, + 0x8EB2, 0x8EF8, 0x8EB3, 0x5B8D, 0x8EB4, 0x96EB, 0x8EB5, 0x4E03, 0x8EB6, 0x53F1, 0x8EB7, 0x57F7, 0x8EB8, 0x5931, 0x8EB9, 0x5AC9, + 0x8EBA, 0x5BA4, 0x8EBB, 0x6089, 0x8EBC, 0x6E7F, 0x8EBD, 0x6F06, 0x8EBE, 0x75BE, 0x8EBF, 0x8CEA, 0x8EC0, 0x5B9F, 0x8EC1, 0x8500, + 0x8EC2, 0x7BE0, 0x8EC3, 0x5072, 0x8EC4, 0x67F4, 0x8EC5, 0x829D, 0x8EC6, 0x5C61, 0x8EC7, 0x854A, 0x8EC8, 0x7E1E, 0x8EC9, 0x820E, + 0x8ECA, 0x5199, 0x8ECB, 0x5C04, 0x8ECC, 0x6368, 0x8ECD, 0x8D66, 0x8ECE, 0x659C, 0x8ECF, 0x716E, 0x8ED0, 0x793E, 0x8ED1, 0x7D17, + 0x8ED2, 0x8005, 0x8ED3, 0x8B1D, 0x8ED4, 0x8ECA, 0x8ED5, 0x906E, 0x8ED6, 0x86C7, 0x8ED7, 0x90AA, 0x8ED8, 0x501F, 0x8ED9, 0x52FA, + 0x8EDA, 0x5C3A, 0x8EDB, 0x6753, 0x8EDC, 0x707C, 0x8EDD, 0x7235, 0x8EDE, 0x914C, 0x8EDF, 0x91C8, 0x8EE0, 0x932B, 0x8EE1, 0x82E5, + 0x8EE2, 0x5BC2, 0x8EE3, 0x5F31, 0x8EE4, 0x60F9, 0x8EE5, 0x4E3B, 0x8EE6, 0x53D6, 0x8EE7, 0x5B88, 0x8EE8, 0x624B, 0x8EE9, 0x6731, + 0x8EEA, 0x6B8A, 0x8EEB, 0x72E9, 0x8EEC, 0x73E0, 0x8EED, 0x7A2E, 0x8EEE, 0x816B, 0x8EEF, 0x8DA3, 0x8EF0, 0x9152, 0x8EF1, 0x9996, + 0x8EF2, 0x5112, 0x8EF3, 0x53D7, 0x8EF4, 0x546A, 0x8EF5, 0x5BFF, 0x8EF6, 0x6388, 0x8EF7, 0x6A39, 0x8EF8, 0x7DAC, 0x8EF9, 0x9700, + 0x8EFA, 0x56DA, 0x8EFB, 0x53CE, 0x8EFC, 0x5468, 0x8F40, 0x5B97, 0x8F41, 0x5C31, 0x8F42, 0x5DDE, 0x8F43, 0x4FEE, 0x8F44, 0x6101, + 0x8F45, 0x62FE, 0x8F46, 0x6D32, 0x8F47, 0x79C0, 0x8F48, 0x79CB, 0x8F49, 0x7D42, 0x8F4A, 0x7E4D, 0x8F4B, 0x7FD2, 0x8F4C, 0x81ED, + 0x8F4D, 0x821F, 0x8F4E, 0x8490, 0x8F4F, 0x8846, 0x8F50, 0x8972, 0x8F51, 0x8B90, 0x8F52, 0x8E74, 0x8F53, 0x8F2F, 0x8F54, 0x9031, + 0x8F55, 0x914B, 0x8F56, 0x916C, 0x8F57, 0x96C6, 0x8F58, 0x919C, 0x8F59, 0x4EC0, 0x8F5A, 0x4F4F, 0x8F5B, 0x5145, 0x8F5C, 0x5341, + 0x8F5D, 0x5F93, 0x8F5E, 0x620E, 0x8F5F, 0x67D4, 0x8F60, 0x6C41, 0x8F61, 0x6E0B, 0x8F62, 0x7363, 0x8F63, 0x7E26, 0x8F64, 0x91CD, + 0x8F65, 0x9283, 0x8F66, 0x53D4, 0x8F67, 0x5919, 0x8F68, 0x5BBF, 0x8F69, 0x6DD1, 0x8F6A, 0x795D, 0x8F6B, 0x7E2E, 0x8F6C, 0x7C9B, + 0x8F6D, 0x587E, 0x8F6E, 0x719F, 0x8F6F, 0x51FA, 0x8F70, 0x8853, 0x8F71, 0x8FF0, 0x8F72, 0x4FCA, 0x8F73, 0x5CFB, 0x8F74, 0x6625, + 0x8F75, 0x77AC, 0x8F76, 0x7AE3, 0x8F77, 0x821C, 0x8F78, 0x99FF, 0x8F79, 0x51C6, 0x8F7A, 0x5FAA, 0x8F7B, 0x65EC, 0x8F7C, 0x696F, + 0x8F7D, 0x6B89, 0x8F7E, 0x6DF3, 0x8F80, 0x6E96, 0x8F81, 0x6F64, 0x8F82, 0x76FE, 0x8F83, 0x7D14, 0x8F84, 0x5DE1, 0x8F85, 0x9075, + 0x8F86, 0x9187, 0x8F87, 0x9806, 0x8F88, 0x51E6, 0x8F89, 0x521D, 0x8F8A, 0x6240, 0x8F8B, 0x6691, 0x8F8C, 0x66D9, 0x8F8D, 0x6E1A, + 0x8F8E, 0x5EB6, 0x8F8F, 0x7DD2, 0x8F90, 0x7F72, 0x8F91, 0x66F8, 0x8F92, 0x85AF, 0x8F93, 0x85F7, 0x8F94, 0x8AF8, 0x8F95, 0x52A9, + 0x8F96, 0x53D9, 0x8F97, 0x5973, 0x8F98, 0x5E8F, 0x8F99, 0x5F90, 0x8F9A, 0x6055, 0x8F9B, 0x92E4, 0x8F9C, 0x9664, 0x8F9D, 0x50B7, + 0x8F9E, 0x511F, 0x8F9F, 0x52DD, 0x8FA0, 0x5320, 0x8FA1, 0x5347, 0x8FA2, 0x53EC, 0x8FA3, 0x54E8, 0x8FA4, 0x5546, 0x8FA5, 0x5531, + 0x8FA6, 0x5617, 0x8FA7, 0x5968, 0x8FA8, 0x59BE, 0x8FA9, 0x5A3C, 0x8FAA, 0x5BB5, 0x8FAB, 0x5C06, 0x8FAC, 0x5C0F, 0x8FAD, 0x5C11, + 0x8FAE, 0x5C1A, 0x8FAF, 0x5E84, 0x8FB0, 0x5E8A, 0x8FB1, 0x5EE0, 0x8FB2, 0x5F70, 0x8FB3, 0x627F, 0x8FB4, 0x6284, 0x8FB5, 0x62DB, + 0x8FB6, 0x638C, 0x8FB7, 0x6377, 0x8FB8, 0x6607, 0x8FB9, 0x660C, 0x8FBA, 0x662D, 0x8FBB, 0x6676, 0x8FBC, 0x677E, 0x8FBD, 0x68A2, + 0x8FBE, 0x6A1F, 0x8FBF, 0x6A35, 0x8FC0, 0x6CBC, 0x8FC1, 0x6D88, 0x8FC2, 0x6E09, 0x8FC3, 0x6E58, 0x8FC4, 0x713C, 0x8FC5, 0x7126, + 0x8FC6, 0x7167, 0x8FC7, 0x75C7, 0x8FC8, 0x7701, 0x8FC9, 0x785D, 0x8FCA, 0x7901, 0x8FCB, 0x7965, 0x8FCC, 0x79F0, 0x8FCD, 0x7AE0, + 0x8FCE, 0x7B11, 0x8FCF, 0x7CA7, 0x8FD0, 0x7D39, 0x8FD1, 0x8096, 0x8FD2, 0x83D6, 0x8FD3, 0x848B, 0x8FD4, 0x8549, 0x8FD5, 0x885D, + 0x8FD6, 0x88F3, 0x8FD7, 0x8A1F, 0x8FD8, 0x8A3C, 0x8FD9, 0x8A54, 0x8FDA, 0x8A73, 0x8FDB, 0x8C61, 0x8FDC, 0x8CDE, 0x8FDD, 0x91A4, + 0x8FDE, 0x9266, 0x8FDF, 0x937E, 0x8FE0, 0x9418, 0x8FE1, 0x969C, 0x8FE2, 0x9798, 0x8FE3, 0x4E0A, 0x8FE4, 0x4E08, 0x8FE5, 0x4E1E, + 0x8FE6, 0x4E57, 0x8FE7, 0x5197, 0x8FE8, 0x5270, 0x8FE9, 0x57CE, 0x8FEA, 0x5834, 0x8FEB, 0x58CC, 0x8FEC, 0x5B22, 0x8FED, 0x5E38, + 0x8FEE, 0x60C5, 0x8FEF, 0x64FE, 0x8FF0, 0x6761, 0x8FF1, 0x6756, 0x8FF2, 0x6D44, 0x8FF3, 0x72B6, 0x8FF4, 0x7573, 0x8FF5, 0x7A63, + 0x8FF6, 0x84B8, 0x8FF7, 0x8B72, 0x8FF8, 0x91B8, 0x8FF9, 0x9320, 0x8FFA, 0x5631, 0x8FFB, 0x57F4, 0x8FFC, 0x98FE, 0x9040, 0x62ED, + 0x9041, 0x690D, 0x9042, 0x6B96, 0x9043, 0x71ED, 0x9044, 0x7E54, 0x9045, 0x8077, 0x9046, 0x8272, 0x9047, 0x89E6, 0x9048, 0x98DF, + 0x9049, 0x8755, 0x904A, 0x8FB1, 0x904B, 0x5C3B, 0x904C, 0x4F38, 0x904D, 0x4FE1, 0x904E, 0x4FB5, 0x904F, 0x5507, 0x9050, 0x5A20, + 0x9051, 0x5BDD, 0x9052, 0x5BE9, 0x9053, 0x5FC3, 0x9054, 0x614E, 0x9055, 0x632F, 0x9056, 0x65B0, 0x9057, 0x664B, 0x9058, 0x68EE, + 0x9059, 0x699B, 0x905A, 0x6D78, 0x905B, 0x6DF1, 0x905C, 0x7533, 0x905D, 0x75B9, 0x905E, 0x771F, 0x905F, 0x795E, 0x9060, 0x79E6, + 0x9061, 0x7D33, 0x9062, 0x81E3, 0x9063, 0x82AF, 0x9064, 0x85AA, 0x9065, 0x89AA, 0x9066, 0x8A3A, 0x9067, 0x8EAB, 0x9068, 0x8F9B, + 0x9069, 0x9032, 0x906A, 0x91DD, 0x906B, 0x9707, 0x906C, 0x4EBA, 0x906D, 0x4EC1, 0x906E, 0x5203, 0x906F, 0x5875, 0x9070, 0x58EC, + 0x9071, 0x5C0B, 0x9072, 0x751A, 0x9073, 0x5C3D, 0x9074, 0x814E, 0x9075, 0x8A0A, 0x9076, 0x8FC5, 0x9077, 0x9663, 0x9078, 0x976D, + 0x9079, 0x7B25, 0x907A, 0x8ACF, 0x907B, 0x9808, 0x907C, 0x9162, 0x907D, 0x56F3, 0x907E, 0x53A8, 0x9080, 0x9017, 0x9081, 0x5439, + 0x9082, 0x5782, 0x9083, 0x5E25, 0x9084, 0x63A8, 0x9085, 0x6C34, 0x9086, 0x708A, 0x9087, 0x7761, 0x9088, 0x7C8B, 0x9089, 0x7FE0, + 0x908A, 0x8870, 0x908B, 0x9042, 0x908C, 0x9154, 0x908D, 0x9310, 0x908E, 0x9318, 0x908F, 0x968F, 0x9090, 0x745E, 0x9091, 0x9AC4, + 0x9092, 0x5D07, 0x9093, 0x5D69, 0x9094, 0x6570, 0x9095, 0x67A2, 0x9096, 0x8DA8, 0x9097, 0x96DB, 0x9098, 0x636E, 0x9099, 0x6749, + 0x909A, 0x6919, 0x909B, 0x83C5, 0x909C, 0x9817, 0x909D, 0x96C0, 0x909E, 0x88FE, 0x909F, 0x6F84, 0x90A0, 0x647A, 0x90A1, 0x5BF8, + 0x90A2, 0x4E16, 0x90A3, 0x702C, 0x90A4, 0x755D, 0x90A5, 0x662F, 0x90A6, 0x51C4, 0x90A7, 0x5236, 0x90A8, 0x52E2, 0x90A9, 0x59D3, + 0x90AA, 0x5F81, 0x90AB, 0x6027, 0x90AC, 0x6210, 0x90AD, 0x653F, 0x90AE, 0x6574, 0x90AF, 0x661F, 0x90B0, 0x6674, 0x90B1, 0x68F2, + 0x90B2, 0x6816, 0x90B3, 0x6B63, 0x90B4, 0x6E05, 0x90B5, 0x7272, 0x90B6, 0x751F, 0x90B7, 0x76DB, 0x90B8, 0x7CBE, 0x90B9, 0x8056, + 0x90BA, 0x58F0, 0x90BB, 0x88FD, 0x90BC, 0x897F, 0x90BD, 0x8AA0, 0x90BE, 0x8A93, 0x90BF, 0x8ACB, 0x90C0, 0x901D, 0x90C1, 0x9192, + 0x90C2, 0x9752, 0x90C3, 0x9759, 0x90C4, 0x6589, 0x90C5, 0x7A0E, 0x90C6, 0x8106, 0x90C7, 0x96BB, 0x90C8, 0x5E2D, 0x90C9, 0x60DC, + 0x90CA, 0x621A, 0x90CB, 0x65A5, 0x90CC, 0x6614, 0x90CD, 0x6790, 0x90CE, 0x77F3, 0x90CF, 0x7A4D, 0x90D0, 0x7C4D, 0x90D1, 0x7E3E, + 0x90D2, 0x810A, 0x90D3, 0x8CAC, 0x90D4, 0x8D64, 0x90D5, 0x8DE1, 0x90D6, 0x8E5F, 0x90D7, 0x78A9, 0x90D8, 0x5207, 0x90D9, 0x62D9, + 0x90DA, 0x63A5, 0x90DB, 0x6442, 0x90DC, 0x6298, 0x90DD, 0x8A2D, 0x90DE, 0x7A83, 0x90DF, 0x7BC0, 0x90E0, 0x8AAC, 0x90E1, 0x96EA, + 0x90E2, 0x7D76, 0x90E3, 0x820C, 0x90E4, 0x8749, 0x90E5, 0x4ED9, 0x90E6, 0x5148, 0x90E7, 0x5343, 0x90E8, 0x5360, 0x90E9, 0x5BA3, + 0x90EA, 0x5C02, 0x90EB, 0x5C16, 0x90EC, 0x5DDD, 0x90ED, 0x6226, 0x90EE, 0x6247, 0x90EF, 0x64B0, 0x90F0, 0x6813, 0x90F1, 0x6834, + 0x90F2, 0x6CC9, 0x90F3, 0x6D45, 0x90F4, 0x6D17, 0x90F5, 0x67D3, 0x90F6, 0x6F5C, 0x90F7, 0x714E, 0x90F8, 0x717D, 0x90F9, 0x65CB, + 0x90FA, 0x7A7F, 0x90FB, 0x7BAD, 0x90FC, 0x7DDA, 0x9140, 0x7E4A, 0x9141, 0x7FA8, 0x9142, 0x817A, 0x9143, 0x821B, 0x9144, 0x8239, + 0x9145, 0x85A6, 0x9146, 0x8A6E, 0x9147, 0x8CCE, 0x9148, 0x8DF5, 0x9149, 0x9078, 0x914A, 0x9077, 0x914B, 0x92AD, 0x914C, 0x9291, + 0x914D, 0x9583, 0x914E, 0x9BAE, 0x914F, 0x524D, 0x9150, 0x5584, 0x9151, 0x6F38, 0x9152, 0x7136, 0x9153, 0x5168, 0x9154, 0x7985, + 0x9155, 0x7E55, 0x9156, 0x81B3, 0x9157, 0x7CCE, 0x9158, 0x564C, 0x9159, 0x5851, 0x915A, 0x5CA8, 0x915B, 0x63AA, 0x915C, 0x66FE, + 0x915D, 0x66FD, 0x915E, 0x695A, 0x915F, 0x72D9, 0x9160, 0x758F, 0x9161, 0x758E, 0x9162, 0x790E, 0x9163, 0x7956, 0x9164, 0x79DF, + 0x9165, 0x7C97, 0x9166, 0x7D20, 0x9167, 0x7D44, 0x9168, 0x8607, 0x9169, 0x8A34, 0x916A, 0x963B, 0x916B, 0x9061, 0x916C, 0x9F20, + 0x916D, 0x50E7, 0x916E, 0x5275, 0x916F, 0x53CC, 0x9170, 0x53E2, 0x9171, 0x5009, 0x9172, 0x55AA, 0x9173, 0x58EE, 0x9174, 0x594F, + 0x9175, 0x723D, 0x9176, 0x5B8B, 0x9177, 0x5C64, 0x9178, 0x531D, 0x9179, 0x60E3, 0x917A, 0x60F3, 0x917B, 0x635C, 0x917C, 0x6383, + 0x917D, 0x633F, 0x917E, 0x63BB, 0x9180, 0x64CD, 0x9181, 0x65E9, 0x9182, 0x66F9, 0x9183, 0x5DE3, 0x9184, 0x69CD, 0x9185, 0x69FD, + 0x9186, 0x6F15, 0x9187, 0x71E5, 0x9188, 0x4E89, 0x9189, 0x75E9, 0x918A, 0x76F8, 0x918B, 0x7A93, 0x918C, 0x7CDF, 0x918D, 0x7DCF, + 0x918E, 0x7D9C, 0x918F, 0x8061, 0x9190, 0x8349, 0x9191, 0x8358, 0x9192, 0x846C, 0x9193, 0x84BC, 0x9194, 0x85FB, 0x9195, 0x88C5, + 0x9196, 0x8D70, 0x9197, 0x9001, 0x9198, 0x906D, 0x9199, 0x9397, 0x919A, 0x971C, 0x919B, 0x9A12, 0x919C, 0x50CF, 0x919D, 0x5897, + 0x919E, 0x618E, 0x919F, 0x81D3, 0x91A0, 0x8535, 0x91A1, 0x8D08, 0x91A2, 0x9020, 0x91A3, 0x4FC3, 0x91A4, 0x5074, 0x91A5, 0x5247, + 0x91A6, 0x5373, 0x91A7, 0x606F, 0x91A8, 0x6349, 0x91A9, 0x675F, 0x91AA, 0x6E2C, 0x91AB, 0x8DB3, 0x91AC, 0x901F, 0x91AD, 0x4FD7, + 0x91AE, 0x5C5E, 0x91AF, 0x8CCA, 0x91B0, 0x65CF, 0x91B1, 0x7D9A, 0x91B2, 0x5352, 0x91B3, 0x8896, 0x91B4, 0x5176, 0x91B5, 0x63C3, + 0x91B6, 0x5B58, 0x91B7, 0x5B6B, 0x91B8, 0x5C0A, 0x91B9, 0x640D, 0x91BA, 0x6751, 0x91BB, 0x905C, 0x91BC, 0x4ED6, 0x91BD, 0x591A, + 0x91BE, 0x592A, 0x91BF, 0x6C70, 0x91C0, 0x8A51, 0x91C1, 0x553E, 0x91C2, 0x5815, 0x91C3, 0x59A5, 0x91C4, 0x60F0, 0x91C5, 0x6253, + 0x91C6, 0x67C1, 0x91C7, 0x8235, 0x91C8, 0x6955, 0x91C9, 0x9640, 0x91CA, 0x99C4, 0x91CB, 0x9A28, 0x91CC, 0x4F53, 0x91CD, 0x5806, + 0x91CE, 0x5BFE, 0x91CF, 0x8010, 0x91D0, 0x5CB1, 0x91D1, 0x5E2F, 0x91D2, 0x5F85, 0x91D3, 0x6020, 0x91D4, 0x614B, 0x91D5, 0x6234, + 0x91D6, 0x66FF, 0x91D7, 0x6CF0, 0x91D8, 0x6EDE, 0x91D9, 0x80CE, 0x91DA, 0x817F, 0x91DB, 0x82D4, 0x91DC, 0x888B, 0x91DD, 0x8CB8, + 0x91DE, 0x9000, 0x91DF, 0x902E, 0x91E0, 0x968A, 0x91E1, 0x9EDB, 0x91E2, 0x9BDB, 0x91E3, 0x4EE3, 0x91E4, 0x53F0, 0x91E5, 0x5927, + 0x91E6, 0x7B2C, 0x91E7, 0x918D, 0x91E8, 0x984C, 0x91E9, 0x9DF9, 0x91EA, 0x6EDD, 0x91EB, 0x7027, 0x91EC, 0x5353, 0x91ED, 0x5544, + 0x91EE, 0x5B85, 0x91EF, 0x6258, 0x91F0, 0x629E, 0x91F1, 0x62D3, 0x91F2, 0x6CA2, 0x91F3, 0x6FEF, 0x91F4, 0x7422, 0x91F5, 0x8A17, + 0x91F6, 0x9438, 0x91F7, 0x6FC1, 0x91F8, 0x8AFE, 0x91F9, 0x8338, 0x91FA, 0x51E7, 0x91FB, 0x86F8, 0x91FC, 0x53EA, 0x9240, 0x53E9, + 0x9241, 0x4F46, 0x9242, 0x9054, 0x9243, 0x8FB0, 0x9244, 0x596A, 0x9245, 0x8131, 0x9246, 0x5DFD, 0x9247, 0x7AEA, 0x9248, 0x8FBF, + 0x9249, 0x68DA, 0x924A, 0x8C37, 0x924B, 0x72F8, 0x924C, 0x9C48, 0x924D, 0x6A3D, 0x924E, 0x8AB0, 0x924F, 0x4E39, 0x9250, 0x5358, + 0x9251, 0x5606, 0x9252, 0x5766, 0x9253, 0x62C5, 0x9254, 0x63A2, 0x9255, 0x65E6, 0x9256, 0x6B4E, 0x9257, 0x6DE1, 0x9258, 0x6E5B, + 0x9259, 0x70AD, 0x925A, 0x77ED, 0x925B, 0x7AEF, 0x925C, 0x7BAA, 0x925D, 0x7DBB, 0x925E, 0x803D, 0x925F, 0x80C6, 0x9260, 0x86CB, + 0x9261, 0x8A95, 0x9262, 0x935B, 0x9263, 0x56E3, 0x9264, 0x58C7, 0x9265, 0x5F3E, 0x9266, 0x65AD, 0x9267, 0x6696, 0x9268, 0x6A80, + 0x9269, 0x6BB5, 0x926A, 0x7537, 0x926B, 0x8AC7, 0x926C, 0x5024, 0x926D, 0x77E5, 0x926E, 0x5730, 0x926F, 0x5F1B, 0x9270, 0x6065, + 0x9271, 0x667A, 0x9272, 0x6C60, 0x9273, 0x75F4, 0x9274, 0x7A1A, 0x9275, 0x7F6E, 0x9276, 0x81F4, 0x9277, 0x8718, 0x9278, 0x9045, + 0x9279, 0x99B3, 0x927A, 0x7BC9, 0x927B, 0x755C, 0x927C, 0x7AF9, 0x927D, 0x7B51, 0x927E, 0x84C4, 0x9280, 0x9010, 0x9281, 0x79E9, + 0x9282, 0x7A92, 0x9283, 0x8336, 0x9284, 0x5AE1, 0x9285, 0x7740, 0x9286, 0x4E2D, 0x9287, 0x4EF2, 0x9288, 0x5B99, 0x9289, 0x5FE0, + 0x928A, 0x62BD, 0x928B, 0x663C, 0x928C, 0x67F1, 0x928D, 0x6CE8, 0x928E, 0x866B, 0x928F, 0x8877, 0x9290, 0x8A3B, 0x9291, 0x914E, + 0x9292, 0x92F3, 0x9293, 0x99D0, 0x9294, 0x6A17, 0x9295, 0x7026, 0x9296, 0x732A, 0x9297, 0x82E7, 0x9298, 0x8457, 0x9299, 0x8CAF, + 0x929A, 0x4E01, 0x929B, 0x5146, 0x929C, 0x51CB, 0x929D, 0x558B, 0x929E, 0x5BF5, 0x929F, 0x5E16, 0x92A0, 0x5E33, 0x92A1, 0x5E81, + 0x92A2, 0x5F14, 0x92A3, 0x5F35, 0x92A4, 0x5F6B, 0x92A5, 0x5FB4, 0x92A6, 0x61F2, 0x92A7, 0x6311, 0x92A8, 0x66A2, 0x92A9, 0x671D, + 0x92AA, 0x6F6E, 0x92AB, 0x7252, 0x92AC, 0x753A, 0x92AD, 0x773A, 0x92AE, 0x8074, 0x92AF, 0x8139, 0x92B0, 0x8178, 0x92B1, 0x8776, + 0x92B2, 0x8ABF, 0x92B3, 0x8ADC, 0x92B4, 0x8D85, 0x92B5, 0x8DF3, 0x92B6, 0x929A, 0x92B7, 0x9577, 0x92B8, 0x9802, 0x92B9, 0x9CE5, + 0x92BA, 0x52C5, 0x92BB, 0x6357, 0x92BC, 0x76F4, 0x92BD, 0x6715, 0x92BE, 0x6C88, 0x92BF, 0x73CD, 0x92C0, 0x8CC3, 0x92C1, 0x93AE, + 0x92C2, 0x9673, 0x92C3, 0x6D25, 0x92C4, 0x589C, 0x92C5, 0x690E, 0x92C6, 0x69CC, 0x92C7, 0x8FFD, 0x92C8, 0x939A, 0x92C9, 0x75DB, + 0x92CA, 0x901A, 0x92CB, 0x585A, 0x92CC, 0x6802, 0x92CD, 0x63B4, 0x92CE, 0x69FB, 0x92CF, 0x4F43, 0x92D0, 0x6F2C, 0x92D1, 0x67D8, + 0x92D2, 0x8FBB, 0x92D3, 0x8526, 0x92D4, 0x7DB4, 0x92D5, 0x9354, 0x92D6, 0x693F, 0x92D7, 0x6F70, 0x92D8, 0x576A, 0x92D9, 0x58F7, + 0x92DA, 0x5B2C, 0x92DB, 0x7D2C, 0x92DC, 0x722A, 0x92DD, 0x540A, 0x92DE, 0x91E3, 0x92DF, 0x9DB4, 0x92E0, 0x4EAD, 0x92E1, 0x4F4E, + 0x92E2, 0x505C, 0x92E3, 0x5075, 0x92E4, 0x5243, 0x92E5, 0x8C9E, 0x92E6, 0x5448, 0x92E7, 0x5824, 0x92E8, 0x5B9A, 0x92E9, 0x5E1D, + 0x92EA, 0x5E95, 0x92EB, 0x5EAD, 0x92EC, 0x5EF7, 0x92ED, 0x5F1F, 0x92EE, 0x608C, 0x92EF, 0x62B5, 0x92F0, 0x633A, 0x92F1, 0x63D0, + 0x92F2, 0x68AF, 0x92F3, 0x6C40, 0x92F4, 0x7887, 0x92F5, 0x798E, 0x92F6, 0x7A0B, 0x92F7, 0x7DE0, 0x92F8, 0x8247, 0x92F9, 0x8A02, + 0x92FA, 0x8AE6, 0x92FB, 0x8E44, 0x92FC, 0x9013, 0x9340, 0x90B8, 0x9341, 0x912D, 0x9342, 0x91D8, 0x9343, 0x9F0E, 0x9344, 0x6CE5, + 0x9345, 0x6458, 0x9346, 0x64E2, 0x9347, 0x6575, 0x9348, 0x6EF4, 0x9349, 0x7684, 0x934A, 0x7B1B, 0x934B, 0x9069, 0x934C, 0x93D1, + 0x934D, 0x6EBA, 0x934E, 0x54F2, 0x934F, 0x5FB9, 0x9350, 0x64A4, 0x9351, 0x8F4D, 0x9352, 0x8FED, 0x9353, 0x9244, 0x9354, 0x5178, + 0x9355, 0x586B, 0x9356, 0x5929, 0x9357, 0x5C55, 0x9358, 0x5E97, 0x9359, 0x6DFB, 0x935A, 0x7E8F, 0x935B, 0x751C, 0x935C, 0x8CBC, + 0x935D, 0x8EE2, 0x935E, 0x985B, 0x935F, 0x70B9, 0x9360, 0x4F1D, 0x9361, 0x6BBF, 0x9362, 0x6FB1, 0x9363, 0x7530, 0x9364, 0x96FB, + 0x9365, 0x514E, 0x9366, 0x5410, 0x9367, 0x5835, 0x9368, 0x5857, 0x9369, 0x59AC, 0x936A, 0x5C60, 0x936B, 0x5F92, 0x936C, 0x6597, + 0x936D, 0x675C, 0x936E, 0x6E21, 0x936F, 0x767B, 0x9370, 0x83DF, 0x9371, 0x8CED, 0x9372, 0x9014, 0x9373, 0x90FD, 0x9374, 0x934D, + 0x9375, 0x7825, 0x9376, 0x783A, 0x9377, 0x52AA, 0x9378, 0x5EA6, 0x9379, 0x571F, 0x937A, 0x5974, 0x937B, 0x6012, 0x937C, 0x5012, + 0x937D, 0x515A, 0x937E, 0x51AC, 0x9380, 0x51CD, 0x9381, 0x5200, 0x9382, 0x5510, 0x9383, 0x5854, 0x9384, 0x5858, 0x9385, 0x5957, + 0x9386, 0x5B95, 0x9387, 0x5CF6, 0x9388, 0x5D8B, 0x9389, 0x60BC, 0x938A, 0x6295, 0x938B, 0x642D, 0x938C, 0x6771, 0x938D, 0x6843, + 0x938E, 0x68BC, 0x938F, 0x68DF, 0x9390, 0x76D7, 0x9391, 0x6DD8, 0x9392, 0x6E6F, 0x9393, 0x6D9B, 0x9394, 0x706F, 0x9395, 0x71C8, + 0x9396, 0x5F53, 0x9397, 0x75D8, 0x9398, 0x7977, 0x9399, 0x7B49, 0x939A, 0x7B54, 0x939B, 0x7B52, 0x939C, 0x7CD6, 0x939D, 0x7D71, + 0x939E, 0x5230, 0x939F, 0x8463, 0x93A0, 0x8569, 0x93A1, 0x85E4, 0x93A2, 0x8A0E, 0x93A3, 0x8B04, 0x93A4, 0x8C46, 0x93A5, 0x8E0F, + 0x93A6, 0x9003, 0x93A7, 0x900F, 0x93A8, 0x9419, 0x93A9, 0x9676, 0x93AA, 0x982D, 0x93AB, 0x9A30, 0x93AC, 0x95D8, 0x93AD, 0x50CD, + 0x93AE, 0x52D5, 0x93AF, 0x540C, 0x93B0, 0x5802, 0x93B1, 0x5C0E, 0x93B2, 0x61A7, 0x93B3, 0x649E, 0x93B4, 0x6D1E, 0x93B5, 0x77B3, + 0x93B6, 0x7AE5, 0x93B7, 0x80F4, 0x93B8, 0x8404, 0x93B9, 0x9053, 0x93BA, 0x9285, 0x93BB, 0x5CE0, 0x93BC, 0x9D07, 0x93BD, 0x533F, + 0x93BE, 0x5F97, 0x93BF, 0x5FB3, 0x93C0, 0x6D9C, 0x93C1, 0x7279, 0x93C2, 0x7763, 0x93C3, 0x79BF, 0x93C4, 0x7BE4, 0x93C5, 0x6BD2, + 0x93C6, 0x72EC, 0x93C7, 0x8AAD, 0x93C8, 0x6803, 0x93C9, 0x6A61, 0x93CA, 0x51F8, 0x93CB, 0x7A81, 0x93CC, 0x6934, 0x93CD, 0x5C4A, + 0x93CE, 0x9CF6, 0x93CF, 0x82EB, 0x93D0, 0x5BC5, 0x93D1, 0x9149, 0x93D2, 0x701E, 0x93D3, 0x5678, 0x93D4, 0x5C6F, 0x93D5, 0x60C7, + 0x93D6, 0x6566, 0x93D7, 0x6C8C, 0x93D8, 0x8C5A, 0x93D9, 0x9041, 0x93DA, 0x9813, 0x93DB, 0x5451, 0x93DC, 0x66C7, 0x93DD, 0x920D, + 0x93DE, 0x5948, 0x93DF, 0x90A3, 0x93E0, 0x5185, 0x93E1, 0x4E4D, 0x93E2, 0x51EA, 0x93E3, 0x8599, 0x93E4, 0x8B0E, 0x93E5, 0x7058, + 0x93E6, 0x637A, 0x93E7, 0x934B, 0x93E8, 0x6962, 0x93E9, 0x99B4, 0x93EA, 0x7E04, 0x93EB, 0x7577, 0x93EC, 0x5357, 0x93ED, 0x6960, + 0x93EE, 0x8EDF, 0x93EF, 0x96E3, 0x93F0, 0x6C5D, 0x93F1, 0x4E8C, 0x93F2, 0x5C3C, 0x93F3, 0x5F10, 0x93F4, 0x8FE9, 0x93F5, 0x5302, + 0x93F6, 0x8CD1, 0x93F7, 0x8089, 0x93F8, 0x8679, 0x93F9, 0x5EFF, 0x93FA, 0x65E5, 0x93FB, 0x4E73, 0x93FC, 0x5165, 0x9440, 0x5982, + 0x9441, 0x5C3F, 0x9442, 0x97EE, 0x9443, 0x4EFB, 0x9444, 0x598A, 0x9445, 0x5FCD, 0x9446, 0x8A8D, 0x9447, 0x6FE1, 0x9448, 0x79B0, + 0x9449, 0x7962, 0x944A, 0x5BE7, 0x944B, 0x8471, 0x944C, 0x732B, 0x944D, 0x71B1, 0x944E, 0x5E74, 0x944F, 0x5FF5, 0x9450, 0x637B, + 0x9451, 0x649A, 0x9452, 0x71C3, 0x9453, 0x7C98, 0x9454, 0x4E43, 0x9455, 0x5EFC, 0x9456, 0x4E4B, 0x9457, 0x57DC, 0x9458, 0x56A2, + 0x9459, 0x60A9, 0x945A, 0x6FC3, 0x945B, 0x7D0D, 0x945C, 0x80FD, 0x945D, 0x8133, 0x945E, 0x81BF, 0x945F, 0x8FB2, 0x9460, 0x8997, + 0x9461, 0x86A4, 0x9462, 0x5DF4, 0x9463, 0x628A, 0x9464, 0x64AD, 0x9465, 0x8987, 0x9466, 0x6777, 0x9467, 0x6CE2, 0x9468, 0x6D3E, + 0x9469, 0x7436, 0x946A, 0x7834, 0x946B, 0x5A46, 0x946C, 0x7F75, 0x946D, 0x82AD, 0x946E, 0x99AC, 0x946F, 0x4FF3, 0x9470, 0x5EC3, + 0x9471, 0x62DD, 0x9472, 0x6392, 0x9473, 0x6557, 0x9474, 0x676F, 0x9475, 0x76C3, 0x9476, 0x724C, 0x9477, 0x80CC, 0x9478, 0x80BA, + 0x9479, 0x8F29, 0x947A, 0x914D, 0x947B, 0x500D, 0x947C, 0x57F9, 0x947D, 0x5A92, 0x947E, 0x6885, 0x9480, 0x6973, 0x9481, 0x7164, + 0x9482, 0x72FD, 0x9483, 0x8CB7, 0x9484, 0x58F2, 0x9485, 0x8CE0, 0x9486, 0x966A, 0x9487, 0x9019, 0x9488, 0x877F, 0x9489, 0x79E4, + 0x948A, 0x77E7, 0x948B, 0x8429, 0x948C, 0x4F2F, 0x948D, 0x5265, 0x948E, 0x535A, 0x948F, 0x62CD, 0x9490, 0x67CF, 0x9491, 0x6CCA, + 0x9492, 0x767D, 0x9493, 0x7B94, 0x9494, 0x7C95, 0x9495, 0x8236, 0x9496, 0x8584, 0x9497, 0x8FEB, 0x9498, 0x66DD, 0x9499, 0x6F20, + 0x949A, 0x7206, 0x949B, 0x7E1B, 0x949C, 0x83AB, 0x949D, 0x99C1, 0x949E, 0x9EA6, 0x949F, 0x51FD, 0x94A0, 0x7BB1, 0x94A1, 0x7872, + 0x94A2, 0x7BB8, 0x94A3, 0x8087, 0x94A4, 0x7B48, 0x94A5, 0x6AE8, 0x94A6, 0x5E61, 0x94A7, 0x808C, 0x94A8, 0x7551, 0x94A9, 0x7560, + 0x94AA, 0x516B, 0x94AB, 0x9262, 0x94AC, 0x6E8C, 0x94AD, 0x767A, 0x94AE, 0x9197, 0x94AF, 0x9AEA, 0x94B0, 0x4F10, 0x94B1, 0x7F70, + 0x94B2, 0x629C, 0x94B3, 0x7B4F, 0x94B4, 0x95A5, 0x94B5, 0x9CE9, 0x94B6, 0x567A, 0x94B7, 0x5859, 0x94B8, 0x86E4, 0x94B9, 0x96BC, + 0x94BA, 0x4F34, 0x94BB, 0x5224, 0x94BC, 0x534A, 0x94BD, 0x53CD, 0x94BE, 0x53DB, 0x94BF, 0x5E06, 0x94C0, 0x642C, 0x94C1, 0x6591, + 0x94C2, 0x677F, 0x94C3, 0x6C3E, 0x94C4, 0x6C4E, 0x94C5, 0x7248, 0x94C6, 0x72AF, 0x94C7, 0x73ED, 0x94C8, 0x7554, 0x94C9, 0x7E41, + 0x94CA, 0x822C, 0x94CB, 0x85E9, 0x94CC, 0x8CA9, 0x94CD, 0x7BC4, 0x94CE, 0x91C6, 0x94CF, 0x7169, 0x94D0, 0x9812, 0x94D1, 0x98EF, + 0x94D2, 0x633D, 0x94D3, 0x6669, 0x94D4, 0x756A, 0x94D5, 0x76E4, 0x94D6, 0x78D0, 0x94D7, 0x8543, 0x94D8, 0x86EE, 0x94D9, 0x532A, + 0x94DA, 0x5351, 0x94DB, 0x5426, 0x94DC, 0x5983, 0x94DD, 0x5E87, 0x94DE, 0x5F7C, 0x94DF, 0x60B2, 0x94E0, 0x6249, 0x94E1, 0x6279, + 0x94E2, 0x62AB, 0x94E3, 0x6590, 0x94E4, 0x6BD4, 0x94E5, 0x6CCC, 0x94E6, 0x75B2, 0x94E7, 0x76AE, 0x94E8, 0x7891, 0x94E9, 0x79D8, + 0x94EA, 0x7DCB, 0x94EB, 0x7F77, 0x94EC, 0x80A5, 0x94ED, 0x88AB, 0x94EE, 0x8AB9, 0x94EF, 0x8CBB, 0x94F0, 0x907F, 0x94F1, 0x975E, + 0x94F2, 0x98DB, 0x94F3, 0x6A0B, 0x94F4, 0x7C38, 0x94F5, 0x5099, 0x94F6, 0x5C3E, 0x94F7, 0x5FAE, 0x94F8, 0x6787, 0x94F9, 0x6BD8, + 0x94FA, 0x7435, 0x94FB, 0x7709, 0x94FC, 0x7F8E, 0x9540, 0x9F3B, 0x9541, 0x67CA, 0x9542, 0x7A17, 0x9543, 0x5339, 0x9544, 0x758B, + 0x9545, 0x9AED, 0x9546, 0x5F66, 0x9547, 0x819D, 0x9548, 0x83F1, 0x9549, 0x8098, 0x954A, 0x5F3C, 0x954B, 0x5FC5, 0x954C, 0x7562, + 0x954D, 0x7B46, 0x954E, 0x903C, 0x954F, 0x6867, 0x9550, 0x59EB, 0x9551, 0x5A9B, 0x9552, 0x7D10, 0x9553, 0x767E, 0x9554, 0x8B2C, + 0x9555, 0x4FF5, 0x9556, 0x5F6A, 0x9557, 0x6A19, 0x9558, 0x6C37, 0x9559, 0x6F02, 0x955A, 0x74E2, 0x955B, 0x7968, 0x955C, 0x8868, + 0x955D, 0x8A55, 0x955E, 0x8C79, 0x955F, 0x5EDF, 0x9560, 0x63CF, 0x9561, 0x75C5, 0x9562, 0x79D2, 0x9563, 0x82D7, 0x9564, 0x9328, + 0x9565, 0x92F2, 0x9566, 0x849C, 0x9567, 0x86ED, 0x9568, 0x9C2D, 0x9569, 0x54C1, 0x956A, 0x5F6C, 0x956B, 0x658C, 0x956C, 0x6D5C, + 0x956D, 0x7015, 0x956E, 0x8CA7, 0x956F, 0x8CD3, 0x9570, 0x983B, 0x9571, 0x654F, 0x9572, 0x74F6, 0x9573, 0x4E0D, 0x9574, 0x4ED8, + 0x9575, 0x57E0, 0x9576, 0x592B, 0x9577, 0x5A66, 0x9578, 0x5BCC, 0x9579, 0x51A8, 0x957A, 0x5E03, 0x957B, 0x5E9C, 0x957C, 0x6016, + 0x957D, 0x6276, 0x957E, 0x6577, 0x9580, 0x65A7, 0x9581, 0x666E, 0x9582, 0x6D6E, 0x9583, 0x7236, 0x9584, 0x7B26, 0x9585, 0x8150, + 0x9586, 0x819A, 0x9587, 0x8299, 0x9588, 0x8B5C, 0x9589, 0x8CA0, 0x958A, 0x8CE6, 0x958B, 0x8D74, 0x958C, 0x961C, 0x958D, 0x9644, + 0x958E, 0x4FAE, 0x958F, 0x64AB, 0x9590, 0x6B66, 0x9591, 0x821E, 0x9592, 0x8461, 0x9593, 0x856A, 0x9594, 0x90E8, 0x9595, 0x5C01, + 0x9596, 0x6953, 0x9597, 0x98A8, 0x9598, 0x847A, 0x9599, 0x8557, 0x959A, 0x4F0F, 0x959B, 0x526F, 0x959C, 0x5FA9, 0x959D, 0x5E45, + 0x959E, 0x670D, 0x959F, 0x798F, 0x95A0, 0x8179, 0x95A1, 0x8907, 0x95A2, 0x8986, 0x95A3, 0x6DF5, 0x95A4, 0x5F17, 0x95A5, 0x6255, + 0x95A6, 0x6CB8, 0x95A7, 0x4ECF, 0x95A8, 0x7269, 0x95A9, 0x9B92, 0x95AA, 0x5206, 0x95AB, 0x543B, 0x95AC, 0x5674, 0x95AD, 0x58B3, + 0x95AE, 0x61A4, 0x95AF, 0x626E, 0x95B0, 0x711A, 0x95B1, 0x596E, 0x95B2, 0x7C89, 0x95B3, 0x7CDE, 0x95B4, 0x7D1B, 0x95B5, 0x96F0, + 0x95B6, 0x6587, 0x95B7, 0x805E, 0x95B8, 0x4E19, 0x95B9, 0x4F75, 0x95BA, 0x5175, 0x95BB, 0x5840, 0x95BC, 0x5E63, 0x95BD, 0x5E73, + 0x95BE, 0x5F0A, 0x95BF, 0x67C4, 0x95C0, 0x4E26, 0x95C1, 0x853D, 0x95C2, 0x9589, 0x95C3, 0x965B, 0x95C4, 0x7C73, 0x95C5, 0x9801, + 0x95C6, 0x50FB, 0x95C7, 0x58C1, 0x95C8, 0x7656, 0x95C9, 0x78A7, 0x95CA, 0x5225, 0x95CB, 0x77A5, 0x95CC, 0x8511, 0x95CD, 0x7B86, + 0x95CE, 0x504F, 0x95CF, 0x5909, 0x95D0, 0x7247, 0x95D1, 0x7BC7, 0x95D2, 0x7DE8, 0x95D3, 0x8FBA, 0x95D4, 0x8FD4, 0x95D5, 0x904D, + 0x95D6, 0x4FBF, 0x95D7, 0x52C9, 0x95D8, 0x5A29, 0x95D9, 0x5F01, 0x95DA, 0x97AD, 0x95DB, 0x4FDD, 0x95DC, 0x8217, 0x95DD, 0x92EA, + 0x95DE, 0x5703, 0x95DF, 0x6355, 0x95E0, 0x6B69, 0x95E1, 0x752B, 0x95E2, 0x88DC, 0x95E3, 0x8F14, 0x95E4, 0x7A42, 0x95E5, 0x52DF, + 0x95E6, 0x5893, 0x95E7, 0x6155, 0x95E8, 0x620A, 0x95E9, 0x66AE, 0x95EA, 0x6BCD, 0x95EB, 0x7C3F, 0x95EC, 0x83E9, 0x95ED, 0x5023, + 0x95EE, 0x4FF8, 0x95EF, 0x5305, 0x95F0, 0x5446, 0x95F1, 0x5831, 0x95F2, 0x5949, 0x95F3, 0x5B9D, 0x95F4, 0x5CF0, 0x95F5, 0x5CEF, + 0x95F6, 0x5D29, 0x95F7, 0x5E96, 0x95F8, 0x62B1, 0x95F9, 0x6367, 0x95FA, 0x653E, 0x95FB, 0x65B9, 0x95FC, 0x670B, 0x9640, 0x6CD5, + 0x9641, 0x6CE1, 0x9642, 0x70F9, 0x9643, 0x7832, 0x9644, 0x7E2B, 0x9645, 0x80DE, 0x9646, 0x82B3, 0x9647, 0x840C, 0x9648, 0x84EC, + 0x9649, 0x8702, 0x964A, 0x8912, 0x964B, 0x8A2A, 0x964C, 0x8C4A, 0x964D, 0x90A6, 0x964E, 0x92D2, 0x964F, 0x98FD, 0x9650, 0x9CF3, + 0x9651, 0x9D6C, 0x9652, 0x4E4F, 0x9653, 0x4EA1, 0x9654, 0x508D, 0x9655, 0x5256, 0x9656, 0x574A, 0x9657, 0x59A8, 0x9658, 0x5E3D, + 0x9659, 0x5FD8, 0x965A, 0x5FD9, 0x965B, 0x623F, 0x965C, 0x66B4, 0x965D, 0x671B, 0x965E, 0x67D0, 0x965F, 0x68D2, 0x9660, 0x5192, + 0x9661, 0x7D21, 0x9662, 0x80AA, 0x9663, 0x81A8, 0x9664, 0x8B00, 0x9665, 0x8C8C, 0x9666, 0x8CBF, 0x9667, 0x927E, 0x9668, 0x9632, + 0x9669, 0x5420, 0x966A, 0x982C, 0x966B, 0x5317, 0x966C, 0x50D5, 0x966D, 0x535C, 0x966E, 0x58A8, 0x966F, 0x64B2, 0x9670, 0x6734, + 0x9671, 0x7267, 0x9672, 0x7766, 0x9673, 0x7A46, 0x9674, 0x91E6, 0x9675, 0x52C3, 0x9676, 0x6CA1, 0x9677, 0x6B86, 0x9678, 0x5800, + 0x9679, 0x5E4C, 0x967A, 0x5954, 0x967B, 0x672C, 0x967C, 0x7FFB, 0x967D, 0x51E1, 0x967E, 0x76C6, 0x9680, 0x6469, 0x9681, 0x78E8, + 0x9682, 0x9B54, 0x9683, 0x9EBB, 0x9684, 0x57CB, 0x9685, 0x59B9, 0x9686, 0x6627, 0x9687, 0x679A, 0x9688, 0x6BCE, 0x9689, 0x54E9, + 0x968A, 0x69D9, 0x968B, 0x5E55, 0x968C, 0x819C, 0x968D, 0x6795, 0x968E, 0x9BAA, 0x968F, 0x67FE, 0x9690, 0x9C52, 0x9691, 0x685D, + 0x9692, 0x4EA6, 0x9693, 0x4FE3, 0x9694, 0x53C8, 0x9695, 0x62B9, 0x9696, 0x672B, 0x9697, 0x6CAB, 0x9698, 0x8FC4, 0x9699, 0x4FAD, + 0x969A, 0x7E6D, 0x969B, 0x9EBF, 0x969C, 0x4E07, 0x969D, 0x6162, 0x969E, 0x6E80, 0x969F, 0x6F2B, 0x96A0, 0x8513, 0x96A1, 0x5473, + 0x96A2, 0x672A, 0x96A3, 0x9B45, 0x96A4, 0x5DF3, 0x96A5, 0x7B95, 0x96A6, 0x5CAC, 0x96A7, 0x5BC6, 0x96A8, 0x871C, 0x96A9, 0x6E4A, + 0x96AA, 0x84D1, 0x96AB, 0x7A14, 0x96AC, 0x8108, 0x96AD, 0x5999, 0x96AE, 0x7C8D, 0x96AF, 0x6C11, 0x96B0, 0x7720, 0x96B1, 0x52D9, + 0x96B2, 0x5922, 0x96B3, 0x7121, 0x96B4, 0x725F, 0x96B5, 0x77DB, 0x96B6, 0x9727, 0x96B7, 0x9D61, 0x96B8, 0x690B, 0x96B9, 0x5A7F, + 0x96BA, 0x5A18, 0x96BB, 0x51A5, 0x96BC, 0x540D, 0x96BD, 0x547D, 0x96BE, 0x660E, 0x96BF, 0x76DF, 0x96C0, 0x8FF7, 0x96C1, 0x9298, + 0x96C2, 0x9CF4, 0x96C3, 0x59EA, 0x96C4, 0x725D, 0x96C5, 0x6EC5, 0x96C6, 0x514D, 0x96C7, 0x68C9, 0x96C8, 0x7DBF, 0x96C9, 0x7DEC, + 0x96CA, 0x9762, 0x96CB, 0x9EBA, 0x96CC, 0x6478, 0x96CD, 0x6A21, 0x96CE, 0x8302, 0x96CF, 0x5984, 0x96D0, 0x5B5F, 0x96D1, 0x6BDB, + 0x96D2, 0x731B, 0x96D3, 0x76F2, 0x96D4, 0x7DB2, 0x96D5, 0x8017, 0x96D6, 0x8499, 0x96D7, 0x5132, 0x96D8, 0x6728, 0x96D9, 0x9ED9, + 0x96DA, 0x76EE, 0x96DB, 0x6762, 0x96DC, 0x52FF, 0x96DD, 0x9905, 0x96DE, 0x5C24, 0x96DF, 0x623B, 0x96E0, 0x7C7E, 0x96E1, 0x8CB0, + 0x96E2, 0x554F, 0x96E3, 0x60B6, 0x96E4, 0x7D0B, 0x96E5, 0x9580, 0x96E6, 0x5301, 0x96E7, 0x4E5F, 0x96E8, 0x51B6, 0x96E9, 0x591C, + 0x96EA, 0x723A, 0x96EB, 0x8036, 0x96EC, 0x91CE, 0x96ED, 0x5F25, 0x96EE, 0x77E2, 0x96EF, 0x5384, 0x96F0, 0x5F79, 0x96F1, 0x7D04, + 0x96F2, 0x85AC, 0x96F3, 0x8A33, 0x96F4, 0x8E8D, 0x96F5, 0x9756, 0x96F6, 0x67F3, 0x96F7, 0x85AE, 0x96F8, 0x9453, 0x96F9, 0x6109, + 0x96FA, 0x6108, 0x96FB, 0x6CB9, 0x96FC, 0x7652, 0x9740, 0x8AED, 0x9741, 0x8F38, 0x9742, 0x552F, 0x9743, 0x4F51, 0x9744, 0x512A, + 0x9745, 0x52C7, 0x9746, 0x53CB, 0x9747, 0x5BA5, 0x9748, 0x5E7D, 0x9749, 0x60A0, 0x974A, 0x6182, 0x974B, 0x63D6, 0x974C, 0x6709, + 0x974D, 0x67DA, 0x974E, 0x6E67, 0x974F, 0x6D8C, 0x9750, 0x7336, 0x9751, 0x7337, 0x9752, 0x7531, 0x9753, 0x7950, 0x9754, 0x88D5, + 0x9755, 0x8A98, 0x9756, 0x904A, 0x9757, 0x9091, 0x9758, 0x90F5, 0x9759, 0x96C4, 0x975A, 0x878D, 0x975B, 0x5915, 0x975C, 0x4E88, + 0x975D, 0x4F59, 0x975E, 0x4E0E, 0x975F, 0x8A89, 0x9760, 0x8F3F, 0x9761, 0x9810, 0x9762, 0x50AD, 0x9763, 0x5E7C, 0x9764, 0x5996, + 0x9765, 0x5BB9, 0x9766, 0x5EB8, 0x9767, 0x63DA, 0x9768, 0x63FA, 0x9769, 0x64C1, 0x976A, 0x66DC, 0x976B, 0x694A, 0x976C, 0x69D8, + 0x976D, 0x6D0B, 0x976E, 0x6EB6, 0x976F, 0x7194, 0x9770, 0x7528, 0x9771, 0x7AAF, 0x9772, 0x7F8A, 0x9773, 0x8000, 0x9774, 0x8449, + 0x9775, 0x84C9, 0x9776, 0x8981, 0x9777, 0x8B21, 0x9778, 0x8E0A, 0x9779, 0x9065, 0x977A, 0x967D, 0x977B, 0x990A, 0x977C, 0x617E, + 0x977D, 0x6291, 0x977E, 0x6B32, 0x9780, 0x6C83, 0x9781, 0x6D74, 0x9782, 0x7FCC, 0x9783, 0x7FFC, 0x9784, 0x6DC0, 0x9785, 0x7F85, + 0x9786, 0x87BA, 0x9787, 0x88F8, 0x9788, 0x6765, 0x9789, 0x83B1, 0x978A, 0x983C, 0x978B, 0x96F7, 0x978C, 0x6D1B, 0x978D, 0x7D61, + 0x978E, 0x843D, 0x978F, 0x916A, 0x9790, 0x4E71, 0x9791, 0x5375, 0x9792, 0x5D50, 0x9793, 0x6B04, 0x9794, 0x6FEB, 0x9795, 0x85CD, + 0x9796, 0x862D, 0x9797, 0x89A7, 0x9798, 0x5229, 0x9799, 0x540F, 0x979A, 0x5C65, 0x979B, 0x674E, 0x979C, 0x68A8, 0x979D, 0x7406, + 0x979E, 0x7483, 0x979F, 0x75E2, 0x97A0, 0x88CF, 0x97A1, 0x88E1, 0x97A2, 0x91CC, 0x97A3, 0x96E2, 0x97A4, 0x9678, 0x97A5, 0x5F8B, + 0x97A6, 0x7387, 0x97A7, 0x7ACB, 0x97A8, 0x844E, 0x97A9, 0x63A0, 0x97AA, 0x7565, 0x97AB, 0x5289, 0x97AC, 0x6D41, 0x97AD, 0x6E9C, + 0x97AE, 0x7409, 0x97AF, 0x7559, 0x97B0, 0x786B, 0x97B1, 0x7C92, 0x97B2, 0x9686, 0x97B3, 0x7ADC, 0x97B4, 0x9F8D, 0x97B5, 0x4FB6, + 0x97B6, 0x616E, 0x97B7, 0x65C5, 0x97B8, 0x865C, 0x97B9, 0x4E86, 0x97BA, 0x4EAE, 0x97BB, 0x50DA, 0x97BC, 0x4E21, 0x97BD, 0x51CC, + 0x97BE, 0x5BEE, 0x97BF, 0x6599, 0x97C0, 0x6881, 0x97C1, 0x6DBC, 0x97C2, 0x731F, 0x97C3, 0x7642, 0x97C4, 0x77AD, 0x97C5, 0x7A1C, + 0x97C6, 0x7CE7, 0x97C7, 0x826F, 0x97C8, 0x8AD2, 0x97C9, 0x907C, 0x97CA, 0x91CF, 0x97CB, 0x9675, 0x97CC, 0x9818, 0x97CD, 0x529B, + 0x97CE, 0x7DD1, 0x97CF, 0x502B, 0x97D0, 0x5398, 0x97D1, 0x6797, 0x97D2, 0x6DCB, 0x97D3, 0x71D0, 0x97D4, 0x7433, 0x97D5, 0x81E8, + 0x97D6, 0x8F2A, 0x97D7, 0x96A3, 0x97D8, 0x9C57, 0x97D9, 0x9E9F, 0x97DA, 0x7460, 0x97DB, 0x5841, 0x97DC, 0x6D99, 0x97DD, 0x7D2F, + 0x97DE, 0x985E, 0x97DF, 0x4EE4, 0x97E0, 0x4F36, 0x97E1, 0x4F8B, 0x97E2, 0x51B7, 0x97E3, 0x52B1, 0x97E4, 0x5DBA, 0x97E5, 0x601C, + 0x97E6, 0x73B2, 0x97E7, 0x793C, 0x97E8, 0x82D3, 0x97E9, 0x9234, 0x97EA, 0x96B7, 0x97EB, 0x96F6, 0x97EC, 0x970A, 0x97ED, 0x9E97, + 0x97EE, 0x9F62, 0x97EF, 0x66A6, 0x97F0, 0x6B74, 0x97F1, 0x5217, 0x97F2, 0x52A3, 0x97F3, 0x70C8, 0x97F4, 0x88C2, 0x97F5, 0x5EC9, + 0x97F6, 0x604B, 0x97F7, 0x6190, 0x97F8, 0x6F23, 0x97F9, 0x7149, 0x97FA, 0x7C3E, 0x97FB, 0x7DF4, 0x97FC, 0x806F, 0x9840, 0x84EE, + 0x9841, 0x9023, 0x9842, 0x932C, 0x9843, 0x5442, 0x9844, 0x9B6F, 0x9845, 0x6AD3, 0x9846, 0x7089, 0x9847, 0x8CC2, 0x9848, 0x8DEF, + 0x9849, 0x9732, 0x984A, 0x52B4, 0x984B, 0x5A41, 0x984C, 0x5ECA, 0x984D, 0x5F04, 0x984E, 0x6717, 0x984F, 0x697C, 0x9850, 0x6994, + 0x9851, 0x6D6A, 0x9852, 0x6F0F, 0x9853, 0x7262, 0x9854, 0x72FC, 0x9855, 0x7BED, 0x9856, 0x8001, 0x9857, 0x807E, 0x9858, 0x874B, + 0x9859, 0x90CE, 0x985A, 0x516D, 0x985B, 0x9E93, 0x985C, 0x7984, 0x985D, 0x808B, 0x985E, 0x9332, 0x985F, 0x8AD6, 0x9860, 0x502D, + 0x9861, 0x548C, 0x9862, 0x8A71, 0x9863, 0x6B6A, 0x9864, 0x8CC4, 0x9865, 0x8107, 0x9866, 0x60D1, 0x9867, 0x67A0, 0x9868, 0x9DF2, + 0x9869, 0x4E99, 0x986A, 0x4E98, 0x986B, 0x9C10, 0x986C, 0x8A6B, 0x986D, 0x85C1, 0x986E, 0x8568, 0x986F, 0x6900, 0x9870, 0x6E7E, + 0x9871, 0x7897, 0x9872, 0x8155, 0x989F, 0x5F0C, 0x98A0, 0x4E10, 0x98A1, 0x4E15, 0x98A2, 0x4E2A, 0x98A3, 0x4E31, 0x98A4, 0x4E36, + 0x98A5, 0x4E3C, 0x98A6, 0x4E3F, 0x98A7, 0x4E42, 0x98A8, 0x4E56, 0x98A9, 0x4E58, 0x98AA, 0x4E82, 0x98AB, 0x4E85, 0x98AC, 0x8C6B, + 0x98AD, 0x4E8A, 0x98AE, 0x8212, 0x98AF, 0x5F0D, 0x98B0, 0x4E8E, 0x98B1, 0x4E9E, 0x98B2, 0x4E9F, 0x98B3, 0x4EA0, 0x98B4, 0x4EA2, + 0x98B5, 0x4EB0, 0x98B6, 0x4EB3, 0x98B7, 0x4EB6, 0x98B8, 0x4ECE, 0x98B9, 0x4ECD, 0x98BA, 0x4EC4, 0x98BB, 0x4EC6, 0x98BC, 0x4EC2, + 0x98BD, 0x4ED7, 0x98BE, 0x4EDE, 0x98BF, 0x4EED, 0x98C0, 0x4EDF, 0x98C1, 0x4EF7, 0x98C2, 0x4F09, 0x98C3, 0x4F5A, 0x98C4, 0x4F30, + 0x98C5, 0x4F5B, 0x98C6, 0x4F5D, 0x98C7, 0x4F57, 0x98C8, 0x4F47, 0x98C9, 0x4F76, 0x98CA, 0x4F88, 0x98CB, 0x4F8F, 0x98CC, 0x4F98, + 0x98CD, 0x4F7B, 0x98CE, 0x4F69, 0x98CF, 0x4F70, 0x98D0, 0x4F91, 0x98D1, 0x4F6F, 0x98D2, 0x4F86, 0x98D3, 0x4F96, 0x98D4, 0x5118, + 0x98D5, 0x4FD4, 0x98D6, 0x4FDF, 0x98D7, 0x4FCE, 0x98D8, 0x4FD8, 0x98D9, 0x4FDB, 0x98DA, 0x4FD1, 0x98DB, 0x4FDA, 0x98DC, 0x4FD0, + 0x98DD, 0x4FE4, 0x98DE, 0x4FE5, 0x98DF, 0x501A, 0x98E0, 0x5028, 0x98E1, 0x5014, 0x98E2, 0x502A, 0x98E3, 0x5025, 0x98E4, 0x5005, + 0x98E5, 0x4F1C, 0x98E6, 0x4FF6, 0x98E7, 0x5021, 0x98E8, 0x5029, 0x98E9, 0x502C, 0x98EA, 0x4FFE, 0x98EB, 0x4FEF, 0x98EC, 0x5011, + 0x98ED, 0x5006, 0x98EE, 0x5043, 0x98EF, 0x5047, 0x98F0, 0x6703, 0x98F1, 0x5055, 0x98F2, 0x5050, 0x98F3, 0x5048, 0x98F4, 0x505A, + 0x98F5, 0x5056, 0x98F6, 0x506C, 0x98F7, 0x5078, 0x98F8, 0x5080, 0x98F9, 0x509A, 0x98FA, 0x5085, 0x98FB, 0x50B4, 0x98FC, 0x50B2, + 0x9940, 0x50C9, 0x9941, 0x50CA, 0x9942, 0x50B3, 0x9943, 0x50C2, 0x9944, 0x50D6, 0x9945, 0x50DE, 0x9946, 0x50E5, 0x9947, 0x50ED, + 0x9948, 0x50E3, 0x9949, 0x50EE, 0x994A, 0x50F9, 0x994B, 0x50F5, 0x994C, 0x5109, 0x994D, 0x5101, 0x994E, 0x5102, 0x994F, 0x5116, + 0x9950, 0x5115, 0x9951, 0x5114, 0x9952, 0x511A, 0x9953, 0x5121, 0x9954, 0x513A, 0x9955, 0x5137, 0x9956, 0x513C, 0x9957, 0x513B, + 0x9958, 0x513F, 0x9959, 0x5140, 0x995A, 0x5152, 0x995B, 0x514C, 0x995C, 0x5154, 0x995D, 0x5162, 0x995E, 0x7AF8, 0x995F, 0x5169, + 0x9960, 0x516A, 0x9961, 0x516E, 0x9962, 0x5180, 0x9963, 0x5182, 0x9964, 0x56D8, 0x9965, 0x518C, 0x9966, 0x5189, 0x9967, 0x518F, + 0x9968, 0x5191, 0x9969, 0x5193, 0x996A, 0x5195, 0x996B, 0x5196, 0x996C, 0x51A4, 0x996D, 0x51A6, 0x996E, 0x51A2, 0x996F, 0x51A9, + 0x9970, 0x51AA, 0x9971, 0x51AB, 0x9972, 0x51B3, 0x9973, 0x51B1, 0x9974, 0x51B2, 0x9975, 0x51B0, 0x9976, 0x51B5, 0x9977, 0x51BD, + 0x9978, 0x51C5, 0x9979, 0x51C9, 0x997A, 0x51DB, 0x997B, 0x51E0, 0x997C, 0x8655, 0x997D, 0x51E9, 0x997E, 0x51ED, 0x9980, 0x51F0, + 0x9981, 0x51F5, 0x9982, 0x51FE, 0x9983, 0x5204, 0x9984, 0x520B, 0x9985, 0x5214, 0x9986, 0x520E, 0x9987, 0x5227, 0x9988, 0x522A, + 0x9989, 0x522E, 0x998A, 0x5233, 0x998B, 0x5239, 0x998C, 0x524F, 0x998D, 0x5244, 0x998E, 0x524B, 0x998F, 0x524C, 0x9990, 0x525E, + 0x9991, 0x5254, 0x9992, 0x526A, 0x9993, 0x5274, 0x9994, 0x5269, 0x9995, 0x5273, 0x9996, 0x527F, 0x9997, 0x527D, 0x9998, 0x528D, + 0x9999, 0x5294, 0x999A, 0x5292, 0x999B, 0x5271, 0x999C, 0x5288, 0x999D, 0x5291, 0x999E, 0x8FA8, 0x999F, 0x8FA7, 0x99A0, 0x52AC, + 0x99A1, 0x52AD, 0x99A2, 0x52BC, 0x99A3, 0x52B5, 0x99A4, 0x52C1, 0x99A5, 0x52CD, 0x99A6, 0x52D7, 0x99A7, 0x52DE, 0x99A8, 0x52E3, + 0x99A9, 0x52E6, 0x99AA, 0x98ED, 0x99AB, 0x52E0, 0x99AC, 0x52F3, 0x99AD, 0x52F5, 0x99AE, 0x52F8, 0x99AF, 0x52F9, 0x99B0, 0x5306, + 0x99B1, 0x5308, 0x99B2, 0x7538, 0x99B3, 0x530D, 0x99B4, 0x5310, 0x99B5, 0x530F, 0x99B6, 0x5315, 0x99B7, 0x531A, 0x99B8, 0x5323, + 0x99B9, 0x532F, 0x99BA, 0x5331, 0x99BB, 0x5333, 0x99BC, 0x5338, 0x99BD, 0x5340, 0x99BE, 0x5346, 0x99BF, 0x5345, 0x99C0, 0x4E17, + 0x99C1, 0x5349, 0x99C2, 0x534D, 0x99C3, 0x51D6, 0x99C4, 0x535E, 0x99C5, 0x5369, 0x99C6, 0x536E, 0x99C7, 0x5918, 0x99C8, 0x537B, + 0x99C9, 0x5377, 0x99CA, 0x5382, 0x99CB, 0x5396, 0x99CC, 0x53A0, 0x99CD, 0x53A6, 0x99CE, 0x53A5, 0x99CF, 0x53AE, 0x99D0, 0x53B0, + 0x99D1, 0x53B6, 0x99D2, 0x53C3, 0x99D3, 0x7C12, 0x99D4, 0x96D9, 0x99D5, 0x53DF, 0x99D6, 0x66FC, 0x99D7, 0x71EE, 0x99D8, 0x53EE, + 0x99D9, 0x53E8, 0x99DA, 0x53ED, 0x99DB, 0x53FA, 0x99DC, 0x5401, 0x99DD, 0x543D, 0x99DE, 0x5440, 0x99DF, 0x542C, 0x99E0, 0x542D, + 0x99E1, 0x543C, 0x99E2, 0x542E, 0x99E3, 0x5436, 0x99E4, 0x5429, 0x99E5, 0x541D, 0x99E6, 0x544E, 0x99E7, 0x548F, 0x99E8, 0x5475, + 0x99E9, 0x548E, 0x99EA, 0x545F, 0x99EB, 0x5471, 0x99EC, 0x5477, 0x99ED, 0x5470, 0x99EE, 0x5492, 0x99EF, 0x547B, 0x99F0, 0x5480, + 0x99F1, 0x5476, 0x99F2, 0x5484, 0x99F3, 0x5490, 0x99F4, 0x5486, 0x99F5, 0x54C7, 0x99F6, 0x54A2, 0x99F7, 0x54B8, 0x99F8, 0x54A5, + 0x99F9, 0x54AC, 0x99FA, 0x54C4, 0x99FB, 0x54C8, 0x99FC, 0x54A8, 0x9A40, 0x54AB, 0x9A41, 0x54C2, 0x9A42, 0x54A4, 0x9A43, 0x54BE, + 0x9A44, 0x54BC, 0x9A45, 0x54D8, 0x9A46, 0x54E5, 0x9A47, 0x54E6, 0x9A48, 0x550F, 0x9A49, 0x5514, 0x9A4A, 0x54FD, 0x9A4B, 0x54EE, + 0x9A4C, 0x54ED, 0x9A4D, 0x54FA, 0x9A4E, 0x54E2, 0x9A4F, 0x5539, 0x9A50, 0x5540, 0x9A51, 0x5563, 0x9A52, 0x554C, 0x9A53, 0x552E, + 0x9A54, 0x555C, 0x9A55, 0x5545, 0x9A56, 0x5556, 0x9A57, 0x5557, 0x9A58, 0x5538, 0x9A59, 0x5533, 0x9A5A, 0x555D, 0x9A5B, 0x5599, + 0x9A5C, 0x5580, 0x9A5D, 0x54AF, 0x9A5E, 0x558A, 0x9A5F, 0x559F, 0x9A60, 0x557B, 0x9A61, 0x557E, 0x9A62, 0x5598, 0x9A63, 0x559E, + 0x9A64, 0x55AE, 0x9A65, 0x557C, 0x9A66, 0x5583, 0x9A67, 0x55A9, 0x9A68, 0x5587, 0x9A69, 0x55A8, 0x9A6A, 0x55DA, 0x9A6B, 0x55C5, + 0x9A6C, 0x55DF, 0x9A6D, 0x55C4, 0x9A6E, 0x55DC, 0x9A6F, 0x55E4, 0x9A70, 0x55D4, 0x9A71, 0x5614, 0x9A72, 0x55F7, 0x9A73, 0x5616, + 0x9A74, 0x55FE, 0x9A75, 0x55FD, 0x9A76, 0x561B, 0x9A77, 0x55F9, 0x9A78, 0x564E, 0x9A79, 0x5650, 0x9A7A, 0x71DF, 0x9A7B, 0x5634, + 0x9A7C, 0x5636, 0x9A7D, 0x5632, 0x9A7E, 0x5638, 0x9A80, 0x566B, 0x9A81, 0x5664, 0x9A82, 0x562F, 0x9A83, 0x566C, 0x9A84, 0x566A, + 0x9A85, 0x5686, 0x9A86, 0x5680, 0x9A87, 0x568A, 0x9A88, 0x56A0, 0x9A89, 0x5694, 0x9A8A, 0x568F, 0x9A8B, 0x56A5, 0x9A8C, 0x56AE, + 0x9A8D, 0x56B6, 0x9A8E, 0x56B4, 0x9A8F, 0x56C2, 0x9A90, 0x56BC, 0x9A91, 0x56C1, 0x9A92, 0x56C3, 0x9A93, 0x56C0, 0x9A94, 0x56C8, + 0x9A95, 0x56CE, 0x9A96, 0x56D1, 0x9A97, 0x56D3, 0x9A98, 0x56D7, 0x9A99, 0x56EE, 0x9A9A, 0x56F9, 0x9A9B, 0x5700, 0x9A9C, 0x56FF, + 0x9A9D, 0x5704, 0x9A9E, 0x5709, 0x9A9F, 0x5708, 0x9AA0, 0x570B, 0x9AA1, 0x570D, 0x9AA2, 0x5713, 0x9AA3, 0x5718, 0x9AA4, 0x5716, + 0x9AA5, 0x55C7, 0x9AA6, 0x571C, 0x9AA7, 0x5726, 0x9AA8, 0x5737, 0x9AA9, 0x5738, 0x9AAA, 0x574E, 0x9AAB, 0x573B, 0x9AAC, 0x5740, + 0x9AAD, 0x574F, 0x9AAE, 0x5769, 0x9AAF, 0x57C0, 0x9AB0, 0x5788, 0x9AB1, 0x5761, 0x9AB2, 0x577F, 0x9AB3, 0x5789, 0x9AB4, 0x5793, + 0x9AB5, 0x57A0, 0x9AB6, 0x57B3, 0x9AB7, 0x57A4, 0x9AB8, 0x57AA, 0x9AB9, 0x57B0, 0x9ABA, 0x57C3, 0x9ABB, 0x57C6, 0x9ABC, 0x57D4, + 0x9ABD, 0x57D2, 0x9ABE, 0x57D3, 0x9ABF, 0x580A, 0x9AC0, 0x57D6, 0x9AC1, 0x57E3, 0x9AC2, 0x580B, 0x9AC3, 0x5819, 0x9AC4, 0x581D, + 0x9AC5, 0x5872, 0x9AC6, 0x5821, 0x9AC7, 0x5862, 0x9AC8, 0x584B, 0x9AC9, 0x5870, 0x9ACA, 0x6BC0, 0x9ACB, 0x5852, 0x9ACC, 0x583D, + 0x9ACD, 0x5879, 0x9ACE, 0x5885, 0x9ACF, 0x58B9, 0x9AD0, 0x589F, 0x9AD1, 0x58AB, 0x9AD2, 0x58BA, 0x9AD3, 0x58DE, 0x9AD4, 0x58BB, + 0x9AD5, 0x58B8, 0x9AD6, 0x58AE, 0x9AD7, 0x58C5, 0x9AD8, 0x58D3, 0x9AD9, 0x58D1, 0x9ADA, 0x58D7, 0x9ADB, 0x58D9, 0x9ADC, 0x58D8, + 0x9ADD, 0x58E5, 0x9ADE, 0x58DC, 0x9ADF, 0x58E4, 0x9AE0, 0x58DF, 0x9AE1, 0x58EF, 0x9AE2, 0x58FA, 0x9AE3, 0x58F9, 0x9AE4, 0x58FB, + 0x9AE5, 0x58FC, 0x9AE6, 0x58FD, 0x9AE7, 0x5902, 0x9AE8, 0x590A, 0x9AE9, 0x5910, 0x9AEA, 0x591B, 0x9AEB, 0x68A6, 0x9AEC, 0x5925, + 0x9AED, 0x592C, 0x9AEE, 0x592D, 0x9AEF, 0x5932, 0x9AF0, 0x5938, 0x9AF1, 0x593E, 0x9AF2, 0x7AD2, 0x9AF3, 0x5955, 0x9AF4, 0x5950, + 0x9AF5, 0x594E, 0x9AF6, 0x595A, 0x9AF7, 0x5958, 0x9AF8, 0x5962, 0x9AF9, 0x5960, 0x9AFA, 0x5967, 0x9AFB, 0x596C, 0x9AFC, 0x5969, + 0x9B40, 0x5978, 0x9B41, 0x5981, 0x9B42, 0x599D, 0x9B43, 0x4F5E, 0x9B44, 0x4FAB, 0x9B45, 0x59A3, 0x9B46, 0x59B2, 0x9B47, 0x59C6, + 0x9B48, 0x59E8, 0x9B49, 0x59DC, 0x9B4A, 0x598D, 0x9B4B, 0x59D9, 0x9B4C, 0x59DA, 0x9B4D, 0x5A25, 0x9B4E, 0x5A1F, 0x9B4F, 0x5A11, + 0x9B50, 0x5A1C, 0x9B51, 0x5A09, 0x9B52, 0x5A1A, 0x9B53, 0x5A40, 0x9B54, 0x5A6C, 0x9B55, 0x5A49, 0x9B56, 0x5A35, 0x9B57, 0x5A36, + 0x9B58, 0x5A62, 0x9B59, 0x5A6A, 0x9B5A, 0x5A9A, 0x9B5B, 0x5ABC, 0x9B5C, 0x5ABE, 0x9B5D, 0x5ACB, 0x9B5E, 0x5AC2, 0x9B5F, 0x5ABD, + 0x9B60, 0x5AE3, 0x9B61, 0x5AD7, 0x9B62, 0x5AE6, 0x9B63, 0x5AE9, 0x9B64, 0x5AD6, 0x9B65, 0x5AFA, 0x9B66, 0x5AFB, 0x9B67, 0x5B0C, + 0x9B68, 0x5B0B, 0x9B69, 0x5B16, 0x9B6A, 0x5B32, 0x9B6B, 0x5AD0, 0x9B6C, 0x5B2A, 0x9B6D, 0x5B36, 0x9B6E, 0x5B3E, 0x9B6F, 0x5B43, + 0x9B70, 0x5B45, 0x9B71, 0x5B40, 0x9B72, 0x5B51, 0x9B73, 0x5B55, 0x9B74, 0x5B5A, 0x9B75, 0x5B5B, 0x9B76, 0x5B65, 0x9B77, 0x5B69, + 0x9B78, 0x5B70, 0x9B79, 0x5B73, 0x9B7A, 0x5B75, 0x9B7B, 0x5B78, 0x9B7C, 0x6588, 0x9B7D, 0x5B7A, 0x9B7E, 0x5B80, 0x9B80, 0x5B83, + 0x9B81, 0x5BA6, 0x9B82, 0x5BB8, 0x9B83, 0x5BC3, 0x9B84, 0x5BC7, 0x9B85, 0x5BC9, 0x9B86, 0x5BD4, 0x9B87, 0x5BD0, 0x9B88, 0x5BE4, + 0x9B89, 0x5BE6, 0x9B8A, 0x5BE2, 0x9B8B, 0x5BDE, 0x9B8C, 0x5BE5, 0x9B8D, 0x5BEB, 0x9B8E, 0x5BF0, 0x9B8F, 0x5BF6, 0x9B90, 0x5BF3, + 0x9B91, 0x5C05, 0x9B92, 0x5C07, 0x9B93, 0x5C08, 0x9B94, 0x5C0D, 0x9B95, 0x5C13, 0x9B96, 0x5C20, 0x9B97, 0x5C22, 0x9B98, 0x5C28, + 0x9B99, 0x5C38, 0x9B9A, 0x5C39, 0x9B9B, 0x5C41, 0x9B9C, 0x5C46, 0x9B9D, 0x5C4E, 0x9B9E, 0x5C53, 0x9B9F, 0x5C50, 0x9BA0, 0x5C4F, + 0x9BA1, 0x5B71, 0x9BA2, 0x5C6C, 0x9BA3, 0x5C6E, 0x9BA4, 0x4E62, 0x9BA5, 0x5C76, 0x9BA6, 0x5C79, 0x9BA7, 0x5C8C, 0x9BA8, 0x5C91, + 0x9BA9, 0x5C94, 0x9BAA, 0x599B, 0x9BAB, 0x5CAB, 0x9BAC, 0x5CBB, 0x9BAD, 0x5CB6, 0x9BAE, 0x5CBC, 0x9BAF, 0x5CB7, 0x9BB0, 0x5CC5, + 0x9BB1, 0x5CBE, 0x9BB2, 0x5CC7, 0x9BB3, 0x5CD9, 0x9BB4, 0x5CE9, 0x9BB5, 0x5CFD, 0x9BB6, 0x5CFA, 0x9BB7, 0x5CED, 0x9BB8, 0x5D8C, + 0x9BB9, 0x5CEA, 0x9BBA, 0x5D0B, 0x9BBB, 0x5D15, 0x9BBC, 0x5D17, 0x9BBD, 0x5D5C, 0x9BBE, 0x5D1F, 0x9BBF, 0x5D1B, 0x9BC0, 0x5D11, + 0x9BC1, 0x5D14, 0x9BC2, 0x5D22, 0x9BC3, 0x5D1A, 0x9BC4, 0x5D19, 0x9BC5, 0x5D18, 0x9BC6, 0x5D4C, 0x9BC7, 0x5D52, 0x9BC8, 0x5D4E, + 0x9BC9, 0x5D4B, 0x9BCA, 0x5D6C, 0x9BCB, 0x5D73, 0x9BCC, 0x5D76, 0x9BCD, 0x5D87, 0x9BCE, 0x5D84, 0x9BCF, 0x5D82, 0x9BD0, 0x5DA2, + 0x9BD1, 0x5D9D, 0x9BD2, 0x5DAC, 0x9BD3, 0x5DAE, 0x9BD4, 0x5DBD, 0x9BD5, 0x5D90, 0x9BD6, 0x5DB7, 0x9BD7, 0x5DBC, 0x9BD8, 0x5DC9, + 0x9BD9, 0x5DCD, 0x9BDA, 0x5DD3, 0x9BDB, 0x5DD2, 0x9BDC, 0x5DD6, 0x9BDD, 0x5DDB, 0x9BDE, 0x5DEB, 0x9BDF, 0x5DF2, 0x9BE0, 0x5DF5, + 0x9BE1, 0x5E0B, 0x9BE2, 0x5E1A, 0x9BE3, 0x5E19, 0x9BE4, 0x5E11, 0x9BE5, 0x5E1B, 0x9BE6, 0x5E36, 0x9BE7, 0x5E37, 0x9BE8, 0x5E44, + 0x9BE9, 0x5E43, 0x9BEA, 0x5E40, 0x9BEB, 0x5E4E, 0x9BEC, 0x5E57, 0x9BED, 0x5E54, 0x9BEE, 0x5E5F, 0x9BEF, 0x5E62, 0x9BF0, 0x5E64, + 0x9BF1, 0x5E47, 0x9BF2, 0x5E75, 0x9BF3, 0x5E76, 0x9BF4, 0x5E7A, 0x9BF5, 0x9EBC, 0x9BF6, 0x5E7F, 0x9BF7, 0x5EA0, 0x9BF8, 0x5EC1, + 0x9BF9, 0x5EC2, 0x9BFA, 0x5EC8, 0x9BFB, 0x5ED0, 0x9BFC, 0x5ECF, 0x9C40, 0x5ED6, 0x9C41, 0x5EE3, 0x9C42, 0x5EDD, 0x9C43, 0x5EDA, + 0x9C44, 0x5EDB, 0x9C45, 0x5EE2, 0x9C46, 0x5EE1, 0x9C47, 0x5EE8, 0x9C48, 0x5EE9, 0x9C49, 0x5EEC, 0x9C4A, 0x5EF1, 0x9C4B, 0x5EF3, + 0x9C4C, 0x5EF0, 0x9C4D, 0x5EF4, 0x9C4E, 0x5EF8, 0x9C4F, 0x5EFE, 0x9C50, 0x5F03, 0x9C51, 0x5F09, 0x9C52, 0x5F5D, 0x9C53, 0x5F5C, + 0x9C54, 0x5F0B, 0x9C55, 0x5F11, 0x9C56, 0x5F16, 0x9C57, 0x5F29, 0x9C58, 0x5F2D, 0x9C59, 0x5F38, 0x9C5A, 0x5F41, 0x9C5B, 0x5F48, + 0x9C5C, 0x5F4C, 0x9C5D, 0x5F4E, 0x9C5E, 0x5F2F, 0x9C5F, 0x5F51, 0x9C60, 0x5F56, 0x9C61, 0x5F57, 0x9C62, 0x5F59, 0x9C63, 0x5F61, + 0x9C64, 0x5F6D, 0x9C65, 0x5F73, 0x9C66, 0x5F77, 0x9C67, 0x5F83, 0x9C68, 0x5F82, 0x9C69, 0x5F7F, 0x9C6A, 0x5F8A, 0x9C6B, 0x5F88, + 0x9C6C, 0x5F91, 0x9C6D, 0x5F87, 0x9C6E, 0x5F9E, 0x9C6F, 0x5F99, 0x9C70, 0x5F98, 0x9C71, 0x5FA0, 0x9C72, 0x5FA8, 0x9C73, 0x5FAD, + 0x9C74, 0x5FBC, 0x9C75, 0x5FD6, 0x9C76, 0x5FFB, 0x9C77, 0x5FE4, 0x9C78, 0x5FF8, 0x9C79, 0x5FF1, 0x9C7A, 0x5FDD, 0x9C7B, 0x60B3, + 0x9C7C, 0x5FFF, 0x9C7D, 0x6021, 0x9C7E, 0x6060, 0x9C80, 0x6019, 0x9C81, 0x6010, 0x9C82, 0x6029, 0x9C83, 0x600E, 0x9C84, 0x6031, + 0x9C85, 0x601B, 0x9C86, 0x6015, 0x9C87, 0x602B, 0x9C88, 0x6026, 0x9C89, 0x600F, 0x9C8A, 0x603A, 0x9C8B, 0x605A, 0x9C8C, 0x6041, + 0x9C8D, 0x606A, 0x9C8E, 0x6077, 0x9C8F, 0x605F, 0x9C90, 0x604A, 0x9C91, 0x6046, 0x9C92, 0x604D, 0x9C93, 0x6063, 0x9C94, 0x6043, + 0x9C95, 0x6064, 0x9C96, 0x6042, 0x9C97, 0x606C, 0x9C98, 0x606B, 0x9C99, 0x6059, 0x9C9A, 0x6081, 0x9C9B, 0x608D, 0x9C9C, 0x60E7, + 0x9C9D, 0x6083, 0x9C9E, 0x609A, 0x9C9F, 0x6084, 0x9CA0, 0x609B, 0x9CA1, 0x6096, 0x9CA2, 0x6097, 0x9CA3, 0x6092, 0x9CA4, 0x60A7, + 0x9CA5, 0x608B, 0x9CA6, 0x60E1, 0x9CA7, 0x60B8, 0x9CA8, 0x60E0, 0x9CA9, 0x60D3, 0x9CAA, 0x60B4, 0x9CAB, 0x5FF0, 0x9CAC, 0x60BD, + 0x9CAD, 0x60C6, 0x9CAE, 0x60B5, 0x9CAF, 0x60D8, 0x9CB0, 0x614D, 0x9CB1, 0x6115, 0x9CB2, 0x6106, 0x9CB3, 0x60F6, 0x9CB4, 0x60F7, + 0x9CB5, 0x6100, 0x9CB6, 0x60F4, 0x9CB7, 0x60FA, 0x9CB8, 0x6103, 0x9CB9, 0x6121, 0x9CBA, 0x60FB, 0x9CBB, 0x60F1, 0x9CBC, 0x610D, + 0x9CBD, 0x610E, 0x9CBE, 0x6147, 0x9CBF, 0x613E, 0x9CC0, 0x6128, 0x9CC1, 0x6127, 0x9CC2, 0x614A, 0x9CC3, 0x613F, 0x9CC4, 0x613C, + 0x9CC5, 0x612C, 0x9CC6, 0x6134, 0x9CC7, 0x613D, 0x9CC8, 0x6142, 0x9CC9, 0x6144, 0x9CCA, 0x6173, 0x9CCB, 0x6177, 0x9CCC, 0x6158, + 0x9CCD, 0x6159, 0x9CCE, 0x615A, 0x9CCF, 0x616B, 0x9CD0, 0x6174, 0x9CD1, 0x616F, 0x9CD2, 0x6165, 0x9CD3, 0x6171, 0x9CD4, 0x615F, + 0x9CD5, 0x615D, 0x9CD6, 0x6153, 0x9CD7, 0x6175, 0x9CD8, 0x6199, 0x9CD9, 0x6196, 0x9CDA, 0x6187, 0x9CDB, 0x61AC, 0x9CDC, 0x6194, + 0x9CDD, 0x619A, 0x9CDE, 0x618A, 0x9CDF, 0x6191, 0x9CE0, 0x61AB, 0x9CE1, 0x61AE, 0x9CE2, 0x61CC, 0x9CE3, 0x61CA, 0x9CE4, 0x61C9, + 0x9CE5, 0x61F7, 0x9CE6, 0x61C8, 0x9CE7, 0x61C3, 0x9CE8, 0x61C6, 0x9CE9, 0x61BA, 0x9CEA, 0x61CB, 0x9CEB, 0x7F79, 0x9CEC, 0x61CD, + 0x9CED, 0x61E6, 0x9CEE, 0x61E3, 0x9CEF, 0x61F6, 0x9CF0, 0x61FA, 0x9CF1, 0x61F4, 0x9CF2, 0x61FF, 0x9CF3, 0x61FD, 0x9CF4, 0x61FC, + 0x9CF5, 0x61FE, 0x9CF6, 0x6200, 0x9CF7, 0x6208, 0x9CF8, 0x6209, 0x9CF9, 0x620D, 0x9CFA, 0x620C, 0x9CFB, 0x6214, 0x9CFC, 0x621B, + 0x9D40, 0x621E, 0x9D41, 0x6221, 0x9D42, 0x622A, 0x9D43, 0x622E, 0x9D44, 0x6230, 0x9D45, 0x6232, 0x9D46, 0x6233, 0x9D47, 0x6241, + 0x9D48, 0x624E, 0x9D49, 0x625E, 0x9D4A, 0x6263, 0x9D4B, 0x625B, 0x9D4C, 0x6260, 0x9D4D, 0x6268, 0x9D4E, 0x627C, 0x9D4F, 0x6282, + 0x9D50, 0x6289, 0x9D51, 0x627E, 0x9D52, 0x6292, 0x9D53, 0x6293, 0x9D54, 0x6296, 0x9D55, 0x62D4, 0x9D56, 0x6283, 0x9D57, 0x6294, + 0x9D58, 0x62D7, 0x9D59, 0x62D1, 0x9D5A, 0x62BB, 0x9D5B, 0x62CF, 0x9D5C, 0x62FF, 0x9D5D, 0x62C6, 0x9D5E, 0x64D4, 0x9D5F, 0x62C8, + 0x9D60, 0x62DC, 0x9D61, 0x62CC, 0x9D62, 0x62CA, 0x9D63, 0x62C2, 0x9D64, 0x62C7, 0x9D65, 0x629B, 0x9D66, 0x62C9, 0x9D67, 0x630C, + 0x9D68, 0x62EE, 0x9D69, 0x62F1, 0x9D6A, 0x6327, 0x9D6B, 0x6302, 0x9D6C, 0x6308, 0x9D6D, 0x62EF, 0x9D6E, 0x62F5, 0x9D6F, 0x6350, + 0x9D70, 0x633E, 0x9D71, 0x634D, 0x9D72, 0x641C, 0x9D73, 0x634F, 0x9D74, 0x6396, 0x9D75, 0x638E, 0x9D76, 0x6380, 0x9D77, 0x63AB, + 0x9D78, 0x6376, 0x9D79, 0x63A3, 0x9D7A, 0x638F, 0x9D7B, 0x6389, 0x9D7C, 0x639F, 0x9D7D, 0x63B5, 0x9D7E, 0x636B, 0x9D80, 0x6369, + 0x9D81, 0x63BE, 0x9D82, 0x63E9, 0x9D83, 0x63C0, 0x9D84, 0x63C6, 0x9D85, 0x63E3, 0x9D86, 0x63C9, 0x9D87, 0x63D2, 0x9D88, 0x63F6, + 0x9D89, 0x63C4, 0x9D8A, 0x6416, 0x9D8B, 0x6434, 0x9D8C, 0x6406, 0x9D8D, 0x6413, 0x9D8E, 0x6426, 0x9D8F, 0x6436, 0x9D90, 0x651D, + 0x9D91, 0x6417, 0x9D92, 0x6428, 0x9D93, 0x640F, 0x9D94, 0x6467, 0x9D95, 0x646F, 0x9D96, 0x6476, 0x9D97, 0x644E, 0x9D98, 0x652A, + 0x9D99, 0x6495, 0x9D9A, 0x6493, 0x9D9B, 0x64A5, 0x9D9C, 0x64A9, 0x9D9D, 0x6488, 0x9D9E, 0x64BC, 0x9D9F, 0x64DA, 0x9DA0, 0x64D2, + 0x9DA1, 0x64C5, 0x9DA2, 0x64C7, 0x9DA3, 0x64BB, 0x9DA4, 0x64D8, 0x9DA5, 0x64C2, 0x9DA6, 0x64F1, 0x9DA7, 0x64E7, 0x9DA8, 0x8209, + 0x9DA9, 0x64E0, 0x9DAA, 0x64E1, 0x9DAB, 0x62AC, 0x9DAC, 0x64E3, 0x9DAD, 0x64EF, 0x9DAE, 0x652C, 0x9DAF, 0x64F6, 0x9DB0, 0x64F4, + 0x9DB1, 0x64F2, 0x9DB2, 0x64FA, 0x9DB3, 0x6500, 0x9DB4, 0x64FD, 0x9DB5, 0x6518, 0x9DB6, 0x651C, 0x9DB7, 0x6505, 0x9DB8, 0x6524, + 0x9DB9, 0x6523, 0x9DBA, 0x652B, 0x9DBB, 0x6534, 0x9DBC, 0x6535, 0x9DBD, 0x6537, 0x9DBE, 0x6536, 0x9DBF, 0x6538, 0x9DC0, 0x754B, + 0x9DC1, 0x6548, 0x9DC2, 0x6556, 0x9DC3, 0x6555, 0x9DC4, 0x654D, 0x9DC5, 0x6558, 0x9DC6, 0x655E, 0x9DC7, 0x655D, 0x9DC8, 0x6572, + 0x9DC9, 0x6578, 0x9DCA, 0x6582, 0x9DCB, 0x6583, 0x9DCC, 0x8B8A, 0x9DCD, 0x659B, 0x9DCE, 0x659F, 0x9DCF, 0x65AB, 0x9DD0, 0x65B7, + 0x9DD1, 0x65C3, 0x9DD2, 0x65C6, 0x9DD3, 0x65C1, 0x9DD4, 0x65C4, 0x9DD5, 0x65CC, 0x9DD6, 0x65D2, 0x9DD7, 0x65DB, 0x9DD8, 0x65D9, + 0x9DD9, 0x65E0, 0x9DDA, 0x65E1, 0x9DDB, 0x65F1, 0x9DDC, 0x6772, 0x9DDD, 0x660A, 0x9DDE, 0x6603, 0x9DDF, 0x65FB, 0x9DE0, 0x6773, + 0x9DE1, 0x6635, 0x9DE2, 0x6636, 0x9DE3, 0x6634, 0x9DE4, 0x661C, 0x9DE5, 0x664F, 0x9DE6, 0x6644, 0x9DE7, 0x6649, 0x9DE8, 0x6641, + 0x9DE9, 0x665E, 0x9DEA, 0x665D, 0x9DEB, 0x6664, 0x9DEC, 0x6667, 0x9DED, 0x6668, 0x9DEE, 0x665F, 0x9DEF, 0x6662, 0x9DF0, 0x6670, + 0x9DF1, 0x6683, 0x9DF2, 0x6688, 0x9DF3, 0x668E, 0x9DF4, 0x6689, 0x9DF5, 0x6684, 0x9DF6, 0x6698, 0x9DF7, 0x669D, 0x9DF8, 0x66C1, + 0x9DF9, 0x66B9, 0x9DFA, 0x66C9, 0x9DFB, 0x66BE, 0x9DFC, 0x66BC, 0x9E40, 0x66C4, 0x9E41, 0x66B8, 0x9E42, 0x66D6, 0x9E43, 0x66DA, + 0x9E44, 0x66E0, 0x9E45, 0x663F, 0x9E46, 0x66E6, 0x9E47, 0x66E9, 0x9E48, 0x66F0, 0x9E49, 0x66F5, 0x9E4A, 0x66F7, 0x9E4B, 0x670F, + 0x9E4C, 0x6716, 0x9E4D, 0x671E, 0x9E4E, 0x6726, 0x9E4F, 0x6727, 0x9E50, 0x9738, 0x9E51, 0x672E, 0x9E52, 0x673F, 0x9E53, 0x6736, + 0x9E54, 0x6741, 0x9E55, 0x6738, 0x9E56, 0x6737, 0x9E57, 0x6746, 0x9E58, 0x675E, 0x9E59, 0x6760, 0x9E5A, 0x6759, 0x9E5B, 0x6763, + 0x9E5C, 0x6764, 0x9E5D, 0x6789, 0x9E5E, 0x6770, 0x9E5F, 0x67A9, 0x9E60, 0x677C, 0x9E61, 0x676A, 0x9E62, 0x678C, 0x9E63, 0x678B, + 0x9E64, 0x67A6, 0x9E65, 0x67A1, 0x9E66, 0x6785, 0x9E67, 0x67B7, 0x9E68, 0x67EF, 0x9E69, 0x67B4, 0x9E6A, 0x67EC, 0x9E6B, 0x67B3, + 0x9E6C, 0x67E9, 0x9E6D, 0x67B8, 0x9E6E, 0x67E4, 0x9E6F, 0x67DE, 0x9E70, 0x67DD, 0x9E71, 0x67E2, 0x9E72, 0x67EE, 0x9E73, 0x67B9, + 0x9E74, 0x67CE, 0x9E75, 0x67C6, 0x9E76, 0x67E7, 0x9E77, 0x6A9C, 0x9E78, 0x681E, 0x9E79, 0x6846, 0x9E7A, 0x6829, 0x9E7B, 0x6840, + 0x9E7C, 0x684D, 0x9E7D, 0x6832, 0x9E7E, 0x684E, 0x9E80, 0x68B3, 0x9E81, 0x682B, 0x9E82, 0x6859, 0x9E83, 0x6863, 0x9E84, 0x6877, + 0x9E85, 0x687F, 0x9E86, 0x689F, 0x9E87, 0x688F, 0x9E88, 0x68AD, 0x9E89, 0x6894, 0x9E8A, 0x689D, 0x9E8B, 0x689B, 0x9E8C, 0x6883, + 0x9E8D, 0x6AAE, 0x9E8E, 0x68B9, 0x9E8F, 0x6874, 0x9E90, 0x68B5, 0x9E91, 0x68A0, 0x9E92, 0x68BA, 0x9E93, 0x690F, 0x9E94, 0x688D, + 0x9E95, 0x687E, 0x9E96, 0x6901, 0x9E97, 0x68CA, 0x9E98, 0x6908, 0x9E99, 0x68D8, 0x9E9A, 0x6922, 0x9E9B, 0x6926, 0x9E9C, 0x68E1, + 0x9E9D, 0x690C, 0x9E9E, 0x68CD, 0x9E9F, 0x68D4, 0x9EA0, 0x68E7, 0x9EA1, 0x68D5, 0x9EA2, 0x6936, 0x9EA3, 0x6912, 0x9EA4, 0x6904, + 0x9EA5, 0x68D7, 0x9EA6, 0x68E3, 0x9EA7, 0x6925, 0x9EA8, 0x68F9, 0x9EA9, 0x68E0, 0x9EAA, 0x68EF, 0x9EAB, 0x6928, 0x9EAC, 0x692A, + 0x9EAD, 0x691A, 0x9EAE, 0x6923, 0x9EAF, 0x6921, 0x9EB0, 0x68C6, 0x9EB1, 0x6979, 0x9EB2, 0x6977, 0x9EB3, 0x695C, 0x9EB4, 0x6978, + 0x9EB5, 0x696B, 0x9EB6, 0x6954, 0x9EB7, 0x697E, 0x9EB8, 0x696E, 0x9EB9, 0x6939, 0x9EBA, 0x6974, 0x9EBB, 0x693D, 0x9EBC, 0x6959, + 0x9EBD, 0x6930, 0x9EBE, 0x6961, 0x9EBF, 0x695E, 0x9EC0, 0x695D, 0x9EC1, 0x6981, 0x9EC2, 0x696A, 0x9EC3, 0x69B2, 0x9EC4, 0x69AE, + 0x9EC5, 0x69D0, 0x9EC6, 0x69BF, 0x9EC7, 0x69C1, 0x9EC8, 0x69D3, 0x9EC9, 0x69BE, 0x9ECA, 0x69CE, 0x9ECB, 0x5BE8, 0x9ECC, 0x69CA, + 0x9ECD, 0x69DD, 0x9ECE, 0x69BB, 0x9ECF, 0x69C3, 0x9ED0, 0x69A7, 0x9ED1, 0x6A2E, 0x9ED2, 0x6991, 0x9ED3, 0x69A0, 0x9ED4, 0x699C, + 0x9ED5, 0x6995, 0x9ED6, 0x69B4, 0x9ED7, 0x69DE, 0x9ED8, 0x69E8, 0x9ED9, 0x6A02, 0x9EDA, 0x6A1B, 0x9EDB, 0x69FF, 0x9EDC, 0x6B0A, + 0x9EDD, 0x69F9, 0x9EDE, 0x69F2, 0x9EDF, 0x69E7, 0x9EE0, 0x6A05, 0x9EE1, 0x69B1, 0x9EE2, 0x6A1E, 0x9EE3, 0x69ED, 0x9EE4, 0x6A14, + 0x9EE5, 0x69EB, 0x9EE6, 0x6A0A, 0x9EE7, 0x6A12, 0x9EE8, 0x6AC1, 0x9EE9, 0x6A23, 0x9EEA, 0x6A13, 0x9EEB, 0x6A44, 0x9EEC, 0x6A0C, + 0x9EED, 0x6A72, 0x9EEE, 0x6A36, 0x9EEF, 0x6A78, 0x9EF0, 0x6A47, 0x9EF1, 0x6A62, 0x9EF2, 0x6A59, 0x9EF3, 0x6A66, 0x9EF4, 0x6A48, + 0x9EF5, 0x6A38, 0x9EF6, 0x6A22, 0x9EF7, 0x6A90, 0x9EF8, 0x6A8D, 0x9EF9, 0x6AA0, 0x9EFA, 0x6A84, 0x9EFB, 0x6AA2, 0x9EFC, 0x6AA3, + 0x9F40, 0x6A97, 0x9F41, 0x8617, 0x9F42, 0x6ABB, 0x9F43, 0x6AC3, 0x9F44, 0x6AC2, 0x9F45, 0x6AB8, 0x9F46, 0x6AB3, 0x9F47, 0x6AAC, + 0x9F48, 0x6ADE, 0x9F49, 0x6AD1, 0x9F4A, 0x6ADF, 0x9F4B, 0x6AAA, 0x9F4C, 0x6ADA, 0x9F4D, 0x6AEA, 0x9F4E, 0x6AFB, 0x9F4F, 0x6B05, + 0x9F50, 0x8616, 0x9F51, 0x6AFA, 0x9F52, 0x6B12, 0x9F53, 0x6B16, 0x9F54, 0x9B31, 0x9F55, 0x6B1F, 0x9F56, 0x6B38, 0x9F57, 0x6B37, + 0x9F58, 0x76DC, 0x9F59, 0x6B39, 0x9F5A, 0x98EE, 0x9F5B, 0x6B47, 0x9F5C, 0x6B43, 0x9F5D, 0x6B49, 0x9F5E, 0x6B50, 0x9F5F, 0x6B59, + 0x9F60, 0x6B54, 0x9F61, 0x6B5B, 0x9F62, 0x6B5F, 0x9F63, 0x6B61, 0x9F64, 0x6B78, 0x9F65, 0x6B79, 0x9F66, 0x6B7F, 0x9F67, 0x6B80, + 0x9F68, 0x6B84, 0x9F69, 0x6B83, 0x9F6A, 0x6B8D, 0x9F6B, 0x6B98, 0x9F6C, 0x6B95, 0x9F6D, 0x6B9E, 0x9F6E, 0x6BA4, 0x9F6F, 0x6BAA, + 0x9F70, 0x6BAB, 0x9F71, 0x6BAF, 0x9F72, 0x6BB2, 0x9F73, 0x6BB1, 0x9F74, 0x6BB3, 0x9F75, 0x6BB7, 0x9F76, 0x6BBC, 0x9F77, 0x6BC6, + 0x9F78, 0x6BCB, 0x9F79, 0x6BD3, 0x9F7A, 0x6BDF, 0x9F7B, 0x6BEC, 0x9F7C, 0x6BEB, 0x9F7D, 0x6BF3, 0x9F7E, 0x6BEF, 0x9F80, 0x9EBE, + 0x9F81, 0x6C08, 0x9F82, 0x6C13, 0x9F83, 0x6C14, 0x9F84, 0x6C1B, 0x9F85, 0x6C24, 0x9F86, 0x6C23, 0x9F87, 0x6C5E, 0x9F88, 0x6C55, + 0x9F89, 0x6C62, 0x9F8A, 0x6C6A, 0x9F8B, 0x6C82, 0x9F8C, 0x6C8D, 0x9F8D, 0x6C9A, 0x9F8E, 0x6C81, 0x9F8F, 0x6C9B, 0x9F90, 0x6C7E, + 0x9F91, 0x6C68, 0x9F92, 0x6C73, 0x9F93, 0x6C92, 0x9F94, 0x6C90, 0x9F95, 0x6CC4, 0x9F96, 0x6CF1, 0x9F97, 0x6CD3, 0x9F98, 0x6CBD, + 0x9F99, 0x6CD7, 0x9F9A, 0x6CC5, 0x9F9B, 0x6CDD, 0x9F9C, 0x6CAE, 0x9F9D, 0x6CB1, 0x9F9E, 0x6CBE, 0x9F9F, 0x6CBA, 0x9FA0, 0x6CDB, + 0x9FA1, 0x6CEF, 0x9FA2, 0x6CD9, 0x9FA3, 0x6CEA, 0x9FA4, 0x6D1F, 0x9FA5, 0x884D, 0x9FA6, 0x6D36, 0x9FA7, 0x6D2B, 0x9FA8, 0x6D3D, + 0x9FA9, 0x6D38, 0x9FAA, 0x6D19, 0x9FAB, 0x6D35, 0x9FAC, 0x6D33, 0x9FAD, 0x6D12, 0x9FAE, 0x6D0C, 0x9FAF, 0x6D63, 0x9FB0, 0x6D93, + 0x9FB1, 0x6D64, 0x9FB2, 0x6D5A, 0x9FB3, 0x6D79, 0x9FB4, 0x6D59, 0x9FB5, 0x6D8E, 0x9FB6, 0x6D95, 0x9FB7, 0x6FE4, 0x9FB8, 0x6D85, + 0x9FB9, 0x6DF9, 0x9FBA, 0x6E15, 0x9FBB, 0x6E0A, 0x9FBC, 0x6DB5, 0x9FBD, 0x6DC7, 0x9FBE, 0x6DE6, 0x9FBF, 0x6DB8, 0x9FC0, 0x6DC6, + 0x9FC1, 0x6DEC, 0x9FC2, 0x6DDE, 0x9FC3, 0x6DCC, 0x9FC4, 0x6DE8, 0x9FC5, 0x6DD2, 0x9FC6, 0x6DC5, 0x9FC7, 0x6DFA, 0x9FC8, 0x6DD9, + 0x9FC9, 0x6DE4, 0x9FCA, 0x6DD5, 0x9FCB, 0x6DEA, 0x9FCC, 0x6DEE, 0x9FCD, 0x6E2D, 0x9FCE, 0x6E6E, 0x9FCF, 0x6E2E, 0x9FD0, 0x6E19, + 0x9FD1, 0x6E72, 0x9FD2, 0x6E5F, 0x9FD3, 0x6E3E, 0x9FD4, 0x6E23, 0x9FD5, 0x6E6B, 0x9FD6, 0x6E2B, 0x9FD7, 0x6E76, 0x9FD8, 0x6E4D, + 0x9FD9, 0x6E1F, 0x9FDA, 0x6E43, 0x9FDB, 0x6E3A, 0x9FDC, 0x6E4E, 0x9FDD, 0x6E24, 0x9FDE, 0x6EFF, 0x9FDF, 0x6E1D, 0x9FE0, 0x6E38, + 0x9FE1, 0x6E82, 0x9FE2, 0x6EAA, 0x9FE3, 0x6E98, 0x9FE4, 0x6EC9, 0x9FE5, 0x6EB7, 0x9FE6, 0x6ED3, 0x9FE7, 0x6EBD, 0x9FE8, 0x6EAF, + 0x9FE9, 0x6EC4, 0x9FEA, 0x6EB2, 0x9FEB, 0x6ED4, 0x9FEC, 0x6ED5, 0x9FED, 0x6E8F, 0x9FEE, 0x6EA5, 0x9FEF, 0x6EC2, 0x9FF0, 0x6E9F, + 0x9FF1, 0x6F41, 0x9FF2, 0x6F11, 0x9FF3, 0x704C, 0x9FF4, 0x6EEC, 0x9FF5, 0x6EF8, 0x9FF6, 0x6EFE, 0x9FF7, 0x6F3F, 0x9FF8, 0x6EF2, + 0x9FF9, 0x6F31, 0x9FFA, 0x6EEF, 0x9FFB, 0x6F32, 0x9FFC, 0x6ECC, 0xE040, 0x6F3E, 0xE041, 0x6F13, 0xE042, 0x6EF7, 0xE043, 0x6F86, + 0xE044, 0x6F7A, 0xE045, 0x6F78, 0xE046, 0x6F81, 0xE047, 0x6F80, 0xE048, 0x6F6F, 0xE049, 0x6F5B, 0xE04A, 0x6FF3, 0xE04B, 0x6F6D, + 0xE04C, 0x6F82, 0xE04D, 0x6F7C, 0xE04E, 0x6F58, 0xE04F, 0x6F8E, 0xE050, 0x6F91, 0xE051, 0x6FC2, 0xE052, 0x6F66, 0xE053, 0x6FB3, + 0xE054, 0x6FA3, 0xE055, 0x6FA1, 0xE056, 0x6FA4, 0xE057, 0x6FB9, 0xE058, 0x6FC6, 0xE059, 0x6FAA, 0xE05A, 0x6FDF, 0xE05B, 0x6FD5, + 0xE05C, 0x6FEC, 0xE05D, 0x6FD4, 0xE05E, 0x6FD8, 0xE05F, 0x6FF1, 0xE060, 0x6FEE, 0xE061, 0x6FDB, 0xE062, 0x7009, 0xE063, 0x700B, + 0xE064, 0x6FFA, 0xE065, 0x7011, 0xE066, 0x7001, 0xE067, 0x700F, 0xE068, 0x6FFE, 0xE069, 0x701B, 0xE06A, 0x701A, 0xE06B, 0x6F74, + 0xE06C, 0x701D, 0xE06D, 0x7018, 0xE06E, 0x701F, 0xE06F, 0x7030, 0xE070, 0x703E, 0xE071, 0x7032, 0xE072, 0x7051, 0xE073, 0x7063, + 0xE074, 0x7099, 0xE075, 0x7092, 0xE076, 0x70AF, 0xE077, 0x70F1, 0xE078, 0x70AC, 0xE079, 0x70B8, 0xE07A, 0x70B3, 0xE07B, 0x70AE, + 0xE07C, 0x70DF, 0xE07D, 0x70CB, 0xE07E, 0x70DD, 0xE080, 0x70D9, 0xE081, 0x7109, 0xE082, 0x70FD, 0xE083, 0x711C, 0xE084, 0x7119, + 0xE085, 0x7165, 0xE086, 0x7155, 0xE087, 0x7188, 0xE088, 0x7166, 0xE089, 0x7162, 0xE08A, 0x714C, 0xE08B, 0x7156, 0xE08C, 0x716C, + 0xE08D, 0x718F, 0xE08E, 0x71FB, 0xE08F, 0x7184, 0xE090, 0x7195, 0xE091, 0x71A8, 0xE092, 0x71AC, 0xE093, 0x71D7, 0xE094, 0x71B9, + 0xE095, 0x71BE, 0xE096, 0x71D2, 0xE097, 0x71C9, 0xE098, 0x71D4, 0xE099, 0x71CE, 0xE09A, 0x71E0, 0xE09B, 0x71EC, 0xE09C, 0x71E7, + 0xE09D, 0x71F5, 0xE09E, 0x71FC, 0xE09F, 0x71F9, 0xE0A0, 0x71FF, 0xE0A1, 0x720D, 0xE0A2, 0x7210, 0xE0A3, 0x721B, 0xE0A4, 0x7228, + 0xE0A5, 0x722D, 0xE0A6, 0x722C, 0xE0A7, 0x7230, 0xE0A8, 0x7232, 0xE0A9, 0x723B, 0xE0AA, 0x723C, 0xE0AB, 0x723F, 0xE0AC, 0x7240, + 0xE0AD, 0x7246, 0xE0AE, 0x724B, 0xE0AF, 0x7258, 0xE0B0, 0x7274, 0xE0B1, 0x727E, 0xE0B2, 0x7282, 0xE0B3, 0x7281, 0xE0B4, 0x7287, + 0xE0B5, 0x7292, 0xE0B6, 0x7296, 0xE0B7, 0x72A2, 0xE0B8, 0x72A7, 0xE0B9, 0x72B9, 0xE0BA, 0x72B2, 0xE0BB, 0x72C3, 0xE0BC, 0x72C6, + 0xE0BD, 0x72C4, 0xE0BE, 0x72CE, 0xE0BF, 0x72D2, 0xE0C0, 0x72E2, 0xE0C1, 0x72E0, 0xE0C2, 0x72E1, 0xE0C3, 0x72F9, 0xE0C4, 0x72F7, + 0xE0C5, 0x500F, 0xE0C6, 0x7317, 0xE0C7, 0x730A, 0xE0C8, 0x731C, 0xE0C9, 0x7316, 0xE0CA, 0x731D, 0xE0CB, 0x7334, 0xE0CC, 0x732F, + 0xE0CD, 0x7329, 0xE0CE, 0x7325, 0xE0CF, 0x733E, 0xE0D0, 0x734E, 0xE0D1, 0x734F, 0xE0D2, 0x9ED8, 0xE0D3, 0x7357, 0xE0D4, 0x736A, + 0xE0D5, 0x7368, 0xE0D6, 0x7370, 0xE0D7, 0x7378, 0xE0D8, 0x7375, 0xE0D9, 0x737B, 0xE0DA, 0x737A, 0xE0DB, 0x73C8, 0xE0DC, 0x73B3, + 0xE0DD, 0x73CE, 0xE0DE, 0x73BB, 0xE0DF, 0x73C0, 0xE0E0, 0x73E5, 0xE0E1, 0x73EE, 0xE0E2, 0x73DE, 0xE0E3, 0x74A2, 0xE0E4, 0x7405, + 0xE0E5, 0x746F, 0xE0E6, 0x7425, 0xE0E7, 0x73F8, 0xE0E8, 0x7432, 0xE0E9, 0x743A, 0xE0EA, 0x7455, 0xE0EB, 0x743F, 0xE0EC, 0x745F, + 0xE0ED, 0x7459, 0xE0EE, 0x7441, 0xE0EF, 0x745C, 0xE0F0, 0x7469, 0xE0F1, 0x7470, 0xE0F2, 0x7463, 0xE0F3, 0x746A, 0xE0F4, 0x7476, + 0xE0F5, 0x747E, 0xE0F6, 0x748B, 0xE0F7, 0x749E, 0xE0F8, 0x74A7, 0xE0F9, 0x74CA, 0xE0FA, 0x74CF, 0xE0FB, 0x74D4, 0xE0FC, 0x73F1, + 0xE140, 0x74E0, 0xE141, 0x74E3, 0xE142, 0x74E7, 0xE143, 0x74E9, 0xE144, 0x74EE, 0xE145, 0x74F2, 0xE146, 0x74F0, 0xE147, 0x74F1, + 0xE148, 0x74F8, 0xE149, 0x74F7, 0xE14A, 0x7504, 0xE14B, 0x7503, 0xE14C, 0x7505, 0xE14D, 0x750C, 0xE14E, 0x750E, 0xE14F, 0x750D, + 0xE150, 0x7515, 0xE151, 0x7513, 0xE152, 0x751E, 0xE153, 0x7526, 0xE154, 0x752C, 0xE155, 0x753C, 0xE156, 0x7544, 0xE157, 0x754D, + 0xE158, 0x754A, 0xE159, 0x7549, 0xE15A, 0x755B, 0xE15B, 0x7546, 0xE15C, 0x755A, 0xE15D, 0x7569, 0xE15E, 0x7564, 0xE15F, 0x7567, + 0xE160, 0x756B, 0xE161, 0x756D, 0xE162, 0x7578, 0xE163, 0x7576, 0xE164, 0x7586, 0xE165, 0x7587, 0xE166, 0x7574, 0xE167, 0x758A, + 0xE168, 0x7589, 0xE169, 0x7582, 0xE16A, 0x7594, 0xE16B, 0x759A, 0xE16C, 0x759D, 0xE16D, 0x75A5, 0xE16E, 0x75A3, 0xE16F, 0x75C2, + 0xE170, 0x75B3, 0xE171, 0x75C3, 0xE172, 0x75B5, 0xE173, 0x75BD, 0xE174, 0x75B8, 0xE175, 0x75BC, 0xE176, 0x75B1, 0xE177, 0x75CD, + 0xE178, 0x75CA, 0xE179, 0x75D2, 0xE17A, 0x75D9, 0xE17B, 0x75E3, 0xE17C, 0x75DE, 0xE17D, 0x75FE, 0xE17E, 0x75FF, 0xE180, 0x75FC, + 0xE181, 0x7601, 0xE182, 0x75F0, 0xE183, 0x75FA, 0xE184, 0x75F2, 0xE185, 0x75F3, 0xE186, 0x760B, 0xE187, 0x760D, 0xE188, 0x7609, + 0xE189, 0x761F, 0xE18A, 0x7627, 0xE18B, 0x7620, 0xE18C, 0x7621, 0xE18D, 0x7622, 0xE18E, 0x7624, 0xE18F, 0x7634, 0xE190, 0x7630, + 0xE191, 0x763B, 0xE192, 0x7647, 0xE193, 0x7648, 0xE194, 0x7646, 0xE195, 0x765C, 0xE196, 0x7658, 0xE197, 0x7661, 0xE198, 0x7662, + 0xE199, 0x7668, 0xE19A, 0x7669, 0xE19B, 0x766A, 0xE19C, 0x7667, 0xE19D, 0x766C, 0xE19E, 0x7670, 0xE19F, 0x7672, 0xE1A0, 0x7676, + 0xE1A1, 0x7678, 0xE1A2, 0x767C, 0xE1A3, 0x7680, 0xE1A4, 0x7683, 0xE1A5, 0x7688, 0xE1A6, 0x768B, 0xE1A7, 0x768E, 0xE1A8, 0x7696, + 0xE1A9, 0x7693, 0xE1AA, 0x7699, 0xE1AB, 0x769A, 0xE1AC, 0x76B0, 0xE1AD, 0x76B4, 0xE1AE, 0x76B8, 0xE1AF, 0x76B9, 0xE1B0, 0x76BA, + 0xE1B1, 0x76C2, 0xE1B2, 0x76CD, 0xE1B3, 0x76D6, 0xE1B4, 0x76D2, 0xE1B5, 0x76DE, 0xE1B6, 0x76E1, 0xE1B7, 0x76E5, 0xE1B8, 0x76E7, + 0xE1B9, 0x76EA, 0xE1BA, 0x862F, 0xE1BB, 0x76FB, 0xE1BC, 0x7708, 0xE1BD, 0x7707, 0xE1BE, 0x7704, 0xE1BF, 0x7729, 0xE1C0, 0x7724, + 0xE1C1, 0x771E, 0xE1C2, 0x7725, 0xE1C3, 0x7726, 0xE1C4, 0x771B, 0xE1C5, 0x7737, 0xE1C6, 0x7738, 0xE1C7, 0x7747, 0xE1C8, 0x775A, + 0xE1C9, 0x7768, 0xE1CA, 0x776B, 0xE1CB, 0x775B, 0xE1CC, 0x7765, 0xE1CD, 0x777F, 0xE1CE, 0x777E, 0xE1CF, 0x7779, 0xE1D0, 0x778E, + 0xE1D1, 0x778B, 0xE1D2, 0x7791, 0xE1D3, 0x77A0, 0xE1D4, 0x779E, 0xE1D5, 0x77B0, 0xE1D6, 0x77B6, 0xE1D7, 0x77B9, 0xE1D8, 0x77BF, + 0xE1D9, 0x77BC, 0xE1DA, 0x77BD, 0xE1DB, 0x77BB, 0xE1DC, 0x77C7, 0xE1DD, 0x77CD, 0xE1DE, 0x77D7, 0xE1DF, 0x77DA, 0xE1E0, 0x77DC, + 0xE1E1, 0x77E3, 0xE1E2, 0x77EE, 0xE1E3, 0x77FC, 0xE1E4, 0x780C, 0xE1E5, 0x7812, 0xE1E6, 0x7926, 0xE1E7, 0x7820, 0xE1E8, 0x792A, + 0xE1E9, 0x7845, 0xE1EA, 0x788E, 0xE1EB, 0x7874, 0xE1EC, 0x7886, 0xE1ED, 0x787C, 0xE1EE, 0x789A, 0xE1EF, 0x788C, 0xE1F0, 0x78A3, + 0xE1F1, 0x78B5, 0xE1F2, 0x78AA, 0xE1F3, 0x78AF, 0xE1F4, 0x78D1, 0xE1F5, 0x78C6, 0xE1F6, 0x78CB, 0xE1F7, 0x78D4, 0xE1F8, 0x78BE, + 0xE1F9, 0x78BC, 0xE1FA, 0x78C5, 0xE1FB, 0x78CA, 0xE1FC, 0x78EC, 0xE240, 0x78E7, 0xE241, 0x78DA, 0xE242, 0x78FD, 0xE243, 0x78F4, + 0xE244, 0x7907, 0xE245, 0x7912, 0xE246, 0x7911, 0xE247, 0x7919, 0xE248, 0x792C, 0xE249, 0x792B, 0xE24A, 0x7940, 0xE24B, 0x7960, + 0xE24C, 0x7957, 0xE24D, 0x795F, 0xE24E, 0x795A, 0xE24F, 0x7955, 0xE250, 0x7953, 0xE251, 0x797A, 0xE252, 0x797F, 0xE253, 0x798A, + 0xE254, 0x799D, 0xE255, 0x79A7, 0xE256, 0x9F4B, 0xE257, 0x79AA, 0xE258, 0x79AE, 0xE259, 0x79B3, 0xE25A, 0x79B9, 0xE25B, 0x79BA, + 0xE25C, 0x79C9, 0xE25D, 0x79D5, 0xE25E, 0x79E7, 0xE25F, 0x79EC, 0xE260, 0x79E1, 0xE261, 0x79E3, 0xE262, 0x7A08, 0xE263, 0x7A0D, + 0xE264, 0x7A18, 0xE265, 0x7A19, 0xE266, 0x7A20, 0xE267, 0x7A1F, 0xE268, 0x7980, 0xE269, 0x7A31, 0xE26A, 0x7A3B, 0xE26B, 0x7A3E, + 0xE26C, 0x7A37, 0xE26D, 0x7A43, 0xE26E, 0x7A57, 0xE26F, 0x7A49, 0xE270, 0x7A61, 0xE271, 0x7A62, 0xE272, 0x7A69, 0xE273, 0x9F9D, + 0xE274, 0x7A70, 0xE275, 0x7A79, 0xE276, 0x7A7D, 0xE277, 0x7A88, 0xE278, 0x7A97, 0xE279, 0x7A95, 0xE27A, 0x7A98, 0xE27B, 0x7A96, + 0xE27C, 0x7AA9, 0xE27D, 0x7AC8, 0xE27E, 0x7AB0, 0xE280, 0x7AB6, 0xE281, 0x7AC5, 0xE282, 0x7AC4, 0xE283, 0x7ABF, 0xE284, 0x9083, + 0xE285, 0x7AC7, 0xE286, 0x7ACA, 0xE287, 0x7ACD, 0xE288, 0x7ACF, 0xE289, 0x7AD5, 0xE28A, 0x7AD3, 0xE28B, 0x7AD9, 0xE28C, 0x7ADA, + 0xE28D, 0x7ADD, 0xE28E, 0x7AE1, 0xE28F, 0x7AE2, 0xE290, 0x7AE6, 0xE291, 0x7AED, 0xE292, 0x7AF0, 0xE293, 0x7B02, 0xE294, 0x7B0F, + 0xE295, 0x7B0A, 0xE296, 0x7B06, 0xE297, 0x7B33, 0xE298, 0x7B18, 0xE299, 0x7B19, 0xE29A, 0x7B1E, 0xE29B, 0x7B35, 0xE29C, 0x7B28, + 0xE29D, 0x7B36, 0xE29E, 0x7B50, 0xE29F, 0x7B7A, 0xE2A0, 0x7B04, 0xE2A1, 0x7B4D, 0xE2A2, 0x7B0B, 0xE2A3, 0x7B4C, 0xE2A4, 0x7B45, + 0xE2A5, 0x7B75, 0xE2A6, 0x7B65, 0xE2A7, 0x7B74, 0xE2A8, 0x7B67, 0xE2A9, 0x7B70, 0xE2AA, 0x7B71, 0xE2AB, 0x7B6C, 0xE2AC, 0x7B6E, + 0xE2AD, 0x7B9D, 0xE2AE, 0x7B98, 0xE2AF, 0x7B9F, 0xE2B0, 0x7B8D, 0xE2B1, 0x7B9C, 0xE2B2, 0x7B9A, 0xE2B3, 0x7B8B, 0xE2B4, 0x7B92, + 0xE2B5, 0x7B8F, 0xE2B6, 0x7B5D, 0xE2B7, 0x7B99, 0xE2B8, 0x7BCB, 0xE2B9, 0x7BC1, 0xE2BA, 0x7BCC, 0xE2BB, 0x7BCF, 0xE2BC, 0x7BB4, + 0xE2BD, 0x7BC6, 0xE2BE, 0x7BDD, 0xE2BF, 0x7BE9, 0xE2C0, 0x7C11, 0xE2C1, 0x7C14, 0xE2C2, 0x7BE6, 0xE2C3, 0x7BE5, 0xE2C4, 0x7C60, + 0xE2C5, 0x7C00, 0xE2C6, 0x7C07, 0xE2C7, 0x7C13, 0xE2C8, 0x7BF3, 0xE2C9, 0x7BF7, 0xE2CA, 0x7C17, 0xE2CB, 0x7C0D, 0xE2CC, 0x7BF6, + 0xE2CD, 0x7C23, 0xE2CE, 0x7C27, 0xE2CF, 0x7C2A, 0xE2D0, 0x7C1F, 0xE2D1, 0x7C37, 0xE2D2, 0x7C2B, 0xE2D3, 0x7C3D, 0xE2D4, 0x7C4C, + 0xE2D5, 0x7C43, 0xE2D6, 0x7C54, 0xE2D7, 0x7C4F, 0xE2D8, 0x7C40, 0xE2D9, 0x7C50, 0xE2DA, 0x7C58, 0xE2DB, 0x7C5F, 0xE2DC, 0x7C64, + 0xE2DD, 0x7C56, 0xE2DE, 0x7C65, 0xE2DF, 0x7C6C, 0xE2E0, 0x7C75, 0xE2E1, 0x7C83, 0xE2E2, 0x7C90, 0xE2E3, 0x7CA4, 0xE2E4, 0x7CAD, + 0xE2E5, 0x7CA2, 0xE2E6, 0x7CAB, 0xE2E7, 0x7CA1, 0xE2E8, 0x7CA8, 0xE2E9, 0x7CB3, 0xE2EA, 0x7CB2, 0xE2EB, 0x7CB1, 0xE2EC, 0x7CAE, + 0xE2ED, 0x7CB9, 0xE2EE, 0x7CBD, 0xE2EF, 0x7CC0, 0xE2F0, 0x7CC5, 0xE2F1, 0x7CC2, 0xE2F2, 0x7CD8, 0xE2F3, 0x7CD2, 0xE2F4, 0x7CDC, + 0xE2F5, 0x7CE2, 0xE2F6, 0x9B3B, 0xE2F7, 0x7CEF, 0xE2F8, 0x7CF2, 0xE2F9, 0x7CF4, 0xE2FA, 0x7CF6, 0xE2FB, 0x7CFA, 0xE2FC, 0x7D06, + 0xE340, 0x7D02, 0xE341, 0x7D1C, 0xE342, 0x7D15, 0xE343, 0x7D0A, 0xE344, 0x7D45, 0xE345, 0x7D4B, 0xE346, 0x7D2E, 0xE347, 0x7D32, + 0xE348, 0x7D3F, 0xE349, 0x7D35, 0xE34A, 0x7D46, 0xE34B, 0x7D73, 0xE34C, 0x7D56, 0xE34D, 0x7D4E, 0xE34E, 0x7D72, 0xE34F, 0x7D68, + 0xE350, 0x7D6E, 0xE351, 0x7D4F, 0xE352, 0x7D63, 0xE353, 0x7D93, 0xE354, 0x7D89, 0xE355, 0x7D5B, 0xE356, 0x7D8F, 0xE357, 0x7D7D, + 0xE358, 0x7D9B, 0xE359, 0x7DBA, 0xE35A, 0x7DAE, 0xE35B, 0x7DA3, 0xE35C, 0x7DB5, 0xE35D, 0x7DC7, 0xE35E, 0x7DBD, 0xE35F, 0x7DAB, + 0xE360, 0x7E3D, 0xE361, 0x7DA2, 0xE362, 0x7DAF, 0xE363, 0x7DDC, 0xE364, 0x7DB8, 0xE365, 0x7D9F, 0xE366, 0x7DB0, 0xE367, 0x7DD8, + 0xE368, 0x7DDD, 0xE369, 0x7DE4, 0xE36A, 0x7DDE, 0xE36B, 0x7DFB, 0xE36C, 0x7DF2, 0xE36D, 0x7DE1, 0xE36E, 0x7E05, 0xE36F, 0x7E0A, + 0xE370, 0x7E23, 0xE371, 0x7E21, 0xE372, 0x7E12, 0xE373, 0x7E31, 0xE374, 0x7E1F, 0xE375, 0x7E09, 0xE376, 0x7E0B, 0xE377, 0x7E22, + 0xE378, 0x7E46, 0xE379, 0x7E66, 0xE37A, 0x7E3B, 0xE37B, 0x7E35, 0xE37C, 0x7E39, 0xE37D, 0x7E43, 0xE37E, 0x7E37, 0xE380, 0x7E32, + 0xE381, 0x7E3A, 0xE382, 0x7E67, 0xE383, 0x7E5D, 0xE384, 0x7E56, 0xE385, 0x7E5E, 0xE386, 0x7E59, 0xE387, 0x7E5A, 0xE388, 0x7E79, + 0xE389, 0x7E6A, 0xE38A, 0x7E69, 0xE38B, 0x7E7C, 0xE38C, 0x7E7B, 0xE38D, 0x7E83, 0xE38E, 0x7DD5, 0xE38F, 0x7E7D, 0xE390, 0x8FAE, + 0xE391, 0x7E7F, 0xE392, 0x7E88, 0xE393, 0x7E89, 0xE394, 0x7E8C, 0xE395, 0x7E92, 0xE396, 0x7E90, 0xE397, 0x7E93, 0xE398, 0x7E94, + 0xE399, 0x7E96, 0xE39A, 0x7E8E, 0xE39B, 0x7E9B, 0xE39C, 0x7E9C, 0xE39D, 0x7F38, 0xE39E, 0x7F3A, 0xE39F, 0x7F45, 0xE3A0, 0x7F4C, + 0xE3A1, 0x7F4D, 0xE3A2, 0x7F4E, 0xE3A3, 0x7F50, 0xE3A4, 0x7F51, 0xE3A5, 0x7F55, 0xE3A6, 0x7F54, 0xE3A7, 0x7F58, 0xE3A8, 0x7F5F, + 0xE3A9, 0x7F60, 0xE3AA, 0x7F68, 0xE3AB, 0x7F69, 0xE3AC, 0x7F67, 0xE3AD, 0x7F78, 0xE3AE, 0x7F82, 0xE3AF, 0x7F86, 0xE3B0, 0x7F83, + 0xE3B1, 0x7F88, 0xE3B2, 0x7F87, 0xE3B3, 0x7F8C, 0xE3B4, 0x7F94, 0xE3B5, 0x7F9E, 0xE3B6, 0x7F9D, 0xE3B7, 0x7F9A, 0xE3B8, 0x7FA3, + 0xE3B9, 0x7FAF, 0xE3BA, 0x7FB2, 0xE3BB, 0x7FB9, 0xE3BC, 0x7FAE, 0xE3BD, 0x7FB6, 0xE3BE, 0x7FB8, 0xE3BF, 0x8B71, 0xE3C0, 0x7FC5, + 0xE3C1, 0x7FC6, 0xE3C2, 0x7FCA, 0xE3C3, 0x7FD5, 0xE3C4, 0x7FD4, 0xE3C5, 0x7FE1, 0xE3C6, 0x7FE6, 0xE3C7, 0x7FE9, 0xE3C8, 0x7FF3, + 0xE3C9, 0x7FF9, 0xE3CA, 0x98DC, 0xE3CB, 0x8006, 0xE3CC, 0x8004, 0xE3CD, 0x800B, 0xE3CE, 0x8012, 0xE3CF, 0x8018, 0xE3D0, 0x8019, + 0xE3D1, 0x801C, 0xE3D2, 0x8021, 0xE3D3, 0x8028, 0xE3D4, 0x803F, 0xE3D5, 0x803B, 0xE3D6, 0x804A, 0xE3D7, 0x8046, 0xE3D8, 0x8052, + 0xE3D9, 0x8058, 0xE3DA, 0x805A, 0xE3DB, 0x805F, 0xE3DC, 0x8062, 0xE3DD, 0x8068, 0xE3DE, 0x8073, 0xE3DF, 0x8072, 0xE3E0, 0x8070, + 0xE3E1, 0x8076, 0xE3E2, 0x8079, 0xE3E3, 0x807D, 0xE3E4, 0x807F, 0xE3E5, 0x8084, 0xE3E6, 0x8086, 0xE3E7, 0x8085, 0xE3E8, 0x809B, + 0xE3E9, 0x8093, 0xE3EA, 0x809A, 0xE3EB, 0x80AD, 0xE3EC, 0x5190, 0xE3ED, 0x80AC, 0xE3EE, 0x80DB, 0xE3EF, 0x80E5, 0xE3F0, 0x80D9, + 0xE3F1, 0x80DD, 0xE3F2, 0x80C4, 0xE3F3, 0x80DA, 0xE3F4, 0x80D6, 0xE3F5, 0x8109, 0xE3F6, 0x80EF, 0xE3F7, 0x80F1, 0xE3F8, 0x811B, + 0xE3F9, 0x8129, 0xE3FA, 0x8123, 0xE3FB, 0x812F, 0xE3FC, 0x814B, 0xE440, 0x968B, 0xE441, 0x8146, 0xE442, 0x813E, 0xE443, 0x8153, + 0xE444, 0x8151, 0xE445, 0x80FC, 0xE446, 0x8171, 0xE447, 0x816E, 0xE448, 0x8165, 0xE449, 0x8166, 0xE44A, 0x8174, 0xE44B, 0x8183, + 0xE44C, 0x8188, 0xE44D, 0x818A, 0xE44E, 0x8180, 0xE44F, 0x8182, 0xE450, 0x81A0, 0xE451, 0x8195, 0xE452, 0x81A4, 0xE453, 0x81A3, + 0xE454, 0x815F, 0xE455, 0x8193, 0xE456, 0x81A9, 0xE457, 0x81B0, 0xE458, 0x81B5, 0xE459, 0x81BE, 0xE45A, 0x81B8, 0xE45B, 0x81BD, + 0xE45C, 0x81C0, 0xE45D, 0x81C2, 0xE45E, 0x81BA, 0xE45F, 0x81C9, 0xE460, 0x81CD, 0xE461, 0x81D1, 0xE462, 0x81D9, 0xE463, 0x81D8, + 0xE464, 0x81C8, 0xE465, 0x81DA, 0xE466, 0x81DF, 0xE467, 0x81E0, 0xE468, 0x81E7, 0xE469, 0x81FA, 0xE46A, 0x81FB, 0xE46B, 0x81FE, + 0xE46C, 0x8201, 0xE46D, 0x8202, 0xE46E, 0x8205, 0xE46F, 0x8207, 0xE470, 0x820A, 0xE471, 0x820D, 0xE472, 0x8210, 0xE473, 0x8216, + 0xE474, 0x8229, 0xE475, 0x822B, 0xE476, 0x8238, 0xE477, 0x8233, 0xE478, 0x8240, 0xE479, 0x8259, 0xE47A, 0x8258, 0xE47B, 0x825D, + 0xE47C, 0x825A, 0xE47D, 0x825F, 0xE47E, 0x8264, 0xE480, 0x8262, 0xE481, 0x8268, 0xE482, 0x826A, 0xE483, 0x826B, 0xE484, 0x822E, + 0xE485, 0x8271, 0xE486, 0x8277, 0xE487, 0x8278, 0xE488, 0x827E, 0xE489, 0x828D, 0xE48A, 0x8292, 0xE48B, 0x82AB, 0xE48C, 0x829F, + 0xE48D, 0x82BB, 0xE48E, 0x82AC, 0xE48F, 0x82E1, 0xE490, 0x82E3, 0xE491, 0x82DF, 0xE492, 0x82D2, 0xE493, 0x82F4, 0xE494, 0x82F3, + 0xE495, 0x82FA, 0xE496, 0x8393, 0xE497, 0x8303, 0xE498, 0x82FB, 0xE499, 0x82F9, 0xE49A, 0x82DE, 0xE49B, 0x8306, 0xE49C, 0x82DC, + 0xE49D, 0x8309, 0xE49E, 0x82D9, 0xE49F, 0x8335, 0xE4A0, 0x8334, 0xE4A1, 0x8316, 0xE4A2, 0x8332, 0xE4A3, 0x8331, 0xE4A4, 0x8340, + 0xE4A5, 0x8339, 0xE4A6, 0x8350, 0xE4A7, 0x8345, 0xE4A8, 0x832F, 0xE4A9, 0x832B, 0xE4AA, 0x8317, 0xE4AB, 0x8318, 0xE4AC, 0x8385, + 0xE4AD, 0x839A, 0xE4AE, 0x83AA, 0xE4AF, 0x839F, 0xE4B0, 0x83A2, 0xE4B1, 0x8396, 0xE4B2, 0x8323, 0xE4B3, 0x838E, 0xE4B4, 0x8387, + 0xE4B5, 0x838A, 0xE4B6, 0x837C, 0xE4B7, 0x83B5, 0xE4B8, 0x8373, 0xE4B9, 0x8375, 0xE4BA, 0x83A0, 0xE4BB, 0x8389, 0xE4BC, 0x83A8, + 0xE4BD, 0x83F4, 0xE4BE, 0x8413, 0xE4BF, 0x83EB, 0xE4C0, 0x83CE, 0xE4C1, 0x83FD, 0xE4C2, 0x8403, 0xE4C3, 0x83D8, 0xE4C4, 0x840B, + 0xE4C5, 0x83C1, 0xE4C6, 0x83F7, 0xE4C7, 0x8407, 0xE4C8, 0x83E0, 0xE4C9, 0x83F2, 0xE4CA, 0x840D, 0xE4CB, 0x8422, 0xE4CC, 0x8420, + 0xE4CD, 0x83BD, 0xE4CE, 0x8438, 0xE4CF, 0x8506, 0xE4D0, 0x83FB, 0xE4D1, 0x846D, 0xE4D2, 0x842A, 0xE4D3, 0x843C, 0xE4D4, 0x855A, + 0xE4D5, 0x8484, 0xE4D6, 0x8477, 0xE4D7, 0x846B, 0xE4D8, 0x84AD, 0xE4D9, 0x846E, 0xE4DA, 0x8482, 0xE4DB, 0x8469, 0xE4DC, 0x8446, + 0xE4DD, 0x842C, 0xE4DE, 0x846F, 0xE4DF, 0x8479, 0xE4E0, 0x8435, 0xE4E1, 0x84CA, 0xE4E2, 0x8462, 0xE4E3, 0x84B9, 0xE4E4, 0x84BF, + 0xE4E5, 0x849F, 0xE4E6, 0x84D9, 0xE4E7, 0x84CD, 0xE4E8, 0x84BB, 0xE4E9, 0x84DA, 0xE4EA, 0x84D0, 0xE4EB, 0x84C1, 0xE4EC, 0x84C6, + 0xE4ED, 0x84D6, 0xE4EE, 0x84A1, 0xE4EF, 0x8521, 0xE4F0, 0x84FF, 0xE4F1, 0x84F4, 0xE4F2, 0x8517, 0xE4F3, 0x8518, 0xE4F4, 0x852C, + 0xE4F5, 0x851F, 0xE4F6, 0x8515, 0xE4F7, 0x8514, 0xE4F8, 0x84FC, 0xE4F9, 0x8540, 0xE4FA, 0x8563, 0xE4FB, 0x8558, 0xE4FC, 0x8548, + 0xE540, 0x8541, 0xE541, 0x8602, 0xE542, 0x854B, 0xE543, 0x8555, 0xE544, 0x8580, 0xE545, 0x85A4, 0xE546, 0x8588, 0xE547, 0x8591, + 0xE548, 0x858A, 0xE549, 0x85A8, 0xE54A, 0x856D, 0xE54B, 0x8594, 0xE54C, 0x859B, 0xE54D, 0x85EA, 0xE54E, 0x8587, 0xE54F, 0x859C, + 0xE550, 0x8577, 0xE551, 0x857E, 0xE552, 0x8590, 0xE553, 0x85C9, 0xE554, 0x85BA, 0xE555, 0x85CF, 0xE556, 0x85B9, 0xE557, 0x85D0, + 0xE558, 0x85D5, 0xE559, 0x85DD, 0xE55A, 0x85E5, 0xE55B, 0x85DC, 0xE55C, 0x85F9, 0xE55D, 0x860A, 0xE55E, 0x8613, 0xE55F, 0x860B, + 0xE560, 0x85FE, 0xE561, 0x85FA, 0xE562, 0x8606, 0xE563, 0x8622, 0xE564, 0x861A, 0xE565, 0x8630, 0xE566, 0x863F, 0xE567, 0x864D, + 0xE568, 0x4E55, 0xE569, 0x8654, 0xE56A, 0x865F, 0xE56B, 0x8667, 0xE56C, 0x8671, 0xE56D, 0x8693, 0xE56E, 0x86A3, 0xE56F, 0x86A9, + 0xE570, 0x86AA, 0xE571, 0x868B, 0xE572, 0x868C, 0xE573, 0x86B6, 0xE574, 0x86AF, 0xE575, 0x86C4, 0xE576, 0x86C6, 0xE577, 0x86B0, + 0xE578, 0x86C9, 0xE579, 0x8823, 0xE57A, 0x86AB, 0xE57B, 0x86D4, 0xE57C, 0x86DE, 0xE57D, 0x86E9, 0xE57E, 0x86EC, 0xE580, 0x86DF, + 0xE581, 0x86DB, 0xE582, 0x86EF, 0xE583, 0x8712, 0xE584, 0x8706, 0xE585, 0x8708, 0xE586, 0x8700, 0xE587, 0x8703, 0xE588, 0x86FB, + 0xE589, 0x8711, 0xE58A, 0x8709, 0xE58B, 0x870D, 0xE58C, 0x86F9, 0xE58D, 0x870A, 0xE58E, 0x8734, 0xE58F, 0x873F, 0xE590, 0x8737, + 0xE591, 0x873B, 0xE592, 0x8725, 0xE593, 0x8729, 0xE594, 0x871A, 0xE595, 0x8760, 0xE596, 0x875F, 0xE597, 0x8778, 0xE598, 0x874C, + 0xE599, 0x874E, 0xE59A, 0x8774, 0xE59B, 0x8757, 0xE59C, 0x8768, 0xE59D, 0x876E, 0xE59E, 0x8759, 0xE59F, 0x8753, 0xE5A0, 0x8763, + 0xE5A1, 0x876A, 0xE5A2, 0x8805, 0xE5A3, 0x87A2, 0xE5A4, 0x879F, 0xE5A5, 0x8782, 0xE5A6, 0x87AF, 0xE5A7, 0x87CB, 0xE5A8, 0x87BD, + 0xE5A9, 0x87C0, 0xE5AA, 0x87D0, 0xE5AB, 0x96D6, 0xE5AC, 0x87AB, 0xE5AD, 0x87C4, 0xE5AE, 0x87B3, 0xE5AF, 0x87C7, 0xE5B0, 0x87C6, + 0xE5B1, 0x87BB, 0xE5B2, 0x87EF, 0xE5B3, 0x87F2, 0xE5B4, 0x87E0, 0xE5B5, 0x880F, 0xE5B6, 0x880D, 0xE5B7, 0x87FE, 0xE5B8, 0x87F6, + 0xE5B9, 0x87F7, 0xE5BA, 0x880E, 0xE5BB, 0x87D2, 0xE5BC, 0x8811, 0xE5BD, 0x8816, 0xE5BE, 0x8815, 0xE5BF, 0x8822, 0xE5C0, 0x8821, + 0xE5C1, 0x8831, 0xE5C2, 0x8836, 0xE5C3, 0x8839, 0xE5C4, 0x8827, 0xE5C5, 0x883B, 0xE5C6, 0x8844, 0xE5C7, 0x8842, 0xE5C8, 0x8852, + 0xE5C9, 0x8859, 0xE5CA, 0x885E, 0xE5CB, 0x8862, 0xE5CC, 0x886B, 0xE5CD, 0x8881, 0xE5CE, 0x887E, 0xE5CF, 0x889E, 0xE5D0, 0x8875, + 0xE5D1, 0x887D, 0xE5D2, 0x88B5, 0xE5D3, 0x8872, 0xE5D4, 0x8882, 0xE5D5, 0x8897, 0xE5D6, 0x8892, 0xE5D7, 0x88AE, 0xE5D8, 0x8899, + 0xE5D9, 0x88A2, 0xE5DA, 0x888D, 0xE5DB, 0x88A4, 0xE5DC, 0x88B0, 0xE5DD, 0x88BF, 0xE5DE, 0x88B1, 0xE5DF, 0x88C3, 0xE5E0, 0x88C4, + 0xE5E1, 0x88D4, 0xE5E2, 0x88D8, 0xE5E3, 0x88D9, 0xE5E4, 0x88DD, 0xE5E5, 0x88F9, 0xE5E6, 0x8902, 0xE5E7, 0x88FC, 0xE5E8, 0x88F4, + 0xE5E9, 0x88E8, 0xE5EA, 0x88F2, 0xE5EB, 0x8904, 0xE5EC, 0x890C, 0xE5ED, 0x890A, 0xE5EE, 0x8913, 0xE5EF, 0x8943, 0xE5F0, 0x891E, + 0xE5F1, 0x8925, 0xE5F2, 0x892A, 0xE5F3, 0x892B, 0xE5F4, 0x8941, 0xE5F5, 0x8944, 0xE5F6, 0x893B, 0xE5F7, 0x8936, 0xE5F8, 0x8938, + 0xE5F9, 0x894C, 0xE5FA, 0x891D, 0xE5FB, 0x8960, 0xE5FC, 0x895E, 0xE640, 0x8966, 0xE641, 0x8964, 0xE642, 0x896D, 0xE643, 0x896A, + 0xE644, 0x896F, 0xE645, 0x8974, 0xE646, 0x8977, 0xE647, 0x897E, 0xE648, 0x8983, 0xE649, 0x8988, 0xE64A, 0x898A, 0xE64B, 0x8993, + 0xE64C, 0x8998, 0xE64D, 0x89A1, 0xE64E, 0x89A9, 0xE64F, 0x89A6, 0xE650, 0x89AC, 0xE651, 0x89AF, 0xE652, 0x89B2, 0xE653, 0x89BA, + 0xE654, 0x89BD, 0xE655, 0x89BF, 0xE656, 0x89C0, 0xE657, 0x89DA, 0xE658, 0x89DC, 0xE659, 0x89DD, 0xE65A, 0x89E7, 0xE65B, 0x89F4, + 0xE65C, 0x89F8, 0xE65D, 0x8A03, 0xE65E, 0x8A16, 0xE65F, 0x8A10, 0xE660, 0x8A0C, 0xE661, 0x8A1B, 0xE662, 0x8A1D, 0xE663, 0x8A25, + 0xE664, 0x8A36, 0xE665, 0x8A41, 0xE666, 0x8A5B, 0xE667, 0x8A52, 0xE668, 0x8A46, 0xE669, 0x8A48, 0xE66A, 0x8A7C, 0xE66B, 0x8A6D, + 0xE66C, 0x8A6C, 0xE66D, 0x8A62, 0xE66E, 0x8A85, 0xE66F, 0x8A82, 0xE670, 0x8A84, 0xE671, 0x8AA8, 0xE672, 0x8AA1, 0xE673, 0x8A91, + 0xE674, 0x8AA5, 0xE675, 0x8AA6, 0xE676, 0x8A9A, 0xE677, 0x8AA3, 0xE678, 0x8AC4, 0xE679, 0x8ACD, 0xE67A, 0x8AC2, 0xE67B, 0x8ADA, + 0xE67C, 0x8AEB, 0xE67D, 0x8AF3, 0xE67E, 0x8AE7, 0xE680, 0x8AE4, 0xE681, 0x8AF1, 0xE682, 0x8B14, 0xE683, 0x8AE0, 0xE684, 0x8AE2, + 0xE685, 0x8AF7, 0xE686, 0x8ADE, 0xE687, 0x8ADB, 0xE688, 0x8B0C, 0xE689, 0x8B07, 0xE68A, 0x8B1A, 0xE68B, 0x8AE1, 0xE68C, 0x8B16, + 0xE68D, 0x8B10, 0xE68E, 0x8B17, 0xE68F, 0x8B20, 0xE690, 0x8B33, 0xE691, 0x97AB, 0xE692, 0x8B26, 0xE693, 0x8B2B, 0xE694, 0x8B3E, + 0xE695, 0x8B28, 0xE696, 0x8B41, 0xE697, 0x8B4C, 0xE698, 0x8B4F, 0xE699, 0x8B4E, 0xE69A, 0x8B49, 0xE69B, 0x8B56, 0xE69C, 0x8B5B, + 0xE69D, 0x8B5A, 0xE69E, 0x8B6B, 0xE69F, 0x8B5F, 0xE6A0, 0x8B6C, 0xE6A1, 0x8B6F, 0xE6A2, 0x8B74, 0xE6A3, 0x8B7D, 0xE6A4, 0x8B80, + 0xE6A5, 0x8B8C, 0xE6A6, 0x8B8E, 0xE6A7, 0x8B92, 0xE6A8, 0x8B93, 0xE6A9, 0x8B96, 0xE6AA, 0x8B99, 0xE6AB, 0x8B9A, 0xE6AC, 0x8C3A, + 0xE6AD, 0x8C41, 0xE6AE, 0x8C3F, 0xE6AF, 0x8C48, 0xE6B0, 0x8C4C, 0xE6B1, 0x8C4E, 0xE6B2, 0x8C50, 0xE6B3, 0x8C55, 0xE6B4, 0x8C62, + 0xE6B5, 0x8C6C, 0xE6B6, 0x8C78, 0xE6B7, 0x8C7A, 0xE6B8, 0x8C82, 0xE6B9, 0x8C89, 0xE6BA, 0x8C85, 0xE6BB, 0x8C8A, 0xE6BC, 0x8C8D, + 0xE6BD, 0x8C8E, 0xE6BE, 0x8C94, 0xE6BF, 0x8C7C, 0xE6C0, 0x8C98, 0xE6C1, 0x621D, 0xE6C2, 0x8CAD, 0xE6C3, 0x8CAA, 0xE6C4, 0x8CBD, + 0xE6C5, 0x8CB2, 0xE6C6, 0x8CB3, 0xE6C7, 0x8CAE, 0xE6C8, 0x8CB6, 0xE6C9, 0x8CC8, 0xE6CA, 0x8CC1, 0xE6CB, 0x8CE4, 0xE6CC, 0x8CE3, + 0xE6CD, 0x8CDA, 0xE6CE, 0x8CFD, 0xE6CF, 0x8CFA, 0xE6D0, 0x8CFB, 0xE6D1, 0x8D04, 0xE6D2, 0x8D05, 0xE6D3, 0x8D0A, 0xE6D4, 0x8D07, + 0xE6D5, 0x8D0F, 0xE6D6, 0x8D0D, 0xE6D7, 0x8D10, 0xE6D8, 0x9F4E, 0xE6D9, 0x8D13, 0xE6DA, 0x8CCD, 0xE6DB, 0x8D14, 0xE6DC, 0x8D16, + 0xE6DD, 0x8D67, 0xE6DE, 0x8D6D, 0xE6DF, 0x8D71, 0xE6E0, 0x8D73, 0xE6E1, 0x8D81, 0xE6E2, 0x8D99, 0xE6E3, 0x8DC2, 0xE6E4, 0x8DBE, + 0xE6E5, 0x8DBA, 0xE6E6, 0x8DCF, 0xE6E7, 0x8DDA, 0xE6E8, 0x8DD6, 0xE6E9, 0x8DCC, 0xE6EA, 0x8DDB, 0xE6EB, 0x8DCB, 0xE6EC, 0x8DEA, + 0xE6ED, 0x8DEB, 0xE6EE, 0x8DDF, 0xE6EF, 0x8DE3, 0xE6F0, 0x8DFC, 0xE6F1, 0x8E08, 0xE6F2, 0x8E09, 0xE6F3, 0x8DFF, 0xE6F4, 0x8E1D, + 0xE6F5, 0x8E1E, 0xE6F6, 0x8E10, 0xE6F7, 0x8E1F, 0xE6F8, 0x8E42, 0xE6F9, 0x8E35, 0xE6FA, 0x8E30, 0xE6FB, 0x8E34, 0xE6FC, 0x8E4A, + 0xE740, 0x8E47, 0xE741, 0x8E49, 0xE742, 0x8E4C, 0xE743, 0x8E50, 0xE744, 0x8E48, 0xE745, 0x8E59, 0xE746, 0x8E64, 0xE747, 0x8E60, + 0xE748, 0x8E2A, 0xE749, 0x8E63, 0xE74A, 0x8E55, 0xE74B, 0x8E76, 0xE74C, 0x8E72, 0xE74D, 0x8E7C, 0xE74E, 0x8E81, 0xE74F, 0x8E87, + 0xE750, 0x8E85, 0xE751, 0x8E84, 0xE752, 0x8E8B, 0xE753, 0x8E8A, 0xE754, 0x8E93, 0xE755, 0x8E91, 0xE756, 0x8E94, 0xE757, 0x8E99, + 0xE758, 0x8EAA, 0xE759, 0x8EA1, 0xE75A, 0x8EAC, 0xE75B, 0x8EB0, 0xE75C, 0x8EC6, 0xE75D, 0x8EB1, 0xE75E, 0x8EBE, 0xE75F, 0x8EC5, + 0xE760, 0x8EC8, 0xE761, 0x8ECB, 0xE762, 0x8EDB, 0xE763, 0x8EE3, 0xE764, 0x8EFC, 0xE765, 0x8EFB, 0xE766, 0x8EEB, 0xE767, 0x8EFE, + 0xE768, 0x8F0A, 0xE769, 0x8F05, 0xE76A, 0x8F15, 0xE76B, 0x8F12, 0xE76C, 0x8F19, 0xE76D, 0x8F13, 0xE76E, 0x8F1C, 0xE76F, 0x8F1F, + 0xE770, 0x8F1B, 0xE771, 0x8F0C, 0xE772, 0x8F26, 0xE773, 0x8F33, 0xE774, 0x8F3B, 0xE775, 0x8F39, 0xE776, 0x8F45, 0xE777, 0x8F42, + 0xE778, 0x8F3E, 0xE779, 0x8F4C, 0xE77A, 0x8F49, 0xE77B, 0x8F46, 0xE77C, 0x8F4E, 0xE77D, 0x8F57, 0xE77E, 0x8F5C, 0xE780, 0x8F62, + 0xE781, 0x8F63, 0xE782, 0x8F64, 0xE783, 0x8F9C, 0xE784, 0x8F9F, 0xE785, 0x8FA3, 0xE786, 0x8FAD, 0xE787, 0x8FAF, 0xE788, 0x8FB7, + 0xE789, 0x8FDA, 0xE78A, 0x8FE5, 0xE78B, 0x8FE2, 0xE78C, 0x8FEA, 0xE78D, 0x8FEF, 0xE78E, 0x9087, 0xE78F, 0x8FF4, 0xE790, 0x9005, + 0xE791, 0x8FF9, 0xE792, 0x8FFA, 0xE793, 0x9011, 0xE794, 0x9015, 0xE795, 0x9021, 0xE796, 0x900D, 0xE797, 0x901E, 0xE798, 0x9016, + 0xE799, 0x900B, 0xE79A, 0x9027, 0xE79B, 0x9036, 0xE79C, 0x9035, 0xE79D, 0x9039, 0xE79E, 0x8FF8, 0xE79F, 0x904F, 0xE7A0, 0x9050, + 0xE7A1, 0x9051, 0xE7A2, 0x9052, 0xE7A3, 0x900E, 0xE7A4, 0x9049, 0xE7A5, 0x903E, 0xE7A6, 0x9056, 0xE7A7, 0x9058, 0xE7A8, 0x905E, + 0xE7A9, 0x9068, 0xE7AA, 0x906F, 0xE7AB, 0x9076, 0xE7AC, 0x96A8, 0xE7AD, 0x9072, 0xE7AE, 0x9082, 0xE7AF, 0x907D, 0xE7B0, 0x9081, + 0xE7B1, 0x9080, 0xE7B2, 0x908A, 0xE7B3, 0x9089, 0xE7B4, 0x908F, 0xE7B5, 0x90A8, 0xE7B6, 0x90AF, 0xE7B7, 0x90B1, 0xE7B8, 0x90B5, + 0xE7B9, 0x90E2, 0xE7BA, 0x90E4, 0xE7BB, 0x6248, 0xE7BC, 0x90DB, 0xE7BD, 0x9102, 0xE7BE, 0x9112, 0xE7BF, 0x9119, 0xE7C0, 0x9132, + 0xE7C1, 0x9130, 0xE7C2, 0x914A, 0xE7C3, 0x9156, 0xE7C4, 0x9158, 0xE7C5, 0x9163, 0xE7C6, 0x9165, 0xE7C7, 0x9169, 0xE7C8, 0x9173, + 0xE7C9, 0x9172, 0xE7CA, 0x918B, 0xE7CB, 0x9189, 0xE7CC, 0x9182, 0xE7CD, 0x91A2, 0xE7CE, 0x91AB, 0xE7CF, 0x91AF, 0xE7D0, 0x91AA, + 0xE7D1, 0x91B5, 0xE7D2, 0x91B4, 0xE7D3, 0x91BA, 0xE7D4, 0x91C0, 0xE7D5, 0x91C1, 0xE7D6, 0x91C9, 0xE7D7, 0x91CB, 0xE7D8, 0x91D0, + 0xE7D9, 0x91D6, 0xE7DA, 0x91DF, 0xE7DB, 0x91E1, 0xE7DC, 0x91DB, 0xE7DD, 0x91FC, 0xE7DE, 0x91F5, 0xE7DF, 0x91F6, 0xE7E0, 0x921E, + 0xE7E1, 0x91FF, 0xE7E2, 0x9214, 0xE7E3, 0x922C, 0xE7E4, 0x9215, 0xE7E5, 0x9211, 0xE7E6, 0x925E, 0xE7E7, 0x9257, 0xE7E8, 0x9245, + 0xE7E9, 0x9249, 0xE7EA, 0x9264, 0xE7EB, 0x9248, 0xE7EC, 0x9295, 0xE7ED, 0x923F, 0xE7EE, 0x924B, 0xE7EF, 0x9250, 0xE7F0, 0x929C, + 0xE7F1, 0x9296, 0xE7F2, 0x9293, 0xE7F3, 0x929B, 0xE7F4, 0x925A, 0xE7F5, 0x92CF, 0xE7F6, 0x92B9, 0xE7F7, 0x92B7, 0xE7F8, 0x92E9, + 0xE7F9, 0x930F, 0xE7FA, 0x92FA, 0xE7FB, 0x9344, 0xE7FC, 0x932E, 0xE840, 0x9319, 0xE841, 0x9322, 0xE842, 0x931A, 0xE843, 0x9323, + 0xE844, 0x933A, 0xE845, 0x9335, 0xE846, 0x933B, 0xE847, 0x935C, 0xE848, 0x9360, 0xE849, 0x937C, 0xE84A, 0x936E, 0xE84B, 0x9356, + 0xE84C, 0x93B0, 0xE84D, 0x93AC, 0xE84E, 0x93AD, 0xE84F, 0x9394, 0xE850, 0x93B9, 0xE851, 0x93D6, 0xE852, 0x93D7, 0xE853, 0x93E8, + 0xE854, 0x93E5, 0xE855, 0x93D8, 0xE856, 0x93C3, 0xE857, 0x93DD, 0xE858, 0x93D0, 0xE859, 0x93C8, 0xE85A, 0x93E4, 0xE85B, 0x941A, + 0xE85C, 0x9414, 0xE85D, 0x9413, 0xE85E, 0x9403, 0xE85F, 0x9407, 0xE860, 0x9410, 0xE861, 0x9436, 0xE862, 0x942B, 0xE863, 0x9435, + 0xE864, 0x9421, 0xE865, 0x943A, 0xE866, 0x9441, 0xE867, 0x9452, 0xE868, 0x9444, 0xE869, 0x945B, 0xE86A, 0x9460, 0xE86B, 0x9462, + 0xE86C, 0x945E, 0xE86D, 0x946A, 0xE86E, 0x9229, 0xE86F, 0x9470, 0xE870, 0x9475, 0xE871, 0x9477, 0xE872, 0x947D, 0xE873, 0x945A, + 0xE874, 0x947C, 0xE875, 0x947E, 0xE876, 0x9481, 0xE877, 0x947F, 0xE878, 0x9582, 0xE879, 0x9587, 0xE87A, 0x958A, 0xE87B, 0x9594, + 0xE87C, 0x9596, 0xE87D, 0x9598, 0xE87E, 0x9599, 0xE880, 0x95A0, 0xE881, 0x95A8, 0xE882, 0x95A7, 0xE883, 0x95AD, 0xE884, 0x95BC, + 0xE885, 0x95BB, 0xE886, 0x95B9, 0xE887, 0x95BE, 0xE888, 0x95CA, 0xE889, 0x6FF6, 0xE88A, 0x95C3, 0xE88B, 0x95CD, 0xE88C, 0x95CC, + 0xE88D, 0x95D5, 0xE88E, 0x95D4, 0xE88F, 0x95D6, 0xE890, 0x95DC, 0xE891, 0x95E1, 0xE892, 0x95E5, 0xE893, 0x95E2, 0xE894, 0x9621, + 0xE895, 0x9628, 0xE896, 0x962E, 0xE897, 0x962F, 0xE898, 0x9642, 0xE899, 0x964C, 0xE89A, 0x964F, 0xE89B, 0x964B, 0xE89C, 0x9677, + 0xE89D, 0x965C, 0xE89E, 0x965E, 0xE89F, 0x965D, 0xE8A0, 0x965F, 0xE8A1, 0x9666, 0xE8A2, 0x9672, 0xE8A3, 0x966C, 0xE8A4, 0x968D, + 0xE8A5, 0x9698, 0xE8A6, 0x9695, 0xE8A7, 0x9697, 0xE8A8, 0x96AA, 0xE8A9, 0x96A7, 0xE8AA, 0x96B1, 0xE8AB, 0x96B2, 0xE8AC, 0x96B0, + 0xE8AD, 0x96B4, 0xE8AE, 0x96B6, 0xE8AF, 0x96B8, 0xE8B0, 0x96B9, 0xE8B1, 0x96CE, 0xE8B2, 0x96CB, 0xE8B3, 0x96C9, 0xE8B4, 0x96CD, + 0xE8B5, 0x894D, 0xE8B6, 0x96DC, 0xE8B7, 0x970D, 0xE8B8, 0x96D5, 0xE8B9, 0x96F9, 0xE8BA, 0x9704, 0xE8BB, 0x9706, 0xE8BC, 0x9708, + 0xE8BD, 0x9713, 0xE8BE, 0x970E, 0xE8BF, 0x9711, 0xE8C0, 0x970F, 0xE8C1, 0x9716, 0xE8C2, 0x9719, 0xE8C3, 0x9724, 0xE8C4, 0x972A, + 0xE8C5, 0x9730, 0xE8C6, 0x9739, 0xE8C7, 0x973D, 0xE8C8, 0x973E, 0xE8C9, 0x9744, 0xE8CA, 0x9746, 0xE8CB, 0x9748, 0xE8CC, 0x9742, + 0xE8CD, 0x9749, 0xE8CE, 0x975C, 0xE8CF, 0x9760, 0xE8D0, 0x9764, 0xE8D1, 0x9766, 0xE8D2, 0x9768, 0xE8D3, 0x52D2, 0xE8D4, 0x976B, + 0xE8D5, 0x9771, 0xE8D6, 0x9779, 0xE8D7, 0x9785, 0xE8D8, 0x977C, 0xE8D9, 0x9781, 0xE8DA, 0x977A, 0xE8DB, 0x9786, 0xE8DC, 0x978B, + 0xE8DD, 0x978F, 0xE8DE, 0x9790, 0xE8DF, 0x979C, 0xE8E0, 0x97A8, 0xE8E1, 0x97A6, 0xE8E2, 0x97A3, 0xE8E3, 0x97B3, 0xE8E4, 0x97B4, + 0xE8E5, 0x97C3, 0xE8E6, 0x97C6, 0xE8E7, 0x97C8, 0xE8E8, 0x97CB, 0xE8E9, 0x97DC, 0xE8EA, 0x97ED, 0xE8EB, 0x9F4F, 0xE8EC, 0x97F2, + 0xE8ED, 0x7ADF, 0xE8EE, 0x97F6, 0xE8EF, 0x97F5, 0xE8F0, 0x980F, 0xE8F1, 0x980C, 0xE8F2, 0x9838, 0xE8F3, 0x9824, 0xE8F4, 0x9821, + 0xE8F5, 0x9837, 0xE8F6, 0x983D, 0xE8F7, 0x9846, 0xE8F8, 0x984F, 0xE8F9, 0x984B, 0xE8FA, 0x986B, 0xE8FB, 0x986F, 0xE8FC, 0x9870, + 0xE940, 0x9871, 0xE941, 0x9874, 0xE942, 0x9873, 0xE943, 0x98AA, 0xE944, 0x98AF, 0xE945, 0x98B1, 0xE946, 0x98B6, 0xE947, 0x98C4, + 0xE948, 0x98C3, 0xE949, 0x98C6, 0xE94A, 0x98E9, 0xE94B, 0x98EB, 0xE94C, 0x9903, 0xE94D, 0x9909, 0xE94E, 0x9912, 0xE94F, 0x9914, + 0xE950, 0x9918, 0xE951, 0x9921, 0xE952, 0x991D, 0xE953, 0x991E, 0xE954, 0x9924, 0xE955, 0x9920, 0xE956, 0x992C, 0xE957, 0x992E, + 0xE958, 0x993D, 0xE959, 0x993E, 0xE95A, 0x9942, 0xE95B, 0x9949, 0xE95C, 0x9945, 0xE95D, 0x9950, 0xE95E, 0x994B, 0xE95F, 0x9951, + 0xE960, 0x9952, 0xE961, 0x994C, 0xE962, 0x9955, 0xE963, 0x9997, 0xE964, 0x9998, 0xE965, 0x99A5, 0xE966, 0x99AD, 0xE967, 0x99AE, + 0xE968, 0x99BC, 0xE969, 0x99DF, 0xE96A, 0x99DB, 0xE96B, 0x99DD, 0xE96C, 0x99D8, 0xE96D, 0x99D1, 0xE96E, 0x99ED, 0xE96F, 0x99EE, + 0xE970, 0x99F1, 0xE971, 0x99F2, 0xE972, 0x99FB, 0xE973, 0x99F8, 0xE974, 0x9A01, 0xE975, 0x9A0F, 0xE976, 0x9A05, 0xE977, 0x99E2, + 0xE978, 0x9A19, 0xE979, 0x9A2B, 0xE97A, 0x9A37, 0xE97B, 0x9A45, 0xE97C, 0x9A42, 0xE97D, 0x9A40, 0xE97E, 0x9A43, 0xE980, 0x9A3E, + 0xE981, 0x9A55, 0xE982, 0x9A4D, 0xE983, 0x9A5B, 0xE984, 0x9A57, 0xE985, 0x9A5F, 0xE986, 0x9A62, 0xE987, 0x9A65, 0xE988, 0x9A64, + 0xE989, 0x9A69, 0xE98A, 0x9A6B, 0xE98B, 0x9A6A, 0xE98C, 0x9AAD, 0xE98D, 0x9AB0, 0xE98E, 0x9ABC, 0xE98F, 0x9AC0, 0xE990, 0x9ACF, + 0xE991, 0x9AD1, 0xE992, 0x9AD3, 0xE993, 0x9AD4, 0xE994, 0x9ADE, 0xE995, 0x9ADF, 0xE996, 0x9AE2, 0xE997, 0x9AE3, 0xE998, 0x9AE6, + 0xE999, 0x9AEF, 0xE99A, 0x9AEB, 0xE99B, 0x9AEE, 0xE99C, 0x9AF4, 0xE99D, 0x9AF1, 0xE99E, 0x9AF7, 0xE99F, 0x9AFB, 0xE9A0, 0x9B06, + 0xE9A1, 0x9B18, 0xE9A2, 0x9B1A, 0xE9A3, 0x9B1F, 0xE9A4, 0x9B22, 0xE9A5, 0x9B23, 0xE9A6, 0x9B25, 0xE9A7, 0x9B27, 0xE9A8, 0x9B28, + 0xE9A9, 0x9B29, 0xE9AA, 0x9B2A, 0xE9AB, 0x9B2E, 0xE9AC, 0x9B2F, 0xE9AD, 0x9B32, 0xE9AE, 0x9B44, 0xE9AF, 0x9B43, 0xE9B0, 0x9B4F, + 0xE9B1, 0x9B4D, 0xE9B2, 0x9B4E, 0xE9B3, 0x9B51, 0xE9B4, 0x9B58, 0xE9B5, 0x9B74, 0xE9B6, 0x9B93, 0xE9B7, 0x9B83, 0xE9B8, 0x9B91, + 0xE9B9, 0x9B96, 0xE9BA, 0x9B97, 0xE9BB, 0x9B9F, 0xE9BC, 0x9BA0, 0xE9BD, 0x9BA8, 0xE9BE, 0x9BB4, 0xE9BF, 0x9BC0, 0xE9C0, 0x9BCA, + 0xE9C1, 0x9BB9, 0xE9C2, 0x9BC6, 0xE9C3, 0x9BCF, 0xE9C4, 0x9BD1, 0xE9C5, 0x9BD2, 0xE9C6, 0x9BE3, 0xE9C7, 0x9BE2, 0xE9C8, 0x9BE4, + 0xE9C9, 0x9BD4, 0xE9CA, 0x9BE1, 0xE9CB, 0x9C3A, 0xE9CC, 0x9BF2, 0xE9CD, 0x9BF1, 0xE9CE, 0x9BF0, 0xE9CF, 0x9C15, 0xE9D0, 0x9C14, + 0xE9D1, 0x9C09, 0xE9D2, 0x9C13, 0xE9D3, 0x9C0C, 0xE9D4, 0x9C06, 0xE9D5, 0x9C08, 0xE9D6, 0x9C12, 0xE9D7, 0x9C0A, 0xE9D8, 0x9C04, + 0xE9D9, 0x9C2E, 0xE9DA, 0x9C1B, 0xE9DB, 0x9C25, 0xE9DC, 0x9C24, 0xE9DD, 0x9C21, 0xE9DE, 0x9C30, 0xE9DF, 0x9C47, 0xE9E0, 0x9C32, + 0xE9E1, 0x9C46, 0xE9E2, 0x9C3E, 0xE9E3, 0x9C5A, 0xE9E4, 0x9C60, 0xE9E5, 0x9C67, 0xE9E6, 0x9C76, 0xE9E7, 0x9C78, 0xE9E8, 0x9CE7, + 0xE9E9, 0x9CEC, 0xE9EA, 0x9CF0, 0xE9EB, 0x9D09, 0xE9EC, 0x9D08, 0xE9ED, 0x9CEB, 0xE9EE, 0x9D03, 0xE9EF, 0x9D06, 0xE9F0, 0x9D2A, + 0xE9F1, 0x9D26, 0xE9F2, 0x9DAF, 0xE9F3, 0x9D23, 0xE9F4, 0x9D1F, 0xE9F5, 0x9D44, 0xE9F6, 0x9D15, 0xE9F7, 0x9D12, 0xE9F8, 0x9D41, + 0xE9F9, 0x9D3F, 0xE9FA, 0x9D3E, 0xE9FB, 0x9D46, 0xE9FC, 0x9D48, 0xEA40, 0x9D5D, 0xEA41, 0x9D5E, 0xEA42, 0x9D64, 0xEA43, 0x9D51, + 0xEA44, 0x9D50, 0xEA45, 0x9D59, 0xEA46, 0x9D72, 0xEA47, 0x9D89, 0xEA48, 0x9D87, 0xEA49, 0x9DAB, 0xEA4A, 0x9D6F, 0xEA4B, 0x9D7A, + 0xEA4C, 0x9D9A, 0xEA4D, 0x9DA4, 0xEA4E, 0x9DA9, 0xEA4F, 0x9DB2, 0xEA50, 0x9DC4, 0xEA51, 0x9DC1, 0xEA52, 0x9DBB, 0xEA53, 0x9DB8, + 0xEA54, 0x9DBA, 0xEA55, 0x9DC6, 0xEA56, 0x9DCF, 0xEA57, 0x9DC2, 0xEA58, 0x9DD9, 0xEA59, 0x9DD3, 0xEA5A, 0x9DF8, 0xEA5B, 0x9DE6, + 0xEA5C, 0x9DED, 0xEA5D, 0x9DEF, 0xEA5E, 0x9DFD, 0xEA5F, 0x9E1A, 0xEA60, 0x9E1B, 0xEA61, 0x9E1E, 0xEA62, 0x9E75, 0xEA63, 0x9E79, + 0xEA64, 0x9E7D, 0xEA65, 0x9E81, 0xEA66, 0x9E88, 0xEA67, 0x9E8B, 0xEA68, 0x9E8C, 0xEA69, 0x9E92, 0xEA6A, 0x9E95, 0xEA6B, 0x9E91, + 0xEA6C, 0x9E9D, 0xEA6D, 0x9EA5, 0xEA6E, 0x9EA9, 0xEA6F, 0x9EB8, 0xEA70, 0x9EAA, 0xEA71, 0x9EAD, 0xEA72, 0x9761, 0xEA73, 0x9ECC, + 0xEA74, 0x9ECE, 0xEA75, 0x9ECF, 0xEA76, 0x9ED0, 0xEA77, 0x9ED4, 0xEA78, 0x9EDC, 0xEA79, 0x9EDE, 0xEA7A, 0x9EDD, 0xEA7B, 0x9EE0, + 0xEA7C, 0x9EE5, 0xEA7D, 0x9EE8, 0xEA7E, 0x9EEF, 0xEA80, 0x9EF4, 0xEA81, 0x9EF6, 0xEA82, 0x9EF7, 0xEA83, 0x9EF9, 0xEA84, 0x9EFB, + 0xEA85, 0x9EFC, 0xEA86, 0x9EFD, 0xEA87, 0x9F07, 0xEA88, 0x9F08, 0xEA89, 0x76B7, 0xEA8A, 0x9F15, 0xEA8B, 0x9F21, 0xEA8C, 0x9F2C, + 0xEA8D, 0x9F3E, 0xEA8E, 0x9F4A, 0xEA8F, 0x9F52, 0xEA90, 0x9F54, 0xEA91, 0x9F63, 0xEA92, 0x9F5F, 0xEA93, 0x9F60, 0xEA94, 0x9F61, + 0xEA95, 0x9F66, 0xEA96, 0x9F67, 0xEA97, 0x9F6C, 0xEA98, 0x9F6A, 0xEA99, 0x9F77, 0xEA9A, 0x9F72, 0xEA9B, 0x9F76, 0xEA9C, 0x9F95, + 0xEA9D, 0x9F9C, 0xEA9E, 0x9FA0, 0xEA9F, 0x582F, 0xEAA0, 0x69C7, 0xEAA1, 0x9059, 0xEAA2, 0x7464, 0xEAA3, 0x51DC, 0xEAA4, 0x7199, + 0xFA40, 0x2170, 0xFA41, 0x2171, 0xFA42, 0x2172, 0xFA43, 0x2173, 0xFA44, 0x2174, 0xFA45, 0x2175, 0xFA46, 0x2176, 0xFA47, 0x2177, + 0xFA48, 0x2178, 0xFA49, 0x2179, 0xFA55, 0xFFE4, 0xFA56, 0xFF07, 0xFA57, 0xFF02, 0xFA5C, 0x7E8A, 0xFA5D, 0x891C, 0xFA5E, 0x9348, + 0xFA5F, 0x9288, 0xFA60, 0x84DC, 0xFA61, 0x4FC9, 0xFA62, 0x70BB, 0xFA63, 0x6631, 0xFA64, 0x68C8, 0xFA65, 0x92F9, 0xFA66, 0x66FB, + 0xFA67, 0x5F45, 0xFA68, 0x4E28, 0xFA69, 0x4EE1, 0xFA6A, 0x4EFC, 0xFA6B, 0x4F00, 0xFA6C, 0x4F03, 0xFA6D, 0x4F39, 0xFA6E, 0x4F56, + 0xFA6F, 0x4F92, 0xFA70, 0x4F8A, 0xFA71, 0x4F9A, 0xFA72, 0x4F94, 0xFA73, 0x4FCD, 0xFA74, 0x5040, 0xFA75, 0x5022, 0xFA76, 0x4FFF, + 0xFA77, 0x501E, 0xFA78, 0x5046, 0xFA79, 0x5070, 0xFA7A, 0x5042, 0xFA7B, 0x5094, 0xFA7C, 0x50F4, 0xFA7D, 0x50D8, 0xFA7E, 0x514A, + 0xFA80, 0x5164, 0xFA81, 0x519D, 0xFA82, 0x51BE, 0xFA83, 0x51EC, 0xFA84, 0x5215, 0xFA85, 0x529C, 0xFA86, 0x52A6, 0xFA87, 0x52C0, + 0xFA88, 0x52DB, 0xFA89, 0x5300, 0xFA8A, 0x5307, 0xFA8B, 0x5324, 0xFA8C, 0x5372, 0xFA8D, 0x5393, 0xFA8E, 0x53B2, 0xFA8F, 0x53DD, + 0xFA90, 0xFA0E, 0xFA91, 0x549C, 0xFA92, 0x548A, 0xFA93, 0x54A9, 0xFA94, 0x54FF, 0xFA95, 0x5586, 0xFA96, 0x5759, 0xFA97, 0x5765, + 0xFA98, 0x57AC, 0xFA99, 0x57C8, 0xFA9A, 0x57C7, 0xFA9B, 0xFA0F, 0xFA9C, 0xFA10, 0xFA9D, 0x589E, 0xFA9E, 0x58B2, 0xFA9F, 0x590B, + 0xFAA0, 0x5953, 0xFAA1, 0x595B, 0xFAA2, 0x595D, 0xFAA3, 0x5963, 0xFAA4, 0x59A4, 0xFAA5, 0x59BA, 0xFAA6, 0x5B56, 0xFAA7, 0x5BC0, + 0xFAA8, 0x752F, 0xFAA9, 0x5BD8, 0xFAAA, 0x5BEC, 0xFAAB, 0x5C1E, 0xFAAC, 0x5CA6, 0xFAAD, 0x5CBA, 0xFAAE, 0x5CF5, 0xFAAF, 0x5D27, + 0xFAB0, 0x5D53, 0xFAB1, 0xFA11, 0xFAB2, 0x5D42, 0xFAB3, 0x5D6D, 0xFAB4, 0x5DB8, 0xFAB5, 0x5DB9, 0xFAB6, 0x5DD0, 0xFAB7, 0x5F21, + 0xFAB8, 0x5F34, 0xFAB9, 0x5F67, 0xFABA, 0x5FB7, 0xFABB, 0x5FDE, 0xFABC, 0x605D, 0xFABD, 0x6085, 0xFABE, 0x608A, 0xFABF, 0x60DE, + 0xFAC0, 0x60D5, 0xFAC1, 0x6120, 0xFAC2, 0x60F2, 0xFAC3, 0x6111, 0xFAC4, 0x6137, 0xFAC5, 0x6130, 0xFAC6, 0x6198, 0xFAC7, 0x6213, + 0xFAC8, 0x62A6, 0xFAC9, 0x63F5, 0xFACA, 0x6460, 0xFACB, 0x649D, 0xFACC, 0x64CE, 0xFACD, 0x654E, 0xFACE, 0x6600, 0xFACF, 0x6615, + 0xFAD0, 0x663B, 0xFAD1, 0x6609, 0xFAD2, 0x662E, 0xFAD3, 0x661E, 0xFAD4, 0x6624, 0xFAD5, 0x6665, 0xFAD6, 0x6657, 0xFAD7, 0x6659, + 0xFAD8, 0xFA12, 0xFAD9, 0x6673, 0xFADA, 0x6699, 0xFADB, 0x66A0, 0xFADC, 0x66B2, 0xFADD, 0x66BF, 0xFADE, 0x66FA, 0xFADF, 0x670E, + 0xFAE0, 0xF929, 0xFAE1, 0x6766, 0xFAE2, 0x67BB, 0xFAE3, 0x6852, 0xFAE4, 0x67C0, 0xFAE5, 0x6801, 0xFAE6, 0x6844, 0xFAE7, 0x68CF, + 0xFAE8, 0xFA13, 0xFAE9, 0x6968, 0xFAEA, 0xFA14, 0xFAEB, 0x6998, 0xFAEC, 0x69E2, 0xFAED, 0x6A30, 0xFAEE, 0x6A6B, 0xFAEF, 0x6A46, + 0xFAF0, 0x6A73, 0xFAF1, 0x6A7E, 0xFAF2, 0x6AE2, 0xFAF3, 0x6AE4, 0xFAF4, 0x6BD6, 0xFAF5, 0x6C3F, 0xFAF6, 0x6C5C, 0xFAF7, 0x6C86, + 0xFAF8, 0x6C6F, 0xFAF9, 0x6CDA, 0xFAFA, 0x6D04, 0xFAFB, 0x6D87, 0xFAFC, 0x6D6F, 0xFB40, 0x6D96, 0xFB41, 0x6DAC, 0xFB42, 0x6DCF, + 0xFB43, 0x6DF8, 0xFB44, 0x6DF2, 0xFB45, 0x6DFC, 0xFB46, 0x6E39, 0xFB47, 0x6E5C, 0xFB48, 0x6E27, 0xFB49, 0x6E3C, 0xFB4A, 0x6EBF, + 0xFB4B, 0x6F88, 0xFB4C, 0x6FB5, 0xFB4D, 0x6FF5, 0xFB4E, 0x7005, 0xFB4F, 0x7007, 0xFB50, 0x7028, 0xFB51, 0x7085, 0xFB52, 0x70AB, + 0xFB53, 0x710F, 0xFB54, 0x7104, 0xFB55, 0x715C, 0xFB56, 0x7146, 0xFB57, 0x7147, 0xFB58, 0xFA15, 0xFB59, 0x71C1, 0xFB5A, 0x71FE, + 0xFB5B, 0x72B1, 0xFB5C, 0x72BE, 0xFB5D, 0x7324, 0xFB5E, 0xFA16, 0xFB5F, 0x7377, 0xFB60, 0x73BD, 0xFB61, 0x73C9, 0xFB62, 0x73D6, + 0xFB63, 0x73E3, 0xFB64, 0x73D2, 0xFB65, 0x7407, 0xFB66, 0x73F5, 0xFB67, 0x7426, 0xFB68, 0x742A, 0xFB69, 0x7429, 0xFB6A, 0x742E, + 0xFB6B, 0x7462, 0xFB6C, 0x7489, 0xFB6D, 0x749F, 0xFB6E, 0x7501, 0xFB6F, 0x756F, 0xFB70, 0x7682, 0xFB71, 0x769C, 0xFB72, 0x769E, + 0xFB73, 0x769B, 0xFB74, 0x76A6, 0xFB75, 0xFA17, 0xFB76, 0x7746, 0xFB77, 0x52AF, 0xFB78, 0x7821, 0xFB79, 0x784E, 0xFB7A, 0x7864, + 0xFB7B, 0x787A, 0xFB7C, 0x7930, 0xFB7D, 0xFA18, 0xFB7E, 0xFA19, 0xFB80, 0xFA1A, 0xFB81, 0x7994, 0xFB82, 0xFA1B, 0xFB83, 0x799B, + 0xFB84, 0x7AD1, 0xFB85, 0x7AE7, 0xFB86, 0xFA1C, 0xFB87, 0x7AEB, 0xFB88, 0x7B9E, 0xFB89, 0xFA1D, 0xFB8A, 0x7D48, 0xFB8B, 0x7D5C, + 0xFB8C, 0x7DB7, 0xFB8D, 0x7DA0, 0xFB8E, 0x7DD6, 0xFB8F, 0x7E52, 0xFB90, 0x7F47, 0xFB91, 0x7FA1, 0xFB92, 0xFA1E, 0xFB93, 0x8301, + 0xFB94, 0x8362, 0xFB95, 0x837F, 0xFB96, 0x83C7, 0xFB97, 0x83F6, 0xFB98, 0x8448, 0xFB99, 0x84B4, 0xFB9A, 0x8553, 0xFB9B, 0x8559, + 0xFB9C, 0x856B, 0xFB9D, 0xFA1F, 0xFB9E, 0x85B0, 0xFB9F, 0xFA20, 0xFBA0, 0xFA21, 0xFBA1, 0x8807, 0xFBA2, 0x88F5, 0xFBA3, 0x8A12, + 0xFBA4, 0x8A37, 0xFBA5, 0x8A79, 0xFBA6, 0x8AA7, 0xFBA7, 0x8ABE, 0xFBA8, 0x8ADF, 0xFBA9, 0xFA22, 0xFBAA, 0x8AF6, 0xFBAB, 0x8B53, + 0xFBAC, 0x8B7F, 0xFBAD, 0x8CF0, 0xFBAE, 0x8CF4, 0xFBAF, 0x8D12, 0xFBB0, 0x8D76, 0xFBB1, 0xFA23, 0xFBB2, 0x8ECF, 0xFBB3, 0xFA24, + 0xFBB4, 0xFA25, 0xFBB5, 0x9067, 0xFBB6, 0x90DE, 0xFBB7, 0xFA26, 0xFBB8, 0x9115, 0xFBB9, 0x9127, 0xFBBA, 0x91DA, 0xFBBB, 0x91D7, + 0xFBBC, 0x91DE, 0xFBBD, 0x91ED, 0xFBBE, 0x91EE, 0xFBBF, 0x91E4, 0xFBC0, 0x91E5, 0xFBC1, 0x9206, 0xFBC2, 0x9210, 0xFBC3, 0x920A, + 0xFBC4, 0x923A, 0xFBC5, 0x9240, 0xFBC6, 0x923C, 0xFBC7, 0x924E, 0xFBC8, 0x9259, 0xFBC9, 0x9251, 0xFBCA, 0x9239, 0xFBCB, 0x9267, + 0xFBCC, 0x92A7, 0xFBCD, 0x9277, 0xFBCE, 0x9278, 0xFBCF, 0x92E7, 0xFBD0, 0x92D7, 0xFBD1, 0x92D9, 0xFBD2, 0x92D0, 0xFBD3, 0xFA27, + 0xFBD4, 0x92D5, 0xFBD5, 0x92E0, 0xFBD6, 0x92D3, 0xFBD7, 0x9325, 0xFBD8, 0x9321, 0xFBD9, 0x92FB, 0xFBDA, 0xFA28, 0xFBDB, 0x931E, + 0xFBDC, 0x92FF, 0xFBDD, 0x931D, 0xFBDE, 0x9302, 0xFBDF, 0x9370, 0xFBE0, 0x9357, 0xFBE1, 0x93A4, 0xFBE2, 0x93C6, 0xFBE3, 0x93DE, + 0xFBE4, 0x93F8, 0xFBE5, 0x9431, 0xFBE6, 0x9445, 0xFBE7, 0x9448, 0xFBE8, 0x9592, 0xFBE9, 0xF9DC, 0xFBEA, 0xFA29, 0xFBEB, 0x969D, + 0xFBEC, 0x96AF, 0xFBED, 0x9733, 0xFBEE, 0x973B, 0xFBEF, 0x9743, 0xFBF0, 0x974D, 0xFBF1, 0x974F, 0xFBF2, 0x9751, 0xFBF3, 0x9755, + 0xFBF4, 0x9857, 0xFBF5, 0x9865, 0xFBF6, 0xFA2A, 0xFBF7, 0xFA2B, 0xFBF8, 0x9927, 0xFBF9, 0xFA2C, 0xFBFA, 0x999E, 0xFBFB, 0x9A4E, + 0xFBFC, 0x9AD9, 0xFC40, 0x9ADC, 0xFC41, 0x9B75, 0xFC42, 0x9B72, 0xFC43, 0x9B8F, 0xFC44, 0x9BB1, 0xFC45, 0x9BBB, 0xFC46, 0x9C00, + 0xFC47, 0x9D70, 0xFC48, 0x9D6B, 0xFC49, 0xFA2D, 0xFC4A, 0x9E19, 0xFC4B, 0x9ED1, 0, 0 +}; +#endif + +#if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */ +static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ + 0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4, + 0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE, + 0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9, + 0x0144, 0xA8BD, 0x0148, 0xA8BE, 0x014D, 0xA8AD, 0x016B, 0xA8B1, 0x01CE, 0xA8A3, 0x01D0, 0xA8AB, 0x01D2, 0xA8AF, 0x01D4, 0xA8B3, + 0x01D6, 0xA8B5, 0x01D8, 0xA8B6, 0x01DA, 0xA8B7, 0x01DC, 0xA8B8, 0x0251, 0xA8BB, 0x0261, 0xA8C0, 0x02C7, 0xA1A6, 0x02C9, 0xA1A5, + 0x02CA, 0xA840, 0x02CB, 0xA841, 0x02D9, 0xA842, 0x0391, 0xA6A1, 0x0392, 0xA6A2, 0x0393, 0xA6A3, 0x0394, 0xA6A4, 0x0395, 0xA6A5, + 0x0396, 0xA6A6, 0x0397, 0xA6A7, 0x0398, 0xA6A8, 0x0399, 0xA6A9, 0x039A, 0xA6AA, 0x039B, 0xA6AB, 0x039C, 0xA6AC, 0x039D, 0xA6AD, + 0x039E, 0xA6AE, 0x039F, 0xA6AF, 0x03A0, 0xA6B0, 0x03A1, 0xA6B1, 0x03A3, 0xA6B2, 0x03A4, 0xA6B3, 0x03A5, 0xA6B4, 0x03A6, 0xA6B5, + 0x03A7, 0xA6B6, 0x03A8, 0xA6B7, 0x03A9, 0xA6B8, 0x03B1, 0xA6C1, 0x03B2, 0xA6C2, 0x03B3, 0xA6C3, 0x03B4, 0xA6C4, 0x03B5, 0xA6C5, + 0x03B6, 0xA6C6, 0x03B7, 0xA6C7, 0x03B8, 0xA6C8, 0x03B9, 0xA6C9, 0x03BA, 0xA6CA, 0x03BB, 0xA6CB, 0x03BC, 0xA6CC, 0x03BD, 0xA6CD, + 0x03BE, 0xA6CE, 0x03BF, 0xA6CF, 0x03C0, 0xA6D0, 0x03C1, 0xA6D1, 0x03C3, 0xA6D2, 0x03C4, 0xA6D3, 0x03C5, 0xA6D4, 0x03C6, 0xA6D5, + 0x03C7, 0xA6D6, 0x03C8, 0xA6D7, 0x03C9, 0xA6D8, 0x0401, 0xA7A7, 0x0410, 0xA7A1, 0x0411, 0xA7A2, 0x0412, 0xA7A3, 0x0413, 0xA7A4, + 0x0414, 0xA7A5, 0x0415, 0xA7A6, 0x0416, 0xA7A8, 0x0417, 0xA7A9, 0x0418, 0xA7AA, 0x0419, 0xA7AB, 0x041A, 0xA7AC, 0x041B, 0xA7AD, + 0x041C, 0xA7AE, 0x041D, 0xA7AF, 0x041E, 0xA7B0, 0x041F, 0xA7B1, 0x0420, 0xA7B2, 0x0421, 0xA7B3, 0x0422, 0xA7B4, 0x0423, 0xA7B5, + 0x0424, 0xA7B6, 0x0425, 0xA7B7, 0x0426, 0xA7B8, 0x0427, 0xA7B9, 0x0428, 0xA7BA, 0x0429, 0xA7BB, 0x042A, 0xA7BC, 0x042B, 0xA7BD, + 0x042C, 0xA7BE, 0x042D, 0xA7BF, 0x042E, 0xA7C0, 0x042F, 0xA7C1, 0x0430, 0xA7D1, 0x0431, 0xA7D2, 0x0432, 0xA7D3, 0x0433, 0xA7D4, + 0x0434, 0xA7D5, 0x0435, 0xA7D6, 0x0436, 0xA7D8, 0x0437, 0xA7D9, 0x0438, 0xA7DA, 0x0439, 0xA7DB, 0x043A, 0xA7DC, 0x043B, 0xA7DD, + 0x043C, 0xA7DE, 0x043D, 0xA7DF, 0x043E, 0xA7E0, 0x043F, 0xA7E1, 0x0440, 0xA7E2, 0x0441, 0xA7E3, 0x0442, 0xA7E4, 0x0443, 0xA7E5, + 0x0444, 0xA7E6, 0x0445, 0xA7E7, 0x0446, 0xA7E8, 0x0447, 0xA7E9, 0x0448, 0xA7EA, 0x0449, 0xA7EB, 0x044A, 0xA7EC, 0x044B, 0xA7ED, + 0x044C, 0xA7EE, 0x044D, 0xA7EF, 0x044E, 0xA7F0, 0x044F, 0xA7F1, 0x0451, 0xA7D7, 0x2010, 0xA95C, 0x2013, 0xA843, 0x2014, 0xA1AA, + 0x2015, 0xA844, 0x2016, 0xA1AC, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, 0x2025, 0xA845, 0x2026, 0xA1AD, + 0x2030, 0xA1EB, 0x2032, 0xA1E4, 0x2033, 0xA1E5, 0x2035, 0xA846, 0x203B, 0xA1F9, 0x20AC, 0x0080, 0x2103, 0xA1E6, 0x2105, 0xA847, + 0x2109, 0xA848, 0x2116, 0xA1ED, 0x2121, 0xA959, 0x2160, 0xA2F1, 0x2161, 0xA2F2, 0x2162, 0xA2F3, 0x2163, 0xA2F4, 0x2164, 0xA2F5, + 0x2165, 0xA2F6, 0x2166, 0xA2F7, 0x2167, 0xA2F8, 0x2168, 0xA2F9, 0x2169, 0xA2FA, 0x216A, 0xA2FB, 0x216B, 0xA2FC, 0x2170, 0xA2A1, + 0x2171, 0xA2A2, 0x2172, 0xA2A3, 0x2173, 0xA2A4, 0x2174, 0xA2A5, 0x2175, 0xA2A6, 0x2176, 0xA2A7, 0x2177, 0xA2A8, 0x2178, 0xA2A9, + 0x2179, 0xA2AA, 0x2190, 0xA1FB, 0x2191, 0xA1FC, 0x2192, 0xA1FA, 0x2193, 0xA1FD, 0x2196, 0xA849, 0x2197, 0xA84A, 0x2198, 0xA84B, + 0x2199, 0xA84C, 0x2208, 0xA1CA, 0x220F, 0xA1C7, 0x2211, 0xA1C6, 0x2215, 0xA84D, 0x221A, 0xA1CC, 0x221D, 0xA1D8, 0x221E, 0xA1DE, + 0x221F, 0xA84E, 0x2220, 0xA1CF, 0x2223, 0xA84F, 0x2225, 0xA1CE, 0x2227, 0xA1C4, 0x2228, 0xA1C5, 0x2229, 0xA1C9, 0x222A, 0xA1C8, + 0x222B, 0xA1D2, 0x222E, 0xA1D3, 0x2234, 0xA1E0, 0x2235, 0xA1DF, 0x2236, 0xA1C3, 0x2237, 0xA1CB, 0x223D, 0xA1D7, 0x2248, 0xA1D6, + 0x224C, 0xA1D5, 0x2252, 0xA850, 0x2260, 0xA1D9, 0x2261, 0xA1D4, 0x2264, 0xA1DC, 0x2265, 0xA1DD, 0x2266, 0xA851, 0x2267, 0xA852, + 0x226E, 0xA1DA, 0x226F, 0xA1DB, 0x2295, 0xA892, 0x2299, 0xA1D1, 0x22A5, 0xA1CD, 0x22BF, 0xA853, 0x2312, 0xA1D0, 0x2460, 0xA2D9, + 0x2461, 0xA2DA, 0x2462, 0xA2DB, 0x2463, 0xA2DC, 0x2464, 0xA2DD, 0x2465, 0xA2DE, 0x2466, 0xA2DF, 0x2467, 0xA2E0, 0x2468, 0xA2E1, + 0x2469, 0xA2E2, 0x2474, 0xA2C5, 0x2475, 0xA2C6, 0x2476, 0xA2C7, 0x2477, 0xA2C8, 0x2478, 0xA2C9, 0x2479, 0xA2CA, 0x247A, 0xA2CB, + 0x247B, 0xA2CC, 0x247C, 0xA2CD, 0x247D, 0xA2CE, 0x247E, 0xA2CF, 0x247F, 0xA2D0, 0x2480, 0xA2D1, 0x2481, 0xA2D2, 0x2482, 0xA2D3, + 0x2483, 0xA2D4, 0x2484, 0xA2D5, 0x2485, 0xA2D6, 0x2486, 0xA2D7, 0x2487, 0xA2D8, 0x2488, 0xA2B1, 0x2489, 0xA2B2, 0x248A, 0xA2B3, + 0x248B, 0xA2B4, 0x248C, 0xA2B5, 0x248D, 0xA2B6, 0x248E, 0xA2B7, 0x248F, 0xA2B8, 0x2490, 0xA2B9, 0x2491, 0xA2BA, 0x2492, 0xA2BB, + 0x2493, 0xA2BC, 0x2494, 0xA2BD, 0x2495, 0xA2BE, 0x2496, 0xA2BF, 0x2497, 0xA2C0, 0x2498, 0xA2C1, 0x2499, 0xA2C2, 0x249A, 0xA2C3, + 0x249B, 0xA2C4, 0x2500, 0xA9A4, 0x2501, 0xA9A5, 0x2502, 0xA9A6, 0x2503, 0xA9A7, 0x2504, 0xA9A8, 0x2505, 0xA9A9, 0x2506, 0xA9AA, + 0x2507, 0xA9AB, 0x2508, 0xA9AC, 0x2509, 0xA9AD, 0x250A, 0xA9AE, 0x250B, 0xA9AF, 0x250C, 0xA9B0, 0x250D, 0xA9B1, 0x250E, 0xA9B2, + 0x250F, 0xA9B3, 0x2510, 0xA9B4, 0x2511, 0xA9B5, 0x2512, 0xA9B6, 0x2513, 0xA9B7, 0x2514, 0xA9B8, 0x2515, 0xA9B9, 0x2516, 0xA9BA, + 0x2517, 0xA9BB, 0x2518, 0xA9BC, 0x2519, 0xA9BD, 0x251A, 0xA9BE, 0x251B, 0xA9BF, 0x251C, 0xA9C0, 0x251D, 0xA9C1, 0x251E, 0xA9C2, + 0x251F, 0xA9C3, 0x2520, 0xA9C4, 0x2521, 0xA9C5, 0x2522, 0xA9C6, 0x2523, 0xA9C7, 0x2524, 0xA9C8, 0x2525, 0xA9C9, 0x2526, 0xA9CA, + 0x2527, 0xA9CB, 0x2528, 0xA9CC, 0x2529, 0xA9CD, 0x252A, 0xA9CE, 0x252B, 0xA9CF, 0x252C, 0xA9D0, 0x252D, 0xA9D1, 0x252E, 0xA9D2, + 0x252F, 0xA9D3, 0x2530, 0xA9D4, 0x2531, 0xA9D5, 0x2532, 0xA9D6, 0x2533, 0xA9D7, 0x2534, 0xA9D8, 0x2535, 0xA9D9, 0x2536, 0xA9DA, + 0x2537, 0xA9DB, 0x2538, 0xA9DC, 0x2539, 0xA9DD, 0x253A, 0xA9DE, 0x253B, 0xA9DF, 0x253C, 0xA9E0, 0x253D, 0xA9E1, 0x253E, 0xA9E2, + 0x253F, 0xA9E3, 0x2540, 0xA9E4, 0x2541, 0xA9E5, 0x2542, 0xA9E6, 0x2543, 0xA9E7, 0x2544, 0xA9E8, 0x2545, 0xA9E9, 0x2546, 0xA9EA, + 0x2547, 0xA9EB, 0x2548, 0xA9EC, 0x2549, 0xA9ED, 0x254A, 0xA9EE, 0x254B, 0xA9EF, 0x2550, 0xA854, 0x2551, 0xA855, 0x2552, 0xA856, + 0x2553, 0xA857, 0x2554, 0xA858, 0x2555, 0xA859, 0x2556, 0xA85A, 0x2557, 0xA85B, 0x2558, 0xA85C, 0x2559, 0xA85D, 0x255A, 0xA85E, + 0x255B, 0xA85F, 0x255C, 0xA860, 0x255D, 0xA861, 0x255E, 0xA862, 0x255F, 0xA863, 0x2560, 0xA864, 0x2561, 0xA865, 0x2562, 0xA866, + 0x2563, 0xA867, 0x2564, 0xA868, 0x2565, 0xA869, 0x2566, 0xA86A, 0x2567, 0xA86B, 0x2568, 0xA86C, 0x2569, 0xA86D, 0x256A, 0xA86E, + 0x256B, 0xA86F, 0x256C, 0xA870, 0x256D, 0xA871, 0x256E, 0xA872, 0x256F, 0xA873, 0x2570, 0xA874, 0x2571, 0xA875, 0x2572, 0xA876, + 0x2573, 0xA877, 0x2581, 0xA878, 0x2582, 0xA879, 0x2583, 0xA87A, 0x2584, 0xA87B, 0x2585, 0xA87C, 0x2586, 0xA87D, 0x2587, 0xA87E, + 0x2588, 0xA880, 0x2589, 0xA881, 0x258A, 0xA882, 0x258B, 0xA883, 0x258C, 0xA884, 0x258D, 0xA885, 0x258E, 0xA886, 0x258F, 0xA887, + 0x2593, 0xA888, 0x2594, 0xA889, 0x2595, 0xA88A, 0x25A0, 0xA1F6, 0x25A1, 0xA1F5, 0x25B2, 0xA1F8, 0x25B3, 0xA1F7, 0x25BC, 0xA88B, + 0x25BD, 0xA88C, 0x25C6, 0xA1F4, 0x25C7, 0xA1F3, 0x25CB, 0xA1F0, 0x25CE, 0xA1F2, 0x25CF, 0xA1F1, 0x25E2, 0xA88D, 0x25E3, 0xA88E, + 0x25E4, 0xA88F, 0x25E5, 0xA890, 0x2605, 0xA1EF, 0x2606, 0xA1EE, 0x2609, 0xA891, 0x2640, 0xA1E2, 0x2642, 0xA1E1, 0x3000, 0xA1A1, + 0x3001, 0xA1A2, 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3005, 0xA1A9, 0x3006, 0xA965, 0x3007, 0xA996, 0x3008, 0xA1B4, 0x3009, 0xA1B5, + 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BE, 0x3011, 0xA1BF, + 0x3012, 0xA893, 0x3013, 0xA1FE, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3016, 0xA1BC, 0x3017, 0xA1BD, 0x301D, 0xA894, 0x301E, 0xA895, + 0x3021, 0xA940, 0x3022, 0xA941, 0x3023, 0xA942, 0x3024, 0xA943, 0x3025, 0xA944, 0x3026, 0xA945, 0x3027, 0xA946, 0x3028, 0xA947, + 0x3029, 0xA948, 0x3041, 0xA4A1, 0x3042, 0xA4A2, 0x3043, 0xA4A3, 0x3044, 0xA4A4, 0x3045, 0xA4A5, 0x3046, 0xA4A6, 0x3047, 0xA4A7, + 0x3048, 0xA4A8, 0x3049, 0xA4A9, 0x304A, 0xA4AA, 0x304B, 0xA4AB, 0x304C, 0xA4AC, 0x304D, 0xA4AD, 0x304E, 0xA4AE, 0x304F, 0xA4AF, + 0x3050, 0xA4B0, 0x3051, 0xA4B1, 0x3052, 0xA4B2, 0x3053, 0xA4B3, 0x3054, 0xA4B4, 0x3055, 0xA4B5, 0x3056, 0xA4B6, 0x3057, 0xA4B7, + 0x3058, 0xA4B8, 0x3059, 0xA4B9, 0x305A, 0xA4BA, 0x305B, 0xA4BB, 0x305C, 0xA4BC, 0x305D, 0xA4BD, 0x305E, 0xA4BE, 0x305F, 0xA4BF, + 0x3060, 0xA4C0, 0x3061, 0xA4C1, 0x3062, 0xA4C2, 0x3063, 0xA4C3, 0x3064, 0xA4C4, 0x3065, 0xA4C5, 0x3066, 0xA4C6, 0x3067, 0xA4C7, + 0x3068, 0xA4C8, 0x3069, 0xA4C9, 0x306A, 0xA4CA, 0x306B, 0xA4CB, 0x306C, 0xA4CC, 0x306D, 0xA4CD, 0x306E, 0xA4CE, 0x306F, 0xA4CF, + 0x3070, 0xA4D0, 0x3071, 0xA4D1, 0x3072, 0xA4D2, 0x3073, 0xA4D3, 0x3074, 0xA4D4, 0x3075, 0xA4D5, 0x3076, 0xA4D6, 0x3077, 0xA4D7, + 0x3078, 0xA4D8, 0x3079, 0xA4D9, 0x307A, 0xA4DA, 0x307B, 0xA4DB, 0x307C, 0xA4DC, 0x307D, 0xA4DD, 0x307E, 0xA4DE, 0x307F, 0xA4DF, + 0x3080, 0xA4E0, 0x3081, 0xA4E1, 0x3082, 0xA4E2, 0x3083, 0xA4E3, 0x3084, 0xA4E4, 0x3085, 0xA4E5, 0x3086, 0xA4E6, 0x3087, 0xA4E7, + 0x3088, 0xA4E8, 0x3089, 0xA4E9, 0x308A, 0xA4EA, 0x308B, 0xA4EB, 0x308C, 0xA4EC, 0x308D, 0xA4ED, 0x308E, 0xA4EE, 0x308F, 0xA4EF, + 0x3090, 0xA4F0, 0x3091, 0xA4F1, 0x3092, 0xA4F2, 0x3093, 0xA4F3, 0x309B, 0xA961, 0x309C, 0xA962, 0x309D, 0xA966, 0x309E, 0xA967, + 0x30A1, 0xA5A1, 0x30A2, 0xA5A2, 0x30A3, 0xA5A3, 0x30A4, 0xA5A4, 0x30A5, 0xA5A5, 0x30A6, 0xA5A6, 0x30A7, 0xA5A7, 0x30A8, 0xA5A8, + 0x30A9, 0xA5A9, 0x30AA, 0xA5AA, 0x30AB, 0xA5AB, 0x30AC, 0xA5AC, 0x30AD, 0xA5AD, 0x30AE, 0xA5AE, 0x30AF, 0xA5AF, 0x30B0, 0xA5B0, + 0x30B1, 0xA5B1, 0x30B2, 0xA5B2, 0x30B3, 0xA5B3, 0x30B4, 0xA5B4, 0x30B5, 0xA5B5, 0x30B6, 0xA5B6, 0x30B7, 0xA5B7, 0x30B8, 0xA5B8, + 0x30B9, 0xA5B9, 0x30BA, 0xA5BA, 0x30BB, 0xA5BB, 0x30BC, 0xA5BC, 0x30BD, 0xA5BD, 0x30BE, 0xA5BE, 0x30BF, 0xA5BF, 0x30C0, 0xA5C0, + 0x30C1, 0xA5C1, 0x30C2, 0xA5C2, 0x30C3, 0xA5C3, 0x30C4, 0xA5C4, 0x30C5, 0xA5C5, 0x30C6, 0xA5C6, 0x30C7, 0xA5C7, 0x30C8, 0xA5C8, + 0x30C9, 0xA5C9, 0x30CA, 0xA5CA, 0x30CB, 0xA5CB, 0x30CC, 0xA5CC, 0x30CD, 0xA5CD, 0x30CE, 0xA5CE, 0x30CF, 0xA5CF, 0x30D0, 0xA5D0, + 0x30D1, 0xA5D1, 0x30D2, 0xA5D2, 0x30D3, 0xA5D3, 0x30D4, 0xA5D4, 0x30D5, 0xA5D5, 0x30D6, 0xA5D6, 0x30D7, 0xA5D7, 0x30D8, 0xA5D8, + 0x30D9, 0xA5D9, 0x30DA, 0xA5DA, 0x30DB, 0xA5DB, 0x30DC, 0xA5DC, 0x30DD, 0xA5DD, 0x30DE, 0xA5DE, 0x30DF, 0xA5DF, 0x30E0, 0xA5E0, + 0x30E1, 0xA5E1, 0x30E2, 0xA5E2, 0x30E3, 0xA5E3, 0x30E4, 0xA5E4, 0x30E5, 0xA5E5, 0x30E6, 0xA5E6, 0x30E7, 0xA5E7, 0x30E8, 0xA5E8, + 0x30E9, 0xA5E9, 0x30EA, 0xA5EA, 0x30EB, 0xA5EB, 0x30EC, 0xA5EC, 0x30ED, 0xA5ED, 0x30EE, 0xA5EE, 0x30EF, 0xA5EF, 0x30F0, 0xA5F0, + 0x30F1, 0xA5F1, 0x30F2, 0xA5F2, 0x30F3, 0xA5F3, 0x30F4, 0xA5F4, 0x30F5, 0xA5F5, 0x30F6, 0xA5F6, 0x30FC, 0xA960, 0x30FD, 0xA963, + 0x30FE, 0xA964, 0x3105, 0xA8C5, 0x3106, 0xA8C6, 0x3107, 0xA8C7, 0x3108, 0xA8C8, 0x3109, 0xA8C9, 0x310A, 0xA8CA, 0x310B, 0xA8CB, + 0x310C, 0xA8CC, 0x310D, 0xA8CD, 0x310E, 0xA8CE, 0x310F, 0xA8CF, 0x3110, 0xA8D0, 0x3111, 0xA8D1, 0x3112, 0xA8D2, 0x3113, 0xA8D3, + 0x3114, 0xA8D4, 0x3115, 0xA8D5, 0x3116, 0xA8D6, 0x3117, 0xA8D7, 0x3118, 0xA8D8, 0x3119, 0xA8D9, 0x311A, 0xA8DA, 0x311B, 0xA8DB, + 0x311C, 0xA8DC, 0x311D, 0xA8DD, 0x311E, 0xA8DE, 0x311F, 0xA8DF, 0x3120, 0xA8E0, 0x3121, 0xA8E1, 0x3122, 0xA8E2, 0x3123, 0xA8E3, + 0x3124, 0xA8E4, 0x3125, 0xA8E5, 0x3126, 0xA8E6, 0x3127, 0xA8E7, 0x3128, 0xA8E8, 0x3129, 0xA8E9, 0x3220, 0xA2E5, 0x3221, 0xA2E6, + 0x3222, 0xA2E7, 0x3223, 0xA2E8, 0x3224, 0xA2E9, 0x3225, 0xA2EA, 0x3226, 0xA2EB, 0x3227, 0xA2EC, 0x3228, 0xA2ED, 0x3229, 0xA2EE, + 0x3231, 0xA95A, 0x32A3, 0xA949, 0x338E, 0xA94A, 0x338F, 0xA94B, 0x339C, 0xA94C, 0x339D, 0xA94D, 0x339E, 0xA94E, 0x33A1, 0xA94F, + 0x33C4, 0xA950, 0x33CE, 0xA951, 0x33D1, 0xA952, 0x33D2, 0xA953, 0x33D5, 0xA954, 0x4E00, 0xD2BB, 0x4E01, 0xB6A1, 0x4E02, 0x8140, + 0x4E03, 0xC6DF, 0x4E04, 0x8141, 0x4E05, 0x8142, 0x4E06, 0x8143, 0x4E07, 0xCDF2, 0x4E08, 0xD5C9, 0x4E09, 0xC8FD, 0x4E0A, 0xC9CF, + 0x4E0B, 0xCFC2, 0x4E0C, 0xD8A2, 0x4E0D, 0xB2BB, 0x4E0E, 0xD3EB, 0x4E0F, 0x8144, 0x4E10, 0xD8A4, 0x4E11, 0xB3F3, 0x4E12, 0x8145, + 0x4E13, 0xD7A8, 0x4E14, 0xC7D2, 0x4E15, 0xD8A7, 0x4E16, 0xCAC0, 0x4E17, 0x8146, 0x4E18, 0xC7F0, 0x4E19, 0xB1FB, 0x4E1A, 0xD2B5, + 0x4E1B, 0xB4D4, 0x4E1C, 0xB6AB, 0x4E1D, 0xCBBF, 0x4E1E, 0xD8A9, 0x4E1F, 0x8147, 0x4E20, 0x8148, 0x4E21, 0x8149, 0x4E22, 0xB6AA, + 0x4E23, 0x814A, 0x4E24, 0xC1BD, 0x4E25, 0xD1CF, 0x4E26, 0x814B, 0x4E27, 0xC9A5, 0x4E28, 0xD8AD, 0x4E29, 0x814C, 0x4E2A, 0xB8F6, + 0x4E2B, 0xD1BE, 0x4E2C, 0xE3DC, 0x4E2D, 0xD6D0, 0x4E2E, 0x814D, 0x4E2F, 0x814E, 0x4E30, 0xB7E1, 0x4E31, 0x814F, 0x4E32, 0xB4AE, + 0x4E33, 0x8150, 0x4E34, 0xC1D9, 0x4E35, 0x8151, 0x4E36, 0xD8BC, 0x4E37, 0x8152, 0x4E38, 0xCDE8, 0x4E39, 0xB5A4, 0x4E3A, 0xCEAA, + 0x4E3B, 0xD6F7, 0x4E3C, 0x8153, 0x4E3D, 0xC0F6, 0x4E3E, 0xBED9, 0x4E3F, 0xD8AF, 0x4E40, 0x8154, 0x4E41, 0x8155, 0x4E42, 0x8156, + 0x4E43, 0xC4CB, 0x4E44, 0x8157, 0x4E45, 0xBEC3, 0x4E46, 0x8158, 0x4E47, 0xD8B1, 0x4E48, 0xC3B4, 0x4E49, 0xD2E5, 0x4E4A, 0x8159, + 0x4E4B, 0xD6AE, 0x4E4C, 0xCEDA, 0x4E4D, 0xD5A7, 0x4E4E, 0xBAF5, 0x4E4F, 0xB7A6, 0x4E50, 0xC0D6, 0x4E51, 0x815A, 0x4E52, 0xC6B9, + 0x4E53, 0xC5D2, 0x4E54, 0xC7C7, 0x4E55, 0x815B, 0x4E56, 0xB9D4, 0x4E57, 0x815C, 0x4E58, 0xB3CB, 0x4E59, 0xD2D2, 0x4E5A, 0x815D, + 0x4E5B, 0x815E, 0x4E5C, 0xD8BF, 0x4E5D, 0xBEC5, 0x4E5E, 0xC6F2, 0x4E5F, 0xD2B2, 0x4E60, 0xCFB0, 0x4E61, 0xCFE7, 0x4E62, 0x815F, + 0x4E63, 0x8160, 0x4E64, 0x8161, 0x4E65, 0x8162, 0x4E66, 0xCAE9, 0x4E67, 0x8163, 0x4E68, 0x8164, 0x4E69, 0xD8C0, 0x4E6A, 0x8165, + 0x4E6B, 0x8166, 0x4E6C, 0x8167, 0x4E6D, 0x8168, 0x4E6E, 0x8169, 0x4E6F, 0x816A, 0x4E70, 0xC2F2, 0x4E71, 0xC2D2, 0x4E72, 0x816B, + 0x4E73, 0xC8E9, 0x4E74, 0x816C, 0x4E75, 0x816D, 0x4E76, 0x816E, 0x4E77, 0x816F, 0x4E78, 0x8170, 0x4E79, 0x8171, 0x4E7A, 0x8172, + 0x4E7B, 0x8173, 0x4E7C, 0x8174, 0x4E7D, 0x8175, 0x4E7E, 0xC7AC, 0x4E7F, 0x8176, 0x4E80, 0x8177, 0x4E81, 0x8178, 0x4E82, 0x8179, + 0x4E83, 0x817A, 0x4E84, 0x817B, 0x4E85, 0x817C, 0x4E86, 0xC1CB, 0x4E87, 0x817D, 0x4E88, 0xD3E8, 0x4E89, 0xD5F9, 0x4E8A, 0x817E, + 0x4E8B, 0xCAC2, 0x4E8C, 0xB6FE, 0x4E8D, 0xD8A1, 0x4E8E, 0xD3DA, 0x4E8F, 0xBFF7, 0x4E90, 0x8180, 0x4E91, 0xD4C6, 0x4E92, 0xBBA5, + 0x4E93, 0xD8C1, 0x4E94, 0xCEE5, 0x4E95, 0xBEAE, 0x4E96, 0x8181, 0x4E97, 0x8182, 0x4E98, 0xD8A8, 0x4E99, 0x8183, 0x4E9A, 0xD1C7, + 0x4E9B, 0xD0A9, 0x4E9C, 0x8184, 0x4E9D, 0x8185, 0x4E9E, 0x8186, 0x4E9F, 0xD8BD, 0x4EA0, 0xD9EF, 0x4EA1, 0xCDF6, 0x4EA2, 0xBFBA, + 0x4EA3, 0x8187, 0x4EA4, 0xBDBB, 0x4EA5, 0xBAA5, 0x4EA6, 0xD2E0, 0x4EA7, 0xB2FA, 0x4EA8, 0xBAE0, 0x4EA9, 0xC4B6, 0x4EAA, 0x8188, + 0x4EAB, 0xCFED, 0x4EAC, 0xBEA9, 0x4EAD, 0xCDA4, 0x4EAE, 0xC1C1, 0x4EAF, 0x8189, 0x4EB0, 0x818A, 0x4EB1, 0x818B, 0x4EB2, 0xC7D7, + 0x4EB3, 0xD9F1, 0x4EB4, 0x818C, 0x4EB5, 0xD9F4, 0x4EB6, 0x818D, 0x4EB7, 0x818E, 0x4EB8, 0x818F, 0x4EB9, 0x8190, 0x4EBA, 0xC8CB, + 0x4EBB, 0xD8E9, 0x4EBC, 0x8191, 0x4EBD, 0x8192, 0x4EBE, 0x8193, 0x4EBF, 0xD2DA, 0x4EC0, 0xCAB2, 0x4EC1, 0xC8CA, 0x4EC2, 0xD8EC, + 0x4EC3, 0xD8EA, 0x4EC4, 0xD8C6, 0x4EC5, 0xBDF6, 0x4EC6, 0xC6CD, 0x4EC7, 0xB3F0, 0x4EC8, 0x8194, 0x4EC9, 0xD8EB, 0x4ECA, 0xBDF1, + 0x4ECB, 0xBDE9, 0x4ECC, 0x8195, 0x4ECD, 0xC8D4, 0x4ECE, 0xB4D3, 0x4ECF, 0x8196, 0x4ED0, 0x8197, 0x4ED1, 0xC2D8, 0x4ED2, 0x8198, + 0x4ED3, 0xB2D6, 0x4ED4, 0xD7D0, 0x4ED5, 0xCACB, 0x4ED6, 0xCBFB, 0x4ED7, 0xD5CC, 0x4ED8, 0xB8B6, 0x4ED9, 0xCFC9, 0x4EDA, 0x8199, + 0x4EDB, 0x819A, 0x4EDC, 0x819B, 0x4EDD, 0xD9DA, 0x4EDE, 0xD8F0, 0x4EDF, 0xC7AA, 0x4EE0, 0x819C, 0x4EE1, 0xD8EE, 0x4EE2, 0x819D, + 0x4EE3, 0xB4FA, 0x4EE4, 0xC1EE, 0x4EE5, 0xD2D4, 0x4EE6, 0x819E, 0x4EE7, 0x819F, 0x4EE8, 0xD8ED, 0x4EE9, 0x81A0, 0x4EEA, 0xD2C7, + 0x4EEB, 0xD8EF, 0x4EEC, 0xC3C7, 0x4EED, 0x81A1, 0x4EEE, 0x81A2, 0x4EEF, 0x81A3, 0x4EF0, 0xD1F6, 0x4EF1, 0x81A4, 0x4EF2, 0xD6D9, + 0x4EF3, 0xD8F2, 0x4EF4, 0x81A5, 0x4EF5, 0xD8F5, 0x4EF6, 0xBCFE, 0x4EF7, 0xBCDB, 0x4EF8, 0x81A6, 0x4EF9, 0x81A7, 0x4EFA, 0x81A8, + 0x4EFB, 0xC8CE, 0x4EFC, 0x81A9, 0x4EFD, 0xB7DD, 0x4EFE, 0x81AA, 0x4EFF, 0xB7C2, 0x4F00, 0x81AB, 0x4F01, 0xC6F3, 0x4F02, 0x81AC, + 0x4F03, 0x81AD, 0x4F04, 0x81AE, 0x4F05, 0x81AF, 0x4F06, 0x81B0, 0x4F07, 0x81B1, 0x4F08, 0x81B2, 0x4F09, 0xD8F8, 0x4F0A, 0xD2C1, + 0x4F0B, 0x81B3, 0x4F0C, 0x81B4, 0x4F0D, 0xCEE9, 0x4F0E, 0xBCBF, 0x4F0F, 0xB7FC, 0x4F10, 0xB7A5, 0x4F11, 0xD0DD, 0x4F12, 0x81B5, + 0x4F13, 0x81B6, 0x4F14, 0x81B7, 0x4F15, 0x81B8, 0x4F16, 0x81B9, 0x4F17, 0xD6DA, 0x4F18, 0xD3C5, 0x4F19, 0xBBEF, 0x4F1A, 0xBBE1, + 0x4F1B, 0xD8F1, 0x4F1C, 0x81BA, 0x4F1D, 0x81BB, 0x4F1E, 0xC9A1, 0x4F1F, 0xCEB0, 0x4F20, 0xB4AB, 0x4F21, 0x81BC, 0x4F22, 0xD8F3, + 0x4F23, 0x81BD, 0x4F24, 0xC9CB, 0x4F25, 0xD8F6, 0x4F26, 0xC2D7, 0x4F27, 0xD8F7, 0x4F28, 0x81BE, 0x4F29, 0x81BF, 0x4F2A, 0xCEB1, + 0x4F2B, 0xD8F9, 0x4F2C, 0x81C0, 0x4F2D, 0x81C1, 0x4F2E, 0x81C2, 0x4F2F, 0xB2AE, 0x4F30, 0xB9C0, 0x4F31, 0x81C3, 0x4F32, 0xD9A3, + 0x4F33, 0x81C4, 0x4F34, 0xB0E9, 0x4F35, 0x81C5, 0x4F36, 0xC1E6, 0x4F37, 0x81C6, 0x4F38, 0xC9EC, 0x4F39, 0x81C7, 0x4F3A, 0xCBC5, + 0x4F3B, 0x81C8, 0x4F3C, 0xCBC6, 0x4F3D, 0xD9A4, 0x4F3E, 0x81C9, 0x4F3F, 0x81CA, 0x4F40, 0x81CB, 0x4F41, 0x81CC, 0x4F42, 0x81CD, + 0x4F43, 0xB5E8, 0x4F44, 0x81CE, 0x4F45, 0x81CF, 0x4F46, 0xB5AB, 0x4F47, 0x81D0, 0x4F48, 0x81D1, 0x4F49, 0x81D2, 0x4F4A, 0x81D3, + 0x4F4B, 0x81D4, 0x4F4C, 0x81D5, 0x4F4D, 0xCEBB, 0x4F4E, 0xB5CD, 0x4F4F, 0xD7A1, 0x4F50, 0xD7F4, 0x4F51, 0xD3D3, 0x4F52, 0x81D6, + 0x4F53, 0xCCE5, 0x4F54, 0x81D7, 0x4F55, 0xBACE, 0x4F56, 0x81D8, 0x4F57, 0xD9A2, 0x4F58, 0xD9DC, 0x4F59, 0xD3E0, 0x4F5A, 0xD8FD, + 0x4F5B, 0xB7F0, 0x4F5C, 0xD7F7, 0x4F5D, 0xD8FE, 0x4F5E, 0xD8FA, 0x4F5F, 0xD9A1, 0x4F60, 0xC4E3, 0x4F61, 0x81D9, 0x4F62, 0x81DA, + 0x4F63, 0xD3B6, 0x4F64, 0xD8F4, 0x4F65, 0xD9DD, 0x4F66, 0x81DB, 0x4F67, 0xD8FB, 0x4F68, 0x81DC, 0x4F69, 0xC5E5, 0x4F6A, 0x81DD, + 0x4F6B, 0x81DE, 0x4F6C, 0xC0D0, 0x4F6D, 0x81DF, 0x4F6E, 0x81E0, 0x4F6F, 0xD1F0, 0x4F70, 0xB0DB, 0x4F71, 0x81E1, 0x4F72, 0x81E2, + 0x4F73, 0xBCD1, 0x4F74, 0xD9A6, 0x4F75, 0x81E3, 0x4F76, 0xD9A5, 0x4F77, 0x81E4, 0x4F78, 0x81E5, 0x4F79, 0x81E6, 0x4F7A, 0x81E7, + 0x4F7B, 0xD9AC, 0x4F7C, 0xD9AE, 0x4F7D, 0x81E8, 0x4F7E, 0xD9AB, 0x4F7F, 0xCAB9, 0x4F80, 0x81E9, 0x4F81, 0x81EA, 0x4F82, 0x81EB, + 0x4F83, 0xD9A9, 0x4F84, 0xD6B6, 0x4F85, 0x81EC, 0x4F86, 0x81ED, 0x4F87, 0x81EE, 0x4F88, 0xB3DE, 0x4F89, 0xD9A8, 0x4F8A, 0x81EF, + 0x4F8B, 0xC0FD, 0x4F8C, 0x81F0, 0x4F8D, 0xCACC, 0x4F8E, 0x81F1, 0x4F8F, 0xD9AA, 0x4F90, 0x81F2, 0x4F91, 0xD9A7, 0x4F92, 0x81F3, + 0x4F93, 0x81F4, 0x4F94, 0xD9B0, 0x4F95, 0x81F5, 0x4F96, 0x81F6, 0x4F97, 0xB6B1, 0x4F98, 0x81F7, 0x4F99, 0x81F8, 0x4F9A, 0x81F9, + 0x4F9B, 0xB9A9, 0x4F9C, 0x81FA, 0x4F9D, 0xD2C0, 0x4F9E, 0x81FB, 0x4F9F, 0x81FC, 0x4FA0, 0xCFC0, 0x4FA1, 0x81FD, 0x4FA2, 0x81FE, + 0x4FA3, 0xC2C2, 0x4FA4, 0x8240, 0x4FA5, 0xBDC4, 0x4FA6, 0xD5EC, 0x4FA7, 0xB2E0, 0x4FA8, 0xC7C8, 0x4FA9, 0xBFEB, 0x4FAA, 0xD9AD, + 0x4FAB, 0x8241, 0x4FAC, 0xD9AF, 0x4FAD, 0x8242, 0x4FAE, 0xCEEA, 0x4FAF, 0xBAEE, 0x4FB0, 0x8243, 0x4FB1, 0x8244, 0x4FB2, 0x8245, + 0x4FB3, 0x8246, 0x4FB4, 0x8247, 0x4FB5, 0xC7D6, 0x4FB6, 0x8248, 0x4FB7, 0x8249, 0x4FB8, 0x824A, 0x4FB9, 0x824B, 0x4FBA, 0x824C, + 0x4FBB, 0x824D, 0x4FBC, 0x824E, 0x4FBD, 0x824F, 0x4FBE, 0x8250, 0x4FBF, 0xB1E3, 0x4FC0, 0x8251, 0x4FC1, 0x8252, 0x4FC2, 0x8253, + 0x4FC3, 0xB4D9, 0x4FC4, 0xB6ED, 0x4FC5, 0xD9B4, 0x4FC6, 0x8254, 0x4FC7, 0x8255, 0x4FC8, 0x8256, 0x4FC9, 0x8257, 0x4FCA, 0xBFA1, + 0x4FCB, 0x8258, 0x4FCC, 0x8259, 0x4FCD, 0x825A, 0x4FCE, 0xD9DE, 0x4FCF, 0xC7CE, 0x4FD0, 0xC0FE, 0x4FD1, 0xD9B8, 0x4FD2, 0x825B, + 0x4FD3, 0x825C, 0x4FD4, 0x825D, 0x4FD5, 0x825E, 0x4FD6, 0x825F, 0x4FD7, 0xCBD7, 0x4FD8, 0xB7FD, 0x4FD9, 0x8260, 0x4FDA, 0xD9B5, + 0x4FDB, 0x8261, 0x4FDC, 0xD9B7, 0x4FDD, 0xB1A3, 0x4FDE, 0xD3E1, 0x4FDF, 0xD9B9, 0x4FE0, 0x8262, 0x4FE1, 0xD0C5, 0x4FE2, 0x8263, + 0x4FE3, 0xD9B6, 0x4FE4, 0x8264, 0x4FE5, 0x8265, 0x4FE6, 0xD9B1, 0x4FE7, 0x8266, 0x4FE8, 0xD9B2, 0x4FE9, 0xC1A9, 0x4FEA, 0xD9B3, + 0x4FEB, 0x8267, 0x4FEC, 0x8268, 0x4FED, 0xBCF3, 0x4FEE, 0xD0DE, 0x4FEF, 0xB8A9, 0x4FF0, 0x8269, 0x4FF1, 0xBEE3, 0x4FF2, 0x826A, + 0x4FF3, 0xD9BD, 0x4FF4, 0x826B, 0x4FF5, 0x826C, 0x4FF6, 0x826D, 0x4FF7, 0x826E, 0x4FF8, 0xD9BA, 0x4FF9, 0x826F, 0x4FFA, 0xB0B3, + 0x4FFB, 0x8270, 0x4FFC, 0x8271, 0x4FFD, 0x8272, 0x4FFE, 0xD9C2, 0x4FFF, 0x8273, 0x5000, 0x8274, 0x5001, 0x8275, 0x5002, 0x8276, + 0x5003, 0x8277, 0x5004, 0x8278, 0x5005, 0x8279, 0x5006, 0x827A, 0x5007, 0x827B, 0x5008, 0x827C, 0x5009, 0x827D, 0x500A, 0x827E, + 0x500B, 0x8280, 0x500C, 0xD9C4, 0x500D, 0xB1B6, 0x500E, 0x8281, 0x500F, 0xD9BF, 0x5010, 0x8282, 0x5011, 0x8283, 0x5012, 0xB5B9, + 0x5013, 0x8284, 0x5014, 0xBEF3, 0x5015, 0x8285, 0x5016, 0x8286, 0x5017, 0x8287, 0x5018, 0xCCC8, 0x5019, 0xBAF2, 0x501A, 0xD2D0, + 0x501B, 0x8288, 0x501C, 0xD9C3, 0x501D, 0x8289, 0x501E, 0x828A, 0x501F, 0xBDE8, 0x5020, 0x828B, 0x5021, 0xB3AB, 0x5022, 0x828C, + 0x5023, 0x828D, 0x5024, 0x828E, 0x5025, 0xD9C5, 0x5026, 0xBEEB, 0x5027, 0x828F, 0x5028, 0xD9C6, 0x5029, 0xD9BB, 0x502A, 0xC4DF, + 0x502B, 0x8290, 0x502C, 0xD9BE, 0x502D, 0xD9C1, 0x502E, 0xD9C0, 0x502F, 0x8291, 0x5030, 0x8292, 0x5031, 0x8293, 0x5032, 0x8294, + 0x5033, 0x8295, 0x5034, 0x8296, 0x5035, 0x8297, 0x5036, 0x8298, 0x5037, 0x8299, 0x5038, 0x829A, 0x5039, 0x829B, 0x503A, 0xD5AE, + 0x503B, 0x829C, 0x503C, 0xD6B5, 0x503D, 0x829D, 0x503E, 0xC7E3, 0x503F, 0x829E, 0x5040, 0x829F, 0x5041, 0x82A0, 0x5042, 0x82A1, + 0x5043, 0xD9C8, 0x5044, 0x82A2, 0x5045, 0x82A3, 0x5046, 0x82A4, 0x5047, 0xBCD9, 0x5048, 0xD9CA, 0x5049, 0x82A5, 0x504A, 0x82A6, + 0x504B, 0x82A7, 0x504C, 0xD9BC, 0x504D, 0x82A8, 0x504E, 0xD9CB, 0x504F, 0xC6AB, 0x5050, 0x82A9, 0x5051, 0x82AA, 0x5052, 0x82AB, + 0x5053, 0x82AC, 0x5054, 0x82AD, 0x5055, 0xD9C9, 0x5056, 0x82AE, 0x5057, 0x82AF, 0x5058, 0x82B0, 0x5059, 0x82B1, 0x505A, 0xD7F6, + 0x505B, 0x82B2, 0x505C, 0xCDA3, 0x505D, 0x82B3, 0x505E, 0x82B4, 0x505F, 0x82B5, 0x5060, 0x82B6, 0x5061, 0x82B7, 0x5062, 0x82B8, + 0x5063, 0x82B9, 0x5064, 0x82BA, 0x5065, 0xBDA1, 0x5066, 0x82BB, 0x5067, 0x82BC, 0x5068, 0x82BD, 0x5069, 0x82BE, 0x506A, 0x82BF, + 0x506B, 0x82C0, 0x506C, 0xD9CC, 0x506D, 0x82C1, 0x506E, 0x82C2, 0x506F, 0x82C3, 0x5070, 0x82C4, 0x5071, 0x82C5, 0x5072, 0x82C6, + 0x5073, 0x82C7, 0x5074, 0x82C8, 0x5075, 0x82C9, 0x5076, 0xC5BC, 0x5077, 0xCDB5, 0x5078, 0x82CA, 0x5079, 0x82CB, 0x507A, 0x82CC, + 0x507B, 0xD9CD, 0x507C, 0x82CD, 0x507D, 0x82CE, 0x507E, 0xD9C7, 0x507F, 0xB3A5, 0x5080, 0xBFFE, 0x5081, 0x82CF, 0x5082, 0x82D0, + 0x5083, 0x82D1, 0x5084, 0x82D2, 0x5085, 0xB8B5, 0x5086, 0x82D3, 0x5087, 0x82D4, 0x5088, 0xC0FC, 0x5089, 0x82D5, 0x508A, 0x82D6, + 0x508B, 0x82D7, 0x508C, 0x82D8, 0x508D, 0xB0F8, 0x508E, 0x82D9, 0x508F, 0x82DA, 0x5090, 0x82DB, 0x5091, 0x82DC, 0x5092, 0x82DD, + 0x5093, 0x82DE, 0x5094, 0x82DF, 0x5095, 0x82E0, 0x5096, 0x82E1, 0x5097, 0x82E2, 0x5098, 0x82E3, 0x5099, 0x82E4, 0x509A, 0x82E5, + 0x509B, 0x82E6, 0x509C, 0x82E7, 0x509D, 0x82E8, 0x509E, 0x82E9, 0x509F, 0x82EA, 0x50A0, 0x82EB, 0x50A1, 0x82EC, 0x50A2, 0x82ED, + 0x50A3, 0xB4F6, 0x50A4, 0x82EE, 0x50A5, 0xD9CE, 0x50A6, 0x82EF, 0x50A7, 0xD9CF, 0x50A8, 0xB4A2, 0x50A9, 0xD9D0, 0x50AA, 0x82F0, + 0x50AB, 0x82F1, 0x50AC, 0xB4DF, 0x50AD, 0x82F2, 0x50AE, 0x82F3, 0x50AF, 0x82F4, 0x50B0, 0x82F5, 0x50B1, 0x82F6, 0x50B2, 0xB0C1, + 0x50B3, 0x82F7, 0x50B4, 0x82F8, 0x50B5, 0x82F9, 0x50B6, 0x82FA, 0x50B7, 0x82FB, 0x50B8, 0x82FC, 0x50B9, 0x82FD, 0x50BA, 0xD9D1, + 0x50BB, 0xC9B5, 0x50BC, 0x82FE, 0x50BD, 0x8340, 0x50BE, 0x8341, 0x50BF, 0x8342, 0x50C0, 0x8343, 0x50C1, 0x8344, 0x50C2, 0x8345, + 0x50C3, 0x8346, 0x50C4, 0x8347, 0x50C5, 0x8348, 0x50C6, 0x8349, 0x50C7, 0x834A, 0x50C8, 0x834B, 0x50C9, 0x834C, 0x50CA, 0x834D, + 0x50CB, 0x834E, 0x50CC, 0x834F, 0x50CD, 0x8350, 0x50CE, 0x8351, 0x50CF, 0xCFF1, 0x50D0, 0x8352, 0x50D1, 0x8353, 0x50D2, 0x8354, + 0x50D3, 0x8355, 0x50D4, 0x8356, 0x50D5, 0x8357, 0x50D6, 0xD9D2, 0x50D7, 0x8358, 0x50D8, 0x8359, 0x50D9, 0x835A, 0x50DA, 0xC1C5, + 0x50DB, 0x835B, 0x50DC, 0x835C, 0x50DD, 0x835D, 0x50DE, 0x835E, 0x50DF, 0x835F, 0x50E0, 0x8360, 0x50E1, 0x8361, 0x50E2, 0x8362, + 0x50E3, 0x8363, 0x50E4, 0x8364, 0x50E5, 0x8365, 0x50E6, 0xD9D6, 0x50E7, 0xC9AE, 0x50E8, 0x8366, 0x50E9, 0x8367, 0x50EA, 0x8368, + 0x50EB, 0x8369, 0x50EC, 0xD9D5, 0x50ED, 0xD9D4, 0x50EE, 0xD9D7, 0x50EF, 0x836A, 0x50F0, 0x836B, 0x50F1, 0x836C, 0x50F2, 0x836D, + 0x50F3, 0xCBDB, 0x50F4, 0x836E, 0x50F5, 0xBDA9, 0x50F6, 0x836F, 0x50F7, 0x8370, 0x50F8, 0x8371, 0x50F9, 0x8372, 0x50FA, 0x8373, + 0x50FB, 0xC6A7, 0x50FC, 0x8374, 0x50FD, 0x8375, 0x50FE, 0x8376, 0x50FF, 0x8377, 0x5100, 0x8378, 0x5101, 0x8379, 0x5102, 0x837A, + 0x5103, 0x837B, 0x5104, 0x837C, 0x5105, 0x837D, 0x5106, 0xD9D3, 0x5107, 0xD9D8, 0x5108, 0x837E, 0x5109, 0x8380, 0x510A, 0x8381, + 0x510B, 0xD9D9, 0x510C, 0x8382, 0x510D, 0x8383, 0x510E, 0x8384, 0x510F, 0x8385, 0x5110, 0x8386, 0x5111, 0x8387, 0x5112, 0xC8E5, + 0x5113, 0x8388, 0x5114, 0x8389, 0x5115, 0x838A, 0x5116, 0x838B, 0x5117, 0x838C, 0x5118, 0x838D, 0x5119, 0x838E, 0x511A, 0x838F, + 0x511B, 0x8390, 0x511C, 0x8391, 0x511D, 0x8392, 0x511E, 0x8393, 0x511F, 0x8394, 0x5120, 0x8395, 0x5121, 0xC0DC, 0x5122, 0x8396, + 0x5123, 0x8397, 0x5124, 0x8398, 0x5125, 0x8399, 0x5126, 0x839A, 0x5127, 0x839B, 0x5128, 0x839C, 0x5129, 0x839D, 0x512A, 0x839E, + 0x512B, 0x839F, 0x512C, 0x83A0, 0x512D, 0x83A1, 0x512E, 0x83A2, 0x512F, 0x83A3, 0x5130, 0x83A4, 0x5131, 0x83A5, 0x5132, 0x83A6, + 0x5133, 0x83A7, 0x5134, 0x83A8, 0x5135, 0x83A9, 0x5136, 0x83AA, 0x5137, 0x83AB, 0x5138, 0x83AC, 0x5139, 0x83AD, 0x513A, 0x83AE, + 0x513B, 0x83AF, 0x513C, 0x83B0, 0x513D, 0x83B1, 0x513E, 0x83B2, 0x513F, 0xB6F9, 0x5140, 0xD8A3, 0x5141, 0xD4CA, 0x5142, 0x83B3, + 0x5143, 0xD4AA, 0x5144, 0xD0D6, 0x5145, 0xB3E4, 0x5146, 0xD5D7, 0x5147, 0x83B4, 0x5148, 0xCFC8, 0x5149, 0xB9E2, 0x514A, 0x83B5, + 0x514B, 0xBFCB, 0x514C, 0x83B6, 0x514D, 0xC3E2, 0x514E, 0x83B7, 0x514F, 0x83B8, 0x5150, 0x83B9, 0x5151, 0xB6D2, 0x5152, 0x83BA, + 0x5153, 0x83BB, 0x5154, 0xCDC3, 0x5155, 0xD9EE, 0x5156, 0xD9F0, 0x5157, 0x83BC, 0x5158, 0x83BD, 0x5159, 0x83BE, 0x515A, 0xB5B3, + 0x515B, 0x83BF, 0x515C, 0xB6B5, 0x515D, 0x83C0, 0x515E, 0x83C1, 0x515F, 0x83C2, 0x5160, 0x83C3, 0x5161, 0x83C4, 0x5162, 0xBEA4, + 0x5163, 0x83C5, 0x5164, 0x83C6, 0x5165, 0xC8EB, 0x5166, 0x83C7, 0x5167, 0x83C8, 0x5168, 0xC8AB, 0x5169, 0x83C9, 0x516A, 0x83CA, + 0x516B, 0xB0CB, 0x516C, 0xB9AB, 0x516D, 0xC1F9, 0x516E, 0xD9E2, 0x516F, 0x83CB, 0x5170, 0xC0BC, 0x5171, 0xB9B2, 0x5172, 0x83CC, + 0x5173, 0xB9D8, 0x5174, 0xD0CB, 0x5175, 0xB1F8, 0x5176, 0xC6E4, 0x5177, 0xBEDF, 0x5178, 0xB5E4, 0x5179, 0xD7C8, 0x517A, 0x83CD, + 0x517B, 0xD1F8, 0x517C, 0xBCE6, 0x517D, 0xCADE, 0x517E, 0x83CE, 0x517F, 0x83CF, 0x5180, 0xBCBD, 0x5181, 0xD9E6, 0x5182, 0xD8E7, + 0x5183, 0x83D0, 0x5184, 0x83D1, 0x5185, 0xC4DA, 0x5186, 0x83D2, 0x5187, 0x83D3, 0x5188, 0xB8D4, 0x5189, 0xC8BD, 0x518A, 0x83D4, + 0x518B, 0x83D5, 0x518C, 0xB2E1, 0x518D, 0xD4D9, 0x518E, 0x83D6, 0x518F, 0x83D7, 0x5190, 0x83D8, 0x5191, 0x83D9, 0x5192, 0xC3B0, + 0x5193, 0x83DA, 0x5194, 0x83DB, 0x5195, 0xC3E1, 0x5196, 0xDAA2, 0x5197, 0xC8DF, 0x5198, 0x83DC, 0x5199, 0xD0B4, 0x519A, 0x83DD, + 0x519B, 0xBEFC, 0x519C, 0xC5A9, 0x519D, 0x83DE, 0x519E, 0x83DF, 0x519F, 0x83E0, 0x51A0, 0xB9DA, 0x51A1, 0x83E1, 0x51A2, 0xDAA3, + 0x51A3, 0x83E2, 0x51A4, 0xD4A9, 0x51A5, 0xDAA4, 0x51A6, 0x83E3, 0x51A7, 0x83E4, 0x51A8, 0x83E5, 0x51A9, 0x83E6, 0x51AA, 0x83E7, + 0x51AB, 0xD9FB, 0x51AC, 0xB6AC, 0x51AD, 0x83E8, 0x51AE, 0x83E9, 0x51AF, 0xB7EB, 0x51B0, 0xB1F9, 0x51B1, 0xD9FC, 0x51B2, 0xB3E5, + 0x51B3, 0xBEF6, 0x51B4, 0x83EA, 0x51B5, 0xBFF6, 0x51B6, 0xD2B1, 0x51B7, 0xC0E4, 0x51B8, 0x83EB, 0x51B9, 0x83EC, 0x51BA, 0x83ED, + 0x51BB, 0xB6B3, 0x51BC, 0xD9FE, 0x51BD, 0xD9FD, 0x51BE, 0x83EE, 0x51BF, 0x83EF, 0x51C0, 0xBEBB, 0x51C1, 0x83F0, 0x51C2, 0x83F1, + 0x51C3, 0x83F2, 0x51C4, 0xC6E0, 0x51C5, 0x83F3, 0x51C6, 0xD7BC, 0x51C7, 0xDAA1, 0x51C8, 0x83F4, 0x51C9, 0xC1B9, 0x51CA, 0x83F5, + 0x51CB, 0xB5F2, 0x51CC, 0xC1E8, 0x51CD, 0x83F6, 0x51CE, 0x83F7, 0x51CF, 0xBCF5, 0x51D0, 0x83F8, 0x51D1, 0xB4D5, 0x51D2, 0x83F9, + 0x51D3, 0x83FA, 0x51D4, 0x83FB, 0x51D5, 0x83FC, 0x51D6, 0x83FD, 0x51D7, 0x83FE, 0x51D8, 0x8440, 0x51D9, 0x8441, 0x51DA, 0x8442, + 0x51DB, 0xC1DD, 0x51DC, 0x8443, 0x51DD, 0xC4FD, 0x51DE, 0x8444, 0x51DF, 0x8445, 0x51E0, 0xBCB8, 0x51E1, 0xB7B2, 0x51E2, 0x8446, + 0x51E3, 0x8447, 0x51E4, 0xB7EF, 0x51E5, 0x8448, 0x51E6, 0x8449, 0x51E7, 0x844A, 0x51E8, 0x844B, 0x51E9, 0x844C, 0x51EA, 0x844D, + 0x51EB, 0xD9EC, 0x51EC, 0x844E, 0x51ED, 0xC6BE, 0x51EE, 0x844F, 0x51EF, 0xBFAD, 0x51F0, 0xBBCB, 0x51F1, 0x8450, 0x51F2, 0x8451, + 0x51F3, 0xB5CA, 0x51F4, 0x8452, 0x51F5, 0xDBC9, 0x51F6, 0xD0D7, 0x51F7, 0x8453, 0x51F8, 0xCDB9, 0x51F9, 0xB0BC, 0x51FA, 0xB3F6, + 0x51FB, 0xBBF7, 0x51FC, 0xDBCA, 0x51FD, 0xBAAF, 0x51FE, 0x8454, 0x51FF, 0xD4E4, 0x5200, 0xB5B6, 0x5201, 0xB5F3, 0x5202, 0xD8D6, + 0x5203, 0xC8D0, 0x5204, 0x8455, 0x5205, 0x8456, 0x5206, 0xB7D6, 0x5207, 0xC7D0, 0x5208, 0xD8D7, 0x5209, 0x8457, 0x520A, 0xBFAF, + 0x520B, 0x8458, 0x520C, 0x8459, 0x520D, 0xDBBB, 0x520E, 0xD8D8, 0x520F, 0x845A, 0x5210, 0x845B, 0x5211, 0xD0CC, 0x5212, 0xBBAE, + 0x5213, 0x845C, 0x5214, 0x845D, 0x5215, 0x845E, 0x5216, 0xEBBE, 0x5217, 0xC1D0, 0x5218, 0xC1F5, 0x5219, 0xD4F2, 0x521A, 0xB8D5, + 0x521B, 0xB4B4, 0x521C, 0x845F, 0x521D, 0xB3F5, 0x521E, 0x8460, 0x521F, 0x8461, 0x5220, 0xC9BE, 0x5221, 0x8462, 0x5222, 0x8463, + 0x5223, 0x8464, 0x5224, 0xC5D0, 0x5225, 0x8465, 0x5226, 0x8466, 0x5227, 0x8467, 0x5228, 0xC5D9, 0x5229, 0xC0FB, 0x522A, 0x8468, + 0x522B, 0xB1F0, 0x522C, 0x8469, 0x522D, 0xD8D9, 0x522E, 0xB9CE, 0x522F, 0x846A, 0x5230, 0xB5BD, 0x5231, 0x846B, 0x5232, 0x846C, + 0x5233, 0xD8DA, 0x5234, 0x846D, 0x5235, 0x846E, 0x5236, 0xD6C6, 0x5237, 0xCBA2, 0x5238, 0xC8AF, 0x5239, 0xC9B2, 0x523A, 0xB4CC, + 0x523B, 0xBFCC, 0x523C, 0x846F, 0x523D, 0xB9F4, 0x523E, 0x8470, 0x523F, 0xD8DB, 0x5240, 0xD8DC, 0x5241, 0xB6E7, 0x5242, 0xBCC1, + 0x5243, 0xCCEA, 0x5244, 0x8471, 0x5245, 0x8472, 0x5246, 0x8473, 0x5247, 0x8474, 0x5248, 0x8475, 0x5249, 0x8476, 0x524A, 0xCFF7, + 0x524B, 0x8477, 0x524C, 0xD8DD, 0x524D, 0xC7B0, 0x524E, 0x8478, 0x524F, 0x8479, 0x5250, 0xB9D0, 0x5251, 0xBDA3, 0x5252, 0x847A, + 0x5253, 0x847B, 0x5254, 0xCCDE, 0x5255, 0x847C, 0x5256, 0xC6CA, 0x5257, 0x847D, 0x5258, 0x847E, 0x5259, 0x8480, 0x525A, 0x8481, + 0x525B, 0x8482, 0x525C, 0xD8E0, 0x525D, 0x8483, 0x525E, 0xD8DE, 0x525F, 0x8484, 0x5260, 0x8485, 0x5261, 0xD8DF, 0x5262, 0x8486, + 0x5263, 0x8487, 0x5264, 0x8488, 0x5265, 0xB0FE, 0x5266, 0x8489, 0x5267, 0xBEE7, 0x5268, 0x848A, 0x5269, 0xCAA3, 0x526A, 0xBCF4, + 0x526B, 0x848B, 0x526C, 0x848C, 0x526D, 0x848D, 0x526E, 0x848E, 0x526F, 0xB8B1, 0x5270, 0x848F, 0x5271, 0x8490, 0x5272, 0xB8EE, + 0x5273, 0x8491, 0x5274, 0x8492, 0x5275, 0x8493, 0x5276, 0x8494, 0x5277, 0x8495, 0x5278, 0x8496, 0x5279, 0x8497, 0x527A, 0x8498, + 0x527B, 0x8499, 0x527C, 0x849A, 0x527D, 0xD8E2, 0x527E, 0x849B, 0x527F, 0xBDCB, 0x5280, 0x849C, 0x5281, 0xD8E4, 0x5282, 0xD8E3, + 0x5283, 0x849D, 0x5284, 0x849E, 0x5285, 0x849F, 0x5286, 0x84A0, 0x5287, 0x84A1, 0x5288, 0xC5FC, 0x5289, 0x84A2, 0x528A, 0x84A3, + 0x528B, 0x84A4, 0x528C, 0x84A5, 0x528D, 0x84A6, 0x528E, 0x84A7, 0x528F, 0x84A8, 0x5290, 0xD8E5, 0x5291, 0x84A9, 0x5292, 0x84AA, + 0x5293, 0xD8E6, 0x5294, 0x84AB, 0x5295, 0x84AC, 0x5296, 0x84AD, 0x5297, 0x84AE, 0x5298, 0x84AF, 0x5299, 0x84B0, 0x529A, 0x84B1, + 0x529B, 0xC1A6, 0x529C, 0x84B2, 0x529D, 0xC8B0, 0x529E, 0xB0EC, 0x529F, 0xB9A6, 0x52A0, 0xBCD3, 0x52A1, 0xCEF1, 0x52A2, 0xDBBD, + 0x52A3, 0xC1D3, 0x52A4, 0x84B3, 0x52A5, 0x84B4, 0x52A6, 0x84B5, 0x52A7, 0x84B6, 0x52A8, 0xB6AF, 0x52A9, 0xD6FA, 0x52AA, 0xC5AC, + 0x52AB, 0xBDD9, 0x52AC, 0xDBBE, 0x52AD, 0xDBBF, 0x52AE, 0x84B7, 0x52AF, 0x84B8, 0x52B0, 0x84B9, 0x52B1, 0xC0F8, 0x52B2, 0xBEA2, + 0x52B3, 0xC0CD, 0x52B4, 0x84BA, 0x52B5, 0x84BB, 0x52B6, 0x84BC, 0x52B7, 0x84BD, 0x52B8, 0x84BE, 0x52B9, 0x84BF, 0x52BA, 0x84C0, + 0x52BB, 0x84C1, 0x52BC, 0x84C2, 0x52BD, 0x84C3, 0x52BE, 0xDBC0, 0x52BF, 0xCAC6, 0x52C0, 0x84C4, 0x52C1, 0x84C5, 0x52C2, 0x84C6, + 0x52C3, 0xB2AA, 0x52C4, 0x84C7, 0x52C5, 0x84C8, 0x52C6, 0x84C9, 0x52C7, 0xD3C2, 0x52C8, 0x84CA, 0x52C9, 0xC3E3, 0x52CA, 0x84CB, + 0x52CB, 0xD1AB, 0x52CC, 0x84CC, 0x52CD, 0x84CD, 0x52CE, 0x84CE, 0x52CF, 0x84CF, 0x52D0, 0xDBC2, 0x52D1, 0x84D0, 0x52D2, 0xC0D5, + 0x52D3, 0x84D1, 0x52D4, 0x84D2, 0x52D5, 0x84D3, 0x52D6, 0xDBC3, 0x52D7, 0x84D4, 0x52D8, 0xBFB1, 0x52D9, 0x84D5, 0x52DA, 0x84D6, + 0x52DB, 0x84D7, 0x52DC, 0x84D8, 0x52DD, 0x84D9, 0x52DE, 0x84DA, 0x52DF, 0xC4BC, 0x52E0, 0x84DB, 0x52E1, 0x84DC, 0x52E2, 0x84DD, + 0x52E3, 0x84DE, 0x52E4, 0xC7DA, 0x52E5, 0x84DF, 0x52E6, 0x84E0, 0x52E7, 0x84E1, 0x52E8, 0x84E2, 0x52E9, 0x84E3, 0x52EA, 0x84E4, + 0x52EB, 0x84E5, 0x52EC, 0x84E6, 0x52ED, 0x84E7, 0x52EE, 0x84E8, 0x52EF, 0x84E9, 0x52F0, 0xDBC4, 0x52F1, 0x84EA, 0x52F2, 0x84EB, + 0x52F3, 0x84EC, 0x52F4, 0x84ED, 0x52F5, 0x84EE, 0x52F6, 0x84EF, 0x52F7, 0x84F0, 0x52F8, 0x84F1, 0x52F9, 0xD9E8, 0x52FA, 0xC9D7, + 0x52FB, 0x84F2, 0x52FC, 0x84F3, 0x52FD, 0x84F4, 0x52FE, 0xB9B4, 0x52FF, 0xCEF0, 0x5300, 0xD4C8, 0x5301, 0x84F5, 0x5302, 0x84F6, + 0x5303, 0x84F7, 0x5304, 0x84F8, 0x5305, 0xB0FC, 0x5306, 0xB4D2, 0x5307, 0x84F9, 0x5308, 0xD0D9, 0x5309, 0x84FA, 0x530A, 0x84FB, + 0x530B, 0x84FC, 0x530C, 0x84FD, 0x530D, 0xD9E9, 0x530E, 0x84FE, 0x530F, 0xDECB, 0x5310, 0xD9EB, 0x5311, 0x8540, 0x5312, 0x8541, + 0x5313, 0x8542, 0x5314, 0x8543, 0x5315, 0xD8B0, 0x5316, 0xBBAF, 0x5317, 0xB1B1, 0x5318, 0x8544, 0x5319, 0xB3D7, 0x531A, 0xD8CE, + 0x531B, 0x8545, 0x531C, 0x8546, 0x531D, 0xD4D1, 0x531E, 0x8547, 0x531F, 0x8548, 0x5320, 0xBDB3, 0x5321, 0xBFEF, 0x5322, 0x8549, + 0x5323, 0xCFBB, 0x5324, 0x854A, 0x5325, 0x854B, 0x5326, 0xD8D0, 0x5327, 0x854C, 0x5328, 0x854D, 0x5329, 0x854E, 0x532A, 0xB7CB, + 0x532B, 0x854F, 0x532C, 0x8550, 0x532D, 0x8551, 0x532E, 0xD8D1, 0x532F, 0x8552, 0x5330, 0x8553, 0x5331, 0x8554, 0x5332, 0x8555, + 0x5333, 0x8556, 0x5334, 0x8557, 0x5335, 0x8558, 0x5336, 0x8559, 0x5337, 0x855A, 0x5338, 0x855B, 0x5339, 0xC6A5, 0x533A, 0xC7F8, + 0x533B, 0xD2BD, 0x533C, 0x855C, 0x533D, 0x855D, 0x533E, 0xD8D2, 0x533F, 0xC4E4, 0x5340, 0x855E, 0x5341, 0xCAAE, 0x5342, 0x855F, + 0x5343, 0xC7A7, 0x5344, 0x8560, 0x5345, 0xD8A6, 0x5346, 0x8561, 0x5347, 0xC9FD, 0x5348, 0xCEE7, 0x5349, 0xBBDC, 0x534A, 0xB0EB, + 0x534B, 0x8562, 0x534C, 0x8563, 0x534D, 0x8564, 0x534E, 0xBBAA, 0x534F, 0xD0AD, 0x5350, 0x8565, 0x5351, 0xB1B0, 0x5352, 0xD7E4, + 0x5353, 0xD7BF, 0x5354, 0x8566, 0x5355, 0xB5A5, 0x5356, 0xC2F4, 0x5357, 0xC4CF, 0x5358, 0x8567, 0x5359, 0x8568, 0x535A, 0xB2A9, + 0x535B, 0x8569, 0x535C, 0xB2B7, 0x535D, 0x856A, 0x535E, 0xB1E5, 0x535F, 0xDFB2, 0x5360, 0xD5BC, 0x5361, 0xBFA8, 0x5362, 0xC2AC, + 0x5363, 0xD8D5, 0x5364, 0xC2B1, 0x5365, 0x856B, 0x5366, 0xD8D4, 0x5367, 0xCED4, 0x5368, 0x856C, 0x5369, 0xDAE0, 0x536A, 0x856D, + 0x536B, 0xCEC0, 0x536C, 0x856E, 0x536D, 0x856F, 0x536E, 0xD8B4, 0x536F, 0xC3AE, 0x5370, 0xD3A1, 0x5371, 0xCEA3, 0x5372, 0x8570, + 0x5373, 0xBCB4, 0x5374, 0xC8B4, 0x5375, 0xC2D1, 0x5376, 0x8571, 0x5377, 0xBEED, 0x5378, 0xD0B6, 0x5379, 0x8572, 0x537A, 0xDAE1, + 0x537B, 0x8573, 0x537C, 0x8574, 0x537D, 0x8575, 0x537E, 0x8576, 0x537F, 0xC7E4, 0x5380, 0x8577, 0x5381, 0x8578, 0x5382, 0xB3A7, + 0x5383, 0x8579, 0x5384, 0xB6F2, 0x5385, 0xCCFC, 0x5386, 0xC0FA, 0x5387, 0x857A, 0x5388, 0x857B, 0x5389, 0xC0F7, 0x538A, 0x857C, + 0x538B, 0xD1B9, 0x538C, 0xD1E1, 0x538D, 0xD8C7, 0x538E, 0x857D, 0x538F, 0x857E, 0x5390, 0x8580, 0x5391, 0x8581, 0x5392, 0x8582, + 0x5393, 0x8583, 0x5394, 0x8584, 0x5395, 0xB2DE, 0x5396, 0x8585, 0x5397, 0x8586, 0x5398, 0xC0E5, 0x5399, 0x8587, 0x539A, 0xBAF1, + 0x539B, 0x8588, 0x539C, 0x8589, 0x539D, 0xD8C8, 0x539E, 0x858A, 0x539F, 0xD4AD, 0x53A0, 0x858B, 0x53A1, 0x858C, 0x53A2, 0xCFE1, + 0x53A3, 0xD8C9, 0x53A4, 0x858D, 0x53A5, 0xD8CA, 0x53A6, 0xCFC3, 0x53A7, 0x858E, 0x53A8, 0xB3F8, 0x53A9, 0xBEC7, 0x53AA, 0x858F, + 0x53AB, 0x8590, 0x53AC, 0x8591, 0x53AD, 0x8592, 0x53AE, 0xD8CB, 0x53AF, 0x8593, 0x53B0, 0x8594, 0x53B1, 0x8595, 0x53B2, 0x8596, + 0x53B3, 0x8597, 0x53B4, 0x8598, 0x53B5, 0x8599, 0x53B6, 0xDBCC, 0x53B7, 0x859A, 0x53B8, 0x859B, 0x53B9, 0x859C, 0x53BA, 0x859D, + 0x53BB, 0xC8A5, 0x53BC, 0x859E, 0x53BD, 0x859F, 0x53BE, 0x85A0, 0x53BF, 0xCFD8, 0x53C0, 0x85A1, 0x53C1, 0xC8FE, 0x53C2, 0xB2CE, + 0x53C3, 0x85A2, 0x53C4, 0x85A3, 0x53C5, 0x85A4, 0x53C6, 0x85A5, 0x53C7, 0x85A6, 0x53C8, 0xD3D6, 0x53C9, 0xB2E6, 0x53CA, 0xBCB0, + 0x53CB, 0xD3D1, 0x53CC, 0xCBAB, 0x53CD, 0xB7B4, 0x53CE, 0x85A7, 0x53CF, 0x85A8, 0x53D0, 0x85A9, 0x53D1, 0xB7A2, 0x53D2, 0x85AA, + 0x53D3, 0x85AB, 0x53D4, 0xCAE5, 0x53D5, 0x85AC, 0x53D6, 0xC8A1, 0x53D7, 0xCADC, 0x53D8, 0xB1E4, 0x53D9, 0xD0F0, 0x53DA, 0x85AD, + 0x53DB, 0xC5D1, 0x53DC, 0x85AE, 0x53DD, 0x85AF, 0x53DE, 0x85B0, 0x53DF, 0xDBC5, 0x53E0, 0xB5FE, 0x53E1, 0x85B1, 0x53E2, 0x85B2, + 0x53E3, 0xBFDA, 0x53E4, 0xB9C5, 0x53E5, 0xBEE4, 0x53E6, 0xC1ED, 0x53E7, 0x85B3, 0x53E8, 0xDFB6, 0x53E9, 0xDFB5, 0x53EA, 0xD6BB, + 0x53EB, 0xBDD0, 0x53EC, 0xD5D9, 0x53ED, 0xB0C8, 0x53EE, 0xB6A3, 0x53EF, 0xBFC9, 0x53F0, 0xCCA8, 0x53F1, 0xDFB3, 0x53F2, 0xCAB7, + 0x53F3, 0xD3D2, 0x53F4, 0x85B4, 0x53F5, 0xD8CF, 0x53F6, 0xD2B6, 0x53F7, 0xBAC5, 0x53F8, 0xCBBE, 0x53F9, 0xCCBE, 0x53FA, 0x85B5, + 0x53FB, 0xDFB7, 0x53FC, 0xB5F0, 0x53FD, 0xDFB4, 0x53FE, 0x85B6, 0x53FF, 0x85B7, 0x5400, 0x85B8, 0x5401, 0xD3F5, 0x5402, 0x85B9, + 0x5403, 0xB3D4, 0x5404, 0xB8F7, 0x5405, 0x85BA, 0x5406, 0xDFBA, 0x5407, 0x85BB, 0x5408, 0xBACF, 0x5409, 0xBCAA, 0x540A, 0xB5F5, + 0x540B, 0x85BC, 0x540C, 0xCDAC, 0x540D, 0xC3FB, 0x540E, 0xBAF3, 0x540F, 0xC0F4, 0x5410, 0xCDC2, 0x5411, 0xCFF2, 0x5412, 0xDFB8, + 0x5413, 0xCFC5, 0x5414, 0x85BD, 0x5415, 0xC2C0, 0x5416, 0xDFB9, 0x5417, 0xC2F0, 0x5418, 0x85BE, 0x5419, 0x85BF, 0x541A, 0x85C0, + 0x541B, 0xBEFD, 0x541C, 0x85C1, 0x541D, 0xC1DF, 0x541E, 0xCDCC, 0x541F, 0xD2F7, 0x5420, 0xB7CD, 0x5421, 0xDFC1, 0x5422, 0x85C2, + 0x5423, 0xDFC4, 0x5424, 0x85C3, 0x5425, 0x85C4, 0x5426, 0xB7F1, 0x5427, 0xB0C9, 0x5428, 0xB6D6, 0x5429, 0xB7D4, 0x542A, 0x85C5, + 0x542B, 0xBAAC, 0x542C, 0xCCFD, 0x542D, 0xBFD4, 0x542E, 0xCBB1, 0x542F, 0xC6F4, 0x5430, 0x85C6, 0x5431, 0xD6A8, 0x5432, 0xDFC5, + 0x5433, 0x85C7, 0x5434, 0xCEE2, 0x5435, 0xB3B3, 0x5436, 0x85C8, 0x5437, 0x85C9, 0x5438, 0xCEFC, 0x5439, 0xB4B5, 0x543A, 0x85CA, + 0x543B, 0xCEC7, 0x543C, 0xBAF0, 0x543D, 0x85CB, 0x543E, 0xCEE1, 0x543F, 0x85CC, 0x5440, 0xD1BD, 0x5441, 0x85CD, 0x5442, 0x85CE, + 0x5443, 0xDFC0, 0x5444, 0x85CF, 0x5445, 0x85D0, 0x5446, 0xB4F4, 0x5447, 0x85D1, 0x5448, 0xB3CA, 0x5449, 0x85D2, 0x544A, 0xB8E6, + 0x544B, 0xDFBB, 0x544C, 0x85D3, 0x544D, 0x85D4, 0x544E, 0x85D5, 0x544F, 0x85D6, 0x5450, 0xC4C5, 0x5451, 0x85D7, 0x5452, 0xDFBC, + 0x5453, 0xDFBD, 0x5454, 0xDFBE, 0x5455, 0xC5BB, 0x5456, 0xDFBF, 0x5457, 0xDFC2, 0x5458, 0xD4B1, 0x5459, 0xDFC3, 0x545A, 0x85D8, + 0x545B, 0xC7BA, 0x545C, 0xCED8, 0x545D, 0x85D9, 0x545E, 0x85DA, 0x545F, 0x85DB, 0x5460, 0x85DC, 0x5461, 0x85DD, 0x5462, 0xC4D8, + 0x5463, 0x85DE, 0x5464, 0xDFCA, 0x5465, 0x85DF, 0x5466, 0xDFCF, 0x5467, 0x85E0, 0x5468, 0xD6DC, 0x5469, 0x85E1, 0x546A, 0x85E2, + 0x546B, 0x85E3, 0x546C, 0x85E4, 0x546D, 0x85E5, 0x546E, 0x85E6, 0x546F, 0x85E7, 0x5470, 0x85E8, 0x5471, 0xDFC9, 0x5472, 0xDFDA, + 0x5473, 0xCEB6, 0x5474, 0x85E9, 0x5475, 0xBAC7, 0x5476, 0xDFCE, 0x5477, 0xDFC8, 0x5478, 0xC5DE, 0x5479, 0x85EA, 0x547A, 0x85EB, + 0x547B, 0xC9EB, 0x547C, 0xBAF4, 0x547D, 0xC3FC, 0x547E, 0x85EC, 0x547F, 0x85ED, 0x5480, 0xBED7, 0x5481, 0x85EE, 0x5482, 0xDFC6, + 0x5483, 0x85EF, 0x5484, 0xDFCD, 0x5485, 0x85F0, 0x5486, 0xC5D8, 0x5487, 0x85F1, 0x5488, 0x85F2, 0x5489, 0x85F3, 0x548A, 0x85F4, + 0x548B, 0xD5A6, 0x548C, 0xBACD, 0x548D, 0x85F5, 0x548E, 0xBECC, 0x548F, 0xD3BD, 0x5490, 0xB8C0, 0x5491, 0x85F6, 0x5492, 0xD6E4, + 0x5493, 0x85F7, 0x5494, 0xDFC7, 0x5495, 0xB9BE, 0x5496, 0xBFA7, 0x5497, 0x85F8, 0x5498, 0x85F9, 0x5499, 0xC1FC, 0x549A, 0xDFCB, + 0x549B, 0xDFCC, 0x549C, 0x85FA, 0x549D, 0xDFD0, 0x549E, 0x85FB, 0x549F, 0x85FC, 0x54A0, 0x85FD, 0x54A1, 0x85FE, 0x54A2, 0x8640, + 0x54A3, 0xDFDB, 0x54A4, 0xDFE5, 0x54A5, 0x8641, 0x54A6, 0xDFD7, 0x54A7, 0xDFD6, 0x54A8, 0xD7C9, 0x54A9, 0xDFE3, 0x54AA, 0xDFE4, + 0x54AB, 0xE5EB, 0x54AC, 0xD2A7, 0x54AD, 0xDFD2, 0x54AE, 0x8642, 0x54AF, 0xBFA9, 0x54B0, 0x8643, 0x54B1, 0xD4DB, 0x54B2, 0x8644, + 0x54B3, 0xBFC8, 0x54B4, 0xDFD4, 0x54B5, 0x8645, 0x54B6, 0x8646, 0x54B7, 0x8647, 0x54B8, 0xCFCC, 0x54B9, 0x8648, 0x54BA, 0x8649, + 0x54BB, 0xDFDD, 0x54BC, 0x864A, 0x54BD, 0xD1CA, 0x54BE, 0x864B, 0x54BF, 0xDFDE, 0x54C0, 0xB0A7, 0x54C1, 0xC6B7, 0x54C2, 0xDFD3, + 0x54C3, 0x864C, 0x54C4, 0xBAE5, 0x54C5, 0x864D, 0x54C6, 0xB6DF, 0x54C7, 0xCDDB, 0x54C8, 0xB9FE, 0x54C9, 0xD4D5, 0x54CA, 0x864E, + 0x54CB, 0x864F, 0x54CC, 0xDFDF, 0x54CD, 0xCFEC, 0x54CE, 0xB0A5, 0x54CF, 0xDFE7, 0x54D0, 0xDFD1, 0x54D1, 0xD1C6, 0x54D2, 0xDFD5, + 0x54D3, 0xDFD8, 0x54D4, 0xDFD9, 0x54D5, 0xDFDC, 0x54D6, 0x8650, 0x54D7, 0xBBA9, 0x54D8, 0x8651, 0x54D9, 0xDFE0, 0x54DA, 0xDFE1, + 0x54DB, 0x8652, 0x54DC, 0xDFE2, 0x54DD, 0xDFE6, 0x54DE, 0xDFE8, 0x54DF, 0xD3B4, 0x54E0, 0x8653, 0x54E1, 0x8654, 0x54E2, 0x8655, + 0x54E3, 0x8656, 0x54E4, 0x8657, 0x54E5, 0xB8E7, 0x54E6, 0xC5B6, 0x54E7, 0xDFEA, 0x54E8, 0xC9DA, 0x54E9, 0xC1A8, 0x54EA, 0xC4C4, + 0x54EB, 0x8658, 0x54EC, 0x8659, 0x54ED, 0xBFDE, 0x54EE, 0xCFF8, 0x54EF, 0x865A, 0x54F0, 0x865B, 0x54F1, 0x865C, 0x54F2, 0xD5DC, + 0x54F3, 0xDFEE, 0x54F4, 0x865D, 0x54F5, 0x865E, 0x54F6, 0x865F, 0x54F7, 0x8660, 0x54F8, 0x8661, 0x54F9, 0x8662, 0x54FA, 0xB2B8, + 0x54FB, 0x8663, 0x54FC, 0xBADF, 0x54FD, 0xDFEC, 0x54FE, 0x8664, 0x54FF, 0xDBC1, 0x5500, 0x8665, 0x5501, 0xD1E4, 0x5502, 0x8666, + 0x5503, 0x8667, 0x5504, 0x8668, 0x5505, 0x8669, 0x5506, 0xCBF4, 0x5507, 0xB4BD, 0x5508, 0x866A, 0x5509, 0xB0A6, 0x550A, 0x866B, + 0x550B, 0x866C, 0x550C, 0x866D, 0x550D, 0x866E, 0x550E, 0x866F, 0x550F, 0xDFF1, 0x5510, 0xCCC6, 0x5511, 0xDFF2, 0x5512, 0x8670, + 0x5513, 0x8671, 0x5514, 0xDFED, 0x5515, 0x8672, 0x5516, 0x8673, 0x5517, 0x8674, 0x5518, 0x8675, 0x5519, 0x8676, 0x551A, 0x8677, + 0x551B, 0xDFE9, 0x551C, 0x8678, 0x551D, 0x8679, 0x551E, 0x867A, 0x551F, 0x867B, 0x5520, 0xDFEB, 0x5521, 0x867C, 0x5522, 0xDFEF, + 0x5523, 0xDFF0, 0x5524, 0xBBBD, 0x5525, 0x867D, 0x5526, 0x867E, 0x5527, 0xDFF3, 0x5528, 0x8680, 0x5529, 0x8681, 0x552A, 0xDFF4, + 0x552B, 0x8682, 0x552C, 0xBBA3, 0x552D, 0x8683, 0x552E, 0xCADB, 0x552F, 0xCEA8, 0x5530, 0xE0A7, 0x5531, 0xB3AA, 0x5532, 0x8684, + 0x5533, 0xE0A6, 0x5534, 0x8685, 0x5535, 0x8686, 0x5536, 0x8687, 0x5537, 0xE0A1, 0x5538, 0x8688, 0x5539, 0x8689, 0x553A, 0x868A, + 0x553B, 0x868B, 0x553C, 0xDFFE, 0x553D, 0x868C, 0x553E, 0xCDD9, 0x553F, 0xDFFC, 0x5540, 0x868D, 0x5541, 0xDFFA, 0x5542, 0x868E, + 0x5543, 0xBFD0, 0x5544, 0xD7C4, 0x5545, 0x868F, 0x5546, 0xC9CC, 0x5547, 0x8690, 0x5548, 0x8691, 0x5549, 0xDFF8, 0x554A, 0xB0A1, + 0x554B, 0x8692, 0x554C, 0x8693, 0x554D, 0x8694, 0x554E, 0x8695, 0x554F, 0x8696, 0x5550, 0xDFFD, 0x5551, 0x8697, 0x5552, 0x8698, + 0x5553, 0x8699, 0x5554, 0x869A, 0x5555, 0xDFFB, 0x5556, 0xE0A2, 0x5557, 0x869B, 0x5558, 0x869C, 0x5559, 0x869D, 0x555A, 0x869E, + 0x555B, 0x869F, 0x555C, 0xE0A8, 0x555D, 0x86A0, 0x555E, 0x86A1, 0x555F, 0x86A2, 0x5560, 0x86A3, 0x5561, 0xB7C8, 0x5562, 0x86A4, + 0x5563, 0x86A5, 0x5564, 0xC6A1, 0x5565, 0xC9B6, 0x5566, 0xC0B2, 0x5567, 0xDFF5, 0x5568, 0x86A6, 0x5569, 0x86A7, 0x556A, 0xC5BE, + 0x556B, 0x86A8, 0x556C, 0xD8C4, 0x556D, 0xDFF9, 0x556E, 0xC4F6, 0x556F, 0x86A9, 0x5570, 0x86AA, 0x5571, 0x86AB, 0x5572, 0x86AC, + 0x5573, 0x86AD, 0x5574, 0x86AE, 0x5575, 0xE0A3, 0x5576, 0xE0A4, 0x5577, 0xE0A5, 0x5578, 0xD0A5, 0x5579, 0x86AF, 0x557A, 0x86B0, + 0x557B, 0xE0B4, 0x557C, 0xCCE4, 0x557D, 0x86B1, 0x557E, 0xE0B1, 0x557F, 0x86B2, 0x5580, 0xBFA6, 0x5581, 0xE0AF, 0x5582, 0xCEB9, + 0x5583, 0xE0AB, 0x5584, 0xC9C6, 0x5585, 0x86B3, 0x5586, 0x86B4, 0x5587, 0xC0AE, 0x5588, 0xE0AE, 0x5589, 0xBAED, 0x558A, 0xBAB0, + 0x558B, 0xE0A9, 0x558C, 0x86B5, 0x558D, 0x86B6, 0x558E, 0x86B7, 0x558F, 0xDFF6, 0x5590, 0x86B8, 0x5591, 0xE0B3, 0x5592, 0x86B9, + 0x5593, 0x86BA, 0x5594, 0xE0B8, 0x5595, 0x86BB, 0x5596, 0x86BC, 0x5597, 0x86BD, 0x5598, 0xB4AD, 0x5599, 0xE0B9, 0x559A, 0x86BE, + 0x559B, 0x86BF, 0x559C, 0xCFB2, 0x559D, 0xBAC8, 0x559E, 0x86C0, 0x559F, 0xE0B0, 0x55A0, 0x86C1, 0x55A1, 0x86C2, 0x55A2, 0x86C3, + 0x55A3, 0x86C4, 0x55A4, 0x86C5, 0x55A5, 0x86C6, 0x55A6, 0x86C7, 0x55A7, 0xD0FA, 0x55A8, 0x86C8, 0x55A9, 0x86C9, 0x55AA, 0x86CA, + 0x55AB, 0x86CB, 0x55AC, 0x86CC, 0x55AD, 0x86CD, 0x55AE, 0x86CE, 0x55AF, 0x86CF, 0x55B0, 0x86D0, 0x55B1, 0xE0AC, 0x55B2, 0x86D1, + 0x55B3, 0xD4FB, 0x55B4, 0x86D2, 0x55B5, 0xDFF7, 0x55B6, 0x86D3, 0x55B7, 0xC5E7, 0x55B8, 0x86D4, 0x55B9, 0xE0AD, 0x55BA, 0x86D5, + 0x55BB, 0xD3F7, 0x55BC, 0x86D6, 0x55BD, 0xE0B6, 0x55BE, 0xE0B7, 0x55BF, 0x86D7, 0x55C0, 0x86D8, 0x55C1, 0x86D9, 0x55C2, 0x86DA, + 0x55C3, 0x86DB, 0x55C4, 0xE0C4, 0x55C5, 0xD0E1, 0x55C6, 0x86DC, 0x55C7, 0x86DD, 0x55C8, 0x86DE, 0x55C9, 0xE0BC, 0x55CA, 0x86DF, + 0x55CB, 0x86E0, 0x55CC, 0xE0C9, 0x55CD, 0xE0CA, 0x55CE, 0x86E1, 0x55CF, 0x86E2, 0x55D0, 0x86E3, 0x55D1, 0xE0BE, 0x55D2, 0xE0AA, + 0x55D3, 0xC9A4, 0x55D4, 0xE0C1, 0x55D5, 0x86E4, 0x55D6, 0xE0B2, 0x55D7, 0x86E5, 0x55D8, 0x86E6, 0x55D9, 0x86E7, 0x55DA, 0x86E8, + 0x55DB, 0x86E9, 0x55DC, 0xCAC8, 0x55DD, 0xE0C3, 0x55DE, 0x86EA, 0x55DF, 0xE0B5, 0x55E0, 0x86EB, 0x55E1, 0xCECB, 0x55E2, 0x86EC, + 0x55E3, 0xCBC3, 0x55E4, 0xE0CD, 0x55E5, 0xE0C6, 0x55E6, 0xE0C2, 0x55E7, 0x86ED, 0x55E8, 0xE0CB, 0x55E9, 0x86EE, 0x55EA, 0xE0BA, + 0x55EB, 0xE0BF, 0x55EC, 0xE0C0, 0x55ED, 0x86EF, 0x55EE, 0x86F0, 0x55EF, 0xE0C5, 0x55F0, 0x86F1, 0x55F1, 0x86F2, 0x55F2, 0xE0C7, + 0x55F3, 0xE0C8, 0x55F4, 0x86F3, 0x55F5, 0xE0CC, 0x55F6, 0x86F4, 0x55F7, 0xE0BB, 0x55F8, 0x86F5, 0x55F9, 0x86F6, 0x55FA, 0x86F7, + 0x55FB, 0x86F8, 0x55FC, 0x86F9, 0x55FD, 0xCBD4, 0x55FE, 0xE0D5, 0x55FF, 0x86FA, 0x5600, 0xE0D6, 0x5601, 0xE0D2, 0x5602, 0x86FB, + 0x5603, 0x86FC, 0x5604, 0x86FD, 0x5605, 0x86FE, 0x5606, 0x8740, 0x5607, 0x8741, 0x5608, 0xE0D0, 0x5609, 0xBCCE, 0x560A, 0x8742, + 0x560B, 0x8743, 0x560C, 0xE0D1, 0x560D, 0x8744, 0x560E, 0xB8C2, 0x560F, 0xD8C5, 0x5610, 0x8745, 0x5611, 0x8746, 0x5612, 0x8747, + 0x5613, 0x8748, 0x5614, 0x8749, 0x5615, 0x874A, 0x5616, 0x874B, 0x5617, 0x874C, 0x5618, 0xD0EA, 0x5619, 0x874D, 0x561A, 0x874E, + 0x561B, 0xC2EF, 0x561C, 0x874F, 0x561D, 0x8750, 0x561E, 0xE0CF, 0x561F, 0xE0BD, 0x5620, 0x8751, 0x5621, 0x8752, 0x5622, 0x8753, + 0x5623, 0xE0D4, 0x5624, 0xE0D3, 0x5625, 0x8754, 0x5626, 0x8755, 0x5627, 0xE0D7, 0x5628, 0x8756, 0x5629, 0x8757, 0x562A, 0x8758, + 0x562B, 0x8759, 0x562C, 0xE0DC, 0x562D, 0xE0D8, 0x562E, 0x875A, 0x562F, 0x875B, 0x5630, 0x875C, 0x5631, 0xD6F6, 0x5632, 0xB3B0, + 0x5633, 0x875D, 0x5634, 0xD7EC, 0x5635, 0x875E, 0x5636, 0xCBBB, 0x5637, 0x875F, 0x5638, 0x8760, 0x5639, 0xE0DA, 0x563A, 0x8761, + 0x563B, 0xCEFB, 0x563C, 0x8762, 0x563D, 0x8763, 0x563E, 0x8764, 0x563F, 0xBAD9, 0x5640, 0x8765, 0x5641, 0x8766, 0x5642, 0x8767, + 0x5643, 0x8768, 0x5644, 0x8769, 0x5645, 0x876A, 0x5646, 0x876B, 0x5647, 0x876C, 0x5648, 0x876D, 0x5649, 0x876E, 0x564A, 0x876F, + 0x564B, 0x8770, 0x564C, 0xE0E1, 0x564D, 0xE0DD, 0x564E, 0xD2AD, 0x564F, 0x8771, 0x5650, 0x8772, 0x5651, 0x8773, 0x5652, 0x8774, + 0x5653, 0x8775, 0x5654, 0xE0E2, 0x5655, 0x8776, 0x5656, 0x8777, 0x5657, 0xE0DB, 0x5658, 0xE0D9, 0x5659, 0xE0DF, 0x565A, 0x8778, + 0x565B, 0x8779, 0x565C, 0xE0E0, 0x565D, 0x877A, 0x565E, 0x877B, 0x565F, 0x877C, 0x5660, 0x877D, 0x5661, 0x877E, 0x5662, 0xE0DE, + 0x5663, 0x8780, 0x5664, 0xE0E4, 0x5665, 0x8781, 0x5666, 0x8782, 0x5667, 0x8783, 0x5668, 0xC6F7, 0x5669, 0xD8AC, 0x566A, 0xD4EB, + 0x566B, 0xE0E6, 0x566C, 0xCAC9, 0x566D, 0x8784, 0x566E, 0x8785, 0x566F, 0x8786, 0x5670, 0x8787, 0x5671, 0xE0E5, 0x5672, 0x8788, + 0x5673, 0x8789, 0x5674, 0x878A, 0x5675, 0x878B, 0x5676, 0xB8C1, 0x5677, 0x878C, 0x5678, 0x878D, 0x5679, 0x878E, 0x567A, 0x878F, + 0x567B, 0xE0E7, 0x567C, 0xE0E8, 0x567D, 0x8790, 0x567E, 0x8791, 0x567F, 0x8792, 0x5680, 0x8793, 0x5681, 0x8794, 0x5682, 0x8795, + 0x5683, 0x8796, 0x5684, 0x8797, 0x5685, 0xE0E9, 0x5686, 0xE0E3, 0x5687, 0x8798, 0x5688, 0x8799, 0x5689, 0x879A, 0x568A, 0x879B, + 0x568B, 0x879C, 0x568C, 0x879D, 0x568D, 0x879E, 0x568E, 0xBABF, 0x568F, 0xCCE7, 0x5690, 0x879F, 0x5691, 0x87A0, 0x5692, 0x87A1, + 0x5693, 0xE0EA, 0x5694, 0x87A2, 0x5695, 0x87A3, 0x5696, 0x87A4, 0x5697, 0x87A5, 0x5698, 0x87A6, 0x5699, 0x87A7, 0x569A, 0x87A8, + 0x569B, 0x87A9, 0x569C, 0x87AA, 0x569D, 0x87AB, 0x569E, 0x87AC, 0x569F, 0x87AD, 0x56A0, 0x87AE, 0x56A1, 0x87AF, 0x56A2, 0x87B0, + 0x56A3, 0xCFF9, 0x56A4, 0x87B1, 0x56A5, 0x87B2, 0x56A6, 0x87B3, 0x56A7, 0x87B4, 0x56A8, 0x87B5, 0x56A9, 0x87B6, 0x56AA, 0x87B7, + 0x56AB, 0x87B8, 0x56AC, 0x87B9, 0x56AD, 0x87BA, 0x56AE, 0x87BB, 0x56AF, 0xE0EB, 0x56B0, 0x87BC, 0x56B1, 0x87BD, 0x56B2, 0x87BE, + 0x56B3, 0x87BF, 0x56B4, 0x87C0, 0x56B5, 0x87C1, 0x56B6, 0x87C2, 0x56B7, 0xC8C2, 0x56B8, 0x87C3, 0x56B9, 0x87C4, 0x56BA, 0x87C5, + 0x56BB, 0x87C6, 0x56BC, 0xBDC0, 0x56BD, 0x87C7, 0x56BE, 0x87C8, 0x56BF, 0x87C9, 0x56C0, 0x87CA, 0x56C1, 0x87CB, 0x56C2, 0x87CC, + 0x56C3, 0x87CD, 0x56C4, 0x87CE, 0x56C5, 0x87CF, 0x56C6, 0x87D0, 0x56C7, 0x87D1, 0x56C8, 0x87D2, 0x56C9, 0x87D3, 0x56CA, 0xC4D2, + 0x56CB, 0x87D4, 0x56CC, 0x87D5, 0x56CD, 0x87D6, 0x56CE, 0x87D7, 0x56CF, 0x87D8, 0x56D0, 0x87D9, 0x56D1, 0x87DA, 0x56D2, 0x87DB, + 0x56D3, 0x87DC, 0x56D4, 0xE0EC, 0x56D5, 0x87DD, 0x56D6, 0x87DE, 0x56D7, 0xE0ED, 0x56D8, 0x87DF, 0x56D9, 0x87E0, 0x56DA, 0xC7F4, + 0x56DB, 0xCBC4, 0x56DC, 0x87E1, 0x56DD, 0xE0EE, 0x56DE, 0xBBD8, 0x56DF, 0xD8B6, 0x56E0, 0xD2F2, 0x56E1, 0xE0EF, 0x56E2, 0xCDC5, + 0x56E3, 0x87E2, 0x56E4, 0xB6DA, 0x56E5, 0x87E3, 0x56E6, 0x87E4, 0x56E7, 0x87E5, 0x56E8, 0x87E6, 0x56E9, 0x87E7, 0x56EA, 0x87E8, + 0x56EB, 0xE0F1, 0x56EC, 0x87E9, 0x56ED, 0xD4B0, 0x56EE, 0x87EA, 0x56EF, 0x87EB, 0x56F0, 0xC0A7, 0x56F1, 0xB4D1, 0x56F2, 0x87EC, + 0x56F3, 0x87ED, 0x56F4, 0xCEA7, 0x56F5, 0xE0F0, 0x56F6, 0x87EE, 0x56F7, 0x87EF, 0x56F8, 0x87F0, 0x56F9, 0xE0F2, 0x56FA, 0xB9CC, + 0x56FB, 0x87F1, 0x56FC, 0x87F2, 0x56FD, 0xB9FA, 0x56FE, 0xCDBC, 0x56FF, 0xE0F3, 0x5700, 0x87F3, 0x5701, 0x87F4, 0x5702, 0x87F5, + 0x5703, 0xC6D4, 0x5704, 0xE0F4, 0x5705, 0x87F6, 0x5706, 0xD4B2, 0x5707, 0x87F7, 0x5708, 0xC8A6, 0x5709, 0xE0F6, 0x570A, 0xE0F5, + 0x570B, 0x87F8, 0x570C, 0x87F9, 0x570D, 0x87FA, 0x570E, 0x87FB, 0x570F, 0x87FC, 0x5710, 0x87FD, 0x5711, 0x87FE, 0x5712, 0x8840, + 0x5713, 0x8841, 0x5714, 0x8842, 0x5715, 0x8843, 0x5716, 0x8844, 0x5717, 0x8845, 0x5718, 0x8846, 0x5719, 0x8847, 0x571A, 0x8848, + 0x571B, 0x8849, 0x571C, 0xE0F7, 0x571D, 0x884A, 0x571E, 0x884B, 0x571F, 0xCDC1, 0x5720, 0x884C, 0x5721, 0x884D, 0x5722, 0x884E, + 0x5723, 0xCAA5, 0x5724, 0x884F, 0x5725, 0x8850, 0x5726, 0x8851, 0x5727, 0x8852, 0x5728, 0xD4DA, 0x5729, 0xDBD7, 0x572A, 0xDBD9, + 0x572B, 0x8853, 0x572C, 0xDBD8, 0x572D, 0xB9E7, 0x572E, 0xDBDC, 0x572F, 0xDBDD, 0x5730, 0xB5D8, 0x5731, 0x8854, 0x5732, 0x8855, + 0x5733, 0xDBDA, 0x5734, 0x8856, 0x5735, 0x8857, 0x5736, 0x8858, 0x5737, 0x8859, 0x5738, 0x885A, 0x5739, 0xDBDB, 0x573A, 0xB3A1, + 0x573B, 0xDBDF, 0x573C, 0x885B, 0x573D, 0x885C, 0x573E, 0xBBF8, 0x573F, 0x885D, 0x5740, 0xD6B7, 0x5741, 0x885E, 0x5742, 0xDBE0, + 0x5743, 0x885F, 0x5744, 0x8860, 0x5745, 0x8861, 0x5746, 0x8862, 0x5747, 0xBEF9, 0x5748, 0x8863, 0x5749, 0x8864, 0x574A, 0xB7BB, + 0x574B, 0x8865, 0x574C, 0xDBD0, 0x574D, 0xCCAE, 0x574E, 0xBFB2, 0x574F, 0xBBB5, 0x5750, 0xD7F8, 0x5751, 0xBFD3, 0x5752, 0x8866, + 0x5753, 0x8867, 0x5754, 0x8868, 0x5755, 0x8869, 0x5756, 0x886A, 0x5757, 0xBFE9, 0x5758, 0x886B, 0x5759, 0x886C, 0x575A, 0xBCE1, + 0x575B, 0xCCB3, 0x575C, 0xDBDE, 0x575D, 0xB0D3, 0x575E, 0xCEEB, 0x575F, 0xB7D8, 0x5760, 0xD7B9, 0x5761, 0xC6C2, 0x5762, 0x886D, + 0x5763, 0x886E, 0x5764, 0xC0A4, 0x5765, 0x886F, 0x5766, 0xCCB9, 0x5767, 0x8870, 0x5768, 0xDBE7, 0x5769, 0xDBE1, 0x576A, 0xC6BA, + 0x576B, 0xDBE3, 0x576C, 0x8871, 0x576D, 0xDBE8, 0x576E, 0x8872, 0x576F, 0xC5F7, 0x5770, 0x8873, 0x5771, 0x8874, 0x5772, 0x8875, + 0x5773, 0xDBEA, 0x5774, 0x8876, 0x5775, 0x8877, 0x5776, 0xDBE9, 0x5777, 0xBFC0, 0x5778, 0x8878, 0x5779, 0x8879, 0x577A, 0x887A, + 0x577B, 0xDBE6, 0x577C, 0xDBE5, 0x577D, 0x887B, 0x577E, 0x887C, 0x577F, 0x887D, 0x5780, 0x887E, 0x5781, 0x8880, 0x5782, 0xB4B9, + 0x5783, 0xC0AC, 0x5784, 0xC2A2, 0x5785, 0xDBE2, 0x5786, 0xDBE4, 0x5787, 0x8881, 0x5788, 0x8882, 0x5789, 0x8883, 0x578A, 0x8884, + 0x578B, 0xD0CD, 0x578C, 0xDBED, 0x578D, 0x8885, 0x578E, 0x8886, 0x578F, 0x8887, 0x5790, 0x8888, 0x5791, 0x8889, 0x5792, 0xC0DD, + 0x5793, 0xDBF2, 0x5794, 0x888A, 0x5795, 0x888B, 0x5796, 0x888C, 0x5797, 0x888D, 0x5798, 0x888E, 0x5799, 0x888F, 0x579A, 0x8890, + 0x579B, 0xB6E2, 0x579C, 0x8891, 0x579D, 0x8892, 0x579E, 0x8893, 0x579F, 0x8894, 0x57A0, 0xDBF3, 0x57A1, 0xDBD2, 0x57A2, 0xB9B8, + 0x57A3, 0xD4AB, 0x57A4, 0xDBEC, 0x57A5, 0x8895, 0x57A6, 0xBFD1, 0x57A7, 0xDBF0, 0x57A8, 0x8896, 0x57A9, 0xDBD1, 0x57AA, 0x8897, + 0x57AB, 0xB5E6, 0x57AC, 0x8898, 0x57AD, 0xDBEB, 0x57AE, 0xBFE5, 0x57AF, 0x8899, 0x57B0, 0x889A, 0x57B1, 0x889B, 0x57B2, 0xDBEE, + 0x57B3, 0x889C, 0x57B4, 0xDBF1, 0x57B5, 0x889D, 0x57B6, 0x889E, 0x57B7, 0x889F, 0x57B8, 0xDBF9, 0x57B9, 0x88A0, 0x57BA, 0x88A1, + 0x57BB, 0x88A2, 0x57BC, 0x88A3, 0x57BD, 0x88A4, 0x57BE, 0x88A5, 0x57BF, 0x88A6, 0x57C0, 0x88A7, 0x57C1, 0x88A8, 0x57C2, 0xB9A1, + 0x57C3, 0xB0A3, 0x57C4, 0x88A9, 0x57C5, 0x88AA, 0x57C6, 0x88AB, 0x57C7, 0x88AC, 0x57C8, 0x88AD, 0x57C9, 0x88AE, 0x57CA, 0x88AF, + 0x57CB, 0xC2F1, 0x57CC, 0x88B0, 0x57CD, 0x88B1, 0x57CE, 0xB3C7, 0x57CF, 0xDBEF, 0x57D0, 0x88B2, 0x57D1, 0x88B3, 0x57D2, 0xDBF8, + 0x57D3, 0x88B4, 0x57D4, 0xC6D2, 0x57D5, 0xDBF4, 0x57D6, 0x88B5, 0x57D7, 0x88B6, 0x57D8, 0xDBF5, 0x57D9, 0xDBF7, 0x57DA, 0xDBF6, + 0x57DB, 0x88B7, 0x57DC, 0x88B8, 0x57DD, 0xDBFE, 0x57DE, 0x88B9, 0x57DF, 0xD3F2, 0x57E0, 0xB2BA, 0x57E1, 0x88BA, 0x57E2, 0x88BB, + 0x57E3, 0x88BC, 0x57E4, 0xDBFD, 0x57E5, 0x88BD, 0x57E6, 0x88BE, 0x57E7, 0x88BF, 0x57E8, 0x88C0, 0x57E9, 0x88C1, 0x57EA, 0x88C2, + 0x57EB, 0x88C3, 0x57EC, 0x88C4, 0x57ED, 0xDCA4, 0x57EE, 0x88C5, 0x57EF, 0xDBFB, 0x57F0, 0x88C6, 0x57F1, 0x88C7, 0x57F2, 0x88C8, + 0x57F3, 0x88C9, 0x57F4, 0xDBFA, 0x57F5, 0x88CA, 0x57F6, 0x88CB, 0x57F7, 0x88CC, 0x57F8, 0xDBFC, 0x57F9, 0xC5E0, 0x57FA, 0xBBF9, + 0x57FB, 0x88CD, 0x57FC, 0x88CE, 0x57FD, 0xDCA3, 0x57FE, 0x88CF, 0x57FF, 0x88D0, 0x5800, 0xDCA5, 0x5801, 0x88D1, 0x5802, 0xCCC3, + 0x5803, 0x88D2, 0x5804, 0x88D3, 0x5805, 0x88D4, 0x5806, 0xB6D1, 0x5807, 0xDDC0, 0x5808, 0x88D5, 0x5809, 0x88D6, 0x580A, 0x88D7, + 0x580B, 0xDCA1, 0x580C, 0x88D8, 0x580D, 0xDCA2, 0x580E, 0x88D9, 0x580F, 0x88DA, 0x5810, 0x88DB, 0x5811, 0xC7B5, 0x5812, 0x88DC, + 0x5813, 0x88DD, 0x5814, 0x88DE, 0x5815, 0xB6E9, 0x5816, 0x88DF, 0x5817, 0x88E0, 0x5818, 0x88E1, 0x5819, 0xDCA7, 0x581A, 0x88E2, + 0x581B, 0x88E3, 0x581C, 0x88E4, 0x581D, 0x88E5, 0x581E, 0xDCA6, 0x581F, 0x88E6, 0x5820, 0xDCA9, 0x5821, 0xB1A4, 0x5822, 0x88E7, + 0x5823, 0x88E8, 0x5824, 0xB5CC, 0x5825, 0x88E9, 0x5826, 0x88EA, 0x5827, 0x88EB, 0x5828, 0x88EC, 0x5829, 0x88ED, 0x582A, 0xBFB0, + 0x582B, 0x88EE, 0x582C, 0x88EF, 0x582D, 0x88F0, 0x582E, 0x88F1, 0x582F, 0x88F2, 0x5830, 0xD1DF, 0x5831, 0x88F3, 0x5832, 0x88F4, + 0x5833, 0x88F5, 0x5834, 0x88F6, 0x5835, 0xB6C2, 0x5836, 0x88F7, 0x5837, 0x88F8, 0x5838, 0x88F9, 0x5839, 0x88FA, 0x583A, 0x88FB, + 0x583B, 0x88FC, 0x583C, 0x88FD, 0x583D, 0x88FE, 0x583E, 0x8940, 0x583F, 0x8941, 0x5840, 0x8942, 0x5841, 0x8943, 0x5842, 0x8944, + 0x5843, 0x8945, 0x5844, 0xDCA8, 0x5845, 0x8946, 0x5846, 0x8947, 0x5847, 0x8948, 0x5848, 0x8949, 0x5849, 0x894A, 0x584A, 0x894B, + 0x584B, 0x894C, 0x584C, 0xCBFA, 0x584D, 0xEBF3, 0x584E, 0x894D, 0x584F, 0x894E, 0x5850, 0x894F, 0x5851, 0xCBDC, 0x5852, 0x8950, + 0x5853, 0x8951, 0x5854, 0xCBFE, 0x5855, 0x8952, 0x5856, 0x8953, 0x5857, 0x8954, 0x5858, 0xCCC1, 0x5859, 0x8955, 0x585A, 0x8956, + 0x585B, 0x8957, 0x585C, 0x8958, 0x585D, 0x8959, 0x585E, 0xC8FB, 0x585F, 0x895A, 0x5860, 0x895B, 0x5861, 0x895C, 0x5862, 0x895D, + 0x5863, 0x895E, 0x5864, 0x895F, 0x5865, 0xDCAA, 0x5866, 0x8960, 0x5867, 0x8961, 0x5868, 0x8962, 0x5869, 0x8963, 0x586A, 0x8964, + 0x586B, 0xCCEE, 0x586C, 0xDCAB, 0x586D, 0x8965, 0x586E, 0x8966, 0x586F, 0x8967, 0x5870, 0x8968, 0x5871, 0x8969, 0x5872, 0x896A, + 0x5873, 0x896B, 0x5874, 0x896C, 0x5875, 0x896D, 0x5876, 0x896E, 0x5877, 0x896F, 0x5878, 0x8970, 0x5879, 0x8971, 0x587A, 0x8972, + 0x587B, 0x8973, 0x587C, 0x8974, 0x587D, 0x8975, 0x587E, 0xDBD3, 0x587F, 0x8976, 0x5880, 0xDCAF, 0x5881, 0xDCAC, 0x5882, 0x8977, + 0x5883, 0xBEB3, 0x5884, 0x8978, 0x5885, 0xCAFB, 0x5886, 0x8979, 0x5887, 0x897A, 0x5888, 0x897B, 0x5889, 0xDCAD, 0x588A, 0x897C, + 0x588B, 0x897D, 0x588C, 0x897E, 0x588D, 0x8980, 0x588E, 0x8981, 0x588F, 0x8982, 0x5890, 0x8983, 0x5891, 0x8984, 0x5892, 0xC9CA, + 0x5893, 0xC4B9, 0x5894, 0x8985, 0x5895, 0x8986, 0x5896, 0x8987, 0x5897, 0x8988, 0x5898, 0x8989, 0x5899, 0xC7BD, 0x589A, 0xDCAE, + 0x589B, 0x898A, 0x589C, 0x898B, 0x589D, 0x898C, 0x589E, 0xD4F6, 0x589F, 0xD0E6, 0x58A0, 0x898D, 0x58A1, 0x898E, 0x58A2, 0x898F, + 0x58A3, 0x8990, 0x58A4, 0x8991, 0x58A5, 0x8992, 0x58A6, 0x8993, 0x58A7, 0x8994, 0x58A8, 0xC4AB, 0x58A9, 0xB6D5, 0x58AA, 0x8995, + 0x58AB, 0x8996, 0x58AC, 0x8997, 0x58AD, 0x8998, 0x58AE, 0x8999, 0x58AF, 0x899A, 0x58B0, 0x899B, 0x58B1, 0x899C, 0x58B2, 0x899D, + 0x58B3, 0x899E, 0x58B4, 0x899F, 0x58B5, 0x89A0, 0x58B6, 0x89A1, 0x58B7, 0x89A2, 0x58B8, 0x89A3, 0x58B9, 0x89A4, 0x58BA, 0x89A5, + 0x58BB, 0x89A6, 0x58BC, 0xDBD4, 0x58BD, 0x89A7, 0x58BE, 0x89A8, 0x58BF, 0x89A9, 0x58C0, 0x89AA, 0x58C1, 0xB1DA, 0x58C2, 0x89AB, + 0x58C3, 0x89AC, 0x58C4, 0x89AD, 0x58C5, 0xDBD5, 0x58C6, 0x89AE, 0x58C7, 0x89AF, 0x58C8, 0x89B0, 0x58C9, 0x89B1, 0x58CA, 0x89B2, + 0x58CB, 0x89B3, 0x58CC, 0x89B4, 0x58CD, 0x89B5, 0x58CE, 0x89B6, 0x58CF, 0x89B7, 0x58D0, 0x89B8, 0x58D1, 0xDBD6, 0x58D2, 0x89B9, + 0x58D3, 0x89BA, 0x58D4, 0x89BB, 0x58D5, 0xBABE, 0x58D6, 0x89BC, 0x58D7, 0x89BD, 0x58D8, 0x89BE, 0x58D9, 0x89BF, 0x58DA, 0x89C0, + 0x58DB, 0x89C1, 0x58DC, 0x89C2, 0x58DD, 0x89C3, 0x58DE, 0x89C4, 0x58DF, 0x89C5, 0x58E0, 0x89C6, 0x58E1, 0x89C7, 0x58E2, 0x89C8, + 0x58E3, 0x89C9, 0x58E4, 0xC8C0, 0x58E5, 0x89CA, 0x58E6, 0x89CB, 0x58E7, 0x89CC, 0x58E8, 0x89CD, 0x58E9, 0x89CE, 0x58EA, 0x89CF, + 0x58EB, 0xCABF, 0x58EC, 0xC8C9, 0x58ED, 0x89D0, 0x58EE, 0xD7B3, 0x58EF, 0x89D1, 0x58F0, 0xC9F9, 0x58F1, 0x89D2, 0x58F2, 0x89D3, + 0x58F3, 0xBFC7, 0x58F4, 0x89D4, 0x58F5, 0x89D5, 0x58F6, 0xBAF8, 0x58F7, 0x89D6, 0x58F8, 0x89D7, 0x58F9, 0xD2BC, 0x58FA, 0x89D8, + 0x58FB, 0x89D9, 0x58FC, 0x89DA, 0x58FD, 0x89DB, 0x58FE, 0x89DC, 0x58FF, 0x89DD, 0x5900, 0x89DE, 0x5901, 0x89DF, 0x5902, 0xE2BA, + 0x5903, 0x89E0, 0x5904, 0xB4A6, 0x5905, 0x89E1, 0x5906, 0x89E2, 0x5907, 0xB1B8, 0x5908, 0x89E3, 0x5909, 0x89E4, 0x590A, 0x89E5, + 0x590B, 0x89E6, 0x590C, 0x89E7, 0x590D, 0xB8B4, 0x590E, 0x89E8, 0x590F, 0xCFC4, 0x5910, 0x89E9, 0x5911, 0x89EA, 0x5912, 0x89EB, + 0x5913, 0x89EC, 0x5914, 0xD9E7, 0x5915, 0xCFA6, 0x5916, 0xCDE2, 0x5917, 0x89ED, 0x5918, 0x89EE, 0x5919, 0xD9ED, 0x591A, 0xB6E0, + 0x591B, 0x89EF, 0x591C, 0xD2B9, 0x591D, 0x89F0, 0x591E, 0x89F1, 0x591F, 0xB9BB, 0x5920, 0x89F2, 0x5921, 0x89F3, 0x5922, 0x89F4, + 0x5923, 0x89F5, 0x5924, 0xE2B9, 0x5925, 0xE2B7, 0x5926, 0x89F6, 0x5927, 0xB4F3, 0x5928, 0x89F7, 0x5929, 0xCCEC, 0x592A, 0xCCAB, + 0x592B, 0xB7F2, 0x592C, 0x89F8, 0x592D, 0xD8B2, 0x592E, 0xD1EB, 0x592F, 0xBABB, 0x5930, 0x89F9, 0x5931, 0xCAA7, 0x5932, 0x89FA, + 0x5933, 0x89FB, 0x5934, 0xCDB7, 0x5935, 0x89FC, 0x5936, 0x89FD, 0x5937, 0xD2C4, 0x5938, 0xBFE4, 0x5939, 0xBCD0, 0x593A, 0xB6E1, + 0x593B, 0x89FE, 0x593C, 0xDEC5, 0x593D, 0x8A40, 0x593E, 0x8A41, 0x593F, 0x8A42, 0x5940, 0x8A43, 0x5941, 0xDEC6, 0x5942, 0xDBBC, + 0x5943, 0x8A44, 0x5944, 0xD1D9, 0x5945, 0x8A45, 0x5946, 0x8A46, 0x5947, 0xC6E6, 0x5948, 0xC4CE, 0x5949, 0xB7EE, 0x594A, 0x8A47, + 0x594B, 0xB7DC, 0x594C, 0x8A48, 0x594D, 0x8A49, 0x594E, 0xBFFC, 0x594F, 0xD7E0, 0x5950, 0x8A4A, 0x5951, 0xC6F5, 0x5952, 0x8A4B, + 0x5953, 0x8A4C, 0x5954, 0xB1BC, 0x5955, 0xDEC8, 0x5956, 0xBDB1, 0x5957, 0xCCD7, 0x5958, 0xDECA, 0x5959, 0x8A4D, 0x595A, 0xDEC9, + 0x595B, 0x8A4E, 0x595C, 0x8A4F, 0x595D, 0x8A50, 0x595E, 0x8A51, 0x595F, 0x8A52, 0x5960, 0xB5EC, 0x5961, 0x8A53, 0x5962, 0xC9DD, + 0x5963, 0x8A54, 0x5964, 0x8A55, 0x5965, 0xB0C2, 0x5966, 0x8A56, 0x5967, 0x8A57, 0x5968, 0x8A58, 0x5969, 0x8A59, 0x596A, 0x8A5A, + 0x596B, 0x8A5B, 0x596C, 0x8A5C, 0x596D, 0x8A5D, 0x596E, 0x8A5E, 0x596F, 0x8A5F, 0x5970, 0x8A60, 0x5971, 0x8A61, 0x5972, 0x8A62, + 0x5973, 0xC5AE, 0x5974, 0xC5AB, 0x5975, 0x8A63, 0x5976, 0xC4CC, 0x5977, 0x8A64, 0x5978, 0xBCE9, 0x5979, 0xCBFD, 0x597A, 0x8A65, + 0x597B, 0x8A66, 0x597C, 0x8A67, 0x597D, 0xBAC3, 0x597E, 0x8A68, 0x597F, 0x8A69, 0x5980, 0x8A6A, 0x5981, 0xE5F9, 0x5982, 0xC8E7, + 0x5983, 0xE5FA, 0x5984, 0xCDFD, 0x5985, 0x8A6B, 0x5986, 0xD7B1, 0x5987, 0xB8BE, 0x5988, 0xC2E8, 0x5989, 0x8A6C, 0x598A, 0xC8D1, + 0x598B, 0x8A6D, 0x598C, 0x8A6E, 0x598D, 0xE5FB, 0x598E, 0x8A6F, 0x598F, 0x8A70, 0x5990, 0x8A71, 0x5991, 0x8A72, 0x5992, 0xB6CA, + 0x5993, 0xBCCB, 0x5994, 0x8A73, 0x5995, 0x8A74, 0x5996, 0xD1FD, 0x5997, 0xE6A1, 0x5998, 0x8A75, 0x5999, 0xC3EE, 0x599A, 0x8A76, + 0x599B, 0x8A77, 0x599C, 0x8A78, 0x599D, 0x8A79, 0x599E, 0xE6A4, 0x599F, 0x8A7A, 0x59A0, 0x8A7B, 0x59A1, 0x8A7C, 0x59A2, 0x8A7D, + 0x59A3, 0xE5FE, 0x59A4, 0xE6A5, 0x59A5, 0xCDD7, 0x59A6, 0x8A7E, 0x59A7, 0x8A80, 0x59A8, 0xB7C1, 0x59A9, 0xE5FC, 0x59AA, 0xE5FD, + 0x59AB, 0xE6A3, 0x59AC, 0x8A81, 0x59AD, 0x8A82, 0x59AE, 0xC4DD, 0x59AF, 0xE6A8, 0x59B0, 0x8A83, 0x59B1, 0x8A84, 0x59B2, 0xE6A7, + 0x59B3, 0x8A85, 0x59B4, 0x8A86, 0x59B5, 0x8A87, 0x59B6, 0x8A88, 0x59B7, 0x8A89, 0x59B8, 0x8A8A, 0x59B9, 0xC3C3, 0x59BA, 0x8A8B, + 0x59BB, 0xC6DE, 0x59BC, 0x8A8C, 0x59BD, 0x8A8D, 0x59BE, 0xE6AA, 0x59BF, 0x8A8E, 0x59C0, 0x8A8F, 0x59C1, 0x8A90, 0x59C2, 0x8A91, + 0x59C3, 0x8A92, 0x59C4, 0x8A93, 0x59C5, 0x8A94, 0x59C6, 0xC4B7, 0x59C7, 0x8A95, 0x59C8, 0x8A96, 0x59C9, 0x8A97, 0x59CA, 0xE6A2, + 0x59CB, 0xCABC, 0x59CC, 0x8A98, 0x59CD, 0x8A99, 0x59CE, 0x8A9A, 0x59CF, 0x8A9B, 0x59D0, 0xBDE3, 0x59D1, 0xB9C3, 0x59D2, 0xE6A6, + 0x59D3, 0xD0D5, 0x59D4, 0xCEAF, 0x59D5, 0x8A9C, 0x59D6, 0x8A9D, 0x59D7, 0xE6A9, 0x59D8, 0xE6B0, 0x59D9, 0x8A9E, 0x59DA, 0xD2A6, + 0x59DB, 0x8A9F, 0x59DC, 0xBDAA, 0x59DD, 0xE6AD, 0x59DE, 0x8AA0, 0x59DF, 0x8AA1, 0x59E0, 0x8AA2, 0x59E1, 0x8AA3, 0x59E2, 0x8AA4, + 0x59E3, 0xE6AF, 0x59E4, 0x8AA5, 0x59E5, 0xC0D1, 0x59E6, 0x8AA6, 0x59E7, 0x8AA7, 0x59E8, 0xD2CC, 0x59E9, 0x8AA8, 0x59EA, 0x8AA9, + 0x59EB, 0x8AAA, 0x59EC, 0xBCA7, 0x59ED, 0x8AAB, 0x59EE, 0x8AAC, 0x59EF, 0x8AAD, 0x59F0, 0x8AAE, 0x59F1, 0x8AAF, 0x59F2, 0x8AB0, + 0x59F3, 0x8AB1, 0x59F4, 0x8AB2, 0x59F5, 0x8AB3, 0x59F6, 0x8AB4, 0x59F7, 0x8AB5, 0x59F8, 0x8AB6, 0x59F9, 0xE6B1, 0x59FA, 0x8AB7, + 0x59FB, 0xD2F6, 0x59FC, 0x8AB8, 0x59FD, 0x8AB9, 0x59FE, 0x8ABA, 0x59FF, 0xD7CB, 0x5A00, 0x8ABB, 0x5A01, 0xCDFE, 0x5A02, 0x8ABC, + 0x5A03, 0xCDDE, 0x5A04, 0xC2A6, 0x5A05, 0xE6AB, 0x5A06, 0xE6AC, 0x5A07, 0xBDBF, 0x5A08, 0xE6AE, 0x5A09, 0xE6B3, 0x5A0A, 0x8ABD, + 0x5A0B, 0x8ABE, 0x5A0C, 0xE6B2, 0x5A0D, 0x8ABF, 0x5A0E, 0x8AC0, 0x5A0F, 0x8AC1, 0x5A10, 0x8AC2, 0x5A11, 0xE6B6, 0x5A12, 0x8AC3, + 0x5A13, 0xE6B8, 0x5A14, 0x8AC4, 0x5A15, 0x8AC5, 0x5A16, 0x8AC6, 0x5A17, 0x8AC7, 0x5A18, 0xC4EF, 0x5A19, 0x8AC8, 0x5A1A, 0x8AC9, + 0x5A1B, 0x8ACA, 0x5A1C, 0xC4C8, 0x5A1D, 0x8ACB, 0x5A1E, 0x8ACC, 0x5A1F, 0xBEEA, 0x5A20, 0xC9EF, 0x5A21, 0x8ACD, 0x5A22, 0x8ACE, + 0x5A23, 0xE6B7, 0x5A24, 0x8ACF, 0x5A25, 0xB6F0, 0x5A26, 0x8AD0, 0x5A27, 0x8AD1, 0x5A28, 0x8AD2, 0x5A29, 0xC3E4, 0x5A2A, 0x8AD3, + 0x5A2B, 0x8AD4, 0x5A2C, 0x8AD5, 0x5A2D, 0x8AD6, 0x5A2E, 0x8AD7, 0x5A2F, 0x8AD8, 0x5A30, 0x8AD9, 0x5A31, 0xD3E9, 0x5A32, 0xE6B4, + 0x5A33, 0x8ADA, 0x5A34, 0xE6B5, 0x5A35, 0x8ADB, 0x5A36, 0xC8A2, 0x5A37, 0x8ADC, 0x5A38, 0x8ADD, 0x5A39, 0x8ADE, 0x5A3A, 0x8ADF, + 0x5A3B, 0x8AE0, 0x5A3C, 0xE6BD, 0x5A3D, 0x8AE1, 0x5A3E, 0x8AE2, 0x5A3F, 0x8AE3, 0x5A40, 0xE6B9, 0x5A41, 0x8AE4, 0x5A42, 0x8AE5, + 0x5A43, 0x8AE6, 0x5A44, 0x8AE7, 0x5A45, 0x8AE8, 0x5A46, 0xC6C5, 0x5A47, 0x8AE9, 0x5A48, 0x8AEA, 0x5A49, 0xCDF1, 0x5A4A, 0xE6BB, + 0x5A4B, 0x8AEB, 0x5A4C, 0x8AEC, 0x5A4D, 0x8AED, 0x5A4E, 0x8AEE, 0x5A4F, 0x8AEF, 0x5A50, 0x8AF0, 0x5A51, 0x8AF1, 0x5A52, 0x8AF2, + 0x5A53, 0x8AF3, 0x5A54, 0x8AF4, 0x5A55, 0xE6BC, 0x5A56, 0x8AF5, 0x5A57, 0x8AF6, 0x5A58, 0x8AF7, 0x5A59, 0x8AF8, 0x5A5A, 0xBBE9, + 0x5A5B, 0x8AF9, 0x5A5C, 0x8AFA, 0x5A5D, 0x8AFB, 0x5A5E, 0x8AFC, 0x5A5F, 0x8AFD, 0x5A60, 0x8AFE, 0x5A61, 0x8B40, 0x5A62, 0xE6BE, + 0x5A63, 0x8B41, 0x5A64, 0x8B42, 0x5A65, 0x8B43, 0x5A66, 0x8B44, 0x5A67, 0xE6BA, 0x5A68, 0x8B45, 0x5A69, 0x8B46, 0x5A6A, 0xC0B7, + 0x5A6B, 0x8B47, 0x5A6C, 0x8B48, 0x5A6D, 0x8B49, 0x5A6E, 0x8B4A, 0x5A6F, 0x8B4B, 0x5A70, 0x8B4C, 0x5A71, 0x8B4D, 0x5A72, 0x8B4E, + 0x5A73, 0x8B4F, 0x5A74, 0xD3A4, 0x5A75, 0xE6BF, 0x5A76, 0xC9F4, 0x5A77, 0xE6C3, 0x5A78, 0x8B50, 0x5A79, 0x8B51, 0x5A7A, 0xE6C4, + 0x5A7B, 0x8B52, 0x5A7C, 0x8B53, 0x5A7D, 0x8B54, 0x5A7E, 0x8B55, 0x5A7F, 0xD0F6, 0x5A80, 0x8B56, 0x5A81, 0x8B57, 0x5A82, 0x8B58, + 0x5A83, 0x8B59, 0x5A84, 0x8B5A, 0x5A85, 0x8B5B, 0x5A86, 0x8B5C, 0x5A87, 0x8B5D, 0x5A88, 0x8B5E, 0x5A89, 0x8B5F, 0x5A8A, 0x8B60, + 0x5A8B, 0x8B61, 0x5A8C, 0x8B62, 0x5A8D, 0x8B63, 0x5A8E, 0x8B64, 0x5A8F, 0x8B65, 0x5A90, 0x8B66, 0x5A91, 0x8B67, 0x5A92, 0xC3BD, + 0x5A93, 0x8B68, 0x5A94, 0x8B69, 0x5A95, 0x8B6A, 0x5A96, 0x8B6B, 0x5A97, 0x8B6C, 0x5A98, 0x8B6D, 0x5A99, 0x8B6E, 0x5A9A, 0xC3C4, + 0x5A9B, 0xE6C2, 0x5A9C, 0x8B6F, 0x5A9D, 0x8B70, 0x5A9E, 0x8B71, 0x5A9F, 0x8B72, 0x5AA0, 0x8B73, 0x5AA1, 0x8B74, 0x5AA2, 0x8B75, + 0x5AA3, 0x8B76, 0x5AA4, 0x8B77, 0x5AA5, 0x8B78, 0x5AA6, 0x8B79, 0x5AA7, 0x8B7A, 0x5AA8, 0x8B7B, 0x5AA9, 0x8B7C, 0x5AAA, 0xE6C1, + 0x5AAB, 0x8B7D, 0x5AAC, 0x8B7E, 0x5AAD, 0x8B80, 0x5AAE, 0x8B81, 0x5AAF, 0x8B82, 0x5AB0, 0x8B83, 0x5AB1, 0x8B84, 0x5AB2, 0xE6C7, + 0x5AB3, 0xCFB1, 0x5AB4, 0x8B85, 0x5AB5, 0xEBF4, 0x5AB6, 0x8B86, 0x5AB7, 0x8B87, 0x5AB8, 0xE6CA, 0x5AB9, 0x8B88, 0x5ABA, 0x8B89, + 0x5ABB, 0x8B8A, 0x5ABC, 0x8B8B, 0x5ABD, 0x8B8C, 0x5ABE, 0xE6C5, 0x5ABF, 0x8B8D, 0x5AC0, 0x8B8E, 0x5AC1, 0xBCDE, 0x5AC2, 0xC9A9, + 0x5AC3, 0x8B8F, 0x5AC4, 0x8B90, 0x5AC5, 0x8B91, 0x5AC6, 0x8B92, 0x5AC7, 0x8B93, 0x5AC8, 0x8B94, 0x5AC9, 0xBCB5, 0x5ACA, 0x8B95, + 0x5ACB, 0x8B96, 0x5ACC, 0xCFD3, 0x5ACD, 0x8B97, 0x5ACE, 0x8B98, 0x5ACF, 0x8B99, 0x5AD0, 0x8B9A, 0x5AD1, 0x8B9B, 0x5AD2, 0xE6C8, + 0x5AD3, 0x8B9C, 0x5AD4, 0xE6C9, 0x5AD5, 0x8B9D, 0x5AD6, 0xE6CE, 0x5AD7, 0x8B9E, 0x5AD8, 0xE6D0, 0x5AD9, 0x8B9F, 0x5ADA, 0x8BA0, + 0x5ADB, 0x8BA1, 0x5ADC, 0xE6D1, 0x5ADD, 0x8BA2, 0x5ADE, 0x8BA3, 0x5ADF, 0x8BA4, 0x5AE0, 0xE6CB, 0x5AE1, 0xB5D5, 0x5AE2, 0x8BA5, + 0x5AE3, 0xE6CC, 0x5AE4, 0x8BA6, 0x5AE5, 0x8BA7, 0x5AE6, 0xE6CF, 0x5AE7, 0x8BA8, 0x5AE8, 0x8BA9, 0x5AE9, 0xC4DB, 0x5AEA, 0x8BAA, + 0x5AEB, 0xE6C6, 0x5AEC, 0x8BAB, 0x5AED, 0x8BAC, 0x5AEE, 0x8BAD, 0x5AEF, 0x8BAE, 0x5AF0, 0x8BAF, 0x5AF1, 0xE6CD, 0x5AF2, 0x8BB0, + 0x5AF3, 0x8BB1, 0x5AF4, 0x8BB2, 0x5AF5, 0x8BB3, 0x5AF6, 0x8BB4, 0x5AF7, 0x8BB5, 0x5AF8, 0x8BB6, 0x5AF9, 0x8BB7, 0x5AFA, 0x8BB8, + 0x5AFB, 0x8BB9, 0x5AFC, 0x8BBA, 0x5AFD, 0x8BBB, 0x5AFE, 0x8BBC, 0x5AFF, 0x8BBD, 0x5B00, 0x8BBE, 0x5B01, 0x8BBF, 0x5B02, 0x8BC0, + 0x5B03, 0x8BC1, 0x5B04, 0x8BC2, 0x5B05, 0x8BC3, 0x5B06, 0x8BC4, 0x5B07, 0x8BC5, 0x5B08, 0x8BC6, 0x5B09, 0xE6D2, 0x5B0A, 0x8BC7, + 0x5B0B, 0x8BC8, 0x5B0C, 0x8BC9, 0x5B0D, 0x8BCA, 0x5B0E, 0x8BCB, 0x5B0F, 0x8BCC, 0x5B10, 0x8BCD, 0x5B11, 0x8BCE, 0x5B12, 0x8BCF, + 0x5B13, 0x8BD0, 0x5B14, 0x8BD1, 0x5B15, 0x8BD2, 0x5B16, 0xE6D4, 0x5B17, 0xE6D3, 0x5B18, 0x8BD3, 0x5B19, 0x8BD4, 0x5B1A, 0x8BD5, + 0x5B1B, 0x8BD6, 0x5B1C, 0x8BD7, 0x5B1D, 0x8BD8, 0x5B1E, 0x8BD9, 0x5B1F, 0x8BDA, 0x5B20, 0x8BDB, 0x5B21, 0x8BDC, 0x5B22, 0x8BDD, + 0x5B23, 0x8BDE, 0x5B24, 0x8BDF, 0x5B25, 0x8BE0, 0x5B26, 0x8BE1, 0x5B27, 0x8BE2, 0x5B28, 0x8BE3, 0x5B29, 0x8BE4, 0x5B2A, 0x8BE5, + 0x5B2B, 0x8BE6, 0x5B2C, 0x8BE7, 0x5B2D, 0x8BE8, 0x5B2E, 0x8BE9, 0x5B2F, 0x8BEA, 0x5B30, 0x8BEB, 0x5B31, 0x8BEC, 0x5B32, 0xE6D5, + 0x5B33, 0x8BED, 0x5B34, 0xD9F8, 0x5B35, 0x8BEE, 0x5B36, 0x8BEF, 0x5B37, 0xE6D6, 0x5B38, 0x8BF0, 0x5B39, 0x8BF1, 0x5B3A, 0x8BF2, + 0x5B3B, 0x8BF3, 0x5B3C, 0x8BF4, 0x5B3D, 0x8BF5, 0x5B3E, 0x8BF6, 0x5B3F, 0x8BF7, 0x5B40, 0xE6D7, 0x5B41, 0x8BF8, 0x5B42, 0x8BF9, + 0x5B43, 0x8BFA, 0x5B44, 0x8BFB, 0x5B45, 0x8BFC, 0x5B46, 0x8BFD, 0x5B47, 0x8BFE, 0x5B48, 0x8C40, 0x5B49, 0x8C41, 0x5B4A, 0x8C42, + 0x5B4B, 0x8C43, 0x5B4C, 0x8C44, 0x5B4D, 0x8C45, 0x5B4E, 0x8C46, 0x5B4F, 0x8C47, 0x5B50, 0xD7D3, 0x5B51, 0xE6DD, 0x5B52, 0x8C48, + 0x5B53, 0xE6DE, 0x5B54, 0xBFD7, 0x5B55, 0xD4D0, 0x5B56, 0x8C49, 0x5B57, 0xD7D6, 0x5B58, 0xB4E6, 0x5B59, 0xCBEF, 0x5B5A, 0xE6DA, + 0x5B5B, 0xD8C3, 0x5B5C, 0xD7CE, 0x5B5D, 0xD0A2, 0x5B5E, 0x8C4A, 0x5B5F, 0xC3CF, 0x5B60, 0x8C4B, 0x5B61, 0x8C4C, 0x5B62, 0xE6DF, + 0x5B63, 0xBCBE, 0x5B64, 0xB9C2, 0x5B65, 0xE6DB, 0x5B66, 0xD1A7, 0x5B67, 0x8C4D, 0x5B68, 0x8C4E, 0x5B69, 0xBAA2, 0x5B6A, 0xC2CF, + 0x5B6B, 0x8C4F, 0x5B6C, 0xD8AB, 0x5B6D, 0x8C50, 0x5B6E, 0x8C51, 0x5B6F, 0x8C52, 0x5B70, 0xCAEB, 0x5B71, 0xE5EE, 0x5B72, 0x8C53, + 0x5B73, 0xE6DC, 0x5B74, 0x8C54, 0x5B75, 0xB7F5, 0x5B76, 0x8C55, 0x5B77, 0x8C56, 0x5B78, 0x8C57, 0x5B79, 0x8C58, 0x5B7A, 0xC8E6, + 0x5B7B, 0x8C59, 0x5B7C, 0x8C5A, 0x5B7D, 0xC4F5, 0x5B7E, 0x8C5B, 0x5B7F, 0x8C5C, 0x5B80, 0xE5B2, 0x5B81, 0xC4FE, 0x5B82, 0x8C5D, + 0x5B83, 0xCBFC, 0x5B84, 0xE5B3, 0x5B85, 0xD5AC, 0x5B86, 0x8C5E, 0x5B87, 0xD3EE, 0x5B88, 0xCAD8, 0x5B89, 0xB0B2, 0x5B8A, 0x8C5F, + 0x5B8B, 0xCBCE, 0x5B8C, 0xCDEA, 0x5B8D, 0x8C60, 0x5B8E, 0x8C61, 0x5B8F, 0xBAEA, 0x5B90, 0x8C62, 0x5B91, 0x8C63, 0x5B92, 0x8C64, + 0x5B93, 0xE5B5, 0x5B94, 0x8C65, 0x5B95, 0xE5B4, 0x5B96, 0x8C66, 0x5B97, 0xD7DA, 0x5B98, 0xB9D9, 0x5B99, 0xD6E6, 0x5B9A, 0xB6A8, + 0x5B9B, 0xCDF0, 0x5B9C, 0xD2CB, 0x5B9D, 0xB1A6, 0x5B9E, 0xCAB5, 0x5B9F, 0x8C67, 0x5BA0, 0xB3E8, 0x5BA1, 0xC9F3, 0x5BA2, 0xBFCD, + 0x5BA3, 0xD0FB, 0x5BA4, 0xCAD2, 0x5BA5, 0xE5B6, 0x5BA6, 0xBBC2, 0x5BA7, 0x8C68, 0x5BA8, 0x8C69, 0x5BA9, 0x8C6A, 0x5BAA, 0xCFDC, + 0x5BAB, 0xB9AC, 0x5BAC, 0x8C6B, 0x5BAD, 0x8C6C, 0x5BAE, 0x8C6D, 0x5BAF, 0x8C6E, 0x5BB0, 0xD4D7, 0x5BB1, 0x8C6F, 0x5BB2, 0x8C70, + 0x5BB3, 0xBAA6, 0x5BB4, 0xD1E7, 0x5BB5, 0xCFFC, 0x5BB6, 0xBCD2, 0x5BB7, 0x8C71, 0x5BB8, 0xE5B7, 0x5BB9, 0xC8DD, 0x5BBA, 0x8C72, + 0x5BBB, 0x8C73, 0x5BBC, 0x8C74, 0x5BBD, 0xBFED, 0x5BBE, 0xB1F6, 0x5BBF, 0xCBDE, 0x5BC0, 0x8C75, 0x5BC1, 0x8C76, 0x5BC2, 0xBCC5, + 0x5BC3, 0x8C77, 0x5BC4, 0xBCC4, 0x5BC5, 0xD2FA, 0x5BC6, 0xC3DC, 0x5BC7, 0xBFDC, 0x5BC8, 0x8C78, 0x5BC9, 0x8C79, 0x5BCA, 0x8C7A, + 0x5BCB, 0x8C7B, 0x5BCC, 0xB8BB, 0x5BCD, 0x8C7C, 0x5BCE, 0x8C7D, 0x5BCF, 0x8C7E, 0x5BD0, 0xC3C2, 0x5BD1, 0x8C80, 0x5BD2, 0xBAAE, + 0x5BD3, 0xD4A2, 0x5BD4, 0x8C81, 0x5BD5, 0x8C82, 0x5BD6, 0x8C83, 0x5BD7, 0x8C84, 0x5BD8, 0x8C85, 0x5BD9, 0x8C86, 0x5BDA, 0x8C87, + 0x5BDB, 0x8C88, 0x5BDC, 0x8C89, 0x5BDD, 0xC7DE, 0x5BDE, 0xC4AF, 0x5BDF, 0xB2EC, 0x5BE0, 0x8C8A, 0x5BE1, 0xB9D1, 0x5BE2, 0x8C8B, + 0x5BE3, 0x8C8C, 0x5BE4, 0xE5BB, 0x5BE5, 0xC1C8, 0x5BE6, 0x8C8D, 0x5BE7, 0x8C8E, 0x5BE8, 0xD5AF, 0x5BE9, 0x8C8F, 0x5BEA, 0x8C90, + 0x5BEB, 0x8C91, 0x5BEC, 0x8C92, 0x5BED, 0x8C93, 0x5BEE, 0xE5BC, 0x5BEF, 0x8C94, 0x5BF0, 0xE5BE, 0x5BF1, 0x8C95, 0x5BF2, 0x8C96, + 0x5BF3, 0x8C97, 0x5BF4, 0x8C98, 0x5BF5, 0x8C99, 0x5BF6, 0x8C9A, 0x5BF7, 0x8C9B, 0x5BF8, 0xB4E7, 0x5BF9, 0xB6D4, 0x5BFA, 0xCBC2, + 0x5BFB, 0xD1B0, 0x5BFC, 0xB5BC, 0x5BFD, 0x8C9C, 0x5BFE, 0x8C9D, 0x5BFF, 0xCAD9, 0x5C00, 0x8C9E, 0x5C01, 0xB7E2, 0x5C02, 0x8C9F, + 0x5C03, 0x8CA0, 0x5C04, 0xC9E4, 0x5C05, 0x8CA1, 0x5C06, 0xBDAB, 0x5C07, 0x8CA2, 0x5C08, 0x8CA3, 0x5C09, 0xCEBE, 0x5C0A, 0xD7F0, + 0x5C0B, 0x8CA4, 0x5C0C, 0x8CA5, 0x5C0D, 0x8CA6, 0x5C0E, 0x8CA7, 0x5C0F, 0xD0A1, 0x5C10, 0x8CA8, 0x5C11, 0xC9D9, 0x5C12, 0x8CA9, + 0x5C13, 0x8CAA, 0x5C14, 0xB6FB, 0x5C15, 0xE6D8, 0x5C16, 0xBCE2, 0x5C17, 0x8CAB, 0x5C18, 0xB3BE, 0x5C19, 0x8CAC, 0x5C1A, 0xC9D0, + 0x5C1B, 0x8CAD, 0x5C1C, 0xE6D9, 0x5C1D, 0xB3A2, 0x5C1E, 0x8CAE, 0x5C1F, 0x8CAF, 0x5C20, 0x8CB0, 0x5C21, 0x8CB1, 0x5C22, 0xDECC, + 0x5C23, 0x8CB2, 0x5C24, 0xD3C8, 0x5C25, 0xDECD, 0x5C26, 0x8CB3, 0x5C27, 0xD2A2, 0x5C28, 0x8CB4, 0x5C29, 0x8CB5, 0x5C2A, 0x8CB6, + 0x5C2B, 0x8CB7, 0x5C2C, 0xDECE, 0x5C2D, 0x8CB8, 0x5C2E, 0x8CB9, 0x5C2F, 0x8CBA, 0x5C30, 0x8CBB, 0x5C31, 0xBECD, 0x5C32, 0x8CBC, + 0x5C33, 0x8CBD, 0x5C34, 0xDECF, 0x5C35, 0x8CBE, 0x5C36, 0x8CBF, 0x5C37, 0x8CC0, 0x5C38, 0xCAAC, 0x5C39, 0xD2FC, 0x5C3A, 0xB3DF, + 0x5C3B, 0xE5EA, 0x5C3C, 0xC4E1, 0x5C3D, 0xBEA1, 0x5C3E, 0xCEB2, 0x5C3F, 0xC4F2, 0x5C40, 0xBED6, 0x5C41, 0xC6A8, 0x5C42, 0xB2E3, + 0x5C43, 0x8CC1, 0x5C44, 0x8CC2, 0x5C45, 0xBED3, 0x5C46, 0x8CC3, 0x5C47, 0x8CC4, 0x5C48, 0xC7FC, 0x5C49, 0xCCEB, 0x5C4A, 0xBDEC, + 0x5C4B, 0xCEDD, 0x5C4C, 0x8CC5, 0x5C4D, 0x8CC6, 0x5C4E, 0xCABA, 0x5C4F, 0xC6C1, 0x5C50, 0xE5EC, 0x5C51, 0xD0BC, 0x5C52, 0x8CC7, + 0x5C53, 0x8CC8, 0x5C54, 0x8CC9, 0x5C55, 0xD5B9, 0x5C56, 0x8CCA, 0x5C57, 0x8CCB, 0x5C58, 0x8CCC, 0x5C59, 0xE5ED, 0x5C5A, 0x8CCD, + 0x5C5B, 0x8CCE, 0x5C5C, 0x8CCF, 0x5C5D, 0x8CD0, 0x5C5E, 0xCAF4, 0x5C5F, 0x8CD1, 0x5C60, 0xCDC0, 0x5C61, 0xC2C5, 0x5C62, 0x8CD2, + 0x5C63, 0xE5EF, 0x5C64, 0x8CD3, 0x5C65, 0xC2C4, 0x5C66, 0xE5F0, 0x5C67, 0x8CD4, 0x5C68, 0x8CD5, 0x5C69, 0x8CD6, 0x5C6A, 0x8CD7, + 0x5C6B, 0x8CD8, 0x5C6C, 0x8CD9, 0x5C6D, 0x8CDA, 0x5C6E, 0xE5F8, 0x5C6F, 0xCDCD, 0x5C70, 0x8CDB, 0x5C71, 0xC9BD, 0x5C72, 0x8CDC, + 0x5C73, 0x8CDD, 0x5C74, 0x8CDE, 0x5C75, 0x8CDF, 0x5C76, 0x8CE0, 0x5C77, 0x8CE1, 0x5C78, 0x8CE2, 0x5C79, 0xD2D9, 0x5C7A, 0xE1A8, + 0x5C7B, 0x8CE3, 0x5C7C, 0x8CE4, 0x5C7D, 0x8CE5, 0x5C7E, 0x8CE6, 0x5C7F, 0xD3EC, 0x5C80, 0x8CE7, 0x5C81, 0xCBEA, 0x5C82, 0xC6F1, + 0x5C83, 0x8CE8, 0x5C84, 0x8CE9, 0x5C85, 0x8CEA, 0x5C86, 0x8CEB, 0x5C87, 0x8CEC, 0x5C88, 0xE1AC, 0x5C89, 0x8CED, 0x5C8A, 0x8CEE, + 0x5C8B, 0x8CEF, 0x5C8C, 0xE1A7, 0x5C8D, 0xE1A9, 0x5C8E, 0x8CF0, 0x5C8F, 0x8CF1, 0x5C90, 0xE1AA, 0x5C91, 0xE1AF, 0x5C92, 0x8CF2, + 0x5C93, 0x8CF3, 0x5C94, 0xB2ED, 0x5C95, 0x8CF4, 0x5C96, 0xE1AB, 0x5C97, 0xB8DA, 0x5C98, 0xE1AD, 0x5C99, 0xE1AE, 0x5C9A, 0xE1B0, + 0x5C9B, 0xB5BA, 0x5C9C, 0xE1B1, 0x5C9D, 0x8CF5, 0x5C9E, 0x8CF6, 0x5C9F, 0x8CF7, 0x5CA0, 0x8CF8, 0x5CA1, 0x8CF9, 0x5CA2, 0xE1B3, + 0x5CA3, 0xE1B8, 0x5CA4, 0x8CFA, 0x5CA5, 0x8CFB, 0x5CA6, 0x8CFC, 0x5CA7, 0x8CFD, 0x5CA8, 0x8CFE, 0x5CA9, 0xD1D2, 0x5CAA, 0x8D40, + 0x5CAB, 0xE1B6, 0x5CAC, 0xE1B5, 0x5CAD, 0xC1EB, 0x5CAE, 0x8D41, 0x5CAF, 0x8D42, 0x5CB0, 0x8D43, 0x5CB1, 0xE1B7, 0x5CB2, 0x8D44, + 0x5CB3, 0xD4C0, 0x5CB4, 0x8D45, 0x5CB5, 0xE1B2, 0x5CB6, 0x8D46, 0x5CB7, 0xE1BA, 0x5CB8, 0xB0B6, 0x5CB9, 0x8D47, 0x5CBA, 0x8D48, + 0x5CBB, 0x8D49, 0x5CBC, 0x8D4A, 0x5CBD, 0xE1B4, 0x5CBE, 0x8D4B, 0x5CBF, 0xBFF9, 0x5CC0, 0x8D4C, 0x5CC1, 0xE1B9, 0x5CC2, 0x8D4D, + 0x5CC3, 0x8D4E, 0x5CC4, 0xE1BB, 0x5CC5, 0x8D4F, 0x5CC6, 0x8D50, 0x5CC7, 0x8D51, 0x5CC8, 0x8D52, 0x5CC9, 0x8D53, 0x5CCA, 0x8D54, + 0x5CCB, 0xE1BE, 0x5CCC, 0x8D55, 0x5CCD, 0x8D56, 0x5CCE, 0x8D57, 0x5CCF, 0x8D58, 0x5CD0, 0x8D59, 0x5CD1, 0x8D5A, 0x5CD2, 0xE1BC, + 0x5CD3, 0x8D5B, 0x5CD4, 0x8D5C, 0x5CD5, 0x8D5D, 0x5CD6, 0x8D5E, 0x5CD7, 0x8D5F, 0x5CD8, 0x8D60, 0x5CD9, 0xD6C5, 0x5CDA, 0x8D61, + 0x5CDB, 0x8D62, 0x5CDC, 0x8D63, 0x5CDD, 0x8D64, 0x5CDE, 0x8D65, 0x5CDF, 0x8D66, 0x5CE0, 0x8D67, 0x5CE1, 0xCFBF, 0x5CE2, 0x8D68, + 0x5CE3, 0x8D69, 0x5CE4, 0xE1BD, 0x5CE5, 0xE1BF, 0x5CE6, 0xC2CD, 0x5CE7, 0x8D6A, 0x5CE8, 0xB6EB, 0x5CE9, 0x8D6B, 0x5CEA, 0xD3F8, + 0x5CEB, 0x8D6C, 0x5CEC, 0x8D6D, 0x5CED, 0xC7CD, 0x5CEE, 0x8D6E, 0x5CEF, 0x8D6F, 0x5CF0, 0xB7E5, 0x5CF1, 0x8D70, 0x5CF2, 0x8D71, + 0x5CF3, 0x8D72, 0x5CF4, 0x8D73, 0x5CF5, 0x8D74, 0x5CF6, 0x8D75, 0x5CF7, 0x8D76, 0x5CF8, 0x8D77, 0x5CF9, 0x8D78, 0x5CFA, 0x8D79, + 0x5CFB, 0xBEFE, 0x5CFC, 0x8D7A, 0x5CFD, 0x8D7B, 0x5CFE, 0x8D7C, 0x5CFF, 0x8D7D, 0x5D00, 0x8D7E, 0x5D01, 0x8D80, 0x5D02, 0xE1C0, + 0x5D03, 0xE1C1, 0x5D04, 0x8D81, 0x5D05, 0x8D82, 0x5D06, 0xE1C7, 0x5D07, 0xB3E7, 0x5D08, 0x8D83, 0x5D09, 0x8D84, 0x5D0A, 0x8D85, + 0x5D0B, 0x8D86, 0x5D0C, 0x8D87, 0x5D0D, 0x8D88, 0x5D0E, 0xC6E9, 0x5D0F, 0x8D89, 0x5D10, 0x8D8A, 0x5D11, 0x8D8B, 0x5D12, 0x8D8C, + 0x5D13, 0x8D8D, 0x5D14, 0xB4DE, 0x5D15, 0x8D8E, 0x5D16, 0xD1C2, 0x5D17, 0x8D8F, 0x5D18, 0x8D90, 0x5D19, 0x8D91, 0x5D1A, 0x8D92, + 0x5D1B, 0xE1C8, 0x5D1C, 0x8D93, 0x5D1D, 0x8D94, 0x5D1E, 0xE1C6, 0x5D1F, 0x8D95, 0x5D20, 0x8D96, 0x5D21, 0x8D97, 0x5D22, 0x8D98, + 0x5D23, 0x8D99, 0x5D24, 0xE1C5, 0x5D25, 0x8D9A, 0x5D26, 0xE1C3, 0x5D27, 0xE1C2, 0x5D28, 0x8D9B, 0x5D29, 0xB1C0, 0x5D2A, 0x8D9C, + 0x5D2B, 0x8D9D, 0x5D2C, 0x8D9E, 0x5D2D, 0xD5B8, 0x5D2E, 0xE1C4, 0x5D2F, 0x8D9F, 0x5D30, 0x8DA0, 0x5D31, 0x8DA1, 0x5D32, 0x8DA2, + 0x5D33, 0x8DA3, 0x5D34, 0xE1CB, 0x5D35, 0x8DA4, 0x5D36, 0x8DA5, 0x5D37, 0x8DA6, 0x5D38, 0x8DA7, 0x5D39, 0x8DA8, 0x5D3A, 0x8DA9, + 0x5D3B, 0x8DAA, 0x5D3C, 0x8DAB, 0x5D3D, 0xE1CC, 0x5D3E, 0xE1CA, 0x5D3F, 0x8DAC, 0x5D40, 0x8DAD, 0x5D41, 0x8DAE, 0x5D42, 0x8DAF, + 0x5D43, 0x8DB0, 0x5D44, 0x8DB1, 0x5D45, 0x8DB2, 0x5D46, 0x8DB3, 0x5D47, 0xEFFA, 0x5D48, 0x8DB4, 0x5D49, 0x8DB5, 0x5D4A, 0xE1D3, + 0x5D4B, 0xE1D2, 0x5D4C, 0xC7B6, 0x5D4D, 0x8DB6, 0x5D4E, 0x8DB7, 0x5D4F, 0x8DB8, 0x5D50, 0x8DB9, 0x5D51, 0x8DBA, 0x5D52, 0x8DBB, + 0x5D53, 0x8DBC, 0x5D54, 0x8DBD, 0x5D55, 0x8DBE, 0x5D56, 0x8DBF, 0x5D57, 0x8DC0, 0x5D58, 0xE1C9, 0x5D59, 0x8DC1, 0x5D5A, 0x8DC2, + 0x5D5B, 0xE1CE, 0x5D5C, 0x8DC3, 0x5D5D, 0xE1D0, 0x5D5E, 0x8DC4, 0x5D5F, 0x8DC5, 0x5D60, 0x8DC6, 0x5D61, 0x8DC7, 0x5D62, 0x8DC8, + 0x5D63, 0x8DC9, 0x5D64, 0x8DCA, 0x5D65, 0x8DCB, 0x5D66, 0x8DCC, 0x5D67, 0x8DCD, 0x5D68, 0x8DCE, 0x5D69, 0xE1D4, 0x5D6A, 0x8DCF, + 0x5D6B, 0xE1D1, 0x5D6C, 0xE1CD, 0x5D6D, 0x8DD0, 0x5D6E, 0x8DD1, 0x5D6F, 0xE1CF, 0x5D70, 0x8DD2, 0x5D71, 0x8DD3, 0x5D72, 0x8DD4, + 0x5D73, 0x8DD5, 0x5D74, 0xE1D5, 0x5D75, 0x8DD6, 0x5D76, 0x8DD7, 0x5D77, 0x8DD8, 0x5D78, 0x8DD9, 0x5D79, 0x8DDA, 0x5D7A, 0x8DDB, + 0x5D7B, 0x8DDC, 0x5D7C, 0x8DDD, 0x5D7D, 0x8DDE, 0x5D7E, 0x8DDF, 0x5D7F, 0x8DE0, 0x5D80, 0x8DE1, 0x5D81, 0x8DE2, 0x5D82, 0xE1D6, + 0x5D83, 0x8DE3, 0x5D84, 0x8DE4, 0x5D85, 0x8DE5, 0x5D86, 0x8DE6, 0x5D87, 0x8DE7, 0x5D88, 0x8DE8, 0x5D89, 0x8DE9, 0x5D8A, 0x8DEA, + 0x5D8B, 0x8DEB, 0x5D8C, 0x8DEC, 0x5D8D, 0x8DED, 0x5D8E, 0x8DEE, 0x5D8F, 0x8DEF, 0x5D90, 0x8DF0, 0x5D91, 0x8DF1, 0x5D92, 0x8DF2, + 0x5D93, 0x8DF3, 0x5D94, 0x8DF4, 0x5D95, 0x8DF5, 0x5D96, 0x8DF6, 0x5D97, 0x8DF7, 0x5D98, 0x8DF8, 0x5D99, 0xE1D7, 0x5D9A, 0x8DF9, + 0x5D9B, 0x8DFA, 0x5D9C, 0x8DFB, 0x5D9D, 0xE1D8, 0x5D9E, 0x8DFC, 0x5D9F, 0x8DFD, 0x5DA0, 0x8DFE, 0x5DA1, 0x8E40, 0x5DA2, 0x8E41, + 0x5DA3, 0x8E42, 0x5DA4, 0x8E43, 0x5DA5, 0x8E44, 0x5DA6, 0x8E45, 0x5DA7, 0x8E46, 0x5DA8, 0x8E47, 0x5DA9, 0x8E48, 0x5DAA, 0x8E49, + 0x5DAB, 0x8E4A, 0x5DAC, 0x8E4B, 0x5DAD, 0x8E4C, 0x5DAE, 0x8E4D, 0x5DAF, 0x8E4E, 0x5DB0, 0x8E4F, 0x5DB1, 0x8E50, 0x5DB2, 0x8E51, + 0x5DB3, 0x8E52, 0x5DB4, 0x8E53, 0x5DB5, 0x8E54, 0x5DB6, 0x8E55, 0x5DB7, 0xE1DA, 0x5DB8, 0x8E56, 0x5DB9, 0x8E57, 0x5DBA, 0x8E58, + 0x5DBB, 0x8E59, 0x5DBC, 0x8E5A, 0x5DBD, 0x8E5B, 0x5DBE, 0x8E5C, 0x5DBF, 0x8E5D, 0x5DC0, 0x8E5E, 0x5DC1, 0x8E5F, 0x5DC2, 0x8E60, + 0x5DC3, 0x8E61, 0x5DC4, 0x8E62, 0x5DC5, 0xE1DB, 0x5DC6, 0x8E63, 0x5DC7, 0x8E64, 0x5DC8, 0x8E65, 0x5DC9, 0x8E66, 0x5DCA, 0x8E67, + 0x5DCB, 0x8E68, 0x5DCC, 0x8E69, 0x5DCD, 0xCEA1, 0x5DCE, 0x8E6A, 0x5DCF, 0x8E6B, 0x5DD0, 0x8E6C, 0x5DD1, 0x8E6D, 0x5DD2, 0x8E6E, + 0x5DD3, 0x8E6F, 0x5DD4, 0x8E70, 0x5DD5, 0x8E71, 0x5DD6, 0x8E72, 0x5DD7, 0x8E73, 0x5DD8, 0x8E74, 0x5DD9, 0x8E75, 0x5DDA, 0x8E76, + 0x5DDB, 0xE7DD, 0x5DDC, 0x8E77, 0x5DDD, 0xB4A8, 0x5DDE, 0xD6DD, 0x5DDF, 0x8E78, 0x5DE0, 0x8E79, 0x5DE1, 0xD1B2, 0x5DE2, 0xB3B2, + 0x5DE3, 0x8E7A, 0x5DE4, 0x8E7B, 0x5DE5, 0xB9A4, 0x5DE6, 0xD7F3, 0x5DE7, 0xC7C9, 0x5DE8, 0xBEDE, 0x5DE9, 0xB9AE, 0x5DEA, 0x8E7C, + 0x5DEB, 0xCED7, 0x5DEC, 0x8E7D, 0x5DED, 0x8E7E, 0x5DEE, 0xB2EE, 0x5DEF, 0xDBCF, 0x5DF0, 0x8E80, 0x5DF1, 0xBCBA, 0x5DF2, 0xD2D1, + 0x5DF3, 0xCBC8, 0x5DF4, 0xB0CD, 0x5DF5, 0x8E81, 0x5DF6, 0x8E82, 0x5DF7, 0xCFEF, 0x5DF8, 0x8E83, 0x5DF9, 0x8E84, 0x5DFA, 0x8E85, + 0x5DFB, 0x8E86, 0x5DFC, 0x8E87, 0x5DFD, 0xD9E3, 0x5DFE, 0xBDED, 0x5DFF, 0x8E88, 0x5E00, 0x8E89, 0x5E01, 0xB1D2, 0x5E02, 0xCAD0, + 0x5E03, 0xB2BC, 0x5E04, 0x8E8A, 0x5E05, 0xCBA7, 0x5E06, 0xB7AB, 0x5E07, 0x8E8B, 0x5E08, 0xCAA6, 0x5E09, 0x8E8C, 0x5E0A, 0x8E8D, + 0x5E0B, 0x8E8E, 0x5E0C, 0xCFA3, 0x5E0D, 0x8E8F, 0x5E0E, 0x8E90, 0x5E0F, 0xE0F8, 0x5E10, 0xD5CA, 0x5E11, 0xE0FB, 0x5E12, 0x8E91, + 0x5E13, 0x8E92, 0x5E14, 0xE0FA, 0x5E15, 0xC5C1, 0x5E16, 0xCCFB, 0x5E17, 0x8E93, 0x5E18, 0xC1B1, 0x5E19, 0xE0F9, 0x5E1A, 0xD6E3, + 0x5E1B, 0xB2AF, 0x5E1C, 0xD6C4, 0x5E1D, 0xB5DB, 0x5E1E, 0x8E94, 0x5E1F, 0x8E95, 0x5E20, 0x8E96, 0x5E21, 0x8E97, 0x5E22, 0x8E98, + 0x5E23, 0x8E99, 0x5E24, 0x8E9A, 0x5E25, 0x8E9B, 0x5E26, 0xB4F8, 0x5E27, 0xD6A1, 0x5E28, 0x8E9C, 0x5E29, 0x8E9D, 0x5E2A, 0x8E9E, + 0x5E2B, 0x8E9F, 0x5E2C, 0x8EA0, 0x5E2D, 0xCFAF, 0x5E2E, 0xB0EF, 0x5E2F, 0x8EA1, 0x5E30, 0x8EA2, 0x5E31, 0xE0FC, 0x5E32, 0x8EA3, + 0x5E33, 0x8EA4, 0x5E34, 0x8EA5, 0x5E35, 0x8EA6, 0x5E36, 0x8EA7, 0x5E37, 0xE1A1, 0x5E38, 0xB3A3, 0x5E39, 0x8EA8, 0x5E3A, 0x8EA9, + 0x5E3B, 0xE0FD, 0x5E3C, 0xE0FE, 0x5E3D, 0xC3B1, 0x5E3E, 0x8EAA, 0x5E3F, 0x8EAB, 0x5E40, 0x8EAC, 0x5E41, 0x8EAD, 0x5E42, 0xC3DD, + 0x5E43, 0x8EAE, 0x5E44, 0xE1A2, 0x5E45, 0xB7F9, 0x5E46, 0x8EAF, 0x5E47, 0x8EB0, 0x5E48, 0x8EB1, 0x5E49, 0x8EB2, 0x5E4A, 0x8EB3, + 0x5E4B, 0x8EB4, 0x5E4C, 0xBBCF, 0x5E4D, 0x8EB5, 0x5E4E, 0x8EB6, 0x5E4F, 0x8EB7, 0x5E50, 0x8EB8, 0x5E51, 0x8EB9, 0x5E52, 0x8EBA, + 0x5E53, 0x8EBB, 0x5E54, 0xE1A3, 0x5E55, 0xC4BB, 0x5E56, 0x8EBC, 0x5E57, 0x8EBD, 0x5E58, 0x8EBE, 0x5E59, 0x8EBF, 0x5E5A, 0x8EC0, + 0x5E5B, 0xE1A4, 0x5E5C, 0x8EC1, 0x5E5D, 0x8EC2, 0x5E5E, 0xE1A5, 0x5E5F, 0x8EC3, 0x5E60, 0x8EC4, 0x5E61, 0xE1A6, 0x5E62, 0xB4B1, + 0x5E63, 0x8EC5, 0x5E64, 0x8EC6, 0x5E65, 0x8EC7, 0x5E66, 0x8EC8, 0x5E67, 0x8EC9, 0x5E68, 0x8ECA, 0x5E69, 0x8ECB, 0x5E6A, 0x8ECC, + 0x5E6B, 0x8ECD, 0x5E6C, 0x8ECE, 0x5E6D, 0x8ECF, 0x5E6E, 0x8ED0, 0x5E6F, 0x8ED1, 0x5E70, 0x8ED2, 0x5E71, 0x8ED3, 0x5E72, 0xB8C9, + 0x5E73, 0xC6BD, 0x5E74, 0xC4EA, 0x5E75, 0x8ED4, 0x5E76, 0xB2A2, 0x5E77, 0x8ED5, 0x5E78, 0xD0D2, 0x5E79, 0x8ED6, 0x5E7A, 0xE7DB, + 0x5E7B, 0xBBC3, 0x5E7C, 0xD3D7, 0x5E7D, 0xD3C4, 0x5E7E, 0x8ED7, 0x5E7F, 0xB9E3, 0x5E80, 0xE2CF, 0x5E81, 0x8ED8, 0x5E82, 0x8ED9, + 0x5E83, 0x8EDA, 0x5E84, 0xD7AF, 0x5E85, 0x8EDB, 0x5E86, 0xC7EC, 0x5E87, 0xB1D3, 0x5E88, 0x8EDC, 0x5E89, 0x8EDD, 0x5E8A, 0xB4B2, + 0x5E8B, 0xE2D1, 0x5E8C, 0x8EDE, 0x5E8D, 0x8EDF, 0x5E8E, 0x8EE0, 0x5E8F, 0xD0F2, 0x5E90, 0xC2AE, 0x5E91, 0xE2D0, 0x5E92, 0x8EE1, + 0x5E93, 0xBFE2, 0x5E94, 0xD3A6, 0x5E95, 0xB5D7, 0x5E96, 0xE2D2, 0x5E97, 0xB5EA, 0x5E98, 0x8EE2, 0x5E99, 0xC3ED, 0x5E9A, 0xB8FD, + 0x5E9B, 0x8EE3, 0x5E9C, 0xB8AE, 0x5E9D, 0x8EE4, 0x5E9E, 0xC5D3, 0x5E9F, 0xB7CF, 0x5EA0, 0xE2D4, 0x5EA1, 0x8EE5, 0x5EA2, 0x8EE6, + 0x5EA3, 0x8EE7, 0x5EA4, 0x8EE8, 0x5EA5, 0xE2D3, 0x5EA6, 0xB6C8, 0x5EA7, 0xD7F9, 0x5EA8, 0x8EE9, 0x5EA9, 0x8EEA, 0x5EAA, 0x8EEB, + 0x5EAB, 0x8EEC, 0x5EAC, 0x8EED, 0x5EAD, 0xCDA5, 0x5EAE, 0x8EEE, 0x5EAF, 0x8EEF, 0x5EB0, 0x8EF0, 0x5EB1, 0x8EF1, 0x5EB2, 0x8EF2, + 0x5EB3, 0xE2D8, 0x5EB4, 0x8EF3, 0x5EB5, 0xE2D6, 0x5EB6, 0xCAFC, 0x5EB7, 0xBFB5, 0x5EB8, 0xD3B9, 0x5EB9, 0xE2D5, 0x5EBA, 0x8EF4, + 0x5EBB, 0x8EF5, 0x5EBC, 0x8EF6, 0x5EBD, 0x8EF7, 0x5EBE, 0xE2D7, 0x5EBF, 0x8EF8, 0x5EC0, 0x8EF9, 0x5EC1, 0x8EFA, 0x5EC2, 0x8EFB, + 0x5EC3, 0x8EFC, 0x5EC4, 0x8EFD, 0x5EC5, 0x8EFE, 0x5EC6, 0x8F40, 0x5EC7, 0x8F41, 0x5EC8, 0x8F42, 0x5EC9, 0xC1AE, 0x5ECA, 0xC0C8, + 0x5ECB, 0x8F43, 0x5ECC, 0x8F44, 0x5ECD, 0x8F45, 0x5ECE, 0x8F46, 0x5ECF, 0x8F47, 0x5ED0, 0x8F48, 0x5ED1, 0xE2DB, 0x5ED2, 0xE2DA, + 0x5ED3, 0xC0AA, 0x5ED4, 0x8F49, 0x5ED5, 0x8F4A, 0x5ED6, 0xC1CE, 0x5ED7, 0x8F4B, 0x5ED8, 0x8F4C, 0x5ED9, 0x8F4D, 0x5EDA, 0x8F4E, + 0x5EDB, 0xE2DC, 0x5EDC, 0x8F4F, 0x5EDD, 0x8F50, 0x5EDE, 0x8F51, 0x5EDF, 0x8F52, 0x5EE0, 0x8F53, 0x5EE1, 0x8F54, 0x5EE2, 0x8F55, + 0x5EE3, 0x8F56, 0x5EE4, 0x8F57, 0x5EE5, 0x8F58, 0x5EE6, 0x8F59, 0x5EE7, 0x8F5A, 0x5EE8, 0xE2DD, 0x5EE9, 0x8F5B, 0x5EEA, 0xE2DE, + 0x5EEB, 0x8F5C, 0x5EEC, 0x8F5D, 0x5EED, 0x8F5E, 0x5EEE, 0x8F5F, 0x5EEF, 0x8F60, 0x5EF0, 0x8F61, 0x5EF1, 0x8F62, 0x5EF2, 0x8F63, + 0x5EF3, 0x8F64, 0x5EF4, 0xDBC8, 0x5EF5, 0x8F65, 0x5EF6, 0xD1D3, 0x5EF7, 0xCDA2, 0x5EF8, 0x8F66, 0x5EF9, 0x8F67, 0x5EFA, 0xBDA8, + 0x5EFB, 0x8F68, 0x5EFC, 0x8F69, 0x5EFD, 0x8F6A, 0x5EFE, 0xDEC3, 0x5EFF, 0xD8A5, 0x5F00, 0xBFAA, 0x5F01, 0xDBCD, 0x5F02, 0xD2EC, + 0x5F03, 0xC6FA, 0x5F04, 0xC5AA, 0x5F05, 0x8F6B, 0x5F06, 0x8F6C, 0x5F07, 0x8F6D, 0x5F08, 0xDEC4, 0x5F09, 0x8F6E, 0x5F0A, 0xB1D7, + 0x5F0B, 0xDFAE, 0x5F0C, 0x8F6F, 0x5F0D, 0x8F70, 0x5F0E, 0x8F71, 0x5F0F, 0xCABD, 0x5F10, 0x8F72, 0x5F11, 0xDFB1, 0x5F12, 0x8F73, + 0x5F13, 0xB9AD, 0x5F14, 0x8F74, 0x5F15, 0xD2FD, 0x5F16, 0x8F75, 0x5F17, 0xB8A5, 0x5F18, 0xBAEB, 0x5F19, 0x8F76, 0x5F1A, 0x8F77, + 0x5F1B, 0xB3DA, 0x5F1C, 0x8F78, 0x5F1D, 0x8F79, 0x5F1E, 0x8F7A, 0x5F1F, 0xB5DC, 0x5F20, 0xD5C5, 0x5F21, 0x8F7B, 0x5F22, 0x8F7C, + 0x5F23, 0x8F7D, 0x5F24, 0x8F7E, 0x5F25, 0xC3D6, 0x5F26, 0xCFD2, 0x5F27, 0xBBA1, 0x5F28, 0x8F80, 0x5F29, 0xE5F3, 0x5F2A, 0xE5F2, + 0x5F2B, 0x8F81, 0x5F2C, 0x8F82, 0x5F2D, 0xE5F4, 0x5F2E, 0x8F83, 0x5F2F, 0xCDE4, 0x5F30, 0x8F84, 0x5F31, 0xC8F5, 0x5F32, 0x8F85, + 0x5F33, 0x8F86, 0x5F34, 0x8F87, 0x5F35, 0x8F88, 0x5F36, 0x8F89, 0x5F37, 0x8F8A, 0x5F38, 0x8F8B, 0x5F39, 0xB5AF, 0x5F3A, 0xC7BF, + 0x5F3B, 0x8F8C, 0x5F3C, 0xE5F6, 0x5F3D, 0x8F8D, 0x5F3E, 0x8F8E, 0x5F3F, 0x8F8F, 0x5F40, 0xECB0, 0x5F41, 0x8F90, 0x5F42, 0x8F91, + 0x5F43, 0x8F92, 0x5F44, 0x8F93, 0x5F45, 0x8F94, 0x5F46, 0x8F95, 0x5F47, 0x8F96, 0x5F48, 0x8F97, 0x5F49, 0x8F98, 0x5F4A, 0x8F99, + 0x5F4B, 0x8F9A, 0x5F4C, 0x8F9B, 0x5F4D, 0x8F9C, 0x5F4E, 0x8F9D, 0x5F4F, 0x8F9E, 0x5F50, 0xE5E6, 0x5F51, 0x8F9F, 0x5F52, 0xB9E9, + 0x5F53, 0xB5B1, 0x5F54, 0x8FA0, 0x5F55, 0xC2BC, 0x5F56, 0xE5E8, 0x5F57, 0xE5E7, 0x5F58, 0xE5E9, 0x5F59, 0x8FA1, 0x5F5A, 0x8FA2, + 0x5F5B, 0x8FA3, 0x5F5C, 0x8FA4, 0x5F5D, 0xD2CD, 0x5F5E, 0x8FA5, 0x5F5F, 0x8FA6, 0x5F60, 0x8FA7, 0x5F61, 0xE1EA, 0x5F62, 0xD0CE, + 0x5F63, 0x8FA8, 0x5F64, 0xCDAE, 0x5F65, 0x8FA9, 0x5F66, 0xD1E5, 0x5F67, 0x8FAA, 0x5F68, 0x8FAB, 0x5F69, 0xB2CA, 0x5F6A, 0xB1EB, + 0x5F6B, 0x8FAC, 0x5F6C, 0xB1F2, 0x5F6D, 0xC5ED, 0x5F6E, 0x8FAD, 0x5F6F, 0x8FAE, 0x5F70, 0xD5C3, 0x5F71, 0xD3B0, 0x5F72, 0x8FAF, + 0x5F73, 0xE1DC, 0x5F74, 0x8FB0, 0x5F75, 0x8FB1, 0x5F76, 0x8FB2, 0x5F77, 0xE1DD, 0x5F78, 0x8FB3, 0x5F79, 0xD2DB, 0x5F7A, 0x8FB4, + 0x5F7B, 0xB3B9, 0x5F7C, 0xB1CB, 0x5F7D, 0x8FB5, 0x5F7E, 0x8FB6, 0x5F7F, 0x8FB7, 0x5F80, 0xCDF9, 0x5F81, 0xD5F7, 0x5F82, 0xE1DE, + 0x5F83, 0x8FB8, 0x5F84, 0xBEB6, 0x5F85, 0xB4FD, 0x5F86, 0x8FB9, 0x5F87, 0xE1DF, 0x5F88, 0xBADC, 0x5F89, 0xE1E0, 0x5F8A, 0xBBB2, + 0x5F8B, 0xC2C9, 0x5F8C, 0xE1E1, 0x5F8D, 0x8FBA, 0x5F8E, 0x8FBB, 0x5F8F, 0x8FBC, 0x5F90, 0xD0EC, 0x5F91, 0x8FBD, 0x5F92, 0xCDBD, + 0x5F93, 0x8FBE, 0x5F94, 0x8FBF, 0x5F95, 0xE1E2, 0x5F96, 0x8FC0, 0x5F97, 0xB5C3, 0x5F98, 0xC5C7, 0x5F99, 0xE1E3, 0x5F9A, 0x8FC1, + 0x5F9B, 0x8FC2, 0x5F9C, 0xE1E4, 0x5F9D, 0x8FC3, 0x5F9E, 0x8FC4, 0x5F9F, 0x8FC5, 0x5FA0, 0x8FC6, 0x5FA1, 0xD3F9, 0x5FA2, 0x8FC7, + 0x5FA3, 0x8FC8, 0x5FA4, 0x8FC9, 0x5FA5, 0x8FCA, 0x5FA6, 0x8FCB, 0x5FA7, 0x8FCC, 0x5FA8, 0xE1E5, 0x5FA9, 0x8FCD, 0x5FAA, 0xD1AD, + 0x5FAB, 0x8FCE, 0x5FAC, 0x8FCF, 0x5FAD, 0xE1E6, 0x5FAE, 0xCEA2, 0x5FAF, 0x8FD0, 0x5FB0, 0x8FD1, 0x5FB1, 0x8FD2, 0x5FB2, 0x8FD3, + 0x5FB3, 0x8FD4, 0x5FB4, 0x8FD5, 0x5FB5, 0xE1E7, 0x5FB6, 0x8FD6, 0x5FB7, 0xB5C2, 0x5FB8, 0x8FD7, 0x5FB9, 0x8FD8, 0x5FBA, 0x8FD9, + 0x5FBB, 0x8FDA, 0x5FBC, 0xE1E8, 0x5FBD, 0xBBD5, 0x5FBE, 0x8FDB, 0x5FBF, 0x8FDC, 0x5FC0, 0x8FDD, 0x5FC1, 0x8FDE, 0x5FC2, 0x8FDF, + 0x5FC3, 0xD0C4, 0x5FC4, 0xE2E0, 0x5FC5, 0xB1D8, 0x5FC6, 0xD2E4, 0x5FC7, 0x8FE0, 0x5FC8, 0x8FE1, 0x5FC9, 0xE2E1, 0x5FCA, 0x8FE2, + 0x5FCB, 0x8FE3, 0x5FCC, 0xBCC9, 0x5FCD, 0xC8CC, 0x5FCE, 0x8FE4, 0x5FCF, 0xE2E3, 0x5FD0, 0xECFE, 0x5FD1, 0xECFD, 0x5FD2, 0xDFAF, + 0x5FD3, 0x8FE5, 0x5FD4, 0x8FE6, 0x5FD5, 0x8FE7, 0x5FD6, 0xE2E2, 0x5FD7, 0xD6BE, 0x5FD8, 0xCDFC, 0x5FD9, 0xC3A6, 0x5FDA, 0x8FE8, + 0x5FDB, 0x8FE9, 0x5FDC, 0x8FEA, 0x5FDD, 0xE3C3, 0x5FDE, 0x8FEB, 0x5FDF, 0x8FEC, 0x5FE0, 0xD6D2, 0x5FE1, 0xE2E7, 0x5FE2, 0x8FED, + 0x5FE3, 0x8FEE, 0x5FE4, 0xE2E8, 0x5FE5, 0x8FEF, 0x5FE6, 0x8FF0, 0x5FE7, 0xD3C7, 0x5FE8, 0x8FF1, 0x5FE9, 0x8FF2, 0x5FEA, 0xE2EC, + 0x5FEB, 0xBFEC, 0x5FEC, 0x8FF3, 0x5FED, 0xE2ED, 0x5FEE, 0xE2E5, 0x5FEF, 0x8FF4, 0x5FF0, 0x8FF5, 0x5FF1, 0xB3C0, 0x5FF2, 0x8FF6, + 0x5FF3, 0x8FF7, 0x5FF4, 0x8FF8, 0x5FF5, 0xC4EE, 0x5FF6, 0x8FF9, 0x5FF7, 0x8FFA, 0x5FF8, 0xE2EE, 0x5FF9, 0x8FFB, 0x5FFA, 0x8FFC, + 0x5FFB, 0xD0C3, 0x5FFC, 0x8FFD, 0x5FFD, 0xBAF6, 0x5FFE, 0xE2E9, 0x5FFF, 0xB7DE, 0x6000, 0xBBB3, 0x6001, 0xCCAC, 0x6002, 0xCBCB, + 0x6003, 0xE2E4, 0x6004, 0xE2E6, 0x6005, 0xE2EA, 0x6006, 0xE2EB, 0x6007, 0x8FFE, 0x6008, 0x9040, 0x6009, 0x9041, 0x600A, 0xE2F7, + 0x600B, 0x9042, 0x600C, 0x9043, 0x600D, 0xE2F4, 0x600E, 0xD4F5, 0x600F, 0xE2F3, 0x6010, 0x9044, 0x6011, 0x9045, 0x6012, 0xC5AD, + 0x6013, 0x9046, 0x6014, 0xD5FA, 0x6015, 0xC5C2, 0x6016, 0xB2C0, 0x6017, 0x9047, 0x6018, 0x9048, 0x6019, 0xE2EF, 0x601A, 0x9049, + 0x601B, 0xE2F2, 0x601C, 0xC1AF, 0x601D, 0xCBBC, 0x601E, 0x904A, 0x601F, 0x904B, 0x6020, 0xB5A1, 0x6021, 0xE2F9, 0x6022, 0x904C, + 0x6023, 0x904D, 0x6024, 0x904E, 0x6025, 0xBCB1, 0x6026, 0xE2F1, 0x6027, 0xD0D4, 0x6028, 0xD4B9, 0x6029, 0xE2F5, 0x602A, 0xB9D6, + 0x602B, 0xE2F6, 0x602C, 0x904F, 0x602D, 0x9050, 0x602E, 0x9051, 0x602F, 0xC7D3, 0x6030, 0x9052, 0x6031, 0x9053, 0x6032, 0x9054, + 0x6033, 0x9055, 0x6034, 0x9056, 0x6035, 0xE2F0, 0x6036, 0x9057, 0x6037, 0x9058, 0x6038, 0x9059, 0x6039, 0x905A, 0x603A, 0x905B, + 0x603B, 0xD7DC, 0x603C, 0xEDA1, 0x603D, 0x905C, 0x603E, 0x905D, 0x603F, 0xE2F8, 0x6040, 0x905E, 0x6041, 0xEDA5, 0x6042, 0xE2FE, + 0x6043, 0xCAD1, 0x6044, 0x905F, 0x6045, 0x9060, 0x6046, 0x9061, 0x6047, 0x9062, 0x6048, 0x9063, 0x6049, 0x9064, 0x604A, 0x9065, + 0x604B, 0xC1B5, 0x604C, 0x9066, 0x604D, 0xBBD0, 0x604E, 0x9067, 0x604F, 0x9068, 0x6050, 0xBFD6, 0x6051, 0x9069, 0x6052, 0xBAE3, + 0x6053, 0x906A, 0x6054, 0x906B, 0x6055, 0xCBA1, 0x6056, 0x906C, 0x6057, 0x906D, 0x6058, 0x906E, 0x6059, 0xEDA6, 0x605A, 0xEDA3, + 0x605B, 0x906F, 0x605C, 0x9070, 0x605D, 0xEDA2, 0x605E, 0x9071, 0x605F, 0x9072, 0x6060, 0x9073, 0x6061, 0x9074, 0x6062, 0xBBD6, + 0x6063, 0xEDA7, 0x6064, 0xD0F4, 0x6065, 0x9075, 0x6066, 0x9076, 0x6067, 0xEDA4, 0x6068, 0xBADE, 0x6069, 0xB6F7, 0x606A, 0xE3A1, + 0x606B, 0xB6B2, 0x606C, 0xCCF1, 0x606D, 0xB9A7, 0x606E, 0x9077, 0x606F, 0xCFA2, 0x6070, 0xC7A1, 0x6071, 0x9078, 0x6072, 0x9079, + 0x6073, 0xBFD2, 0x6074, 0x907A, 0x6075, 0x907B, 0x6076, 0xB6F1, 0x6077, 0x907C, 0x6078, 0xE2FA, 0x6079, 0xE2FB, 0x607A, 0xE2FD, + 0x607B, 0xE2FC, 0x607C, 0xC4D5, 0x607D, 0xE3A2, 0x607E, 0x907D, 0x607F, 0xD3C1, 0x6080, 0x907E, 0x6081, 0x9080, 0x6082, 0x9081, + 0x6083, 0xE3A7, 0x6084, 0xC7C4, 0x6085, 0x9082, 0x6086, 0x9083, 0x6087, 0x9084, 0x6088, 0x9085, 0x6089, 0xCFA4, 0x608A, 0x9086, + 0x608B, 0x9087, 0x608C, 0xE3A9, 0x608D, 0xBAB7, 0x608E, 0x9088, 0x608F, 0x9089, 0x6090, 0x908A, 0x6091, 0x908B, 0x6092, 0xE3A8, + 0x6093, 0x908C, 0x6094, 0xBBDA, 0x6095, 0x908D, 0x6096, 0xE3A3, 0x6097, 0x908E, 0x6098, 0x908F, 0x6099, 0x9090, 0x609A, 0xE3A4, + 0x609B, 0xE3AA, 0x609C, 0x9091, 0x609D, 0xE3A6, 0x609E, 0x9092, 0x609F, 0xCEF2, 0x60A0, 0xD3C6, 0x60A1, 0x9093, 0x60A2, 0x9094, + 0x60A3, 0xBBBC, 0x60A4, 0x9095, 0x60A5, 0x9096, 0x60A6, 0xD4C3, 0x60A7, 0x9097, 0x60A8, 0xC4FA, 0x60A9, 0x9098, 0x60AA, 0x9099, + 0x60AB, 0xEDA8, 0x60AC, 0xD0FC, 0x60AD, 0xE3A5, 0x60AE, 0x909A, 0x60AF, 0xC3F5, 0x60B0, 0x909B, 0x60B1, 0xE3AD, 0x60B2, 0xB1AF, + 0x60B3, 0x909C, 0x60B4, 0xE3B2, 0x60B5, 0x909D, 0x60B6, 0x909E, 0x60B7, 0x909F, 0x60B8, 0xBCC2, 0x60B9, 0x90A0, 0x60BA, 0x90A1, + 0x60BB, 0xE3AC, 0x60BC, 0xB5BF, 0x60BD, 0x90A2, 0x60BE, 0x90A3, 0x60BF, 0x90A4, 0x60C0, 0x90A5, 0x60C1, 0x90A6, 0x60C2, 0x90A7, + 0x60C3, 0x90A8, 0x60C4, 0x90A9, 0x60C5, 0xC7E9, 0x60C6, 0xE3B0, 0x60C7, 0x90AA, 0x60C8, 0x90AB, 0x60C9, 0x90AC, 0x60CA, 0xBEAA, + 0x60CB, 0xCDEF, 0x60CC, 0x90AD, 0x60CD, 0x90AE, 0x60CE, 0x90AF, 0x60CF, 0x90B0, 0x60D0, 0x90B1, 0x60D1, 0xBBF3, 0x60D2, 0x90B2, + 0x60D3, 0x90B3, 0x60D4, 0x90B4, 0x60D5, 0xCCE8, 0x60D6, 0x90B5, 0x60D7, 0x90B6, 0x60D8, 0xE3AF, 0x60D9, 0x90B7, 0x60DA, 0xE3B1, + 0x60DB, 0x90B8, 0x60DC, 0xCFA7, 0x60DD, 0xE3AE, 0x60DE, 0x90B9, 0x60DF, 0xCEA9, 0x60E0, 0xBBDD, 0x60E1, 0x90BA, 0x60E2, 0x90BB, + 0x60E3, 0x90BC, 0x60E4, 0x90BD, 0x60E5, 0x90BE, 0x60E6, 0xB5EB, 0x60E7, 0xBEE5, 0x60E8, 0xB2D2, 0x60E9, 0xB3CD, 0x60EA, 0x90BF, + 0x60EB, 0xB1B9, 0x60EC, 0xE3AB, 0x60ED, 0xB2D1, 0x60EE, 0xB5AC, 0x60EF, 0xB9DF, 0x60F0, 0xB6E8, 0x60F1, 0x90C0, 0x60F2, 0x90C1, + 0x60F3, 0xCFEB, 0x60F4, 0xE3B7, 0x60F5, 0x90C2, 0x60F6, 0xBBCC, 0x60F7, 0x90C3, 0x60F8, 0x90C4, 0x60F9, 0xC8C7, 0x60FA, 0xD0CA, + 0x60FB, 0x90C5, 0x60FC, 0x90C6, 0x60FD, 0x90C7, 0x60FE, 0x90C8, 0x60FF, 0x90C9, 0x6100, 0xE3B8, 0x6101, 0xB3EE, 0x6102, 0x90CA, + 0x6103, 0x90CB, 0x6104, 0x90CC, 0x6105, 0x90CD, 0x6106, 0xEDA9, 0x6107, 0x90CE, 0x6108, 0xD3FA, 0x6109, 0xD3E4, 0x610A, 0x90CF, + 0x610B, 0x90D0, 0x610C, 0x90D1, 0x610D, 0xEDAA, 0x610E, 0xE3B9, 0x610F, 0xD2E2, 0x6110, 0x90D2, 0x6111, 0x90D3, 0x6112, 0x90D4, + 0x6113, 0x90D5, 0x6114, 0x90D6, 0x6115, 0xE3B5, 0x6116, 0x90D7, 0x6117, 0x90D8, 0x6118, 0x90D9, 0x6119, 0x90DA, 0x611A, 0xD3DE, + 0x611B, 0x90DB, 0x611C, 0x90DC, 0x611D, 0x90DD, 0x611E, 0x90DE, 0x611F, 0xB8D0, 0x6120, 0xE3B3, 0x6121, 0x90DF, 0x6122, 0x90E0, + 0x6123, 0xE3B6, 0x6124, 0xB7DF, 0x6125, 0x90E1, 0x6126, 0xE3B4, 0x6127, 0xC0A2, 0x6128, 0x90E2, 0x6129, 0x90E3, 0x612A, 0x90E4, + 0x612B, 0xE3BA, 0x612C, 0x90E5, 0x612D, 0x90E6, 0x612E, 0x90E7, 0x612F, 0x90E8, 0x6130, 0x90E9, 0x6131, 0x90EA, 0x6132, 0x90EB, + 0x6133, 0x90EC, 0x6134, 0x90ED, 0x6135, 0x90EE, 0x6136, 0x90EF, 0x6137, 0x90F0, 0x6138, 0x90F1, 0x6139, 0x90F2, 0x613A, 0x90F3, + 0x613B, 0x90F4, 0x613C, 0x90F5, 0x613D, 0x90F6, 0x613E, 0x90F7, 0x613F, 0xD4B8, 0x6140, 0x90F8, 0x6141, 0x90F9, 0x6142, 0x90FA, + 0x6143, 0x90FB, 0x6144, 0x90FC, 0x6145, 0x90FD, 0x6146, 0x90FE, 0x6147, 0x9140, 0x6148, 0xB4C8, 0x6149, 0x9141, 0x614A, 0xE3BB, + 0x614B, 0x9142, 0x614C, 0xBBC5, 0x614D, 0x9143, 0x614E, 0xC9F7, 0x614F, 0x9144, 0x6150, 0x9145, 0x6151, 0xC9E5, 0x6152, 0x9146, + 0x6153, 0x9147, 0x6154, 0x9148, 0x6155, 0xC4BD, 0x6156, 0x9149, 0x6157, 0x914A, 0x6158, 0x914B, 0x6159, 0x914C, 0x615A, 0x914D, + 0x615B, 0x914E, 0x615C, 0x914F, 0x615D, 0xEDAB, 0x615E, 0x9150, 0x615F, 0x9151, 0x6160, 0x9152, 0x6161, 0x9153, 0x6162, 0xC2FD, + 0x6163, 0x9154, 0x6164, 0x9155, 0x6165, 0x9156, 0x6166, 0x9157, 0x6167, 0xBBDB, 0x6168, 0xBFAE, 0x6169, 0x9158, 0x616A, 0x9159, + 0x616B, 0x915A, 0x616C, 0x915B, 0x616D, 0x915C, 0x616E, 0x915D, 0x616F, 0x915E, 0x6170, 0xCEBF, 0x6171, 0x915F, 0x6172, 0x9160, + 0x6173, 0x9161, 0x6174, 0x9162, 0x6175, 0xE3BC, 0x6176, 0x9163, 0x6177, 0xBFB6, 0x6178, 0x9164, 0x6179, 0x9165, 0x617A, 0x9166, + 0x617B, 0x9167, 0x617C, 0x9168, 0x617D, 0x9169, 0x617E, 0x916A, 0x617F, 0x916B, 0x6180, 0x916C, 0x6181, 0x916D, 0x6182, 0x916E, + 0x6183, 0x916F, 0x6184, 0x9170, 0x6185, 0x9171, 0x6186, 0x9172, 0x6187, 0x9173, 0x6188, 0x9174, 0x6189, 0x9175, 0x618A, 0x9176, + 0x618B, 0xB1EF, 0x618C, 0x9177, 0x618D, 0x9178, 0x618E, 0xD4F7, 0x618F, 0x9179, 0x6190, 0x917A, 0x6191, 0x917B, 0x6192, 0x917C, + 0x6193, 0x917D, 0x6194, 0xE3BE, 0x6195, 0x917E, 0x6196, 0x9180, 0x6197, 0x9181, 0x6198, 0x9182, 0x6199, 0x9183, 0x619A, 0x9184, + 0x619B, 0x9185, 0x619C, 0x9186, 0x619D, 0xEDAD, 0x619E, 0x9187, 0x619F, 0x9188, 0x61A0, 0x9189, 0x61A1, 0x918A, 0x61A2, 0x918B, + 0x61A3, 0x918C, 0x61A4, 0x918D, 0x61A5, 0x918E, 0x61A6, 0x918F, 0x61A7, 0xE3BF, 0x61A8, 0xBAA9, 0x61A9, 0xEDAC, 0x61AA, 0x9190, + 0x61AB, 0x9191, 0x61AC, 0xE3BD, 0x61AD, 0x9192, 0x61AE, 0x9193, 0x61AF, 0x9194, 0x61B0, 0x9195, 0x61B1, 0x9196, 0x61B2, 0x9197, + 0x61B3, 0x9198, 0x61B4, 0x9199, 0x61B5, 0x919A, 0x61B6, 0x919B, 0x61B7, 0xE3C0, 0x61B8, 0x919C, 0x61B9, 0x919D, 0x61BA, 0x919E, + 0x61BB, 0x919F, 0x61BC, 0x91A0, 0x61BD, 0x91A1, 0x61BE, 0xBAB6, 0x61BF, 0x91A2, 0x61C0, 0x91A3, 0x61C1, 0x91A4, 0x61C2, 0xB6AE, + 0x61C3, 0x91A5, 0x61C4, 0x91A6, 0x61C5, 0x91A7, 0x61C6, 0x91A8, 0x61C7, 0x91A9, 0x61C8, 0xD0B8, 0x61C9, 0x91AA, 0x61CA, 0xB0C3, + 0x61CB, 0xEDAE, 0x61CC, 0x91AB, 0x61CD, 0x91AC, 0x61CE, 0x91AD, 0x61CF, 0x91AE, 0x61D0, 0x91AF, 0x61D1, 0xEDAF, 0x61D2, 0xC0C1, + 0x61D3, 0x91B0, 0x61D4, 0xE3C1, 0x61D5, 0x91B1, 0x61D6, 0x91B2, 0x61D7, 0x91B3, 0x61D8, 0x91B4, 0x61D9, 0x91B5, 0x61DA, 0x91B6, + 0x61DB, 0x91B7, 0x61DC, 0x91B8, 0x61DD, 0x91B9, 0x61DE, 0x91BA, 0x61DF, 0x91BB, 0x61E0, 0x91BC, 0x61E1, 0x91BD, 0x61E2, 0x91BE, + 0x61E3, 0x91BF, 0x61E4, 0x91C0, 0x61E5, 0x91C1, 0x61E6, 0xC5B3, 0x61E7, 0x91C2, 0x61E8, 0x91C3, 0x61E9, 0x91C4, 0x61EA, 0x91C5, + 0x61EB, 0x91C6, 0x61EC, 0x91C7, 0x61ED, 0x91C8, 0x61EE, 0x91C9, 0x61EF, 0x91CA, 0x61F0, 0x91CB, 0x61F1, 0x91CC, 0x61F2, 0x91CD, + 0x61F3, 0x91CE, 0x61F4, 0x91CF, 0x61F5, 0xE3C2, 0x61F6, 0x91D0, 0x61F7, 0x91D1, 0x61F8, 0x91D2, 0x61F9, 0x91D3, 0x61FA, 0x91D4, + 0x61FB, 0x91D5, 0x61FC, 0x91D6, 0x61FD, 0x91D7, 0x61FE, 0x91D8, 0x61FF, 0xDCB2, 0x6200, 0x91D9, 0x6201, 0x91DA, 0x6202, 0x91DB, + 0x6203, 0x91DC, 0x6204, 0x91DD, 0x6205, 0x91DE, 0x6206, 0xEDB0, 0x6207, 0x91DF, 0x6208, 0xB8EA, 0x6209, 0x91E0, 0x620A, 0xCEEC, + 0x620B, 0xEAA7, 0x620C, 0xD0E7, 0x620D, 0xCAF9, 0x620E, 0xC8D6, 0x620F, 0xCFB7, 0x6210, 0xB3C9, 0x6211, 0xCED2, 0x6212, 0xBDE4, + 0x6213, 0x91E1, 0x6214, 0x91E2, 0x6215, 0xE3DE, 0x6216, 0xBBF2, 0x6217, 0xEAA8, 0x6218, 0xD5BD, 0x6219, 0x91E3, 0x621A, 0xC6DD, + 0x621B, 0xEAA9, 0x621C, 0x91E4, 0x621D, 0x91E5, 0x621E, 0x91E6, 0x621F, 0xEAAA, 0x6220, 0x91E7, 0x6221, 0xEAAC, 0x6222, 0xEAAB, + 0x6223, 0x91E8, 0x6224, 0xEAAE, 0x6225, 0xEAAD, 0x6226, 0x91E9, 0x6227, 0x91EA, 0x6228, 0x91EB, 0x6229, 0x91EC, 0x622A, 0xBDD8, + 0x622B, 0x91ED, 0x622C, 0xEAAF, 0x622D, 0x91EE, 0x622E, 0xC2BE, 0x622F, 0x91EF, 0x6230, 0x91F0, 0x6231, 0x91F1, 0x6232, 0x91F2, + 0x6233, 0xB4C1, 0x6234, 0xB4F7, 0x6235, 0x91F3, 0x6236, 0x91F4, 0x6237, 0xBBA7, 0x6238, 0x91F5, 0x6239, 0x91F6, 0x623A, 0x91F7, + 0x623B, 0x91F8, 0x623C, 0x91F9, 0x623D, 0xECE6, 0x623E, 0xECE5, 0x623F, 0xB7BF, 0x6240, 0xCBF9, 0x6241, 0xB1E2, 0x6242, 0x91FA, + 0x6243, 0xECE7, 0x6244, 0x91FB, 0x6245, 0x91FC, 0x6246, 0x91FD, 0x6247, 0xC9C8, 0x6248, 0xECE8, 0x6249, 0xECE9, 0x624A, 0x91FE, + 0x624B, 0xCAD6, 0x624C, 0xDED0, 0x624D, 0xB2C5, 0x624E, 0xD4FA, 0x624F, 0x9240, 0x6250, 0x9241, 0x6251, 0xC6CB, 0x6252, 0xB0C7, + 0x6253, 0xB4F2, 0x6254, 0xC8D3, 0x6255, 0x9242, 0x6256, 0x9243, 0x6257, 0x9244, 0x6258, 0xCDD0, 0x6259, 0x9245, 0x625A, 0x9246, + 0x625B, 0xBFB8, 0x625C, 0x9247, 0x625D, 0x9248, 0x625E, 0x9249, 0x625F, 0x924A, 0x6260, 0x924B, 0x6261, 0x924C, 0x6262, 0x924D, + 0x6263, 0xBFDB, 0x6264, 0x924E, 0x6265, 0x924F, 0x6266, 0xC7A4, 0x6267, 0xD6B4, 0x6268, 0x9250, 0x6269, 0xC0A9, 0x626A, 0xDED1, + 0x626B, 0xC9A8, 0x626C, 0xD1EF, 0x626D, 0xC5A4, 0x626E, 0xB0E7, 0x626F, 0xB3B6, 0x6270, 0xC8C5, 0x6271, 0x9251, 0x6272, 0x9252, + 0x6273, 0xB0E2, 0x6274, 0x9253, 0x6275, 0x9254, 0x6276, 0xB7F6, 0x6277, 0x9255, 0x6278, 0x9256, 0x6279, 0xC5FA, 0x627A, 0x9257, + 0x627B, 0x9258, 0x627C, 0xB6F3, 0x627D, 0x9259, 0x627E, 0xD5D2, 0x627F, 0xB3D0, 0x6280, 0xBCBC, 0x6281, 0x925A, 0x6282, 0x925B, + 0x6283, 0x925C, 0x6284, 0xB3AD, 0x6285, 0x925D, 0x6286, 0x925E, 0x6287, 0x925F, 0x6288, 0x9260, 0x6289, 0xBEF1, 0x628A, 0xB0D1, + 0x628B, 0x9261, 0x628C, 0x9262, 0x628D, 0x9263, 0x628E, 0x9264, 0x628F, 0x9265, 0x6290, 0x9266, 0x6291, 0xD2D6, 0x6292, 0xCAE3, + 0x6293, 0xD7A5, 0x6294, 0x9267, 0x6295, 0xCDB6, 0x6296, 0xB6B6, 0x6297, 0xBFB9, 0x6298, 0xD5DB, 0x6299, 0x9268, 0x629A, 0xB8A7, + 0x629B, 0xC5D7, 0x629C, 0x9269, 0x629D, 0x926A, 0x629E, 0x926B, 0x629F, 0xDED2, 0x62A0, 0xBFD9, 0x62A1, 0xC2D5, 0x62A2, 0xC7C0, + 0x62A3, 0x926C, 0x62A4, 0xBBA4, 0x62A5, 0xB1A8, 0x62A6, 0x926D, 0x62A7, 0x926E, 0x62A8, 0xC5EA, 0x62A9, 0x926F, 0x62AA, 0x9270, + 0x62AB, 0xC5FB, 0x62AC, 0xCCA7, 0x62AD, 0x9271, 0x62AE, 0x9272, 0x62AF, 0x9273, 0x62B0, 0x9274, 0x62B1, 0xB1A7, 0x62B2, 0x9275, + 0x62B3, 0x9276, 0x62B4, 0x9277, 0x62B5, 0xB5D6, 0x62B6, 0x9278, 0x62B7, 0x9279, 0x62B8, 0x927A, 0x62B9, 0xC4A8, 0x62BA, 0x927B, + 0x62BB, 0xDED3, 0x62BC, 0xD1BA, 0x62BD, 0xB3E9, 0x62BE, 0x927C, 0x62BF, 0xC3F2, 0x62C0, 0x927D, 0x62C1, 0x927E, 0x62C2, 0xB7F7, + 0x62C3, 0x9280, 0x62C4, 0xD6F4, 0x62C5, 0xB5A3, 0x62C6, 0xB2F0, 0x62C7, 0xC4B4, 0x62C8, 0xC4E9, 0x62C9, 0xC0AD, 0x62CA, 0xDED4, + 0x62CB, 0x9281, 0x62CC, 0xB0E8, 0x62CD, 0xC5C4, 0x62CE, 0xC1E0, 0x62CF, 0x9282, 0x62D0, 0xB9D5, 0x62D1, 0x9283, 0x62D2, 0xBEDC, + 0x62D3, 0xCDD8, 0x62D4, 0xB0CE, 0x62D5, 0x9284, 0x62D6, 0xCDCF, 0x62D7, 0xDED6, 0x62D8, 0xBED0, 0x62D9, 0xD7BE, 0x62DA, 0xDED5, + 0x62DB, 0xD5D0, 0x62DC, 0xB0DD, 0x62DD, 0x9285, 0x62DE, 0x9286, 0x62DF, 0xC4E2, 0x62E0, 0x9287, 0x62E1, 0x9288, 0x62E2, 0xC2A3, + 0x62E3, 0xBCF0, 0x62E4, 0x9289, 0x62E5, 0xD3B5, 0x62E6, 0xC0B9, 0x62E7, 0xC5A1, 0x62E8, 0xB2A6, 0x62E9, 0xD4F1, 0x62EA, 0x928A, + 0x62EB, 0x928B, 0x62EC, 0xC0A8, 0x62ED, 0xCAC3, 0x62EE, 0xDED7, 0x62EF, 0xD5FC, 0x62F0, 0x928C, 0x62F1, 0xB9B0, 0x62F2, 0x928D, + 0x62F3, 0xC8AD, 0x62F4, 0xCBA9, 0x62F5, 0x928E, 0x62F6, 0xDED9, 0x62F7, 0xBFBD, 0x62F8, 0x928F, 0x62F9, 0x9290, 0x62FA, 0x9291, + 0x62FB, 0x9292, 0x62FC, 0xC6B4, 0x62FD, 0xD7A7, 0x62FE, 0xCAB0, 0x62FF, 0xC4C3, 0x6300, 0x9293, 0x6301, 0xB3D6, 0x6302, 0xB9D2, + 0x6303, 0x9294, 0x6304, 0x9295, 0x6305, 0x9296, 0x6306, 0x9297, 0x6307, 0xD6B8, 0x6308, 0xEAFC, 0x6309, 0xB0B4, 0x630A, 0x9298, + 0x630B, 0x9299, 0x630C, 0x929A, 0x630D, 0x929B, 0x630E, 0xBFE6, 0x630F, 0x929C, 0x6310, 0x929D, 0x6311, 0xCCF4, 0x6312, 0x929E, + 0x6313, 0x929F, 0x6314, 0x92A0, 0x6315, 0x92A1, 0x6316, 0xCDDA, 0x6317, 0x92A2, 0x6318, 0x92A3, 0x6319, 0x92A4, 0x631A, 0xD6BF, + 0x631B, 0xC2CE, 0x631C, 0x92A5, 0x631D, 0xCECE, 0x631E, 0xCCA2, 0x631F, 0xD0AE, 0x6320, 0xC4D3, 0x6321, 0xB5B2, 0x6322, 0xDED8, + 0x6323, 0xD5F5, 0x6324, 0xBCB7, 0x6325, 0xBBD3, 0x6326, 0x92A6, 0x6327, 0x92A7, 0x6328, 0xB0A4, 0x6329, 0x92A8, 0x632A, 0xC5B2, + 0x632B, 0xB4EC, 0x632C, 0x92A9, 0x632D, 0x92AA, 0x632E, 0x92AB, 0x632F, 0xD5F1, 0x6330, 0x92AC, 0x6331, 0x92AD, 0x6332, 0xEAFD, + 0x6333, 0x92AE, 0x6334, 0x92AF, 0x6335, 0x92B0, 0x6336, 0x92B1, 0x6337, 0x92B2, 0x6338, 0x92B3, 0x6339, 0xDEDA, 0x633A, 0xCDA6, + 0x633B, 0x92B4, 0x633C, 0x92B5, 0x633D, 0xCDEC, 0x633E, 0x92B6, 0x633F, 0x92B7, 0x6340, 0x92B8, 0x6341, 0x92B9, 0x6342, 0xCEE6, + 0x6343, 0xDEDC, 0x6344, 0x92BA, 0x6345, 0xCDB1, 0x6346, 0xC0A6, 0x6347, 0x92BB, 0x6348, 0x92BC, 0x6349, 0xD7BD, 0x634A, 0x92BD, + 0x634B, 0xDEDB, 0x634C, 0xB0C6, 0x634D, 0xBAB4, 0x634E, 0xC9D3, 0x634F, 0xC4F3, 0x6350, 0xBEE8, 0x6351, 0x92BE, 0x6352, 0x92BF, + 0x6353, 0x92C0, 0x6354, 0x92C1, 0x6355, 0xB2B6, 0x6356, 0x92C2, 0x6357, 0x92C3, 0x6358, 0x92C4, 0x6359, 0x92C5, 0x635A, 0x92C6, + 0x635B, 0x92C7, 0x635C, 0x92C8, 0x635D, 0x92C9, 0x635E, 0xC0CC, 0x635F, 0xCBF0, 0x6360, 0x92CA, 0x6361, 0xBCF1, 0x6362, 0xBBBB, + 0x6363, 0xB5B7, 0x6364, 0x92CB, 0x6365, 0x92CC, 0x6366, 0x92CD, 0x6367, 0xC5F5, 0x6368, 0x92CE, 0x6369, 0xDEE6, 0x636A, 0x92CF, + 0x636B, 0x92D0, 0x636C, 0x92D1, 0x636D, 0xDEE3, 0x636E, 0xBEDD, 0x636F, 0x92D2, 0x6370, 0x92D3, 0x6371, 0xDEDF, 0x6372, 0x92D4, + 0x6373, 0x92D5, 0x6374, 0x92D6, 0x6375, 0x92D7, 0x6376, 0xB4B7, 0x6377, 0xBDDD, 0x6378, 0x92D8, 0x6379, 0x92D9, 0x637A, 0xDEE0, + 0x637B, 0xC4ED, 0x637C, 0x92DA, 0x637D, 0x92DB, 0x637E, 0x92DC, 0x637F, 0x92DD, 0x6380, 0xCFC6, 0x6381, 0x92DE, 0x6382, 0xB5E0, + 0x6383, 0x92DF, 0x6384, 0x92E0, 0x6385, 0x92E1, 0x6386, 0x92E2, 0x6387, 0xB6DE, 0x6388, 0xCADA, 0x6389, 0xB5F4, 0x638A, 0xDEE5, + 0x638B, 0x92E3, 0x638C, 0xD5C6, 0x638D, 0x92E4, 0x638E, 0xDEE1, 0x638F, 0xCCCD, 0x6390, 0xC6FE, 0x6391, 0x92E5, 0x6392, 0xC5C5, + 0x6393, 0x92E6, 0x6394, 0x92E7, 0x6395, 0x92E8, 0x6396, 0xD2B4, 0x6397, 0x92E9, 0x6398, 0xBEF2, 0x6399, 0x92EA, 0x639A, 0x92EB, + 0x639B, 0x92EC, 0x639C, 0x92ED, 0x639D, 0x92EE, 0x639E, 0x92EF, 0x639F, 0x92F0, 0x63A0, 0xC2D3, 0x63A1, 0x92F1, 0x63A2, 0xCCBD, + 0x63A3, 0xB3B8, 0x63A4, 0x92F2, 0x63A5, 0xBDD3, 0x63A6, 0x92F3, 0x63A7, 0xBFD8, 0x63A8, 0xCDC6, 0x63A9, 0xD1DA, 0x63AA, 0xB4EB, + 0x63AB, 0x92F4, 0x63AC, 0xDEE4, 0x63AD, 0xDEDD, 0x63AE, 0xDEE7, 0x63AF, 0x92F5, 0x63B0, 0xEAFE, 0x63B1, 0x92F6, 0x63B2, 0x92F7, + 0x63B3, 0xC2B0, 0x63B4, 0xDEE2, 0x63B5, 0x92F8, 0x63B6, 0x92F9, 0x63B7, 0xD6C0, 0x63B8, 0xB5A7, 0x63B9, 0x92FA, 0x63BA, 0xB2F4, + 0x63BB, 0x92FB, 0x63BC, 0xDEE8, 0x63BD, 0x92FC, 0x63BE, 0xDEF2, 0x63BF, 0x92FD, 0x63C0, 0x92FE, 0x63C1, 0x9340, 0x63C2, 0x9341, + 0x63C3, 0x9342, 0x63C4, 0xDEED, 0x63C5, 0x9343, 0x63C6, 0xDEF1, 0x63C7, 0x9344, 0x63C8, 0x9345, 0x63C9, 0xC8E0, 0x63CA, 0x9346, + 0x63CB, 0x9347, 0x63CC, 0x9348, 0x63CD, 0xD7E1, 0x63CE, 0xDEEF, 0x63CF, 0xC3E8, 0x63D0, 0xCCE1, 0x63D1, 0x9349, 0x63D2, 0xB2E5, + 0x63D3, 0x934A, 0x63D4, 0x934B, 0x63D5, 0x934C, 0x63D6, 0xD2BE, 0x63D7, 0x934D, 0x63D8, 0x934E, 0x63D9, 0x934F, 0x63DA, 0x9350, + 0x63DB, 0x9351, 0x63DC, 0x9352, 0x63DD, 0x9353, 0x63DE, 0xDEEE, 0x63DF, 0x9354, 0x63E0, 0xDEEB, 0x63E1, 0xCED5, 0x63E2, 0x9355, + 0x63E3, 0xB4A7, 0x63E4, 0x9356, 0x63E5, 0x9357, 0x63E6, 0x9358, 0x63E7, 0x9359, 0x63E8, 0x935A, 0x63E9, 0xBFAB, 0x63EA, 0xBEBE, + 0x63EB, 0x935B, 0x63EC, 0x935C, 0x63ED, 0xBDD2, 0x63EE, 0x935D, 0x63EF, 0x935E, 0x63F0, 0x935F, 0x63F1, 0x9360, 0x63F2, 0xDEE9, + 0x63F3, 0x9361, 0x63F4, 0xD4AE, 0x63F5, 0x9362, 0x63F6, 0xDEDE, 0x63F7, 0x9363, 0x63F8, 0xDEEA, 0x63F9, 0x9364, 0x63FA, 0x9365, + 0x63FB, 0x9366, 0x63FC, 0x9367, 0x63FD, 0xC0BF, 0x63FE, 0x9368, 0x63FF, 0xDEEC, 0x6400, 0xB2F3, 0x6401, 0xB8E9, 0x6402, 0xC2A7, + 0x6403, 0x9369, 0x6404, 0x936A, 0x6405, 0xBDC1, 0x6406, 0x936B, 0x6407, 0x936C, 0x6408, 0x936D, 0x6409, 0x936E, 0x640A, 0x936F, + 0x640B, 0xDEF5, 0x640C, 0xDEF8, 0x640D, 0x9370, 0x640E, 0x9371, 0x640F, 0xB2AB, 0x6410, 0xB4A4, 0x6411, 0x9372, 0x6412, 0x9373, + 0x6413, 0xB4EA, 0x6414, 0xC9A6, 0x6415, 0x9374, 0x6416, 0x9375, 0x6417, 0x9376, 0x6418, 0x9377, 0x6419, 0x9378, 0x641A, 0x9379, + 0x641B, 0xDEF6, 0x641C, 0xCBD1, 0x641D, 0x937A, 0x641E, 0xB8E3, 0x641F, 0x937B, 0x6420, 0xDEF7, 0x6421, 0xDEFA, 0x6422, 0x937C, + 0x6423, 0x937D, 0x6424, 0x937E, 0x6425, 0x9380, 0x6426, 0xDEF9, 0x6427, 0x9381, 0x6428, 0x9382, 0x6429, 0x9383, 0x642A, 0xCCC2, + 0x642B, 0x9384, 0x642C, 0xB0E1, 0x642D, 0xB4EE, 0x642E, 0x9385, 0x642F, 0x9386, 0x6430, 0x9387, 0x6431, 0x9388, 0x6432, 0x9389, + 0x6433, 0x938A, 0x6434, 0xE5BA, 0x6435, 0x938B, 0x6436, 0x938C, 0x6437, 0x938D, 0x6438, 0x938E, 0x6439, 0x938F, 0x643A, 0xD0AF, + 0x643B, 0x9390, 0x643C, 0x9391, 0x643D, 0xB2EB, 0x643E, 0x9392, 0x643F, 0xEBA1, 0x6440, 0x9393, 0x6441, 0xDEF4, 0x6442, 0x9394, + 0x6443, 0x9395, 0x6444, 0xC9E3, 0x6445, 0xDEF3, 0x6446, 0xB0DA, 0x6447, 0xD2A1, 0x6448, 0xB1F7, 0x6449, 0x9396, 0x644A, 0xCCAF, + 0x644B, 0x9397, 0x644C, 0x9398, 0x644D, 0x9399, 0x644E, 0x939A, 0x644F, 0x939B, 0x6450, 0x939C, 0x6451, 0x939D, 0x6452, 0xDEF0, + 0x6453, 0x939E, 0x6454, 0xCBA4, 0x6455, 0x939F, 0x6456, 0x93A0, 0x6457, 0x93A1, 0x6458, 0xD5AA, 0x6459, 0x93A2, 0x645A, 0x93A3, + 0x645B, 0x93A4, 0x645C, 0x93A5, 0x645D, 0x93A6, 0x645E, 0xDEFB, 0x645F, 0x93A7, 0x6460, 0x93A8, 0x6461, 0x93A9, 0x6462, 0x93AA, + 0x6463, 0x93AB, 0x6464, 0x93AC, 0x6465, 0x93AD, 0x6466, 0x93AE, 0x6467, 0xB4DD, 0x6468, 0x93AF, 0x6469, 0xC4A6, 0x646A, 0x93B0, + 0x646B, 0x93B1, 0x646C, 0x93B2, 0x646D, 0xDEFD, 0x646E, 0x93B3, 0x646F, 0x93B4, 0x6470, 0x93B5, 0x6471, 0x93B6, 0x6472, 0x93B7, + 0x6473, 0x93B8, 0x6474, 0x93B9, 0x6475, 0x93BA, 0x6476, 0x93BB, 0x6477, 0x93BC, 0x6478, 0xC3FE, 0x6479, 0xC4A1, 0x647A, 0xDFA1, + 0x647B, 0x93BD, 0x647C, 0x93BE, 0x647D, 0x93BF, 0x647E, 0x93C0, 0x647F, 0x93C1, 0x6480, 0x93C2, 0x6481, 0x93C3, 0x6482, 0xC1CC, + 0x6483, 0x93C4, 0x6484, 0xDEFC, 0x6485, 0xBEEF, 0x6486, 0x93C5, 0x6487, 0xC6B2, 0x6488, 0x93C6, 0x6489, 0x93C7, 0x648A, 0x93C8, + 0x648B, 0x93C9, 0x648C, 0x93CA, 0x648D, 0x93CB, 0x648E, 0x93CC, 0x648F, 0x93CD, 0x6490, 0x93CE, 0x6491, 0xB3C5, 0x6492, 0xC8F6, + 0x6493, 0x93CF, 0x6494, 0x93D0, 0x6495, 0xCBBA, 0x6496, 0xDEFE, 0x6497, 0x93D1, 0x6498, 0x93D2, 0x6499, 0xDFA4, 0x649A, 0x93D3, + 0x649B, 0x93D4, 0x649C, 0x93D5, 0x649D, 0x93D6, 0x649E, 0xD7B2, 0x649F, 0x93D7, 0x64A0, 0x93D8, 0x64A1, 0x93D9, 0x64A2, 0x93DA, + 0x64A3, 0x93DB, 0x64A4, 0xB3B7, 0x64A5, 0x93DC, 0x64A6, 0x93DD, 0x64A7, 0x93DE, 0x64A8, 0x93DF, 0x64A9, 0xC1C3, 0x64AA, 0x93E0, + 0x64AB, 0x93E1, 0x64AC, 0xC7CB, 0x64AD, 0xB2A5, 0x64AE, 0xB4E9, 0x64AF, 0x93E2, 0x64B0, 0xD7AB, 0x64B1, 0x93E3, 0x64B2, 0x93E4, + 0x64B3, 0x93E5, 0x64B4, 0x93E6, 0x64B5, 0xC4EC, 0x64B6, 0x93E7, 0x64B7, 0xDFA2, 0x64B8, 0xDFA3, 0x64B9, 0x93E8, 0x64BA, 0xDFA5, + 0x64BB, 0x93E9, 0x64BC, 0xBAB3, 0x64BD, 0x93EA, 0x64BE, 0x93EB, 0x64BF, 0x93EC, 0x64C0, 0xDFA6, 0x64C1, 0x93ED, 0x64C2, 0xC0DE, + 0x64C3, 0x93EE, 0x64C4, 0x93EF, 0x64C5, 0xC9C3, 0x64C6, 0x93F0, 0x64C7, 0x93F1, 0x64C8, 0x93F2, 0x64C9, 0x93F3, 0x64CA, 0x93F4, + 0x64CB, 0x93F5, 0x64CC, 0x93F6, 0x64CD, 0xB2D9, 0x64CE, 0xC7E6, 0x64CF, 0x93F7, 0x64D0, 0xDFA7, 0x64D1, 0x93F8, 0x64D2, 0xC7DC, + 0x64D3, 0x93F9, 0x64D4, 0x93FA, 0x64D5, 0x93FB, 0x64D6, 0x93FC, 0x64D7, 0xDFA8, 0x64D8, 0xEBA2, 0x64D9, 0x93FD, 0x64DA, 0x93FE, + 0x64DB, 0x9440, 0x64DC, 0x9441, 0x64DD, 0x9442, 0x64DE, 0xCBD3, 0x64DF, 0x9443, 0x64E0, 0x9444, 0x64E1, 0x9445, 0x64E2, 0xDFAA, + 0x64E3, 0x9446, 0x64E4, 0xDFA9, 0x64E5, 0x9447, 0x64E6, 0xB2C1, 0x64E7, 0x9448, 0x64E8, 0x9449, 0x64E9, 0x944A, 0x64EA, 0x944B, + 0x64EB, 0x944C, 0x64EC, 0x944D, 0x64ED, 0x944E, 0x64EE, 0x944F, 0x64EF, 0x9450, 0x64F0, 0x9451, 0x64F1, 0x9452, 0x64F2, 0x9453, + 0x64F3, 0x9454, 0x64F4, 0x9455, 0x64F5, 0x9456, 0x64F6, 0x9457, 0x64F7, 0x9458, 0x64F8, 0x9459, 0x64F9, 0x945A, 0x64FA, 0x945B, + 0x64FB, 0x945C, 0x64FC, 0x945D, 0x64FD, 0x945E, 0x64FE, 0x945F, 0x64FF, 0x9460, 0x6500, 0xC5CA, 0x6501, 0x9461, 0x6502, 0x9462, + 0x6503, 0x9463, 0x6504, 0x9464, 0x6505, 0x9465, 0x6506, 0x9466, 0x6507, 0x9467, 0x6508, 0x9468, 0x6509, 0xDFAB, 0x650A, 0x9469, + 0x650B, 0x946A, 0x650C, 0x946B, 0x650D, 0x946C, 0x650E, 0x946D, 0x650F, 0x946E, 0x6510, 0x946F, 0x6511, 0x9470, 0x6512, 0xD4DC, + 0x6513, 0x9471, 0x6514, 0x9472, 0x6515, 0x9473, 0x6516, 0x9474, 0x6517, 0x9475, 0x6518, 0xC8C1, 0x6519, 0x9476, 0x651A, 0x9477, + 0x651B, 0x9478, 0x651C, 0x9479, 0x651D, 0x947A, 0x651E, 0x947B, 0x651F, 0x947C, 0x6520, 0x947D, 0x6521, 0x947E, 0x6522, 0x9480, + 0x6523, 0x9481, 0x6524, 0x9482, 0x6525, 0xDFAC, 0x6526, 0x9483, 0x6527, 0x9484, 0x6528, 0x9485, 0x6529, 0x9486, 0x652A, 0x9487, + 0x652B, 0xBEF0, 0x652C, 0x9488, 0x652D, 0x9489, 0x652E, 0xDFAD, 0x652F, 0xD6A7, 0x6530, 0x948A, 0x6531, 0x948B, 0x6532, 0x948C, + 0x6533, 0x948D, 0x6534, 0xEAB7, 0x6535, 0xEBB6, 0x6536, 0xCAD5, 0x6537, 0x948E, 0x6538, 0xD8FC, 0x6539, 0xB8C4, 0x653A, 0x948F, + 0x653B, 0xB9A5, 0x653C, 0x9490, 0x653D, 0x9491, 0x653E, 0xB7C5, 0x653F, 0xD5FE, 0x6540, 0x9492, 0x6541, 0x9493, 0x6542, 0x9494, + 0x6543, 0x9495, 0x6544, 0x9496, 0x6545, 0xB9CA, 0x6546, 0x9497, 0x6547, 0x9498, 0x6548, 0xD0A7, 0x6549, 0xF4CD, 0x654A, 0x9499, + 0x654B, 0x949A, 0x654C, 0xB5D0, 0x654D, 0x949B, 0x654E, 0x949C, 0x654F, 0xC3F4, 0x6550, 0x949D, 0x6551, 0xBEC8, 0x6552, 0x949E, + 0x6553, 0x949F, 0x6554, 0x94A0, 0x6555, 0xEBB7, 0x6556, 0xB0BD, 0x6557, 0x94A1, 0x6558, 0x94A2, 0x6559, 0xBDCC, 0x655A, 0x94A3, + 0x655B, 0xC1B2, 0x655C, 0x94A4, 0x655D, 0xB1D6, 0x655E, 0xB3A8, 0x655F, 0x94A5, 0x6560, 0x94A6, 0x6561, 0x94A7, 0x6562, 0xB8D2, + 0x6563, 0xC9A2, 0x6564, 0x94A8, 0x6565, 0x94A9, 0x6566, 0xB6D8, 0x6567, 0x94AA, 0x6568, 0x94AB, 0x6569, 0x94AC, 0x656A, 0x94AD, + 0x656B, 0xEBB8, 0x656C, 0xBEB4, 0x656D, 0x94AE, 0x656E, 0x94AF, 0x656F, 0x94B0, 0x6570, 0xCAFD, 0x6571, 0x94B1, 0x6572, 0xC7C3, + 0x6573, 0x94B2, 0x6574, 0xD5FB, 0x6575, 0x94B3, 0x6576, 0x94B4, 0x6577, 0xB7F3, 0x6578, 0x94B5, 0x6579, 0x94B6, 0x657A, 0x94B7, + 0x657B, 0x94B8, 0x657C, 0x94B9, 0x657D, 0x94BA, 0x657E, 0x94BB, 0x657F, 0x94BC, 0x6580, 0x94BD, 0x6581, 0x94BE, 0x6582, 0x94BF, + 0x6583, 0x94C0, 0x6584, 0x94C1, 0x6585, 0x94C2, 0x6586, 0x94C3, 0x6587, 0xCEC4, 0x6588, 0x94C4, 0x6589, 0x94C5, 0x658A, 0x94C6, + 0x658B, 0xD5AB, 0x658C, 0xB1F3, 0x658D, 0x94C7, 0x658E, 0x94C8, 0x658F, 0x94C9, 0x6590, 0xECB3, 0x6591, 0xB0DF, 0x6592, 0x94CA, + 0x6593, 0xECB5, 0x6594, 0x94CB, 0x6595, 0x94CC, 0x6596, 0x94CD, 0x6597, 0xB6B7, 0x6598, 0x94CE, 0x6599, 0xC1CF, 0x659A, 0x94CF, + 0x659B, 0xF5FA, 0x659C, 0xD0B1, 0x659D, 0x94D0, 0x659E, 0x94D1, 0x659F, 0xD5E5, 0x65A0, 0x94D2, 0x65A1, 0xCED3, 0x65A2, 0x94D3, + 0x65A3, 0x94D4, 0x65A4, 0xBDEF, 0x65A5, 0xB3E2, 0x65A6, 0x94D5, 0x65A7, 0xB8AB, 0x65A8, 0x94D6, 0x65A9, 0xD5B6, 0x65AA, 0x94D7, + 0x65AB, 0xEDBD, 0x65AC, 0x94D8, 0x65AD, 0xB6CF, 0x65AE, 0x94D9, 0x65AF, 0xCBB9, 0x65B0, 0xD0C2, 0x65B1, 0x94DA, 0x65B2, 0x94DB, + 0x65B3, 0x94DC, 0x65B4, 0x94DD, 0x65B5, 0x94DE, 0x65B6, 0x94DF, 0x65B7, 0x94E0, 0x65B8, 0x94E1, 0x65B9, 0xB7BD, 0x65BA, 0x94E2, + 0x65BB, 0x94E3, 0x65BC, 0xECB6, 0x65BD, 0xCAA9, 0x65BE, 0x94E4, 0x65BF, 0x94E5, 0x65C0, 0x94E6, 0x65C1, 0xC5D4, 0x65C2, 0x94E7, + 0x65C3, 0xECB9, 0x65C4, 0xECB8, 0x65C5, 0xC2C3, 0x65C6, 0xECB7, 0x65C7, 0x94E8, 0x65C8, 0x94E9, 0x65C9, 0x94EA, 0x65CA, 0x94EB, + 0x65CB, 0xD0FD, 0x65CC, 0xECBA, 0x65CD, 0x94EC, 0x65CE, 0xECBB, 0x65CF, 0xD7E5, 0x65D0, 0x94ED, 0x65D1, 0x94EE, 0x65D2, 0xECBC, + 0x65D3, 0x94EF, 0x65D4, 0x94F0, 0x65D5, 0x94F1, 0x65D6, 0xECBD, 0x65D7, 0xC6EC, 0x65D8, 0x94F2, 0x65D9, 0x94F3, 0x65DA, 0x94F4, + 0x65DB, 0x94F5, 0x65DC, 0x94F6, 0x65DD, 0x94F7, 0x65DE, 0x94F8, 0x65DF, 0x94F9, 0x65E0, 0xCEDE, 0x65E1, 0x94FA, 0x65E2, 0xBCC8, + 0x65E3, 0x94FB, 0x65E4, 0x94FC, 0x65E5, 0xC8D5, 0x65E6, 0xB5A9, 0x65E7, 0xBEC9, 0x65E8, 0xD6BC, 0x65E9, 0xD4E7, 0x65EA, 0x94FD, + 0x65EB, 0x94FE, 0x65EC, 0xD1AE, 0x65ED, 0xD0F1, 0x65EE, 0xEAB8, 0x65EF, 0xEAB9, 0x65F0, 0xEABA, 0x65F1, 0xBAB5, 0x65F2, 0x9540, + 0x65F3, 0x9541, 0x65F4, 0x9542, 0x65F5, 0x9543, 0x65F6, 0xCAB1, 0x65F7, 0xBFF5, 0x65F8, 0x9544, 0x65F9, 0x9545, 0x65FA, 0xCDFA, + 0x65FB, 0x9546, 0x65FC, 0x9547, 0x65FD, 0x9548, 0x65FE, 0x9549, 0x65FF, 0x954A, 0x6600, 0xEAC0, 0x6601, 0x954B, 0x6602, 0xB0BA, + 0x6603, 0xEABE, 0x6604, 0x954C, 0x6605, 0x954D, 0x6606, 0xC0A5, 0x6607, 0x954E, 0x6608, 0x954F, 0x6609, 0x9550, 0x660A, 0xEABB, + 0x660B, 0x9551, 0x660C, 0xB2FD, 0x660D, 0x9552, 0x660E, 0xC3F7, 0x660F, 0xBBE8, 0x6610, 0x9553, 0x6611, 0x9554, 0x6612, 0x9555, + 0x6613, 0xD2D7, 0x6614, 0xCEF4, 0x6615, 0xEABF, 0x6616, 0x9556, 0x6617, 0x9557, 0x6618, 0x9558, 0x6619, 0xEABC, 0x661A, 0x9559, + 0x661B, 0x955A, 0x661C, 0x955B, 0x661D, 0xEAC3, 0x661E, 0x955C, 0x661F, 0xD0C7, 0x6620, 0xD3B3, 0x6621, 0x955D, 0x6622, 0x955E, + 0x6623, 0x955F, 0x6624, 0x9560, 0x6625, 0xB4BA, 0x6626, 0x9561, 0x6627, 0xC3C1, 0x6628, 0xD7F2, 0x6629, 0x9562, 0x662A, 0x9563, + 0x662B, 0x9564, 0x662C, 0x9565, 0x662D, 0xD5D1, 0x662E, 0x9566, 0x662F, 0xCAC7, 0x6630, 0x9567, 0x6631, 0xEAC5, 0x6632, 0x9568, + 0x6633, 0x9569, 0x6634, 0xEAC4, 0x6635, 0xEAC7, 0x6636, 0xEAC6, 0x6637, 0x956A, 0x6638, 0x956B, 0x6639, 0x956C, 0x663A, 0x956D, + 0x663B, 0x956E, 0x663C, 0xD6E7, 0x663D, 0x956F, 0x663E, 0xCFD4, 0x663F, 0x9570, 0x6640, 0x9571, 0x6641, 0xEACB, 0x6642, 0x9572, + 0x6643, 0xBBCE, 0x6644, 0x9573, 0x6645, 0x9574, 0x6646, 0x9575, 0x6647, 0x9576, 0x6648, 0x9577, 0x6649, 0x9578, 0x664A, 0x9579, + 0x664B, 0xBDFA, 0x664C, 0xC9CE, 0x664D, 0x957A, 0x664E, 0x957B, 0x664F, 0xEACC, 0x6650, 0x957C, 0x6651, 0x957D, 0x6652, 0xC9B9, + 0x6653, 0xCFFE, 0x6654, 0xEACA, 0x6655, 0xD4CE, 0x6656, 0xEACD, 0x6657, 0xEACF, 0x6658, 0x957E, 0x6659, 0x9580, 0x665A, 0xCDED, + 0x665B, 0x9581, 0x665C, 0x9582, 0x665D, 0x9583, 0x665E, 0x9584, 0x665F, 0xEAC9, 0x6660, 0x9585, 0x6661, 0xEACE, 0x6662, 0x9586, + 0x6663, 0x9587, 0x6664, 0xCEEE, 0x6665, 0x9588, 0x6666, 0xBBDE, 0x6667, 0x9589, 0x6668, 0xB3BF, 0x6669, 0x958A, 0x666A, 0x958B, + 0x666B, 0x958C, 0x666C, 0x958D, 0x666D, 0x958E, 0x666E, 0xC6D5, 0x666F, 0xBEB0, 0x6670, 0xCEFA, 0x6671, 0x958F, 0x6672, 0x9590, + 0x6673, 0x9591, 0x6674, 0xC7E7, 0x6675, 0x9592, 0x6676, 0xBEA7, 0x6677, 0xEAD0, 0x6678, 0x9593, 0x6679, 0x9594, 0x667A, 0xD6C7, + 0x667B, 0x9595, 0x667C, 0x9596, 0x667D, 0x9597, 0x667E, 0xC1C0, 0x667F, 0x9598, 0x6680, 0x9599, 0x6681, 0x959A, 0x6682, 0xD4DD, + 0x6683, 0x959B, 0x6684, 0xEAD1, 0x6685, 0x959C, 0x6686, 0x959D, 0x6687, 0xCFBE, 0x6688, 0x959E, 0x6689, 0x959F, 0x668A, 0x95A0, + 0x668B, 0x95A1, 0x668C, 0xEAD2, 0x668D, 0x95A2, 0x668E, 0x95A3, 0x668F, 0x95A4, 0x6690, 0x95A5, 0x6691, 0xCAEE, 0x6692, 0x95A6, + 0x6693, 0x95A7, 0x6694, 0x95A8, 0x6695, 0x95A9, 0x6696, 0xC5AF, 0x6697, 0xB0B5, 0x6698, 0x95AA, 0x6699, 0x95AB, 0x669A, 0x95AC, + 0x669B, 0x95AD, 0x669C, 0x95AE, 0x669D, 0xEAD4, 0x669E, 0x95AF, 0x669F, 0x95B0, 0x66A0, 0x95B1, 0x66A1, 0x95B2, 0x66A2, 0x95B3, + 0x66A3, 0x95B4, 0x66A4, 0x95B5, 0x66A5, 0x95B6, 0x66A6, 0x95B7, 0x66A7, 0xEAD3, 0x66A8, 0xF4DF, 0x66A9, 0x95B8, 0x66AA, 0x95B9, + 0x66AB, 0x95BA, 0x66AC, 0x95BB, 0x66AD, 0x95BC, 0x66AE, 0xC4BA, 0x66AF, 0x95BD, 0x66B0, 0x95BE, 0x66B1, 0x95BF, 0x66B2, 0x95C0, + 0x66B3, 0x95C1, 0x66B4, 0xB1A9, 0x66B5, 0x95C2, 0x66B6, 0x95C3, 0x66B7, 0x95C4, 0x66B8, 0x95C5, 0x66B9, 0xE5DF, 0x66BA, 0x95C6, + 0x66BB, 0x95C7, 0x66BC, 0x95C8, 0x66BD, 0x95C9, 0x66BE, 0xEAD5, 0x66BF, 0x95CA, 0x66C0, 0x95CB, 0x66C1, 0x95CC, 0x66C2, 0x95CD, + 0x66C3, 0x95CE, 0x66C4, 0x95CF, 0x66C5, 0x95D0, 0x66C6, 0x95D1, 0x66C7, 0x95D2, 0x66C8, 0x95D3, 0x66C9, 0x95D4, 0x66CA, 0x95D5, + 0x66CB, 0x95D6, 0x66CC, 0x95D7, 0x66CD, 0x95D8, 0x66CE, 0x95D9, 0x66CF, 0x95DA, 0x66D0, 0x95DB, 0x66D1, 0x95DC, 0x66D2, 0x95DD, + 0x66D3, 0x95DE, 0x66D4, 0x95DF, 0x66D5, 0x95E0, 0x66D6, 0x95E1, 0x66D7, 0x95E2, 0x66D8, 0x95E3, 0x66D9, 0xCAEF, 0x66DA, 0x95E4, + 0x66DB, 0xEAD6, 0x66DC, 0xEAD7, 0x66DD, 0xC6D8, 0x66DE, 0x95E5, 0x66DF, 0x95E6, 0x66E0, 0x95E7, 0x66E1, 0x95E8, 0x66E2, 0x95E9, + 0x66E3, 0x95EA, 0x66E4, 0x95EB, 0x66E5, 0x95EC, 0x66E6, 0xEAD8, 0x66E7, 0x95ED, 0x66E8, 0x95EE, 0x66E9, 0xEAD9, 0x66EA, 0x95EF, + 0x66EB, 0x95F0, 0x66EC, 0x95F1, 0x66ED, 0x95F2, 0x66EE, 0x95F3, 0x66EF, 0x95F4, 0x66F0, 0xD4BB, 0x66F1, 0x95F5, 0x66F2, 0xC7FA, + 0x66F3, 0xD2B7, 0x66F4, 0xB8FC, 0x66F5, 0x95F6, 0x66F6, 0x95F7, 0x66F7, 0xEAC2, 0x66F8, 0x95F8, 0x66F9, 0xB2DC, 0x66FA, 0x95F9, + 0x66FB, 0x95FA, 0x66FC, 0xC2FC, 0x66FD, 0x95FB, 0x66FE, 0xD4F8, 0x66FF, 0xCCE6, 0x6700, 0xD7EE, 0x6701, 0x95FC, 0x6702, 0x95FD, + 0x6703, 0x95FE, 0x6704, 0x9640, 0x6705, 0x9641, 0x6706, 0x9642, 0x6707, 0x9643, 0x6708, 0xD4C2, 0x6709, 0xD3D0, 0x670A, 0xEBC3, + 0x670B, 0xC5F3, 0x670C, 0x9644, 0x670D, 0xB7FE, 0x670E, 0x9645, 0x670F, 0x9646, 0x6710, 0xEBD4, 0x6711, 0x9647, 0x6712, 0x9648, + 0x6713, 0x9649, 0x6714, 0xCBB7, 0x6715, 0xEBDE, 0x6716, 0x964A, 0x6717, 0xC0CA, 0x6718, 0x964B, 0x6719, 0x964C, 0x671A, 0x964D, + 0x671B, 0xCDFB, 0x671C, 0x964E, 0x671D, 0xB3AF, 0x671E, 0x964F, 0x671F, 0xC6DA, 0x6720, 0x9650, 0x6721, 0x9651, 0x6722, 0x9652, + 0x6723, 0x9653, 0x6724, 0x9654, 0x6725, 0x9655, 0x6726, 0xEBFC, 0x6727, 0x9656, 0x6728, 0xC4BE, 0x6729, 0x9657, 0x672A, 0xCEB4, + 0x672B, 0xC4A9, 0x672C, 0xB1BE, 0x672D, 0xD4FD, 0x672E, 0x9658, 0x672F, 0xCAF5, 0x6730, 0x9659, 0x6731, 0xD6EC, 0x6732, 0x965A, + 0x6733, 0x965B, 0x6734, 0xC6D3, 0x6735, 0xB6E4, 0x6736, 0x965C, 0x6737, 0x965D, 0x6738, 0x965E, 0x6739, 0x965F, 0x673A, 0xBBFA, + 0x673B, 0x9660, 0x673C, 0x9661, 0x673D, 0xD0E0, 0x673E, 0x9662, 0x673F, 0x9663, 0x6740, 0xC9B1, 0x6741, 0x9664, 0x6742, 0xD4D3, + 0x6743, 0xC8A8, 0x6744, 0x9665, 0x6745, 0x9666, 0x6746, 0xB8CB, 0x6747, 0x9667, 0x6748, 0xE8BE, 0x6749, 0xC9BC, 0x674A, 0x9668, + 0x674B, 0x9669, 0x674C, 0xE8BB, 0x674D, 0x966A, 0x674E, 0xC0EE, 0x674F, 0xD0D3, 0x6750, 0xB2C4, 0x6751, 0xB4E5, 0x6752, 0x966B, + 0x6753, 0xE8BC, 0x6754, 0x966C, 0x6755, 0x966D, 0x6756, 0xD5C8, 0x6757, 0x966E, 0x6758, 0x966F, 0x6759, 0x9670, 0x675A, 0x9671, + 0x675B, 0x9672, 0x675C, 0xB6C5, 0x675D, 0x9673, 0x675E, 0xE8BD, 0x675F, 0xCAF8, 0x6760, 0xB8DC, 0x6761, 0xCCF5, 0x6762, 0x9674, + 0x6763, 0x9675, 0x6764, 0x9676, 0x6765, 0xC0B4, 0x6766, 0x9677, 0x6767, 0x9678, 0x6768, 0xD1EE, 0x6769, 0xE8BF, 0x676A, 0xE8C2, + 0x676B, 0x9679, 0x676C, 0x967A, 0x676D, 0xBABC, 0x676E, 0x967B, 0x676F, 0xB1AD, 0x6770, 0xBDDC, 0x6771, 0x967C, 0x6772, 0xEABD, + 0x6773, 0xE8C3, 0x6774, 0x967D, 0x6775, 0xE8C6, 0x6776, 0x967E, 0x6777, 0xE8CB, 0x6778, 0x9680, 0x6779, 0x9681, 0x677A, 0x9682, + 0x677B, 0x9683, 0x677C, 0xE8CC, 0x677D, 0x9684, 0x677E, 0xCBC9, 0x677F, 0xB0E5, 0x6780, 0x9685, 0x6781, 0xBCAB, 0x6782, 0x9686, + 0x6783, 0x9687, 0x6784, 0xB9B9, 0x6785, 0x9688, 0x6786, 0x9689, 0x6787, 0xE8C1, 0x6788, 0x968A, 0x6789, 0xCDF7, 0x678A, 0x968B, + 0x678B, 0xE8CA, 0x678C, 0x968C, 0x678D, 0x968D, 0x678E, 0x968E, 0x678F, 0x968F, 0x6790, 0xCEF6, 0x6791, 0x9690, 0x6792, 0x9691, + 0x6793, 0x9692, 0x6794, 0x9693, 0x6795, 0xD5ED, 0x6796, 0x9694, 0x6797, 0xC1D6, 0x6798, 0xE8C4, 0x6799, 0x9695, 0x679A, 0xC3B6, + 0x679B, 0x9696, 0x679C, 0xB9FB, 0x679D, 0xD6A6, 0x679E, 0xE8C8, 0x679F, 0x9697, 0x67A0, 0x9698, 0x67A1, 0x9699, 0x67A2, 0xCAE0, + 0x67A3, 0xD4E6, 0x67A4, 0x969A, 0x67A5, 0xE8C0, 0x67A6, 0x969B, 0x67A7, 0xE8C5, 0x67A8, 0xE8C7, 0x67A9, 0x969C, 0x67AA, 0xC7B9, + 0x67AB, 0xB7E3, 0x67AC, 0x969D, 0x67AD, 0xE8C9, 0x67AE, 0x969E, 0x67AF, 0xBFDD, 0x67B0, 0xE8D2, 0x67B1, 0x969F, 0x67B2, 0x96A0, + 0x67B3, 0xE8D7, 0x67B4, 0x96A1, 0x67B5, 0xE8D5, 0x67B6, 0xBCDC, 0x67B7, 0xBCCF, 0x67B8, 0xE8DB, 0x67B9, 0x96A2, 0x67BA, 0x96A3, + 0x67BB, 0x96A4, 0x67BC, 0x96A5, 0x67BD, 0x96A6, 0x67BE, 0x96A7, 0x67BF, 0x96A8, 0x67C0, 0x96A9, 0x67C1, 0xE8DE, 0x67C2, 0x96AA, + 0x67C3, 0xE8DA, 0x67C4, 0xB1FA, 0x67C5, 0x96AB, 0x67C6, 0x96AC, 0x67C7, 0x96AD, 0x67C8, 0x96AE, 0x67C9, 0x96AF, 0x67CA, 0x96B0, + 0x67CB, 0x96B1, 0x67CC, 0x96B2, 0x67CD, 0x96B3, 0x67CE, 0x96B4, 0x67CF, 0xB0D8, 0x67D0, 0xC4B3, 0x67D1, 0xB8CC, 0x67D2, 0xC6E2, + 0x67D3, 0xC8BE, 0x67D4, 0xC8E1, 0x67D5, 0x96B5, 0x67D6, 0x96B6, 0x67D7, 0x96B7, 0x67D8, 0xE8CF, 0x67D9, 0xE8D4, 0x67DA, 0xE8D6, + 0x67DB, 0x96B8, 0x67DC, 0xB9F1, 0x67DD, 0xE8D8, 0x67DE, 0xD7F5, 0x67DF, 0x96B9, 0x67E0, 0xC4FB, 0x67E1, 0x96BA, 0x67E2, 0xE8DC, + 0x67E3, 0x96BB, 0x67E4, 0x96BC, 0x67E5, 0xB2E9, 0x67E6, 0x96BD, 0x67E7, 0x96BE, 0x67E8, 0x96BF, 0x67E9, 0xE8D1, 0x67EA, 0x96C0, + 0x67EB, 0x96C1, 0x67EC, 0xBCED, 0x67ED, 0x96C2, 0x67EE, 0x96C3, 0x67EF, 0xBFC2, 0x67F0, 0xE8CD, 0x67F1, 0xD6F9, 0x67F2, 0x96C4, + 0x67F3, 0xC1F8, 0x67F4, 0xB2F1, 0x67F5, 0x96C5, 0x67F6, 0x96C6, 0x67F7, 0x96C7, 0x67F8, 0x96C8, 0x67F9, 0x96C9, 0x67FA, 0x96CA, + 0x67FB, 0x96CB, 0x67FC, 0x96CC, 0x67FD, 0xE8DF, 0x67FE, 0x96CD, 0x67FF, 0xCAC1, 0x6800, 0xE8D9, 0x6801, 0x96CE, 0x6802, 0x96CF, + 0x6803, 0x96D0, 0x6804, 0x96D1, 0x6805, 0xD5A4, 0x6806, 0x96D2, 0x6807, 0xB1EA, 0x6808, 0xD5BB, 0x6809, 0xE8CE, 0x680A, 0xE8D0, + 0x680B, 0xB6B0, 0x680C, 0xE8D3, 0x680D, 0x96D3, 0x680E, 0xE8DD, 0x680F, 0xC0B8, 0x6810, 0x96D4, 0x6811, 0xCAF7, 0x6812, 0x96D5, + 0x6813, 0xCBA8, 0x6814, 0x96D6, 0x6815, 0x96D7, 0x6816, 0xC6DC, 0x6817, 0xC0F5, 0x6818, 0x96D8, 0x6819, 0x96D9, 0x681A, 0x96DA, + 0x681B, 0x96DB, 0x681C, 0x96DC, 0x681D, 0xE8E9, 0x681E, 0x96DD, 0x681F, 0x96DE, 0x6820, 0x96DF, 0x6821, 0xD0A3, 0x6822, 0x96E0, + 0x6823, 0x96E1, 0x6824, 0x96E2, 0x6825, 0x96E3, 0x6826, 0x96E4, 0x6827, 0x96E5, 0x6828, 0x96E6, 0x6829, 0xE8F2, 0x682A, 0xD6EA, + 0x682B, 0x96E7, 0x682C, 0x96E8, 0x682D, 0x96E9, 0x682E, 0x96EA, 0x682F, 0x96EB, 0x6830, 0x96EC, 0x6831, 0x96ED, 0x6832, 0xE8E0, + 0x6833, 0xE8E1, 0x6834, 0x96EE, 0x6835, 0x96EF, 0x6836, 0x96F0, 0x6837, 0xD1F9, 0x6838, 0xBACB, 0x6839, 0xB8F9, 0x683A, 0x96F1, + 0x683B, 0x96F2, 0x683C, 0xB8F1, 0x683D, 0xD4D4, 0x683E, 0xE8EF, 0x683F, 0x96F3, 0x6840, 0xE8EE, 0x6841, 0xE8EC, 0x6842, 0xB9F0, + 0x6843, 0xCCD2, 0x6844, 0xE8E6, 0x6845, 0xCEA6, 0x6846, 0xBFF2, 0x6847, 0x96F4, 0x6848, 0xB0B8, 0x6849, 0xE8F1, 0x684A, 0xE8F0, + 0x684B, 0x96F5, 0x684C, 0xD7C0, 0x684D, 0x96F6, 0x684E, 0xE8E4, 0x684F, 0x96F7, 0x6850, 0xCDA9, 0x6851, 0xC9A3, 0x6852, 0x96F8, + 0x6853, 0xBBB8, 0x6854, 0xBDDB, 0x6855, 0xE8EA, 0x6856, 0x96F9, 0x6857, 0x96FA, 0x6858, 0x96FB, 0x6859, 0x96FC, 0x685A, 0x96FD, + 0x685B, 0x96FE, 0x685C, 0x9740, 0x685D, 0x9741, 0x685E, 0x9742, 0x685F, 0x9743, 0x6860, 0xE8E2, 0x6861, 0xE8E3, 0x6862, 0xE8E5, + 0x6863, 0xB5B5, 0x6864, 0xE8E7, 0x6865, 0xC7C5, 0x6866, 0xE8EB, 0x6867, 0xE8ED, 0x6868, 0xBDB0, 0x6869, 0xD7AE, 0x686A, 0x9744, + 0x686B, 0xE8F8, 0x686C, 0x9745, 0x686D, 0x9746, 0x686E, 0x9747, 0x686F, 0x9748, 0x6870, 0x9749, 0x6871, 0x974A, 0x6872, 0x974B, + 0x6873, 0x974C, 0x6874, 0xE8F5, 0x6875, 0x974D, 0x6876, 0xCDB0, 0x6877, 0xE8F6, 0x6878, 0x974E, 0x6879, 0x974F, 0x687A, 0x9750, + 0x687B, 0x9751, 0x687C, 0x9752, 0x687D, 0x9753, 0x687E, 0x9754, 0x687F, 0x9755, 0x6880, 0x9756, 0x6881, 0xC1BA, 0x6882, 0x9757, + 0x6883, 0xE8E8, 0x6884, 0x9758, 0x6885, 0xC3B7, 0x6886, 0xB0F0, 0x6887, 0x9759, 0x6888, 0x975A, 0x6889, 0x975B, 0x688A, 0x975C, + 0x688B, 0x975D, 0x688C, 0x975E, 0x688D, 0x975F, 0x688E, 0x9760, 0x688F, 0xE8F4, 0x6890, 0x9761, 0x6891, 0x9762, 0x6892, 0x9763, + 0x6893, 0xE8F7, 0x6894, 0x9764, 0x6895, 0x9765, 0x6896, 0x9766, 0x6897, 0xB9A3, 0x6898, 0x9767, 0x6899, 0x9768, 0x689A, 0x9769, + 0x689B, 0x976A, 0x689C, 0x976B, 0x689D, 0x976C, 0x689E, 0x976D, 0x689F, 0x976E, 0x68A0, 0x976F, 0x68A1, 0x9770, 0x68A2, 0xC9D2, + 0x68A3, 0x9771, 0x68A4, 0x9772, 0x68A5, 0x9773, 0x68A6, 0xC3CE, 0x68A7, 0xCEE0, 0x68A8, 0xC0E6, 0x68A9, 0x9774, 0x68AA, 0x9775, + 0x68AB, 0x9776, 0x68AC, 0x9777, 0x68AD, 0xCBF3, 0x68AE, 0x9778, 0x68AF, 0xCCDD, 0x68B0, 0xD0B5, 0x68B1, 0x9779, 0x68B2, 0x977A, + 0x68B3, 0xCAE1, 0x68B4, 0x977B, 0x68B5, 0xE8F3, 0x68B6, 0x977C, 0x68B7, 0x977D, 0x68B8, 0x977E, 0x68B9, 0x9780, 0x68BA, 0x9781, + 0x68BB, 0x9782, 0x68BC, 0x9783, 0x68BD, 0x9784, 0x68BE, 0x9785, 0x68BF, 0x9786, 0x68C0, 0xBCEC, 0x68C1, 0x9787, 0x68C2, 0xE8F9, + 0x68C3, 0x9788, 0x68C4, 0x9789, 0x68C5, 0x978A, 0x68C6, 0x978B, 0x68C7, 0x978C, 0x68C8, 0x978D, 0x68C9, 0xC3DE, 0x68CA, 0x978E, + 0x68CB, 0xC6E5, 0x68CC, 0x978F, 0x68CD, 0xB9F7, 0x68CE, 0x9790, 0x68CF, 0x9791, 0x68D0, 0x9792, 0x68D1, 0x9793, 0x68D2, 0xB0F4, + 0x68D3, 0x9794, 0x68D4, 0x9795, 0x68D5, 0xD7D8, 0x68D6, 0x9796, 0x68D7, 0x9797, 0x68D8, 0xBCAC, 0x68D9, 0x9798, 0x68DA, 0xC5EF, + 0x68DB, 0x9799, 0x68DC, 0x979A, 0x68DD, 0x979B, 0x68DE, 0x979C, 0x68DF, 0x979D, 0x68E0, 0xCCC4, 0x68E1, 0x979E, 0x68E2, 0x979F, + 0x68E3, 0xE9A6, 0x68E4, 0x97A0, 0x68E5, 0x97A1, 0x68E6, 0x97A2, 0x68E7, 0x97A3, 0x68E8, 0x97A4, 0x68E9, 0x97A5, 0x68EA, 0x97A6, + 0x68EB, 0x97A7, 0x68EC, 0x97A8, 0x68ED, 0x97A9, 0x68EE, 0xC9AD, 0x68EF, 0x97AA, 0x68F0, 0xE9A2, 0x68F1, 0xC0E2, 0x68F2, 0x97AB, + 0x68F3, 0x97AC, 0x68F4, 0x97AD, 0x68F5, 0xBFC3, 0x68F6, 0x97AE, 0x68F7, 0x97AF, 0x68F8, 0x97B0, 0x68F9, 0xE8FE, 0x68FA, 0xB9D7, + 0x68FB, 0x97B1, 0x68FC, 0xE8FB, 0x68FD, 0x97B2, 0x68FE, 0x97B3, 0x68FF, 0x97B4, 0x6900, 0x97B5, 0x6901, 0xE9A4, 0x6902, 0x97B6, + 0x6903, 0x97B7, 0x6904, 0x97B8, 0x6905, 0xD2CE, 0x6906, 0x97B9, 0x6907, 0x97BA, 0x6908, 0x97BB, 0x6909, 0x97BC, 0x690A, 0x97BD, + 0x690B, 0xE9A3, 0x690C, 0x97BE, 0x690D, 0xD6B2, 0x690E, 0xD7B5, 0x690F, 0x97BF, 0x6910, 0xE9A7, 0x6911, 0x97C0, 0x6912, 0xBDB7, + 0x6913, 0x97C1, 0x6914, 0x97C2, 0x6915, 0x97C3, 0x6916, 0x97C4, 0x6917, 0x97C5, 0x6918, 0x97C6, 0x6919, 0x97C7, 0x691A, 0x97C8, + 0x691B, 0x97C9, 0x691C, 0x97CA, 0x691D, 0x97CB, 0x691E, 0x97CC, 0x691F, 0xE8FC, 0x6920, 0xE8FD, 0x6921, 0x97CD, 0x6922, 0x97CE, + 0x6923, 0x97CF, 0x6924, 0xE9A1, 0x6925, 0x97D0, 0x6926, 0x97D1, 0x6927, 0x97D2, 0x6928, 0x97D3, 0x6929, 0x97D4, 0x692A, 0x97D5, + 0x692B, 0x97D6, 0x692C, 0x97D7, 0x692D, 0xCDD6, 0x692E, 0x97D8, 0x692F, 0x97D9, 0x6930, 0xD2AC, 0x6931, 0x97DA, 0x6932, 0x97DB, + 0x6933, 0x97DC, 0x6934, 0xE9B2, 0x6935, 0x97DD, 0x6936, 0x97DE, 0x6937, 0x97DF, 0x6938, 0x97E0, 0x6939, 0xE9A9, 0x693A, 0x97E1, + 0x693B, 0x97E2, 0x693C, 0x97E3, 0x693D, 0xB4AA, 0x693E, 0x97E4, 0x693F, 0xB4BB, 0x6940, 0x97E5, 0x6941, 0x97E6, 0x6942, 0xE9AB, + 0x6943, 0x97E7, 0x6944, 0x97E8, 0x6945, 0x97E9, 0x6946, 0x97EA, 0x6947, 0x97EB, 0x6948, 0x97EC, 0x6949, 0x97ED, 0x694A, 0x97EE, + 0x694B, 0x97EF, 0x694C, 0x97F0, 0x694D, 0x97F1, 0x694E, 0x97F2, 0x694F, 0x97F3, 0x6950, 0x97F4, 0x6951, 0x97F5, 0x6952, 0x97F6, + 0x6953, 0x97F7, 0x6954, 0xD0A8, 0x6955, 0x97F8, 0x6956, 0x97F9, 0x6957, 0xE9A5, 0x6958, 0x97FA, 0x6959, 0x97FB, 0x695A, 0xB3FE, + 0x695B, 0x97FC, 0x695C, 0x97FD, 0x695D, 0xE9AC, 0x695E, 0xC0E3, 0x695F, 0x97FE, 0x6960, 0xE9AA, 0x6961, 0x9840, 0x6962, 0x9841, + 0x6963, 0xE9B9, 0x6964, 0x9842, 0x6965, 0x9843, 0x6966, 0xE9B8, 0x6967, 0x9844, 0x6968, 0x9845, 0x6969, 0x9846, 0x696A, 0x9847, + 0x696B, 0xE9AE, 0x696C, 0x9848, 0x696D, 0x9849, 0x696E, 0xE8FA, 0x696F, 0x984A, 0x6970, 0x984B, 0x6971, 0xE9A8, 0x6972, 0x984C, + 0x6973, 0x984D, 0x6974, 0x984E, 0x6975, 0x984F, 0x6976, 0x9850, 0x6977, 0xBFAC, 0x6978, 0xE9B1, 0x6979, 0xE9BA, 0x697A, 0x9851, + 0x697B, 0x9852, 0x697C, 0xC2A5, 0x697D, 0x9853, 0x697E, 0x9854, 0x697F, 0x9855, 0x6980, 0xE9AF, 0x6981, 0x9856, 0x6982, 0xB8C5, + 0x6983, 0x9857, 0x6984, 0xE9AD, 0x6985, 0x9858, 0x6986, 0xD3DC, 0x6987, 0xE9B4, 0x6988, 0xE9B5, 0x6989, 0xE9B7, 0x698A, 0x9859, + 0x698B, 0x985A, 0x698C, 0x985B, 0x698D, 0xE9C7, 0x698E, 0x985C, 0x698F, 0x985D, 0x6990, 0x985E, 0x6991, 0x985F, 0x6992, 0x9860, + 0x6993, 0x9861, 0x6994, 0xC0C6, 0x6995, 0xE9C5, 0x6996, 0x9862, 0x6997, 0x9863, 0x6998, 0xE9B0, 0x6999, 0x9864, 0x699A, 0x9865, + 0x699B, 0xE9BB, 0x699C, 0xB0F1, 0x699D, 0x9866, 0x699E, 0x9867, 0x699F, 0x9868, 0x69A0, 0x9869, 0x69A1, 0x986A, 0x69A2, 0x986B, + 0x69A3, 0x986C, 0x69A4, 0x986D, 0x69A5, 0x986E, 0x69A6, 0x986F, 0x69A7, 0xE9BC, 0x69A8, 0xD5A5, 0x69A9, 0x9870, 0x69AA, 0x9871, + 0x69AB, 0xE9BE, 0x69AC, 0x9872, 0x69AD, 0xE9BF, 0x69AE, 0x9873, 0x69AF, 0x9874, 0x69B0, 0x9875, 0x69B1, 0xE9C1, 0x69B2, 0x9876, + 0x69B3, 0x9877, 0x69B4, 0xC1F1, 0x69B5, 0x9878, 0x69B6, 0x9879, 0x69B7, 0xC8B6, 0x69B8, 0x987A, 0x69B9, 0x987B, 0x69BA, 0x987C, + 0x69BB, 0xE9BD, 0x69BC, 0x987D, 0x69BD, 0x987E, 0x69BE, 0x9880, 0x69BF, 0x9881, 0x69C0, 0x9882, 0x69C1, 0xE9C2, 0x69C2, 0x9883, + 0x69C3, 0x9884, 0x69C4, 0x9885, 0x69C5, 0x9886, 0x69C6, 0x9887, 0x69C7, 0x9888, 0x69C8, 0x9889, 0x69C9, 0x988A, 0x69CA, 0xE9C3, + 0x69CB, 0x988B, 0x69CC, 0xE9B3, 0x69CD, 0x988C, 0x69CE, 0xE9B6, 0x69CF, 0x988D, 0x69D0, 0xBBB1, 0x69D1, 0x988E, 0x69D2, 0x988F, + 0x69D3, 0x9890, 0x69D4, 0xE9C0, 0x69D5, 0x9891, 0x69D6, 0x9892, 0x69D7, 0x9893, 0x69D8, 0x9894, 0x69D9, 0x9895, 0x69DA, 0x9896, + 0x69DB, 0xBCF7, 0x69DC, 0x9897, 0x69DD, 0x9898, 0x69DE, 0x9899, 0x69DF, 0xE9C4, 0x69E0, 0xE9C6, 0x69E1, 0x989A, 0x69E2, 0x989B, + 0x69E3, 0x989C, 0x69E4, 0x989D, 0x69E5, 0x989E, 0x69E6, 0x989F, 0x69E7, 0x98A0, 0x69E8, 0x98A1, 0x69E9, 0x98A2, 0x69EA, 0x98A3, + 0x69EB, 0x98A4, 0x69EC, 0x98A5, 0x69ED, 0xE9CA, 0x69EE, 0x98A6, 0x69EF, 0x98A7, 0x69F0, 0x98A8, 0x69F1, 0x98A9, 0x69F2, 0xE9CE, + 0x69F3, 0x98AA, 0x69F4, 0x98AB, 0x69F5, 0x98AC, 0x69F6, 0x98AD, 0x69F7, 0x98AE, 0x69F8, 0x98AF, 0x69F9, 0x98B0, 0x69FA, 0x98B1, + 0x69FB, 0x98B2, 0x69FC, 0x98B3, 0x69FD, 0xB2DB, 0x69FE, 0x98B4, 0x69FF, 0xE9C8, 0x6A00, 0x98B5, 0x6A01, 0x98B6, 0x6A02, 0x98B7, + 0x6A03, 0x98B8, 0x6A04, 0x98B9, 0x6A05, 0x98BA, 0x6A06, 0x98BB, 0x6A07, 0x98BC, 0x6A08, 0x98BD, 0x6A09, 0x98BE, 0x6A0A, 0xB7AE, + 0x6A0B, 0x98BF, 0x6A0C, 0x98C0, 0x6A0D, 0x98C1, 0x6A0E, 0x98C2, 0x6A0F, 0x98C3, 0x6A10, 0x98C4, 0x6A11, 0x98C5, 0x6A12, 0x98C6, + 0x6A13, 0x98C7, 0x6A14, 0x98C8, 0x6A15, 0x98C9, 0x6A16, 0x98CA, 0x6A17, 0xE9CB, 0x6A18, 0xE9CC, 0x6A19, 0x98CB, 0x6A1A, 0x98CC, + 0x6A1B, 0x98CD, 0x6A1C, 0x98CE, 0x6A1D, 0x98CF, 0x6A1E, 0x98D0, 0x6A1F, 0xD5C1, 0x6A20, 0x98D1, 0x6A21, 0xC4A3, 0x6A22, 0x98D2, + 0x6A23, 0x98D3, 0x6A24, 0x98D4, 0x6A25, 0x98D5, 0x6A26, 0x98D6, 0x6A27, 0x98D7, 0x6A28, 0xE9D8, 0x6A29, 0x98D8, 0x6A2A, 0xBAE1, + 0x6A2B, 0x98D9, 0x6A2C, 0x98DA, 0x6A2D, 0x98DB, 0x6A2E, 0x98DC, 0x6A2F, 0xE9C9, 0x6A30, 0x98DD, 0x6A31, 0xD3A3, 0x6A32, 0x98DE, + 0x6A33, 0x98DF, 0x6A34, 0x98E0, 0x6A35, 0xE9D4, 0x6A36, 0x98E1, 0x6A37, 0x98E2, 0x6A38, 0x98E3, 0x6A39, 0x98E4, 0x6A3A, 0x98E5, + 0x6A3B, 0x98E6, 0x6A3C, 0x98E7, 0x6A3D, 0xE9D7, 0x6A3E, 0xE9D0, 0x6A3F, 0x98E8, 0x6A40, 0x98E9, 0x6A41, 0x98EA, 0x6A42, 0x98EB, + 0x6A43, 0x98EC, 0x6A44, 0xE9CF, 0x6A45, 0x98ED, 0x6A46, 0x98EE, 0x6A47, 0xC7C1, 0x6A48, 0x98EF, 0x6A49, 0x98F0, 0x6A4A, 0x98F1, + 0x6A4B, 0x98F2, 0x6A4C, 0x98F3, 0x6A4D, 0x98F4, 0x6A4E, 0x98F5, 0x6A4F, 0x98F6, 0x6A50, 0xE9D2, 0x6A51, 0x98F7, 0x6A52, 0x98F8, + 0x6A53, 0x98F9, 0x6A54, 0x98FA, 0x6A55, 0x98FB, 0x6A56, 0x98FC, 0x6A57, 0x98FD, 0x6A58, 0xE9D9, 0x6A59, 0xB3C8, 0x6A5A, 0x98FE, + 0x6A5B, 0xE9D3, 0x6A5C, 0x9940, 0x6A5D, 0x9941, 0x6A5E, 0x9942, 0x6A5F, 0x9943, 0x6A60, 0x9944, 0x6A61, 0xCFF0, 0x6A62, 0x9945, + 0x6A63, 0x9946, 0x6A64, 0x9947, 0x6A65, 0xE9CD, 0x6A66, 0x9948, 0x6A67, 0x9949, 0x6A68, 0x994A, 0x6A69, 0x994B, 0x6A6A, 0x994C, + 0x6A6B, 0x994D, 0x6A6C, 0x994E, 0x6A6D, 0x994F, 0x6A6E, 0x9950, 0x6A6F, 0x9951, 0x6A70, 0x9952, 0x6A71, 0xB3F7, 0x6A72, 0x9953, + 0x6A73, 0x9954, 0x6A74, 0x9955, 0x6A75, 0x9956, 0x6A76, 0x9957, 0x6A77, 0x9958, 0x6A78, 0x9959, 0x6A79, 0xE9D6, 0x6A7A, 0x995A, + 0x6A7B, 0x995B, 0x6A7C, 0xE9DA, 0x6A7D, 0x995C, 0x6A7E, 0x995D, 0x6A7F, 0x995E, 0x6A80, 0xCCB4, 0x6A81, 0x995F, 0x6A82, 0x9960, + 0x6A83, 0x9961, 0x6A84, 0xCFAD, 0x6A85, 0x9962, 0x6A86, 0x9963, 0x6A87, 0x9964, 0x6A88, 0x9965, 0x6A89, 0x9966, 0x6A8A, 0x9967, + 0x6A8B, 0x9968, 0x6A8C, 0x9969, 0x6A8D, 0x996A, 0x6A8E, 0xE9D5, 0x6A8F, 0x996B, 0x6A90, 0xE9DC, 0x6A91, 0xE9DB, 0x6A92, 0x996C, + 0x6A93, 0x996D, 0x6A94, 0x996E, 0x6A95, 0x996F, 0x6A96, 0x9970, 0x6A97, 0xE9DE, 0x6A98, 0x9971, 0x6A99, 0x9972, 0x6A9A, 0x9973, + 0x6A9B, 0x9974, 0x6A9C, 0x9975, 0x6A9D, 0x9976, 0x6A9E, 0x9977, 0x6A9F, 0x9978, 0x6AA0, 0xE9D1, 0x6AA1, 0x9979, 0x6AA2, 0x997A, + 0x6AA3, 0x997B, 0x6AA4, 0x997C, 0x6AA5, 0x997D, 0x6AA6, 0x997E, 0x6AA7, 0x9980, 0x6AA8, 0x9981, 0x6AA9, 0xE9DD, 0x6AAA, 0x9982, + 0x6AAB, 0xE9DF, 0x6AAC, 0xC3CA, 0x6AAD, 0x9983, 0x6AAE, 0x9984, 0x6AAF, 0x9985, 0x6AB0, 0x9986, 0x6AB1, 0x9987, 0x6AB2, 0x9988, + 0x6AB3, 0x9989, 0x6AB4, 0x998A, 0x6AB5, 0x998B, 0x6AB6, 0x998C, 0x6AB7, 0x998D, 0x6AB8, 0x998E, 0x6AB9, 0x998F, 0x6ABA, 0x9990, + 0x6ABB, 0x9991, 0x6ABC, 0x9992, 0x6ABD, 0x9993, 0x6ABE, 0x9994, 0x6ABF, 0x9995, 0x6AC0, 0x9996, 0x6AC1, 0x9997, 0x6AC2, 0x9998, + 0x6AC3, 0x9999, 0x6AC4, 0x999A, 0x6AC5, 0x999B, 0x6AC6, 0x999C, 0x6AC7, 0x999D, 0x6AC8, 0x999E, 0x6AC9, 0x999F, 0x6ACA, 0x99A0, + 0x6ACB, 0x99A1, 0x6ACC, 0x99A2, 0x6ACD, 0x99A3, 0x6ACE, 0x99A4, 0x6ACF, 0x99A5, 0x6AD0, 0x99A6, 0x6AD1, 0x99A7, 0x6AD2, 0x99A8, + 0x6AD3, 0x99A9, 0x6AD4, 0x99AA, 0x6AD5, 0x99AB, 0x6AD6, 0x99AC, 0x6AD7, 0x99AD, 0x6AD8, 0x99AE, 0x6AD9, 0x99AF, 0x6ADA, 0x99B0, + 0x6ADB, 0x99B1, 0x6ADC, 0x99B2, 0x6ADD, 0x99B3, 0x6ADE, 0x99B4, 0x6ADF, 0x99B5, 0x6AE0, 0x99B6, 0x6AE1, 0x99B7, 0x6AE2, 0x99B8, + 0x6AE3, 0x99B9, 0x6AE4, 0x99BA, 0x6AE5, 0x99BB, 0x6AE6, 0x99BC, 0x6AE7, 0x99BD, 0x6AE8, 0x99BE, 0x6AE9, 0x99BF, 0x6AEA, 0x99C0, + 0x6AEB, 0x99C1, 0x6AEC, 0x99C2, 0x6AED, 0x99C3, 0x6AEE, 0x99C4, 0x6AEF, 0x99C5, 0x6AF0, 0x99C6, 0x6AF1, 0x99C7, 0x6AF2, 0x99C8, + 0x6AF3, 0x99C9, 0x6AF4, 0x99CA, 0x6AF5, 0x99CB, 0x6AF6, 0x99CC, 0x6AF7, 0x99CD, 0x6AF8, 0x99CE, 0x6AF9, 0x99CF, 0x6AFA, 0x99D0, + 0x6AFB, 0x99D1, 0x6AFC, 0x99D2, 0x6AFD, 0x99D3, 0x6AFE, 0x99D4, 0x6AFF, 0x99D5, 0x6B00, 0x99D6, 0x6B01, 0x99D7, 0x6B02, 0x99D8, + 0x6B03, 0x99D9, 0x6B04, 0x99DA, 0x6B05, 0x99DB, 0x6B06, 0x99DC, 0x6B07, 0x99DD, 0x6B08, 0x99DE, 0x6B09, 0x99DF, 0x6B0A, 0x99E0, + 0x6B0B, 0x99E1, 0x6B0C, 0x99E2, 0x6B0D, 0x99E3, 0x6B0E, 0x99E4, 0x6B0F, 0x99E5, 0x6B10, 0x99E6, 0x6B11, 0x99E7, 0x6B12, 0x99E8, + 0x6B13, 0x99E9, 0x6B14, 0x99EA, 0x6B15, 0x99EB, 0x6B16, 0x99EC, 0x6B17, 0x99ED, 0x6B18, 0x99EE, 0x6B19, 0x99EF, 0x6B1A, 0x99F0, + 0x6B1B, 0x99F1, 0x6B1C, 0x99F2, 0x6B1D, 0x99F3, 0x6B1E, 0x99F4, 0x6B1F, 0x99F5, 0x6B20, 0xC7B7, 0x6B21, 0xB4CE, 0x6B22, 0xBBB6, + 0x6B23, 0xD0C0, 0x6B24, 0xECA3, 0x6B25, 0x99F6, 0x6B26, 0x99F7, 0x6B27, 0xC5B7, 0x6B28, 0x99F8, 0x6B29, 0x99F9, 0x6B2A, 0x99FA, + 0x6B2B, 0x99FB, 0x6B2C, 0x99FC, 0x6B2D, 0x99FD, 0x6B2E, 0x99FE, 0x6B2F, 0x9A40, 0x6B30, 0x9A41, 0x6B31, 0x9A42, 0x6B32, 0xD3FB, + 0x6B33, 0x9A43, 0x6B34, 0x9A44, 0x6B35, 0x9A45, 0x6B36, 0x9A46, 0x6B37, 0xECA4, 0x6B38, 0x9A47, 0x6B39, 0xECA5, 0x6B3A, 0xC6DB, + 0x6B3B, 0x9A48, 0x6B3C, 0x9A49, 0x6B3D, 0x9A4A, 0x6B3E, 0xBFEE, 0x6B3F, 0x9A4B, 0x6B40, 0x9A4C, 0x6B41, 0x9A4D, 0x6B42, 0x9A4E, + 0x6B43, 0xECA6, 0x6B44, 0x9A4F, 0x6B45, 0x9A50, 0x6B46, 0xECA7, 0x6B47, 0xD0AA, 0x6B48, 0x9A51, 0x6B49, 0xC7B8, 0x6B4A, 0x9A52, + 0x6B4B, 0x9A53, 0x6B4C, 0xB8E8, 0x6B4D, 0x9A54, 0x6B4E, 0x9A55, 0x6B4F, 0x9A56, 0x6B50, 0x9A57, 0x6B51, 0x9A58, 0x6B52, 0x9A59, + 0x6B53, 0x9A5A, 0x6B54, 0x9A5B, 0x6B55, 0x9A5C, 0x6B56, 0x9A5D, 0x6B57, 0x9A5E, 0x6B58, 0x9A5F, 0x6B59, 0xECA8, 0x6B5A, 0x9A60, + 0x6B5B, 0x9A61, 0x6B5C, 0x9A62, 0x6B5D, 0x9A63, 0x6B5E, 0x9A64, 0x6B5F, 0x9A65, 0x6B60, 0x9A66, 0x6B61, 0x9A67, 0x6B62, 0xD6B9, + 0x6B63, 0xD5FD, 0x6B64, 0xB4CB, 0x6B65, 0xB2BD, 0x6B66, 0xCEE4, 0x6B67, 0xC6E7, 0x6B68, 0x9A68, 0x6B69, 0x9A69, 0x6B6A, 0xCDE1, + 0x6B6B, 0x9A6A, 0x6B6C, 0x9A6B, 0x6B6D, 0x9A6C, 0x6B6E, 0x9A6D, 0x6B6F, 0x9A6E, 0x6B70, 0x9A6F, 0x6B71, 0x9A70, 0x6B72, 0x9A71, + 0x6B73, 0x9A72, 0x6B74, 0x9A73, 0x6B75, 0x9A74, 0x6B76, 0x9A75, 0x6B77, 0x9A76, 0x6B78, 0x9A77, 0x6B79, 0xB4F5, 0x6B7A, 0x9A78, + 0x6B7B, 0xCBC0, 0x6B7C, 0xBCDF, 0x6B7D, 0x9A79, 0x6B7E, 0x9A7A, 0x6B7F, 0x9A7B, 0x6B80, 0x9A7C, 0x6B81, 0xE9E2, 0x6B82, 0xE9E3, + 0x6B83, 0xD1EA, 0x6B84, 0xE9E5, 0x6B85, 0x9A7D, 0x6B86, 0xB4F9, 0x6B87, 0xE9E4, 0x6B88, 0x9A7E, 0x6B89, 0xD1B3, 0x6B8A, 0xCAE2, + 0x6B8B, 0xB2D0, 0x6B8C, 0x9A80, 0x6B8D, 0xE9E8, 0x6B8E, 0x9A81, 0x6B8F, 0x9A82, 0x6B90, 0x9A83, 0x6B91, 0x9A84, 0x6B92, 0xE9E6, + 0x6B93, 0xE9E7, 0x6B94, 0x9A85, 0x6B95, 0x9A86, 0x6B96, 0xD6B3, 0x6B97, 0x9A87, 0x6B98, 0x9A88, 0x6B99, 0x9A89, 0x6B9A, 0xE9E9, + 0x6B9B, 0xE9EA, 0x6B9C, 0x9A8A, 0x6B9D, 0x9A8B, 0x6B9E, 0x9A8C, 0x6B9F, 0x9A8D, 0x6BA0, 0x9A8E, 0x6BA1, 0xE9EB, 0x6BA2, 0x9A8F, + 0x6BA3, 0x9A90, 0x6BA4, 0x9A91, 0x6BA5, 0x9A92, 0x6BA6, 0x9A93, 0x6BA7, 0x9A94, 0x6BA8, 0x9A95, 0x6BA9, 0x9A96, 0x6BAA, 0xE9EC, + 0x6BAB, 0x9A97, 0x6BAC, 0x9A98, 0x6BAD, 0x9A99, 0x6BAE, 0x9A9A, 0x6BAF, 0x9A9B, 0x6BB0, 0x9A9C, 0x6BB1, 0x9A9D, 0x6BB2, 0x9A9E, + 0x6BB3, 0xECAF, 0x6BB4, 0xC5B9, 0x6BB5, 0xB6CE, 0x6BB6, 0x9A9F, 0x6BB7, 0xD2F3, 0x6BB8, 0x9AA0, 0x6BB9, 0x9AA1, 0x6BBA, 0x9AA2, + 0x6BBB, 0x9AA3, 0x6BBC, 0x9AA4, 0x6BBD, 0x9AA5, 0x6BBE, 0x9AA6, 0x6BBF, 0xB5EE, 0x6BC0, 0x9AA7, 0x6BC1, 0xBBD9, 0x6BC2, 0xECB1, + 0x6BC3, 0x9AA8, 0x6BC4, 0x9AA9, 0x6BC5, 0xD2E3, 0x6BC6, 0x9AAA, 0x6BC7, 0x9AAB, 0x6BC8, 0x9AAC, 0x6BC9, 0x9AAD, 0x6BCA, 0x9AAE, + 0x6BCB, 0xCEE3, 0x6BCC, 0x9AAF, 0x6BCD, 0xC4B8, 0x6BCE, 0x9AB0, 0x6BCF, 0xC3BF, 0x6BD0, 0x9AB1, 0x6BD1, 0x9AB2, 0x6BD2, 0xB6BE, + 0x6BD3, 0xD8B9, 0x6BD4, 0xB1C8, 0x6BD5, 0xB1CF, 0x6BD6, 0xB1D1, 0x6BD7, 0xC5FE, 0x6BD8, 0x9AB3, 0x6BD9, 0xB1D0, 0x6BDA, 0x9AB4, + 0x6BDB, 0xC3AB, 0x6BDC, 0x9AB5, 0x6BDD, 0x9AB6, 0x6BDE, 0x9AB7, 0x6BDF, 0x9AB8, 0x6BE0, 0x9AB9, 0x6BE1, 0xD5B1, 0x6BE2, 0x9ABA, + 0x6BE3, 0x9ABB, 0x6BE4, 0x9ABC, 0x6BE5, 0x9ABD, 0x6BE6, 0x9ABE, 0x6BE7, 0x9ABF, 0x6BE8, 0x9AC0, 0x6BE9, 0x9AC1, 0x6BEA, 0xEBA4, + 0x6BEB, 0xBAC1, 0x6BEC, 0x9AC2, 0x6BED, 0x9AC3, 0x6BEE, 0x9AC4, 0x6BEF, 0xCCBA, 0x6BF0, 0x9AC5, 0x6BF1, 0x9AC6, 0x6BF2, 0x9AC7, + 0x6BF3, 0xEBA5, 0x6BF4, 0x9AC8, 0x6BF5, 0xEBA7, 0x6BF6, 0x9AC9, 0x6BF7, 0x9ACA, 0x6BF8, 0x9ACB, 0x6BF9, 0xEBA8, 0x6BFA, 0x9ACC, + 0x6BFB, 0x9ACD, 0x6BFC, 0x9ACE, 0x6BFD, 0xEBA6, 0x6BFE, 0x9ACF, 0x6BFF, 0x9AD0, 0x6C00, 0x9AD1, 0x6C01, 0x9AD2, 0x6C02, 0x9AD3, + 0x6C03, 0x9AD4, 0x6C04, 0x9AD5, 0x6C05, 0xEBA9, 0x6C06, 0xEBAB, 0x6C07, 0xEBAA, 0x6C08, 0x9AD6, 0x6C09, 0x9AD7, 0x6C0A, 0x9AD8, + 0x6C0B, 0x9AD9, 0x6C0C, 0x9ADA, 0x6C0D, 0xEBAC, 0x6C0E, 0x9ADB, 0x6C0F, 0xCACF, 0x6C10, 0xD8B5, 0x6C11, 0xC3F1, 0x6C12, 0x9ADC, + 0x6C13, 0xC3A5, 0x6C14, 0xC6F8, 0x6C15, 0xEBAD, 0x6C16, 0xC4CA, 0x6C17, 0x9ADD, 0x6C18, 0xEBAE, 0x6C19, 0xEBAF, 0x6C1A, 0xEBB0, + 0x6C1B, 0xB7D5, 0x6C1C, 0x9ADE, 0x6C1D, 0x9ADF, 0x6C1E, 0x9AE0, 0x6C1F, 0xB7FA, 0x6C20, 0x9AE1, 0x6C21, 0xEBB1, 0x6C22, 0xC7E2, + 0x6C23, 0x9AE2, 0x6C24, 0xEBB3, 0x6C25, 0x9AE3, 0x6C26, 0xBAA4, 0x6C27, 0xD1F5, 0x6C28, 0xB0B1, 0x6C29, 0xEBB2, 0x6C2A, 0xEBB4, + 0x6C2B, 0x9AE4, 0x6C2C, 0x9AE5, 0x6C2D, 0x9AE6, 0x6C2E, 0xB5AA, 0x6C2F, 0xC2C8, 0x6C30, 0xC7E8, 0x6C31, 0x9AE7, 0x6C32, 0xEBB5, + 0x6C33, 0x9AE8, 0x6C34, 0xCBAE, 0x6C35, 0xE3DF, 0x6C36, 0x9AE9, 0x6C37, 0x9AEA, 0x6C38, 0xD3C0, 0x6C39, 0x9AEB, 0x6C3A, 0x9AEC, + 0x6C3B, 0x9AED, 0x6C3C, 0x9AEE, 0x6C3D, 0xD9DB, 0x6C3E, 0x9AEF, 0x6C3F, 0x9AF0, 0x6C40, 0xCDA1, 0x6C41, 0xD6AD, 0x6C42, 0xC7F3, + 0x6C43, 0x9AF1, 0x6C44, 0x9AF2, 0x6C45, 0x9AF3, 0x6C46, 0xD9E0, 0x6C47, 0xBBE3, 0x6C48, 0x9AF4, 0x6C49, 0xBABA, 0x6C4A, 0xE3E2, + 0x6C4B, 0x9AF5, 0x6C4C, 0x9AF6, 0x6C4D, 0x9AF7, 0x6C4E, 0x9AF8, 0x6C4F, 0x9AF9, 0x6C50, 0xCFAB, 0x6C51, 0x9AFA, 0x6C52, 0x9AFB, + 0x6C53, 0x9AFC, 0x6C54, 0xE3E0, 0x6C55, 0xC9C7, 0x6C56, 0x9AFD, 0x6C57, 0xBAB9, 0x6C58, 0x9AFE, 0x6C59, 0x9B40, 0x6C5A, 0x9B41, + 0x6C5B, 0xD1B4, 0x6C5C, 0xE3E1, 0x6C5D, 0xC8EA, 0x6C5E, 0xB9AF, 0x6C5F, 0xBDAD, 0x6C60, 0xB3D8, 0x6C61, 0xCEDB, 0x6C62, 0x9B42, + 0x6C63, 0x9B43, 0x6C64, 0xCCC0, 0x6C65, 0x9B44, 0x6C66, 0x9B45, 0x6C67, 0x9B46, 0x6C68, 0xE3E8, 0x6C69, 0xE3E9, 0x6C6A, 0xCDF4, + 0x6C6B, 0x9B47, 0x6C6C, 0x9B48, 0x6C6D, 0x9B49, 0x6C6E, 0x9B4A, 0x6C6F, 0x9B4B, 0x6C70, 0xCCAD, 0x6C71, 0x9B4C, 0x6C72, 0xBCB3, + 0x6C73, 0x9B4D, 0x6C74, 0xE3EA, 0x6C75, 0x9B4E, 0x6C76, 0xE3EB, 0x6C77, 0x9B4F, 0x6C78, 0x9B50, 0x6C79, 0xD0DA, 0x6C7A, 0x9B51, + 0x6C7B, 0x9B52, 0x6C7C, 0x9B53, 0x6C7D, 0xC6FB, 0x6C7E, 0xB7DA, 0x6C7F, 0x9B54, 0x6C80, 0x9B55, 0x6C81, 0xC7DF, 0x6C82, 0xD2CA, + 0x6C83, 0xCED6, 0x6C84, 0x9B56, 0x6C85, 0xE3E4, 0x6C86, 0xE3EC, 0x6C87, 0x9B57, 0x6C88, 0xC9F2, 0x6C89, 0xB3C1, 0x6C8A, 0x9B58, + 0x6C8B, 0x9B59, 0x6C8C, 0xE3E7, 0x6C8D, 0x9B5A, 0x6C8E, 0x9B5B, 0x6C8F, 0xC6E3, 0x6C90, 0xE3E5, 0x6C91, 0x9B5C, 0x6C92, 0x9B5D, + 0x6C93, 0xEDB3, 0x6C94, 0xE3E6, 0x6C95, 0x9B5E, 0x6C96, 0x9B5F, 0x6C97, 0x9B60, 0x6C98, 0x9B61, 0x6C99, 0xC9B3, 0x6C9A, 0x9B62, + 0x6C9B, 0xC5E6, 0x6C9C, 0x9B63, 0x6C9D, 0x9B64, 0x6C9E, 0x9B65, 0x6C9F, 0xB9B5, 0x6CA0, 0x9B66, 0x6CA1, 0xC3BB, 0x6CA2, 0x9B67, + 0x6CA3, 0xE3E3, 0x6CA4, 0xC5BD, 0x6CA5, 0xC1A4, 0x6CA6, 0xC2D9, 0x6CA7, 0xB2D7, 0x6CA8, 0x9B68, 0x6CA9, 0xE3ED, 0x6CAA, 0xBBA6, + 0x6CAB, 0xC4AD, 0x6CAC, 0x9B69, 0x6CAD, 0xE3F0, 0x6CAE, 0xBEDA, 0x6CAF, 0x9B6A, 0x6CB0, 0x9B6B, 0x6CB1, 0xE3FB, 0x6CB2, 0xE3F5, + 0x6CB3, 0xBAD3, 0x6CB4, 0x9B6C, 0x6CB5, 0x9B6D, 0x6CB6, 0x9B6E, 0x6CB7, 0x9B6F, 0x6CB8, 0xB7D0, 0x6CB9, 0xD3CD, 0x6CBA, 0x9B70, + 0x6CBB, 0xD6CE, 0x6CBC, 0xD5D3, 0x6CBD, 0xB9C1, 0x6CBE, 0xD5B4, 0x6CBF, 0xD1D8, 0x6CC0, 0x9B71, 0x6CC1, 0x9B72, 0x6CC2, 0x9B73, + 0x6CC3, 0x9B74, 0x6CC4, 0xD0B9, 0x6CC5, 0xC7F6, 0x6CC6, 0x9B75, 0x6CC7, 0x9B76, 0x6CC8, 0x9B77, 0x6CC9, 0xC8AA, 0x6CCA, 0xB2B4, + 0x6CCB, 0x9B78, 0x6CCC, 0xC3DA, 0x6CCD, 0x9B79, 0x6CCE, 0x9B7A, 0x6CCF, 0x9B7B, 0x6CD0, 0xE3EE, 0x6CD1, 0x9B7C, 0x6CD2, 0x9B7D, + 0x6CD3, 0xE3FC, 0x6CD4, 0xE3EF, 0x6CD5, 0xB7A8, 0x6CD6, 0xE3F7, 0x6CD7, 0xE3F4, 0x6CD8, 0x9B7E, 0x6CD9, 0x9B80, 0x6CDA, 0x9B81, + 0x6CDB, 0xB7BA, 0x6CDC, 0x9B82, 0x6CDD, 0x9B83, 0x6CDE, 0xC5A2, 0x6CDF, 0x9B84, 0x6CE0, 0xE3F6, 0x6CE1, 0xC5DD, 0x6CE2, 0xB2A8, + 0x6CE3, 0xC6FC, 0x6CE4, 0x9B85, 0x6CE5, 0xC4E0, 0x6CE6, 0x9B86, 0x6CE7, 0x9B87, 0x6CE8, 0xD7A2, 0x6CE9, 0x9B88, 0x6CEA, 0xC0E1, + 0x6CEB, 0xE3F9, 0x6CEC, 0x9B89, 0x6CED, 0x9B8A, 0x6CEE, 0xE3FA, 0x6CEF, 0xE3FD, 0x6CF0, 0xCCA9, 0x6CF1, 0xE3F3, 0x6CF2, 0x9B8B, + 0x6CF3, 0xD3BE, 0x6CF4, 0x9B8C, 0x6CF5, 0xB1C3, 0x6CF6, 0xEDB4, 0x6CF7, 0xE3F1, 0x6CF8, 0xE3F2, 0x6CF9, 0x9B8D, 0x6CFA, 0xE3F8, + 0x6CFB, 0xD0BA, 0x6CFC, 0xC6C3, 0x6CFD, 0xD4F3, 0x6CFE, 0xE3FE, 0x6CFF, 0x9B8E, 0x6D00, 0x9B8F, 0x6D01, 0xBDE0, 0x6D02, 0x9B90, + 0x6D03, 0x9B91, 0x6D04, 0xE4A7, 0x6D05, 0x9B92, 0x6D06, 0x9B93, 0x6D07, 0xE4A6, 0x6D08, 0x9B94, 0x6D09, 0x9B95, 0x6D0A, 0x9B96, + 0x6D0B, 0xD1F3, 0x6D0C, 0xE4A3, 0x6D0D, 0x9B97, 0x6D0E, 0xE4A9, 0x6D0F, 0x9B98, 0x6D10, 0x9B99, 0x6D11, 0x9B9A, 0x6D12, 0xC8F7, + 0x6D13, 0x9B9B, 0x6D14, 0x9B9C, 0x6D15, 0x9B9D, 0x6D16, 0x9B9E, 0x6D17, 0xCFB4, 0x6D18, 0x9B9F, 0x6D19, 0xE4A8, 0x6D1A, 0xE4AE, + 0x6D1B, 0xC2E5, 0x6D1C, 0x9BA0, 0x6D1D, 0x9BA1, 0x6D1E, 0xB6B4, 0x6D1F, 0x9BA2, 0x6D20, 0x9BA3, 0x6D21, 0x9BA4, 0x6D22, 0x9BA5, + 0x6D23, 0x9BA6, 0x6D24, 0x9BA7, 0x6D25, 0xBDF2, 0x6D26, 0x9BA8, 0x6D27, 0xE4A2, 0x6D28, 0x9BA9, 0x6D29, 0x9BAA, 0x6D2A, 0xBAE9, + 0x6D2B, 0xE4AA, 0x6D2C, 0x9BAB, 0x6D2D, 0x9BAC, 0x6D2E, 0xE4AC, 0x6D2F, 0x9BAD, 0x6D30, 0x9BAE, 0x6D31, 0xB6FD, 0x6D32, 0xD6DE, + 0x6D33, 0xE4B2, 0x6D34, 0x9BAF, 0x6D35, 0xE4AD, 0x6D36, 0x9BB0, 0x6D37, 0x9BB1, 0x6D38, 0x9BB2, 0x6D39, 0xE4A1, 0x6D3A, 0x9BB3, + 0x6D3B, 0xBBEE, 0x6D3C, 0xCDDD, 0x6D3D, 0xC7A2, 0x6D3E, 0xC5C9, 0x6D3F, 0x9BB4, 0x6D40, 0x9BB5, 0x6D41, 0xC1F7, 0x6D42, 0x9BB6, + 0x6D43, 0xE4A4, 0x6D44, 0x9BB7, 0x6D45, 0xC7B3, 0x6D46, 0xBDAC, 0x6D47, 0xBDBD, 0x6D48, 0xE4A5, 0x6D49, 0x9BB8, 0x6D4A, 0xD7C7, + 0x6D4B, 0xB2E2, 0x6D4C, 0x9BB9, 0x6D4D, 0xE4AB, 0x6D4E, 0xBCC3, 0x6D4F, 0xE4AF, 0x6D50, 0x9BBA, 0x6D51, 0xBBEB, 0x6D52, 0xE4B0, + 0x6D53, 0xC5A8, 0x6D54, 0xE4B1, 0x6D55, 0x9BBB, 0x6D56, 0x9BBC, 0x6D57, 0x9BBD, 0x6D58, 0x9BBE, 0x6D59, 0xD5E3, 0x6D5A, 0xBFA3, + 0x6D5B, 0x9BBF, 0x6D5C, 0xE4BA, 0x6D5D, 0x9BC0, 0x6D5E, 0xE4B7, 0x6D5F, 0x9BC1, 0x6D60, 0xE4BB, 0x6D61, 0x9BC2, 0x6D62, 0x9BC3, + 0x6D63, 0xE4BD, 0x6D64, 0x9BC4, 0x6D65, 0x9BC5, 0x6D66, 0xC6D6, 0x6D67, 0x9BC6, 0x6D68, 0x9BC7, 0x6D69, 0xBAC6, 0x6D6A, 0xC0CB, + 0x6D6B, 0x9BC8, 0x6D6C, 0x9BC9, 0x6D6D, 0x9BCA, 0x6D6E, 0xB8A1, 0x6D6F, 0xE4B4, 0x6D70, 0x9BCB, 0x6D71, 0x9BCC, 0x6D72, 0x9BCD, + 0x6D73, 0x9BCE, 0x6D74, 0xD4A1, 0x6D75, 0x9BCF, 0x6D76, 0x9BD0, 0x6D77, 0xBAA3, 0x6D78, 0xBDFE, 0x6D79, 0x9BD1, 0x6D7A, 0x9BD2, + 0x6D7B, 0x9BD3, 0x6D7C, 0xE4BC, 0x6D7D, 0x9BD4, 0x6D7E, 0x9BD5, 0x6D7F, 0x9BD6, 0x6D80, 0x9BD7, 0x6D81, 0x9BD8, 0x6D82, 0xCDBF, + 0x6D83, 0x9BD9, 0x6D84, 0x9BDA, 0x6D85, 0xC4F9, 0x6D86, 0x9BDB, 0x6D87, 0x9BDC, 0x6D88, 0xCFFB, 0x6D89, 0xC9E6, 0x6D8A, 0x9BDD, + 0x6D8B, 0x9BDE, 0x6D8C, 0xD3BF, 0x6D8D, 0x9BDF, 0x6D8E, 0xCFD1, 0x6D8F, 0x9BE0, 0x6D90, 0x9BE1, 0x6D91, 0xE4B3, 0x6D92, 0x9BE2, + 0x6D93, 0xE4B8, 0x6D94, 0xE4B9, 0x6D95, 0xCCE9, 0x6D96, 0x9BE3, 0x6D97, 0x9BE4, 0x6D98, 0x9BE5, 0x6D99, 0x9BE6, 0x6D9A, 0x9BE7, + 0x6D9B, 0xCCCE, 0x6D9C, 0x9BE8, 0x6D9D, 0xC0D4, 0x6D9E, 0xE4B5, 0x6D9F, 0xC1B0, 0x6DA0, 0xE4B6, 0x6DA1, 0xCED0, 0x6DA2, 0x9BE9, + 0x6DA3, 0xBBC1, 0x6DA4, 0xB5D3, 0x6DA5, 0x9BEA, 0x6DA6, 0xC8F3, 0x6DA7, 0xBDA7, 0x6DA8, 0xD5C7, 0x6DA9, 0xC9AC, 0x6DAA, 0xB8A2, + 0x6DAB, 0xE4CA, 0x6DAC, 0x9BEB, 0x6DAD, 0x9BEC, 0x6DAE, 0xE4CC, 0x6DAF, 0xD1C4, 0x6DB0, 0x9BED, 0x6DB1, 0x9BEE, 0x6DB2, 0xD2BA, + 0x6DB3, 0x9BEF, 0x6DB4, 0x9BF0, 0x6DB5, 0xBAAD, 0x6DB6, 0x9BF1, 0x6DB7, 0x9BF2, 0x6DB8, 0xBAD4, 0x6DB9, 0x9BF3, 0x6DBA, 0x9BF4, + 0x6DBB, 0x9BF5, 0x6DBC, 0x9BF6, 0x6DBD, 0x9BF7, 0x6DBE, 0x9BF8, 0x6DBF, 0xE4C3, 0x6DC0, 0xB5ED, 0x6DC1, 0x9BF9, 0x6DC2, 0x9BFA, + 0x6DC3, 0x9BFB, 0x6DC4, 0xD7CD, 0x6DC5, 0xE4C0, 0x6DC6, 0xCFFD, 0x6DC7, 0xE4BF, 0x6DC8, 0x9BFC, 0x6DC9, 0x9BFD, 0x6DCA, 0x9BFE, + 0x6DCB, 0xC1DC, 0x6DCC, 0xCCCA, 0x6DCD, 0x9C40, 0x6DCE, 0x9C41, 0x6DCF, 0x9C42, 0x6DD0, 0x9C43, 0x6DD1, 0xCAE7, 0x6DD2, 0x9C44, + 0x6DD3, 0x9C45, 0x6DD4, 0x9C46, 0x6DD5, 0x9C47, 0x6DD6, 0xC4D7, 0x6DD7, 0x9C48, 0x6DD8, 0xCCD4, 0x6DD9, 0xE4C8, 0x6DDA, 0x9C49, + 0x6DDB, 0x9C4A, 0x6DDC, 0x9C4B, 0x6DDD, 0xE4C7, 0x6DDE, 0xE4C1, 0x6DDF, 0x9C4C, 0x6DE0, 0xE4C4, 0x6DE1, 0xB5AD, 0x6DE2, 0x9C4D, + 0x6DE3, 0x9C4E, 0x6DE4, 0xD3D9, 0x6DE5, 0x9C4F, 0x6DE6, 0xE4C6, 0x6DE7, 0x9C50, 0x6DE8, 0x9C51, 0x6DE9, 0x9C52, 0x6DEA, 0x9C53, + 0x6DEB, 0xD2F9, 0x6DEC, 0xB4E3, 0x6DED, 0x9C54, 0x6DEE, 0xBBB4, 0x6DEF, 0x9C55, 0x6DF0, 0x9C56, 0x6DF1, 0xC9EE, 0x6DF2, 0x9C57, + 0x6DF3, 0xB4BE, 0x6DF4, 0x9C58, 0x6DF5, 0x9C59, 0x6DF6, 0x9C5A, 0x6DF7, 0xBBEC, 0x6DF8, 0x9C5B, 0x6DF9, 0xD1CD, 0x6DFA, 0x9C5C, + 0x6DFB, 0xCCED, 0x6DFC, 0xEDB5, 0x6DFD, 0x9C5D, 0x6DFE, 0x9C5E, 0x6DFF, 0x9C5F, 0x6E00, 0x9C60, 0x6E01, 0x9C61, 0x6E02, 0x9C62, + 0x6E03, 0x9C63, 0x6E04, 0x9C64, 0x6E05, 0xC7E5, 0x6E06, 0x9C65, 0x6E07, 0x9C66, 0x6E08, 0x9C67, 0x6E09, 0x9C68, 0x6E0A, 0xD4A8, + 0x6E0B, 0x9C69, 0x6E0C, 0xE4CB, 0x6E0D, 0xD7D5, 0x6E0E, 0xE4C2, 0x6E0F, 0x9C6A, 0x6E10, 0xBDA5, 0x6E11, 0xE4C5, 0x6E12, 0x9C6B, + 0x6E13, 0x9C6C, 0x6E14, 0xD3E6, 0x6E15, 0x9C6D, 0x6E16, 0xE4C9, 0x6E17, 0xC9F8, 0x6E18, 0x9C6E, 0x6E19, 0x9C6F, 0x6E1A, 0xE4BE, + 0x6E1B, 0x9C70, 0x6E1C, 0x9C71, 0x6E1D, 0xD3E5, 0x6E1E, 0x9C72, 0x6E1F, 0x9C73, 0x6E20, 0xC7FE, 0x6E21, 0xB6C9, 0x6E22, 0x9C74, + 0x6E23, 0xD4FC, 0x6E24, 0xB2B3, 0x6E25, 0xE4D7, 0x6E26, 0x9C75, 0x6E27, 0x9C76, 0x6E28, 0x9C77, 0x6E29, 0xCEC2, 0x6E2A, 0x9C78, + 0x6E2B, 0xE4CD, 0x6E2C, 0x9C79, 0x6E2D, 0xCEBC, 0x6E2E, 0x9C7A, 0x6E2F, 0xB8DB, 0x6E30, 0x9C7B, 0x6E31, 0x9C7C, 0x6E32, 0xE4D6, + 0x6E33, 0x9C7D, 0x6E34, 0xBFCA, 0x6E35, 0x9C7E, 0x6E36, 0x9C80, 0x6E37, 0x9C81, 0x6E38, 0xD3CE, 0x6E39, 0x9C82, 0x6E3A, 0xC3EC, + 0x6E3B, 0x9C83, 0x6E3C, 0x9C84, 0x6E3D, 0x9C85, 0x6E3E, 0x9C86, 0x6E3F, 0x9C87, 0x6E40, 0x9C88, 0x6E41, 0x9C89, 0x6E42, 0x9C8A, + 0x6E43, 0xC5C8, 0x6E44, 0xE4D8, 0x6E45, 0x9C8B, 0x6E46, 0x9C8C, 0x6E47, 0x9C8D, 0x6E48, 0x9C8E, 0x6E49, 0x9C8F, 0x6E4A, 0x9C90, + 0x6E4B, 0x9C91, 0x6E4C, 0x9C92, 0x6E4D, 0xCDC4, 0x6E4E, 0xE4CF, 0x6E4F, 0x9C93, 0x6E50, 0x9C94, 0x6E51, 0x9C95, 0x6E52, 0x9C96, + 0x6E53, 0xE4D4, 0x6E54, 0xE4D5, 0x6E55, 0x9C97, 0x6E56, 0xBAFE, 0x6E57, 0x9C98, 0x6E58, 0xCFE6, 0x6E59, 0x9C99, 0x6E5A, 0x9C9A, + 0x6E5B, 0xD5BF, 0x6E5C, 0x9C9B, 0x6E5D, 0x9C9C, 0x6E5E, 0x9C9D, 0x6E5F, 0xE4D2, 0x6E60, 0x9C9E, 0x6E61, 0x9C9F, 0x6E62, 0x9CA0, + 0x6E63, 0x9CA1, 0x6E64, 0x9CA2, 0x6E65, 0x9CA3, 0x6E66, 0x9CA4, 0x6E67, 0x9CA5, 0x6E68, 0x9CA6, 0x6E69, 0x9CA7, 0x6E6A, 0x9CA8, + 0x6E6B, 0xE4D0, 0x6E6C, 0x9CA9, 0x6E6D, 0x9CAA, 0x6E6E, 0xE4CE, 0x6E6F, 0x9CAB, 0x6E70, 0x9CAC, 0x6E71, 0x9CAD, 0x6E72, 0x9CAE, + 0x6E73, 0x9CAF, 0x6E74, 0x9CB0, 0x6E75, 0x9CB1, 0x6E76, 0x9CB2, 0x6E77, 0x9CB3, 0x6E78, 0x9CB4, 0x6E79, 0x9CB5, 0x6E7A, 0x9CB6, + 0x6E7B, 0x9CB7, 0x6E7C, 0x9CB8, 0x6E7D, 0x9CB9, 0x6E7E, 0xCDE5, 0x6E7F, 0xCAAA, 0x6E80, 0x9CBA, 0x6E81, 0x9CBB, 0x6E82, 0x9CBC, + 0x6E83, 0xC0A3, 0x6E84, 0x9CBD, 0x6E85, 0xBDA6, 0x6E86, 0xE4D3, 0x6E87, 0x9CBE, 0x6E88, 0x9CBF, 0x6E89, 0xB8C8, 0x6E8A, 0x9CC0, + 0x6E8B, 0x9CC1, 0x6E8C, 0x9CC2, 0x6E8D, 0x9CC3, 0x6E8E, 0x9CC4, 0x6E8F, 0xE4E7, 0x6E90, 0xD4B4, 0x6E91, 0x9CC5, 0x6E92, 0x9CC6, + 0x6E93, 0x9CC7, 0x6E94, 0x9CC8, 0x6E95, 0x9CC9, 0x6E96, 0x9CCA, 0x6E97, 0x9CCB, 0x6E98, 0xE4DB, 0x6E99, 0x9CCC, 0x6E9A, 0x9CCD, + 0x6E9B, 0x9CCE, 0x6E9C, 0xC1EF, 0x6E9D, 0x9CCF, 0x6E9E, 0x9CD0, 0x6E9F, 0xE4E9, 0x6EA0, 0x9CD1, 0x6EA1, 0x9CD2, 0x6EA2, 0xD2E7, + 0x6EA3, 0x9CD3, 0x6EA4, 0x9CD4, 0x6EA5, 0xE4DF, 0x6EA6, 0x9CD5, 0x6EA7, 0xE4E0, 0x6EA8, 0x9CD6, 0x6EA9, 0x9CD7, 0x6EAA, 0xCFAA, + 0x6EAB, 0x9CD8, 0x6EAC, 0x9CD9, 0x6EAD, 0x9CDA, 0x6EAE, 0x9CDB, 0x6EAF, 0xCBDD, 0x6EB0, 0x9CDC, 0x6EB1, 0xE4DA, 0x6EB2, 0xE4D1, + 0x6EB3, 0x9CDD, 0x6EB4, 0xE4E5, 0x6EB5, 0x9CDE, 0x6EB6, 0xC8DC, 0x6EB7, 0xE4E3, 0x6EB8, 0x9CDF, 0x6EB9, 0x9CE0, 0x6EBA, 0xC4E7, + 0x6EBB, 0xE4E2, 0x6EBC, 0x9CE1, 0x6EBD, 0xE4E1, 0x6EBE, 0x9CE2, 0x6EBF, 0x9CE3, 0x6EC0, 0x9CE4, 0x6EC1, 0xB3FC, 0x6EC2, 0xE4E8, + 0x6EC3, 0x9CE5, 0x6EC4, 0x9CE6, 0x6EC5, 0x9CE7, 0x6EC6, 0x9CE8, 0x6EC7, 0xB5E1, 0x6EC8, 0x9CE9, 0x6EC9, 0x9CEA, 0x6ECA, 0x9CEB, + 0x6ECB, 0xD7CC, 0x6ECC, 0x9CEC, 0x6ECD, 0x9CED, 0x6ECE, 0x9CEE, 0x6ECF, 0xE4E6, 0x6ED0, 0x9CEF, 0x6ED1, 0xBBAC, 0x6ED2, 0x9CF0, + 0x6ED3, 0xD7D2, 0x6ED4, 0xCCCF, 0x6ED5, 0xEBF8, 0x6ED6, 0x9CF1, 0x6ED7, 0xE4E4, 0x6ED8, 0x9CF2, 0x6ED9, 0x9CF3, 0x6EDA, 0xB9F6, + 0x6EDB, 0x9CF4, 0x6EDC, 0x9CF5, 0x6EDD, 0x9CF6, 0x6EDE, 0xD6CD, 0x6EDF, 0xE4D9, 0x6EE0, 0xE4DC, 0x6EE1, 0xC2FA, 0x6EE2, 0xE4DE, + 0x6EE3, 0x9CF7, 0x6EE4, 0xC2CB, 0x6EE5, 0xC0C4, 0x6EE6, 0xC2D0, 0x6EE7, 0x9CF8, 0x6EE8, 0xB1F5, 0x6EE9, 0xCCB2, 0x6EEA, 0x9CF9, + 0x6EEB, 0x9CFA, 0x6EEC, 0x9CFB, 0x6EED, 0x9CFC, 0x6EEE, 0x9CFD, 0x6EEF, 0x9CFE, 0x6EF0, 0x9D40, 0x6EF1, 0x9D41, 0x6EF2, 0x9D42, + 0x6EF3, 0x9D43, 0x6EF4, 0xB5CE, 0x6EF5, 0x9D44, 0x6EF6, 0x9D45, 0x6EF7, 0x9D46, 0x6EF8, 0x9D47, 0x6EF9, 0xE4EF, 0x6EFA, 0x9D48, + 0x6EFB, 0x9D49, 0x6EFC, 0x9D4A, 0x6EFD, 0x9D4B, 0x6EFE, 0x9D4C, 0x6EFF, 0x9D4D, 0x6F00, 0x9D4E, 0x6F01, 0x9D4F, 0x6F02, 0xC6AF, + 0x6F03, 0x9D50, 0x6F04, 0x9D51, 0x6F05, 0x9D52, 0x6F06, 0xC6E1, 0x6F07, 0x9D53, 0x6F08, 0x9D54, 0x6F09, 0xE4F5, 0x6F0A, 0x9D55, + 0x6F0B, 0x9D56, 0x6F0C, 0x9D57, 0x6F0D, 0x9D58, 0x6F0E, 0x9D59, 0x6F0F, 0xC2A9, 0x6F10, 0x9D5A, 0x6F11, 0x9D5B, 0x6F12, 0x9D5C, + 0x6F13, 0xC0EC, 0x6F14, 0xD1DD, 0x6F15, 0xE4EE, 0x6F16, 0x9D5D, 0x6F17, 0x9D5E, 0x6F18, 0x9D5F, 0x6F19, 0x9D60, 0x6F1A, 0x9D61, + 0x6F1B, 0x9D62, 0x6F1C, 0x9D63, 0x6F1D, 0x9D64, 0x6F1E, 0x9D65, 0x6F1F, 0x9D66, 0x6F20, 0xC4AE, 0x6F21, 0x9D67, 0x6F22, 0x9D68, + 0x6F23, 0x9D69, 0x6F24, 0xE4ED, 0x6F25, 0x9D6A, 0x6F26, 0x9D6B, 0x6F27, 0x9D6C, 0x6F28, 0x9D6D, 0x6F29, 0xE4F6, 0x6F2A, 0xE4F4, + 0x6F2B, 0xC2FE, 0x6F2C, 0x9D6E, 0x6F2D, 0xE4DD, 0x6F2E, 0x9D6F, 0x6F2F, 0xE4F0, 0x6F30, 0x9D70, 0x6F31, 0xCAFE, 0x6F32, 0x9D71, + 0x6F33, 0xD5C4, 0x6F34, 0x9D72, 0x6F35, 0x9D73, 0x6F36, 0xE4F1, 0x6F37, 0x9D74, 0x6F38, 0x9D75, 0x6F39, 0x9D76, 0x6F3A, 0x9D77, + 0x6F3B, 0x9D78, 0x6F3C, 0x9D79, 0x6F3D, 0x9D7A, 0x6F3E, 0xD1FA, 0x6F3F, 0x9D7B, 0x6F40, 0x9D7C, 0x6F41, 0x9D7D, 0x6F42, 0x9D7E, + 0x6F43, 0x9D80, 0x6F44, 0x9D81, 0x6F45, 0x9D82, 0x6F46, 0xE4EB, 0x6F47, 0xE4EC, 0x6F48, 0x9D83, 0x6F49, 0x9D84, 0x6F4A, 0x9D85, + 0x6F4B, 0xE4F2, 0x6F4C, 0x9D86, 0x6F4D, 0xCEAB, 0x6F4E, 0x9D87, 0x6F4F, 0x9D88, 0x6F50, 0x9D89, 0x6F51, 0x9D8A, 0x6F52, 0x9D8B, + 0x6F53, 0x9D8C, 0x6F54, 0x9D8D, 0x6F55, 0x9D8E, 0x6F56, 0x9D8F, 0x6F57, 0x9D90, 0x6F58, 0xC5CB, 0x6F59, 0x9D91, 0x6F5A, 0x9D92, + 0x6F5B, 0x9D93, 0x6F5C, 0xC7B1, 0x6F5D, 0x9D94, 0x6F5E, 0xC2BA, 0x6F5F, 0x9D95, 0x6F60, 0x9D96, 0x6F61, 0x9D97, 0x6F62, 0xE4EA, + 0x6F63, 0x9D98, 0x6F64, 0x9D99, 0x6F65, 0x9D9A, 0x6F66, 0xC1CA, 0x6F67, 0x9D9B, 0x6F68, 0x9D9C, 0x6F69, 0x9D9D, 0x6F6A, 0x9D9E, + 0x6F6B, 0x9D9F, 0x6F6C, 0x9DA0, 0x6F6D, 0xCCB6, 0x6F6E, 0xB3B1, 0x6F6F, 0x9DA1, 0x6F70, 0x9DA2, 0x6F71, 0x9DA3, 0x6F72, 0xE4FB, + 0x6F73, 0x9DA4, 0x6F74, 0xE4F3, 0x6F75, 0x9DA5, 0x6F76, 0x9DA6, 0x6F77, 0x9DA7, 0x6F78, 0xE4FA, 0x6F79, 0x9DA8, 0x6F7A, 0xE4FD, + 0x6F7B, 0x9DA9, 0x6F7C, 0xE4FC, 0x6F7D, 0x9DAA, 0x6F7E, 0x9DAB, 0x6F7F, 0x9DAC, 0x6F80, 0x9DAD, 0x6F81, 0x9DAE, 0x6F82, 0x9DAF, + 0x6F83, 0x9DB0, 0x6F84, 0xB3CE, 0x6F85, 0x9DB1, 0x6F86, 0x9DB2, 0x6F87, 0x9DB3, 0x6F88, 0xB3BA, 0x6F89, 0xE4F7, 0x6F8A, 0x9DB4, + 0x6F8B, 0x9DB5, 0x6F8C, 0xE4F9, 0x6F8D, 0xE4F8, 0x6F8E, 0xC5EC, 0x6F8F, 0x9DB6, 0x6F90, 0x9DB7, 0x6F91, 0x9DB8, 0x6F92, 0x9DB9, + 0x6F93, 0x9DBA, 0x6F94, 0x9DBB, 0x6F95, 0x9DBC, 0x6F96, 0x9DBD, 0x6F97, 0x9DBE, 0x6F98, 0x9DBF, 0x6F99, 0x9DC0, 0x6F9A, 0x9DC1, + 0x6F9B, 0x9DC2, 0x6F9C, 0xC0BD, 0x6F9D, 0x9DC3, 0x6F9E, 0x9DC4, 0x6F9F, 0x9DC5, 0x6FA0, 0x9DC6, 0x6FA1, 0xD4E8, 0x6FA2, 0x9DC7, + 0x6FA3, 0x9DC8, 0x6FA4, 0x9DC9, 0x6FA5, 0x9DCA, 0x6FA6, 0x9DCB, 0x6FA7, 0xE5A2, 0x6FA8, 0x9DCC, 0x6FA9, 0x9DCD, 0x6FAA, 0x9DCE, + 0x6FAB, 0x9DCF, 0x6FAC, 0x9DD0, 0x6FAD, 0x9DD1, 0x6FAE, 0x9DD2, 0x6FAF, 0x9DD3, 0x6FB0, 0x9DD4, 0x6FB1, 0x9DD5, 0x6FB2, 0x9DD6, + 0x6FB3, 0xB0C4, 0x6FB4, 0x9DD7, 0x6FB5, 0x9DD8, 0x6FB6, 0xE5A4, 0x6FB7, 0x9DD9, 0x6FB8, 0x9DDA, 0x6FB9, 0xE5A3, 0x6FBA, 0x9DDB, + 0x6FBB, 0x9DDC, 0x6FBC, 0x9DDD, 0x6FBD, 0x9DDE, 0x6FBE, 0x9DDF, 0x6FBF, 0x9DE0, 0x6FC0, 0xBCA4, 0x6FC1, 0x9DE1, 0x6FC2, 0xE5A5, + 0x6FC3, 0x9DE2, 0x6FC4, 0x9DE3, 0x6FC5, 0x9DE4, 0x6FC6, 0x9DE5, 0x6FC7, 0x9DE6, 0x6FC8, 0x9DE7, 0x6FC9, 0xE5A1, 0x6FCA, 0x9DE8, + 0x6FCB, 0x9DE9, 0x6FCC, 0x9DEA, 0x6FCD, 0x9DEB, 0x6FCE, 0x9DEC, 0x6FCF, 0x9DED, 0x6FD0, 0x9DEE, 0x6FD1, 0xE4FE, 0x6FD2, 0xB1F4, + 0x6FD3, 0x9DEF, 0x6FD4, 0x9DF0, 0x6FD5, 0x9DF1, 0x6FD6, 0x9DF2, 0x6FD7, 0x9DF3, 0x6FD8, 0x9DF4, 0x6FD9, 0x9DF5, 0x6FDA, 0x9DF6, + 0x6FDB, 0x9DF7, 0x6FDC, 0x9DF8, 0x6FDD, 0x9DF9, 0x6FDE, 0xE5A8, 0x6FDF, 0x9DFA, 0x6FE0, 0xE5A9, 0x6FE1, 0xE5A6, 0x6FE2, 0x9DFB, + 0x6FE3, 0x9DFC, 0x6FE4, 0x9DFD, 0x6FE5, 0x9DFE, 0x6FE6, 0x9E40, 0x6FE7, 0x9E41, 0x6FE8, 0x9E42, 0x6FE9, 0x9E43, 0x6FEA, 0x9E44, + 0x6FEB, 0x9E45, 0x6FEC, 0x9E46, 0x6FED, 0x9E47, 0x6FEE, 0xE5A7, 0x6FEF, 0xE5AA, 0x6FF0, 0x9E48, 0x6FF1, 0x9E49, 0x6FF2, 0x9E4A, + 0x6FF3, 0x9E4B, 0x6FF4, 0x9E4C, 0x6FF5, 0x9E4D, 0x6FF6, 0x9E4E, 0x6FF7, 0x9E4F, 0x6FF8, 0x9E50, 0x6FF9, 0x9E51, 0x6FFA, 0x9E52, + 0x6FFB, 0x9E53, 0x6FFC, 0x9E54, 0x6FFD, 0x9E55, 0x6FFE, 0x9E56, 0x6FFF, 0x9E57, 0x7000, 0x9E58, 0x7001, 0x9E59, 0x7002, 0x9E5A, + 0x7003, 0x9E5B, 0x7004, 0x9E5C, 0x7005, 0x9E5D, 0x7006, 0x9E5E, 0x7007, 0x9E5F, 0x7008, 0x9E60, 0x7009, 0x9E61, 0x700A, 0x9E62, + 0x700B, 0x9E63, 0x700C, 0x9E64, 0x700D, 0x9E65, 0x700E, 0x9E66, 0x700F, 0x9E67, 0x7010, 0x9E68, 0x7011, 0xC6D9, 0x7012, 0x9E69, + 0x7013, 0x9E6A, 0x7014, 0x9E6B, 0x7015, 0x9E6C, 0x7016, 0x9E6D, 0x7017, 0x9E6E, 0x7018, 0x9E6F, 0x7019, 0x9E70, 0x701A, 0xE5AB, + 0x701B, 0xE5AD, 0x701C, 0x9E71, 0x701D, 0x9E72, 0x701E, 0x9E73, 0x701F, 0x9E74, 0x7020, 0x9E75, 0x7021, 0x9E76, 0x7022, 0x9E77, + 0x7023, 0xE5AC, 0x7024, 0x9E78, 0x7025, 0x9E79, 0x7026, 0x9E7A, 0x7027, 0x9E7B, 0x7028, 0x9E7C, 0x7029, 0x9E7D, 0x702A, 0x9E7E, + 0x702B, 0x9E80, 0x702C, 0x9E81, 0x702D, 0x9E82, 0x702E, 0x9E83, 0x702F, 0x9E84, 0x7030, 0x9E85, 0x7031, 0x9E86, 0x7032, 0x9E87, + 0x7033, 0x9E88, 0x7034, 0x9E89, 0x7035, 0xE5AF, 0x7036, 0x9E8A, 0x7037, 0x9E8B, 0x7038, 0x9E8C, 0x7039, 0xE5AE, 0x703A, 0x9E8D, + 0x703B, 0x9E8E, 0x703C, 0x9E8F, 0x703D, 0x9E90, 0x703E, 0x9E91, 0x703F, 0x9E92, 0x7040, 0x9E93, 0x7041, 0x9E94, 0x7042, 0x9E95, + 0x7043, 0x9E96, 0x7044, 0x9E97, 0x7045, 0x9E98, 0x7046, 0x9E99, 0x7047, 0x9E9A, 0x7048, 0x9E9B, 0x7049, 0x9E9C, 0x704A, 0x9E9D, + 0x704B, 0x9E9E, 0x704C, 0xB9E0, 0x704D, 0x9E9F, 0x704E, 0x9EA0, 0x704F, 0xE5B0, 0x7050, 0x9EA1, 0x7051, 0x9EA2, 0x7052, 0x9EA3, + 0x7053, 0x9EA4, 0x7054, 0x9EA5, 0x7055, 0x9EA6, 0x7056, 0x9EA7, 0x7057, 0x9EA8, 0x7058, 0x9EA9, 0x7059, 0x9EAA, 0x705A, 0x9EAB, + 0x705B, 0x9EAC, 0x705C, 0x9EAD, 0x705D, 0x9EAE, 0x705E, 0xE5B1, 0x705F, 0x9EAF, 0x7060, 0x9EB0, 0x7061, 0x9EB1, 0x7062, 0x9EB2, + 0x7063, 0x9EB3, 0x7064, 0x9EB4, 0x7065, 0x9EB5, 0x7066, 0x9EB6, 0x7067, 0x9EB7, 0x7068, 0x9EB8, 0x7069, 0x9EB9, 0x706A, 0x9EBA, + 0x706B, 0xBBF0, 0x706C, 0xECE1, 0x706D, 0xC3F0, 0x706E, 0x9EBB, 0x706F, 0xB5C6, 0x7070, 0xBBD2, 0x7071, 0x9EBC, 0x7072, 0x9EBD, + 0x7073, 0x9EBE, 0x7074, 0x9EBF, 0x7075, 0xC1E9, 0x7076, 0xD4EE, 0x7077, 0x9EC0, 0x7078, 0xBEC4, 0x7079, 0x9EC1, 0x707A, 0x9EC2, + 0x707B, 0x9EC3, 0x707C, 0xD7C6, 0x707D, 0x9EC4, 0x707E, 0xD4D6, 0x707F, 0xB2D3, 0x7080, 0xECBE, 0x7081, 0x9EC5, 0x7082, 0x9EC6, + 0x7083, 0x9EC7, 0x7084, 0x9EC8, 0x7085, 0xEAC1, 0x7086, 0x9EC9, 0x7087, 0x9ECA, 0x7088, 0x9ECB, 0x7089, 0xC2AF, 0x708A, 0xB4B6, + 0x708B, 0x9ECC, 0x708C, 0x9ECD, 0x708D, 0x9ECE, 0x708E, 0xD1D7, 0x708F, 0x9ECF, 0x7090, 0x9ED0, 0x7091, 0x9ED1, 0x7092, 0xB3B4, + 0x7093, 0x9ED2, 0x7094, 0xC8B2, 0x7095, 0xBFBB, 0x7096, 0xECC0, 0x7097, 0x9ED3, 0x7098, 0x9ED4, 0x7099, 0xD6CB, 0x709A, 0x9ED5, + 0x709B, 0x9ED6, 0x709C, 0xECBF, 0x709D, 0xECC1, 0x709E, 0x9ED7, 0x709F, 0x9ED8, 0x70A0, 0x9ED9, 0x70A1, 0x9EDA, 0x70A2, 0x9EDB, + 0x70A3, 0x9EDC, 0x70A4, 0x9EDD, 0x70A5, 0x9EDE, 0x70A6, 0x9EDF, 0x70A7, 0x9EE0, 0x70A8, 0x9EE1, 0x70A9, 0x9EE2, 0x70AA, 0x9EE3, + 0x70AB, 0xECC5, 0x70AC, 0xBEE6, 0x70AD, 0xCCBF, 0x70AE, 0xC5DA, 0x70AF, 0xBEBC, 0x70B0, 0x9EE4, 0x70B1, 0xECC6, 0x70B2, 0x9EE5, + 0x70B3, 0xB1FE, 0x70B4, 0x9EE6, 0x70B5, 0x9EE7, 0x70B6, 0x9EE8, 0x70B7, 0xECC4, 0x70B8, 0xD5A8, 0x70B9, 0xB5E3, 0x70BA, 0x9EE9, + 0x70BB, 0xECC2, 0x70BC, 0xC1B6, 0x70BD, 0xB3E3, 0x70BE, 0x9EEA, 0x70BF, 0x9EEB, 0x70C0, 0xECC3, 0x70C1, 0xCBB8, 0x70C2, 0xC0C3, + 0x70C3, 0xCCFE, 0x70C4, 0x9EEC, 0x70C5, 0x9EED, 0x70C6, 0x9EEE, 0x70C7, 0x9EEF, 0x70C8, 0xC1D2, 0x70C9, 0x9EF0, 0x70CA, 0xECC8, + 0x70CB, 0x9EF1, 0x70CC, 0x9EF2, 0x70CD, 0x9EF3, 0x70CE, 0x9EF4, 0x70CF, 0x9EF5, 0x70D0, 0x9EF6, 0x70D1, 0x9EF7, 0x70D2, 0x9EF8, + 0x70D3, 0x9EF9, 0x70D4, 0x9EFA, 0x70D5, 0x9EFB, 0x70D6, 0x9EFC, 0x70D7, 0x9EFD, 0x70D8, 0xBAE6, 0x70D9, 0xC0D3, 0x70DA, 0x9EFE, + 0x70DB, 0xD6F2, 0x70DC, 0x9F40, 0x70DD, 0x9F41, 0x70DE, 0x9F42, 0x70DF, 0xD1CC, 0x70E0, 0x9F43, 0x70E1, 0x9F44, 0x70E2, 0x9F45, + 0x70E3, 0x9F46, 0x70E4, 0xBFBE, 0x70E5, 0x9F47, 0x70E6, 0xB7B3, 0x70E7, 0xC9D5, 0x70E8, 0xECC7, 0x70E9, 0xBBE2, 0x70EA, 0x9F48, + 0x70EB, 0xCCCC, 0x70EC, 0xBDFD, 0x70ED, 0xC8C8, 0x70EE, 0x9F49, 0x70EF, 0xCFA9, 0x70F0, 0x9F4A, 0x70F1, 0x9F4B, 0x70F2, 0x9F4C, + 0x70F3, 0x9F4D, 0x70F4, 0x9F4E, 0x70F5, 0x9F4F, 0x70F6, 0x9F50, 0x70F7, 0xCDE9, 0x70F8, 0x9F51, 0x70F9, 0xC5EB, 0x70FA, 0x9F52, + 0x70FB, 0x9F53, 0x70FC, 0x9F54, 0x70FD, 0xB7E9, 0x70FE, 0x9F55, 0x70FF, 0x9F56, 0x7100, 0x9F57, 0x7101, 0x9F58, 0x7102, 0x9F59, + 0x7103, 0x9F5A, 0x7104, 0x9F5B, 0x7105, 0x9F5C, 0x7106, 0x9F5D, 0x7107, 0x9F5E, 0x7108, 0x9F5F, 0x7109, 0xD1C9, 0x710A, 0xBAB8, + 0x710B, 0x9F60, 0x710C, 0x9F61, 0x710D, 0x9F62, 0x710E, 0x9F63, 0x710F, 0x9F64, 0x7110, 0xECC9, 0x7111, 0x9F65, 0x7112, 0x9F66, + 0x7113, 0xECCA, 0x7114, 0x9F67, 0x7115, 0xBBC0, 0x7116, 0xECCB, 0x7117, 0x9F68, 0x7118, 0xECE2, 0x7119, 0xB1BA, 0x711A, 0xB7D9, + 0x711B, 0x9F69, 0x711C, 0x9F6A, 0x711D, 0x9F6B, 0x711E, 0x9F6C, 0x711F, 0x9F6D, 0x7120, 0x9F6E, 0x7121, 0x9F6F, 0x7122, 0x9F70, + 0x7123, 0x9F71, 0x7124, 0x9F72, 0x7125, 0x9F73, 0x7126, 0xBDB9, 0x7127, 0x9F74, 0x7128, 0x9F75, 0x7129, 0x9F76, 0x712A, 0x9F77, + 0x712B, 0x9F78, 0x712C, 0x9F79, 0x712D, 0x9F7A, 0x712E, 0x9F7B, 0x712F, 0xECCC, 0x7130, 0xD1E6, 0x7131, 0xECCD, 0x7132, 0x9F7C, + 0x7133, 0x9F7D, 0x7134, 0x9F7E, 0x7135, 0x9F80, 0x7136, 0xC8BB, 0x7137, 0x9F81, 0x7138, 0x9F82, 0x7139, 0x9F83, 0x713A, 0x9F84, + 0x713B, 0x9F85, 0x713C, 0x9F86, 0x713D, 0x9F87, 0x713E, 0x9F88, 0x713F, 0x9F89, 0x7140, 0x9F8A, 0x7141, 0x9F8B, 0x7142, 0x9F8C, + 0x7143, 0x9F8D, 0x7144, 0x9F8E, 0x7145, 0xECD1, 0x7146, 0x9F8F, 0x7147, 0x9F90, 0x7148, 0x9F91, 0x7149, 0x9F92, 0x714A, 0xECD3, + 0x714B, 0x9F93, 0x714C, 0xBBCD, 0x714D, 0x9F94, 0x714E, 0xBCE5, 0x714F, 0x9F95, 0x7150, 0x9F96, 0x7151, 0x9F97, 0x7152, 0x9F98, + 0x7153, 0x9F99, 0x7154, 0x9F9A, 0x7155, 0x9F9B, 0x7156, 0x9F9C, 0x7157, 0x9F9D, 0x7158, 0x9F9E, 0x7159, 0x9F9F, 0x715A, 0x9FA0, + 0x715B, 0x9FA1, 0x715C, 0xECCF, 0x715D, 0x9FA2, 0x715E, 0xC9B7, 0x715F, 0x9FA3, 0x7160, 0x9FA4, 0x7161, 0x9FA5, 0x7162, 0x9FA6, + 0x7163, 0x9FA7, 0x7164, 0xC3BA, 0x7165, 0x9FA8, 0x7166, 0xECE3, 0x7167, 0xD5D5, 0x7168, 0xECD0, 0x7169, 0x9FA9, 0x716A, 0x9FAA, + 0x716B, 0x9FAB, 0x716C, 0x9FAC, 0x716D, 0x9FAD, 0x716E, 0xD6F3, 0x716F, 0x9FAE, 0x7170, 0x9FAF, 0x7171, 0x9FB0, 0x7172, 0xECD2, + 0x7173, 0xECCE, 0x7174, 0x9FB1, 0x7175, 0x9FB2, 0x7176, 0x9FB3, 0x7177, 0x9FB4, 0x7178, 0xECD4, 0x7179, 0x9FB5, 0x717A, 0xECD5, + 0x717B, 0x9FB6, 0x717C, 0x9FB7, 0x717D, 0xC9BF, 0x717E, 0x9FB8, 0x717F, 0x9FB9, 0x7180, 0x9FBA, 0x7181, 0x9FBB, 0x7182, 0x9FBC, + 0x7183, 0x9FBD, 0x7184, 0xCFA8, 0x7185, 0x9FBE, 0x7186, 0x9FBF, 0x7187, 0x9FC0, 0x7188, 0x9FC1, 0x7189, 0x9FC2, 0x718A, 0xD0DC, + 0x718B, 0x9FC3, 0x718C, 0x9FC4, 0x718D, 0x9FC5, 0x718E, 0x9FC6, 0x718F, 0xD1AC, 0x7190, 0x9FC7, 0x7191, 0x9FC8, 0x7192, 0x9FC9, + 0x7193, 0x9FCA, 0x7194, 0xC8DB, 0x7195, 0x9FCB, 0x7196, 0x9FCC, 0x7197, 0x9FCD, 0x7198, 0xECD6, 0x7199, 0xCEF5, 0x719A, 0x9FCE, + 0x719B, 0x9FCF, 0x719C, 0x9FD0, 0x719D, 0x9FD1, 0x719E, 0x9FD2, 0x719F, 0xCAEC, 0x71A0, 0xECDA, 0x71A1, 0x9FD3, 0x71A2, 0x9FD4, + 0x71A3, 0x9FD5, 0x71A4, 0x9FD6, 0x71A5, 0x9FD7, 0x71A6, 0x9FD8, 0x71A7, 0x9FD9, 0x71A8, 0xECD9, 0x71A9, 0x9FDA, 0x71AA, 0x9FDB, + 0x71AB, 0x9FDC, 0x71AC, 0xB0BE, 0x71AD, 0x9FDD, 0x71AE, 0x9FDE, 0x71AF, 0x9FDF, 0x71B0, 0x9FE0, 0x71B1, 0x9FE1, 0x71B2, 0x9FE2, + 0x71B3, 0xECD7, 0x71B4, 0x9FE3, 0x71B5, 0xECD8, 0x71B6, 0x9FE4, 0x71B7, 0x9FE5, 0x71B8, 0x9FE6, 0x71B9, 0xECE4, 0x71BA, 0x9FE7, + 0x71BB, 0x9FE8, 0x71BC, 0x9FE9, 0x71BD, 0x9FEA, 0x71BE, 0x9FEB, 0x71BF, 0x9FEC, 0x71C0, 0x9FED, 0x71C1, 0x9FEE, 0x71C2, 0x9FEF, + 0x71C3, 0xC8BC, 0x71C4, 0x9FF0, 0x71C5, 0x9FF1, 0x71C6, 0x9FF2, 0x71C7, 0x9FF3, 0x71C8, 0x9FF4, 0x71C9, 0x9FF5, 0x71CA, 0x9FF6, + 0x71CB, 0x9FF7, 0x71CC, 0x9FF8, 0x71CD, 0x9FF9, 0x71CE, 0xC1C7, 0x71CF, 0x9FFA, 0x71D0, 0x9FFB, 0x71D1, 0x9FFC, 0x71D2, 0x9FFD, + 0x71D3, 0x9FFE, 0x71D4, 0xECDC, 0x71D5, 0xD1E0, 0x71D6, 0xA040, 0x71D7, 0xA041, 0x71D8, 0xA042, 0x71D9, 0xA043, 0x71DA, 0xA044, + 0x71DB, 0xA045, 0x71DC, 0xA046, 0x71DD, 0xA047, 0x71DE, 0xA048, 0x71DF, 0xA049, 0x71E0, 0xECDB, 0x71E1, 0xA04A, 0x71E2, 0xA04B, + 0x71E3, 0xA04C, 0x71E4, 0xA04D, 0x71E5, 0xD4EF, 0x71E6, 0xA04E, 0x71E7, 0xECDD, 0x71E8, 0xA04F, 0x71E9, 0xA050, 0x71EA, 0xA051, + 0x71EB, 0xA052, 0x71EC, 0xA053, 0x71ED, 0xA054, 0x71EE, 0xDBC6, 0x71EF, 0xA055, 0x71F0, 0xA056, 0x71F1, 0xA057, 0x71F2, 0xA058, + 0x71F3, 0xA059, 0x71F4, 0xA05A, 0x71F5, 0xA05B, 0x71F6, 0xA05C, 0x71F7, 0xA05D, 0x71F8, 0xA05E, 0x71F9, 0xECDE, 0x71FA, 0xA05F, + 0x71FB, 0xA060, 0x71FC, 0xA061, 0x71FD, 0xA062, 0x71FE, 0xA063, 0x71FF, 0xA064, 0x7200, 0xA065, 0x7201, 0xA066, 0x7202, 0xA067, + 0x7203, 0xA068, 0x7204, 0xA069, 0x7205, 0xA06A, 0x7206, 0xB1AC, 0x7207, 0xA06B, 0x7208, 0xA06C, 0x7209, 0xA06D, 0x720A, 0xA06E, + 0x720B, 0xA06F, 0x720C, 0xA070, 0x720D, 0xA071, 0x720E, 0xA072, 0x720F, 0xA073, 0x7210, 0xA074, 0x7211, 0xA075, 0x7212, 0xA076, + 0x7213, 0xA077, 0x7214, 0xA078, 0x7215, 0xA079, 0x7216, 0xA07A, 0x7217, 0xA07B, 0x7218, 0xA07C, 0x7219, 0xA07D, 0x721A, 0xA07E, + 0x721B, 0xA080, 0x721C, 0xA081, 0x721D, 0xECDF, 0x721E, 0xA082, 0x721F, 0xA083, 0x7220, 0xA084, 0x7221, 0xA085, 0x7222, 0xA086, + 0x7223, 0xA087, 0x7224, 0xA088, 0x7225, 0xA089, 0x7226, 0xA08A, 0x7227, 0xA08B, 0x7228, 0xECE0, 0x7229, 0xA08C, 0x722A, 0xD7A6, + 0x722B, 0xA08D, 0x722C, 0xC5C0, 0x722D, 0xA08E, 0x722E, 0xA08F, 0x722F, 0xA090, 0x7230, 0xEBBC, 0x7231, 0xB0AE, 0x7232, 0xA091, + 0x7233, 0xA092, 0x7234, 0xA093, 0x7235, 0xBEF4, 0x7236, 0xB8B8, 0x7237, 0xD2AF, 0x7238, 0xB0D6, 0x7239, 0xB5F9, 0x723A, 0xA094, + 0x723B, 0xD8B3, 0x723C, 0xA095, 0x723D, 0xCBAC, 0x723E, 0xA096, 0x723F, 0xE3DD, 0x7240, 0xA097, 0x7241, 0xA098, 0x7242, 0xA099, + 0x7243, 0xA09A, 0x7244, 0xA09B, 0x7245, 0xA09C, 0x7246, 0xA09D, 0x7247, 0xC6AC, 0x7248, 0xB0E6, 0x7249, 0xA09E, 0x724A, 0xA09F, + 0x724B, 0xA0A0, 0x724C, 0xC5C6, 0x724D, 0xEBB9, 0x724E, 0xA0A1, 0x724F, 0xA0A2, 0x7250, 0xA0A3, 0x7251, 0xA0A4, 0x7252, 0xEBBA, + 0x7253, 0xA0A5, 0x7254, 0xA0A6, 0x7255, 0xA0A7, 0x7256, 0xEBBB, 0x7257, 0xA0A8, 0x7258, 0xA0A9, 0x7259, 0xD1C0, 0x725A, 0xA0AA, + 0x725B, 0xC5A3, 0x725C, 0xA0AB, 0x725D, 0xEAF2, 0x725E, 0xA0AC, 0x725F, 0xC4B2, 0x7260, 0xA0AD, 0x7261, 0xC4B5, 0x7262, 0xC0CE, + 0x7263, 0xA0AE, 0x7264, 0xA0AF, 0x7265, 0xA0B0, 0x7266, 0xEAF3, 0x7267, 0xC4C1, 0x7268, 0xA0B1, 0x7269, 0xCEEF, 0x726A, 0xA0B2, + 0x726B, 0xA0B3, 0x726C, 0xA0B4, 0x726D, 0xA0B5, 0x726E, 0xEAF0, 0x726F, 0xEAF4, 0x7270, 0xA0B6, 0x7271, 0xA0B7, 0x7272, 0xC9FC, + 0x7273, 0xA0B8, 0x7274, 0xA0B9, 0x7275, 0xC7A3, 0x7276, 0xA0BA, 0x7277, 0xA0BB, 0x7278, 0xA0BC, 0x7279, 0xCCD8, 0x727A, 0xCEFE, + 0x727B, 0xA0BD, 0x727C, 0xA0BE, 0x727D, 0xA0BF, 0x727E, 0xEAF5, 0x727F, 0xEAF6, 0x7280, 0xCFAC, 0x7281, 0xC0E7, 0x7282, 0xA0C0, + 0x7283, 0xA0C1, 0x7284, 0xEAF7, 0x7285, 0xA0C2, 0x7286, 0xA0C3, 0x7287, 0xA0C4, 0x7288, 0xA0C5, 0x7289, 0xA0C6, 0x728A, 0xB6BF, + 0x728B, 0xEAF8, 0x728C, 0xA0C7, 0x728D, 0xEAF9, 0x728E, 0xA0C8, 0x728F, 0xEAFA, 0x7290, 0xA0C9, 0x7291, 0xA0CA, 0x7292, 0xEAFB, + 0x7293, 0xA0CB, 0x7294, 0xA0CC, 0x7295, 0xA0CD, 0x7296, 0xA0CE, 0x7297, 0xA0CF, 0x7298, 0xA0D0, 0x7299, 0xA0D1, 0x729A, 0xA0D2, + 0x729B, 0xA0D3, 0x729C, 0xA0D4, 0x729D, 0xA0D5, 0x729E, 0xA0D6, 0x729F, 0xEAF1, 0x72A0, 0xA0D7, 0x72A1, 0xA0D8, 0x72A2, 0xA0D9, + 0x72A3, 0xA0DA, 0x72A4, 0xA0DB, 0x72A5, 0xA0DC, 0x72A6, 0xA0DD, 0x72A7, 0xA0DE, 0x72A8, 0xA0DF, 0x72A9, 0xA0E0, 0x72AA, 0xA0E1, + 0x72AB, 0xA0E2, 0x72AC, 0xC8AE, 0x72AD, 0xE1EB, 0x72AE, 0xA0E3, 0x72AF, 0xB7B8, 0x72B0, 0xE1EC, 0x72B1, 0xA0E4, 0x72B2, 0xA0E5, + 0x72B3, 0xA0E6, 0x72B4, 0xE1ED, 0x72B5, 0xA0E7, 0x72B6, 0xD7B4, 0x72B7, 0xE1EE, 0x72B8, 0xE1EF, 0x72B9, 0xD3CC, 0x72BA, 0xA0E8, + 0x72BB, 0xA0E9, 0x72BC, 0xA0EA, 0x72BD, 0xA0EB, 0x72BE, 0xA0EC, 0x72BF, 0xA0ED, 0x72C0, 0xA0EE, 0x72C1, 0xE1F1, 0x72C2, 0xBFF1, + 0x72C3, 0xE1F0, 0x72C4, 0xB5D2, 0x72C5, 0xA0EF, 0x72C6, 0xA0F0, 0x72C7, 0xA0F1, 0x72C8, 0xB1B7, 0x72C9, 0xA0F2, 0x72CA, 0xA0F3, + 0x72CB, 0xA0F4, 0x72CC, 0xA0F5, 0x72CD, 0xE1F3, 0x72CE, 0xE1F2, 0x72CF, 0xA0F6, 0x72D0, 0xBAFC, 0x72D1, 0xA0F7, 0x72D2, 0xE1F4, + 0x72D3, 0xA0F8, 0x72D4, 0xA0F9, 0x72D5, 0xA0FA, 0x72D6, 0xA0FB, 0x72D7, 0xB9B7, 0x72D8, 0xA0FC, 0x72D9, 0xBED1, 0x72DA, 0xA0FD, + 0x72DB, 0xA0FE, 0x72DC, 0xAA40, 0x72DD, 0xAA41, 0x72DE, 0xC4FC, 0x72DF, 0xAA42, 0x72E0, 0xBADD, 0x72E1, 0xBDC6, 0x72E2, 0xAA43, + 0x72E3, 0xAA44, 0x72E4, 0xAA45, 0x72E5, 0xAA46, 0x72E6, 0xAA47, 0x72E7, 0xAA48, 0x72E8, 0xE1F5, 0x72E9, 0xE1F7, 0x72EA, 0xAA49, + 0x72EB, 0xAA4A, 0x72EC, 0xB6C0, 0x72ED, 0xCFC1, 0x72EE, 0xCAA8, 0x72EF, 0xE1F6, 0x72F0, 0xD5F8, 0x72F1, 0xD3FC, 0x72F2, 0xE1F8, + 0x72F3, 0xE1FC, 0x72F4, 0xE1F9, 0x72F5, 0xAA4B, 0x72F6, 0xAA4C, 0x72F7, 0xE1FA, 0x72F8, 0xC0EA, 0x72F9, 0xAA4D, 0x72FA, 0xE1FE, + 0x72FB, 0xE2A1, 0x72FC, 0xC0C7, 0x72FD, 0xAA4E, 0x72FE, 0xAA4F, 0x72FF, 0xAA50, 0x7300, 0xAA51, 0x7301, 0xE1FB, 0x7302, 0xAA52, + 0x7303, 0xE1FD, 0x7304, 0xAA53, 0x7305, 0xAA54, 0x7306, 0xAA55, 0x7307, 0xAA56, 0x7308, 0xAA57, 0x7309, 0xAA58, 0x730A, 0xE2A5, + 0x730B, 0xAA59, 0x730C, 0xAA5A, 0x730D, 0xAA5B, 0x730E, 0xC1D4, 0x730F, 0xAA5C, 0x7310, 0xAA5D, 0x7311, 0xAA5E, 0x7312, 0xAA5F, + 0x7313, 0xE2A3, 0x7314, 0xAA60, 0x7315, 0xE2A8, 0x7316, 0xB2FE, 0x7317, 0xE2A2, 0x7318, 0xAA61, 0x7319, 0xAA62, 0x731A, 0xAA63, + 0x731B, 0xC3CD, 0x731C, 0xB2C2, 0x731D, 0xE2A7, 0x731E, 0xE2A6, 0x731F, 0xAA64, 0x7320, 0xAA65, 0x7321, 0xE2A4, 0x7322, 0xE2A9, + 0x7323, 0xAA66, 0x7324, 0xAA67, 0x7325, 0xE2AB, 0x7326, 0xAA68, 0x7327, 0xAA69, 0x7328, 0xAA6A, 0x7329, 0xD0C9, 0x732A, 0xD6ED, + 0x732B, 0xC3A8, 0x732C, 0xE2AC, 0x732D, 0xAA6B, 0x732E, 0xCFD7, 0x732F, 0xAA6C, 0x7330, 0xAA6D, 0x7331, 0xE2AE, 0x7332, 0xAA6E, + 0x7333, 0xAA6F, 0x7334, 0xBAEF, 0x7335, 0xAA70, 0x7336, 0xAA71, 0x7337, 0xE9E0, 0x7338, 0xE2AD, 0x7339, 0xE2AA, 0x733A, 0xAA72, + 0x733B, 0xAA73, 0x733C, 0xAA74, 0x733D, 0xAA75, 0x733E, 0xBBAB, 0x733F, 0xD4B3, 0x7340, 0xAA76, 0x7341, 0xAA77, 0x7342, 0xAA78, + 0x7343, 0xAA79, 0x7344, 0xAA7A, 0x7345, 0xAA7B, 0x7346, 0xAA7C, 0x7347, 0xAA7D, 0x7348, 0xAA7E, 0x7349, 0xAA80, 0x734A, 0xAA81, + 0x734B, 0xAA82, 0x734C, 0xAA83, 0x734D, 0xE2B0, 0x734E, 0xAA84, 0x734F, 0xAA85, 0x7350, 0xE2AF, 0x7351, 0xAA86, 0x7352, 0xE9E1, + 0x7353, 0xAA87, 0x7354, 0xAA88, 0x7355, 0xAA89, 0x7356, 0xAA8A, 0x7357, 0xE2B1, 0x7358, 0xAA8B, 0x7359, 0xAA8C, 0x735A, 0xAA8D, + 0x735B, 0xAA8E, 0x735C, 0xAA8F, 0x735D, 0xAA90, 0x735E, 0xAA91, 0x735F, 0xAA92, 0x7360, 0xE2B2, 0x7361, 0xAA93, 0x7362, 0xAA94, + 0x7363, 0xAA95, 0x7364, 0xAA96, 0x7365, 0xAA97, 0x7366, 0xAA98, 0x7367, 0xAA99, 0x7368, 0xAA9A, 0x7369, 0xAA9B, 0x736A, 0xAA9C, + 0x736B, 0xAA9D, 0x736C, 0xE2B3, 0x736D, 0xCCA1, 0x736E, 0xAA9E, 0x736F, 0xE2B4, 0x7370, 0xAA9F, 0x7371, 0xAAA0, 0x7372, 0xAB40, + 0x7373, 0xAB41, 0x7374, 0xAB42, 0x7375, 0xAB43, 0x7376, 0xAB44, 0x7377, 0xAB45, 0x7378, 0xAB46, 0x7379, 0xAB47, 0x737A, 0xAB48, + 0x737B, 0xAB49, 0x737C, 0xAB4A, 0x737D, 0xAB4B, 0x737E, 0xE2B5, 0x737F, 0xAB4C, 0x7380, 0xAB4D, 0x7381, 0xAB4E, 0x7382, 0xAB4F, + 0x7383, 0xAB50, 0x7384, 0xD0FE, 0x7385, 0xAB51, 0x7386, 0xAB52, 0x7387, 0xC2CA, 0x7388, 0xAB53, 0x7389, 0xD3F1, 0x738A, 0xAB54, + 0x738B, 0xCDF5, 0x738C, 0xAB55, 0x738D, 0xAB56, 0x738E, 0xE7E0, 0x738F, 0xAB57, 0x7390, 0xAB58, 0x7391, 0xE7E1, 0x7392, 0xAB59, + 0x7393, 0xAB5A, 0x7394, 0xAB5B, 0x7395, 0xAB5C, 0x7396, 0xBEC1, 0x7397, 0xAB5D, 0x7398, 0xAB5E, 0x7399, 0xAB5F, 0x739A, 0xAB60, + 0x739B, 0xC2EA, 0x739C, 0xAB61, 0x739D, 0xAB62, 0x739E, 0xAB63, 0x739F, 0xE7E4, 0x73A0, 0xAB64, 0x73A1, 0xAB65, 0x73A2, 0xE7E3, + 0x73A3, 0xAB66, 0x73A4, 0xAB67, 0x73A5, 0xAB68, 0x73A6, 0xAB69, 0x73A7, 0xAB6A, 0x73A8, 0xAB6B, 0x73A9, 0xCDE6, 0x73AA, 0xAB6C, + 0x73AB, 0xC3B5, 0x73AC, 0xAB6D, 0x73AD, 0xAB6E, 0x73AE, 0xE7E2, 0x73AF, 0xBBB7, 0x73B0, 0xCFD6, 0x73B1, 0xAB6F, 0x73B2, 0xC1E1, + 0x73B3, 0xE7E9, 0x73B4, 0xAB70, 0x73B5, 0xAB71, 0x73B6, 0xAB72, 0x73B7, 0xE7E8, 0x73B8, 0xAB73, 0x73B9, 0xAB74, 0x73BA, 0xE7F4, + 0x73BB, 0xB2A3, 0x73BC, 0xAB75, 0x73BD, 0xAB76, 0x73BE, 0xAB77, 0x73BF, 0xAB78, 0x73C0, 0xE7EA, 0x73C1, 0xAB79, 0x73C2, 0xE7E6, + 0x73C3, 0xAB7A, 0x73C4, 0xAB7B, 0x73C5, 0xAB7C, 0x73C6, 0xAB7D, 0x73C7, 0xAB7E, 0x73C8, 0xE7EC, 0x73C9, 0xE7EB, 0x73CA, 0xC9BA, + 0x73CB, 0xAB80, 0x73CC, 0xAB81, 0x73CD, 0xD5E4, 0x73CE, 0xAB82, 0x73CF, 0xE7E5, 0x73D0, 0xB7A9, 0x73D1, 0xE7E7, 0x73D2, 0xAB83, + 0x73D3, 0xAB84, 0x73D4, 0xAB85, 0x73D5, 0xAB86, 0x73D6, 0xAB87, 0x73D7, 0xAB88, 0x73D8, 0xAB89, 0x73D9, 0xE7EE, 0x73DA, 0xAB8A, + 0x73DB, 0xAB8B, 0x73DC, 0xAB8C, 0x73DD, 0xAB8D, 0x73DE, 0xE7F3, 0x73DF, 0xAB8E, 0x73E0, 0xD6E9, 0x73E1, 0xAB8F, 0x73E2, 0xAB90, + 0x73E3, 0xAB91, 0x73E4, 0xAB92, 0x73E5, 0xE7ED, 0x73E6, 0xAB93, 0x73E7, 0xE7F2, 0x73E8, 0xAB94, 0x73E9, 0xE7F1, 0x73EA, 0xAB95, + 0x73EB, 0xAB96, 0x73EC, 0xAB97, 0x73ED, 0xB0E0, 0x73EE, 0xAB98, 0x73EF, 0xAB99, 0x73F0, 0xAB9A, 0x73F1, 0xAB9B, 0x73F2, 0xE7F5, + 0x73F3, 0xAB9C, 0x73F4, 0xAB9D, 0x73F5, 0xAB9E, 0x73F6, 0xAB9F, 0x73F7, 0xABA0, 0x73F8, 0xAC40, 0x73F9, 0xAC41, 0x73FA, 0xAC42, + 0x73FB, 0xAC43, 0x73FC, 0xAC44, 0x73FD, 0xAC45, 0x73FE, 0xAC46, 0x73FF, 0xAC47, 0x7400, 0xAC48, 0x7401, 0xAC49, 0x7402, 0xAC4A, + 0x7403, 0xC7F2, 0x7404, 0xAC4B, 0x7405, 0xC0C5, 0x7406, 0xC0ED, 0x7407, 0xAC4C, 0x7408, 0xAC4D, 0x7409, 0xC1F0, 0x740A, 0xE7F0, + 0x740B, 0xAC4E, 0x740C, 0xAC4F, 0x740D, 0xAC50, 0x740E, 0xAC51, 0x740F, 0xE7F6, 0x7410, 0xCBF6, 0x7411, 0xAC52, 0x7412, 0xAC53, + 0x7413, 0xAC54, 0x7414, 0xAC55, 0x7415, 0xAC56, 0x7416, 0xAC57, 0x7417, 0xAC58, 0x7418, 0xAC59, 0x7419, 0xAC5A, 0x741A, 0xE8A2, + 0x741B, 0xE8A1, 0x741C, 0xAC5B, 0x741D, 0xAC5C, 0x741E, 0xAC5D, 0x741F, 0xAC5E, 0x7420, 0xAC5F, 0x7421, 0xAC60, 0x7422, 0xD7C1, + 0x7423, 0xAC61, 0x7424, 0xAC62, 0x7425, 0xE7FA, 0x7426, 0xE7F9, 0x7427, 0xAC63, 0x7428, 0xE7FB, 0x7429, 0xAC64, 0x742A, 0xE7F7, + 0x742B, 0xAC65, 0x742C, 0xE7FE, 0x742D, 0xAC66, 0x742E, 0xE7FD, 0x742F, 0xAC67, 0x7430, 0xE7FC, 0x7431, 0xAC68, 0x7432, 0xAC69, + 0x7433, 0xC1D5, 0x7434, 0xC7D9, 0x7435, 0xC5FD, 0x7436, 0xC5C3, 0x7437, 0xAC6A, 0x7438, 0xAC6B, 0x7439, 0xAC6C, 0x743A, 0xAC6D, + 0x743B, 0xAC6E, 0x743C, 0xC7ED, 0x743D, 0xAC6F, 0x743E, 0xAC70, 0x743F, 0xAC71, 0x7440, 0xAC72, 0x7441, 0xE8A3, 0x7442, 0xAC73, + 0x7443, 0xAC74, 0x7444, 0xAC75, 0x7445, 0xAC76, 0x7446, 0xAC77, 0x7447, 0xAC78, 0x7448, 0xAC79, 0x7449, 0xAC7A, 0x744A, 0xAC7B, + 0x744B, 0xAC7C, 0x744C, 0xAC7D, 0x744D, 0xAC7E, 0x744E, 0xAC80, 0x744F, 0xAC81, 0x7450, 0xAC82, 0x7451, 0xAC83, 0x7452, 0xAC84, + 0x7453, 0xAC85, 0x7454, 0xAC86, 0x7455, 0xE8A6, 0x7456, 0xAC87, 0x7457, 0xE8A5, 0x7458, 0xAC88, 0x7459, 0xE8A7, 0x745A, 0xBAF7, + 0x745B, 0xE7F8, 0x745C, 0xE8A4, 0x745D, 0xAC89, 0x745E, 0xC8F0, 0x745F, 0xC9AA, 0x7460, 0xAC8A, 0x7461, 0xAC8B, 0x7462, 0xAC8C, + 0x7463, 0xAC8D, 0x7464, 0xAC8E, 0x7465, 0xAC8F, 0x7466, 0xAC90, 0x7467, 0xAC91, 0x7468, 0xAC92, 0x7469, 0xAC93, 0x746A, 0xAC94, + 0x746B, 0xAC95, 0x746C, 0xAC96, 0x746D, 0xE8A9, 0x746E, 0xAC97, 0x746F, 0xAC98, 0x7470, 0xB9E5, 0x7471, 0xAC99, 0x7472, 0xAC9A, + 0x7473, 0xAC9B, 0x7474, 0xAC9C, 0x7475, 0xAC9D, 0x7476, 0xD1FE, 0x7477, 0xE8A8, 0x7478, 0xAC9E, 0x7479, 0xAC9F, 0x747A, 0xACA0, + 0x747B, 0xAD40, 0x747C, 0xAD41, 0x747D, 0xAD42, 0x747E, 0xE8AA, 0x747F, 0xAD43, 0x7480, 0xE8AD, 0x7481, 0xE8AE, 0x7482, 0xAD44, + 0x7483, 0xC1A7, 0x7484, 0xAD45, 0x7485, 0xAD46, 0x7486, 0xAD47, 0x7487, 0xE8AF, 0x7488, 0xAD48, 0x7489, 0xAD49, 0x748A, 0xAD4A, + 0x748B, 0xE8B0, 0x748C, 0xAD4B, 0x748D, 0xAD4C, 0x748E, 0xE8AC, 0x748F, 0xAD4D, 0x7490, 0xE8B4, 0x7491, 0xAD4E, 0x7492, 0xAD4F, + 0x7493, 0xAD50, 0x7494, 0xAD51, 0x7495, 0xAD52, 0x7496, 0xAD53, 0x7497, 0xAD54, 0x7498, 0xAD55, 0x7499, 0xAD56, 0x749A, 0xAD57, + 0x749B, 0xAD58, 0x749C, 0xE8AB, 0x749D, 0xAD59, 0x749E, 0xE8B1, 0x749F, 0xAD5A, 0x74A0, 0xAD5B, 0x74A1, 0xAD5C, 0x74A2, 0xAD5D, + 0x74A3, 0xAD5E, 0x74A4, 0xAD5F, 0x74A5, 0xAD60, 0x74A6, 0xAD61, 0x74A7, 0xE8B5, 0x74A8, 0xE8B2, 0x74A9, 0xE8B3, 0x74AA, 0xAD62, + 0x74AB, 0xAD63, 0x74AC, 0xAD64, 0x74AD, 0xAD65, 0x74AE, 0xAD66, 0x74AF, 0xAD67, 0x74B0, 0xAD68, 0x74B1, 0xAD69, 0x74B2, 0xAD6A, + 0x74B3, 0xAD6B, 0x74B4, 0xAD6C, 0x74B5, 0xAD6D, 0x74B6, 0xAD6E, 0x74B7, 0xAD6F, 0x74B8, 0xAD70, 0x74B9, 0xAD71, 0x74BA, 0xE8B7, + 0x74BB, 0xAD72, 0x74BC, 0xAD73, 0x74BD, 0xAD74, 0x74BE, 0xAD75, 0x74BF, 0xAD76, 0x74C0, 0xAD77, 0x74C1, 0xAD78, 0x74C2, 0xAD79, + 0x74C3, 0xAD7A, 0x74C4, 0xAD7B, 0x74C5, 0xAD7C, 0x74C6, 0xAD7D, 0x74C7, 0xAD7E, 0x74C8, 0xAD80, 0x74C9, 0xAD81, 0x74CA, 0xAD82, + 0x74CB, 0xAD83, 0x74CC, 0xAD84, 0x74CD, 0xAD85, 0x74CE, 0xAD86, 0x74CF, 0xAD87, 0x74D0, 0xAD88, 0x74D1, 0xAD89, 0x74D2, 0xE8B6, + 0x74D3, 0xAD8A, 0x74D4, 0xAD8B, 0x74D5, 0xAD8C, 0x74D6, 0xAD8D, 0x74D7, 0xAD8E, 0x74D8, 0xAD8F, 0x74D9, 0xAD90, 0x74DA, 0xAD91, + 0x74DB, 0xAD92, 0x74DC, 0xB9CF, 0x74DD, 0xAD93, 0x74DE, 0xF0AC, 0x74DF, 0xAD94, 0x74E0, 0xF0AD, 0x74E1, 0xAD95, 0x74E2, 0xC6B0, + 0x74E3, 0xB0EA, 0x74E4, 0xC8BF, 0x74E5, 0xAD96, 0x74E6, 0xCDDF, 0x74E7, 0xAD97, 0x74E8, 0xAD98, 0x74E9, 0xAD99, 0x74EA, 0xAD9A, + 0x74EB, 0xAD9B, 0x74EC, 0xAD9C, 0x74ED, 0xAD9D, 0x74EE, 0xCECD, 0x74EF, 0xEAB1, 0x74F0, 0xAD9E, 0x74F1, 0xAD9F, 0x74F2, 0xADA0, + 0x74F3, 0xAE40, 0x74F4, 0xEAB2, 0x74F5, 0xAE41, 0x74F6, 0xC6BF, 0x74F7, 0xB4C9, 0x74F8, 0xAE42, 0x74F9, 0xAE43, 0x74FA, 0xAE44, + 0x74FB, 0xAE45, 0x74FC, 0xAE46, 0x74FD, 0xAE47, 0x74FE, 0xAE48, 0x74FF, 0xEAB3, 0x7500, 0xAE49, 0x7501, 0xAE4A, 0x7502, 0xAE4B, + 0x7503, 0xAE4C, 0x7504, 0xD5E7, 0x7505, 0xAE4D, 0x7506, 0xAE4E, 0x7507, 0xAE4F, 0x7508, 0xAE50, 0x7509, 0xAE51, 0x750A, 0xAE52, + 0x750B, 0xAE53, 0x750C, 0xAE54, 0x750D, 0xDDF9, 0x750E, 0xAE55, 0x750F, 0xEAB4, 0x7510, 0xAE56, 0x7511, 0xEAB5, 0x7512, 0xAE57, + 0x7513, 0xEAB6, 0x7514, 0xAE58, 0x7515, 0xAE59, 0x7516, 0xAE5A, 0x7517, 0xAE5B, 0x7518, 0xB8CA, 0x7519, 0xDFB0, 0x751A, 0xC9F5, + 0x751B, 0xAE5C, 0x751C, 0xCCF0, 0x751D, 0xAE5D, 0x751E, 0xAE5E, 0x751F, 0xC9FA, 0x7520, 0xAE5F, 0x7521, 0xAE60, 0x7522, 0xAE61, + 0x7523, 0xAE62, 0x7524, 0xAE63, 0x7525, 0xC9FB, 0x7526, 0xAE64, 0x7527, 0xAE65, 0x7528, 0xD3C3, 0x7529, 0xCBA6, 0x752A, 0xAE66, + 0x752B, 0xB8A6, 0x752C, 0xF0AE, 0x752D, 0xB1C2, 0x752E, 0xAE67, 0x752F, 0xE5B8, 0x7530, 0xCCEF, 0x7531, 0xD3C9, 0x7532, 0xBCD7, + 0x7533, 0xC9EA, 0x7534, 0xAE68, 0x7535, 0xB5E7, 0x7536, 0xAE69, 0x7537, 0xC4D0, 0x7538, 0xB5E9, 0x7539, 0xAE6A, 0x753A, 0xEEAE, + 0x753B, 0xBBAD, 0x753C, 0xAE6B, 0x753D, 0xAE6C, 0x753E, 0xE7DE, 0x753F, 0xAE6D, 0x7540, 0xEEAF, 0x7541, 0xAE6E, 0x7542, 0xAE6F, + 0x7543, 0xAE70, 0x7544, 0xAE71, 0x7545, 0xB3A9, 0x7546, 0xAE72, 0x7547, 0xAE73, 0x7548, 0xEEB2, 0x7549, 0xAE74, 0x754A, 0xAE75, + 0x754B, 0xEEB1, 0x754C, 0xBDE7, 0x754D, 0xAE76, 0x754E, 0xEEB0, 0x754F, 0xCEB7, 0x7550, 0xAE77, 0x7551, 0xAE78, 0x7552, 0xAE79, + 0x7553, 0xAE7A, 0x7554, 0xC5CF, 0x7555, 0xAE7B, 0x7556, 0xAE7C, 0x7557, 0xAE7D, 0x7558, 0xAE7E, 0x7559, 0xC1F4, 0x755A, 0xDBCE, + 0x755B, 0xEEB3, 0x755C, 0xD0F3, 0x755D, 0xAE80, 0x755E, 0xAE81, 0x755F, 0xAE82, 0x7560, 0xAE83, 0x7561, 0xAE84, 0x7562, 0xAE85, + 0x7563, 0xAE86, 0x7564, 0xAE87, 0x7565, 0xC2D4, 0x7566, 0xC6E8, 0x7567, 0xAE88, 0x7568, 0xAE89, 0x7569, 0xAE8A, 0x756A, 0xB7AC, + 0x756B, 0xAE8B, 0x756C, 0xAE8C, 0x756D, 0xAE8D, 0x756E, 0xAE8E, 0x756F, 0xAE8F, 0x7570, 0xAE90, 0x7571, 0xAE91, 0x7572, 0xEEB4, + 0x7573, 0xAE92, 0x7574, 0xB3EB, 0x7575, 0xAE93, 0x7576, 0xAE94, 0x7577, 0xAE95, 0x7578, 0xBBFB, 0x7579, 0xEEB5, 0x757A, 0xAE96, + 0x757B, 0xAE97, 0x757C, 0xAE98, 0x757D, 0xAE99, 0x757E, 0xAE9A, 0x757F, 0xE7DC, 0x7580, 0xAE9B, 0x7581, 0xAE9C, 0x7582, 0xAE9D, + 0x7583, 0xEEB6, 0x7584, 0xAE9E, 0x7585, 0xAE9F, 0x7586, 0xBDAE, 0x7587, 0xAEA0, 0x7588, 0xAF40, 0x7589, 0xAF41, 0x758A, 0xAF42, + 0x758B, 0xF1E2, 0x758C, 0xAF43, 0x758D, 0xAF44, 0x758E, 0xAF45, 0x758F, 0xCAE8, 0x7590, 0xAF46, 0x7591, 0xD2C9, 0x7592, 0xF0DA, + 0x7593, 0xAF47, 0x7594, 0xF0DB, 0x7595, 0xAF48, 0x7596, 0xF0DC, 0x7597, 0xC1C6, 0x7598, 0xAF49, 0x7599, 0xB8ED, 0x759A, 0xBECE, + 0x759B, 0xAF4A, 0x759C, 0xAF4B, 0x759D, 0xF0DE, 0x759E, 0xAF4C, 0x759F, 0xC5B1, 0x75A0, 0xF0DD, 0x75A1, 0xD1F1, 0x75A2, 0xAF4D, + 0x75A3, 0xF0E0, 0x75A4, 0xB0CC, 0x75A5, 0xBDEA, 0x75A6, 0xAF4E, 0x75A7, 0xAF4F, 0x75A8, 0xAF50, 0x75A9, 0xAF51, 0x75AA, 0xAF52, + 0x75AB, 0xD2DF, 0x75AC, 0xF0DF, 0x75AD, 0xAF53, 0x75AE, 0xB4AF, 0x75AF, 0xB7E8, 0x75B0, 0xF0E6, 0x75B1, 0xF0E5, 0x75B2, 0xC6A3, + 0x75B3, 0xF0E1, 0x75B4, 0xF0E2, 0x75B5, 0xB4C3, 0x75B6, 0xAF54, 0x75B7, 0xAF55, 0x75B8, 0xF0E3, 0x75B9, 0xD5EE, 0x75BA, 0xAF56, + 0x75BB, 0xAF57, 0x75BC, 0xCCDB, 0x75BD, 0xBED2, 0x75BE, 0xBCB2, 0x75BF, 0xAF58, 0x75C0, 0xAF59, 0x75C1, 0xAF5A, 0x75C2, 0xF0E8, + 0x75C3, 0xF0E7, 0x75C4, 0xF0E4, 0x75C5, 0xB2A1, 0x75C6, 0xAF5B, 0x75C7, 0xD6A2, 0x75C8, 0xD3B8, 0x75C9, 0xBEB7, 0x75CA, 0xC8AC, + 0x75CB, 0xAF5C, 0x75CC, 0xAF5D, 0x75CD, 0xF0EA, 0x75CE, 0xAF5E, 0x75CF, 0xAF5F, 0x75D0, 0xAF60, 0x75D1, 0xAF61, 0x75D2, 0xD1F7, + 0x75D3, 0xAF62, 0x75D4, 0xD6CC, 0x75D5, 0xBADB, 0x75D6, 0xF0E9, 0x75D7, 0xAF63, 0x75D8, 0xB6BB, 0x75D9, 0xAF64, 0x75DA, 0xAF65, + 0x75DB, 0xCDB4, 0x75DC, 0xAF66, 0x75DD, 0xAF67, 0x75DE, 0xC6A6, 0x75DF, 0xAF68, 0x75E0, 0xAF69, 0x75E1, 0xAF6A, 0x75E2, 0xC1A1, + 0x75E3, 0xF0EB, 0x75E4, 0xF0EE, 0x75E5, 0xAF6B, 0x75E6, 0xF0ED, 0x75E7, 0xF0F0, 0x75E8, 0xF0EC, 0x75E9, 0xAF6C, 0x75EA, 0xBBBE, + 0x75EB, 0xF0EF, 0x75EC, 0xAF6D, 0x75ED, 0xAF6E, 0x75EE, 0xAF6F, 0x75EF, 0xAF70, 0x75F0, 0xCCB5, 0x75F1, 0xF0F2, 0x75F2, 0xAF71, + 0x75F3, 0xAF72, 0x75F4, 0xB3D5, 0x75F5, 0xAF73, 0x75F6, 0xAF74, 0x75F7, 0xAF75, 0x75F8, 0xAF76, 0x75F9, 0xB1D4, 0x75FA, 0xAF77, + 0x75FB, 0xAF78, 0x75FC, 0xF0F3, 0x75FD, 0xAF79, 0x75FE, 0xAF7A, 0x75FF, 0xF0F4, 0x7600, 0xF0F6, 0x7601, 0xB4E1, 0x7602, 0xAF7B, + 0x7603, 0xF0F1, 0x7604, 0xAF7C, 0x7605, 0xF0F7, 0x7606, 0xAF7D, 0x7607, 0xAF7E, 0x7608, 0xAF80, 0x7609, 0xAF81, 0x760A, 0xF0FA, + 0x760B, 0xAF82, 0x760C, 0xF0F8, 0x760D, 0xAF83, 0x760E, 0xAF84, 0x760F, 0xAF85, 0x7610, 0xF0F5, 0x7611, 0xAF86, 0x7612, 0xAF87, + 0x7613, 0xAF88, 0x7614, 0xAF89, 0x7615, 0xF0FD, 0x7616, 0xAF8A, 0x7617, 0xF0F9, 0x7618, 0xF0FC, 0x7619, 0xF0FE, 0x761A, 0xAF8B, + 0x761B, 0xF1A1, 0x761C, 0xAF8C, 0x761D, 0xAF8D, 0x761E, 0xAF8E, 0x761F, 0xCEC1, 0x7620, 0xF1A4, 0x7621, 0xAF8F, 0x7622, 0xF1A3, + 0x7623, 0xAF90, 0x7624, 0xC1F6, 0x7625, 0xF0FB, 0x7626, 0xCADD, 0x7627, 0xAF91, 0x7628, 0xAF92, 0x7629, 0xB4F1, 0x762A, 0xB1F1, + 0x762B, 0xCCB1, 0x762C, 0xAF93, 0x762D, 0xF1A6, 0x762E, 0xAF94, 0x762F, 0xAF95, 0x7630, 0xF1A7, 0x7631, 0xAF96, 0x7632, 0xAF97, + 0x7633, 0xF1AC, 0x7634, 0xD5CE, 0x7635, 0xF1A9, 0x7636, 0xAF98, 0x7637, 0xAF99, 0x7638, 0xC8B3, 0x7639, 0xAF9A, 0x763A, 0xAF9B, + 0x763B, 0xAF9C, 0x763C, 0xF1A2, 0x763D, 0xAF9D, 0x763E, 0xF1AB, 0x763F, 0xF1A8, 0x7640, 0xF1A5, 0x7641, 0xAF9E, 0x7642, 0xAF9F, + 0x7643, 0xF1AA, 0x7644, 0xAFA0, 0x7645, 0xB040, 0x7646, 0xB041, 0x7647, 0xB042, 0x7648, 0xB043, 0x7649, 0xB044, 0x764A, 0xB045, + 0x764B, 0xB046, 0x764C, 0xB0A9, 0x764D, 0xF1AD, 0x764E, 0xB047, 0x764F, 0xB048, 0x7650, 0xB049, 0x7651, 0xB04A, 0x7652, 0xB04B, + 0x7653, 0xB04C, 0x7654, 0xF1AF, 0x7655, 0xB04D, 0x7656, 0xF1B1, 0x7657, 0xB04E, 0x7658, 0xB04F, 0x7659, 0xB050, 0x765A, 0xB051, + 0x765B, 0xB052, 0x765C, 0xF1B0, 0x765D, 0xB053, 0x765E, 0xF1AE, 0x765F, 0xB054, 0x7660, 0xB055, 0x7661, 0xB056, 0x7662, 0xB057, + 0x7663, 0xD1A2, 0x7664, 0xB058, 0x7665, 0xB059, 0x7666, 0xB05A, 0x7667, 0xB05B, 0x7668, 0xB05C, 0x7669, 0xB05D, 0x766A, 0xB05E, + 0x766B, 0xF1B2, 0x766C, 0xB05F, 0x766D, 0xB060, 0x766E, 0xB061, 0x766F, 0xF1B3, 0x7670, 0xB062, 0x7671, 0xB063, 0x7672, 0xB064, + 0x7673, 0xB065, 0x7674, 0xB066, 0x7675, 0xB067, 0x7676, 0xB068, 0x7677, 0xB069, 0x7678, 0xB9EF, 0x7679, 0xB06A, 0x767A, 0xB06B, + 0x767B, 0xB5C7, 0x767C, 0xB06C, 0x767D, 0xB0D7, 0x767E, 0xB0D9, 0x767F, 0xB06D, 0x7680, 0xB06E, 0x7681, 0xB06F, 0x7682, 0xD4ED, + 0x7683, 0xB070, 0x7684, 0xB5C4, 0x7685, 0xB071, 0x7686, 0xBDD4, 0x7687, 0xBBCA, 0x7688, 0xF0A7, 0x7689, 0xB072, 0x768A, 0xB073, + 0x768B, 0xB8DE, 0x768C, 0xB074, 0x768D, 0xB075, 0x768E, 0xF0A8, 0x768F, 0xB076, 0x7690, 0xB077, 0x7691, 0xB0A8, 0x7692, 0xB078, + 0x7693, 0xF0A9, 0x7694, 0xB079, 0x7695, 0xB07A, 0x7696, 0xCDEE, 0x7697, 0xB07B, 0x7698, 0xB07C, 0x7699, 0xF0AA, 0x769A, 0xB07D, + 0x769B, 0xB07E, 0x769C, 0xB080, 0x769D, 0xB081, 0x769E, 0xB082, 0x769F, 0xB083, 0x76A0, 0xB084, 0x76A1, 0xB085, 0x76A2, 0xB086, + 0x76A3, 0xB087, 0x76A4, 0xF0AB, 0x76A5, 0xB088, 0x76A6, 0xB089, 0x76A7, 0xB08A, 0x76A8, 0xB08B, 0x76A9, 0xB08C, 0x76AA, 0xB08D, + 0x76AB, 0xB08E, 0x76AC, 0xB08F, 0x76AD, 0xB090, 0x76AE, 0xC6A4, 0x76AF, 0xB091, 0x76B0, 0xB092, 0x76B1, 0xD6E5, 0x76B2, 0xF1E4, + 0x76B3, 0xB093, 0x76B4, 0xF1E5, 0x76B5, 0xB094, 0x76B6, 0xB095, 0x76B7, 0xB096, 0x76B8, 0xB097, 0x76B9, 0xB098, 0x76BA, 0xB099, + 0x76BB, 0xB09A, 0x76BC, 0xB09B, 0x76BD, 0xB09C, 0x76BE, 0xB09D, 0x76BF, 0xC3F3, 0x76C0, 0xB09E, 0x76C1, 0xB09F, 0x76C2, 0xD3DB, + 0x76C3, 0xB0A0, 0x76C4, 0xB140, 0x76C5, 0xD6D1, 0x76C6, 0xC5E8, 0x76C7, 0xB141, 0x76C8, 0xD3AF, 0x76C9, 0xB142, 0x76CA, 0xD2E6, + 0x76CB, 0xB143, 0x76CC, 0xB144, 0x76CD, 0xEEC1, 0x76CE, 0xB0BB, 0x76CF, 0xD5B5, 0x76D0, 0xD1CE, 0x76D1, 0xBCE0, 0x76D2, 0xBAD0, + 0x76D3, 0xB145, 0x76D4, 0xBFF8, 0x76D5, 0xB146, 0x76D6, 0xB8C7, 0x76D7, 0xB5C1, 0x76D8, 0xC5CC, 0x76D9, 0xB147, 0x76DA, 0xB148, + 0x76DB, 0xCAA2, 0x76DC, 0xB149, 0x76DD, 0xB14A, 0x76DE, 0xB14B, 0x76DF, 0xC3CB, 0x76E0, 0xB14C, 0x76E1, 0xB14D, 0x76E2, 0xB14E, + 0x76E3, 0xB14F, 0x76E4, 0xB150, 0x76E5, 0xEEC2, 0x76E6, 0xB151, 0x76E7, 0xB152, 0x76E8, 0xB153, 0x76E9, 0xB154, 0x76EA, 0xB155, + 0x76EB, 0xB156, 0x76EC, 0xB157, 0x76ED, 0xB158, 0x76EE, 0xC4BF, 0x76EF, 0xB6A2, 0x76F0, 0xB159, 0x76F1, 0xEDEC, 0x76F2, 0xC3A4, + 0x76F3, 0xB15A, 0x76F4, 0xD6B1, 0x76F5, 0xB15B, 0x76F6, 0xB15C, 0x76F7, 0xB15D, 0x76F8, 0xCFE0, 0x76F9, 0xEDEF, 0x76FA, 0xB15E, + 0x76FB, 0xB15F, 0x76FC, 0xC5CE, 0x76FD, 0xB160, 0x76FE, 0xB6DC, 0x76FF, 0xB161, 0x7700, 0xB162, 0x7701, 0xCAA1, 0x7702, 0xB163, + 0x7703, 0xB164, 0x7704, 0xEDED, 0x7705, 0xB165, 0x7706, 0xB166, 0x7707, 0xEDF0, 0x7708, 0xEDF1, 0x7709, 0xC3BC, 0x770A, 0xB167, + 0x770B, 0xBFB4, 0x770C, 0xB168, 0x770D, 0xEDEE, 0x770E, 0xB169, 0x770F, 0xB16A, 0x7710, 0xB16B, 0x7711, 0xB16C, 0x7712, 0xB16D, + 0x7713, 0xB16E, 0x7714, 0xB16F, 0x7715, 0xB170, 0x7716, 0xB171, 0x7717, 0xB172, 0x7718, 0xB173, 0x7719, 0xEDF4, 0x771A, 0xEDF2, + 0x771B, 0xB174, 0x771C, 0xB175, 0x771D, 0xB176, 0x771E, 0xB177, 0x771F, 0xD5E6, 0x7720, 0xC3DF, 0x7721, 0xB178, 0x7722, 0xEDF3, + 0x7723, 0xB179, 0x7724, 0xB17A, 0x7725, 0xB17B, 0x7726, 0xEDF6, 0x7727, 0xB17C, 0x7728, 0xD5A3, 0x7729, 0xD1A3, 0x772A, 0xB17D, + 0x772B, 0xB17E, 0x772C, 0xB180, 0x772D, 0xEDF5, 0x772E, 0xB181, 0x772F, 0xC3D0, 0x7730, 0xB182, 0x7731, 0xB183, 0x7732, 0xB184, + 0x7733, 0xB185, 0x7734, 0xB186, 0x7735, 0xEDF7, 0x7736, 0xBFF4, 0x7737, 0xBEEC, 0x7738, 0xEDF8, 0x7739, 0xB187, 0x773A, 0xCCF7, + 0x773B, 0xB188, 0x773C, 0xD1DB, 0x773D, 0xB189, 0x773E, 0xB18A, 0x773F, 0xB18B, 0x7740, 0xD7C5, 0x7741, 0xD5F6, 0x7742, 0xB18C, + 0x7743, 0xEDFC, 0x7744, 0xB18D, 0x7745, 0xB18E, 0x7746, 0xB18F, 0x7747, 0xEDFB, 0x7748, 0xB190, 0x7749, 0xB191, 0x774A, 0xB192, + 0x774B, 0xB193, 0x774C, 0xB194, 0x774D, 0xB195, 0x774E, 0xB196, 0x774F, 0xB197, 0x7750, 0xEDF9, 0x7751, 0xEDFA, 0x7752, 0xB198, + 0x7753, 0xB199, 0x7754, 0xB19A, 0x7755, 0xB19B, 0x7756, 0xB19C, 0x7757, 0xB19D, 0x7758, 0xB19E, 0x7759, 0xB19F, 0x775A, 0xEDFD, + 0x775B, 0xBEA6, 0x775C, 0xB1A0, 0x775D, 0xB240, 0x775E, 0xB241, 0x775F, 0xB242, 0x7760, 0xB243, 0x7761, 0xCBAF, 0x7762, 0xEEA1, + 0x7763, 0xB6BD, 0x7764, 0xB244, 0x7765, 0xEEA2, 0x7766, 0xC4C0, 0x7767, 0xB245, 0x7768, 0xEDFE, 0x7769, 0xB246, 0x776A, 0xB247, + 0x776B, 0xBDDE, 0x776C, 0xB2C7, 0x776D, 0xB248, 0x776E, 0xB249, 0x776F, 0xB24A, 0x7770, 0xB24B, 0x7771, 0xB24C, 0x7772, 0xB24D, + 0x7773, 0xB24E, 0x7774, 0xB24F, 0x7775, 0xB250, 0x7776, 0xB251, 0x7777, 0xB252, 0x7778, 0xB253, 0x7779, 0xB6C3, 0x777A, 0xB254, + 0x777B, 0xB255, 0x777C, 0xB256, 0x777D, 0xEEA5, 0x777E, 0xD8BA, 0x777F, 0xEEA3, 0x7780, 0xEEA6, 0x7781, 0xB257, 0x7782, 0xB258, + 0x7783, 0xB259, 0x7784, 0xC3E9, 0x7785, 0xB3F2, 0x7786, 0xB25A, 0x7787, 0xB25B, 0x7788, 0xB25C, 0x7789, 0xB25D, 0x778A, 0xB25E, + 0x778B, 0xB25F, 0x778C, 0xEEA7, 0x778D, 0xEEA4, 0x778E, 0xCFB9, 0x778F, 0xB260, 0x7790, 0xB261, 0x7791, 0xEEA8, 0x7792, 0xC2F7, + 0x7793, 0xB262, 0x7794, 0xB263, 0x7795, 0xB264, 0x7796, 0xB265, 0x7797, 0xB266, 0x7798, 0xB267, 0x7799, 0xB268, 0x779A, 0xB269, + 0x779B, 0xB26A, 0x779C, 0xB26B, 0x779D, 0xB26C, 0x779E, 0xB26D, 0x779F, 0xEEA9, 0x77A0, 0xEEAA, 0x77A1, 0xB26E, 0x77A2, 0xDEAB, + 0x77A3, 0xB26F, 0x77A4, 0xB270, 0x77A5, 0xC6B3, 0x77A6, 0xB271, 0x77A7, 0xC7C6, 0x77A8, 0xB272, 0x77A9, 0xD6F5, 0x77AA, 0xB5C9, + 0x77AB, 0xB273, 0x77AC, 0xCBB2, 0x77AD, 0xB274, 0x77AE, 0xB275, 0x77AF, 0xB276, 0x77B0, 0xEEAB, 0x77B1, 0xB277, 0x77B2, 0xB278, + 0x77B3, 0xCDAB, 0x77B4, 0xB279, 0x77B5, 0xEEAC, 0x77B6, 0xB27A, 0x77B7, 0xB27B, 0x77B8, 0xB27C, 0x77B9, 0xB27D, 0x77BA, 0xB27E, + 0x77BB, 0xD5B0, 0x77BC, 0xB280, 0x77BD, 0xEEAD, 0x77BE, 0xB281, 0x77BF, 0xF6C4, 0x77C0, 0xB282, 0x77C1, 0xB283, 0x77C2, 0xB284, + 0x77C3, 0xB285, 0x77C4, 0xB286, 0x77C5, 0xB287, 0x77C6, 0xB288, 0x77C7, 0xB289, 0x77C8, 0xB28A, 0x77C9, 0xB28B, 0x77CA, 0xB28C, + 0x77CB, 0xB28D, 0x77CC, 0xB28E, 0x77CD, 0xDBC7, 0x77CE, 0xB28F, 0x77CF, 0xB290, 0x77D0, 0xB291, 0x77D1, 0xB292, 0x77D2, 0xB293, + 0x77D3, 0xB294, 0x77D4, 0xB295, 0x77D5, 0xB296, 0x77D6, 0xB297, 0x77D7, 0xB4A3, 0x77D8, 0xB298, 0x77D9, 0xB299, 0x77DA, 0xB29A, + 0x77DB, 0xC3AC, 0x77DC, 0xF1E6, 0x77DD, 0xB29B, 0x77DE, 0xB29C, 0x77DF, 0xB29D, 0x77E0, 0xB29E, 0x77E1, 0xB29F, 0x77E2, 0xCAB8, + 0x77E3, 0xD2D3, 0x77E4, 0xB2A0, 0x77E5, 0xD6AA, 0x77E6, 0xB340, 0x77E7, 0xEFF2, 0x77E8, 0xB341, 0x77E9, 0xBED8, 0x77EA, 0xB342, + 0x77EB, 0xBDC3, 0x77EC, 0xEFF3, 0x77ED, 0xB6CC, 0x77EE, 0xB0AB, 0x77EF, 0xB343, 0x77F0, 0xB344, 0x77F1, 0xB345, 0x77F2, 0xB346, + 0x77F3, 0xCAAF, 0x77F4, 0xB347, 0x77F5, 0xB348, 0x77F6, 0xEDB6, 0x77F7, 0xB349, 0x77F8, 0xEDB7, 0x77F9, 0xB34A, 0x77FA, 0xB34B, + 0x77FB, 0xB34C, 0x77FC, 0xB34D, 0x77FD, 0xCEF9, 0x77FE, 0xB7AF, 0x77FF, 0xBFF3, 0x7800, 0xEDB8, 0x7801, 0xC2EB, 0x7802, 0xC9B0, + 0x7803, 0xB34E, 0x7804, 0xB34F, 0x7805, 0xB350, 0x7806, 0xB351, 0x7807, 0xB352, 0x7808, 0xB353, 0x7809, 0xEDB9, 0x780A, 0xB354, + 0x780B, 0xB355, 0x780C, 0xC6F6, 0x780D, 0xBFB3, 0x780E, 0xB356, 0x780F, 0xB357, 0x7810, 0xB358, 0x7811, 0xEDBC, 0x7812, 0xC5F8, + 0x7813, 0xB359, 0x7814, 0xD1D0, 0x7815, 0xB35A, 0x7816, 0xD7A9, 0x7817, 0xEDBA, 0x7818, 0xEDBB, 0x7819, 0xB35B, 0x781A, 0xD1E2, + 0x781B, 0xB35C, 0x781C, 0xEDBF, 0x781D, 0xEDC0, 0x781E, 0xB35D, 0x781F, 0xEDC4, 0x7820, 0xB35E, 0x7821, 0xB35F, 0x7822, 0xB360, + 0x7823, 0xEDC8, 0x7824, 0xB361, 0x7825, 0xEDC6, 0x7826, 0xEDCE, 0x7827, 0xD5E8, 0x7828, 0xB362, 0x7829, 0xEDC9, 0x782A, 0xB363, + 0x782B, 0xB364, 0x782C, 0xEDC7, 0x782D, 0xEDBE, 0x782E, 0xB365, 0x782F, 0xB366, 0x7830, 0xC5E9, 0x7831, 0xB367, 0x7832, 0xB368, + 0x7833, 0xB369, 0x7834, 0xC6C6, 0x7835, 0xB36A, 0x7836, 0xB36B, 0x7837, 0xC9E9, 0x7838, 0xD4D2, 0x7839, 0xEDC1, 0x783A, 0xEDC2, + 0x783B, 0xEDC3, 0x783C, 0xEDC5, 0x783D, 0xB36C, 0x783E, 0xC0F9, 0x783F, 0xB36D, 0x7840, 0xB4A1, 0x7841, 0xB36E, 0x7842, 0xB36F, + 0x7843, 0xB370, 0x7844, 0xB371, 0x7845, 0xB9E8, 0x7846, 0xB372, 0x7847, 0xEDD0, 0x7848, 0xB373, 0x7849, 0xB374, 0x784A, 0xB375, + 0x784B, 0xB376, 0x784C, 0xEDD1, 0x784D, 0xB377, 0x784E, 0xEDCA, 0x784F, 0xB378, 0x7850, 0xEDCF, 0x7851, 0xB379, 0x7852, 0xCEF8, + 0x7853, 0xB37A, 0x7854, 0xB37B, 0x7855, 0xCBB6, 0x7856, 0xEDCC, 0x7857, 0xEDCD, 0x7858, 0xB37C, 0x7859, 0xB37D, 0x785A, 0xB37E, + 0x785B, 0xB380, 0x785C, 0xB381, 0x785D, 0xCFF5, 0x785E, 0xB382, 0x785F, 0xB383, 0x7860, 0xB384, 0x7861, 0xB385, 0x7862, 0xB386, + 0x7863, 0xB387, 0x7864, 0xB388, 0x7865, 0xB389, 0x7866, 0xB38A, 0x7867, 0xB38B, 0x7868, 0xB38C, 0x7869, 0xB38D, 0x786A, 0xEDD2, + 0x786B, 0xC1F2, 0x786C, 0xD3B2, 0x786D, 0xEDCB, 0x786E, 0xC8B7, 0x786F, 0xB38E, 0x7870, 0xB38F, 0x7871, 0xB390, 0x7872, 0xB391, + 0x7873, 0xB392, 0x7874, 0xB393, 0x7875, 0xB394, 0x7876, 0xB395, 0x7877, 0xBCEF, 0x7878, 0xB396, 0x7879, 0xB397, 0x787A, 0xB398, + 0x787B, 0xB399, 0x787C, 0xC5F0, 0x787D, 0xB39A, 0x787E, 0xB39B, 0x787F, 0xB39C, 0x7880, 0xB39D, 0x7881, 0xB39E, 0x7882, 0xB39F, + 0x7883, 0xB3A0, 0x7884, 0xB440, 0x7885, 0xB441, 0x7886, 0xB442, 0x7887, 0xEDD6, 0x7888, 0xB443, 0x7889, 0xB5EF, 0x788A, 0xB444, + 0x788B, 0xB445, 0x788C, 0xC2B5, 0x788D, 0xB0AD, 0x788E, 0xCBE9, 0x788F, 0xB446, 0x7890, 0xB447, 0x7891, 0xB1AE, 0x7892, 0xB448, + 0x7893, 0xEDD4, 0x7894, 0xB449, 0x7895, 0xB44A, 0x7896, 0xB44B, 0x7897, 0xCDEB, 0x7898, 0xB5E2, 0x7899, 0xB44C, 0x789A, 0xEDD5, + 0x789B, 0xEDD3, 0x789C, 0xEDD7, 0x789D, 0xB44D, 0x789E, 0xB44E, 0x789F, 0xB5FA, 0x78A0, 0xB44F, 0x78A1, 0xEDD8, 0x78A2, 0xB450, + 0x78A3, 0xEDD9, 0x78A4, 0xB451, 0x78A5, 0xEDDC, 0x78A6, 0xB452, 0x78A7, 0xB1CC, 0x78A8, 0xB453, 0x78A9, 0xB454, 0x78AA, 0xB455, + 0x78AB, 0xB456, 0x78AC, 0xB457, 0x78AD, 0xB458, 0x78AE, 0xB459, 0x78AF, 0xB45A, 0x78B0, 0xC5F6, 0x78B1, 0xBCEE, 0x78B2, 0xEDDA, + 0x78B3, 0xCCBC, 0x78B4, 0xB2EA, 0x78B5, 0xB45B, 0x78B6, 0xB45C, 0x78B7, 0xB45D, 0x78B8, 0xB45E, 0x78B9, 0xEDDB, 0x78BA, 0xB45F, + 0x78BB, 0xB460, 0x78BC, 0xB461, 0x78BD, 0xB462, 0x78BE, 0xC4EB, 0x78BF, 0xB463, 0x78C0, 0xB464, 0x78C1, 0xB4C5, 0x78C2, 0xB465, + 0x78C3, 0xB466, 0x78C4, 0xB467, 0x78C5, 0xB0F5, 0x78C6, 0xB468, 0x78C7, 0xB469, 0x78C8, 0xB46A, 0x78C9, 0xEDDF, 0x78CA, 0xC0DA, + 0x78CB, 0xB4E8, 0x78CC, 0xB46B, 0x78CD, 0xB46C, 0x78CE, 0xB46D, 0x78CF, 0xB46E, 0x78D0, 0xC5CD, 0x78D1, 0xB46F, 0x78D2, 0xB470, + 0x78D3, 0xB471, 0x78D4, 0xEDDD, 0x78D5, 0xBFC4, 0x78D6, 0xB472, 0x78D7, 0xB473, 0x78D8, 0xB474, 0x78D9, 0xEDDE, 0x78DA, 0xB475, + 0x78DB, 0xB476, 0x78DC, 0xB477, 0x78DD, 0xB478, 0x78DE, 0xB479, 0x78DF, 0xB47A, 0x78E0, 0xB47B, 0x78E1, 0xB47C, 0x78E2, 0xB47D, + 0x78E3, 0xB47E, 0x78E4, 0xB480, 0x78E5, 0xB481, 0x78E6, 0xB482, 0x78E7, 0xB483, 0x78E8, 0xC4A5, 0x78E9, 0xB484, 0x78EA, 0xB485, + 0x78EB, 0xB486, 0x78EC, 0xEDE0, 0x78ED, 0xB487, 0x78EE, 0xB488, 0x78EF, 0xB489, 0x78F0, 0xB48A, 0x78F1, 0xB48B, 0x78F2, 0xEDE1, + 0x78F3, 0xB48C, 0x78F4, 0xEDE3, 0x78F5, 0xB48D, 0x78F6, 0xB48E, 0x78F7, 0xC1D7, 0x78F8, 0xB48F, 0x78F9, 0xB490, 0x78FA, 0xBBC7, + 0x78FB, 0xB491, 0x78FC, 0xB492, 0x78FD, 0xB493, 0x78FE, 0xB494, 0x78FF, 0xB495, 0x7900, 0xB496, 0x7901, 0xBDB8, 0x7902, 0xB497, + 0x7903, 0xB498, 0x7904, 0xB499, 0x7905, 0xEDE2, 0x7906, 0xB49A, 0x7907, 0xB49B, 0x7908, 0xB49C, 0x7909, 0xB49D, 0x790A, 0xB49E, + 0x790B, 0xB49F, 0x790C, 0xB4A0, 0x790D, 0xB540, 0x790E, 0xB541, 0x790F, 0xB542, 0x7910, 0xB543, 0x7911, 0xB544, 0x7912, 0xB545, + 0x7913, 0xEDE4, 0x7914, 0xB546, 0x7915, 0xB547, 0x7916, 0xB548, 0x7917, 0xB549, 0x7918, 0xB54A, 0x7919, 0xB54B, 0x791A, 0xB54C, + 0x791B, 0xB54D, 0x791C, 0xB54E, 0x791D, 0xB54F, 0x791E, 0xEDE6, 0x791F, 0xB550, 0x7920, 0xB551, 0x7921, 0xB552, 0x7922, 0xB553, + 0x7923, 0xB554, 0x7924, 0xEDE5, 0x7925, 0xB555, 0x7926, 0xB556, 0x7927, 0xB557, 0x7928, 0xB558, 0x7929, 0xB559, 0x792A, 0xB55A, + 0x792B, 0xB55B, 0x792C, 0xB55C, 0x792D, 0xB55D, 0x792E, 0xB55E, 0x792F, 0xB55F, 0x7930, 0xB560, 0x7931, 0xB561, 0x7932, 0xB562, + 0x7933, 0xB563, 0x7934, 0xEDE7, 0x7935, 0xB564, 0x7936, 0xB565, 0x7937, 0xB566, 0x7938, 0xB567, 0x7939, 0xB568, 0x793A, 0xCABE, + 0x793B, 0xECEA, 0x793C, 0xC0F1, 0x793D, 0xB569, 0x793E, 0xC9E7, 0x793F, 0xB56A, 0x7940, 0xECEB, 0x7941, 0xC6EE, 0x7942, 0xB56B, + 0x7943, 0xB56C, 0x7944, 0xB56D, 0x7945, 0xB56E, 0x7946, 0xECEC, 0x7947, 0xB56F, 0x7948, 0xC6ED, 0x7949, 0xECED, 0x794A, 0xB570, + 0x794B, 0xB571, 0x794C, 0xB572, 0x794D, 0xB573, 0x794E, 0xB574, 0x794F, 0xB575, 0x7950, 0xB576, 0x7951, 0xB577, 0x7952, 0xB578, + 0x7953, 0xECF0, 0x7954, 0xB579, 0x7955, 0xB57A, 0x7956, 0xD7E6, 0x7957, 0xECF3, 0x7958, 0xB57B, 0x7959, 0xB57C, 0x795A, 0xECF1, + 0x795B, 0xECEE, 0x795C, 0xECEF, 0x795D, 0xD7A3, 0x795E, 0xC9F1, 0x795F, 0xCBEE, 0x7960, 0xECF4, 0x7961, 0xB57D, 0x7962, 0xECF2, + 0x7963, 0xB57E, 0x7964, 0xB580, 0x7965, 0xCFE9, 0x7966, 0xB581, 0x7967, 0xECF6, 0x7968, 0xC6B1, 0x7969, 0xB582, 0x796A, 0xB583, + 0x796B, 0xB584, 0x796C, 0xB585, 0x796D, 0xBCC0, 0x796E, 0xB586, 0x796F, 0xECF5, 0x7970, 0xB587, 0x7971, 0xB588, 0x7972, 0xB589, + 0x7973, 0xB58A, 0x7974, 0xB58B, 0x7975, 0xB58C, 0x7976, 0xB58D, 0x7977, 0xB5BB, 0x7978, 0xBBF6, 0x7979, 0xB58E, 0x797A, 0xECF7, + 0x797B, 0xB58F, 0x797C, 0xB590, 0x797D, 0xB591, 0x797E, 0xB592, 0x797F, 0xB593, 0x7980, 0xD9F7, 0x7981, 0xBDFB, 0x7982, 0xB594, + 0x7983, 0xB595, 0x7984, 0xC2BB, 0x7985, 0xECF8, 0x7986, 0xB596, 0x7987, 0xB597, 0x7988, 0xB598, 0x7989, 0xB599, 0x798A, 0xECF9, + 0x798B, 0xB59A, 0x798C, 0xB59B, 0x798D, 0xB59C, 0x798E, 0xB59D, 0x798F, 0xB8A3, 0x7990, 0xB59E, 0x7991, 0xB59F, 0x7992, 0xB5A0, + 0x7993, 0xB640, 0x7994, 0xB641, 0x7995, 0xB642, 0x7996, 0xB643, 0x7997, 0xB644, 0x7998, 0xB645, 0x7999, 0xB646, 0x799A, 0xECFA, + 0x799B, 0xB647, 0x799C, 0xB648, 0x799D, 0xB649, 0x799E, 0xB64A, 0x799F, 0xB64B, 0x79A0, 0xB64C, 0x79A1, 0xB64D, 0x79A2, 0xB64E, + 0x79A3, 0xB64F, 0x79A4, 0xB650, 0x79A5, 0xB651, 0x79A6, 0xB652, 0x79A7, 0xECFB, 0x79A8, 0xB653, 0x79A9, 0xB654, 0x79AA, 0xB655, + 0x79AB, 0xB656, 0x79AC, 0xB657, 0x79AD, 0xB658, 0x79AE, 0xB659, 0x79AF, 0xB65A, 0x79B0, 0xB65B, 0x79B1, 0xB65C, 0x79B2, 0xB65D, + 0x79B3, 0xECFC, 0x79B4, 0xB65E, 0x79B5, 0xB65F, 0x79B6, 0xB660, 0x79B7, 0xB661, 0x79B8, 0xB662, 0x79B9, 0xD3ED, 0x79BA, 0xD8AE, + 0x79BB, 0xC0EB, 0x79BC, 0xB663, 0x79BD, 0xC7DD, 0x79BE, 0xBACC, 0x79BF, 0xB664, 0x79C0, 0xD0E3, 0x79C1, 0xCBBD, 0x79C2, 0xB665, + 0x79C3, 0xCDBA, 0x79C4, 0xB666, 0x79C5, 0xB667, 0x79C6, 0xB8D1, 0x79C7, 0xB668, 0x79C8, 0xB669, 0x79C9, 0xB1FC, 0x79CA, 0xB66A, + 0x79CB, 0xC7EF, 0x79CC, 0xB66B, 0x79CD, 0xD6D6, 0x79CE, 0xB66C, 0x79CF, 0xB66D, 0x79D0, 0xB66E, 0x79D1, 0xBFC6, 0x79D2, 0xC3EB, + 0x79D3, 0xB66F, 0x79D4, 0xB670, 0x79D5, 0xEFF5, 0x79D6, 0xB671, 0x79D7, 0xB672, 0x79D8, 0xC3D8, 0x79D9, 0xB673, 0x79DA, 0xB674, + 0x79DB, 0xB675, 0x79DC, 0xB676, 0x79DD, 0xB677, 0x79DE, 0xB678, 0x79DF, 0xD7E2, 0x79E0, 0xB679, 0x79E1, 0xB67A, 0x79E2, 0xB67B, + 0x79E3, 0xEFF7, 0x79E4, 0xB3D3, 0x79E5, 0xB67C, 0x79E6, 0xC7D8, 0x79E7, 0xD1ED, 0x79E8, 0xB67D, 0x79E9, 0xD6C8, 0x79EA, 0xB67E, + 0x79EB, 0xEFF8, 0x79EC, 0xB680, 0x79ED, 0xEFF6, 0x79EE, 0xB681, 0x79EF, 0xBBFD, 0x79F0, 0xB3C6, 0x79F1, 0xB682, 0x79F2, 0xB683, + 0x79F3, 0xB684, 0x79F4, 0xB685, 0x79F5, 0xB686, 0x79F6, 0xB687, 0x79F7, 0xB688, 0x79F8, 0xBDD5, 0x79F9, 0xB689, 0x79FA, 0xB68A, + 0x79FB, 0xD2C6, 0x79FC, 0xB68B, 0x79FD, 0xBBE0, 0x79FE, 0xB68C, 0x79FF, 0xB68D, 0x7A00, 0xCFA1, 0x7A01, 0xB68E, 0x7A02, 0xEFFC, + 0x7A03, 0xEFFB, 0x7A04, 0xB68F, 0x7A05, 0xB690, 0x7A06, 0xEFF9, 0x7A07, 0xB691, 0x7A08, 0xB692, 0x7A09, 0xB693, 0x7A0A, 0xB694, + 0x7A0B, 0xB3CC, 0x7A0C, 0xB695, 0x7A0D, 0xC9D4, 0x7A0E, 0xCBB0, 0x7A0F, 0xB696, 0x7A10, 0xB697, 0x7A11, 0xB698, 0x7A12, 0xB699, + 0x7A13, 0xB69A, 0x7A14, 0xEFFE, 0x7A15, 0xB69B, 0x7A16, 0xB69C, 0x7A17, 0xB0DE, 0x7A18, 0xB69D, 0x7A19, 0xB69E, 0x7A1A, 0xD6C9, + 0x7A1B, 0xB69F, 0x7A1C, 0xB6A0, 0x7A1D, 0xB740, 0x7A1E, 0xEFFD, 0x7A1F, 0xB741, 0x7A20, 0xB3ED, 0x7A21, 0xB742, 0x7A22, 0xB743, + 0x7A23, 0xF6D5, 0x7A24, 0xB744, 0x7A25, 0xB745, 0x7A26, 0xB746, 0x7A27, 0xB747, 0x7A28, 0xB748, 0x7A29, 0xB749, 0x7A2A, 0xB74A, + 0x7A2B, 0xB74B, 0x7A2C, 0xB74C, 0x7A2D, 0xB74D, 0x7A2E, 0xB74E, 0x7A2F, 0xB74F, 0x7A30, 0xB750, 0x7A31, 0xB751, 0x7A32, 0xB752, + 0x7A33, 0xCEC8, 0x7A34, 0xB753, 0x7A35, 0xB754, 0x7A36, 0xB755, 0x7A37, 0xF0A2, 0x7A38, 0xB756, 0x7A39, 0xF0A1, 0x7A3A, 0xB757, + 0x7A3B, 0xB5BE, 0x7A3C, 0xBCDA, 0x7A3D, 0xBBFC, 0x7A3E, 0xB758, 0x7A3F, 0xB8E5, 0x7A40, 0xB759, 0x7A41, 0xB75A, 0x7A42, 0xB75B, + 0x7A43, 0xB75C, 0x7A44, 0xB75D, 0x7A45, 0xB75E, 0x7A46, 0xC4C2, 0x7A47, 0xB75F, 0x7A48, 0xB760, 0x7A49, 0xB761, 0x7A4A, 0xB762, + 0x7A4B, 0xB763, 0x7A4C, 0xB764, 0x7A4D, 0xB765, 0x7A4E, 0xB766, 0x7A4F, 0xB767, 0x7A50, 0xB768, 0x7A51, 0xF0A3, 0x7A52, 0xB769, + 0x7A53, 0xB76A, 0x7A54, 0xB76B, 0x7A55, 0xB76C, 0x7A56, 0xB76D, 0x7A57, 0xCBEB, 0x7A58, 0xB76E, 0x7A59, 0xB76F, 0x7A5A, 0xB770, + 0x7A5B, 0xB771, 0x7A5C, 0xB772, 0x7A5D, 0xB773, 0x7A5E, 0xB774, 0x7A5F, 0xB775, 0x7A60, 0xB776, 0x7A61, 0xB777, 0x7A62, 0xB778, + 0x7A63, 0xB779, 0x7A64, 0xB77A, 0x7A65, 0xB77B, 0x7A66, 0xB77C, 0x7A67, 0xB77D, 0x7A68, 0xB77E, 0x7A69, 0xB780, 0x7A6A, 0xB781, + 0x7A6B, 0xB782, 0x7A6C, 0xB783, 0x7A6D, 0xB784, 0x7A6E, 0xB785, 0x7A6F, 0xB786, 0x7A70, 0xF0A6, 0x7A71, 0xB787, 0x7A72, 0xB788, + 0x7A73, 0xB789, 0x7A74, 0xD1A8, 0x7A75, 0xB78A, 0x7A76, 0xBEBF, 0x7A77, 0xC7EE, 0x7A78, 0xF1B6, 0x7A79, 0xF1B7, 0x7A7A, 0xBFD5, + 0x7A7B, 0xB78B, 0x7A7C, 0xB78C, 0x7A7D, 0xB78D, 0x7A7E, 0xB78E, 0x7A7F, 0xB4A9, 0x7A80, 0xF1B8, 0x7A81, 0xCDBB, 0x7A82, 0xB78F, + 0x7A83, 0xC7D4, 0x7A84, 0xD5AD, 0x7A85, 0xB790, 0x7A86, 0xF1B9, 0x7A87, 0xB791, 0x7A88, 0xF1BA, 0x7A89, 0xB792, 0x7A8A, 0xB793, + 0x7A8B, 0xB794, 0x7A8C, 0xB795, 0x7A8D, 0xC7CF, 0x7A8E, 0xB796, 0x7A8F, 0xB797, 0x7A90, 0xB798, 0x7A91, 0xD2A4, 0x7A92, 0xD6CF, + 0x7A93, 0xB799, 0x7A94, 0xB79A, 0x7A95, 0xF1BB, 0x7A96, 0xBDD1, 0x7A97, 0xB4B0, 0x7A98, 0xBEBD, 0x7A99, 0xB79B, 0x7A9A, 0xB79C, + 0x7A9B, 0xB79D, 0x7A9C, 0xB4DC, 0x7A9D, 0xCED1, 0x7A9E, 0xB79E, 0x7A9F, 0xBFDF, 0x7AA0, 0xF1BD, 0x7AA1, 0xB79F, 0x7AA2, 0xB7A0, + 0x7AA3, 0xB840, 0x7AA4, 0xB841, 0x7AA5, 0xBFFA, 0x7AA6, 0xF1BC, 0x7AA7, 0xB842, 0x7AA8, 0xF1BF, 0x7AA9, 0xB843, 0x7AAA, 0xB844, + 0x7AAB, 0xB845, 0x7AAC, 0xF1BE, 0x7AAD, 0xF1C0, 0x7AAE, 0xB846, 0x7AAF, 0xB847, 0x7AB0, 0xB848, 0x7AB1, 0xB849, 0x7AB2, 0xB84A, + 0x7AB3, 0xF1C1, 0x7AB4, 0xB84B, 0x7AB5, 0xB84C, 0x7AB6, 0xB84D, 0x7AB7, 0xB84E, 0x7AB8, 0xB84F, 0x7AB9, 0xB850, 0x7ABA, 0xB851, + 0x7ABB, 0xB852, 0x7ABC, 0xB853, 0x7ABD, 0xB854, 0x7ABE, 0xB855, 0x7ABF, 0xC1FE, 0x7AC0, 0xB856, 0x7AC1, 0xB857, 0x7AC2, 0xB858, + 0x7AC3, 0xB859, 0x7AC4, 0xB85A, 0x7AC5, 0xB85B, 0x7AC6, 0xB85C, 0x7AC7, 0xB85D, 0x7AC8, 0xB85E, 0x7AC9, 0xB85F, 0x7ACA, 0xB860, + 0x7ACB, 0xC1A2, 0x7ACC, 0xB861, 0x7ACD, 0xB862, 0x7ACE, 0xB863, 0x7ACF, 0xB864, 0x7AD0, 0xB865, 0x7AD1, 0xB866, 0x7AD2, 0xB867, + 0x7AD3, 0xB868, 0x7AD4, 0xB869, 0x7AD5, 0xB86A, 0x7AD6, 0xCAFA, 0x7AD7, 0xB86B, 0x7AD8, 0xB86C, 0x7AD9, 0xD5BE, 0x7ADA, 0xB86D, + 0x7ADB, 0xB86E, 0x7ADC, 0xB86F, 0x7ADD, 0xB870, 0x7ADE, 0xBEBA, 0x7ADF, 0xBEB9, 0x7AE0, 0xD5C2, 0x7AE1, 0xB871, 0x7AE2, 0xB872, + 0x7AE3, 0xBFA2, 0x7AE4, 0xB873, 0x7AE5, 0xCDAF, 0x7AE6, 0xF1B5, 0x7AE7, 0xB874, 0x7AE8, 0xB875, 0x7AE9, 0xB876, 0x7AEA, 0xB877, + 0x7AEB, 0xB878, 0x7AEC, 0xB879, 0x7AED, 0xBDDF, 0x7AEE, 0xB87A, 0x7AEF, 0xB6CB, 0x7AF0, 0xB87B, 0x7AF1, 0xB87C, 0x7AF2, 0xB87D, + 0x7AF3, 0xB87E, 0x7AF4, 0xB880, 0x7AF5, 0xB881, 0x7AF6, 0xB882, 0x7AF7, 0xB883, 0x7AF8, 0xB884, 0x7AF9, 0xD6F1, 0x7AFA, 0xF3C3, + 0x7AFB, 0xB885, 0x7AFC, 0xB886, 0x7AFD, 0xF3C4, 0x7AFE, 0xB887, 0x7AFF, 0xB8CD, 0x7B00, 0xB888, 0x7B01, 0xB889, 0x7B02, 0xB88A, + 0x7B03, 0xF3C6, 0x7B04, 0xF3C7, 0x7B05, 0xB88B, 0x7B06, 0xB0CA, 0x7B07, 0xB88C, 0x7B08, 0xF3C5, 0x7B09, 0xB88D, 0x7B0A, 0xF3C9, + 0x7B0B, 0xCBF1, 0x7B0C, 0xB88E, 0x7B0D, 0xB88F, 0x7B0E, 0xB890, 0x7B0F, 0xF3CB, 0x7B10, 0xB891, 0x7B11, 0xD0A6, 0x7B12, 0xB892, + 0x7B13, 0xB893, 0x7B14, 0xB1CA, 0x7B15, 0xF3C8, 0x7B16, 0xB894, 0x7B17, 0xB895, 0x7B18, 0xB896, 0x7B19, 0xF3CF, 0x7B1A, 0xB897, + 0x7B1B, 0xB5D1, 0x7B1C, 0xB898, 0x7B1D, 0xB899, 0x7B1E, 0xF3D7, 0x7B1F, 0xB89A, 0x7B20, 0xF3D2, 0x7B21, 0xB89B, 0x7B22, 0xB89C, + 0x7B23, 0xB89D, 0x7B24, 0xF3D4, 0x7B25, 0xF3D3, 0x7B26, 0xB7FB, 0x7B27, 0xB89E, 0x7B28, 0xB1BF, 0x7B29, 0xB89F, 0x7B2A, 0xF3CE, + 0x7B2B, 0xF3CA, 0x7B2C, 0xB5DA, 0x7B2D, 0xB8A0, 0x7B2E, 0xF3D0, 0x7B2F, 0xB940, 0x7B30, 0xB941, 0x7B31, 0xF3D1, 0x7B32, 0xB942, + 0x7B33, 0xF3D5, 0x7B34, 0xB943, 0x7B35, 0xB944, 0x7B36, 0xB945, 0x7B37, 0xB946, 0x7B38, 0xF3CD, 0x7B39, 0xB947, 0x7B3A, 0xBCE3, + 0x7B3B, 0xB948, 0x7B3C, 0xC1FD, 0x7B3D, 0xB949, 0x7B3E, 0xF3D6, 0x7B3F, 0xB94A, 0x7B40, 0xB94B, 0x7B41, 0xB94C, 0x7B42, 0xB94D, + 0x7B43, 0xB94E, 0x7B44, 0xB94F, 0x7B45, 0xF3DA, 0x7B46, 0xB950, 0x7B47, 0xF3CC, 0x7B48, 0xB951, 0x7B49, 0xB5C8, 0x7B4A, 0xB952, + 0x7B4B, 0xBDEE, 0x7B4C, 0xF3DC, 0x7B4D, 0xB953, 0x7B4E, 0xB954, 0x7B4F, 0xB7A4, 0x7B50, 0xBFF0, 0x7B51, 0xD6FE, 0x7B52, 0xCDB2, + 0x7B53, 0xB955, 0x7B54, 0xB4F0, 0x7B55, 0xB956, 0x7B56, 0xB2DF, 0x7B57, 0xB957, 0x7B58, 0xF3D8, 0x7B59, 0xB958, 0x7B5A, 0xF3D9, + 0x7B5B, 0xC9B8, 0x7B5C, 0xB959, 0x7B5D, 0xF3DD, 0x7B5E, 0xB95A, 0x7B5F, 0xB95B, 0x7B60, 0xF3DE, 0x7B61, 0xB95C, 0x7B62, 0xF3E1, + 0x7B63, 0xB95D, 0x7B64, 0xB95E, 0x7B65, 0xB95F, 0x7B66, 0xB960, 0x7B67, 0xB961, 0x7B68, 0xB962, 0x7B69, 0xB963, 0x7B6A, 0xB964, + 0x7B6B, 0xB965, 0x7B6C, 0xB966, 0x7B6D, 0xB967, 0x7B6E, 0xF3DF, 0x7B6F, 0xB968, 0x7B70, 0xB969, 0x7B71, 0xF3E3, 0x7B72, 0xF3E2, + 0x7B73, 0xB96A, 0x7B74, 0xB96B, 0x7B75, 0xF3DB, 0x7B76, 0xB96C, 0x7B77, 0xBFEA, 0x7B78, 0xB96D, 0x7B79, 0xB3EF, 0x7B7A, 0xB96E, + 0x7B7B, 0xF3E0, 0x7B7C, 0xB96F, 0x7B7D, 0xB970, 0x7B7E, 0xC7A9, 0x7B7F, 0xB971, 0x7B80, 0xBCF2, 0x7B81, 0xB972, 0x7B82, 0xB973, + 0x7B83, 0xB974, 0x7B84, 0xB975, 0x7B85, 0xF3EB, 0x7B86, 0xB976, 0x7B87, 0xB977, 0x7B88, 0xB978, 0x7B89, 0xB979, 0x7B8A, 0xB97A, + 0x7B8B, 0xB97B, 0x7B8C, 0xB97C, 0x7B8D, 0xB9BF, 0x7B8E, 0xB97D, 0x7B8F, 0xB97E, 0x7B90, 0xF3E4, 0x7B91, 0xB980, 0x7B92, 0xB981, + 0x7B93, 0xB982, 0x7B94, 0xB2AD, 0x7B95, 0xBBFE, 0x7B96, 0xB983, 0x7B97, 0xCBE3, 0x7B98, 0xB984, 0x7B99, 0xB985, 0x7B9A, 0xB986, + 0x7B9B, 0xB987, 0x7B9C, 0xF3ED, 0x7B9D, 0xF3E9, 0x7B9E, 0xB988, 0x7B9F, 0xB989, 0x7BA0, 0xB98A, 0x7BA1, 0xB9DC, 0x7BA2, 0xF3EE, + 0x7BA3, 0xB98B, 0x7BA4, 0xB98C, 0x7BA5, 0xB98D, 0x7BA6, 0xF3E5, 0x7BA7, 0xF3E6, 0x7BA8, 0xF3EA, 0x7BA9, 0xC2E1, 0x7BAA, 0xF3EC, + 0x7BAB, 0xF3EF, 0x7BAC, 0xF3E8, 0x7BAD, 0xBCFD, 0x7BAE, 0xB98E, 0x7BAF, 0xB98F, 0x7BB0, 0xB990, 0x7BB1, 0xCFE4, 0x7BB2, 0xB991, + 0x7BB3, 0xB992, 0x7BB4, 0xF3F0, 0x7BB5, 0xB993, 0x7BB6, 0xB994, 0x7BB7, 0xB995, 0x7BB8, 0xF3E7, 0x7BB9, 0xB996, 0x7BBA, 0xB997, + 0x7BBB, 0xB998, 0x7BBC, 0xB999, 0x7BBD, 0xB99A, 0x7BBE, 0xB99B, 0x7BBF, 0xB99C, 0x7BC0, 0xB99D, 0x7BC1, 0xF3F2, 0x7BC2, 0xB99E, + 0x7BC3, 0xB99F, 0x7BC4, 0xB9A0, 0x7BC5, 0xBA40, 0x7BC6, 0xD7AD, 0x7BC7, 0xC6AA, 0x7BC8, 0xBA41, 0x7BC9, 0xBA42, 0x7BCA, 0xBA43, + 0x7BCB, 0xBA44, 0x7BCC, 0xF3F3, 0x7BCD, 0xBA45, 0x7BCE, 0xBA46, 0x7BCF, 0xBA47, 0x7BD0, 0xBA48, 0x7BD1, 0xF3F1, 0x7BD2, 0xBA49, + 0x7BD3, 0xC2A8, 0x7BD4, 0xBA4A, 0x7BD5, 0xBA4B, 0x7BD6, 0xBA4C, 0x7BD7, 0xBA4D, 0x7BD8, 0xBA4E, 0x7BD9, 0xB8DD, 0x7BDA, 0xF3F5, + 0x7BDB, 0xBA4F, 0x7BDC, 0xBA50, 0x7BDD, 0xF3F4, 0x7BDE, 0xBA51, 0x7BDF, 0xBA52, 0x7BE0, 0xBA53, 0x7BE1, 0xB4DB, 0x7BE2, 0xBA54, + 0x7BE3, 0xBA55, 0x7BE4, 0xBA56, 0x7BE5, 0xF3F6, 0x7BE6, 0xF3F7, 0x7BE7, 0xBA57, 0x7BE8, 0xBA58, 0x7BE9, 0xBA59, 0x7BEA, 0xF3F8, + 0x7BEB, 0xBA5A, 0x7BEC, 0xBA5B, 0x7BED, 0xBA5C, 0x7BEE, 0xC0BA, 0x7BEF, 0xBA5D, 0x7BF0, 0xBA5E, 0x7BF1, 0xC0E9, 0x7BF2, 0xBA5F, + 0x7BF3, 0xBA60, 0x7BF4, 0xBA61, 0x7BF5, 0xBA62, 0x7BF6, 0xBA63, 0x7BF7, 0xC5F1, 0x7BF8, 0xBA64, 0x7BF9, 0xBA65, 0x7BFA, 0xBA66, + 0x7BFB, 0xBA67, 0x7BFC, 0xF3FB, 0x7BFD, 0xBA68, 0x7BFE, 0xF3FA, 0x7BFF, 0xBA69, 0x7C00, 0xBA6A, 0x7C01, 0xBA6B, 0x7C02, 0xBA6C, + 0x7C03, 0xBA6D, 0x7C04, 0xBA6E, 0x7C05, 0xBA6F, 0x7C06, 0xBA70, 0x7C07, 0xB4D8, 0x7C08, 0xBA71, 0x7C09, 0xBA72, 0x7C0A, 0xBA73, + 0x7C0B, 0xF3FE, 0x7C0C, 0xF3F9, 0x7C0D, 0xBA74, 0x7C0E, 0xBA75, 0x7C0F, 0xF3FC, 0x7C10, 0xBA76, 0x7C11, 0xBA77, 0x7C12, 0xBA78, + 0x7C13, 0xBA79, 0x7C14, 0xBA7A, 0x7C15, 0xBA7B, 0x7C16, 0xF3FD, 0x7C17, 0xBA7C, 0x7C18, 0xBA7D, 0x7C19, 0xBA7E, 0x7C1A, 0xBA80, + 0x7C1B, 0xBA81, 0x7C1C, 0xBA82, 0x7C1D, 0xBA83, 0x7C1E, 0xBA84, 0x7C1F, 0xF4A1, 0x7C20, 0xBA85, 0x7C21, 0xBA86, 0x7C22, 0xBA87, + 0x7C23, 0xBA88, 0x7C24, 0xBA89, 0x7C25, 0xBA8A, 0x7C26, 0xF4A3, 0x7C27, 0xBBC9, 0x7C28, 0xBA8B, 0x7C29, 0xBA8C, 0x7C2A, 0xF4A2, + 0x7C2B, 0xBA8D, 0x7C2C, 0xBA8E, 0x7C2D, 0xBA8F, 0x7C2E, 0xBA90, 0x7C2F, 0xBA91, 0x7C30, 0xBA92, 0x7C31, 0xBA93, 0x7C32, 0xBA94, + 0x7C33, 0xBA95, 0x7C34, 0xBA96, 0x7C35, 0xBA97, 0x7C36, 0xBA98, 0x7C37, 0xBA99, 0x7C38, 0xF4A4, 0x7C39, 0xBA9A, 0x7C3A, 0xBA9B, + 0x7C3B, 0xBA9C, 0x7C3C, 0xBA9D, 0x7C3D, 0xBA9E, 0x7C3E, 0xBA9F, 0x7C3F, 0xB2BE, 0x7C40, 0xF4A6, 0x7C41, 0xF4A5, 0x7C42, 0xBAA0, + 0x7C43, 0xBB40, 0x7C44, 0xBB41, 0x7C45, 0xBB42, 0x7C46, 0xBB43, 0x7C47, 0xBB44, 0x7C48, 0xBB45, 0x7C49, 0xBB46, 0x7C4A, 0xBB47, + 0x7C4B, 0xBB48, 0x7C4C, 0xBB49, 0x7C4D, 0xBCAE, 0x7C4E, 0xBB4A, 0x7C4F, 0xBB4B, 0x7C50, 0xBB4C, 0x7C51, 0xBB4D, 0x7C52, 0xBB4E, + 0x7C53, 0xBB4F, 0x7C54, 0xBB50, 0x7C55, 0xBB51, 0x7C56, 0xBB52, 0x7C57, 0xBB53, 0x7C58, 0xBB54, 0x7C59, 0xBB55, 0x7C5A, 0xBB56, + 0x7C5B, 0xBB57, 0x7C5C, 0xBB58, 0x7C5D, 0xBB59, 0x7C5E, 0xBB5A, 0x7C5F, 0xBB5B, 0x7C60, 0xBB5C, 0x7C61, 0xBB5D, 0x7C62, 0xBB5E, + 0x7C63, 0xBB5F, 0x7C64, 0xBB60, 0x7C65, 0xBB61, 0x7C66, 0xBB62, 0x7C67, 0xBB63, 0x7C68, 0xBB64, 0x7C69, 0xBB65, 0x7C6A, 0xBB66, + 0x7C6B, 0xBB67, 0x7C6C, 0xBB68, 0x7C6D, 0xBB69, 0x7C6E, 0xBB6A, 0x7C6F, 0xBB6B, 0x7C70, 0xBB6C, 0x7C71, 0xBB6D, 0x7C72, 0xBB6E, + 0x7C73, 0xC3D7, 0x7C74, 0xD9E1, 0x7C75, 0xBB6F, 0x7C76, 0xBB70, 0x7C77, 0xBB71, 0x7C78, 0xBB72, 0x7C79, 0xBB73, 0x7C7A, 0xBB74, + 0x7C7B, 0xC0E0, 0x7C7C, 0xF4CC, 0x7C7D, 0xD7D1, 0x7C7E, 0xBB75, 0x7C7F, 0xBB76, 0x7C80, 0xBB77, 0x7C81, 0xBB78, 0x7C82, 0xBB79, + 0x7C83, 0xBB7A, 0x7C84, 0xBB7B, 0x7C85, 0xBB7C, 0x7C86, 0xBB7D, 0x7C87, 0xBB7E, 0x7C88, 0xBB80, 0x7C89, 0xB7DB, 0x7C8A, 0xBB81, + 0x7C8B, 0xBB82, 0x7C8C, 0xBB83, 0x7C8D, 0xBB84, 0x7C8E, 0xBB85, 0x7C8F, 0xBB86, 0x7C90, 0xBB87, 0x7C91, 0xF4CE, 0x7C92, 0xC1A3, + 0x7C93, 0xBB88, 0x7C94, 0xBB89, 0x7C95, 0xC6C9, 0x7C96, 0xBB8A, 0x7C97, 0xB4D6, 0x7C98, 0xD5B3, 0x7C99, 0xBB8B, 0x7C9A, 0xBB8C, + 0x7C9B, 0xBB8D, 0x7C9C, 0xF4D0, 0x7C9D, 0xF4CF, 0x7C9E, 0xF4D1, 0x7C9F, 0xCBDA, 0x7CA0, 0xBB8E, 0x7CA1, 0xBB8F, 0x7CA2, 0xF4D2, + 0x7CA3, 0xBB90, 0x7CA4, 0xD4C1, 0x7CA5, 0xD6E0, 0x7CA6, 0xBB91, 0x7CA7, 0xBB92, 0x7CA8, 0xBB93, 0x7CA9, 0xBB94, 0x7CAA, 0xB7E0, + 0x7CAB, 0xBB95, 0x7CAC, 0xBB96, 0x7CAD, 0xBB97, 0x7CAE, 0xC1B8, 0x7CAF, 0xBB98, 0x7CB0, 0xBB99, 0x7CB1, 0xC1BB, 0x7CB2, 0xF4D3, + 0x7CB3, 0xBEAC, 0x7CB4, 0xBB9A, 0x7CB5, 0xBB9B, 0x7CB6, 0xBB9C, 0x7CB7, 0xBB9D, 0x7CB8, 0xBB9E, 0x7CB9, 0xB4E2, 0x7CBA, 0xBB9F, + 0x7CBB, 0xBBA0, 0x7CBC, 0xF4D4, 0x7CBD, 0xF4D5, 0x7CBE, 0xBEAB, 0x7CBF, 0xBC40, 0x7CC0, 0xBC41, 0x7CC1, 0xF4D6, 0x7CC2, 0xBC42, + 0x7CC3, 0xBC43, 0x7CC4, 0xBC44, 0x7CC5, 0xF4DB, 0x7CC6, 0xBC45, 0x7CC7, 0xF4D7, 0x7CC8, 0xF4DA, 0x7CC9, 0xBC46, 0x7CCA, 0xBAFD, + 0x7CCB, 0xBC47, 0x7CCC, 0xF4D8, 0x7CCD, 0xF4D9, 0x7CCE, 0xBC48, 0x7CCF, 0xBC49, 0x7CD0, 0xBC4A, 0x7CD1, 0xBC4B, 0x7CD2, 0xBC4C, + 0x7CD3, 0xBC4D, 0x7CD4, 0xBC4E, 0x7CD5, 0xB8E2, 0x7CD6, 0xCCC7, 0x7CD7, 0xF4DC, 0x7CD8, 0xBC4F, 0x7CD9, 0xB2DA, 0x7CDA, 0xBC50, + 0x7CDB, 0xBC51, 0x7CDC, 0xC3D3, 0x7CDD, 0xBC52, 0x7CDE, 0xBC53, 0x7CDF, 0xD4E3, 0x7CE0, 0xBFB7, 0x7CE1, 0xBC54, 0x7CE2, 0xBC55, + 0x7CE3, 0xBC56, 0x7CE4, 0xBC57, 0x7CE5, 0xBC58, 0x7CE6, 0xBC59, 0x7CE7, 0xBC5A, 0x7CE8, 0xF4DD, 0x7CE9, 0xBC5B, 0x7CEA, 0xBC5C, + 0x7CEB, 0xBC5D, 0x7CEC, 0xBC5E, 0x7CED, 0xBC5F, 0x7CEE, 0xBC60, 0x7CEF, 0xC5B4, 0x7CF0, 0xBC61, 0x7CF1, 0xBC62, 0x7CF2, 0xBC63, + 0x7CF3, 0xBC64, 0x7CF4, 0xBC65, 0x7CF5, 0xBC66, 0x7CF6, 0xBC67, 0x7CF7, 0xBC68, 0x7CF8, 0xF4E9, 0x7CF9, 0xBC69, 0x7CFA, 0xBC6A, + 0x7CFB, 0xCFB5, 0x7CFC, 0xBC6B, 0x7CFD, 0xBC6C, 0x7CFE, 0xBC6D, 0x7CFF, 0xBC6E, 0x7D00, 0xBC6F, 0x7D01, 0xBC70, 0x7D02, 0xBC71, + 0x7D03, 0xBC72, 0x7D04, 0xBC73, 0x7D05, 0xBC74, 0x7D06, 0xBC75, 0x7D07, 0xBC76, 0x7D08, 0xBC77, 0x7D09, 0xBC78, 0x7D0A, 0xCEC9, + 0x7D0B, 0xBC79, 0x7D0C, 0xBC7A, 0x7D0D, 0xBC7B, 0x7D0E, 0xBC7C, 0x7D0F, 0xBC7D, 0x7D10, 0xBC7E, 0x7D11, 0xBC80, 0x7D12, 0xBC81, + 0x7D13, 0xBC82, 0x7D14, 0xBC83, 0x7D15, 0xBC84, 0x7D16, 0xBC85, 0x7D17, 0xBC86, 0x7D18, 0xBC87, 0x7D19, 0xBC88, 0x7D1A, 0xBC89, + 0x7D1B, 0xBC8A, 0x7D1C, 0xBC8B, 0x7D1D, 0xBC8C, 0x7D1E, 0xBC8D, 0x7D1F, 0xBC8E, 0x7D20, 0xCBD8, 0x7D21, 0xBC8F, 0x7D22, 0xCBF7, + 0x7D23, 0xBC90, 0x7D24, 0xBC91, 0x7D25, 0xBC92, 0x7D26, 0xBC93, 0x7D27, 0xBDF4, 0x7D28, 0xBC94, 0x7D29, 0xBC95, 0x7D2A, 0xBC96, + 0x7D2B, 0xD7CF, 0x7D2C, 0xBC97, 0x7D2D, 0xBC98, 0x7D2E, 0xBC99, 0x7D2F, 0xC0DB, 0x7D30, 0xBC9A, 0x7D31, 0xBC9B, 0x7D32, 0xBC9C, + 0x7D33, 0xBC9D, 0x7D34, 0xBC9E, 0x7D35, 0xBC9F, 0x7D36, 0xBCA0, 0x7D37, 0xBD40, 0x7D38, 0xBD41, 0x7D39, 0xBD42, 0x7D3A, 0xBD43, + 0x7D3B, 0xBD44, 0x7D3C, 0xBD45, 0x7D3D, 0xBD46, 0x7D3E, 0xBD47, 0x7D3F, 0xBD48, 0x7D40, 0xBD49, 0x7D41, 0xBD4A, 0x7D42, 0xBD4B, + 0x7D43, 0xBD4C, 0x7D44, 0xBD4D, 0x7D45, 0xBD4E, 0x7D46, 0xBD4F, 0x7D47, 0xBD50, 0x7D48, 0xBD51, 0x7D49, 0xBD52, 0x7D4A, 0xBD53, + 0x7D4B, 0xBD54, 0x7D4C, 0xBD55, 0x7D4D, 0xBD56, 0x7D4E, 0xBD57, 0x7D4F, 0xBD58, 0x7D50, 0xBD59, 0x7D51, 0xBD5A, 0x7D52, 0xBD5B, + 0x7D53, 0xBD5C, 0x7D54, 0xBD5D, 0x7D55, 0xBD5E, 0x7D56, 0xBD5F, 0x7D57, 0xBD60, 0x7D58, 0xBD61, 0x7D59, 0xBD62, 0x7D5A, 0xBD63, + 0x7D5B, 0xBD64, 0x7D5C, 0xBD65, 0x7D5D, 0xBD66, 0x7D5E, 0xBD67, 0x7D5F, 0xBD68, 0x7D60, 0xBD69, 0x7D61, 0xBD6A, 0x7D62, 0xBD6B, + 0x7D63, 0xBD6C, 0x7D64, 0xBD6D, 0x7D65, 0xBD6E, 0x7D66, 0xBD6F, 0x7D67, 0xBD70, 0x7D68, 0xBD71, 0x7D69, 0xBD72, 0x7D6A, 0xBD73, + 0x7D6B, 0xBD74, 0x7D6C, 0xBD75, 0x7D6D, 0xBD76, 0x7D6E, 0xD0F5, 0x7D6F, 0xBD77, 0x7D70, 0xBD78, 0x7D71, 0xBD79, 0x7D72, 0xBD7A, + 0x7D73, 0xBD7B, 0x7D74, 0xBD7C, 0x7D75, 0xBD7D, 0x7D76, 0xBD7E, 0x7D77, 0xF4EA, 0x7D78, 0xBD80, 0x7D79, 0xBD81, 0x7D7A, 0xBD82, + 0x7D7B, 0xBD83, 0x7D7C, 0xBD84, 0x7D7D, 0xBD85, 0x7D7E, 0xBD86, 0x7D7F, 0xBD87, 0x7D80, 0xBD88, 0x7D81, 0xBD89, 0x7D82, 0xBD8A, + 0x7D83, 0xBD8B, 0x7D84, 0xBD8C, 0x7D85, 0xBD8D, 0x7D86, 0xBD8E, 0x7D87, 0xBD8F, 0x7D88, 0xBD90, 0x7D89, 0xBD91, 0x7D8A, 0xBD92, + 0x7D8B, 0xBD93, 0x7D8C, 0xBD94, 0x7D8D, 0xBD95, 0x7D8E, 0xBD96, 0x7D8F, 0xBD97, 0x7D90, 0xBD98, 0x7D91, 0xBD99, 0x7D92, 0xBD9A, + 0x7D93, 0xBD9B, 0x7D94, 0xBD9C, 0x7D95, 0xBD9D, 0x7D96, 0xBD9E, 0x7D97, 0xBD9F, 0x7D98, 0xBDA0, 0x7D99, 0xBE40, 0x7D9A, 0xBE41, + 0x7D9B, 0xBE42, 0x7D9C, 0xBE43, 0x7D9D, 0xBE44, 0x7D9E, 0xBE45, 0x7D9F, 0xBE46, 0x7DA0, 0xBE47, 0x7DA1, 0xBE48, 0x7DA2, 0xBE49, + 0x7DA3, 0xBE4A, 0x7DA4, 0xBE4B, 0x7DA5, 0xBE4C, 0x7DA6, 0xF4EB, 0x7DA7, 0xBE4D, 0x7DA8, 0xBE4E, 0x7DA9, 0xBE4F, 0x7DAA, 0xBE50, + 0x7DAB, 0xBE51, 0x7DAC, 0xBE52, 0x7DAD, 0xBE53, 0x7DAE, 0xF4EC, 0x7DAF, 0xBE54, 0x7DB0, 0xBE55, 0x7DB1, 0xBE56, 0x7DB2, 0xBE57, + 0x7DB3, 0xBE58, 0x7DB4, 0xBE59, 0x7DB5, 0xBE5A, 0x7DB6, 0xBE5B, 0x7DB7, 0xBE5C, 0x7DB8, 0xBE5D, 0x7DB9, 0xBE5E, 0x7DBA, 0xBE5F, + 0x7DBB, 0xBE60, 0x7DBC, 0xBE61, 0x7DBD, 0xBE62, 0x7DBE, 0xBE63, 0x7DBF, 0xBE64, 0x7DC0, 0xBE65, 0x7DC1, 0xBE66, 0x7DC2, 0xBE67, + 0x7DC3, 0xBE68, 0x7DC4, 0xBE69, 0x7DC5, 0xBE6A, 0x7DC6, 0xBE6B, 0x7DC7, 0xBE6C, 0x7DC8, 0xBE6D, 0x7DC9, 0xBE6E, 0x7DCA, 0xBE6F, + 0x7DCB, 0xBE70, 0x7DCC, 0xBE71, 0x7DCD, 0xBE72, 0x7DCE, 0xBE73, 0x7DCF, 0xBE74, 0x7DD0, 0xBE75, 0x7DD1, 0xBE76, 0x7DD2, 0xBE77, + 0x7DD3, 0xBE78, 0x7DD4, 0xBE79, 0x7DD5, 0xBE7A, 0x7DD6, 0xBE7B, 0x7DD7, 0xBE7C, 0x7DD8, 0xBE7D, 0x7DD9, 0xBE7E, 0x7DDA, 0xBE80, + 0x7DDB, 0xBE81, 0x7DDC, 0xBE82, 0x7DDD, 0xBE83, 0x7DDE, 0xBE84, 0x7DDF, 0xBE85, 0x7DE0, 0xBE86, 0x7DE1, 0xBE87, 0x7DE2, 0xBE88, + 0x7DE3, 0xBE89, 0x7DE4, 0xBE8A, 0x7DE5, 0xBE8B, 0x7DE6, 0xBE8C, 0x7DE7, 0xBE8D, 0x7DE8, 0xBE8E, 0x7DE9, 0xBE8F, 0x7DEA, 0xBE90, + 0x7DEB, 0xBE91, 0x7DEC, 0xBE92, 0x7DED, 0xBE93, 0x7DEE, 0xBE94, 0x7DEF, 0xBE95, 0x7DF0, 0xBE96, 0x7DF1, 0xBE97, 0x7DF2, 0xBE98, + 0x7DF3, 0xBE99, 0x7DF4, 0xBE9A, 0x7DF5, 0xBE9B, 0x7DF6, 0xBE9C, 0x7DF7, 0xBE9D, 0x7DF8, 0xBE9E, 0x7DF9, 0xBE9F, 0x7DFA, 0xBEA0, + 0x7DFB, 0xBF40, 0x7DFC, 0xBF41, 0x7DFD, 0xBF42, 0x7DFE, 0xBF43, 0x7DFF, 0xBF44, 0x7E00, 0xBF45, 0x7E01, 0xBF46, 0x7E02, 0xBF47, + 0x7E03, 0xBF48, 0x7E04, 0xBF49, 0x7E05, 0xBF4A, 0x7E06, 0xBF4B, 0x7E07, 0xBF4C, 0x7E08, 0xBF4D, 0x7E09, 0xBF4E, 0x7E0A, 0xBF4F, + 0x7E0B, 0xBF50, 0x7E0C, 0xBF51, 0x7E0D, 0xBF52, 0x7E0E, 0xBF53, 0x7E0F, 0xBF54, 0x7E10, 0xBF55, 0x7E11, 0xBF56, 0x7E12, 0xBF57, + 0x7E13, 0xBF58, 0x7E14, 0xBF59, 0x7E15, 0xBF5A, 0x7E16, 0xBF5B, 0x7E17, 0xBF5C, 0x7E18, 0xBF5D, 0x7E19, 0xBF5E, 0x7E1A, 0xBF5F, + 0x7E1B, 0xBF60, 0x7E1C, 0xBF61, 0x7E1D, 0xBF62, 0x7E1E, 0xBF63, 0x7E1F, 0xBF64, 0x7E20, 0xBF65, 0x7E21, 0xBF66, 0x7E22, 0xBF67, + 0x7E23, 0xBF68, 0x7E24, 0xBF69, 0x7E25, 0xBF6A, 0x7E26, 0xBF6B, 0x7E27, 0xBF6C, 0x7E28, 0xBF6D, 0x7E29, 0xBF6E, 0x7E2A, 0xBF6F, + 0x7E2B, 0xBF70, 0x7E2C, 0xBF71, 0x7E2D, 0xBF72, 0x7E2E, 0xBF73, 0x7E2F, 0xBF74, 0x7E30, 0xBF75, 0x7E31, 0xBF76, 0x7E32, 0xBF77, + 0x7E33, 0xBF78, 0x7E34, 0xBF79, 0x7E35, 0xBF7A, 0x7E36, 0xBF7B, 0x7E37, 0xBF7C, 0x7E38, 0xBF7D, 0x7E39, 0xBF7E, 0x7E3A, 0xBF80, + 0x7E3B, 0xF7E3, 0x7E3C, 0xBF81, 0x7E3D, 0xBF82, 0x7E3E, 0xBF83, 0x7E3F, 0xBF84, 0x7E40, 0xBF85, 0x7E41, 0xB7B1, 0x7E42, 0xBF86, + 0x7E43, 0xBF87, 0x7E44, 0xBF88, 0x7E45, 0xBF89, 0x7E46, 0xBF8A, 0x7E47, 0xF4ED, 0x7E48, 0xBF8B, 0x7E49, 0xBF8C, 0x7E4A, 0xBF8D, + 0x7E4B, 0xBF8E, 0x7E4C, 0xBF8F, 0x7E4D, 0xBF90, 0x7E4E, 0xBF91, 0x7E4F, 0xBF92, 0x7E50, 0xBF93, 0x7E51, 0xBF94, 0x7E52, 0xBF95, + 0x7E53, 0xBF96, 0x7E54, 0xBF97, 0x7E55, 0xBF98, 0x7E56, 0xBF99, 0x7E57, 0xBF9A, 0x7E58, 0xBF9B, 0x7E59, 0xBF9C, 0x7E5A, 0xBF9D, + 0x7E5B, 0xBF9E, 0x7E5C, 0xBF9F, 0x7E5D, 0xBFA0, 0x7E5E, 0xC040, 0x7E5F, 0xC041, 0x7E60, 0xC042, 0x7E61, 0xC043, 0x7E62, 0xC044, + 0x7E63, 0xC045, 0x7E64, 0xC046, 0x7E65, 0xC047, 0x7E66, 0xC048, 0x7E67, 0xC049, 0x7E68, 0xC04A, 0x7E69, 0xC04B, 0x7E6A, 0xC04C, + 0x7E6B, 0xC04D, 0x7E6C, 0xC04E, 0x7E6D, 0xC04F, 0x7E6E, 0xC050, 0x7E6F, 0xC051, 0x7E70, 0xC052, 0x7E71, 0xC053, 0x7E72, 0xC054, + 0x7E73, 0xC055, 0x7E74, 0xC056, 0x7E75, 0xC057, 0x7E76, 0xC058, 0x7E77, 0xC059, 0x7E78, 0xC05A, 0x7E79, 0xC05B, 0x7E7A, 0xC05C, + 0x7E7B, 0xC05D, 0x7E7C, 0xC05E, 0x7E7D, 0xC05F, 0x7E7E, 0xC060, 0x7E7F, 0xC061, 0x7E80, 0xC062, 0x7E81, 0xC063, 0x7E82, 0xD7EB, + 0x7E83, 0xC064, 0x7E84, 0xC065, 0x7E85, 0xC066, 0x7E86, 0xC067, 0x7E87, 0xC068, 0x7E88, 0xC069, 0x7E89, 0xC06A, 0x7E8A, 0xC06B, + 0x7E8B, 0xC06C, 0x7E8C, 0xC06D, 0x7E8D, 0xC06E, 0x7E8E, 0xC06F, 0x7E8F, 0xC070, 0x7E90, 0xC071, 0x7E91, 0xC072, 0x7E92, 0xC073, + 0x7E93, 0xC074, 0x7E94, 0xC075, 0x7E95, 0xC076, 0x7E96, 0xC077, 0x7E97, 0xC078, 0x7E98, 0xC079, 0x7E99, 0xC07A, 0x7E9A, 0xC07B, + 0x7E9B, 0xF4EE, 0x7E9C, 0xC07C, 0x7E9D, 0xC07D, 0x7E9E, 0xC07E, 0x7E9F, 0xE6F9, 0x7EA0, 0xBEC0, 0x7EA1, 0xE6FA, 0x7EA2, 0xBAEC, + 0x7EA3, 0xE6FB, 0x7EA4, 0xCFCB, 0x7EA5, 0xE6FC, 0x7EA6, 0xD4BC, 0x7EA7, 0xBCB6, 0x7EA8, 0xE6FD, 0x7EA9, 0xE6FE, 0x7EAA, 0xBCCD, + 0x7EAB, 0xC8D2, 0x7EAC, 0xCEB3, 0x7EAD, 0xE7A1, 0x7EAE, 0xC080, 0x7EAF, 0xB4BF, 0x7EB0, 0xE7A2, 0x7EB1, 0xC9B4, 0x7EB2, 0xB8D9, + 0x7EB3, 0xC4C9, 0x7EB4, 0xC081, 0x7EB5, 0xD7DD, 0x7EB6, 0xC2DA, 0x7EB7, 0xB7D7, 0x7EB8, 0xD6BD, 0x7EB9, 0xCEC6, 0x7EBA, 0xB7C4, + 0x7EBB, 0xC082, 0x7EBC, 0xC083, 0x7EBD, 0xC5A6, 0x7EBE, 0xE7A3, 0x7EBF, 0xCFDF, 0x7EC0, 0xE7A4, 0x7EC1, 0xE7A5, 0x7EC2, 0xE7A6, + 0x7EC3, 0xC1B7, 0x7EC4, 0xD7E9, 0x7EC5, 0xC9F0, 0x7EC6, 0xCFB8, 0x7EC7, 0xD6AF, 0x7EC8, 0xD6D5, 0x7EC9, 0xE7A7, 0x7ECA, 0xB0ED, + 0x7ECB, 0xE7A8, 0x7ECC, 0xE7A9, 0x7ECD, 0xC9DC, 0x7ECE, 0xD2EF, 0x7ECF, 0xBEAD, 0x7ED0, 0xE7AA, 0x7ED1, 0xB0F3, 0x7ED2, 0xC8DE, + 0x7ED3, 0xBDE1, 0x7ED4, 0xE7AB, 0x7ED5, 0xC8C6, 0x7ED6, 0xC084, 0x7ED7, 0xE7AC, 0x7ED8, 0xBBE6, 0x7ED9, 0xB8F8, 0x7EDA, 0xD1A4, + 0x7EDB, 0xE7AD, 0x7EDC, 0xC2E7, 0x7EDD, 0xBEF8, 0x7EDE, 0xBDCA, 0x7EDF, 0xCDB3, 0x7EE0, 0xE7AE, 0x7EE1, 0xE7AF, 0x7EE2, 0xBEEE, + 0x7EE3, 0xD0E5, 0x7EE4, 0xC085, 0x7EE5, 0xCBE7, 0x7EE6, 0xCCD0, 0x7EE7, 0xBCCC, 0x7EE8, 0xE7B0, 0x7EE9, 0xBCA8, 0x7EEA, 0xD0F7, + 0x7EEB, 0xE7B1, 0x7EEC, 0xC086, 0x7EED, 0xD0F8, 0x7EEE, 0xE7B2, 0x7EEF, 0xE7B3, 0x7EF0, 0xB4C2, 0x7EF1, 0xE7B4, 0x7EF2, 0xE7B5, + 0x7EF3, 0xC9FE, 0x7EF4, 0xCEAC, 0x7EF5, 0xC3E0, 0x7EF6, 0xE7B7, 0x7EF7, 0xB1C1, 0x7EF8, 0xB3F1, 0x7EF9, 0xC087, 0x7EFA, 0xE7B8, + 0x7EFB, 0xE7B9, 0x7EFC, 0xD7DB, 0x7EFD, 0xD5C0, 0x7EFE, 0xE7BA, 0x7EFF, 0xC2CC, 0x7F00, 0xD7BA, 0x7F01, 0xE7BB, 0x7F02, 0xE7BC, + 0x7F03, 0xE7BD, 0x7F04, 0xBCEA, 0x7F05, 0xC3E5, 0x7F06, 0xC0C2, 0x7F07, 0xE7BE, 0x7F08, 0xE7BF, 0x7F09, 0xBCA9, 0x7F0A, 0xC088, + 0x7F0B, 0xE7C0, 0x7F0C, 0xE7C1, 0x7F0D, 0xE7B6, 0x7F0E, 0xB6D0, 0x7F0F, 0xE7C2, 0x7F10, 0xC089, 0x7F11, 0xE7C3, 0x7F12, 0xE7C4, + 0x7F13, 0xBBBA, 0x7F14, 0xB5DE, 0x7F15, 0xC2C6, 0x7F16, 0xB1E0, 0x7F17, 0xE7C5, 0x7F18, 0xD4B5, 0x7F19, 0xE7C6, 0x7F1A, 0xB8BF, + 0x7F1B, 0xE7C8, 0x7F1C, 0xE7C7, 0x7F1D, 0xB7EC, 0x7F1E, 0xC08A, 0x7F1F, 0xE7C9, 0x7F20, 0xB2F8, 0x7F21, 0xE7CA, 0x7F22, 0xE7CB, + 0x7F23, 0xE7CC, 0x7F24, 0xE7CD, 0x7F25, 0xE7CE, 0x7F26, 0xE7CF, 0x7F27, 0xE7D0, 0x7F28, 0xD3A7, 0x7F29, 0xCBF5, 0x7F2A, 0xE7D1, + 0x7F2B, 0xE7D2, 0x7F2C, 0xE7D3, 0x7F2D, 0xE7D4, 0x7F2E, 0xC9C9, 0x7F2F, 0xE7D5, 0x7F30, 0xE7D6, 0x7F31, 0xE7D7, 0x7F32, 0xE7D8, + 0x7F33, 0xE7D9, 0x7F34, 0xBDC9, 0x7F35, 0xE7DA, 0x7F36, 0xF3BE, 0x7F37, 0xC08B, 0x7F38, 0xB8D7, 0x7F39, 0xC08C, 0x7F3A, 0xC8B1, + 0x7F3B, 0xC08D, 0x7F3C, 0xC08E, 0x7F3D, 0xC08F, 0x7F3E, 0xC090, 0x7F3F, 0xC091, 0x7F40, 0xC092, 0x7F41, 0xC093, 0x7F42, 0xF3BF, + 0x7F43, 0xC094, 0x7F44, 0xF3C0, 0x7F45, 0xF3C1, 0x7F46, 0xC095, 0x7F47, 0xC096, 0x7F48, 0xC097, 0x7F49, 0xC098, 0x7F4A, 0xC099, + 0x7F4B, 0xC09A, 0x7F4C, 0xC09B, 0x7F4D, 0xC09C, 0x7F4E, 0xC09D, 0x7F4F, 0xC09E, 0x7F50, 0xB9DE, 0x7F51, 0xCDF8, 0x7F52, 0xC09F, + 0x7F53, 0xC0A0, 0x7F54, 0xD8E8, 0x7F55, 0xBAB1, 0x7F56, 0xC140, 0x7F57, 0xC2DE, 0x7F58, 0xEEB7, 0x7F59, 0xC141, 0x7F5A, 0xB7A3, + 0x7F5B, 0xC142, 0x7F5C, 0xC143, 0x7F5D, 0xC144, 0x7F5E, 0xC145, 0x7F5F, 0xEEB9, 0x7F60, 0xC146, 0x7F61, 0xEEB8, 0x7F62, 0xB0D5, + 0x7F63, 0xC147, 0x7F64, 0xC148, 0x7F65, 0xC149, 0x7F66, 0xC14A, 0x7F67, 0xC14B, 0x7F68, 0xEEBB, 0x7F69, 0xD5D6, 0x7F6A, 0xD7EF, + 0x7F6B, 0xC14C, 0x7F6C, 0xC14D, 0x7F6D, 0xC14E, 0x7F6E, 0xD6C3, 0x7F6F, 0xC14F, 0x7F70, 0xC150, 0x7F71, 0xEEBD, 0x7F72, 0xCAF0, + 0x7F73, 0xC151, 0x7F74, 0xEEBC, 0x7F75, 0xC152, 0x7F76, 0xC153, 0x7F77, 0xC154, 0x7F78, 0xC155, 0x7F79, 0xEEBE, 0x7F7A, 0xC156, + 0x7F7B, 0xC157, 0x7F7C, 0xC158, 0x7F7D, 0xC159, 0x7F7E, 0xEEC0, 0x7F7F, 0xC15A, 0x7F80, 0xC15B, 0x7F81, 0xEEBF, 0x7F82, 0xC15C, + 0x7F83, 0xC15D, 0x7F84, 0xC15E, 0x7F85, 0xC15F, 0x7F86, 0xC160, 0x7F87, 0xC161, 0x7F88, 0xC162, 0x7F89, 0xC163, 0x7F8A, 0xD1F2, + 0x7F8B, 0xC164, 0x7F8C, 0xC7BC, 0x7F8D, 0xC165, 0x7F8E, 0xC3C0, 0x7F8F, 0xC166, 0x7F90, 0xC167, 0x7F91, 0xC168, 0x7F92, 0xC169, + 0x7F93, 0xC16A, 0x7F94, 0xB8E1, 0x7F95, 0xC16B, 0x7F96, 0xC16C, 0x7F97, 0xC16D, 0x7F98, 0xC16E, 0x7F99, 0xC16F, 0x7F9A, 0xC1E7, + 0x7F9B, 0xC170, 0x7F9C, 0xC171, 0x7F9D, 0xF4C6, 0x7F9E, 0xD0DF, 0x7F9F, 0xF4C7, 0x7FA0, 0xC172, 0x7FA1, 0xCFDB, 0x7FA2, 0xC173, + 0x7FA3, 0xC174, 0x7FA4, 0xC8BA, 0x7FA5, 0xC175, 0x7FA6, 0xC176, 0x7FA7, 0xF4C8, 0x7FA8, 0xC177, 0x7FA9, 0xC178, 0x7FAA, 0xC179, + 0x7FAB, 0xC17A, 0x7FAC, 0xC17B, 0x7FAD, 0xC17C, 0x7FAE, 0xC17D, 0x7FAF, 0xF4C9, 0x7FB0, 0xF4CA, 0x7FB1, 0xC17E, 0x7FB2, 0xF4CB, + 0x7FB3, 0xC180, 0x7FB4, 0xC181, 0x7FB5, 0xC182, 0x7FB6, 0xC183, 0x7FB7, 0xC184, 0x7FB8, 0xD9FA, 0x7FB9, 0xB8FE, 0x7FBA, 0xC185, + 0x7FBB, 0xC186, 0x7FBC, 0xE5F1, 0x7FBD, 0xD3F0, 0x7FBE, 0xC187, 0x7FBF, 0xF4E0, 0x7FC0, 0xC188, 0x7FC1, 0xCECC, 0x7FC2, 0xC189, + 0x7FC3, 0xC18A, 0x7FC4, 0xC18B, 0x7FC5, 0xB3E1, 0x7FC6, 0xC18C, 0x7FC7, 0xC18D, 0x7FC8, 0xC18E, 0x7FC9, 0xC18F, 0x7FCA, 0xF1B4, + 0x7FCB, 0xC190, 0x7FCC, 0xD2EE, 0x7FCD, 0xC191, 0x7FCE, 0xF4E1, 0x7FCF, 0xC192, 0x7FD0, 0xC193, 0x7FD1, 0xC194, 0x7FD2, 0xC195, + 0x7FD3, 0xC196, 0x7FD4, 0xCFE8, 0x7FD5, 0xF4E2, 0x7FD6, 0xC197, 0x7FD7, 0xC198, 0x7FD8, 0xC7CC, 0x7FD9, 0xC199, 0x7FDA, 0xC19A, + 0x7FDB, 0xC19B, 0x7FDC, 0xC19C, 0x7FDD, 0xC19D, 0x7FDE, 0xC19E, 0x7FDF, 0xB5D4, 0x7FE0, 0xB4E4, 0x7FE1, 0xF4E4, 0x7FE2, 0xC19F, + 0x7FE3, 0xC1A0, 0x7FE4, 0xC240, 0x7FE5, 0xF4E3, 0x7FE6, 0xF4E5, 0x7FE7, 0xC241, 0x7FE8, 0xC242, 0x7FE9, 0xF4E6, 0x7FEA, 0xC243, + 0x7FEB, 0xC244, 0x7FEC, 0xC245, 0x7FED, 0xC246, 0x7FEE, 0xF4E7, 0x7FEF, 0xC247, 0x7FF0, 0xBAB2, 0x7FF1, 0xB0BF, 0x7FF2, 0xC248, + 0x7FF3, 0xF4E8, 0x7FF4, 0xC249, 0x7FF5, 0xC24A, 0x7FF6, 0xC24B, 0x7FF7, 0xC24C, 0x7FF8, 0xC24D, 0x7FF9, 0xC24E, 0x7FFA, 0xC24F, + 0x7FFB, 0xB7AD, 0x7FFC, 0xD2ED, 0x7FFD, 0xC250, 0x7FFE, 0xC251, 0x7FFF, 0xC252, 0x8000, 0xD2AB, 0x8001, 0xC0CF, 0x8002, 0xC253, + 0x8003, 0xBFBC, 0x8004, 0xEBA3, 0x8005, 0xD5DF, 0x8006, 0xEAC8, 0x8007, 0xC254, 0x8008, 0xC255, 0x8009, 0xC256, 0x800A, 0xC257, + 0x800B, 0xF1F3, 0x800C, 0xB6F8, 0x800D, 0xCBA3, 0x800E, 0xC258, 0x800F, 0xC259, 0x8010, 0xC4CD, 0x8011, 0xC25A, 0x8012, 0xF1E7, + 0x8013, 0xC25B, 0x8014, 0xF1E8, 0x8015, 0xB8FB, 0x8016, 0xF1E9, 0x8017, 0xBAC4, 0x8018, 0xD4C5, 0x8019, 0xB0D2, 0x801A, 0xC25C, + 0x801B, 0xC25D, 0x801C, 0xF1EA, 0x801D, 0xC25E, 0x801E, 0xC25F, 0x801F, 0xC260, 0x8020, 0xF1EB, 0x8021, 0xC261, 0x8022, 0xF1EC, + 0x8023, 0xC262, 0x8024, 0xC263, 0x8025, 0xF1ED, 0x8026, 0xF1EE, 0x8027, 0xF1EF, 0x8028, 0xF1F1, 0x8029, 0xF1F0, 0x802A, 0xC5D5, + 0x802B, 0xC264, 0x802C, 0xC265, 0x802D, 0xC266, 0x802E, 0xC267, 0x802F, 0xC268, 0x8030, 0xC269, 0x8031, 0xF1F2, 0x8032, 0xC26A, + 0x8033, 0xB6FA, 0x8034, 0xC26B, 0x8035, 0xF1F4, 0x8036, 0xD2AE, 0x8037, 0xDEC7, 0x8038, 0xCBCA, 0x8039, 0xC26C, 0x803A, 0xC26D, + 0x803B, 0xB3DC, 0x803C, 0xC26E, 0x803D, 0xB5A2, 0x803E, 0xC26F, 0x803F, 0xB9A2, 0x8040, 0xC270, 0x8041, 0xC271, 0x8042, 0xC4F4, + 0x8043, 0xF1F5, 0x8044, 0xC272, 0x8045, 0xC273, 0x8046, 0xF1F6, 0x8047, 0xC274, 0x8048, 0xC275, 0x8049, 0xC276, 0x804A, 0xC1C4, + 0x804B, 0xC1FB, 0x804C, 0xD6B0, 0x804D, 0xF1F7, 0x804E, 0xC277, 0x804F, 0xC278, 0x8050, 0xC279, 0x8051, 0xC27A, 0x8052, 0xF1F8, + 0x8053, 0xC27B, 0x8054, 0xC1AA, 0x8055, 0xC27C, 0x8056, 0xC27D, 0x8057, 0xC27E, 0x8058, 0xC6B8, 0x8059, 0xC280, 0x805A, 0xBEDB, + 0x805B, 0xC281, 0x805C, 0xC282, 0x805D, 0xC283, 0x805E, 0xC284, 0x805F, 0xC285, 0x8060, 0xC286, 0x8061, 0xC287, 0x8062, 0xC288, + 0x8063, 0xC289, 0x8064, 0xC28A, 0x8065, 0xC28B, 0x8066, 0xC28C, 0x8067, 0xC28D, 0x8068, 0xC28E, 0x8069, 0xF1F9, 0x806A, 0xB4CF, + 0x806B, 0xC28F, 0x806C, 0xC290, 0x806D, 0xC291, 0x806E, 0xC292, 0x806F, 0xC293, 0x8070, 0xC294, 0x8071, 0xF1FA, 0x8072, 0xC295, + 0x8073, 0xC296, 0x8074, 0xC297, 0x8075, 0xC298, 0x8076, 0xC299, 0x8077, 0xC29A, 0x8078, 0xC29B, 0x8079, 0xC29C, 0x807A, 0xC29D, + 0x807B, 0xC29E, 0x807C, 0xC29F, 0x807D, 0xC2A0, 0x807E, 0xC340, 0x807F, 0xEDB2, 0x8080, 0xEDB1, 0x8081, 0xC341, 0x8082, 0xC342, + 0x8083, 0xCBE0, 0x8084, 0xD2DE, 0x8085, 0xC343, 0x8086, 0xCBC1, 0x8087, 0xD5D8, 0x8088, 0xC344, 0x8089, 0xC8E2, 0x808A, 0xC345, + 0x808B, 0xC0DF, 0x808C, 0xBCA1, 0x808D, 0xC346, 0x808E, 0xC347, 0x808F, 0xC348, 0x8090, 0xC349, 0x8091, 0xC34A, 0x8092, 0xC34B, + 0x8093, 0xEBC1, 0x8094, 0xC34C, 0x8095, 0xC34D, 0x8096, 0xD0A4, 0x8097, 0xC34E, 0x8098, 0xD6E2, 0x8099, 0xC34F, 0x809A, 0xB6C7, + 0x809B, 0xB8D8, 0x809C, 0xEBC0, 0x809D, 0xB8CE, 0x809E, 0xC350, 0x809F, 0xEBBF, 0x80A0, 0xB3A6, 0x80A1, 0xB9C9, 0x80A2, 0xD6AB, + 0x80A3, 0xC351, 0x80A4, 0xB7F4, 0x80A5, 0xB7CA, 0x80A6, 0xC352, 0x80A7, 0xC353, 0x80A8, 0xC354, 0x80A9, 0xBCE7, 0x80AA, 0xB7BE, + 0x80AB, 0xEBC6, 0x80AC, 0xC355, 0x80AD, 0xEBC7, 0x80AE, 0xB0B9, 0x80AF, 0xBFCF, 0x80B0, 0xC356, 0x80B1, 0xEBC5, 0x80B2, 0xD3FD, + 0x80B3, 0xC357, 0x80B4, 0xEBC8, 0x80B5, 0xC358, 0x80B6, 0xC359, 0x80B7, 0xEBC9, 0x80B8, 0xC35A, 0x80B9, 0xC35B, 0x80BA, 0xB7CE, + 0x80BB, 0xC35C, 0x80BC, 0xEBC2, 0x80BD, 0xEBC4, 0x80BE, 0xC9F6, 0x80BF, 0xD6D7, 0x80C0, 0xD5CD, 0x80C1, 0xD0B2, 0x80C2, 0xEBCF, + 0x80C3, 0xCEB8, 0x80C4, 0xEBD0, 0x80C5, 0xC35D, 0x80C6, 0xB5A8, 0x80C7, 0xC35E, 0x80C8, 0xC35F, 0x80C9, 0xC360, 0x80CA, 0xC361, + 0x80CB, 0xC362, 0x80CC, 0xB1B3, 0x80CD, 0xEBD2, 0x80CE, 0xCCA5, 0x80CF, 0xC363, 0x80D0, 0xC364, 0x80D1, 0xC365, 0x80D2, 0xC366, + 0x80D3, 0xC367, 0x80D4, 0xC368, 0x80D5, 0xC369, 0x80D6, 0xC5D6, 0x80D7, 0xEBD3, 0x80D8, 0xC36A, 0x80D9, 0xEBD1, 0x80DA, 0xC5DF, + 0x80DB, 0xEBCE, 0x80DC, 0xCAA4, 0x80DD, 0xEBD5, 0x80DE, 0xB0FB, 0x80DF, 0xC36B, 0x80E0, 0xC36C, 0x80E1, 0xBAFA, 0x80E2, 0xC36D, + 0x80E3, 0xC36E, 0x80E4, 0xD8B7, 0x80E5, 0xF1E3, 0x80E6, 0xC36F, 0x80E7, 0xEBCA, 0x80E8, 0xEBCB, 0x80E9, 0xEBCC, 0x80EA, 0xEBCD, + 0x80EB, 0xEBD6, 0x80EC, 0xE6C0, 0x80ED, 0xEBD9, 0x80EE, 0xC370, 0x80EF, 0xBFE8, 0x80F0, 0xD2C8, 0x80F1, 0xEBD7, 0x80F2, 0xEBDC, + 0x80F3, 0xB8EC, 0x80F4, 0xEBD8, 0x80F5, 0xC371, 0x80F6, 0xBDBA, 0x80F7, 0xC372, 0x80F8, 0xD0D8, 0x80F9, 0xC373, 0x80FA, 0xB0B7, + 0x80FB, 0xC374, 0x80FC, 0xEBDD, 0x80FD, 0xC4DC, 0x80FE, 0xC375, 0x80FF, 0xC376, 0x8100, 0xC377, 0x8101, 0xC378, 0x8102, 0xD6AC, + 0x8103, 0xC379, 0x8104, 0xC37A, 0x8105, 0xC37B, 0x8106, 0xB4E0, 0x8107, 0xC37C, 0x8108, 0xC37D, 0x8109, 0xC2F6, 0x810A, 0xBCB9, + 0x810B, 0xC37E, 0x810C, 0xC380, 0x810D, 0xEBDA, 0x810E, 0xEBDB, 0x810F, 0xD4E0, 0x8110, 0xC6EA, 0x8111, 0xC4D4, 0x8112, 0xEBDF, + 0x8113, 0xC5A7, 0x8114, 0xD9F5, 0x8115, 0xC381, 0x8116, 0xB2B1, 0x8117, 0xC382, 0x8118, 0xEBE4, 0x8119, 0xC383, 0x811A, 0xBDC5, + 0x811B, 0xC384, 0x811C, 0xC385, 0x811D, 0xC386, 0x811E, 0xEBE2, 0x811F, 0xC387, 0x8120, 0xC388, 0x8121, 0xC389, 0x8122, 0xC38A, + 0x8123, 0xC38B, 0x8124, 0xC38C, 0x8125, 0xC38D, 0x8126, 0xC38E, 0x8127, 0xC38F, 0x8128, 0xC390, 0x8129, 0xC391, 0x812A, 0xC392, + 0x812B, 0xC393, 0x812C, 0xEBE3, 0x812D, 0xC394, 0x812E, 0xC395, 0x812F, 0xB8AC, 0x8130, 0xC396, 0x8131, 0xCDD1, 0x8132, 0xEBE5, + 0x8133, 0xC397, 0x8134, 0xC398, 0x8135, 0xC399, 0x8136, 0xEBE1, 0x8137, 0xC39A, 0x8138, 0xC1B3, 0x8139, 0xC39B, 0x813A, 0xC39C, + 0x813B, 0xC39D, 0x813C, 0xC39E, 0x813D, 0xC39F, 0x813E, 0xC6A2, 0x813F, 0xC3A0, 0x8140, 0xC440, 0x8141, 0xC441, 0x8142, 0xC442, + 0x8143, 0xC443, 0x8144, 0xC444, 0x8145, 0xC445, 0x8146, 0xCCF3, 0x8147, 0xC446, 0x8148, 0xEBE6, 0x8149, 0xC447, 0x814A, 0xC0B0, + 0x814B, 0xD2B8, 0x814C, 0xEBE7, 0x814D, 0xC448, 0x814E, 0xC449, 0x814F, 0xC44A, 0x8150, 0xB8AF, 0x8151, 0xB8AD, 0x8152, 0xC44B, + 0x8153, 0xEBE8, 0x8154, 0xC7BB, 0x8155, 0xCDF3, 0x8156, 0xC44C, 0x8157, 0xC44D, 0x8158, 0xC44E, 0x8159, 0xEBEA, 0x815A, 0xEBEB, + 0x815B, 0xC44F, 0x815C, 0xC450, 0x815D, 0xC451, 0x815E, 0xC452, 0x815F, 0xC453, 0x8160, 0xEBED, 0x8161, 0xC454, 0x8162, 0xC455, + 0x8163, 0xC456, 0x8164, 0xC457, 0x8165, 0xD0C8, 0x8166, 0xC458, 0x8167, 0xEBF2, 0x8168, 0xC459, 0x8169, 0xEBEE, 0x816A, 0xC45A, + 0x816B, 0xC45B, 0x816C, 0xC45C, 0x816D, 0xEBF1, 0x816E, 0xC8F9, 0x816F, 0xC45D, 0x8170, 0xD1FC, 0x8171, 0xEBEC, 0x8172, 0xC45E, + 0x8173, 0xC45F, 0x8174, 0xEBE9, 0x8175, 0xC460, 0x8176, 0xC461, 0x8177, 0xC462, 0x8178, 0xC463, 0x8179, 0xB8B9, 0x817A, 0xCFD9, + 0x817B, 0xC4E5, 0x817C, 0xEBEF, 0x817D, 0xEBF0, 0x817E, 0xCCDA, 0x817F, 0xCDC8, 0x8180, 0xB0F2, 0x8181, 0xC464, 0x8182, 0xEBF6, + 0x8183, 0xC465, 0x8184, 0xC466, 0x8185, 0xC467, 0x8186, 0xC468, 0x8187, 0xC469, 0x8188, 0xEBF5, 0x8189, 0xC46A, 0x818A, 0xB2B2, + 0x818B, 0xC46B, 0x818C, 0xC46C, 0x818D, 0xC46D, 0x818E, 0xC46E, 0x818F, 0xB8E0, 0x8190, 0xC46F, 0x8191, 0xEBF7, 0x8192, 0xC470, + 0x8193, 0xC471, 0x8194, 0xC472, 0x8195, 0xC473, 0x8196, 0xC474, 0x8197, 0xC475, 0x8198, 0xB1EC, 0x8199, 0xC476, 0x819A, 0xC477, + 0x819B, 0xCCC5, 0x819C, 0xC4A4, 0x819D, 0xCFA5, 0x819E, 0xC478, 0x819F, 0xC479, 0x81A0, 0xC47A, 0x81A1, 0xC47B, 0x81A2, 0xC47C, + 0x81A3, 0xEBF9, 0x81A4, 0xC47D, 0x81A5, 0xC47E, 0x81A6, 0xECA2, 0x81A7, 0xC480, 0x81A8, 0xC5F2, 0x81A9, 0xC481, 0x81AA, 0xEBFA, + 0x81AB, 0xC482, 0x81AC, 0xC483, 0x81AD, 0xC484, 0x81AE, 0xC485, 0x81AF, 0xC486, 0x81B0, 0xC487, 0x81B1, 0xC488, 0x81B2, 0xC489, + 0x81B3, 0xC9C5, 0x81B4, 0xC48A, 0x81B5, 0xC48B, 0x81B6, 0xC48C, 0x81B7, 0xC48D, 0x81B8, 0xC48E, 0x81B9, 0xC48F, 0x81BA, 0xE2DF, + 0x81BB, 0xEBFE, 0x81BC, 0xC490, 0x81BD, 0xC491, 0x81BE, 0xC492, 0x81BF, 0xC493, 0x81C0, 0xCDCE, 0x81C1, 0xECA1, 0x81C2, 0xB1DB, + 0x81C3, 0xD3B7, 0x81C4, 0xC494, 0x81C5, 0xC495, 0x81C6, 0xD2DC, 0x81C7, 0xC496, 0x81C8, 0xC497, 0x81C9, 0xC498, 0x81CA, 0xEBFD, + 0x81CB, 0xC499, 0x81CC, 0xEBFB, 0x81CD, 0xC49A, 0x81CE, 0xC49B, 0x81CF, 0xC49C, 0x81D0, 0xC49D, 0x81D1, 0xC49E, 0x81D2, 0xC49F, + 0x81D3, 0xC4A0, 0x81D4, 0xC540, 0x81D5, 0xC541, 0x81D6, 0xC542, 0x81D7, 0xC543, 0x81D8, 0xC544, 0x81D9, 0xC545, 0x81DA, 0xC546, + 0x81DB, 0xC547, 0x81DC, 0xC548, 0x81DD, 0xC549, 0x81DE, 0xC54A, 0x81DF, 0xC54B, 0x81E0, 0xC54C, 0x81E1, 0xC54D, 0x81E2, 0xC54E, + 0x81E3, 0xB3BC, 0x81E4, 0xC54F, 0x81E5, 0xC550, 0x81E6, 0xC551, 0x81E7, 0xEAB0, 0x81E8, 0xC552, 0x81E9, 0xC553, 0x81EA, 0xD7D4, + 0x81EB, 0xC554, 0x81EC, 0xF4AB, 0x81ED, 0xB3F4, 0x81EE, 0xC555, 0x81EF, 0xC556, 0x81F0, 0xC557, 0x81F1, 0xC558, 0x81F2, 0xC559, + 0x81F3, 0xD6C1, 0x81F4, 0xD6C2, 0x81F5, 0xC55A, 0x81F6, 0xC55B, 0x81F7, 0xC55C, 0x81F8, 0xC55D, 0x81F9, 0xC55E, 0x81FA, 0xC55F, + 0x81FB, 0xD5E9, 0x81FC, 0xBECA, 0x81FD, 0xC560, 0x81FE, 0xF4A7, 0x81FF, 0xC561, 0x8200, 0xD2A8, 0x8201, 0xF4A8, 0x8202, 0xF4A9, + 0x8203, 0xC562, 0x8204, 0xF4AA, 0x8205, 0xBECB, 0x8206, 0xD3DF, 0x8207, 0xC563, 0x8208, 0xC564, 0x8209, 0xC565, 0x820A, 0xC566, + 0x820B, 0xC567, 0x820C, 0xC9E0, 0x820D, 0xC9E1, 0x820E, 0xC568, 0x820F, 0xC569, 0x8210, 0xF3C2, 0x8211, 0xC56A, 0x8212, 0xCAE6, + 0x8213, 0xC56B, 0x8214, 0xCCF2, 0x8215, 0xC56C, 0x8216, 0xC56D, 0x8217, 0xC56E, 0x8218, 0xC56F, 0x8219, 0xC570, 0x821A, 0xC571, + 0x821B, 0xE2B6, 0x821C, 0xCBB4, 0x821D, 0xC572, 0x821E, 0xCEE8, 0x821F, 0xD6DB, 0x8220, 0xC573, 0x8221, 0xF4AD, 0x8222, 0xF4AE, + 0x8223, 0xF4AF, 0x8224, 0xC574, 0x8225, 0xC575, 0x8226, 0xC576, 0x8227, 0xC577, 0x8228, 0xF4B2, 0x8229, 0xC578, 0x822A, 0xBABD, + 0x822B, 0xF4B3, 0x822C, 0xB0E3, 0x822D, 0xF4B0, 0x822E, 0xC579, 0x822F, 0xF4B1, 0x8230, 0xBDA2, 0x8231, 0xB2D5, 0x8232, 0xC57A, + 0x8233, 0xF4B6, 0x8234, 0xF4B7, 0x8235, 0xB6E6, 0x8236, 0xB2B0, 0x8237, 0xCFCF, 0x8238, 0xF4B4, 0x8239, 0xB4AC, 0x823A, 0xC57B, + 0x823B, 0xF4B5, 0x823C, 0xC57C, 0x823D, 0xC57D, 0x823E, 0xF4B8, 0x823F, 0xC57E, 0x8240, 0xC580, 0x8241, 0xC581, 0x8242, 0xC582, + 0x8243, 0xC583, 0x8244, 0xF4B9, 0x8245, 0xC584, 0x8246, 0xC585, 0x8247, 0xCDA7, 0x8248, 0xC586, 0x8249, 0xF4BA, 0x824A, 0xC587, + 0x824B, 0xF4BB, 0x824C, 0xC588, 0x824D, 0xC589, 0x824E, 0xC58A, 0x824F, 0xF4BC, 0x8250, 0xC58B, 0x8251, 0xC58C, 0x8252, 0xC58D, + 0x8253, 0xC58E, 0x8254, 0xC58F, 0x8255, 0xC590, 0x8256, 0xC591, 0x8257, 0xC592, 0x8258, 0xCBD2, 0x8259, 0xC593, 0x825A, 0xF4BD, + 0x825B, 0xC594, 0x825C, 0xC595, 0x825D, 0xC596, 0x825E, 0xC597, 0x825F, 0xF4BE, 0x8260, 0xC598, 0x8261, 0xC599, 0x8262, 0xC59A, + 0x8263, 0xC59B, 0x8264, 0xC59C, 0x8265, 0xC59D, 0x8266, 0xC59E, 0x8267, 0xC59F, 0x8268, 0xF4BF, 0x8269, 0xC5A0, 0x826A, 0xC640, + 0x826B, 0xC641, 0x826C, 0xC642, 0x826D, 0xC643, 0x826E, 0xF4DE, 0x826F, 0xC1BC, 0x8270, 0xBCE8, 0x8271, 0xC644, 0x8272, 0xC9AB, + 0x8273, 0xD1DE, 0x8274, 0xE5F5, 0x8275, 0xC645, 0x8276, 0xC646, 0x8277, 0xC647, 0x8278, 0xC648, 0x8279, 0xDCB3, 0x827A, 0xD2D5, + 0x827B, 0xC649, 0x827C, 0xC64A, 0x827D, 0xDCB4, 0x827E, 0xB0AC, 0x827F, 0xDCB5, 0x8280, 0xC64B, 0x8281, 0xC64C, 0x8282, 0xBDDA, + 0x8283, 0xC64D, 0x8284, 0xDCB9, 0x8285, 0xC64E, 0x8286, 0xC64F, 0x8287, 0xC650, 0x8288, 0xD8C2, 0x8289, 0xC651, 0x828A, 0xDCB7, + 0x828B, 0xD3F3, 0x828C, 0xC652, 0x828D, 0xC9D6, 0x828E, 0xDCBA, 0x828F, 0xDCB6, 0x8290, 0xC653, 0x8291, 0xDCBB, 0x8292, 0xC3A2, + 0x8293, 0xC654, 0x8294, 0xC655, 0x8295, 0xC656, 0x8296, 0xC657, 0x8297, 0xDCBC, 0x8298, 0xDCC5, 0x8299, 0xDCBD, 0x829A, 0xC658, + 0x829B, 0xC659, 0x829C, 0xCEDF, 0x829D, 0xD6A5, 0x829E, 0xC65A, 0x829F, 0xDCCF, 0x82A0, 0xC65B, 0x82A1, 0xDCCD, 0x82A2, 0xC65C, + 0x82A3, 0xC65D, 0x82A4, 0xDCD2, 0x82A5, 0xBDE6, 0x82A6, 0xC2AB, 0x82A7, 0xC65E, 0x82A8, 0xDCB8, 0x82A9, 0xDCCB, 0x82AA, 0xDCCE, + 0x82AB, 0xDCBE, 0x82AC, 0xB7D2, 0x82AD, 0xB0C5, 0x82AE, 0xDCC7, 0x82AF, 0xD0BE, 0x82B0, 0xDCC1, 0x82B1, 0xBBA8, 0x82B2, 0xC65F, + 0x82B3, 0xB7BC, 0x82B4, 0xDCCC, 0x82B5, 0xC660, 0x82B6, 0xC661, 0x82B7, 0xDCC6, 0x82B8, 0xDCBF, 0x82B9, 0xC7DB, 0x82BA, 0xC662, + 0x82BB, 0xC663, 0x82BC, 0xC664, 0x82BD, 0xD1BF, 0x82BE, 0xDCC0, 0x82BF, 0xC665, 0x82C0, 0xC666, 0x82C1, 0xDCCA, 0x82C2, 0xC667, + 0x82C3, 0xC668, 0x82C4, 0xDCD0, 0x82C5, 0xC669, 0x82C6, 0xC66A, 0x82C7, 0xCEAD, 0x82C8, 0xDCC2, 0x82C9, 0xC66B, 0x82CA, 0xDCC3, + 0x82CB, 0xDCC8, 0x82CC, 0xDCC9, 0x82CD, 0xB2D4, 0x82CE, 0xDCD1, 0x82CF, 0xCBD5, 0x82D0, 0xC66C, 0x82D1, 0xD4B7, 0x82D2, 0xDCDB, + 0x82D3, 0xDCDF, 0x82D4, 0xCCA6, 0x82D5, 0xDCE6, 0x82D6, 0xC66D, 0x82D7, 0xC3E7, 0x82D8, 0xDCDC, 0x82D9, 0xC66E, 0x82DA, 0xC66F, + 0x82DB, 0xBFC1, 0x82DC, 0xDCD9, 0x82DD, 0xC670, 0x82DE, 0xB0FA, 0x82DF, 0xB9B6, 0x82E0, 0xDCE5, 0x82E1, 0xDCD3, 0x82E2, 0xC671, + 0x82E3, 0xDCC4, 0x82E4, 0xDCD6, 0x82E5, 0xC8F4, 0x82E6, 0xBFE0, 0x82E7, 0xC672, 0x82E8, 0xC673, 0x82E9, 0xC674, 0x82EA, 0xC675, + 0x82EB, 0xC9BB, 0x82EC, 0xC676, 0x82ED, 0xC677, 0x82EE, 0xC678, 0x82EF, 0xB1BD, 0x82F0, 0xC679, 0x82F1, 0xD3A2, 0x82F2, 0xC67A, + 0x82F3, 0xC67B, 0x82F4, 0xDCDA, 0x82F5, 0xC67C, 0x82F6, 0xC67D, 0x82F7, 0xDCD5, 0x82F8, 0xC67E, 0x82F9, 0xC6BB, 0x82FA, 0xC680, + 0x82FB, 0xDCDE, 0x82FC, 0xC681, 0x82FD, 0xC682, 0x82FE, 0xC683, 0x82FF, 0xC684, 0x8300, 0xC685, 0x8301, 0xD7C2, 0x8302, 0xC3AF, + 0x8303, 0xB7B6, 0x8304, 0xC7D1, 0x8305, 0xC3A9, 0x8306, 0xDCE2, 0x8307, 0xDCD8, 0x8308, 0xDCEB, 0x8309, 0xDCD4, 0x830A, 0xC686, + 0x830B, 0xC687, 0x830C, 0xDCDD, 0x830D, 0xC688, 0x830E, 0xBEA5, 0x830F, 0xDCD7, 0x8310, 0xC689, 0x8311, 0xDCE0, 0x8312, 0xC68A, + 0x8313, 0xC68B, 0x8314, 0xDCE3, 0x8315, 0xDCE4, 0x8316, 0xC68C, 0x8317, 0xDCF8, 0x8318, 0xC68D, 0x8319, 0xC68E, 0x831A, 0xDCE1, + 0x831B, 0xDDA2, 0x831C, 0xDCE7, 0x831D, 0xC68F, 0x831E, 0xC690, 0x831F, 0xC691, 0x8320, 0xC692, 0x8321, 0xC693, 0x8322, 0xC694, + 0x8323, 0xC695, 0x8324, 0xC696, 0x8325, 0xC697, 0x8326, 0xC698, 0x8327, 0xBCEB, 0x8328, 0xB4C4, 0x8329, 0xC699, 0x832A, 0xC69A, + 0x832B, 0xC3A3, 0x832C, 0xB2E7, 0x832D, 0xDCFA, 0x832E, 0xC69B, 0x832F, 0xDCF2, 0x8330, 0xC69C, 0x8331, 0xDCEF, 0x8332, 0xC69D, + 0x8333, 0xDCFC, 0x8334, 0xDCEE, 0x8335, 0xD2F0, 0x8336, 0xB2E8, 0x8337, 0xC69E, 0x8338, 0xC8D7, 0x8339, 0xC8E3, 0x833A, 0xDCFB, + 0x833B, 0xC69F, 0x833C, 0xDCED, 0x833D, 0xC6A0, 0x833E, 0xC740, 0x833F, 0xC741, 0x8340, 0xDCF7, 0x8341, 0xC742, 0x8342, 0xC743, + 0x8343, 0xDCF5, 0x8344, 0xC744, 0x8345, 0xC745, 0x8346, 0xBEA3, 0x8347, 0xDCF4, 0x8348, 0xC746, 0x8349, 0xB2DD, 0x834A, 0xC747, + 0x834B, 0xC748, 0x834C, 0xC749, 0x834D, 0xC74A, 0x834E, 0xC74B, 0x834F, 0xDCF3, 0x8350, 0xBCF6, 0x8351, 0xDCE8, 0x8352, 0xBBC4, + 0x8353, 0xC74C, 0x8354, 0xC0F3, 0x8355, 0xC74D, 0x8356, 0xC74E, 0x8357, 0xC74F, 0x8358, 0xC750, 0x8359, 0xC751, 0x835A, 0xBCD4, + 0x835B, 0xDCE9, 0x835C, 0xDCEA, 0x835D, 0xC752, 0x835E, 0xDCF1, 0x835F, 0xDCF6, 0x8360, 0xDCF9, 0x8361, 0xB5B4, 0x8362, 0xC753, + 0x8363, 0xC8D9, 0x8364, 0xBBE7, 0x8365, 0xDCFE, 0x8366, 0xDCFD, 0x8367, 0xD3AB, 0x8368, 0xDDA1, 0x8369, 0xDDA3, 0x836A, 0xDDA5, + 0x836B, 0xD2F1, 0x836C, 0xDDA4, 0x836D, 0xDDA6, 0x836E, 0xDDA7, 0x836F, 0xD2A9, 0x8370, 0xC754, 0x8371, 0xC755, 0x8372, 0xC756, + 0x8373, 0xC757, 0x8374, 0xC758, 0x8375, 0xC759, 0x8376, 0xC75A, 0x8377, 0xBAC9, 0x8378, 0xDDA9, 0x8379, 0xC75B, 0x837A, 0xC75C, + 0x837B, 0xDDB6, 0x837C, 0xDDB1, 0x837D, 0xDDB4, 0x837E, 0xC75D, 0x837F, 0xC75E, 0x8380, 0xC75F, 0x8381, 0xC760, 0x8382, 0xC761, + 0x8383, 0xC762, 0x8384, 0xC763, 0x8385, 0xDDB0, 0x8386, 0xC6CE, 0x8387, 0xC764, 0x8388, 0xC765, 0x8389, 0xC0F2, 0x838A, 0xC766, + 0x838B, 0xC767, 0x838C, 0xC768, 0x838D, 0xC769, 0x838E, 0xC9AF, 0x838F, 0xC76A, 0x8390, 0xC76B, 0x8391, 0xC76C, 0x8392, 0xDCEC, + 0x8393, 0xDDAE, 0x8394, 0xC76D, 0x8395, 0xC76E, 0x8396, 0xC76F, 0x8397, 0xC770, 0x8398, 0xDDB7, 0x8399, 0xC771, 0x839A, 0xC772, + 0x839B, 0xDCF0, 0x839C, 0xDDAF, 0x839D, 0xC773, 0x839E, 0xDDB8, 0x839F, 0xC774, 0x83A0, 0xDDAC, 0x83A1, 0xC775, 0x83A2, 0xC776, + 0x83A3, 0xC777, 0x83A4, 0xC778, 0x83A5, 0xC779, 0x83A6, 0xC77A, 0x83A7, 0xC77B, 0x83A8, 0xDDB9, 0x83A9, 0xDDB3, 0x83AA, 0xDDAD, + 0x83AB, 0xC4AA, 0x83AC, 0xC77C, 0x83AD, 0xC77D, 0x83AE, 0xC77E, 0x83AF, 0xC780, 0x83B0, 0xDDA8, 0x83B1, 0xC0B3, 0x83B2, 0xC1AB, + 0x83B3, 0xDDAA, 0x83B4, 0xDDAB, 0x83B5, 0xC781, 0x83B6, 0xDDB2, 0x83B7, 0xBBF1, 0x83B8, 0xDDB5, 0x83B9, 0xD3A8, 0x83BA, 0xDDBA, + 0x83BB, 0xC782, 0x83BC, 0xDDBB, 0x83BD, 0xC3A7, 0x83BE, 0xC783, 0x83BF, 0xC784, 0x83C0, 0xDDD2, 0x83C1, 0xDDBC, 0x83C2, 0xC785, + 0x83C3, 0xC786, 0x83C4, 0xC787, 0x83C5, 0xDDD1, 0x83C6, 0xC788, 0x83C7, 0xB9BD, 0x83C8, 0xC789, 0x83C9, 0xC78A, 0x83CA, 0xBED5, + 0x83CB, 0xC78B, 0x83CC, 0xBEFA, 0x83CD, 0xC78C, 0x83CE, 0xC78D, 0x83CF, 0xBACA, 0x83D0, 0xC78E, 0x83D1, 0xC78F, 0x83D2, 0xC790, + 0x83D3, 0xC791, 0x83D4, 0xDDCA, 0x83D5, 0xC792, 0x83D6, 0xDDC5, 0x83D7, 0xC793, 0x83D8, 0xDDBF, 0x83D9, 0xC794, 0x83DA, 0xC795, + 0x83DB, 0xC796, 0x83DC, 0xB2CB, 0x83DD, 0xDDC3, 0x83DE, 0xC797, 0x83DF, 0xDDCB, 0x83E0, 0xB2A4, 0x83E1, 0xDDD5, 0x83E2, 0xC798, + 0x83E3, 0xC799, 0x83E4, 0xC79A, 0x83E5, 0xDDBE, 0x83E6, 0xC79B, 0x83E7, 0xC79C, 0x83E8, 0xC79D, 0x83E9, 0xC6D0, 0x83EA, 0xDDD0, + 0x83EB, 0xC79E, 0x83EC, 0xC79F, 0x83ED, 0xC7A0, 0x83EE, 0xC840, 0x83EF, 0xC841, 0x83F0, 0xDDD4, 0x83F1, 0xC1E2, 0x83F2, 0xB7C6, + 0x83F3, 0xC842, 0x83F4, 0xC843, 0x83F5, 0xC844, 0x83F6, 0xC845, 0x83F7, 0xC846, 0x83F8, 0xDDCE, 0x83F9, 0xDDCF, 0x83FA, 0xC847, + 0x83FB, 0xC848, 0x83FC, 0xC849, 0x83FD, 0xDDC4, 0x83FE, 0xC84A, 0x83FF, 0xC84B, 0x8400, 0xC84C, 0x8401, 0xDDBD, 0x8402, 0xC84D, + 0x8403, 0xDDCD, 0x8404, 0xCCD1, 0x8405, 0xC84E, 0x8406, 0xDDC9, 0x8407, 0xC84F, 0x8408, 0xC850, 0x8409, 0xC851, 0x840A, 0xC852, + 0x840B, 0xDDC2, 0x840C, 0xC3C8, 0x840D, 0xC6BC, 0x840E, 0xCEAE, 0x840F, 0xDDCC, 0x8410, 0xC853, 0x8411, 0xDDC8, 0x8412, 0xC854, + 0x8413, 0xC855, 0x8414, 0xC856, 0x8415, 0xC857, 0x8416, 0xC858, 0x8417, 0xC859, 0x8418, 0xDDC1, 0x8419, 0xC85A, 0x841A, 0xC85B, + 0x841B, 0xC85C, 0x841C, 0xDDC6, 0x841D, 0xC2DC, 0x841E, 0xC85D, 0x841F, 0xC85E, 0x8420, 0xC85F, 0x8421, 0xC860, 0x8422, 0xC861, + 0x8423, 0xC862, 0x8424, 0xD3A9, 0x8425, 0xD3AA, 0x8426, 0xDDD3, 0x8427, 0xCFF4, 0x8428, 0xC8F8, 0x8429, 0xC863, 0x842A, 0xC864, + 0x842B, 0xC865, 0x842C, 0xC866, 0x842D, 0xC867, 0x842E, 0xC868, 0x842F, 0xC869, 0x8430, 0xC86A, 0x8431, 0xDDE6, 0x8432, 0xC86B, + 0x8433, 0xC86C, 0x8434, 0xC86D, 0x8435, 0xC86E, 0x8436, 0xC86F, 0x8437, 0xC870, 0x8438, 0xDDC7, 0x8439, 0xC871, 0x843A, 0xC872, + 0x843B, 0xC873, 0x843C, 0xDDE0, 0x843D, 0xC2E4, 0x843E, 0xC874, 0x843F, 0xC875, 0x8440, 0xC876, 0x8441, 0xC877, 0x8442, 0xC878, + 0x8443, 0xC879, 0x8444, 0xC87A, 0x8445, 0xC87B, 0x8446, 0xDDE1, 0x8447, 0xC87C, 0x8448, 0xC87D, 0x8449, 0xC87E, 0x844A, 0xC880, + 0x844B, 0xC881, 0x844C, 0xC882, 0x844D, 0xC883, 0x844E, 0xC884, 0x844F, 0xC885, 0x8450, 0xC886, 0x8451, 0xDDD7, 0x8452, 0xC887, + 0x8453, 0xC888, 0x8454, 0xC889, 0x8455, 0xC88A, 0x8456, 0xC88B, 0x8457, 0xD6F8, 0x8458, 0xC88C, 0x8459, 0xDDD9, 0x845A, 0xDDD8, + 0x845B, 0xB8F0, 0x845C, 0xDDD6, 0x845D, 0xC88D, 0x845E, 0xC88E, 0x845F, 0xC88F, 0x8460, 0xC890, 0x8461, 0xC6CF, 0x8462, 0xC891, + 0x8463, 0xB6AD, 0x8464, 0xC892, 0x8465, 0xC893, 0x8466, 0xC894, 0x8467, 0xC895, 0x8468, 0xC896, 0x8469, 0xDDE2, 0x846A, 0xC897, + 0x846B, 0xBAF9, 0x846C, 0xD4E1, 0x846D, 0xDDE7, 0x846E, 0xC898, 0x846F, 0xC899, 0x8470, 0xC89A, 0x8471, 0xB4D0, 0x8472, 0xC89B, + 0x8473, 0xDDDA, 0x8474, 0xC89C, 0x8475, 0xBFFB, 0x8476, 0xDDE3, 0x8477, 0xC89D, 0x8478, 0xDDDF, 0x8479, 0xC89E, 0x847A, 0xDDDD, + 0x847B, 0xC89F, 0x847C, 0xC8A0, 0x847D, 0xC940, 0x847E, 0xC941, 0x847F, 0xC942, 0x8480, 0xC943, 0x8481, 0xC944, 0x8482, 0xB5D9, + 0x8483, 0xC945, 0x8484, 0xC946, 0x8485, 0xC947, 0x8486, 0xC948, 0x8487, 0xDDDB, 0x8488, 0xDDDC, 0x8489, 0xDDDE, 0x848A, 0xC949, + 0x848B, 0xBDAF, 0x848C, 0xDDE4, 0x848D, 0xC94A, 0x848E, 0xDDE5, 0x848F, 0xC94B, 0x8490, 0xC94C, 0x8491, 0xC94D, 0x8492, 0xC94E, + 0x8493, 0xC94F, 0x8494, 0xC950, 0x8495, 0xC951, 0x8496, 0xC952, 0x8497, 0xDDF5, 0x8498, 0xC953, 0x8499, 0xC3C9, 0x849A, 0xC954, + 0x849B, 0xC955, 0x849C, 0xCBE2, 0x849D, 0xC956, 0x849E, 0xC957, 0x849F, 0xC958, 0x84A0, 0xC959, 0x84A1, 0xDDF2, 0x84A2, 0xC95A, + 0x84A3, 0xC95B, 0x84A4, 0xC95C, 0x84A5, 0xC95D, 0x84A6, 0xC95E, 0x84A7, 0xC95F, 0x84A8, 0xC960, 0x84A9, 0xC961, 0x84AA, 0xC962, + 0x84AB, 0xC963, 0x84AC, 0xC964, 0x84AD, 0xC965, 0x84AE, 0xC966, 0x84AF, 0xD8E1, 0x84B0, 0xC967, 0x84B1, 0xC968, 0x84B2, 0xC6D1, + 0x84B3, 0xC969, 0x84B4, 0xDDF4, 0x84B5, 0xC96A, 0x84B6, 0xC96B, 0x84B7, 0xC96C, 0x84B8, 0xD5F4, 0x84B9, 0xDDF3, 0x84BA, 0xDDF0, + 0x84BB, 0xC96D, 0x84BC, 0xC96E, 0x84BD, 0xDDEC, 0x84BE, 0xC96F, 0x84BF, 0xDDEF, 0x84C0, 0xC970, 0x84C1, 0xDDE8, 0x84C2, 0xC971, + 0x84C3, 0xC972, 0x84C4, 0xD0EE, 0x84C5, 0xC973, 0x84C6, 0xC974, 0x84C7, 0xC975, 0x84C8, 0xC976, 0x84C9, 0xC8D8, 0x84CA, 0xDDEE, + 0x84CB, 0xC977, 0x84CC, 0xC978, 0x84CD, 0xDDE9, 0x84CE, 0xC979, 0x84CF, 0xC97A, 0x84D0, 0xDDEA, 0x84D1, 0xCBF2, 0x84D2, 0xC97B, + 0x84D3, 0xDDED, 0x84D4, 0xC97C, 0x84D5, 0xC97D, 0x84D6, 0xB1CD, 0x84D7, 0xC97E, 0x84D8, 0xC980, 0x84D9, 0xC981, 0x84DA, 0xC982, + 0x84DB, 0xC983, 0x84DC, 0xC984, 0x84DD, 0xC0B6, 0x84DE, 0xC985, 0x84DF, 0xBCBB, 0x84E0, 0xDDF1, 0x84E1, 0xC986, 0x84E2, 0xC987, + 0x84E3, 0xDDF7, 0x84E4, 0xC988, 0x84E5, 0xDDF6, 0x84E6, 0xDDEB, 0x84E7, 0xC989, 0x84E8, 0xC98A, 0x84E9, 0xC98B, 0x84EA, 0xC98C, + 0x84EB, 0xC98D, 0x84EC, 0xC5EE, 0x84ED, 0xC98E, 0x84EE, 0xC98F, 0x84EF, 0xC990, 0x84F0, 0xDDFB, 0x84F1, 0xC991, 0x84F2, 0xC992, + 0x84F3, 0xC993, 0x84F4, 0xC994, 0x84F5, 0xC995, 0x84F6, 0xC996, 0x84F7, 0xC997, 0x84F8, 0xC998, 0x84F9, 0xC999, 0x84FA, 0xC99A, + 0x84FB, 0xC99B, 0x84FC, 0xDEA4, 0x84FD, 0xC99C, 0x84FE, 0xC99D, 0x84FF, 0xDEA3, 0x8500, 0xC99E, 0x8501, 0xC99F, 0x8502, 0xC9A0, + 0x8503, 0xCA40, 0x8504, 0xCA41, 0x8505, 0xCA42, 0x8506, 0xCA43, 0x8507, 0xCA44, 0x8508, 0xCA45, 0x8509, 0xCA46, 0x850A, 0xCA47, + 0x850B, 0xCA48, 0x850C, 0xDDF8, 0x850D, 0xCA49, 0x850E, 0xCA4A, 0x850F, 0xCA4B, 0x8510, 0xCA4C, 0x8511, 0xC3EF, 0x8512, 0xCA4D, + 0x8513, 0xC2FB, 0x8514, 0xCA4E, 0x8515, 0xCA4F, 0x8516, 0xCA50, 0x8517, 0xD5E1, 0x8518, 0xCA51, 0x8519, 0xCA52, 0x851A, 0xCEB5, + 0x851B, 0xCA53, 0x851C, 0xCA54, 0x851D, 0xCA55, 0x851E, 0xCA56, 0x851F, 0xDDFD, 0x8520, 0xCA57, 0x8521, 0xB2CC, 0x8522, 0xCA58, + 0x8523, 0xCA59, 0x8524, 0xCA5A, 0x8525, 0xCA5B, 0x8526, 0xCA5C, 0x8527, 0xCA5D, 0x8528, 0xCA5E, 0x8529, 0xCA5F, 0x852A, 0xCA60, + 0x852B, 0xC4E8, 0x852C, 0xCADF, 0x852D, 0xCA61, 0x852E, 0xCA62, 0x852F, 0xCA63, 0x8530, 0xCA64, 0x8531, 0xCA65, 0x8532, 0xCA66, + 0x8533, 0xCA67, 0x8534, 0xCA68, 0x8535, 0xCA69, 0x8536, 0xCA6A, 0x8537, 0xC7BE, 0x8538, 0xDDFA, 0x8539, 0xDDFC, 0x853A, 0xDDFE, + 0x853B, 0xDEA2, 0x853C, 0xB0AA, 0x853D, 0xB1CE, 0x853E, 0xCA6B, 0x853F, 0xCA6C, 0x8540, 0xCA6D, 0x8541, 0xCA6E, 0x8542, 0xCA6F, + 0x8543, 0xDEAC, 0x8544, 0xCA70, 0x8545, 0xCA71, 0x8546, 0xCA72, 0x8547, 0xCA73, 0x8548, 0xDEA6, 0x8549, 0xBDB6, 0x854A, 0xC8EF, + 0x854B, 0xCA74, 0x854C, 0xCA75, 0x854D, 0xCA76, 0x854E, 0xCA77, 0x854F, 0xCA78, 0x8550, 0xCA79, 0x8551, 0xCA7A, 0x8552, 0xCA7B, + 0x8553, 0xCA7C, 0x8554, 0xCA7D, 0x8555, 0xCA7E, 0x8556, 0xDEA1, 0x8557, 0xCA80, 0x8558, 0xCA81, 0x8559, 0xDEA5, 0x855A, 0xCA82, + 0x855B, 0xCA83, 0x855C, 0xCA84, 0x855D, 0xCA85, 0x855E, 0xDEA9, 0x855F, 0xCA86, 0x8560, 0xCA87, 0x8561, 0xCA88, 0x8562, 0xCA89, + 0x8563, 0xCA8A, 0x8564, 0xDEA8, 0x8565, 0xCA8B, 0x8566, 0xCA8C, 0x8567, 0xCA8D, 0x8568, 0xDEA7, 0x8569, 0xCA8E, 0x856A, 0xCA8F, + 0x856B, 0xCA90, 0x856C, 0xCA91, 0x856D, 0xCA92, 0x856E, 0xCA93, 0x856F, 0xCA94, 0x8570, 0xCA95, 0x8571, 0xCA96, 0x8572, 0xDEAD, + 0x8573, 0xCA97, 0x8574, 0xD4CC, 0x8575, 0xCA98, 0x8576, 0xCA99, 0x8577, 0xCA9A, 0x8578, 0xCA9B, 0x8579, 0xDEB3, 0x857A, 0xDEAA, + 0x857B, 0xDEAE, 0x857C, 0xCA9C, 0x857D, 0xCA9D, 0x857E, 0xC0D9, 0x857F, 0xCA9E, 0x8580, 0xCA9F, 0x8581, 0xCAA0, 0x8582, 0xCB40, + 0x8583, 0xCB41, 0x8584, 0xB1A1, 0x8585, 0xDEB6, 0x8586, 0xCB42, 0x8587, 0xDEB1, 0x8588, 0xCB43, 0x8589, 0xCB44, 0x858A, 0xCB45, + 0x858B, 0xCB46, 0x858C, 0xCB47, 0x858D, 0xCB48, 0x858E, 0xCB49, 0x858F, 0xDEB2, 0x8590, 0xCB4A, 0x8591, 0xCB4B, 0x8592, 0xCB4C, + 0x8593, 0xCB4D, 0x8594, 0xCB4E, 0x8595, 0xCB4F, 0x8596, 0xCB50, 0x8597, 0xCB51, 0x8598, 0xCB52, 0x8599, 0xCB53, 0x859A, 0xCB54, + 0x859B, 0xD1A6, 0x859C, 0xDEB5, 0x859D, 0xCB55, 0x859E, 0xCB56, 0x859F, 0xCB57, 0x85A0, 0xCB58, 0x85A1, 0xCB59, 0x85A2, 0xCB5A, + 0x85A3, 0xCB5B, 0x85A4, 0xDEAF, 0x85A5, 0xCB5C, 0x85A6, 0xCB5D, 0x85A7, 0xCB5E, 0x85A8, 0xDEB0, 0x85A9, 0xCB5F, 0x85AA, 0xD0BD, + 0x85AB, 0xCB60, 0x85AC, 0xCB61, 0x85AD, 0xCB62, 0x85AE, 0xDEB4, 0x85AF, 0xCAED, 0x85B0, 0xDEB9, 0x85B1, 0xCB63, 0x85B2, 0xCB64, + 0x85B3, 0xCB65, 0x85B4, 0xCB66, 0x85B5, 0xCB67, 0x85B6, 0xCB68, 0x85B7, 0xDEB8, 0x85B8, 0xCB69, 0x85B9, 0xDEB7, 0x85BA, 0xCB6A, + 0x85BB, 0xCB6B, 0x85BC, 0xCB6C, 0x85BD, 0xCB6D, 0x85BE, 0xCB6E, 0x85BF, 0xCB6F, 0x85C0, 0xCB70, 0x85C1, 0xDEBB, 0x85C2, 0xCB71, + 0x85C3, 0xCB72, 0x85C4, 0xCB73, 0x85C5, 0xCB74, 0x85C6, 0xCB75, 0x85C7, 0xCB76, 0x85C8, 0xCB77, 0x85C9, 0xBDE5, 0x85CA, 0xCB78, + 0x85CB, 0xCB79, 0x85CC, 0xCB7A, 0x85CD, 0xCB7B, 0x85CE, 0xCB7C, 0x85CF, 0xB2D8, 0x85D0, 0xC3EA, 0x85D1, 0xCB7D, 0x85D2, 0xCB7E, + 0x85D3, 0xDEBA, 0x85D4, 0xCB80, 0x85D5, 0xC5BA, 0x85D6, 0xCB81, 0x85D7, 0xCB82, 0x85D8, 0xCB83, 0x85D9, 0xCB84, 0x85DA, 0xCB85, + 0x85DB, 0xCB86, 0x85DC, 0xDEBC, 0x85DD, 0xCB87, 0x85DE, 0xCB88, 0x85DF, 0xCB89, 0x85E0, 0xCB8A, 0x85E1, 0xCB8B, 0x85E2, 0xCB8C, + 0x85E3, 0xCB8D, 0x85E4, 0xCCD9, 0x85E5, 0xCB8E, 0x85E6, 0xCB8F, 0x85E7, 0xCB90, 0x85E8, 0xCB91, 0x85E9, 0xB7AA, 0x85EA, 0xCB92, + 0x85EB, 0xCB93, 0x85EC, 0xCB94, 0x85ED, 0xCB95, 0x85EE, 0xCB96, 0x85EF, 0xCB97, 0x85F0, 0xCB98, 0x85F1, 0xCB99, 0x85F2, 0xCB9A, + 0x85F3, 0xCB9B, 0x85F4, 0xCB9C, 0x85F5, 0xCB9D, 0x85F6, 0xCB9E, 0x85F7, 0xCB9F, 0x85F8, 0xCBA0, 0x85F9, 0xCC40, 0x85FA, 0xCC41, + 0x85FB, 0xD4E5, 0x85FC, 0xCC42, 0x85FD, 0xCC43, 0x85FE, 0xCC44, 0x85FF, 0xDEBD, 0x8600, 0xCC45, 0x8601, 0xCC46, 0x8602, 0xCC47, + 0x8603, 0xCC48, 0x8604, 0xCC49, 0x8605, 0xDEBF, 0x8606, 0xCC4A, 0x8607, 0xCC4B, 0x8608, 0xCC4C, 0x8609, 0xCC4D, 0x860A, 0xCC4E, + 0x860B, 0xCC4F, 0x860C, 0xCC50, 0x860D, 0xCC51, 0x860E, 0xCC52, 0x860F, 0xCC53, 0x8610, 0xCC54, 0x8611, 0xC4A2, 0x8612, 0xCC55, + 0x8613, 0xCC56, 0x8614, 0xCC57, 0x8615, 0xCC58, 0x8616, 0xDEC1, 0x8617, 0xCC59, 0x8618, 0xCC5A, 0x8619, 0xCC5B, 0x861A, 0xCC5C, + 0x861B, 0xCC5D, 0x861C, 0xCC5E, 0x861D, 0xCC5F, 0x861E, 0xCC60, 0x861F, 0xCC61, 0x8620, 0xCC62, 0x8621, 0xCC63, 0x8622, 0xCC64, + 0x8623, 0xCC65, 0x8624, 0xCC66, 0x8625, 0xCC67, 0x8626, 0xCC68, 0x8627, 0xDEBE, 0x8628, 0xCC69, 0x8629, 0xDEC0, 0x862A, 0xCC6A, + 0x862B, 0xCC6B, 0x862C, 0xCC6C, 0x862D, 0xCC6D, 0x862E, 0xCC6E, 0x862F, 0xCC6F, 0x8630, 0xCC70, 0x8631, 0xCC71, 0x8632, 0xCC72, + 0x8633, 0xCC73, 0x8634, 0xCC74, 0x8635, 0xCC75, 0x8636, 0xCC76, 0x8637, 0xCC77, 0x8638, 0xD5BA, 0x8639, 0xCC78, 0x863A, 0xCC79, + 0x863B, 0xCC7A, 0x863C, 0xDEC2, 0x863D, 0xCC7B, 0x863E, 0xCC7C, 0x863F, 0xCC7D, 0x8640, 0xCC7E, 0x8641, 0xCC80, 0x8642, 0xCC81, + 0x8643, 0xCC82, 0x8644, 0xCC83, 0x8645, 0xCC84, 0x8646, 0xCC85, 0x8647, 0xCC86, 0x8648, 0xCC87, 0x8649, 0xCC88, 0x864A, 0xCC89, + 0x864B, 0xCC8A, 0x864C, 0xCC8B, 0x864D, 0xF2AE, 0x864E, 0xBBA2, 0x864F, 0xC2B2, 0x8650, 0xC5B0, 0x8651, 0xC2C7, 0x8652, 0xCC8C, + 0x8653, 0xCC8D, 0x8654, 0xF2AF, 0x8655, 0xCC8E, 0x8656, 0xCC8F, 0x8657, 0xCC90, 0x8658, 0xCC91, 0x8659, 0xCC92, 0x865A, 0xD0E9, + 0x865B, 0xCC93, 0x865C, 0xCC94, 0x865D, 0xCC95, 0x865E, 0xD3DD, 0x865F, 0xCC96, 0x8660, 0xCC97, 0x8661, 0xCC98, 0x8662, 0xEBBD, + 0x8663, 0xCC99, 0x8664, 0xCC9A, 0x8665, 0xCC9B, 0x8666, 0xCC9C, 0x8667, 0xCC9D, 0x8668, 0xCC9E, 0x8669, 0xCC9F, 0x866A, 0xCCA0, + 0x866B, 0xB3E6, 0x866C, 0xF2B0, 0x866D, 0xCD40, 0x866E, 0xF2B1, 0x866F, 0xCD41, 0x8670, 0xCD42, 0x8671, 0xCAAD, 0x8672, 0xCD43, + 0x8673, 0xCD44, 0x8674, 0xCD45, 0x8675, 0xCD46, 0x8676, 0xCD47, 0x8677, 0xCD48, 0x8678, 0xCD49, 0x8679, 0xBAE7, 0x867A, 0xF2B3, + 0x867B, 0xF2B5, 0x867C, 0xF2B4, 0x867D, 0xCBE4, 0x867E, 0xCFBA, 0x867F, 0xF2B2, 0x8680, 0xCAB4, 0x8681, 0xD2CF, 0x8682, 0xC2EC, + 0x8683, 0xCD4A, 0x8684, 0xCD4B, 0x8685, 0xCD4C, 0x8686, 0xCD4D, 0x8687, 0xCD4E, 0x8688, 0xCD4F, 0x8689, 0xCD50, 0x868A, 0xCEC3, + 0x868B, 0xF2B8, 0x868C, 0xB0F6, 0x868D, 0xF2B7, 0x868E, 0xCD51, 0x868F, 0xCD52, 0x8690, 0xCD53, 0x8691, 0xCD54, 0x8692, 0xCD55, + 0x8693, 0xF2BE, 0x8694, 0xCD56, 0x8695, 0xB2CF, 0x8696, 0xCD57, 0x8697, 0xCD58, 0x8698, 0xCD59, 0x8699, 0xCD5A, 0x869A, 0xCD5B, + 0x869B, 0xCD5C, 0x869C, 0xD1C1, 0x869D, 0xF2BA, 0x869E, 0xCD5D, 0x869F, 0xCD5E, 0x86A0, 0xCD5F, 0x86A1, 0xCD60, 0x86A2, 0xCD61, + 0x86A3, 0xF2BC, 0x86A4, 0xD4E9, 0x86A5, 0xCD62, 0x86A6, 0xCD63, 0x86A7, 0xF2BB, 0x86A8, 0xF2B6, 0x86A9, 0xF2BF, 0x86AA, 0xF2BD, + 0x86AB, 0xCD64, 0x86AC, 0xF2B9, 0x86AD, 0xCD65, 0x86AE, 0xCD66, 0x86AF, 0xF2C7, 0x86B0, 0xF2C4, 0x86B1, 0xF2C6, 0x86B2, 0xCD67, + 0x86B3, 0xCD68, 0x86B4, 0xF2CA, 0x86B5, 0xF2C2, 0x86B6, 0xF2C0, 0x86B7, 0xCD69, 0x86B8, 0xCD6A, 0x86B9, 0xCD6B, 0x86BA, 0xF2C5, + 0x86BB, 0xCD6C, 0x86BC, 0xCD6D, 0x86BD, 0xCD6E, 0x86BE, 0xCD6F, 0x86BF, 0xCD70, 0x86C0, 0xD6FB, 0x86C1, 0xCD71, 0x86C2, 0xCD72, + 0x86C3, 0xCD73, 0x86C4, 0xF2C1, 0x86C5, 0xCD74, 0x86C6, 0xC7F9, 0x86C7, 0xC9DF, 0x86C8, 0xCD75, 0x86C9, 0xF2C8, 0x86CA, 0xB9C6, + 0x86CB, 0xB5B0, 0x86CC, 0xCD76, 0x86CD, 0xCD77, 0x86CE, 0xF2C3, 0x86CF, 0xF2C9, 0x86D0, 0xF2D0, 0x86D1, 0xF2D6, 0x86D2, 0xCD78, + 0x86D3, 0xCD79, 0x86D4, 0xBBD7, 0x86D5, 0xCD7A, 0x86D6, 0xCD7B, 0x86D7, 0xCD7C, 0x86D8, 0xF2D5, 0x86D9, 0xCDDC, 0x86DA, 0xCD7D, + 0x86DB, 0xD6EB, 0x86DC, 0xCD7E, 0x86DD, 0xCD80, 0x86DE, 0xF2D2, 0x86DF, 0xF2D4, 0x86E0, 0xCD81, 0x86E1, 0xCD82, 0x86E2, 0xCD83, + 0x86E3, 0xCD84, 0x86E4, 0xB8F2, 0x86E5, 0xCD85, 0x86E6, 0xCD86, 0x86E7, 0xCD87, 0x86E8, 0xCD88, 0x86E9, 0xF2CB, 0x86EA, 0xCD89, + 0x86EB, 0xCD8A, 0x86EC, 0xCD8B, 0x86ED, 0xF2CE, 0x86EE, 0xC2F9, 0x86EF, 0xCD8C, 0x86F0, 0xD5DD, 0x86F1, 0xF2CC, 0x86F2, 0xF2CD, + 0x86F3, 0xF2CF, 0x86F4, 0xF2D3, 0x86F5, 0xCD8D, 0x86F6, 0xCD8E, 0x86F7, 0xCD8F, 0x86F8, 0xF2D9, 0x86F9, 0xD3BC, 0x86FA, 0xCD90, + 0x86FB, 0xCD91, 0x86FC, 0xCD92, 0x86FD, 0xCD93, 0x86FE, 0xB6EA, 0x86FF, 0xCD94, 0x8700, 0xCAF1, 0x8701, 0xCD95, 0x8702, 0xB7E4, + 0x8703, 0xF2D7, 0x8704, 0xCD96, 0x8705, 0xCD97, 0x8706, 0xCD98, 0x8707, 0xF2D8, 0x8708, 0xF2DA, 0x8709, 0xF2DD, 0x870A, 0xF2DB, + 0x870B, 0xCD99, 0x870C, 0xCD9A, 0x870D, 0xF2DC, 0x870E, 0xCD9B, 0x870F, 0xCD9C, 0x8710, 0xCD9D, 0x8711, 0xCD9E, 0x8712, 0xD1D1, + 0x8713, 0xF2D1, 0x8714, 0xCD9F, 0x8715, 0xCDC9, 0x8716, 0xCDA0, 0x8717, 0xCECF, 0x8718, 0xD6A9, 0x8719, 0xCE40, 0x871A, 0xF2E3, + 0x871B, 0xCE41, 0x871C, 0xC3DB, 0x871D, 0xCE42, 0x871E, 0xF2E0, 0x871F, 0xCE43, 0x8720, 0xCE44, 0x8721, 0xC0AF, 0x8722, 0xF2EC, + 0x8723, 0xF2DE, 0x8724, 0xCE45, 0x8725, 0xF2E1, 0x8726, 0xCE46, 0x8727, 0xCE47, 0x8728, 0xCE48, 0x8729, 0xF2E8, 0x872A, 0xCE49, + 0x872B, 0xCE4A, 0x872C, 0xCE4B, 0x872D, 0xCE4C, 0x872E, 0xF2E2, 0x872F, 0xCE4D, 0x8730, 0xCE4E, 0x8731, 0xF2E7, 0x8732, 0xCE4F, + 0x8733, 0xCE50, 0x8734, 0xF2E6, 0x8735, 0xCE51, 0x8736, 0xCE52, 0x8737, 0xF2E9, 0x8738, 0xCE53, 0x8739, 0xCE54, 0x873A, 0xCE55, + 0x873B, 0xF2DF, 0x873C, 0xCE56, 0x873D, 0xCE57, 0x873E, 0xF2E4, 0x873F, 0xF2EA, 0x8740, 0xCE58, 0x8741, 0xCE59, 0x8742, 0xCE5A, + 0x8743, 0xCE5B, 0x8744, 0xCE5C, 0x8745, 0xCE5D, 0x8746, 0xCE5E, 0x8747, 0xD3AC, 0x8748, 0xF2E5, 0x8749, 0xB2F5, 0x874A, 0xCE5F, + 0x874B, 0xCE60, 0x874C, 0xF2F2, 0x874D, 0xCE61, 0x874E, 0xD0AB, 0x874F, 0xCE62, 0x8750, 0xCE63, 0x8751, 0xCE64, 0x8752, 0xCE65, + 0x8753, 0xF2F5, 0x8754, 0xCE66, 0x8755, 0xCE67, 0x8756, 0xCE68, 0x8757, 0xBBC8, 0x8758, 0xCE69, 0x8759, 0xF2F9, 0x875A, 0xCE6A, + 0x875B, 0xCE6B, 0x875C, 0xCE6C, 0x875D, 0xCE6D, 0x875E, 0xCE6E, 0x875F, 0xCE6F, 0x8760, 0xF2F0, 0x8761, 0xCE70, 0x8762, 0xCE71, + 0x8763, 0xF2F6, 0x8764, 0xF2F8, 0x8765, 0xF2FA, 0x8766, 0xCE72, 0x8767, 0xCE73, 0x8768, 0xCE74, 0x8769, 0xCE75, 0x876A, 0xCE76, + 0x876B, 0xCE77, 0x876C, 0xCE78, 0x876D, 0xCE79, 0x876E, 0xF2F3, 0x876F, 0xCE7A, 0x8770, 0xF2F1, 0x8771, 0xCE7B, 0x8772, 0xCE7C, + 0x8773, 0xCE7D, 0x8774, 0xBAFB, 0x8775, 0xCE7E, 0x8776, 0xB5FB, 0x8777, 0xCE80, 0x8778, 0xCE81, 0x8779, 0xCE82, 0x877A, 0xCE83, + 0x877B, 0xF2EF, 0x877C, 0xF2F7, 0x877D, 0xF2ED, 0x877E, 0xF2EE, 0x877F, 0xCE84, 0x8780, 0xCE85, 0x8781, 0xCE86, 0x8782, 0xF2EB, + 0x8783, 0xF3A6, 0x8784, 0xCE87, 0x8785, 0xF3A3, 0x8786, 0xCE88, 0x8787, 0xCE89, 0x8788, 0xF3A2, 0x8789, 0xCE8A, 0x878A, 0xCE8B, + 0x878B, 0xF2F4, 0x878C, 0xCE8C, 0x878D, 0xC8DA, 0x878E, 0xCE8D, 0x878F, 0xCE8E, 0x8790, 0xCE8F, 0x8791, 0xCE90, 0x8792, 0xCE91, + 0x8793, 0xF2FB, 0x8794, 0xCE92, 0x8795, 0xCE93, 0x8796, 0xCE94, 0x8797, 0xF3A5, 0x8798, 0xCE95, 0x8799, 0xCE96, 0x879A, 0xCE97, + 0x879B, 0xCE98, 0x879C, 0xCE99, 0x879D, 0xCE9A, 0x879E, 0xCE9B, 0x879F, 0xC3F8, 0x87A0, 0xCE9C, 0x87A1, 0xCE9D, 0x87A2, 0xCE9E, + 0x87A3, 0xCE9F, 0x87A4, 0xCEA0, 0x87A5, 0xCF40, 0x87A6, 0xCF41, 0x87A7, 0xCF42, 0x87A8, 0xF2FD, 0x87A9, 0xCF43, 0x87AA, 0xCF44, + 0x87AB, 0xF3A7, 0x87AC, 0xF3A9, 0x87AD, 0xF3A4, 0x87AE, 0xCF45, 0x87AF, 0xF2FC, 0x87B0, 0xCF46, 0x87B1, 0xCF47, 0x87B2, 0xCF48, + 0x87B3, 0xF3AB, 0x87B4, 0xCF49, 0x87B5, 0xF3AA, 0x87B6, 0xCF4A, 0x87B7, 0xCF4B, 0x87B8, 0xCF4C, 0x87B9, 0xCF4D, 0x87BA, 0xC2DD, + 0x87BB, 0xCF4E, 0x87BC, 0xCF4F, 0x87BD, 0xF3AE, 0x87BE, 0xCF50, 0x87BF, 0xCF51, 0x87C0, 0xF3B0, 0x87C1, 0xCF52, 0x87C2, 0xCF53, + 0x87C3, 0xCF54, 0x87C4, 0xCF55, 0x87C5, 0xCF56, 0x87C6, 0xF3A1, 0x87C7, 0xCF57, 0x87C8, 0xCF58, 0x87C9, 0xCF59, 0x87CA, 0xF3B1, + 0x87CB, 0xF3AC, 0x87CC, 0xCF5A, 0x87CD, 0xCF5B, 0x87CE, 0xCF5C, 0x87CF, 0xCF5D, 0x87D0, 0xCF5E, 0x87D1, 0xF3AF, 0x87D2, 0xF2FE, + 0x87D3, 0xF3AD, 0x87D4, 0xCF5F, 0x87D5, 0xCF60, 0x87D6, 0xCF61, 0x87D7, 0xCF62, 0x87D8, 0xCF63, 0x87D9, 0xCF64, 0x87DA, 0xCF65, + 0x87DB, 0xF3B2, 0x87DC, 0xCF66, 0x87DD, 0xCF67, 0x87DE, 0xCF68, 0x87DF, 0xCF69, 0x87E0, 0xF3B4, 0x87E1, 0xCF6A, 0x87E2, 0xCF6B, + 0x87E3, 0xCF6C, 0x87E4, 0xCF6D, 0x87E5, 0xF3A8, 0x87E6, 0xCF6E, 0x87E7, 0xCF6F, 0x87E8, 0xCF70, 0x87E9, 0xCF71, 0x87EA, 0xF3B3, + 0x87EB, 0xCF72, 0x87EC, 0xCF73, 0x87ED, 0xCF74, 0x87EE, 0xF3B5, 0x87EF, 0xCF75, 0x87F0, 0xCF76, 0x87F1, 0xCF77, 0x87F2, 0xCF78, + 0x87F3, 0xCF79, 0x87F4, 0xCF7A, 0x87F5, 0xCF7B, 0x87F6, 0xCF7C, 0x87F7, 0xCF7D, 0x87F8, 0xCF7E, 0x87F9, 0xD0B7, 0x87FA, 0xCF80, + 0x87FB, 0xCF81, 0x87FC, 0xCF82, 0x87FD, 0xCF83, 0x87FE, 0xF3B8, 0x87FF, 0xCF84, 0x8800, 0xCF85, 0x8801, 0xCF86, 0x8802, 0xCF87, + 0x8803, 0xD9F9, 0x8804, 0xCF88, 0x8805, 0xCF89, 0x8806, 0xCF8A, 0x8807, 0xCF8B, 0x8808, 0xCF8C, 0x8809, 0xCF8D, 0x880A, 0xF3B9, + 0x880B, 0xCF8E, 0x880C, 0xCF8F, 0x880D, 0xCF90, 0x880E, 0xCF91, 0x880F, 0xCF92, 0x8810, 0xCF93, 0x8811, 0xCF94, 0x8812, 0xCF95, + 0x8813, 0xF3B7, 0x8814, 0xCF96, 0x8815, 0xC8E4, 0x8816, 0xF3B6, 0x8817, 0xCF97, 0x8818, 0xCF98, 0x8819, 0xCF99, 0x881A, 0xCF9A, + 0x881B, 0xF3BA, 0x881C, 0xCF9B, 0x881D, 0xCF9C, 0x881E, 0xCF9D, 0x881F, 0xCF9E, 0x8820, 0xCF9F, 0x8821, 0xF3BB, 0x8822, 0xB4C0, + 0x8823, 0xCFA0, 0x8824, 0xD040, 0x8825, 0xD041, 0x8826, 0xD042, 0x8827, 0xD043, 0x8828, 0xD044, 0x8829, 0xD045, 0x882A, 0xD046, + 0x882B, 0xD047, 0x882C, 0xD048, 0x882D, 0xD049, 0x882E, 0xD04A, 0x882F, 0xD04B, 0x8830, 0xD04C, 0x8831, 0xD04D, 0x8832, 0xEEC3, + 0x8833, 0xD04E, 0x8834, 0xD04F, 0x8835, 0xD050, 0x8836, 0xD051, 0x8837, 0xD052, 0x8838, 0xD053, 0x8839, 0xF3BC, 0x883A, 0xD054, + 0x883B, 0xD055, 0x883C, 0xF3BD, 0x883D, 0xD056, 0x883E, 0xD057, 0x883F, 0xD058, 0x8840, 0xD1AA, 0x8841, 0xD059, 0x8842, 0xD05A, + 0x8843, 0xD05B, 0x8844, 0xF4AC, 0x8845, 0xD0C6, 0x8846, 0xD05C, 0x8847, 0xD05D, 0x8848, 0xD05E, 0x8849, 0xD05F, 0x884A, 0xD060, + 0x884B, 0xD061, 0x884C, 0xD0D0, 0x884D, 0xD1DC, 0x884E, 0xD062, 0x884F, 0xD063, 0x8850, 0xD064, 0x8851, 0xD065, 0x8852, 0xD066, + 0x8853, 0xD067, 0x8854, 0xCFCE, 0x8855, 0xD068, 0x8856, 0xD069, 0x8857, 0xBDD6, 0x8858, 0xD06A, 0x8859, 0xD1C3, 0x885A, 0xD06B, + 0x885B, 0xD06C, 0x885C, 0xD06D, 0x885D, 0xD06E, 0x885E, 0xD06F, 0x885F, 0xD070, 0x8860, 0xD071, 0x8861, 0xBAE2, 0x8862, 0xE1E9, + 0x8863, 0xD2C2, 0x8864, 0xF1C2, 0x8865, 0xB2B9, 0x8866, 0xD072, 0x8867, 0xD073, 0x8868, 0xB1ED, 0x8869, 0xF1C3, 0x886A, 0xD074, + 0x886B, 0xC9C0, 0x886C, 0xB3C4, 0x886D, 0xD075, 0x886E, 0xD9F2, 0x886F, 0xD076, 0x8870, 0xCBA5, 0x8871, 0xD077, 0x8872, 0xF1C4, + 0x8873, 0xD078, 0x8874, 0xD079, 0x8875, 0xD07A, 0x8876, 0xD07B, 0x8877, 0xD6D4, 0x8878, 0xD07C, 0x8879, 0xD07D, 0x887A, 0xD07E, + 0x887B, 0xD080, 0x887C, 0xD081, 0x887D, 0xF1C5, 0x887E, 0xF4C0, 0x887F, 0xF1C6, 0x8880, 0xD082, 0x8881, 0xD4AC, 0x8882, 0xF1C7, + 0x8883, 0xD083, 0x8884, 0xB0C0, 0x8885, 0xF4C1, 0x8886, 0xD084, 0x8887, 0xD085, 0x8888, 0xF4C2, 0x8889, 0xD086, 0x888A, 0xD087, + 0x888B, 0xB4FC, 0x888C, 0xD088, 0x888D, 0xC5DB, 0x888E, 0xD089, 0x888F, 0xD08A, 0x8890, 0xD08B, 0x8891, 0xD08C, 0x8892, 0xCCBB, + 0x8893, 0xD08D, 0x8894, 0xD08E, 0x8895, 0xD08F, 0x8896, 0xD0E4, 0x8897, 0xD090, 0x8898, 0xD091, 0x8899, 0xD092, 0x889A, 0xD093, + 0x889B, 0xD094, 0x889C, 0xCDE0, 0x889D, 0xD095, 0x889E, 0xD096, 0x889F, 0xD097, 0x88A0, 0xD098, 0x88A1, 0xD099, 0x88A2, 0xF1C8, + 0x88A3, 0xD09A, 0x88A4, 0xD9F3, 0x88A5, 0xD09B, 0x88A6, 0xD09C, 0x88A7, 0xD09D, 0x88A8, 0xD09E, 0x88A9, 0xD09F, 0x88AA, 0xD0A0, + 0x88AB, 0xB1BB, 0x88AC, 0xD140, 0x88AD, 0xCFAE, 0x88AE, 0xD141, 0x88AF, 0xD142, 0x88B0, 0xD143, 0x88B1, 0xB8A4, 0x88B2, 0xD144, + 0x88B3, 0xD145, 0x88B4, 0xD146, 0x88B5, 0xD147, 0x88B6, 0xD148, 0x88B7, 0xF1CA, 0x88B8, 0xD149, 0x88B9, 0xD14A, 0x88BA, 0xD14B, + 0x88BB, 0xD14C, 0x88BC, 0xF1CB, 0x88BD, 0xD14D, 0x88BE, 0xD14E, 0x88BF, 0xD14F, 0x88C0, 0xD150, 0x88C1, 0xB2C3, 0x88C2, 0xC1D1, + 0x88C3, 0xD151, 0x88C4, 0xD152, 0x88C5, 0xD7B0, 0x88C6, 0xF1C9, 0x88C7, 0xD153, 0x88C8, 0xD154, 0x88C9, 0xF1CC, 0x88CA, 0xD155, + 0x88CB, 0xD156, 0x88CC, 0xD157, 0x88CD, 0xD158, 0x88CE, 0xF1CE, 0x88CF, 0xD159, 0x88D0, 0xD15A, 0x88D1, 0xD15B, 0x88D2, 0xD9F6, + 0x88D3, 0xD15C, 0x88D4, 0xD2E1, 0x88D5, 0xD4A3, 0x88D6, 0xD15D, 0x88D7, 0xD15E, 0x88D8, 0xF4C3, 0x88D9, 0xC8B9, 0x88DA, 0xD15F, + 0x88DB, 0xD160, 0x88DC, 0xD161, 0x88DD, 0xD162, 0x88DE, 0xD163, 0x88DF, 0xF4C4, 0x88E0, 0xD164, 0x88E1, 0xD165, 0x88E2, 0xF1CD, + 0x88E3, 0xF1CF, 0x88E4, 0xBFE3, 0x88E5, 0xF1D0, 0x88E6, 0xD166, 0x88E7, 0xD167, 0x88E8, 0xF1D4, 0x88E9, 0xD168, 0x88EA, 0xD169, + 0x88EB, 0xD16A, 0x88EC, 0xD16B, 0x88ED, 0xD16C, 0x88EE, 0xD16D, 0x88EF, 0xD16E, 0x88F0, 0xF1D6, 0x88F1, 0xF1D1, 0x88F2, 0xD16F, + 0x88F3, 0xC9D1, 0x88F4, 0xC5E1, 0x88F5, 0xD170, 0x88F6, 0xD171, 0x88F7, 0xD172, 0x88F8, 0xC2E3, 0x88F9, 0xB9FC, 0x88FA, 0xD173, + 0x88FB, 0xD174, 0x88FC, 0xF1D3, 0x88FD, 0xD175, 0x88FE, 0xF1D5, 0x88FF, 0xD176, 0x8900, 0xD177, 0x8901, 0xD178, 0x8902, 0xB9D3, + 0x8903, 0xD179, 0x8904, 0xD17A, 0x8905, 0xD17B, 0x8906, 0xD17C, 0x8907, 0xD17D, 0x8908, 0xD17E, 0x8909, 0xD180, 0x890A, 0xF1DB, + 0x890B, 0xD181, 0x890C, 0xD182, 0x890D, 0xD183, 0x890E, 0xD184, 0x890F, 0xD185, 0x8910, 0xBAD6, 0x8911, 0xD186, 0x8912, 0xB0FD, + 0x8913, 0xF1D9, 0x8914, 0xD187, 0x8915, 0xD188, 0x8916, 0xD189, 0x8917, 0xD18A, 0x8918, 0xD18B, 0x8919, 0xF1D8, 0x891A, 0xF1D2, + 0x891B, 0xF1DA, 0x891C, 0xD18C, 0x891D, 0xD18D, 0x891E, 0xD18E, 0x891F, 0xD18F, 0x8920, 0xD190, 0x8921, 0xF1D7, 0x8922, 0xD191, + 0x8923, 0xD192, 0x8924, 0xD193, 0x8925, 0xC8EC, 0x8926, 0xD194, 0x8927, 0xD195, 0x8928, 0xD196, 0x8929, 0xD197, 0x892A, 0xCDCA, + 0x892B, 0xF1DD, 0x892C, 0xD198, 0x892D, 0xD199, 0x892E, 0xD19A, 0x892F, 0xD19B, 0x8930, 0xE5BD, 0x8931, 0xD19C, 0x8932, 0xD19D, + 0x8933, 0xD19E, 0x8934, 0xF1DC, 0x8935, 0xD19F, 0x8936, 0xF1DE, 0x8937, 0xD1A0, 0x8938, 0xD240, 0x8939, 0xD241, 0x893A, 0xD242, + 0x893B, 0xD243, 0x893C, 0xD244, 0x893D, 0xD245, 0x893E, 0xD246, 0x893F, 0xD247, 0x8940, 0xD248, 0x8941, 0xF1DF, 0x8942, 0xD249, + 0x8943, 0xD24A, 0x8944, 0xCFE5, 0x8945, 0xD24B, 0x8946, 0xD24C, 0x8947, 0xD24D, 0x8948, 0xD24E, 0x8949, 0xD24F, 0x894A, 0xD250, + 0x894B, 0xD251, 0x894C, 0xD252, 0x894D, 0xD253, 0x894E, 0xD254, 0x894F, 0xD255, 0x8950, 0xD256, 0x8951, 0xD257, 0x8952, 0xD258, + 0x8953, 0xD259, 0x8954, 0xD25A, 0x8955, 0xD25B, 0x8956, 0xD25C, 0x8957, 0xD25D, 0x8958, 0xD25E, 0x8959, 0xD25F, 0x895A, 0xD260, + 0x895B, 0xD261, 0x895C, 0xD262, 0x895D, 0xD263, 0x895E, 0xF4C5, 0x895F, 0xBDF3, 0x8960, 0xD264, 0x8961, 0xD265, 0x8962, 0xD266, + 0x8963, 0xD267, 0x8964, 0xD268, 0x8965, 0xD269, 0x8966, 0xF1E0, 0x8967, 0xD26A, 0x8968, 0xD26B, 0x8969, 0xD26C, 0x896A, 0xD26D, + 0x896B, 0xD26E, 0x896C, 0xD26F, 0x896D, 0xD270, 0x896E, 0xD271, 0x896F, 0xD272, 0x8970, 0xD273, 0x8971, 0xD274, 0x8972, 0xD275, + 0x8973, 0xD276, 0x8974, 0xD277, 0x8975, 0xD278, 0x8976, 0xD279, 0x8977, 0xD27A, 0x8978, 0xD27B, 0x8979, 0xD27C, 0x897A, 0xD27D, + 0x897B, 0xF1E1, 0x897C, 0xD27E, 0x897D, 0xD280, 0x897E, 0xD281, 0x897F, 0xCEF7, 0x8980, 0xD282, 0x8981, 0xD2AA, 0x8982, 0xD283, + 0x8983, 0xF1FB, 0x8984, 0xD284, 0x8985, 0xD285, 0x8986, 0xB8B2, 0x8987, 0xD286, 0x8988, 0xD287, 0x8989, 0xD288, 0x898A, 0xD289, + 0x898B, 0xD28A, 0x898C, 0xD28B, 0x898D, 0xD28C, 0x898E, 0xD28D, 0x898F, 0xD28E, 0x8990, 0xD28F, 0x8991, 0xD290, 0x8992, 0xD291, + 0x8993, 0xD292, 0x8994, 0xD293, 0x8995, 0xD294, 0x8996, 0xD295, 0x8997, 0xD296, 0x8998, 0xD297, 0x8999, 0xD298, 0x899A, 0xD299, + 0x899B, 0xD29A, 0x899C, 0xD29B, 0x899D, 0xD29C, 0x899E, 0xD29D, 0x899F, 0xD29E, 0x89A0, 0xD29F, 0x89A1, 0xD2A0, 0x89A2, 0xD340, + 0x89A3, 0xD341, 0x89A4, 0xD342, 0x89A5, 0xD343, 0x89A6, 0xD344, 0x89A7, 0xD345, 0x89A8, 0xD346, 0x89A9, 0xD347, 0x89AA, 0xD348, + 0x89AB, 0xD349, 0x89AC, 0xD34A, 0x89AD, 0xD34B, 0x89AE, 0xD34C, 0x89AF, 0xD34D, 0x89B0, 0xD34E, 0x89B1, 0xD34F, 0x89B2, 0xD350, + 0x89B3, 0xD351, 0x89B4, 0xD352, 0x89B5, 0xD353, 0x89B6, 0xD354, 0x89B7, 0xD355, 0x89B8, 0xD356, 0x89B9, 0xD357, 0x89BA, 0xD358, + 0x89BB, 0xD359, 0x89BC, 0xD35A, 0x89BD, 0xD35B, 0x89BE, 0xD35C, 0x89BF, 0xD35D, 0x89C0, 0xD35E, 0x89C1, 0xBCFB, 0x89C2, 0xB9DB, + 0x89C3, 0xD35F, 0x89C4, 0xB9E6, 0x89C5, 0xC3D9, 0x89C6, 0xCAD3, 0x89C7, 0xEAE8, 0x89C8, 0xC0C0, 0x89C9, 0xBEF5, 0x89CA, 0xEAE9, + 0x89CB, 0xEAEA, 0x89CC, 0xEAEB, 0x89CD, 0xD360, 0x89CE, 0xEAEC, 0x89CF, 0xEAED, 0x89D0, 0xEAEE, 0x89D1, 0xEAEF, 0x89D2, 0xBDC7, + 0x89D3, 0xD361, 0x89D4, 0xD362, 0x89D5, 0xD363, 0x89D6, 0xF5FB, 0x89D7, 0xD364, 0x89D8, 0xD365, 0x89D9, 0xD366, 0x89DA, 0xF5FD, + 0x89DB, 0xD367, 0x89DC, 0xF5FE, 0x89DD, 0xD368, 0x89DE, 0xF5FC, 0x89DF, 0xD369, 0x89E0, 0xD36A, 0x89E1, 0xD36B, 0x89E2, 0xD36C, + 0x89E3, 0xBDE2, 0x89E4, 0xD36D, 0x89E5, 0xF6A1, 0x89E6, 0xB4A5, 0x89E7, 0xD36E, 0x89E8, 0xD36F, 0x89E9, 0xD370, 0x89EA, 0xD371, + 0x89EB, 0xF6A2, 0x89EC, 0xD372, 0x89ED, 0xD373, 0x89EE, 0xD374, 0x89EF, 0xF6A3, 0x89F0, 0xD375, 0x89F1, 0xD376, 0x89F2, 0xD377, + 0x89F3, 0xECB2, 0x89F4, 0xD378, 0x89F5, 0xD379, 0x89F6, 0xD37A, 0x89F7, 0xD37B, 0x89F8, 0xD37C, 0x89F9, 0xD37D, 0x89FA, 0xD37E, + 0x89FB, 0xD380, 0x89FC, 0xD381, 0x89FD, 0xD382, 0x89FE, 0xD383, 0x89FF, 0xD384, 0x8A00, 0xD1D4, 0x8A01, 0xD385, 0x8A02, 0xD386, + 0x8A03, 0xD387, 0x8A04, 0xD388, 0x8A05, 0xD389, 0x8A06, 0xD38A, 0x8A07, 0xD9EA, 0x8A08, 0xD38B, 0x8A09, 0xD38C, 0x8A0A, 0xD38D, + 0x8A0B, 0xD38E, 0x8A0C, 0xD38F, 0x8A0D, 0xD390, 0x8A0E, 0xD391, 0x8A0F, 0xD392, 0x8A10, 0xD393, 0x8A11, 0xD394, 0x8A12, 0xD395, + 0x8A13, 0xD396, 0x8A14, 0xD397, 0x8A15, 0xD398, 0x8A16, 0xD399, 0x8A17, 0xD39A, 0x8A18, 0xD39B, 0x8A19, 0xD39C, 0x8A1A, 0xD39D, + 0x8A1B, 0xD39E, 0x8A1C, 0xD39F, 0x8A1D, 0xD3A0, 0x8A1E, 0xD440, 0x8A1F, 0xD441, 0x8A20, 0xD442, 0x8A21, 0xD443, 0x8A22, 0xD444, + 0x8A23, 0xD445, 0x8A24, 0xD446, 0x8A25, 0xD447, 0x8A26, 0xD448, 0x8A27, 0xD449, 0x8A28, 0xD44A, 0x8A29, 0xD44B, 0x8A2A, 0xD44C, + 0x8A2B, 0xD44D, 0x8A2C, 0xD44E, 0x8A2D, 0xD44F, 0x8A2E, 0xD450, 0x8A2F, 0xD451, 0x8A30, 0xD452, 0x8A31, 0xD453, 0x8A32, 0xD454, + 0x8A33, 0xD455, 0x8A34, 0xD456, 0x8A35, 0xD457, 0x8A36, 0xD458, 0x8A37, 0xD459, 0x8A38, 0xD45A, 0x8A39, 0xD45B, 0x8A3A, 0xD45C, + 0x8A3B, 0xD45D, 0x8A3C, 0xD45E, 0x8A3D, 0xD45F, 0x8A3E, 0xF6A4, 0x8A3F, 0xD460, 0x8A40, 0xD461, 0x8A41, 0xD462, 0x8A42, 0xD463, + 0x8A43, 0xD464, 0x8A44, 0xD465, 0x8A45, 0xD466, 0x8A46, 0xD467, 0x8A47, 0xD468, 0x8A48, 0xEEBA, 0x8A49, 0xD469, 0x8A4A, 0xD46A, + 0x8A4B, 0xD46B, 0x8A4C, 0xD46C, 0x8A4D, 0xD46D, 0x8A4E, 0xD46E, 0x8A4F, 0xD46F, 0x8A50, 0xD470, 0x8A51, 0xD471, 0x8A52, 0xD472, + 0x8A53, 0xD473, 0x8A54, 0xD474, 0x8A55, 0xD475, 0x8A56, 0xD476, 0x8A57, 0xD477, 0x8A58, 0xD478, 0x8A59, 0xD479, 0x8A5A, 0xD47A, + 0x8A5B, 0xD47B, 0x8A5C, 0xD47C, 0x8A5D, 0xD47D, 0x8A5E, 0xD47E, 0x8A5F, 0xD480, 0x8A60, 0xD481, 0x8A61, 0xD482, 0x8A62, 0xD483, + 0x8A63, 0xD484, 0x8A64, 0xD485, 0x8A65, 0xD486, 0x8A66, 0xD487, 0x8A67, 0xD488, 0x8A68, 0xD489, 0x8A69, 0xD48A, 0x8A6A, 0xD48B, + 0x8A6B, 0xD48C, 0x8A6C, 0xD48D, 0x8A6D, 0xD48E, 0x8A6E, 0xD48F, 0x8A6F, 0xD490, 0x8A70, 0xD491, 0x8A71, 0xD492, 0x8A72, 0xD493, + 0x8A73, 0xD494, 0x8A74, 0xD495, 0x8A75, 0xD496, 0x8A76, 0xD497, 0x8A77, 0xD498, 0x8A78, 0xD499, 0x8A79, 0xD5B2, 0x8A7A, 0xD49A, + 0x8A7B, 0xD49B, 0x8A7C, 0xD49C, 0x8A7D, 0xD49D, 0x8A7E, 0xD49E, 0x8A7F, 0xD49F, 0x8A80, 0xD4A0, 0x8A81, 0xD540, 0x8A82, 0xD541, + 0x8A83, 0xD542, 0x8A84, 0xD543, 0x8A85, 0xD544, 0x8A86, 0xD545, 0x8A87, 0xD546, 0x8A88, 0xD547, 0x8A89, 0xD3FE, 0x8A8A, 0xCCDC, + 0x8A8B, 0xD548, 0x8A8C, 0xD549, 0x8A8D, 0xD54A, 0x8A8E, 0xD54B, 0x8A8F, 0xD54C, 0x8A90, 0xD54D, 0x8A91, 0xD54E, 0x8A92, 0xD54F, + 0x8A93, 0xCAC4, 0x8A94, 0xD550, 0x8A95, 0xD551, 0x8A96, 0xD552, 0x8A97, 0xD553, 0x8A98, 0xD554, 0x8A99, 0xD555, 0x8A9A, 0xD556, + 0x8A9B, 0xD557, 0x8A9C, 0xD558, 0x8A9D, 0xD559, 0x8A9E, 0xD55A, 0x8A9F, 0xD55B, 0x8AA0, 0xD55C, 0x8AA1, 0xD55D, 0x8AA2, 0xD55E, + 0x8AA3, 0xD55F, 0x8AA4, 0xD560, 0x8AA5, 0xD561, 0x8AA6, 0xD562, 0x8AA7, 0xD563, 0x8AA8, 0xD564, 0x8AA9, 0xD565, 0x8AAA, 0xD566, + 0x8AAB, 0xD567, 0x8AAC, 0xD568, 0x8AAD, 0xD569, 0x8AAE, 0xD56A, 0x8AAF, 0xD56B, 0x8AB0, 0xD56C, 0x8AB1, 0xD56D, 0x8AB2, 0xD56E, + 0x8AB3, 0xD56F, 0x8AB4, 0xD570, 0x8AB5, 0xD571, 0x8AB6, 0xD572, 0x8AB7, 0xD573, 0x8AB8, 0xD574, 0x8AB9, 0xD575, 0x8ABA, 0xD576, + 0x8ABB, 0xD577, 0x8ABC, 0xD578, 0x8ABD, 0xD579, 0x8ABE, 0xD57A, 0x8ABF, 0xD57B, 0x8AC0, 0xD57C, 0x8AC1, 0xD57D, 0x8AC2, 0xD57E, + 0x8AC3, 0xD580, 0x8AC4, 0xD581, 0x8AC5, 0xD582, 0x8AC6, 0xD583, 0x8AC7, 0xD584, 0x8AC8, 0xD585, 0x8AC9, 0xD586, 0x8ACA, 0xD587, + 0x8ACB, 0xD588, 0x8ACC, 0xD589, 0x8ACD, 0xD58A, 0x8ACE, 0xD58B, 0x8ACF, 0xD58C, 0x8AD0, 0xD58D, 0x8AD1, 0xD58E, 0x8AD2, 0xD58F, + 0x8AD3, 0xD590, 0x8AD4, 0xD591, 0x8AD5, 0xD592, 0x8AD6, 0xD593, 0x8AD7, 0xD594, 0x8AD8, 0xD595, 0x8AD9, 0xD596, 0x8ADA, 0xD597, + 0x8ADB, 0xD598, 0x8ADC, 0xD599, 0x8ADD, 0xD59A, 0x8ADE, 0xD59B, 0x8ADF, 0xD59C, 0x8AE0, 0xD59D, 0x8AE1, 0xD59E, 0x8AE2, 0xD59F, + 0x8AE3, 0xD5A0, 0x8AE4, 0xD640, 0x8AE5, 0xD641, 0x8AE6, 0xD642, 0x8AE7, 0xD643, 0x8AE8, 0xD644, 0x8AE9, 0xD645, 0x8AEA, 0xD646, + 0x8AEB, 0xD647, 0x8AEC, 0xD648, 0x8AED, 0xD649, 0x8AEE, 0xD64A, 0x8AEF, 0xD64B, 0x8AF0, 0xD64C, 0x8AF1, 0xD64D, 0x8AF2, 0xD64E, + 0x8AF3, 0xD64F, 0x8AF4, 0xD650, 0x8AF5, 0xD651, 0x8AF6, 0xD652, 0x8AF7, 0xD653, 0x8AF8, 0xD654, 0x8AF9, 0xD655, 0x8AFA, 0xD656, + 0x8AFB, 0xD657, 0x8AFC, 0xD658, 0x8AFD, 0xD659, 0x8AFE, 0xD65A, 0x8AFF, 0xD65B, 0x8B00, 0xD65C, 0x8B01, 0xD65D, 0x8B02, 0xD65E, + 0x8B03, 0xD65F, 0x8B04, 0xD660, 0x8B05, 0xD661, 0x8B06, 0xD662, 0x8B07, 0xE5C0, 0x8B08, 0xD663, 0x8B09, 0xD664, 0x8B0A, 0xD665, + 0x8B0B, 0xD666, 0x8B0C, 0xD667, 0x8B0D, 0xD668, 0x8B0E, 0xD669, 0x8B0F, 0xD66A, 0x8B10, 0xD66B, 0x8B11, 0xD66C, 0x8B12, 0xD66D, + 0x8B13, 0xD66E, 0x8B14, 0xD66F, 0x8B15, 0xD670, 0x8B16, 0xD671, 0x8B17, 0xD672, 0x8B18, 0xD673, 0x8B19, 0xD674, 0x8B1A, 0xD675, + 0x8B1B, 0xD676, 0x8B1C, 0xD677, 0x8B1D, 0xD678, 0x8B1E, 0xD679, 0x8B1F, 0xD67A, 0x8B20, 0xD67B, 0x8B21, 0xD67C, 0x8B22, 0xD67D, + 0x8B23, 0xD67E, 0x8B24, 0xD680, 0x8B25, 0xD681, 0x8B26, 0xF6A5, 0x8B27, 0xD682, 0x8B28, 0xD683, 0x8B29, 0xD684, 0x8B2A, 0xD685, + 0x8B2B, 0xD686, 0x8B2C, 0xD687, 0x8B2D, 0xD688, 0x8B2E, 0xD689, 0x8B2F, 0xD68A, 0x8B30, 0xD68B, 0x8B31, 0xD68C, 0x8B32, 0xD68D, + 0x8B33, 0xD68E, 0x8B34, 0xD68F, 0x8B35, 0xD690, 0x8B36, 0xD691, 0x8B37, 0xD692, 0x8B38, 0xD693, 0x8B39, 0xD694, 0x8B3A, 0xD695, + 0x8B3B, 0xD696, 0x8B3C, 0xD697, 0x8B3D, 0xD698, 0x8B3E, 0xD699, 0x8B3F, 0xD69A, 0x8B40, 0xD69B, 0x8B41, 0xD69C, 0x8B42, 0xD69D, + 0x8B43, 0xD69E, 0x8B44, 0xD69F, 0x8B45, 0xD6A0, 0x8B46, 0xD740, 0x8B47, 0xD741, 0x8B48, 0xD742, 0x8B49, 0xD743, 0x8B4A, 0xD744, + 0x8B4B, 0xD745, 0x8B4C, 0xD746, 0x8B4D, 0xD747, 0x8B4E, 0xD748, 0x8B4F, 0xD749, 0x8B50, 0xD74A, 0x8B51, 0xD74B, 0x8B52, 0xD74C, + 0x8B53, 0xD74D, 0x8B54, 0xD74E, 0x8B55, 0xD74F, 0x8B56, 0xD750, 0x8B57, 0xD751, 0x8B58, 0xD752, 0x8B59, 0xD753, 0x8B5A, 0xD754, + 0x8B5B, 0xD755, 0x8B5C, 0xD756, 0x8B5D, 0xD757, 0x8B5E, 0xD758, 0x8B5F, 0xD759, 0x8B60, 0xD75A, 0x8B61, 0xD75B, 0x8B62, 0xD75C, + 0x8B63, 0xD75D, 0x8B64, 0xD75E, 0x8B65, 0xD75F, 0x8B66, 0xBEAF, 0x8B67, 0xD760, 0x8B68, 0xD761, 0x8B69, 0xD762, 0x8B6A, 0xD763, + 0x8B6B, 0xD764, 0x8B6C, 0xC6A9, 0x8B6D, 0xD765, 0x8B6E, 0xD766, 0x8B6F, 0xD767, 0x8B70, 0xD768, 0x8B71, 0xD769, 0x8B72, 0xD76A, + 0x8B73, 0xD76B, 0x8B74, 0xD76C, 0x8B75, 0xD76D, 0x8B76, 0xD76E, 0x8B77, 0xD76F, 0x8B78, 0xD770, 0x8B79, 0xD771, 0x8B7A, 0xD772, + 0x8B7B, 0xD773, 0x8B7C, 0xD774, 0x8B7D, 0xD775, 0x8B7E, 0xD776, 0x8B7F, 0xD777, 0x8B80, 0xD778, 0x8B81, 0xD779, 0x8B82, 0xD77A, + 0x8B83, 0xD77B, 0x8B84, 0xD77C, 0x8B85, 0xD77D, 0x8B86, 0xD77E, 0x8B87, 0xD780, 0x8B88, 0xD781, 0x8B89, 0xD782, 0x8B8A, 0xD783, + 0x8B8B, 0xD784, 0x8B8C, 0xD785, 0x8B8D, 0xD786, 0x8B8E, 0xD787, 0x8B8F, 0xD788, 0x8B90, 0xD789, 0x8B91, 0xD78A, 0x8B92, 0xD78B, + 0x8B93, 0xD78C, 0x8B94, 0xD78D, 0x8B95, 0xD78E, 0x8B96, 0xD78F, 0x8B97, 0xD790, 0x8B98, 0xD791, 0x8B99, 0xD792, 0x8B9A, 0xD793, + 0x8B9B, 0xD794, 0x8B9C, 0xD795, 0x8B9D, 0xD796, 0x8B9E, 0xD797, 0x8B9F, 0xD798, 0x8BA0, 0xDAA5, 0x8BA1, 0xBCC6, 0x8BA2, 0xB6A9, + 0x8BA3, 0xB8BC, 0x8BA4, 0xC8CF, 0x8BA5, 0xBCA5, 0x8BA6, 0xDAA6, 0x8BA7, 0xDAA7, 0x8BA8, 0xCCD6, 0x8BA9, 0xC8C3, 0x8BAA, 0xDAA8, + 0x8BAB, 0xC6FD, 0x8BAC, 0xD799, 0x8BAD, 0xD1B5, 0x8BAE, 0xD2E9, 0x8BAF, 0xD1B6, 0x8BB0, 0xBCC7, 0x8BB1, 0xD79A, 0x8BB2, 0xBDB2, + 0x8BB3, 0xBBE4, 0x8BB4, 0xDAA9, 0x8BB5, 0xDAAA, 0x8BB6, 0xD1C8, 0x8BB7, 0xDAAB, 0x8BB8, 0xD0ED, 0x8BB9, 0xB6EF, 0x8BBA, 0xC2DB, + 0x8BBB, 0xD79B, 0x8BBC, 0xCBCF, 0x8BBD, 0xB7ED, 0x8BBE, 0xC9E8, 0x8BBF, 0xB7C3, 0x8BC0, 0xBEF7, 0x8BC1, 0xD6A4, 0x8BC2, 0xDAAC, + 0x8BC3, 0xDAAD, 0x8BC4, 0xC6C0, 0x8BC5, 0xD7E7, 0x8BC6, 0xCAB6, 0x8BC7, 0xD79C, 0x8BC8, 0xD5A9, 0x8BC9, 0xCBDF, 0x8BCA, 0xD5EF, + 0x8BCB, 0xDAAE, 0x8BCC, 0xD6DF, 0x8BCD, 0xB4CA, 0x8BCE, 0xDAB0, 0x8BCF, 0xDAAF, 0x8BD0, 0xD79D, 0x8BD1, 0xD2EB, 0x8BD2, 0xDAB1, + 0x8BD3, 0xDAB2, 0x8BD4, 0xDAB3, 0x8BD5, 0xCAD4, 0x8BD6, 0xDAB4, 0x8BD7, 0xCAAB, 0x8BD8, 0xDAB5, 0x8BD9, 0xDAB6, 0x8BDA, 0xB3CF, + 0x8BDB, 0xD6EF, 0x8BDC, 0xDAB7, 0x8BDD, 0xBBB0, 0x8BDE, 0xB5AE, 0x8BDF, 0xDAB8, 0x8BE0, 0xDAB9, 0x8BE1, 0xB9EE, 0x8BE2, 0xD1AF, + 0x8BE3, 0xD2E8, 0x8BE4, 0xDABA, 0x8BE5, 0xB8C3, 0x8BE6, 0xCFEA, 0x8BE7, 0xB2EF, 0x8BE8, 0xDABB, 0x8BE9, 0xDABC, 0x8BEA, 0xD79E, + 0x8BEB, 0xBDEB, 0x8BEC, 0xCEDC, 0x8BED, 0xD3EF, 0x8BEE, 0xDABD, 0x8BEF, 0xCEF3, 0x8BF0, 0xDABE, 0x8BF1, 0xD3D5, 0x8BF2, 0xBBE5, + 0x8BF3, 0xDABF, 0x8BF4, 0xCBB5, 0x8BF5, 0xCBD0, 0x8BF6, 0xDAC0, 0x8BF7, 0xC7EB, 0x8BF8, 0xD6EE, 0x8BF9, 0xDAC1, 0x8BFA, 0xC5B5, + 0x8BFB, 0xB6C1, 0x8BFC, 0xDAC2, 0x8BFD, 0xB7CC, 0x8BFE, 0xBFCE, 0x8BFF, 0xDAC3, 0x8C00, 0xDAC4, 0x8C01, 0xCBAD, 0x8C02, 0xDAC5, + 0x8C03, 0xB5F7, 0x8C04, 0xDAC6, 0x8C05, 0xC1C2, 0x8C06, 0xD7BB, 0x8C07, 0xDAC7, 0x8C08, 0xCCB8, 0x8C09, 0xD79F, 0x8C0A, 0xD2EA, + 0x8C0B, 0xC4B1, 0x8C0C, 0xDAC8, 0x8C0D, 0xB5FD, 0x8C0E, 0xBBD1, 0x8C0F, 0xDAC9, 0x8C10, 0xD0B3, 0x8C11, 0xDACA, 0x8C12, 0xDACB, + 0x8C13, 0xCEBD, 0x8C14, 0xDACC, 0x8C15, 0xDACD, 0x8C16, 0xDACE, 0x8C17, 0xB2F7, 0x8C18, 0xDAD1, 0x8C19, 0xDACF, 0x8C1A, 0xD1E8, + 0x8C1B, 0xDAD0, 0x8C1C, 0xC3D5, 0x8C1D, 0xDAD2, 0x8C1E, 0xD7A0, 0x8C1F, 0xDAD3, 0x8C20, 0xDAD4, 0x8C21, 0xDAD5, 0x8C22, 0xD0BB, + 0x8C23, 0xD2A5, 0x8C24, 0xB0F9, 0x8C25, 0xDAD6, 0x8C26, 0xC7AB, 0x8C27, 0xDAD7, 0x8C28, 0xBDF7, 0x8C29, 0xC3A1, 0x8C2A, 0xDAD8, + 0x8C2B, 0xDAD9, 0x8C2C, 0xC3FD, 0x8C2D, 0xCCB7, 0x8C2E, 0xDADA, 0x8C2F, 0xDADB, 0x8C30, 0xC0BE, 0x8C31, 0xC6D7, 0x8C32, 0xDADC, + 0x8C33, 0xDADD, 0x8C34, 0xC7B4, 0x8C35, 0xDADE, 0x8C36, 0xDADF, 0x8C37, 0xB9C8, 0x8C38, 0xD840, 0x8C39, 0xD841, 0x8C3A, 0xD842, + 0x8C3B, 0xD843, 0x8C3C, 0xD844, 0x8C3D, 0xD845, 0x8C3E, 0xD846, 0x8C3F, 0xD847, 0x8C40, 0xD848, 0x8C41, 0xBBED, 0x8C42, 0xD849, + 0x8C43, 0xD84A, 0x8C44, 0xD84B, 0x8C45, 0xD84C, 0x8C46, 0xB6B9, 0x8C47, 0xF4F8, 0x8C48, 0xD84D, 0x8C49, 0xF4F9, 0x8C4A, 0xD84E, + 0x8C4B, 0xD84F, 0x8C4C, 0xCDE3, 0x8C4D, 0xD850, 0x8C4E, 0xD851, 0x8C4F, 0xD852, 0x8C50, 0xD853, 0x8C51, 0xD854, 0x8C52, 0xD855, + 0x8C53, 0xD856, 0x8C54, 0xD857, 0x8C55, 0xF5B9, 0x8C56, 0xD858, 0x8C57, 0xD859, 0x8C58, 0xD85A, 0x8C59, 0xD85B, 0x8C5A, 0xEBE0, + 0x8C5B, 0xD85C, 0x8C5C, 0xD85D, 0x8C5D, 0xD85E, 0x8C5E, 0xD85F, 0x8C5F, 0xD860, 0x8C60, 0xD861, 0x8C61, 0xCFF3, 0x8C62, 0xBBBF, + 0x8C63, 0xD862, 0x8C64, 0xD863, 0x8C65, 0xD864, 0x8C66, 0xD865, 0x8C67, 0xD866, 0x8C68, 0xD867, 0x8C69, 0xD868, 0x8C6A, 0xBAC0, + 0x8C6B, 0xD4A5, 0x8C6C, 0xD869, 0x8C6D, 0xD86A, 0x8C6E, 0xD86B, 0x8C6F, 0xD86C, 0x8C70, 0xD86D, 0x8C71, 0xD86E, 0x8C72, 0xD86F, + 0x8C73, 0xE1D9, 0x8C74, 0xD870, 0x8C75, 0xD871, 0x8C76, 0xD872, 0x8C77, 0xD873, 0x8C78, 0xF5F4, 0x8C79, 0xB1AA, 0x8C7A, 0xB2F2, + 0x8C7B, 0xD874, 0x8C7C, 0xD875, 0x8C7D, 0xD876, 0x8C7E, 0xD877, 0x8C7F, 0xD878, 0x8C80, 0xD879, 0x8C81, 0xD87A, 0x8C82, 0xF5F5, + 0x8C83, 0xD87B, 0x8C84, 0xD87C, 0x8C85, 0xF5F7, 0x8C86, 0xD87D, 0x8C87, 0xD87E, 0x8C88, 0xD880, 0x8C89, 0xBAD1, 0x8C8A, 0xF5F6, + 0x8C8B, 0xD881, 0x8C8C, 0xC3B2, 0x8C8D, 0xD882, 0x8C8E, 0xD883, 0x8C8F, 0xD884, 0x8C90, 0xD885, 0x8C91, 0xD886, 0x8C92, 0xD887, + 0x8C93, 0xD888, 0x8C94, 0xF5F9, 0x8C95, 0xD889, 0x8C96, 0xD88A, 0x8C97, 0xD88B, 0x8C98, 0xF5F8, 0x8C99, 0xD88C, 0x8C9A, 0xD88D, + 0x8C9B, 0xD88E, 0x8C9C, 0xD88F, 0x8C9D, 0xD890, 0x8C9E, 0xD891, 0x8C9F, 0xD892, 0x8CA0, 0xD893, 0x8CA1, 0xD894, 0x8CA2, 0xD895, + 0x8CA3, 0xD896, 0x8CA4, 0xD897, 0x8CA5, 0xD898, 0x8CA6, 0xD899, 0x8CA7, 0xD89A, 0x8CA8, 0xD89B, 0x8CA9, 0xD89C, 0x8CAA, 0xD89D, + 0x8CAB, 0xD89E, 0x8CAC, 0xD89F, 0x8CAD, 0xD8A0, 0x8CAE, 0xD940, 0x8CAF, 0xD941, 0x8CB0, 0xD942, 0x8CB1, 0xD943, 0x8CB2, 0xD944, + 0x8CB3, 0xD945, 0x8CB4, 0xD946, 0x8CB5, 0xD947, 0x8CB6, 0xD948, 0x8CB7, 0xD949, 0x8CB8, 0xD94A, 0x8CB9, 0xD94B, 0x8CBA, 0xD94C, + 0x8CBB, 0xD94D, 0x8CBC, 0xD94E, 0x8CBD, 0xD94F, 0x8CBE, 0xD950, 0x8CBF, 0xD951, 0x8CC0, 0xD952, 0x8CC1, 0xD953, 0x8CC2, 0xD954, + 0x8CC3, 0xD955, 0x8CC4, 0xD956, 0x8CC5, 0xD957, 0x8CC6, 0xD958, 0x8CC7, 0xD959, 0x8CC8, 0xD95A, 0x8CC9, 0xD95B, 0x8CCA, 0xD95C, + 0x8CCB, 0xD95D, 0x8CCC, 0xD95E, 0x8CCD, 0xD95F, 0x8CCE, 0xD960, 0x8CCF, 0xD961, 0x8CD0, 0xD962, 0x8CD1, 0xD963, 0x8CD2, 0xD964, + 0x8CD3, 0xD965, 0x8CD4, 0xD966, 0x8CD5, 0xD967, 0x8CD6, 0xD968, 0x8CD7, 0xD969, 0x8CD8, 0xD96A, 0x8CD9, 0xD96B, 0x8CDA, 0xD96C, + 0x8CDB, 0xD96D, 0x8CDC, 0xD96E, 0x8CDD, 0xD96F, 0x8CDE, 0xD970, 0x8CDF, 0xD971, 0x8CE0, 0xD972, 0x8CE1, 0xD973, 0x8CE2, 0xD974, + 0x8CE3, 0xD975, 0x8CE4, 0xD976, 0x8CE5, 0xD977, 0x8CE6, 0xD978, 0x8CE7, 0xD979, 0x8CE8, 0xD97A, 0x8CE9, 0xD97B, 0x8CEA, 0xD97C, + 0x8CEB, 0xD97D, 0x8CEC, 0xD97E, 0x8CED, 0xD980, 0x8CEE, 0xD981, 0x8CEF, 0xD982, 0x8CF0, 0xD983, 0x8CF1, 0xD984, 0x8CF2, 0xD985, + 0x8CF3, 0xD986, 0x8CF4, 0xD987, 0x8CF5, 0xD988, 0x8CF6, 0xD989, 0x8CF7, 0xD98A, 0x8CF8, 0xD98B, 0x8CF9, 0xD98C, 0x8CFA, 0xD98D, + 0x8CFB, 0xD98E, 0x8CFC, 0xD98F, 0x8CFD, 0xD990, 0x8CFE, 0xD991, 0x8CFF, 0xD992, 0x8D00, 0xD993, 0x8D01, 0xD994, 0x8D02, 0xD995, + 0x8D03, 0xD996, 0x8D04, 0xD997, 0x8D05, 0xD998, 0x8D06, 0xD999, 0x8D07, 0xD99A, 0x8D08, 0xD99B, 0x8D09, 0xD99C, 0x8D0A, 0xD99D, + 0x8D0B, 0xD99E, 0x8D0C, 0xD99F, 0x8D0D, 0xD9A0, 0x8D0E, 0xDA40, 0x8D0F, 0xDA41, 0x8D10, 0xDA42, 0x8D11, 0xDA43, 0x8D12, 0xDA44, + 0x8D13, 0xDA45, 0x8D14, 0xDA46, 0x8D15, 0xDA47, 0x8D16, 0xDA48, 0x8D17, 0xDA49, 0x8D18, 0xDA4A, 0x8D19, 0xDA4B, 0x8D1A, 0xDA4C, + 0x8D1B, 0xDA4D, 0x8D1C, 0xDA4E, 0x8D1D, 0xB1B4, 0x8D1E, 0xD5EA, 0x8D1F, 0xB8BA, 0x8D20, 0xDA4F, 0x8D21, 0xB9B1, 0x8D22, 0xB2C6, + 0x8D23, 0xD4F0, 0x8D24, 0xCFCD, 0x8D25, 0xB0DC, 0x8D26, 0xD5CB, 0x8D27, 0xBBF5, 0x8D28, 0xD6CA, 0x8D29, 0xB7B7, 0x8D2A, 0xCCB0, + 0x8D2B, 0xC6B6, 0x8D2C, 0xB1E1, 0x8D2D, 0xB9BA, 0x8D2E, 0xD6FC, 0x8D2F, 0xB9E1, 0x8D30, 0xB7A1, 0x8D31, 0xBCFA, 0x8D32, 0xEADA, + 0x8D33, 0xEADB, 0x8D34, 0xCCF9, 0x8D35, 0xB9F3, 0x8D36, 0xEADC, 0x8D37, 0xB4FB, 0x8D38, 0xC3B3, 0x8D39, 0xB7D1, 0x8D3A, 0xBAD8, + 0x8D3B, 0xEADD, 0x8D3C, 0xD4F4, 0x8D3D, 0xEADE, 0x8D3E, 0xBCD6, 0x8D3F, 0xBBDF, 0x8D40, 0xEADF, 0x8D41, 0xC1DE, 0x8D42, 0xC2B8, + 0x8D43, 0xD4DF, 0x8D44, 0xD7CA, 0x8D45, 0xEAE0, 0x8D46, 0xEAE1, 0x8D47, 0xEAE4, 0x8D48, 0xEAE2, 0x8D49, 0xEAE3, 0x8D4A, 0xC9DE, + 0x8D4B, 0xB8B3, 0x8D4C, 0xB6C4, 0x8D4D, 0xEAE5, 0x8D4E, 0xCAEA, 0x8D4F, 0xC9CD, 0x8D50, 0xB4CD, 0x8D51, 0xDA50, 0x8D52, 0xDA51, + 0x8D53, 0xE2D9, 0x8D54, 0xC5E2, 0x8D55, 0xEAE6, 0x8D56, 0xC0B5, 0x8D57, 0xDA52, 0x8D58, 0xD7B8, 0x8D59, 0xEAE7, 0x8D5A, 0xD7AC, + 0x8D5B, 0xC8FC, 0x8D5C, 0xD8D3, 0x8D5D, 0xD8CD, 0x8D5E, 0xD4DE, 0x8D5F, 0xDA53, 0x8D60, 0xD4F9, 0x8D61, 0xC9C4, 0x8D62, 0xD3AE, + 0x8D63, 0xB8D3, 0x8D64, 0xB3E0, 0x8D65, 0xDA54, 0x8D66, 0xC9E2, 0x8D67, 0xF4F6, 0x8D68, 0xDA55, 0x8D69, 0xDA56, 0x8D6A, 0xDA57, + 0x8D6B, 0xBAD5, 0x8D6C, 0xDA58, 0x8D6D, 0xF4F7, 0x8D6E, 0xDA59, 0x8D6F, 0xDA5A, 0x8D70, 0xD7DF, 0x8D71, 0xDA5B, 0x8D72, 0xDA5C, + 0x8D73, 0xF4F1, 0x8D74, 0xB8B0, 0x8D75, 0xD5D4, 0x8D76, 0xB8CF, 0x8D77, 0xC6F0, 0x8D78, 0xDA5D, 0x8D79, 0xDA5E, 0x8D7A, 0xDA5F, + 0x8D7B, 0xDA60, 0x8D7C, 0xDA61, 0x8D7D, 0xDA62, 0x8D7E, 0xDA63, 0x8D7F, 0xDA64, 0x8D80, 0xDA65, 0x8D81, 0xB3C3, 0x8D82, 0xDA66, + 0x8D83, 0xDA67, 0x8D84, 0xF4F2, 0x8D85, 0xB3AC, 0x8D86, 0xDA68, 0x8D87, 0xDA69, 0x8D88, 0xDA6A, 0x8D89, 0xDA6B, 0x8D8A, 0xD4BD, + 0x8D8B, 0xC7F7, 0x8D8C, 0xDA6C, 0x8D8D, 0xDA6D, 0x8D8E, 0xDA6E, 0x8D8F, 0xDA6F, 0x8D90, 0xDA70, 0x8D91, 0xF4F4, 0x8D92, 0xDA71, + 0x8D93, 0xDA72, 0x8D94, 0xF4F3, 0x8D95, 0xDA73, 0x8D96, 0xDA74, 0x8D97, 0xDA75, 0x8D98, 0xDA76, 0x8D99, 0xDA77, 0x8D9A, 0xDA78, + 0x8D9B, 0xDA79, 0x8D9C, 0xDA7A, 0x8D9D, 0xDA7B, 0x8D9E, 0xDA7C, 0x8D9F, 0xCCCB, 0x8DA0, 0xDA7D, 0x8DA1, 0xDA7E, 0x8DA2, 0xDA80, + 0x8DA3, 0xC8A4, 0x8DA4, 0xDA81, 0x8DA5, 0xDA82, 0x8DA6, 0xDA83, 0x8DA7, 0xDA84, 0x8DA8, 0xDA85, 0x8DA9, 0xDA86, 0x8DAA, 0xDA87, + 0x8DAB, 0xDA88, 0x8DAC, 0xDA89, 0x8DAD, 0xDA8A, 0x8DAE, 0xDA8B, 0x8DAF, 0xDA8C, 0x8DB0, 0xDA8D, 0x8DB1, 0xF4F5, 0x8DB2, 0xDA8E, + 0x8DB3, 0xD7E3, 0x8DB4, 0xC5BF, 0x8DB5, 0xF5C0, 0x8DB6, 0xDA8F, 0x8DB7, 0xDA90, 0x8DB8, 0xF5BB, 0x8DB9, 0xDA91, 0x8DBA, 0xF5C3, + 0x8DBB, 0xDA92, 0x8DBC, 0xF5C2, 0x8DBD, 0xDA93, 0x8DBE, 0xD6BA, 0x8DBF, 0xF5C1, 0x8DC0, 0xDA94, 0x8DC1, 0xDA95, 0x8DC2, 0xDA96, + 0x8DC3, 0xD4BE, 0x8DC4, 0xF5C4, 0x8DC5, 0xDA97, 0x8DC6, 0xF5CC, 0x8DC7, 0xDA98, 0x8DC8, 0xDA99, 0x8DC9, 0xDA9A, 0x8DCA, 0xDA9B, + 0x8DCB, 0xB0CF, 0x8DCC, 0xB5F8, 0x8DCD, 0xDA9C, 0x8DCE, 0xF5C9, 0x8DCF, 0xF5CA, 0x8DD0, 0xDA9D, 0x8DD1, 0xC5DC, 0x8DD2, 0xDA9E, + 0x8DD3, 0xDA9F, 0x8DD4, 0xDAA0, 0x8DD5, 0xDB40, 0x8DD6, 0xF5C5, 0x8DD7, 0xF5C6, 0x8DD8, 0xDB41, 0x8DD9, 0xDB42, 0x8DDA, 0xF5C7, + 0x8DDB, 0xF5CB, 0x8DDC, 0xDB43, 0x8DDD, 0xBEE0, 0x8DDE, 0xF5C8, 0x8DDF, 0xB8FA, 0x8DE0, 0xDB44, 0x8DE1, 0xDB45, 0x8DE2, 0xDB46, + 0x8DE3, 0xF5D0, 0x8DE4, 0xF5D3, 0x8DE5, 0xDB47, 0x8DE6, 0xDB48, 0x8DE7, 0xDB49, 0x8DE8, 0xBFE7, 0x8DE9, 0xDB4A, 0x8DEA, 0xB9F2, + 0x8DEB, 0xF5BC, 0x8DEC, 0xF5CD, 0x8DED, 0xDB4B, 0x8DEE, 0xDB4C, 0x8DEF, 0xC2B7, 0x8DF0, 0xDB4D, 0x8DF1, 0xDB4E, 0x8DF2, 0xDB4F, + 0x8DF3, 0xCCF8, 0x8DF4, 0xDB50, 0x8DF5, 0xBCF9, 0x8DF6, 0xDB51, 0x8DF7, 0xF5CE, 0x8DF8, 0xF5CF, 0x8DF9, 0xF5D1, 0x8DFA, 0xB6E5, + 0x8DFB, 0xF5D2, 0x8DFC, 0xDB52, 0x8DFD, 0xF5D5, 0x8DFE, 0xDB53, 0x8DFF, 0xDB54, 0x8E00, 0xDB55, 0x8E01, 0xDB56, 0x8E02, 0xDB57, + 0x8E03, 0xDB58, 0x8E04, 0xDB59, 0x8E05, 0xF5BD, 0x8E06, 0xDB5A, 0x8E07, 0xDB5B, 0x8E08, 0xDB5C, 0x8E09, 0xF5D4, 0x8E0A, 0xD3BB, + 0x8E0B, 0xDB5D, 0x8E0C, 0xB3EC, 0x8E0D, 0xDB5E, 0x8E0E, 0xDB5F, 0x8E0F, 0xCCA4, 0x8E10, 0xDB60, 0x8E11, 0xDB61, 0x8E12, 0xDB62, + 0x8E13, 0xDB63, 0x8E14, 0xF5D6, 0x8E15, 0xDB64, 0x8E16, 0xDB65, 0x8E17, 0xDB66, 0x8E18, 0xDB67, 0x8E19, 0xDB68, 0x8E1A, 0xDB69, + 0x8E1B, 0xDB6A, 0x8E1C, 0xDB6B, 0x8E1D, 0xF5D7, 0x8E1E, 0xBEE1, 0x8E1F, 0xF5D8, 0x8E20, 0xDB6C, 0x8E21, 0xDB6D, 0x8E22, 0xCCDF, + 0x8E23, 0xF5DB, 0x8E24, 0xDB6E, 0x8E25, 0xDB6F, 0x8E26, 0xDB70, 0x8E27, 0xDB71, 0x8E28, 0xDB72, 0x8E29, 0xB2C8, 0x8E2A, 0xD7D9, + 0x8E2B, 0xDB73, 0x8E2C, 0xF5D9, 0x8E2D, 0xDB74, 0x8E2E, 0xF5DA, 0x8E2F, 0xF5DC, 0x8E30, 0xDB75, 0x8E31, 0xF5E2, 0x8E32, 0xDB76, + 0x8E33, 0xDB77, 0x8E34, 0xDB78, 0x8E35, 0xF5E0, 0x8E36, 0xDB79, 0x8E37, 0xDB7A, 0x8E38, 0xDB7B, 0x8E39, 0xF5DF, 0x8E3A, 0xF5DD, + 0x8E3B, 0xDB7C, 0x8E3C, 0xDB7D, 0x8E3D, 0xF5E1, 0x8E3E, 0xDB7E, 0x8E3F, 0xDB80, 0x8E40, 0xF5DE, 0x8E41, 0xF5E4, 0x8E42, 0xF5E5, + 0x8E43, 0xDB81, 0x8E44, 0xCCE3, 0x8E45, 0xDB82, 0x8E46, 0xDB83, 0x8E47, 0xE5BF, 0x8E48, 0xB5B8, 0x8E49, 0xF5E3, 0x8E4A, 0xF5E8, + 0x8E4B, 0xCCA3, 0x8E4C, 0xDB84, 0x8E4D, 0xDB85, 0x8E4E, 0xDB86, 0x8E4F, 0xDB87, 0x8E50, 0xDB88, 0x8E51, 0xF5E6, 0x8E52, 0xF5E7, + 0x8E53, 0xDB89, 0x8E54, 0xDB8A, 0x8E55, 0xDB8B, 0x8E56, 0xDB8C, 0x8E57, 0xDB8D, 0x8E58, 0xDB8E, 0x8E59, 0xF5BE, 0x8E5A, 0xDB8F, + 0x8E5B, 0xDB90, 0x8E5C, 0xDB91, 0x8E5D, 0xDB92, 0x8E5E, 0xDB93, 0x8E5F, 0xDB94, 0x8E60, 0xDB95, 0x8E61, 0xDB96, 0x8E62, 0xDB97, + 0x8E63, 0xDB98, 0x8E64, 0xDB99, 0x8E65, 0xDB9A, 0x8E66, 0xB1C4, 0x8E67, 0xDB9B, 0x8E68, 0xDB9C, 0x8E69, 0xF5BF, 0x8E6A, 0xDB9D, + 0x8E6B, 0xDB9E, 0x8E6C, 0xB5C5, 0x8E6D, 0xB2E4, 0x8E6E, 0xDB9F, 0x8E6F, 0xF5EC, 0x8E70, 0xF5E9, 0x8E71, 0xDBA0, 0x8E72, 0xB6D7, + 0x8E73, 0xDC40, 0x8E74, 0xF5ED, 0x8E75, 0xDC41, 0x8E76, 0xF5EA, 0x8E77, 0xDC42, 0x8E78, 0xDC43, 0x8E79, 0xDC44, 0x8E7A, 0xDC45, + 0x8E7B, 0xDC46, 0x8E7C, 0xF5EB, 0x8E7D, 0xDC47, 0x8E7E, 0xDC48, 0x8E7F, 0xB4DA, 0x8E80, 0xDC49, 0x8E81, 0xD4EA, 0x8E82, 0xDC4A, + 0x8E83, 0xDC4B, 0x8E84, 0xDC4C, 0x8E85, 0xF5EE, 0x8E86, 0xDC4D, 0x8E87, 0xB3F9, 0x8E88, 0xDC4E, 0x8E89, 0xDC4F, 0x8E8A, 0xDC50, + 0x8E8B, 0xDC51, 0x8E8C, 0xDC52, 0x8E8D, 0xDC53, 0x8E8E, 0xDC54, 0x8E8F, 0xF5EF, 0x8E90, 0xF5F1, 0x8E91, 0xDC55, 0x8E92, 0xDC56, + 0x8E93, 0xDC57, 0x8E94, 0xF5F0, 0x8E95, 0xDC58, 0x8E96, 0xDC59, 0x8E97, 0xDC5A, 0x8E98, 0xDC5B, 0x8E99, 0xDC5C, 0x8E9A, 0xDC5D, + 0x8E9B, 0xDC5E, 0x8E9C, 0xF5F2, 0x8E9D, 0xDC5F, 0x8E9E, 0xF5F3, 0x8E9F, 0xDC60, 0x8EA0, 0xDC61, 0x8EA1, 0xDC62, 0x8EA2, 0xDC63, + 0x8EA3, 0xDC64, 0x8EA4, 0xDC65, 0x8EA5, 0xDC66, 0x8EA6, 0xDC67, 0x8EA7, 0xDC68, 0x8EA8, 0xDC69, 0x8EA9, 0xDC6A, 0x8EAA, 0xDC6B, + 0x8EAB, 0xC9ED, 0x8EAC, 0xB9AA, 0x8EAD, 0xDC6C, 0x8EAE, 0xDC6D, 0x8EAF, 0xC7FB, 0x8EB0, 0xDC6E, 0x8EB1, 0xDC6F, 0x8EB2, 0xB6E3, + 0x8EB3, 0xDC70, 0x8EB4, 0xDC71, 0x8EB5, 0xDC72, 0x8EB6, 0xDC73, 0x8EB7, 0xDC74, 0x8EB8, 0xDC75, 0x8EB9, 0xDC76, 0x8EBA, 0xCCC9, + 0x8EBB, 0xDC77, 0x8EBC, 0xDC78, 0x8EBD, 0xDC79, 0x8EBE, 0xDC7A, 0x8EBF, 0xDC7B, 0x8EC0, 0xDC7C, 0x8EC1, 0xDC7D, 0x8EC2, 0xDC7E, + 0x8EC3, 0xDC80, 0x8EC4, 0xDC81, 0x8EC5, 0xDC82, 0x8EC6, 0xDC83, 0x8EC7, 0xDC84, 0x8EC8, 0xDC85, 0x8EC9, 0xDC86, 0x8ECA, 0xDC87, + 0x8ECB, 0xDC88, 0x8ECC, 0xDC89, 0x8ECD, 0xDC8A, 0x8ECE, 0xEAA6, 0x8ECF, 0xDC8B, 0x8ED0, 0xDC8C, 0x8ED1, 0xDC8D, 0x8ED2, 0xDC8E, + 0x8ED3, 0xDC8F, 0x8ED4, 0xDC90, 0x8ED5, 0xDC91, 0x8ED6, 0xDC92, 0x8ED7, 0xDC93, 0x8ED8, 0xDC94, 0x8ED9, 0xDC95, 0x8EDA, 0xDC96, + 0x8EDB, 0xDC97, 0x8EDC, 0xDC98, 0x8EDD, 0xDC99, 0x8EDE, 0xDC9A, 0x8EDF, 0xDC9B, 0x8EE0, 0xDC9C, 0x8EE1, 0xDC9D, 0x8EE2, 0xDC9E, + 0x8EE3, 0xDC9F, 0x8EE4, 0xDCA0, 0x8EE5, 0xDD40, 0x8EE6, 0xDD41, 0x8EE7, 0xDD42, 0x8EE8, 0xDD43, 0x8EE9, 0xDD44, 0x8EEA, 0xDD45, + 0x8EEB, 0xDD46, 0x8EEC, 0xDD47, 0x8EED, 0xDD48, 0x8EEE, 0xDD49, 0x8EEF, 0xDD4A, 0x8EF0, 0xDD4B, 0x8EF1, 0xDD4C, 0x8EF2, 0xDD4D, + 0x8EF3, 0xDD4E, 0x8EF4, 0xDD4F, 0x8EF5, 0xDD50, 0x8EF6, 0xDD51, 0x8EF7, 0xDD52, 0x8EF8, 0xDD53, 0x8EF9, 0xDD54, 0x8EFA, 0xDD55, + 0x8EFB, 0xDD56, 0x8EFC, 0xDD57, 0x8EFD, 0xDD58, 0x8EFE, 0xDD59, 0x8EFF, 0xDD5A, 0x8F00, 0xDD5B, 0x8F01, 0xDD5C, 0x8F02, 0xDD5D, + 0x8F03, 0xDD5E, 0x8F04, 0xDD5F, 0x8F05, 0xDD60, 0x8F06, 0xDD61, 0x8F07, 0xDD62, 0x8F08, 0xDD63, 0x8F09, 0xDD64, 0x8F0A, 0xDD65, + 0x8F0B, 0xDD66, 0x8F0C, 0xDD67, 0x8F0D, 0xDD68, 0x8F0E, 0xDD69, 0x8F0F, 0xDD6A, 0x8F10, 0xDD6B, 0x8F11, 0xDD6C, 0x8F12, 0xDD6D, + 0x8F13, 0xDD6E, 0x8F14, 0xDD6F, 0x8F15, 0xDD70, 0x8F16, 0xDD71, 0x8F17, 0xDD72, 0x8F18, 0xDD73, 0x8F19, 0xDD74, 0x8F1A, 0xDD75, + 0x8F1B, 0xDD76, 0x8F1C, 0xDD77, 0x8F1D, 0xDD78, 0x8F1E, 0xDD79, 0x8F1F, 0xDD7A, 0x8F20, 0xDD7B, 0x8F21, 0xDD7C, 0x8F22, 0xDD7D, + 0x8F23, 0xDD7E, 0x8F24, 0xDD80, 0x8F25, 0xDD81, 0x8F26, 0xDD82, 0x8F27, 0xDD83, 0x8F28, 0xDD84, 0x8F29, 0xDD85, 0x8F2A, 0xDD86, + 0x8F2B, 0xDD87, 0x8F2C, 0xDD88, 0x8F2D, 0xDD89, 0x8F2E, 0xDD8A, 0x8F2F, 0xDD8B, 0x8F30, 0xDD8C, 0x8F31, 0xDD8D, 0x8F32, 0xDD8E, + 0x8F33, 0xDD8F, 0x8F34, 0xDD90, 0x8F35, 0xDD91, 0x8F36, 0xDD92, 0x8F37, 0xDD93, 0x8F38, 0xDD94, 0x8F39, 0xDD95, 0x8F3A, 0xDD96, + 0x8F3B, 0xDD97, 0x8F3C, 0xDD98, 0x8F3D, 0xDD99, 0x8F3E, 0xDD9A, 0x8F3F, 0xDD9B, 0x8F40, 0xDD9C, 0x8F41, 0xDD9D, 0x8F42, 0xDD9E, + 0x8F43, 0xDD9F, 0x8F44, 0xDDA0, 0x8F45, 0xDE40, 0x8F46, 0xDE41, 0x8F47, 0xDE42, 0x8F48, 0xDE43, 0x8F49, 0xDE44, 0x8F4A, 0xDE45, + 0x8F4B, 0xDE46, 0x8F4C, 0xDE47, 0x8F4D, 0xDE48, 0x8F4E, 0xDE49, 0x8F4F, 0xDE4A, 0x8F50, 0xDE4B, 0x8F51, 0xDE4C, 0x8F52, 0xDE4D, + 0x8F53, 0xDE4E, 0x8F54, 0xDE4F, 0x8F55, 0xDE50, 0x8F56, 0xDE51, 0x8F57, 0xDE52, 0x8F58, 0xDE53, 0x8F59, 0xDE54, 0x8F5A, 0xDE55, + 0x8F5B, 0xDE56, 0x8F5C, 0xDE57, 0x8F5D, 0xDE58, 0x8F5E, 0xDE59, 0x8F5F, 0xDE5A, 0x8F60, 0xDE5B, 0x8F61, 0xDE5C, 0x8F62, 0xDE5D, + 0x8F63, 0xDE5E, 0x8F64, 0xDE5F, 0x8F65, 0xDE60, 0x8F66, 0xB3B5, 0x8F67, 0xD4FE, 0x8F68, 0xB9EC, 0x8F69, 0xD0F9, 0x8F6A, 0xDE61, + 0x8F6B, 0xE9ED, 0x8F6C, 0xD7AA, 0x8F6D, 0xE9EE, 0x8F6E, 0xC2D6, 0x8F6F, 0xC8ED, 0x8F70, 0xBAE4, 0x8F71, 0xE9EF, 0x8F72, 0xE9F0, + 0x8F73, 0xE9F1, 0x8F74, 0xD6E1, 0x8F75, 0xE9F2, 0x8F76, 0xE9F3, 0x8F77, 0xE9F5, 0x8F78, 0xE9F4, 0x8F79, 0xE9F6, 0x8F7A, 0xE9F7, + 0x8F7B, 0xC7E1, 0x8F7C, 0xE9F8, 0x8F7D, 0xD4D8, 0x8F7E, 0xE9F9, 0x8F7F, 0xBDCE, 0x8F80, 0xDE62, 0x8F81, 0xE9FA, 0x8F82, 0xE9FB, + 0x8F83, 0xBDCF, 0x8F84, 0xE9FC, 0x8F85, 0xB8A8, 0x8F86, 0xC1BE, 0x8F87, 0xE9FD, 0x8F88, 0xB1B2, 0x8F89, 0xBBD4, 0x8F8A, 0xB9F5, + 0x8F8B, 0xE9FE, 0x8F8C, 0xDE63, 0x8F8D, 0xEAA1, 0x8F8E, 0xEAA2, 0x8F8F, 0xEAA3, 0x8F90, 0xB7F8, 0x8F91, 0xBCAD, 0x8F92, 0xDE64, + 0x8F93, 0xCAE4, 0x8F94, 0xE0CE, 0x8F95, 0xD4AF, 0x8F96, 0xCFBD, 0x8F97, 0xD5B7, 0x8F98, 0xEAA4, 0x8F99, 0xD5DE, 0x8F9A, 0xEAA5, + 0x8F9B, 0xD0C1, 0x8F9C, 0xB9BC, 0x8F9D, 0xDE65, 0x8F9E, 0xB4C7, 0x8F9F, 0xB1D9, 0x8FA0, 0xDE66, 0x8FA1, 0xDE67, 0x8FA2, 0xDE68, + 0x8FA3, 0xC0B1, 0x8FA4, 0xDE69, 0x8FA5, 0xDE6A, 0x8FA6, 0xDE6B, 0x8FA7, 0xDE6C, 0x8FA8, 0xB1E6, 0x8FA9, 0xB1E7, 0x8FAA, 0xDE6D, + 0x8FAB, 0xB1E8, 0x8FAC, 0xDE6E, 0x8FAD, 0xDE6F, 0x8FAE, 0xDE70, 0x8FAF, 0xDE71, 0x8FB0, 0xB3BD, 0x8FB1, 0xC8E8, 0x8FB2, 0xDE72, + 0x8FB3, 0xDE73, 0x8FB4, 0xDE74, 0x8FB5, 0xDE75, 0x8FB6, 0xE5C1, 0x8FB7, 0xDE76, 0x8FB8, 0xDE77, 0x8FB9, 0xB1DF, 0x8FBA, 0xDE78, + 0x8FBB, 0xDE79, 0x8FBC, 0xDE7A, 0x8FBD, 0xC1C9, 0x8FBE, 0xB4EF, 0x8FBF, 0xDE7B, 0x8FC0, 0xDE7C, 0x8FC1, 0xC7A8, 0x8FC2, 0xD3D8, + 0x8FC3, 0xDE7D, 0x8FC4, 0xC6F9, 0x8FC5, 0xD1B8, 0x8FC6, 0xDE7E, 0x8FC7, 0xB9FD, 0x8FC8, 0xC2F5, 0x8FC9, 0xDE80, 0x8FCA, 0xDE81, + 0x8FCB, 0xDE82, 0x8FCC, 0xDE83, 0x8FCD, 0xDE84, 0x8FCE, 0xD3AD, 0x8FCF, 0xDE85, 0x8FD0, 0xD4CB, 0x8FD1, 0xBDFC, 0x8FD2, 0xDE86, + 0x8FD3, 0xE5C2, 0x8FD4, 0xB7B5, 0x8FD5, 0xE5C3, 0x8FD6, 0xDE87, 0x8FD7, 0xDE88, 0x8FD8, 0xBBB9, 0x8FD9, 0xD5E2, 0x8FDA, 0xDE89, + 0x8FDB, 0xBDF8, 0x8FDC, 0xD4B6, 0x8FDD, 0xCEA5, 0x8FDE, 0xC1AC, 0x8FDF, 0xB3D9, 0x8FE0, 0xDE8A, 0x8FE1, 0xDE8B, 0x8FE2, 0xCCF6, + 0x8FE3, 0xDE8C, 0x8FE4, 0xE5C6, 0x8FE5, 0xE5C4, 0x8FE6, 0xE5C8, 0x8FE7, 0xDE8D, 0x8FE8, 0xE5CA, 0x8FE9, 0xE5C7, 0x8FEA, 0xB5CF, + 0x8FEB, 0xC6C8, 0x8FEC, 0xDE8E, 0x8FED, 0xB5FC, 0x8FEE, 0xE5C5, 0x8FEF, 0xDE8F, 0x8FF0, 0xCAF6, 0x8FF1, 0xDE90, 0x8FF2, 0xDE91, + 0x8FF3, 0xE5C9, 0x8FF4, 0xDE92, 0x8FF5, 0xDE93, 0x8FF6, 0xDE94, 0x8FF7, 0xC3D4, 0x8FF8, 0xB1C5, 0x8FF9, 0xBCA3, 0x8FFA, 0xDE95, + 0x8FFB, 0xDE96, 0x8FFC, 0xDE97, 0x8FFD, 0xD7B7, 0x8FFE, 0xDE98, 0x8FFF, 0xDE99, 0x9000, 0xCDCB, 0x9001, 0xCBCD, 0x9002, 0xCACA, + 0x9003, 0xCCD3, 0x9004, 0xE5CC, 0x9005, 0xE5CB, 0x9006, 0xC4E6, 0x9007, 0xDE9A, 0x9008, 0xDE9B, 0x9009, 0xD1A1, 0x900A, 0xD1B7, + 0x900B, 0xE5CD, 0x900C, 0xDE9C, 0x900D, 0xE5D0, 0x900E, 0xDE9D, 0x900F, 0xCDB8, 0x9010, 0xD6F0, 0x9011, 0xE5CF, 0x9012, 0xB5DD, + 0x9013, 0xDE9E, 0x9014, 0xCDBE, 0x9015, 0xDE9F, 0x9016, 0xE5D1, 0x9017, 0xB6BA, 0x9018, 0xDEA0, 0x9019, 0xDF40, 0x901A, 0xCDA8, + 0x901B, 0xB9E4, 0x901C, 0xDF41, 0x901D, 0xCAC5, 0x901E, 0xB3D1, 0x901F, 0xCBD9, 0x9020, 0xD4EC, 0x9021, 0xE5D2, 0x9022, 0xB7EA, + 0x9023, 0xDF42, 0x9024, 0xDF43, 0x9025, 0xDF44, 0x9026, 0xE5CE, 0x9027, 0xDF45, 0x9028, 0xDF46, 0x9029, 0xDF47, 0x902A, 0xDF48, + 0x902B, 0xDF49, 0x902C, 0xDF4A, 0x902D, 0xE5D5, 0x902E, 0xB4FE, 0x902F, 0xE5D6, 0x9030, 0xDF4B, 0x9031, 0xDF4C, 0x9032, 0xDF4D, + 0x9033, 0xDF4E, 0x9034, 0xDF4F, 0x9035, 0xE5D3, 0x9036, 0xE5D4, 0x9037, 0xDF50, 0x9038, 0xD2DD, 0x9039, 0xDF51, 0x903A, 0xDF52, + 0x903B, 0xC2DF, 0x903C, 0xB1C6, 0x903D, 0xDF53, 0x903E, 0xD3E2, 0x903F, 0xDF54, 0x9040, 0xDF55, 0x9041, 0xB6DD, 0x9042, 0xCBEC, + 0x9043, 0xDF56, 0x9044, 0xE5D7, 0x9045, 0xDF57, 0x9046, 0xDF58, 0x9047, 0xD3F6, 0x9048, 0xDF59, 0x9049, 0xDF5A, 0x904A, 0xDF5B, + 0x904B, 0xDF5C, 0x904C, 0xDF5D, 0x904D, 0xB1E9, 0x904E, 0xDF5E, 0x904F, 0xB6F4, 0x9050, 0xE5DA, 0x9051, 0xE5D8, 0x9052, 0xE5D9, + 0x9053, 0xB5C0, 0x9054, 0xDF5F, 0x9055, 0xDF60, 0x9056, 0xDF61, 0x9057, 0xD2C5, 0x9058, 0xE5DC, 0x9059, 0xDF62, 0x905A, 0xDF63, + 0x905B, 0xE5DE, 0x905C, 0xDF64, 0x905D, 0xDF65, 0x905E, 0xDF66, 0x905F, 0xDF67, 0x9060, 0xDF68, 0x9061, 0xDF69, 0x9062, 0xE5DD, + 0x9063, 0xC7B2, 0x9064, 0xDF6A, 0x9065, 0xD2A3, 0x9066, 0xDF6B, 0x9067, 0xDF6C, 0x9068, 0xE5DB, 0x9069, 0xDF6D, 0x906A, 0xDF6E, + 0x906B, 0xDF6F, 0x906C, 0xDF70, 0x906D, 0xD4E2, 0x906E, 0xD5DA, 0x906F, 0xDF71, 0x9070, 0xDF72, 0x9071, 0xDF73, 0x9072, 0xDF74, + 0x9073, 0xDF75, 0x9074, 0xE5E0, 0x9075, 0xD7F1, 0x9076, 0xDF76, 0x9077, 0xDF77, 0x9078, 0xDF78, 0x9079, 0xDF79, 0x907A, 0xDF7A, + 0x907B, 0xDF7B, 0x907C, 0xDF7C, 0x907D, 0xE5E1, 0x907E, 0xDF7D, 0x907F, 0xB1DC, 0x9080, 0xD1FB, 0x9081, 0xDF7E, 0x9082, 0xE5E2, + 0x9083, 0xE5E4, 0x9084, 0xDF80, 0x9085, 0xDF81, 0x9086, 0xDF82, 0x9087, 0xDF83, 0x9088, 0xE5E3, 0x9089, 0xDF84, 0x908A, 0xDF85, + 0x908B, 0xE5E5, 0x908C, 0xDF86, 0x908D, 0xDF87, 0x908E, 0xDF88, 0x908F, 0xDF89, 0x9090, 0xDF8A, 0x9091, 0xD2D8, 0x9092, 0xDF8B, + 0x9093, 0xB5CB, 0x9094, 0xDF8C, 0x9095, 0xE7DF, 0x9096, 0xDF8D, 0x9097, 0xDAF5, 0x9098, 0xDF8E, 0x9099, 0xDAF8, 0x909A, 0xDF8F, + 0x909B, 0xDAF6, 0x909C, 0xDF90, 0x909D, 0xDAF7, 0x909E, 0xDF91, 0x909F, 0xDF92, 0x90A0, 0xDF93, 0x90A1, 0xDAFA, 0x90A2, 0xD0CF, + 0x90A3, 0xC4C7, 0x90A4, 0xDF94, 0x90A5, 0xDF95, 0x90A6, 0xB0EE, 0x90A7, 0xDF96, 0x90A8, 0xDF97, 0x90A9, 0xDF98, 0x90AA, 0xD0B0, + 0x90AB, 0xDF99, 0x90AC, 0xDAF9, 0x90AD, 0xDF9A, 0x90AE, 0xD3CA, 0x90AF, 0xBAAA, 0x90B0, 0xDBA2, 0x90B1, 0xC7F1, 0x90B2, 0xDF9B, + 0x90B3, 0xDAFC, 0x90B4, 0xDAFB, 0x90B5, 0xC9DB, 0x90B6, 0xDAFD, 0x90B7, 0xDF9C, 0x90B8, 0xDBA1, 0x90B9, 0xD7DE, 0x90BA, 0xDAFE, + 0x90BB, 0xC1DA, 0x90BC, 0xDF9D, 0x90BD, 0xDF9E, 0x90BE, 0xDBA5, 0x90BF, 0xDF9F, 0x90C0, 0xDFA0, 0x90C1, 0xD3F4, 0x90C2, 0xE040, + 0x90C3, 0xE041, 0x90C4, 0xDBA7, 0x90C5, 0xDBA4, 0x90C6, 0xE042, 0x90C7, 0xDBA8, 0x90C8, 0xE043, 0x90C9, 0xE044, 0x90CA, 0xBDBC, + 0x90CB, 0xE045, 0x90CC, 0xE046, 0x90CD, 0xE047, 0x90CE, 0xC0C9, 0x90CF, 0xDBA3, 0x90D0, 0xDBA6, 0x90D1, 0xD6A3, 0x90D2, 0xE048, + 0x90D3, 0xDBA9, 0x90D4, 0xE049, 0x90D5, 0xE04A, 0x90D6, 0xE04B, 0x90D7, 0xDBAD, 0x90D8, 0xE04C, 0x90D9, 0xE04D, 0x90DA, 0xE04E, + 0x90DB, 0xDBAE, 0x90DC, 0xDBAC, 0x90DD, 0xBAC2, 0x90DE, 0xE04F, 0x90DF, 0xE050, 0x90E0, 0xE051, 0x90E1, 0xBFA4, 0x90E2, 0xDBAB, + 0x90E3, 0xE052, 0x90E4, 0xE053, 0x90E5, 0xE054, 0x90E6, 0xDBAA, 0x90E7, 0xD4C7, 0x90E8, 0xB2BF, 0x90E9, 0xE055, 0x90EA, 0xE056, + 0x90EB, 0xDBAF, 0x90EC, 0xE057, 0x90ED, 0xB9F9, 0x90EE, 0xE058, 0x90EF, 0xDBB0, 0x90F0, 0xE059, 0x90F1, 0xE05A, 0x90F2, 0xE05B, + 0x90F3, 0xE05C, 0x90F4, 0xB3BB, 0x90F5, 0xE05D, 0x90F6, 0xE05E, 0x90F7, 0xE05F, 0x90F8, 0xB5A6, 0x90F9, 0xE060, 0x90FA, 0xE061, + 0x90FB, 0xE062, 0x90FC, 0xE063, 0x90FD, 0xB6BC, 0x90FE, 0xDBB1, 0x90FF, 0xE064, 0x9100, 0xE065, 0x9101, 0xE066, 0x9102, 0xB6F5, + 0x9103, 0xE067, 0x9104, 0xDBB2, 0x9105, 0xE068, 0x9106, 0xE069, 0x9107, 0xE06A, 0x9108, 0xE06B, 0x9109, 0xE06C, 0x910A, 0xE06D, + 0x910B, 0xE06E, 0x910C, 0xE06F, 0x910D, 0xE070, 0x910E, 0xE071, 0x910F, 0xE072, 0x9110, 0xE073, 0x9111, 0xE074, 0x9112, 0xE075, + 0x9113, 0xE076, 0x9114, 0xE077, 0x9115, 0xE078, 0x9116, 0xE079, 0x9117, 0xE07A, 0x9118, 0xE07B, 0x9119, 0xB1C9, 0x911A, 0xE07C, + 0x911B, 0xE07D, 0x911C, 0xE07E, 0x911D, 0xE080, 0x911E, 0xDBB4, 0x911F, 0xE081, 0x9120, 0xE082, 0x9121, 0xE083, 0x9122, 0xDBB3, + 0x9123, 0xDBB5, 0x9124, 0xE084, 0x9125, 0xE085, 0x9126, 0xE086, 0x9127, 0xE087, 0x9128, 0xE088, 0x9129, 0xE089, 0x912A, 0xE08A, + 0x912B, 0xE08B, 0x912C, 0xE08C, 0x912D, 0xE08D, 0x912E, 0xE08E, 0x912F, 0xDBB7, 0x9130, 0xE08F, 0x9131, 0xDBB6, 0x9132, 0xE090, + 0x9133, 0xE091, 0x9134, 0xE092, 0x9135, 0xE093, 0x9136, 0xE094, 0x9137, 0xE095, 0x9138, 0xE096, 0x9139, 0xDBB8, 0x913A, 0xE097, + 0x913B, 0xE098, 0x913C, 0xE099, 0x913D, 0xE09A, 0x913E, 0xE09B, 0x913F, 0xE09C, 0x9140, 0xE09D, 0x9141, 0xE09E, 0x9142, 0xE09F, + 0x9143, 0xDBB9, 0x9144, 0xE0A0, 0x9145, 0xE140, 0x9146, 0xDBBA, 0x9147, 0xE141, 0x9148, 0xE142, 0x9149, 0xD3CF, 0x914A, 0xF4FA, + 0x914B, 0xC7F5, 0x914C, 0xD7C3, 0x914D, 0xC5E4, 0x914E, 0xF4FC, 0x914F, 0xF4FD, 0x9150, 0xF4FB, 0x9151, 0xE143, 0x9152, 0xBEC6, + 0x9153, 0xE144, 0x9154, 0xE145, 0x9155, 0xE146, 0x9156, 0xE147, 0x9157, 0xD0EF, 0x9158, 0xE148, 0x9159, 0xE149, 0x915A, 0xB7D3, + 0x915B, 0xE14A, 0x915C, 0xE14B, 0x915D, 0xD4CD, 0x915E, 0xCCAA, 0x915F, 0xE14C, 0x9160, 0xE14D, 0x9161, 0xF5A2, 0x9162, 0xF5A1, + 0x9163, 0xBAA8, 0x9164, 0xF4FE, 0x9165, 0xCBD6, 0x9166, 0xE14E, 0x9167, 0xE14F, 0x9168, 0xE150, 0x9169, 0xF5A4, 0x916A, 0xC0D2, + 0x916B, 0xE151, 0x916C, 0xB3EA, 0x916D, 0xE152, 0x916E, 0xCDAA, 0x916F, 0xF5A5, 0x9170, 0xF5A3, 0x9171, 0xBDB4, 0x9172, 0xF5A8, + 0x9173, 0xE153, 0x9174, 0xF5A9, 0x9175, 0xBDCD, 0x9176, 0xC3B8, 0x9177, 0xBFE1, 0x9178, 0xCBE1, 0x9179, 0xF5AA, 0x917A, 0xE154, + 0x917B, 0xE155, 0x917C, 0xE156, 0x917D, 0xF5A6, 0x917E, 0xF5A7, 0x917F, 0xC4F0, 0x9180, 0xE157, 0x9181, 0xE158, 0x9182, 0xE159, + 0x9183, 0xE15A, 0x9184, 0xE15B, 0x9185, 0xF5AC, 0x9186, 0xE15C, 0x9187, 0xB4BC, 0x9188, 0xE15D, 0x9189, 0xD7ED, 0x918A, 0xE15E, + 0x918B, 0xB4D7, 0x918C, 0xF5AB, 0x918D, 0xF5AE, 0x918E, 0xE15F, 0x918F, 0xE160, 0x9190, 0xF5AD, 0x9191, 0xF5AF, 0x9192, 0xD0D1, + 0x9193, 0xE161, 0x9194, 0xE162, 0x9195, 0xE163, 0x9196, 0xE164, 0x9197, 0xE165, 0x9198, 0xE166, 0x9199, 0xE167, 0x919A, 0xC3D1, + 0x919B, 0xC8A9, 0x919C, 0xE168, 0x919D, 0xE169, 0x919E, 0xE16A, 0x919F, 0xE16B, 0x91A0, 0xE16C, 0x91A1, 0xE16D, 0x91A2, 0xF5B0, + 0x91A3, 0xF5B1, 0x91A4, 0xE16E, 0x91A5, 0xE16F, 0x91A6, 0xE170, 0x91A7, 0xE171, 0x91A8, 0xE172, 0x91A9, 0xE173, 0x91AA, 0xF5B2, + 0x91AB, 0xE174, 0x91AC, 0xE175, 0x91AD, 0xF5B3, 0x91AE, 0xF5B4, 0x91AF, 0xF5B5, 0x91B0, 0xE176, 0x91B1, 0xE177, 0x91B2, 0xE178, + 0x91B3, 0xE179, 0x91B4, 0xF5B7, 0x91B5, 0xF5B6, 0x91B6, 0xE17A, 0x91B7, 0xE17B, 0x91B8, 0xE17C, 0x91B9, 0xE17D, 0x91BA, 0xF5B8, + 0x91BB, 0xE17E, 0x91BC, 0xE180, 0x91BD, 0xE181, 0x91BE, 0xE182, 0x91BF, 0xE183, 0x91C0, 0xE184, 0x91C1, 0xE185, 0x91C2, 0xE186, + 0x91C3, 0xE187, 0x91C4, 0xE188, 0x91C5, 0xE189, 0x91C6, 0xE18A, 0x91C7, 0xB2C9, 0x91C8, 0xE18B, 0x91C9, 0xD3D4, 0x91CA, 0xCACD, + 0x91CB, 0xE18C, 0x91CC, 0xC0EF, 0x91CD, 0xD6D8, 0x91CE, 0xD2B0, 0x91CF, 0xC1BF, 0x91D0, 0xE18D, 0x91D1, 0xBDF0, 0x91D2, 0xE18E, + 0x91D3, 0xE18F, 0x91D4, 0xE190, 0x91D5, 0xE191, 0x91D6, 0xE192, 0x91D7, 0xE193, 0x91D8, 0xE194, 0x91D9, 0xE195, 0x91DA, 0xE196, + 0x91DB, 0xE197, 0x91DC, 0xB8AA, 0x91DD, 0xE198, 0x91DE, 0xE199, 0x91DF, 0xE19A, 0x91E0, 0xE19B, 0x91E1, 0xE19C, 0x91E2, 0xE19D, + 0x91E3, 0xE19E, 0x91E4, 0xE19F, 0x91E5, 0xE1A0, 0x91E6, 0xE240, 0x91E7, 0xE241, 0x91E8, 0xE242, 0x91E9, 0xE243, 0x91EA, 0xE244, + 0x91EB, 0xE245, 0x91EC, 0xE246, 0x91ED, 0xE247, 0x91EE, 0xE248, 0x91EF, 0xE249, 0x91F0, 0xE24A, 0x91F1, 0xE24B, 0x91F2, 0xE24C, + 0x91F3, 0xE24D, 0x91F4, 0xE24E, 0x91F5, 0xE24F, 0x91F6, 0xE250, 0x91F7, 0xE251, 0x91F8, 0xE252, 0x91F9, 0xE253, 0x91FA, 0xE254, + 0x91FB, 0xE255, 0x91FC, 0xE256, 0x91FD, 0xE257, 0x91FE, 0xE258, 0x91FF, 0xE259, 0x9200, 0xE25A, 0x9201, 0xE25B, 0x9202, 0xE25C, + 0x9203, 0xE25D, 0x9204, 0xE25E, 0x9205, 0xE25F, 0x9206, 0xE260, 0x9207, 0xE261, 0x9208, 0xE262, 0x9209, 0xE263, 0x920A, 0xE264, + 0x920B, 0xE265, 0x920C, 0xE266, 0x920D, 0xE267, 0x920E, 0xE268, 0x920F, 0xE269, 0x9210, 0xE26A, 0x9211, 0xE26B, 0x9212, 0xE26C, + 0x9213, 0xE26D, 0x9214, 0xE26E, 0x9215, 0xE26F, 0x9216, 0xE270, 0x9217, 0xE271, 0x9218, 0xE272, 0x9219, 0xE273, 0x921A, 0xE274, + 0x921B, 0xE275, 0x921C, 0xE276, 0x921D, 0xE277, 0x921E, 0xE278, 0x921F, 0xE279, 0x9220, 0xE27A, 0x9221, 0xE27B, 0x9222, 0xE27C, + 0x9223, 0xE27D, 0x9224, 0xE27E, 0x9225, 0xE280, 0x9226, 0xE281, 0x9227, 0xE282, 0x9228, 0xE283, 0x9229, 0xE284, 0x922A, 0xE285, + 0x922B, 0xE286, 0x922C, 0xE287, 0x922D, 0xE288, 0x922E, 0xE289, 0x922F, 0xE28A, 0x9230, 0xE28B, 0x9231, 0xE28C, 0x9232, 0xE28D, + 0x9233, 0xE28E, 0x9234, 0xE28F, 0x9235, 0xE290, 0x9236, 0xE291, 0x9237, 0xE292, 0x9238, 0xE293, 0x9239, 0xE294, 0x923A, 0xE295, + 0x923B, 0xE296, 0x923C, 0xE297, 0x923D, 0xE298, 0x923E, 0xE299, 0x923F, 0xE29A, 0x9240, 0xE29B, 0x9241, 0xE29C, 0x9242, 0xE29D, + 0x9243, 0xE29E, 0x9244, 0xE29F, 0x9245, 0xE2A0, 0x9246, 0xE340, 0x9247, 0xE341, 0x9248, 0xE342, 0x9249, 0xE343, 0x924A, 0xE344, + 0x924B, 0xE345, 0x924C, 0xE346, 0x924D, 0xE347, 0x924E, 0xE348, 0x924F, 0xE349, 0x9250, 0xE34A, 0x9251, 0xE34B, 0x9252, 0xE34C, + 0x9253, 0xE34D, 0x9254, 0xE34E, 0x9255, 0xE34F, 0x9256, 0xE350, 0x9257, 0xE351, 0x9258, 0xE352, 0x9259, 0xE353, 0x925A, 0xE354, + 0x925B, 0xE355, 0x925C, 0xE356, 0x925D, 0xE357, 0x925E, 0xE358, 0x925F, 0xE359, 0x9260, 0xE35A, 0x9261, 0xE35B, 0x9262, 0xE35C, + 0x9263, 0xE35D, 0x9264, 0xE35E, 0x9265, 0xE35F, 0x9266, 0xE360, 0x9267, 0xE361, 0x9268, 0xE362, 0x9269, 0xE363, 0x926A, 0xE364, + 0x926B, 0xE365, 0x926C, 0xE366, 0x926D, 0xE367, 0x926E, 0xE368, 0x926F, 0xE369, 0x9270, 0xE36A, 0x9271, 0xE36B, 0x9272, 0xE36C, + 0x9273, 0xE36D, 0x9274, 0xBCF8, 0x9275, 0xE36E, 0x9276, 0xE36F, 0x9277, 0xE370, 0x9278, 0xE371, 0x9279, 0xE372, 0x927A, 0xE373, + 0x927B, 0xE374, 0x927C, 0xE375, 0x927D, 0xE376, 0x927E, 0xE377, 0x927F, 0xE378, 0x9280, 0xE379, 0x9281, 0xE37A, 0x9282, 0xE37B, + 0x9283, 0xE37C, 0x9284, 0xE37D, 0x9285, 0xE37E, 0x9286, 0xE380, 0x9287, 0xE381, 0x9288, 0xE382, 0x9289, 0xE383, 0x928A, 0xE384, + 0x928B, 0xE385, 0x928C, 0xE386, 0x928D, 0xE387, 0x928E, 0xF6C6, 0x928F, 0xE388, 0x9290, 0xE389, 0x9291, 0xE38A, 0x9292, 0xE38B, + 0x9293, 0xE38C, 0x9294, 0xE38D, 0x9295, 0xE38E, 0x9296, 0xE38F, 0x9297, 0xE390, 0x9298, 0xE391, 0x9299, 0xE392, 0x929A, 0xE393, + 0x929B, 0xE394, 0x929C, 0xE395, 0x929D, 0xE396, 0x929E, 0xE397, 0x929F, 0xE398, 0x92A0, 0xE399, 0x92A1, 0xE39A, 0x92A2, 0xE39B, + 0x92A3, 0xE39C, 0x92A4, 0xE39D, 0x92A5, 0xE39E, 0x92A6, 0xE39F, 0x92A7, 0xE3A0, 0x92A8, 0xE440, 0x92A9, 0xE441, 0x92AA, 0xE442, + 0x92AB, 0xE443, 0x92AC, 0xE444, 0x92AD, 0xE445, 0x92AE, 0xF6C7, 0x92AF, 0xE446, 0x92B0, 0xE447, 0x92B1, 0xE448, 0x92B2, 0xE449, + 0x92B3, 0xE44A, 0x92B4, 0xE44B, 0x92B5, 0xE44C, 0x92B6, 0xE44D, 0x92B7, 0xE44E, 0x92B8, 0xE44F, 0x92B9, 0xE450, 0x92BA, 0xE451, + 0x92BB, 0xE452, 0x92BC, 0xE453, 0x92BD, 0xE454, 0x92BE, 0xE455, 0x92BF, 0xE456, 0x92C0, 0xE457, 0x92C1, 0xE458, 0x92C2, 0xE459, + 0x92C3, 0xE45A, 0x92C4, 0xE45B, 0x92C5, 0xE45C, 0x92C6, 0xE45D, 0x92C7, 0xE45E, 0x92C8, 0xF6C8, 0x92C9, 0xE45F, 0x92CA, 0xE460, + 0x92CB, 0xE461, 0x92CC, 0xE462, 0x92CD, 0xE463, 0x92CE, 0xE464, 0x92CF, 0xE465, 0x92D0, 0xE466, 0x92D1, 0xE467, 0x92D2, 0xE468, + 0x92D3, 0xE469, 0x92D4, 0xE46A, 0x92D5, 0xE46B, 0x92D6, 0xE46C, 0x92D7, 0xE46D, 0x92D8, 0xE46E, 0x92D9, 0xE46F, 0x92DA, 0xE470, + 0x92DB, 0xE471, 0x92DC, 0xE472, 0x92DD, 0xE473, 0x92DE, 0xE474, 0x92DF, 0xE475, 0x92E0, 0xE476, 0x92E1, 0xE477, 0x92E2, 0xE478, + 0x92E3, 0xE479, 0x92E4, 0xE47A, 0x92E5, 0xE47B, 0x92E6, 0xE47C, 0x92E7, 0xE47D, 0x92E8, 0xE47E, 0x92E9, 0xE480, 0x92EA, 0xE481, + 0x92EB, 0xE482, 0x92EC, 0xE483, 0x92ED, 0xE484, 0x92EE, 0xE485, 0x92EF, 0xE486, 0x92F0, 0xE487, 0x92F1, 0xE488, 0x92F2, 0xE489, + 0x92F3, 0xE48A, 0x92F4, 0xE48B, 0x92F5, 0xE48C, 0x92F6, 0xE48D, 0x92F7, 0xE48E, 0x92F8, 0xE48F, 0x92F9, 0xE490, 0x92FA, 0xE491, + 0x92FB, 0xE492, 0x92FC, 0xE493, 0x92FD, 0xE494, 0x92FE, 0xE495, 0x92FF, 0xE496, 0x9300, 0xE497, 0x9301, 0xE498, 0x9302, 0xE499, + 0x9303, 0xE49A, 0x9304, 0xE49B, 0x9305, 0xE49C, 0x9306, 0xE49D, 0x9307, 0xE49E, 0x9308, 0xE49F, 0x9309, 0xE4A0, 0x930A, 0xE540, + 0x930B, 0xE541, 0x930C, 0xE542, 0x930D, 0xE543, 0x930E, 0xE544, 0x930F, 0xE545, 0x9310, 0xE546, 0x9311, 0xE547, 0x9312, 0xE548, + 0x9313, 0xE549, 0x9314, 0xE54A, 0x9315, 0xE54B, 0x9316, 0xE54C, 0x9317, 0xE54D, 0x9318, 0xE54E, 0x9319, 0xE54F, 0x931A, 0xE550, + 0x931B, 0xE551, 0x931C, 0xE552, 0x931D, 0xE553, 0x931E, 0xE554, 0x931F, 0xE555, 0x9320, 0xE556, 0x9321, 0xE557, 0x9322, 0xE558, + 0x9323, 0xE559, 0x9324, 0xE55A, 0x9325, 0xE55B, 0x9326, 0xE55C, 0x9327, 0xE55D, 0x9328, 0xE55E, 0x9329, 0xE55F, 0x932A, 0xE560, + 0x932B, 0xE561, 0x932C, 0xE562, 0x932D, 0xE563, 0x932E, 0xE564, 0x932F, 0xE565, 0x9330, 0xE566, 0x9331, 0xE567, 0x9332, 0xE568, + 0x9333, 0xE569, 0x9334, 0xE56A, 0x9335, 0xE56B, 0x9336, 0xE56C, 0x9337, 0xE56D, 0x9338, 0xE56E, 0x9339, 0xE56F, 0x933A, 0xE570, + 0x933B, 0xE571, 0x933C, 0xE572, 0x933D, 0xE573, 0x933E, 0xF6C9, 0x933F, 0xE574, 0x9340, 0xE575, 0x9341, 0xE576, 0x9342, 0xE577, + 0x9343, 0xE578, 0x9344, 0xE579, 0x9345, 0xE57A, 0x9346, 0xE57B, 0x9347, 0xE57C, 0x9348, 0xE57D, 0x9349, 0xE57E, 0x934A, 0xE580, + 0x934B, 0xE581, 0x934C, 0xE582, 0x934D, 0xE583, 0x934E, 0xE584, 0x934F, 0xE585, 0x9350, 0xE586, 0x9351, 0xE587, 0x9352, 0xE588, + 0x9353, 0xE589, 0x9354, 0xE58A, 0x9355, 0xE58B, 0x9356, 0xE58C, 0x9357, 0xE58D, 0x9358, 0xE58E, 0x9359, 0xE58F, 0x935A, 0xE590, + 0x935B, 0xE591, 0x935C, 0xE592, 0x935D, 0xE593, 0x935E, 0xE594, 0x935F, 0xE595, 0x9360, 0xE596, 0x9361, 0xE597, 0x9362, 0xE598, + 0x9363, 0xE599, 0x9364, 0xE59A, 0x9365, 0xE59B, 0x9366, 0xE59C, 0x9367, 0xE59D, 0x9368, 0xE59E, 0x9369, 0xE59F, 0x936A, 0xF6CA, + 0x936B, 0xE5A0, 0x936C, 0xE640, 0x936D, 0xE641, 0x936E, 0xE642, 0x936F, 0xE643, 0x9370, 0xE644, 0x9371, 0xE645, 0x9372, 0xE646, + 0x9373, 0xE647, 0x9374, 0xE648, 0x9375, 0xE649, 0x9376, 0xE64A, 0x9377, 0xE64B, 0x9378, 0xE64C, 0x9379, 0xE64D, 0x937A, 0xE64E, + 0x937B, 0xE64F, 0x937C, 0xE650, 0x937D, 0xE651, 0x937E, 0xE652, 0x937F, 0xE653, 0x9380, 0xE654, 0x9381, 0xE655, 0x9382, 0xE656, + 0x9383, 0xE657, 0x9384, 0xE658, 0x9385, 0xE659, 0x9386, 0xE65A, 0x9387, 0xE65B, 0x9388, 0xE65C, 0x9389, 0xE65D, 0x938A, 0xE65E, + 0x938B, 0xE65F, 0x938C, 0xE660, 0x938D, 0xE661, 0x938E, 0xE662, 0x938F, 0xF6CC, 0x9390, 0xE663, 0x9391, 0xE664, 0x9392, 0xE665, + 0x9393, 0xE666, 0x9394, 0xE667, 0x9395, 0xE668, 0x9396, 0xE669, 0x9397, 0xE66A, 0x9398, 0xE66B, 0x9399, 0xE66C, 0x939A, 0xE66D, + 0x939B, 0xE66E, 0x939C, 0xE66F, 0x939D, 0xE670, 0x939E, 0xE671, 0x939F, 0xE672, 0x93A0, 0xE673, 0x93A1, 0xE674, 0x93A2, 0xE675, + 0x93A3, 0xE676, 0x93A4, 0xE677, 0x93A5, 0xE678, 0x93A6, 0xE679, 0x93A7, 0xE67A, 0x93A8, 0xE67B, 0x93A9, 0xE67C, 0x93AA, 0xE67D, + 0x93AB, 0xE67E, 0x93AC, 0xE680, 0x93AD, 0xE681, 0x93AE, 0xE682, 0x93AF, 0xE683, 0x93B0, 0xE684, 0x93B1, 0xE685, 0x93B2, 0xE686, + 0x93B3, 0xE687, 0x93B4, 0xE688, 0x93B5, 0xE689, 0x93B6, 0xE68A, 0x93B7, 0xE68B, 0x93B8, 0xE68C, 0x93B9, 0xE68D, 0x93BA, 0xE68E, + 0x93BB, 0xE68F, 0x93BC, 0xE690, 0x93BD, 0xE691, 0x93BE, 0xE692, 0x93BF, 0xE693, 0x93C0, 0xE694, 0x93C1, 0xE695, 0x93C2, 0xE696, + 0x93C3, 0xE697, 0x93C4, 0xE698, 0x93C5, 0xE699, 0x93C6, 0xE69A, 0x93C7, 0xE69B, 0x93C8, 0xE69C, 0x93C9, 0xE69D, 0x93CA, 0xF6CB, + 0x93CB, 0xE69E, 0x93CC, 0xE69F, 0x93CD, 0xE6A0, 0x93CE, 0xE740, 0x93CF, 0xE741, 0x93D0, 0xE742, 0x93D1, 0xE743, 0x93D2, 0xE744, + 0x93D3, 0xE745, 0x93D4, 0xE746, 0x93D5, 0xE747, 0x93D6, 0xF7E9, 0x93D7, 0xE748, 0x93D8, 0xE749, 0x93D9, 0xE74A, 0x93DA, 0xE74B, + 0x93DB, 0xE74C, 0x93DC, 0xE74D, 0x93DD, 0xE74E, 0x93DE, 0xE74F, 0x93DF, 0xE750, 0x93E0, 0xE751, 0x93E1, 0xE752, 0x93E2, 0xE753, + 0x93E3, 0xE754, 0x93E4, 0xE755, 0x93E5, 0xE756, 0x93E6, 0xE757, 0x93E7, 0xE758, 0x93E8, 0xE759, 0x93E9, 0xE75A, 0x93EA, 0xE75B, + 0x93EB, 0xE75C, 0x93EC, 0xE75D, 0x93ED, 0xE75E, 0x93EE, 0xE75F, 0x93EF, 0xE760, 0x93F0, 0xE761, 0x93F1, 0xE762, 0x93F2, 0xE763, + 0x93F3, 0xE764, 0x93F4, 0xE765, 0x93F5, 0xE766, 0x93F6, 0xE767, 0x93F7, 0xE768, 0x93F8, 0xE769, 0x93F9, 0xE76A, 0x93FA, 0xE76B, + 0x93FB, 0xE76C, 0x93FC, 0xE76D, 0x93FD, 0xE76E, 0x93FE, 0xE76F, 0x93FF, 0xE770, 0x9400, 0xE771, 0x9401, 0xE772, 0x9402, 0xE773, + 0x9403, 0xE774, 0x9404, 0xE775, 0x9405, 0xE776, 0x9406, 0xE777, 0x9407, 0xE778, 0x9408, 0xE779, 0x9409, 0xE77A, 0x940A, 0xE77B, + 0x940B, 0xE77C, 0x940C, 0xE77D, 0x940D, 0xE77E, 0x940E, 0xE780, 0x940F, 0xE781, 0x9410, 0xE782, 0x9411, 0xE783, 0x9412, 0xE784, + 0x9413, 0xE785, 0x9414, 0xE786, 0x9415, 0xE787, 0x9416, 0xE788, 0x9417, 0xE789, 0x9418, 0xE78A, 0x9419, 0xE78B, 0x941A, 0xE78C, + 0x941B, 0xE78D, 0x941C, 0xE78E, 0x941D, 0xE78F, 0x941E, 0xE790, 0x941F, 0xE791, 0x9420, 0xE792, 0x9421, 0xE793, 0x9422, 0xE794, + 0x9423, 0xE795, 0x9424, 0xE796, 0x9425, 0xE797, 0x9426, 0xE798, 0x9427, 0xE799, 0x9428, 0xE79A, 0x9429, 0xE79B, 0x942A, 0xE79C, + 0x942B, 0xE79D, 0x942C, 0xE79E, 0x942D, 0xE79F, 0x942E, 0xE7A0, 0x942F, 0xE840, 0x9430, 0xE841, 0x9431, 0xE842, 0x9432, 0xE843, + 0x9433, 0xE844, 0x9434, 0xE845, 0x9435, 0xE846, 0x9436, 0xE847, 0x9437, 0xE848, 0x9438, 0xE849, 0x9439, 0xE84A, 0x943A, 0xE84B, + 0x943B, 0xE84C, 0x943C, 0xE84D, 0x943D, 0xE84E, 0x943E, 0xF6CD, 0x943F, 0xE84F, 0x9440, 0xE850, 0x9441, 0xE851, 0x9442, 0xE852, + 0x9443, 0xE853, 0x9444, 0xE854, 0x9445, 0xE855, 0x9446, 0xE856, 0x9447, 0xE857, 0x9448, 0xE858, 0x9449, 0xE859, 0x944A, 0xE85A, + 0x944B, 0xE85B, 0x944C, 0xE85C, 0x944D, 0xE85D, 0x944E, 0xE85E, 0x944F, 0xE85F, 0x9450, 0xE860, 0x9451, 0xE861, 0x9452, 0xE862, + 0x9453, 0xE863, 0x9454, 0xE864, 0x9455, 0xE865, 0x9456, 0xE866, 0x9457, 0xE867, 0x9458, 0xE868, 0x9459, 0xE869, 0x945A, 0xE86A, + 0x945B, 0xE86B, 0x945C, 0xE86C, 0x945D, 0xE86D, 0x945E, 0xE86E, 0x945F, 0xE86F, 0x9460, 0xE870, 0x9461, 0xE871, 0x9462, 0xE872, + 0x9463, 0xE873, 0x9464, 0xE874, 0x9465, 0xE875, 0x9466, 0xE876, 0x9467, 0xE877, 0x9468, 0xE878, 0x9469, 0xE879, 0x946A, 0xE87A, + 0x946B, 0xF6CE, 0x946C, 0xE87B, 0x946D, 0xE87C, 0x946E, 0xE87D, 0x946F, 0xE87E, 0x9470, 0xE880, 0x9471, 0xE881, 0x9472, 0xE882, + 0x9473, 0xE883, 0x9474, 0xE884, 0x9475, 0xE885, 0x9476, 0xE886, 0x9477, 0xE887, 0x9478, 0xE888, 0x9479, 0xE889, 0x947A, 0xE88A, + 0x947B, 0xE88B, 0x947C, 0xE88C, 0x947D, 0xE88D, 0x947E, 0xE88E, 0x947F, 0xE88F, 0x9480, 0xE890, 0x9481, 0xE891, 0x9482, 0xE892, + 0x9483, 0xE893, 0x9484, 0xE894, 0x9485, 0xEEC4, 0x9486, 0xEEC5, 0x9487, 0xEEC6, 0x9488, 0xD5EB, 0x9489, 0xB6A4, 0x948A, 0xEEC8, + 0x948B, 0xEEC7, 0x948C, 0xEEC9, 0x948D, 0xEECA, 0x948E, 0xC7A5, 0x948F, 0xEECB, 0x9490, 0xEECC, 0x9491, 0xE895, 0x9492, 0xB7B0, + 0x9493, 0xB5F6, 0x9494, 0xEECD, 0x9495, 0xEECF, 0x9496, 0xE896, 0x9497, 0xEECE, 0x9498, 0xE897, 0x9499, 0xB8C6, 0x949A, 0xEED0, + 0x949B, 0xEED1, 0x949C, 0xEED2, 0x949D, 0xB6DB, 0x949E, 0xB3AE, 0x949F, 0xD6D3, 0x94A0, 0xC4C6, 0x94A1, 0xB1B5, 0x94A2, 0xB8D6, + 0x94A3, 0xEED3, 0x94A4, 0xEED4, 0x94A5, 0xD4BF, 0x94A6, 0xC7D5, 0x94A7, 0xBEFB, 0x94A8, 0xCED9, 0x94A9, 0xB9B3, 0x94AA, 0xEED6, + 0x94AB, 0xEED5, 0x94AC, 0xEED8, 0x94AD, 0xEED7, 0x94AE, 0xC5A5, 0x94AF, 0xEED9, 0x94B0, 0xEEDA, 0x94B1, 0xC7AE, 0x94B2, 0xEEDB, + 0x94B3, 0xC7AF, 0x94B4, 0xEEDC, 0x94B5, 0xB2A7, 0x94B6, 0xEEDD, 0x94B7, 0xEEDE, 0x94B8, 0xEEDF, 0x94B9, 0xEEE0, 0x94BA, 0xEEE1, + 0x94BB, 0xD7EA, 0x94BC, 0xEEE2, 0x94BD, 0xEEE3, 0x94BE, 0xBCD8, 0x94BF, 0xEEE4, 0x94C0, 0xD3CB, 0x94C1, 0xCCFA, 0x94C2, 0xB2AC, + 0x94C3, 0xC1E5, 0x94C4, 0xEEE5, 0x94C5, 0xC7A6, 0x94C6, 0xC3AD, 0x94C7, 0xE898, 0x94C8, 0xEEE6, 0x94C9, 0xEEE7, 0x94CA, 0xEEE8, + 0x94CB, 0xEEE9, 0x94CC, 0xEEEA, 0x94CD, 0xEEEB, 0x94CE, 0xEEEC, 0x94CF, 0xE899, 0x94D0, 0xEEED, 0x94D1, 0xEEEE, 0x94D2, 0xEEEF, + 0x94D3, 0xE89A, 0x94D4, 0xE89B, 0x94D5, 0xEEF0, 0x94D6, 0xEEF1, 0x94D7, 0xEEF2, 0x94D8, 0xEEF4, 0x94D9, 0xEEF3, 0x94DA, 0xE89C, + 0x94DB, 0xEEF5, 0x94DC, 0xCDAD, 0x94DD, 0xC2C1, 0x94DE, 0xEEF6, 0x94DF, 0xEEF7, 0x94E0, 0xEEF8, 0x94E1, 0xD5A1, 0x94E2, 0xEEF9, + 0x94E3, 0xCFB3, 0x94E4, 0xEEFA, 0x94E5, 0xEEFB, 0x94E6, 0xE89D, 0x94E7, 0xEEFC, 0x94E8, 0xEEFD, 0x94E9, 0xEFA1, 0x94EA, 0xEEFE, + 0x94EB, 0xEFA2, 0x94EC, 0xB8F5, 0x94ED, 0xC3FA, 0x94EE, 0xEFA3, 0x94EF, 0xEFA4, 0x94F0, 0xBDC2, 0x94F1, 0xD2BF, 0x94F2, 0xB2F9, + 0x94F3, 0xEFA5, 0x94F4, 0xEFA6, 0x94F5, 0xEFA7, 0x94F6, 0xD2F8, 0x94F7, 0xEFA8, 0x94F8, 0xD6FD, 0x94F9, 0xEFA9, 0x94FA, 0xC6CC, + 0x94FB, 0xE89E, 0x94FC, 0xEFAA, 0x94FD, 0xEFAB, 0x94FE, 0xC1B4, 0x94FF, 0xEFAC, 0x9500, 0xCFFA, 0x9501, 0xCBF8, 0x9502, 0xEFAE, + 0x9503, 0xEFAD, 0x9504, 0xB3FA, 0x9505, 0xB9F8, 0x9506, 0xEFAF, 0x9507, 0xEFB0, 0x9508, 0xD0E2, 0x9509, 0xEFB1, 0x950A, 0xEFB2, + 0x950B, 0xB7E6, 0x950C, 0xD0BF, 0x950D, 0xEFB3, 0x950E, 0xEFB4, 0x950F, 0xEFB5, 0x9510, 0xC8F1, 0x9511, 0xCCE0, 0x9512, 0xEFB6, + 0x9513, 0xEFB7, 0x9514, 0xEFB8, 0x9515, 0xEFB9, 0x9516, 0xEFBA, 0x9517, 0xD5E0, 0x9518, 0xEFBB, 0x9519, 0xB4ED, 0x951A, 0xC3AA, + 0x951B, 0xEFBC, 0x951C, 0xE89F, 0x951D, 0xEFBD, 0x951E, 0xEFBE, 0x951F, 0xEFBF, 0x9520, 0xE8A0, 0x9521, 0xCEFD, 0x9522, 0xEFC0, + 0x9523, 0xC2E0, 0x9524, 0xB4B8, 0x9525, 0xD7B6, 0x9526, 0xBDF5, 0x9527, 0xE940, 0x9528, 0xCFC7, 0x9529, 0xEFC3, 0x952A, 0xEFC1, + 0x952B, 0xEFC2, 0x952C, 0xEFC4, 0x952D, 0xB6A7, 0x952E, 0xBCFC, 0x952F, 0xBEE2, 0x9530, 0xC3CC, 0x9531, 0xEFC5, 0x9532, 0xEFC6, + 0x9533, 0xE941, 0x9534, 0xEFC7, 0x9535, 0xEFCF, 0x9536, 0xEFC8, 0x9537, 0xEFC9, 0x9538, 0xEFCA, 0x9539, 0xC7C2, 0x953A, 0xEFF1, + 0x953B, 0xB6CD, 0x953C, 0xEFCB, 0x953D, 0xE942, 0x953E, 0xEFCC, 0x953F, 0xEFCD, 0x9540, 0xB6C6, 0x9541, 0xC3BE, 0x9542, 0xEFCE, + 0x9543, 0xE943, 0x9544, 0xEFD0, 0x9545, 0xEFD1, 0x9546, 0xEFD2, 0x9547, 0xD5F2, 0x9548, 0xE944, 0x9549, 0xEFD3, 0x954A, 0xC4F7, + 0x954B, 0xE945, 0x954C, 0xEFD4, 0x954D, 0xC4F8, 0x954E, 0xEFD5, 0x954F, 0xEFD6, 0x9550, 0xB8E4, 0x9551, 0xB0F7, 0x9552, 0xEFD7, + 0x9553, 0xEFD8, 0x9554, 0xEFD9, 0x9555, 0xE946, 0x9556, 0xEFDA, 0x9557, 0xEFDB, 0x9558, 0xEFDC, 0x9559, 0xEFDD, 0x955A, 0xE947, + 0x955B, 0xEFDE, 0x955C, 0xBEB5, 0x955D, 0xEFE1, 0x955E, 0xEFDF, 0x955F, 0xEFE0, 0x9560, 0xE948, 0x9561, 0xEFE2, 0x9562, 0xEFE3, + 0x9563, 0xC1CD, 0x9564, 0xEFE4, 0x9565, 0xEFE5, 0x9566, 0xEFE6, 0x9567, 0xEFE7, 0x9568, 0xEFE8, 0x9569, 0xEFE9, 0x956A, 0xEFEA, + 0x956B, 0xEFEB, 0x956C, 0xEFEC, 0x956D, 0xC0D8, 0x956E, 0xE949, 0x956F, 0xEFED, 0x9570, 0xC1AD, 0x9571, 0xEFEE, 0x9572, 0xEFEF, + 0x9573, 0xEFF0, 0x9574, 0xE94A, 0x9575, 0xE94B, 0x9576, 0xCFE2, 0x9577, 0xE94C, 0x9578, 0xE94D, 0x9579, 0xE94E, 0x957A, 0xE94F, + 0x957B, 0xE950, 0x957C, 0xE951, 0x957D, 0xE952, 0x957E, 0xE953, 0x957F, 0xB3A4, 0x9580, 0xE954, 0x9581, 0xE955, 0x9582, 0xE956, + 0x9583, 0xE957, 0x9584, 0xE958, 0x9585, 0xE959, 0x9586, 0xE95A, 0x9587, 0xE95B, 0x9588, 0xE95C, 0x9589, 0xE95D, 0x958A, 0xE95E, + 0x958B, 0xE95F, 0x958C, 0xE960, 0x958D, 0xE961, 0x958E, 0xE962, 0x958F, 0xE963, 0x9590, 0xE964, 0x9591, 0xE965, 0x9592, 0xE966, + 0x9593, 0xE967, 0x9594, 0xE968, 0x9595, 0xE969, 0x9596, 0xE96A, 0x9597, 0xE96B, 0x9598, 0xE96C, 0x9599, 0xE96D, 0x959A, 0xE96E, + 0x959B, 0xE96F, 0x959C, 0xE970, 0x959D, 0xE971, 0x959E, 0xE972, 0x959F, 0xE973, 0x95A0, 0xE974, 0x95A1, 0xE975, 0x95A2, 0xE976, + 0x95A3, 0xE977, 0x95A4, 0xE978, 0x95A5, 0xE979, 0x95A6, 0xE97A, 0x95A7, 0xE97B, 0x95A8, 0xE97C, 0x95A9, 0xE97D, 0x95AA, 0xE97E, + 0x95AB, 0xE980, 0x95AC, 0xE981, 0x95AD, 0xE982, 0x95AE, 0xE983, 0x95AF, 0xE984, 0x95B0, 0xE985, 0x95B1, 0xE986, 0x95B2, 0xE987, + 0x95B3, 0xE988, 0x95B4, 0xE989, 0x95B5, 0xE98A, 0x95B6, 0xE98B, 0x95B7, 0xE98C, 0x95B8, 0xE98D, 0x95B9, 0xE98E, 0x95BA, 0xE98F, + 0x95BB, 0xE990, 0x95BC, 0xE991, 0x95BD, 0xE992, 0x95BE, 0xE993, 0x95BF, 0xE994, 0x95C0, 0xE995, 0x95C1, 0xE996, 0x95C2, 0xE997, + 0x95C3, 0xE998, 0x95C4, 0xE999, 0x95C5, 0xE99A, 0x95C6, 0xE99B, 0x95C7, 0xE99C, 0x95C8, 0xE99D, 0x95C9, 0xE99E, 0x95CA, 0xE99F, + 0x95CB, 0xE9A0, 0x95CC, 0xEA40, 0x95CD, 0xEA41, 0x95CE, 0xEA42, 0x95CF, 0xEA43, 0x95D0, 0xEA44, 0x95D1, 0xEA45, 0x95D2, 0xEA46, + 0x95D3, 0xEA47, 0x95D4, 0xEA48, 0x95D5, 0xEA49, 0x95D6, 0xEA4A, 0x95D7, 0xEA4B, 0x95D8, 0xEA4C, 0x95D9, 0xEA4D, 0x95DA, 0xEA4E, + 0x95DB, 0xEA4F, 0x95DC, 0xEA50, 0x95DD, 0xEA51, 0x95DE, 0xEA52, 0x95DF, 0xEA53, 0x95E0, 0xEA54, 0x95E1, 0xEA55, 0x95E2, 0xEA56, + 0x95E3, 0xEA57, 0x95E4, 0xEA58, 0x95E5, 0xEA59, 0x95E6, 0xEA5A, 0x95E7, 0xEA5B, 0x95E8, 0xC3C5, 0x95E9, 0xE3C5, 0x95EA, 0xC9C1, + 0x95EB, 0xE3C6, 0x95EC, 0xEA5C, 0x95ED, 0xB1D5, 0x95EE, 0xCECA, 0x95EF, 0xB4B3, 0x95F0, 0xC8F2, 0x95F1, 0xE3C7, 0x95F2, 0xCFD0, + 0x95F3, 0xE3C8, 0x95F4, 0xBCE4, 0x95F5, 0xE3C9, 0x95F6, 0xE3CA, 0x95F7, 0xC3C6, 0x95F8, 0xD5A2, 0x95F9, 0xC4D6, 0x95FA, 0xB9EB, + 0x95FB, 0xCEC5, 0x95FC, 0xE3CB, 0x95FD, 0xC3F6, 0x95FE, 0xE3CC, 0x95FF, 0xEA5D, 0x9600, 0xB7A7, 0x9601, 0xB8F3, 0x9602, 0xBAD2, + 0x9603, 0xE3CD, 0x9604, 0xE3CE, 0x9605, 0xD4C4, 0x9606, 0xE3CF, 0x9607, 0xEA5E, 0x9608, 0xE3D0, 0x9609, 0xD1CB, 0x960A, 0xE3D1, + 0x960B, 0xE3D2, 0x960C, 0xE3D3, 0x960D, 0xE3D4, 0x960E, 0xD1D6, 0x960F, 0xE3D5, 0x9610, 0xB2FB, 0x9611, 0xC0BB, 0x9612, 0xE3D6, + 0x9613, 0xEA5F, 0x9614, 0xC0AB, 0x9615, 0xE3D7, 0x9616, 0xE3D8, 0x9617, 0xE3D9, 0x9618, 0xEA60, 0x9619, 0xE3DA, 0x961A, 0xE3DB, + 0x961B, 0xEA61, 0x961C, 0xB8B7, 0x961D, 0xDAE2, 0x961E, 0xEA62, 0x961F, 0xB6D3, 0x9620, 0xEA63, 0x9621, 0xDAE4, 0x9622, 0xDAE3, + 0x9623, 0xEA64, 0x9624, 0xEA65, 0x9625, 0xEA66, 0x9626, 0xEA67, 0x9627, 0xEA68, 0x9628, 0xEA69, 0x9629, 0xEA6A, 0x962A, 0xDAE6, + 0x962B, 0xEA6B, 0x962C, 0xEA6C, 0x962D, 0xEA6D, 0x962E, 0xC8EE, 0x962F, 0xEA6E, 0x9630, 0xEA6F, 0x9631, 0xDAE5, 0x9632, 0xB7C0, + 0x9633, 0xD1F4, 0x9634, 0xD2F5, 0x9635, 0xD5F3, 0x9636, 0xBDD7, 0x9637, 0xEA70, 0x9638, 0xEA71, 0x9639, 0xEA72, 0x963A, 0xEA73, + 0x963B, 0xD7E8, 0x963C, 0xDAE8, 0x963D, 0xDAE7, 0x963E, 0xEA74, 0x963F, 0xB0A2, 0x9640, 0xCDD3, 0x9641, 0xEA75, 0x9642, 0xDAE9, + 0x9643, 0xEA76, 0x9644, 0xB8BD, 0x9645, 0xBCCA, 0x9646, 0xC2BD, 0x9647, 0xC2A4, 0x9648, 0xB3C2, 0x9649, 0xDAEA, 0x964A, 0xEA77, + 0x964B, 0xC2AA, 0x964C, 0xC4B0, 0x964D, 0xBDB5, 0x964E, 0xEA78, 0x964F, 0xEA79, 0x9650, 0xCFDE, 0x9651, 0xEA7A, 0x9652, 0xEA7B, + 0x9653, 0xEA7C, 0x9654, 0xDAEB, 0x9655, 0xC9C2, 0x9656, 0xEA7D, 0x9657, 0xEA7E, 0x9658, 0xEA80, 0x9659, 0xEA81, 0x965A, 0xEA82, + 0x965B, 0xB1DD, 0x965C, 0xEA83, 0x965D, 0xEA84, 0x965E, 0xEA85, 0x965F, 0xDAEC, 0x9660, 0xEA86, 0x9661, 0xB6B8, 0x9662, 0xD4BA, + 0x9663, 0xEA87, 0x9664, 0xB3FD, 0x9665, 0xEA88, 0x9666, 0xEA89, 0x9667, 0xDAED, 0x9668, 0xD4C9, 0x9669, 0xCFD5, 0x966A, 0xC5E3, + 0x966B, 0xEA8A, 0x966C, 0xDAEE, 0x966D, 0xEA8B, 0x966E, 0xEA8C, 0x966F, 0xEA8D, 0x9670, 0xEA8E, 0x9671, 0xEA8F, 0x9672, 0xDAEF, + 0x9673, 0xEA90, 0x9674, 0xDAF0, 0x9675, 0xC1EA, 0x9676, 0xCCD5, 0x9677, 0xCFDD, 0x9678, 0xEA91, 0x9679, 0xEA92, 0x967A, 0xEA93, + 0x967B, 0xEA94, 0x967C, 0xEA95, 0x967D, 0xEA96, 0x967E, 0xEA97, 0x967F, 0xEA98, 0x9680, 0xEA99, 0x9681, 0xEA9A, 0x9682, 0xEA9B, + 0x9683, 0xEA9C, 0x9684, 0xEA9D, 0x9685, 0xD3E7, 0x9686, 0xC2A1, 0x9687, 0xEA9E, 0x9688, 0xDAF1, 0x9689, 0xEA9F, 0x968A, 0xEAA0, + 0x968B, 0xCBE5, 0x968C, 0xEB40, 0x968D, 0xDAF2, 0x968E, 0xEB41, 0x968F, 0xCBE6, 0x9690, 0xD2FE, 0x9691, 0xEB42, 0x9692, 0xEB43, + 0x9693, 0xEB44, 0x9694, 0xB8F4, 0x9695, 0xEB45, 0x9696, 0xEB46, 0x9697, 0xDAF3, 0x9698, 0xB0AF, 0x9699, 0xCFB6, 0x969A, 0xEB47, + 0x969B, 0xEB48, 0x969C, 0xD5CF, 0x969D, 0xEB49, 0x969E, 0xEB4A, 0x969F, 0xEB4B, 0x96A0, 0xEB4C, 0x96A1, 0xEB4D, 0x96A2, 0xEB4E, + 0x96A3, 0xEB4F, 0x96A4, 0xEB50, 0x96A5, 0xEB51, 0x96A6, 0xEB52, 0x96A7, 0xCBED, 0x96A8, 0xEB53, 0x96A9, 0xEB54, 0x96AA, 0xEB55, + 0x96AB, 0xEB56, 0x96AC, 0xEB57, 0x96AD, 0xEB58, 0x96AE, 0xEB59, 0x96AF, 0xEB5A, 0x96B0, 0xDAF4, 0x96B1, 0xEB5B, 0x96B2, 0xEB5C, + 0x96B3, 0xE3C4, 0x96B4, 0xEB5D, 0x96B5, 0xEB5E, 0x96B6, 0xC1A5, 0x96B7, 0xEB5F, 0x96B8, 0xEB60, 0x96B9, 0xF6BF, 0x96BA, 0xEB61, + 0x96BB, 0xEB62, 0x96BC, 0xF6C0, 0x96BD, 0xF6C1, 0x96BE, 0xC4D1, 0x96BF, 0xEB63, 0x96C0, 0xC8B8, 0x96C1, 0xD1E3, 0x96C2, 0xEB64, + 0x96C3, 0xEB65, 0x96C4, 0xD0DB, 0x96C5, 0xD1C5, 0x96C6, 0xBCAF, 0x96C7, 0xB9CD, 0x96C8, 0xEB66, 0x96C9, 0xEFF4, 0x96CA, 0xEB67, + 0x96CB, 0xEB68, 0x96CC, 0xB4C6, 0x96CD, 0xD3BA, 0x96CE, 0xF6C2, 0x96CF, 0xB3FB, 0x96D0, 0xEB69, 0x96D1, 0xEB6A, 0x96D2, 0xF6C3, + 0x96D3, 0xEB6B, 0x96D4, 0xEB6C, 0x96D5, 0xB5F1, 0x96D6, 0xEB6D, 0x96D7, 0xEB6E, 0x96D8, 0xEB6F, 0x96D9, 0xEB70, 0x96DA, 0xEB71, + 0x96DB, 0xEB72, 0x96DC, 0xEB73, 0x96DD, 0xEB74, 0x96DE, 0xEB75, 0x96DF, 0xEB76, 0x96E0, 0xF6C5, 0x96E1, 0xEB77, 0x96E2, 0xEB78, + 0x96E3, 0xEB79, 0x96E4, 0xEB7A, 0x96E5, 0xEB7B, 0x96E6, 0xEB7C, 0x96E7, 0xEB7D, 0x96E8, 0xD3EA, 0x96E9, 0xF6A7, 0x96EA, 0xD1A9, + 0x96EB, 0xEB7E, 0x96EC, 0xEB80, 0x96ED, 0xEB81, 0x96EE, 0xEB82, 0x96EF, 0xF6A9, 0x96F0, 0xEB83, 0x96F1, 0xEB84, 0x96F2, 0xEB85, + 0x96F3, 0xF6A8, 0x96F4, 0xEB86, 0x96F5, 0xEB87, 0x96F6, 0xC1E3, 0x96F7, 0xC0D7, 0x96F8, 0xEB88, 0x96F9, 0xB1A2, 0x96FA, 0xEB89, + 0x96FB, 0xEB8A, 0x96FC, 0xEB8B, 0x96FD, 0xEB8C, 0x96FE, 0xCEED, 0x96FF, 0xEB8D, 0x9700, 0xD0E8, 0x9701, 0xF6AB, 0x9702, 0xEB8E, + 0x9703, 0xEB8F, 0x9704, 0xCFF6, 0x9705, 0xEB90, 0x9706, 0xF6AA, 0x9707, 0xD5F0, 0x9708, 0xF6AC, 0x9709, 0xC3B9, 0x970A, 0xEB91, + 0x970B, 0xEB92, 0x970C, 0xEB93, 0x970D, 0xBBF4, 0x970E, 0xF6AE, 0x970F, 0xF6AD, 0x9710, 0xEB94, 0x9711, 0xEB95, 0x9712, 0xEB96, + 0x9713, 0xC4DE, 0x9714, 0xEB97, 0x9715, 0xEB98, 0x9716, 0xC1D8, 0x9717, 0xEB99, 0x9718, 0xEB9A, 0x9719, 0xEB9B, 0x971A, 0xEB9C, + 0x971B, 0xEB9D, 0x971C, 0xCBAA, 0x971D, 0xEB9E, 0x971E, 0xCFBC, 0x971F, 0xEB9F, 0x9720, 0xEBA0, 0x9721, 0xEC40, 0x9722, 0xEC41, + 0x9723, 0xEC42, 0x9724, 0xEC43, 0x9725, 0xEC44, 0x9726, 0xEC45, 0x9727, 0xEC46, 0x9728, 0xEC47, 0x9729, 0xEC48, 0x972A, 0xF6AF, + 0x972B, 0xEC49, 0x972C, 0xEC4A, 0x972D, 0xF6B0, 0x972E, 0xEC4B, 0x972F, 0xEC4C, 0x9730, 0xF6B1, 0x9731, 0xEC4D, 0x9732, 0xC2B6, + 0x9733, 0xEC4E, 0x9734, 0xEC4F, 0x9735, 0xEC50, 0x9736, 0xEC51, 0x9737, 0xEC52, 0x9738, 0xB0D4, 0x9739, 0xC5F9, 0x973A, 0xEC53, + 0x973B, 0xEC54, 0x973C, 0xEC55, 0x973D, 0xEC56, 0x973E, 0xF6B2, 0x973F, 0xEC57, 0x9740, 0xEC58, 0x9741, 0xEC59, 0x9742, 0xEC5A, + 0x9743, 0xEC5B, 0x9744, 0xEC5C, 0x9745, 0xEC5D, 0x9746, 0xEC5E, 0x9747, 0xEC5F, 0x9748, 0xEC60, 0x9749, 0xEC61, 0x974A, 0xEC62, + 0x974B, 0xEC63, 0x974C, 0xEC64, 0x974D, 0xEC65, 0x974E, 0xEC66, 0x974F, 0xEC67, 0x9750, 0xEC68, 0x9751, 0xEC69, 0x9752, 0xC7E0, + 0x9753, 0xF6A6, 0x9754, 0xEC6A, 0x9755, 0xEC6B, 0x9756, 0xBEB8, 0x9757, 0xEC6C, 0x9758, 0xEC6D, 0x9759, 0xBEB2, 0x975A, 0xEC6E, + 0x975B, 0xB5E5, 0x975C, 0xEC6F, 0x975D, 0xEC70, 0x975E, 0xB7C7, 0x975F, 0xEC71, 0x9760, 0xBFBF, 0x9761, 0xC3D2, 0x9762, 0xC3E6, + 0x9763, 0xEC72, 0x9764, 0xEC73, 0x9765, 0xD8CC, 0x9766, 0xEC74, 0x9767, 0xEC75, 0x9768, 0xEC76, 0x9769, 0xB8EF, 0x976A, 0xEC77, + 0x976B, 0xEC78, 0x976C, 0xEC79, 0x976D, 0xEC7A, 0x976E, 0xEC7B, 0x976F, 0xEC7C, 0x9770, 0xEC7D, 0x9771, 0xEC7E, 0x9772, 0xEC80, + 0x9773, 0xBDF9, 0x9774, 0xD1A5, 0x9775, 0xEC81, 0x9776, 0xB0D0, 0x9777, 0xEC82, 0x9778, 0xEC83, 0x9779, 0xEC84, 0x977A, 0xEC85, + 0x977B, 0xEC86, 0x977C, 0xF7B0, 0x977D, 0xEC87, 0x977E, 0xEC88, 0x977F, 0xEC89, 0x9780, 0xEC8A, 0x9781, 0xEC8B, 0x9782, 0xEC8C, + 0x9783, 0xEC8D, 0x9784, 0xEC8E, 0x9785, 0xF7B1, 0x9786, 0xEC8F, 0x9787, 0xEC90, 0x9788, 0xEC91, 0x9789, 0xEC92, 0x978A, 0xEC93, + 0x978B, 0xD0AC, 0x978C, 0xEC94, 0x978D, 0xB0B0, 0x978E, 0xEC95, 0x978F, 0xEC96, 0x9790, 0xEC97, 0x9791, 0xF7B2, 0x9792, 0xF7B3, + 0x9793, 0xEC98, 0x9794, 0xF7B4, 0x9795, 0xEC99, 0x9796, 0xEC9A, 0x9797, 0xEC9B, 0x9798, 0xC7CA, 0x9799, 0xEC9C, 0x979A, 0xEC9D, + 0x979B, 0xEC9E, 0x979C, 0xEC9F, 0x979D, 0xECA0, 0x979E, 0xED40, 0x979F, 0xED41, 0x97A0, 0xBECF, 0x97A1, 0xED42, 0x97A2, 0xED43, + 0x97A3, 0xF7B7, 0x97A4, 0xED44, 0x97A5, 0xED45, 0x97A6, 0xED46, 0x97A7, 0xED47, 0x97A8, 0xED48, 0x97A9, 0xED49, 0x97AA, 0xED4A, + 0x97AB, 0xF7B6, 0x97AC, 0xED4B, 0x97AD, 0xB1DE, 0x97AE, 0xED4C, 0x97AF, 0xF7B5, 0x97B0, 0xED4D, 0x97B1, 0xED4E, 0x97B2, 0xF7B8, + 0x97B3, 0xED4F, 0x97B4, 0xF7B9, 0x97B5, 0xED50, 0x97B6, 0xED51, 0x97B7, 0xED52, 0x97B8, 0xED53, 0x97B9, 0xED54, 0x97BA, 0xED55, + 0x97BB, 0xED56, 0x97BC, 0xED57, 0x97BD, 0xED58, 0x97BE, 0xED59, 0x97BF, 0xED5A, 0x97C0, 0xED5B, 0x97C1, 0xED5C, 0x97C2, 0xED5D, + 0x97C3, 0xED5E, 0x97C4, 0xED5F, 0x97C5, 0xED60, 0x97C6, 0xED61, 0x97C7, 0xED62, 0x97C8, 0xED63, 0x97C9, 0xED64, 0x97CA, 0xED65, + 0x97CB, 0xED66, 0x97CC, 0xED67, 0x97CD, 0xED68, 0x97CE, 0xED69, 0x97CF, 0xED6A, 0x97D0, 0xED6B, 0x97D1, 0xED6C, 0x97D2, 0xED6D, + 0x97D3, 0xED6E, 0x97D4, 0xED6F, 0x97D5, 0xED70, 0x97D6, 0xED71, 0x97D7, 0xED72, 0x97D8, 0xED73, 0x97D9, 0xED74, 0x97DA, 0xED75, + 0x97DB, 0xED76, 0x97DC, 0xED77, 0x97DD, 0xED78, 0x97DE, 0xED79, 0x97DF, 0xED7A, 0x97E0, 0xED7B, 0x97E1, 0xED7C, 0x97E2, 0xED7D, + 0x97E3, 0xED7E, 0x97E4, 0xED80, 0x97E5, 0xED81, 0x97E6, 0xCEA4, 0x97E7, 0xC8CD, 0x97E8, 0xED82, 0x97E9, 0xBAAB, 0x97EA, 0xE8B8, + 0x97EB, 0xE8B9, 0x97EC, 0xE8BA, 0x97ED, 0xBEC2, 0x97EE, 0xED83, 0x97EF, 0xED84, 0x97F0, 0xED85, 0x97F1, 0xED86, 0x97F2, 0xED87, + 0x97F3, 0xD2F4, 0x97F4, 0xED88, 0x97F5, 0xD4CF, 0x97F6, 0xC9D8, 0x97F7, 0xED89, 0x97F8, 0xED8A, 0x97F9, 0xED8B, 0x97FA, 0xED8C, + 0x97FB, 0xED8D, 0x97FC, 0xED8E, 0x97FD, 0xED8F, 0x97FE, 0xED90, 0x97FF, 0xED91, 0x9800, 0xED92, 0x9801, 0xED93, 0x9802, 0xED94, + 0x9803, 0xED95, 0x9804, 0xED96, 0x9805, 0xED97, 0x9806, 0xED98, 0x9807, 0xED99, 0x9808, 0xED9A, 0x9809, 0xED9B, 0x980A, 0xED9C, + 0x980B, 0xED9D, 0x980C, 0xED9E, 0x980D, 0xED9F, 0x980E, 0xEDA0, 0x980F, 0xEE40, 0x9810, 0xEE41, 0x9811, 0xEE42, 0x9812, 0xEE43, + 0x9813, 0xEE44, 0x9814, 0xEE45, 0x9815, 0xEE46, 0x9816, 0xEE47, 0x9817, 0xEE48, 0x9818, 0xEE49, 0x9819, 0xEE4A, 0x981A, 0xEE4B, + 0x981B, 0xEE4C, 0x981C, 0xEE4D, 0x981D, 0xEE4E, 0x981E, 0xEE4F, 0x981F, 0xEE50, 0x9820, 0xEE51, 0x9821, 0xEE52, 0x9822, 0xEE53, + 0x9823, 0xEE54, 0x9824, 0xEE55, 0x9825, 0xEE56, 0x9826, 0xEE57, 0x9827, 0xEE58, 0x9828, 0xEE59, 0x9829, 0xEE5A, 0x982A, 0xEE5B, + 0x982B, 0xEE5C, 0x982C, 0xEE5D, 0x982D, 0xEE5E, 0x982E, 0xEE5F, 0x982F, 0xEE60, 0x9830, 0xEE61, 0x9831, 0xEE62, 0x9832, 0xEE63, + 0x9833, 0xEE64, 0x9834, 0xEE65, 0x9835, 0xEE66, 0x9836, 0xEE67, 0x9837, 0xEE68, 0x9838, 0xEE69, 0x9839, 0xEE6A, 0x983A, 0xEE6B, + 0x983B, 0xEE6C, 0x983C, 0xEE6D, 0x983D, 0xEE6E, 0x983E, 0xEE6F, 0x983F, 0xEE70, 0x9840, 0xEE71, 0x9841, 0xEE72, 0x9842, 0xEE73, + 0x9843, 0xEE74, 0x9844, 0xEE75, 0x9845, 0xEE76, 0x9846, 0xEE77, 0x9847, 0xEE78, 0x9848, 0xEE79, 0x9849, 0xEE7A, 0x984A, 0xEE7B, + 0x984B, 0xEE7C, 0x984C, 0xEE7D, 0x984D, 0xEE7E, 0x984E, 0xEE80, 0x984F, 0xEE81, 0x9850, 0xEE82, 0x9851, 0xEE83, 0x9852, 0xEE84, + 0x9853, 0xEE85, 0x9854, 0xEE86, 0x9855, 0xEE87, 0x9856, 0xEE88, 0x9857, 0xEE89, 0x9858, 0xEE8A, 0x9859, 0xEE8B, 0x985A, 0xEE8C, + 0x985B, 0xEE8D, 0x985C, 0xEE8E, 0x985D, 0xEE8F, 0x985E, 0xEE90, 0x985F, 0xEE91, 0x9860, 0xEE92, 0x9861, 0xEE93, 0x9862, 0xEE94, + 0x9863, 0xEE95, 0x9864, 0xEE96, 0x9865, 0xEE97, 0x9866, 0xEE98, 0x9867, 0xEE99, 0x9868, 0xEE9A, 0x9869, 0xEE9B, 0x986A, 0xEE9C, + 0x986B, 0xEE9D, 0x986C, 0xEE9E, 0x986D, 0xEE9F, 0x986E, 0xEEA0, 0x986F, 0xEF40, 0x9870, 0xEF41, 0x9871, 0xEF42, 0x9872, 0xEF43, + 0x9873, 0xEF44, 0x9874, 0xEF45, 0x9875, 0xD2B3, 0x9876, 0xB6A5, 0x9877, 0xC7EA, 0x9878, 0xF1FC, 0x9879, 0xCFEE, 0x987A, 0xCBB3, + 0x987B, 0xD0EB, 0x987C, 0xE7EF, 0x987D, 0xCDE7, 0x987E, 0xB9CB, 0x987F, 0xB6D9, 0x9880, 0xF1FD, 0x9881, 0xB0E4, 0x9882, 0xCBCC, + 0x9883, 0xF1FE, 0x9884, 0xD4A4, 0x9885, 0xC2AD, 0x9886, 0xC1EC, 0x9887, 0xC6C4, 0x9888, 0xBEB1, 0x9889, 0xF2A1, 0x988A, 0xBCD5, + 0x988B, 0xEF46, 0x988C, 0xF2A2, 0x988D, 0xF2A3, 0x988E, 0xEF47, 0x988F, 0xF2A4, 0x9890, 0xD2C3, 0x9891, 0xC6B5, 0x9892, 0xEF48, + 0x9893, 0xCDC7, 0x9894, 0xF2A5, 0x9895, 0xEF49, 0x9896, 0xD3B1, 0x9897, 0xBFC5, 0x9898, 0xCCE2, 0x9899, 0xEF4A, 0x989A, 0xF2A6, + 0x989B, 0xF2A7, 0x989C, 0xD1D5, 0x989D, 0xB6EE, 0x989E, 0xF2A8, 0x989F, 0xF2A9, 0x98A0, 0xB5DF, 0x98A1, 0xF2AA, 0x98A2, 0xF2AB, + 0x98A3, 0xEF4B, 0x98A4, 0xB2FC, 0x98A5, 0xF2AC, 0x98A6, 0xF2AD, 0x98A7, 0xC8A7, 0x98A8, 0xEF4C, 0x98A9, 0xEF4D, 0x98AA, 0xEF4E, + 0x98AB, 0xEF4F, 0x98AC, 0xEF50, 0x98AD, 0xEF51, 0x98AE, 0xEF52, 0x98AF, 0xEF53, 0x98B0, 0xEF54, 0x98B1, 0xEF55, 0x98B2, 0xEF56, + 0x98B3, 0xEF57, 0x98B4, 0xEF58, 0x98B5, 0xEF59, 0x98B6, 0xEF5A, 0x98B7, 0xEF5B, 0x98B8, 0xEF5C, 0x98B9, 0xEF5D, 0x98BA, 0xEF5E, + 0x98BB, 0xEF5F, 0x98BC, 0xEF60, 0x98BD, 0xEF61, 0x98BE, 0xEF62, 0x98BF, 0xEF63, 0x98C0, 0xEF64, 0x98C1, 0xEF65, 0x98C2, 0xEF66, + 0x98C3, 0xEF67, 0x98C4, 0xEF68, 0x98C5, 0xEF69, 0x98C6, 0xEF6A, 0x98C7, 0xEF6B, 0x98C8, 0xEF6C, 0x98C9, 0xEF6D, 0x98CA, 0xEF6E, + 0x98CB, 0xEF6F, 0x98CC, 0xEF70, 0x98CD, 0xEF71, 0x98CE, 0xB7E7, 0x98CF, 0xEF72, 0x98D0, 0xEF73, 0x98D1, 0xECA9, 0x98D2, 0xECAA, + 0x98D3, 0xECAB, 0x98D4, 0xEF74, 0x98D5, 0xECAC, 0x98D6, 0xEF75, 0x98D7, 0xEF76, 0x98D8, 0xC6AE, 0x98D9, 0xECAD, 0x98DA, 0xECAE, + 0x98DB, 0xEF77, 0x98DC, 0xEF78, 0x98DD, 0xEF79, 0x98DE, 0xB7C9, 0x98DF, 0xCAB3, 0x98E0, 0xEF7A, 0x98E1, 0xEF7B, 0x98E2, 0xEF7C, + 0x98E3, 0xEF7D, 0x98E4, 0xEF7E, 0x98E5, 0xEF80, 0x98E6, 0xEF81, 0x98E7, 0xE2B8, 0x98E8, 0xF7CF, 0x98E9, 0xEF82, 0x98EA, 0xEF83, + 0x98EB, 0xEF84, 0x98EC, 0xEF85, 0x98ED, 0xEF86, 0x98EE, 0xEF87, 0x98EF, 0xEF88, 0x98F0, 0xEF89, 0x98F1, 0xEF8A, 0x98F2, 0xEF8B, + 0x98F3, 0xEF8C, 0x98F4, 0xEF8D, 0x98F5, 0xEF8E, 0x98F6, 0xEF8F, 0x98F7, 0xEF90, 0x98F8, 0xEF91, 0x98F9, 0xEF92, 0x98FA, 0xEF93, + 0x98FB, 0xEF94, 0x98FC, 0xEF95, 0x98FD, 0xEF96, 0x98FE, 0xEF97, 0x98FF, 0xEF98, 0x9900, 0xEF99, 0x9901, 0xEF9A, 0x9902, 0xEF9B, + 0x9903, 0xEF9C, 0x9904, 0xEF9D, 0x9905, 0xEF9E, 0x9906, 0xEF9F, 0x9907, 0xEFA0, 0x9908, 0xF040, 0x9909, 0xF041, 0x990A, 0xF042, + 0x990B, 0xF043, 0x990C, 0xF044, 0x990D, 0xF7D0, 0x990E, 0xF045, 0x990F, 0xF046, 0x9910, 0xB2CD, 0x9911, 0xF047, 0x9912, 0xF048, + 0x9913, 0xF049, 0x9914, 0xF04A, 0x9915, 0xF04B, 0x9916, 0xF04C, 0x9917, 0xF04D, 0x9918, 0xF04E, 0x9919, 0xF04F, 0x991A, 0xF050, + 0x991B, 0xF051, 0x991C, 0xF052, 0x991D, 0xF053, 0x991E, 0xF054, 0x991F, 0xF055, 0x9920, 0xF056, 0x9921, 0xF057, 0x9922, 0xF058, + 0x9923, 0xF059, 0x9924, 0xF05A, 0x9925, 0xF05B, 0x9926, 0xF05C, 0x9927, 0xF05D, 0x9928, 0xF05E, 0x9929, 0xF05F, 0x992A, 0xF060, + 0x992B, 0xF061, 0x992C, 0xF062, 0x992D, 0xF063, 0x992E, 0xF7D1, 0x992F, 0xF064, 0x9930, 0xF065, 0x9931, 0xF066, 0x9932, 0xF067, + 0x9933, 0xF068, 0x9934, 0xF069, 0x9935, 0xF06A, 0x9936, 0xF06B, 0x9937, 0xF06C, 0x9938, 0xF06D, 0x9939, 0xF06E, 0x993A, 0xF06F, + 0x993B, 0xF070, 0x993C, 0xF071, 0x993D, 0xF072, 0x993E, 0xF073, 0x993F, 0xF074, 0x9940, 0xF075, 0x9941, 0xF076, 0x9942, 0xF077, + 0x9943, 0xF078, 0x9944, 0xF079, 0x9945, 0xF07A, 0x9946, 0xF07B, 0x9947, 0xF07C, 0x9948, 0xF07D, 0x9949, 0xF07E, 0x994A, 0xF080, + 0x994B, 0xF081, 0x994C, 0xF082, 0x994D, 0xF083, 0x994E, 0xF084, 0x994F, 0xF085, 0x9950, 0xF086, 0x9951, 0xF087, 0x9952, 0xF088, + 0x9953, 0xF089, 0x9954, 0xF7D3, 0x9955, 0xF7D2, 0x9956, 0xF08A, 0x9957, 0xF08B, 0x9958, 0xF08C, 0x9959, 0xF08D, 0x995A, 0xF08E, + 0x995B, 0xF08F, 0x995C, 0xF090, 0x995D, 0xF091, 0x995E, 0xF092, 0x995F, 0xF093, 0x9960, 0xF094, 0x9961, 0xF095, 0x9962, 0xF096, + 0x9963, 0xE2BB, 0x9964, 0xF097, 0x9965, 0xBCA2, 0x9966, 0xF098, 0x9967, 0xE2BC, 0x9968, 0xE2BD, 0x9969, 0xE2BE, 0x996A, 0xE2BF, + 0x996B, 0xE2C0, 0x996C, 0xE2C1, 0x996D, 0xB7B9, 0x996E, 0xD2FB, 0x996F, 0xBDA4, 0x9970, 0xCACE, 0x9971, 0xB1A5, 0x9972, 0xCBC7, + 0x9973, 0xF099, 0x9974, 0xE2C2, 0x9975, 0xB6FC, 0x9976, 0xC8C4, 0x9977, 0xE2C3, 0x9978, 0xF09A, 0x9979, 0xF09B, 0x997A, 0xBDC8, + 0x997B, 0xF09C, 0x997C, 0xB1FD, 0x997D, 0xE2C4, 0x997E, 0xF09D, 0x997F, 0xB6F6, 0x9980, 0xE2C5, 0x9981, 0xC4D9, 0x9982, 0xF09E, + 0x9983, 0xF09F, 0x9984, 0xE2C6, 0x9985, 0xCFDA, 0x9986, 0xB9DD, 0x9987, 0xE2C7, 0x9988, 0xC0A1, 0x9989, 0xF0A0, 0x998A, 0xE2C8, + 0x998B, 0xB2F6, 0x998C, 0xF140, 0x998D, 0xE2C9, 0x998E, 0xF141, 0x998F, 0xC1F3, 0x9990, 0xE2CA, 0x9991, 0xE2CB, 0x9992, 0xC2F8, + 0x9993, 0xE2CC, 0x9994, 0xE2CD, 0x9995, 0xE2CE, 0x9996, 0xCAD7, 0x9997, 0xD8B8, 0x9998, 0xD9E5, 0x9999, 0xCFE3, 0x999A, 0xF142, + 0x999B, 0xF143, 0x999C, 0xF144, 0x999D, 0xF145, 0x999E, 0xF146, 0x999F, 0xF147, 0x99A0, 0xF148, 0x99A1, 0xF149, 0x99A2, 0xF14A, + 0x99A3, 0xF14B, 0x99A4, 0xF14C, 0x99A5, 0xF0A5, 0x99A6, 0xF14D, 0x99A7, 0xF14E, 0x99A8, 0xDCB0, 0x99A9, 0xF14F, 0x99AA, 0xF150, + 0x99AB, 0xF151, 0x99AC, 0xF152, 0x99AD, 0xF153, 0x99AE, 0xF154, 0x99AF, 0xF155, 0x99B0, 0xF156, 0x99B1, 0xF157, 0x99B2, 0xF158, + 0x99B3, 0xF159, 0x99B4, 0xF15A, 0x99B5, 0xF15B, 0x99B6, 0xF15C, 0x99B7, 0xF15D, 0x99B8, 0xF15E, 0x99B9, 0xF15F, 0x99BA, 0xF160, + 0x99BB, 0xF161, 0x99BC, 0xF162, 0x99BD, 0xF163, 0x99BE, 0xF164, 0x99BF, 0xF165, 0x99C0, 0xF166, 0x99C1, 0xF167, 0x99C2, 0xF168, + 0x99C3, 0xF169, 0x99C4, 0xF16A, 0x99C5, 0xF16B, 0x99C6, 0xF16C, 0x99C7, 0xF16D, 0x99C8, 0xF16E, 0x99C9, 0xF16F, 0x99CA, 0xF170, + 0x99CB, 0xF171, 0x99CC, 0xF172, 0x99CD, 0xF173, 0x99CE, 0xF174, 0x99CF, 0xF175, 0x99D0, 0xF176, 0x99D1, 0xF177, 0x99D2, 0xF178, + 0x99D3, 0xF179, 0x99D4, 0xF17A, 0x99D5, 0xF17B, 0x99D6, 0xF17C, 0x99D7, 0xF17D, 0x99D8, 0xF17E, 0x99D9, 0xF180, 0x99DA, 0xF181, + 0x99DB, 0xF182, 0x99DC, 0xF183, 0x99DD, 0xF184, 0x99DE, 0xF185, 0x99DF, 0xF186, 0x99E0, 0xF187, 0x99E1, 0xF188, 0x99E2, 0xF189, + 0x99E3, 0xF18A, 0x99E4, 0xF18B, 0x99E5, 0xF18C, 0x99E6, 0xF18D, 0x99E7, 0xF18E, 0x99E8, 0xF18F, 0x99E9, 0xF190, 0x99EA, 0xF191, + 0x99EB, 0xF192, 0x99EC, 0xF193, 0x99ED, 0xF194, 0x99EE, 0xF195, 0x99EF, 0xF196, 0x99F0, 0xF197, 0x99F1, 0xF198, 0x99F2, 0xF199, + 0x99F3, 0xF19A, 0x99F4, 0xF19B, 0x99F5, 0xF19C, 0x99F6, 0xF19D, 0x99F7, 0xF19E, 0x99F8, 0xF19F, 0x99F9, 0xF1A0, 0x99FA, 0xF240, + 0x99FB, 0xF241, 0x99FC, 0xF242, 0x99FD, 0xF243, 0x99FE, 0xF244, 0x99FF, 0xF245, 0x9A00, 0xF246, 0x9A01, 0xF247, 0x9A02, 0xF248, + 0x9A03, 0xF249, 0x9A04, 0xF24A, 0x9A05, 0xF24B, 0x9A06, 0xF24C, 0x9A07, 0xF24D, 0x9A08, 0xF24E, 0x9A09, 0xF24F, 0x9A0A, 0xF250, + 0x9A0B, 0xF251, 0x9A0C, 0xF252, 0x9A0D, 0xF253, 0x9A0E, 0xF254, 0x9A0F, 0xF255, 0x9A10, 0xF256, 0x9A11, 0xF257, 0x9A12, 0xF258, + 0x9A13, 0xF259, 0x9A14, 0xF25A, 0x9A15, 0xF25B, 0x9A16, 0xF25C, 0x9A17, 0xF25D, 0x9A18, 0xF25E, 0x9A19, 0xF25F, 0x9A1A, 0xF260, + 0x9A1B, 0xF261, 0x9A1C, 0xF262, 0x9A1D, 0xF263, 0x9A1E, 0xF264, 0x9A1F, 0xF265, 0x9A20, 0xF266, 0x9A21, 0xF267, 0x9A22, 0xF268, + 0x9A23, 0xF269, 0x9A24, 0xF26A, 0x9A25, 0xF26B, 0x9A26, 0xF26C, 0x9A27, 0xF26D, 0x9A28, 0xF26E, 0x9A29, 0xF26F, 0x9A2A, 0xF270, + 0x9A2B, 0xF271, 0x9A2C, 0xF272, 0x9A2D, 0xF273, 0x9A2E, 0xF274, 0x9A2F, 0xF275, 0x9A30, 0xF276, 0x9A31, 0xF277, 0x9A32, 0xF278, + 0x9A33, 0xF279, 0x9A34, 0xF27A, 0x9A35, 0xF27B, 0x9A36, 0xF27C, 0x9A37, 0xF27D, 0x9A38, 0xF27E, 0x9A39, 0xF280, 0x9A3A, 0xF281, + 0x9A3B, 0xF282, 0x9A3C, 0xF283, 0x9A3D, 0xF284, 0x9A3E, 0xF285, 0x9A3F, 0xF286, 0x9A40, 0xF287, 0x9A41, 0xF288, 0x9A42, 0xF289, + 0x9A43, 0xF28A, 0x9A44, 0xF28B, 0x9A45, 0xF28C, 0x9A46, 0xF28D, 0x9A47, 0xF28E, 0x9A48, 0xF28F, 0x9A49, 0xF290, 0x9A4A, 0xF291, + 0x9A4B, 0xF292, 0x9A4C, 0xF293, 0x9A4D, 0xF294, 0x9A4E, 0xF295, 0x9A4F, 0xF296, 0x9A50, 0xF297, 0x9A51, 0xF298, 0x9A52, 0xF299, + 0x9A53, 0xF29A, 0x9A54, 0xF29B, 0x9A55, 0xF29C, 0x9A56, 0xF29D, 0x9A57, 0xF29E, 0x9A58, 0xF29F, 0x9A59, 0xF2A0, 0x9A5A, 0xF340, + 0x9A5B, 0xF341, 0x9A5C, 0xF342, 0x9A5D, 0xF343, 0x9A5E, 0xF344, 0x9A5F, 0xF345, 0x9A60, 0xF346, 0x9A61, 0xF347, 0x9A62, 0xF348, + 0x9A63, 0xF349, 0x9A64, 0xF34A, 0x9A65, 0xF34B, 0x9A66, 0xF34C, 0x9A67, 0xF34D, 0x9A68, 0xF34E, 0x9A69, 0xF34F, 0x9A6A, 0xF350, + 0x9A6B, 0xF351, 0x9A6C, 0xC2ED, 0x9A6D, 0xD4A6, 0x9A6E, 0xCDD4, 0x9A6F, 0xD1B1, 0x9A70, 0xB3DB, 0x9A71, 0xC7FD, 0x9A72, 0xF352, + 0x9A73, 0xB2B5, 0x9A74, 0xC2BF, 0x9A75, 0xE6E0, 0x9A76, 0xCABB, 0x9A77, 0xE6E1, 0x9A78, 0xE6E2, 0x9A79, 0xBED4, 0x9A7A, 0xE6E3, + 0x9A7B, 0xD7A4, 0x9A7C, 0xCDD5, 0x9A7D, 0xE6E5, 0x9A7E, 0xBCDD, 0x9A7F, 0xE6E4, 0x9A80, 0xE6E6, 0x9A81, 0xE6E7, 0x9A82, 0xC2EE, + 0x9A83, 0xF353, 0x9A84, 0xBDBE, 0x9A85, 0xE6E8, 0x9A86, 0xC2E6, 0x9A87, 0xBAA7, 0x9A88, 0xE6E9, 0x9A89, 0xF354, 0x9A8A, 0xE6EA, + 0x9A8B, 0xB3D2, 0x9A8C, 0xD1E9, 0x9A8D, 0xF355, 0x9A8E, 0xF356, 0x9A8F, 0xBFA5, 0x9A90, 0xE6EB, 0x9A91, 0xC6EF, 0x9A92, 0xE6EC, + 0x9A93, 0xE6ED, 0x9A94, 0xF357, 0x9A95, 0xF358, 0x9A96, 0xE6EE, 0x9A97, 0xC6AD, 0x9A98, 0xE6EF, 0x9A99, 0xF359, 0x9A9A, 0xC9A7, + 0x9A9B, 0xE6F0, 0x9A9C, 0xE6F1, 0x9A9D, 0xE6F2, 0x9A9E, 0xE5B9, 0x9A9F, 0xE6F3, 0x9AA0, 0xE6F4, 0x9AA1, 0xC2E2, 0x9AA2, 0xE6F5, + 0x9AA3, 0xE6F6, 0x9AA4, 0xD6E8, 0x9AA5, 0xE6F7, 0x9AA6, 0xF35A, 0x9AA7, 0xE6F8, 0x9AA8, 0xB9C7, 0x9AA9, 0xF35B, 0x9AAA, 0xF35C, + 0x9AAB, 0xF35D, 0x9AAC, 0xF35E, 0x9AAD, 0xF35F, 0x9AAE, 0xF360, 0x9AAF, 0xF361, 0x9AB0, 0xF7BB, 0x9AB1, 0xF7BA, 0x9AB2, 0xF362, + 0x9AB3, 0xF363, 0x9AB4, 0xF364, 0x9AB5, 0xF365, 0x9AB6, 0xF7BE, 0x9AB7, 0xF7BC, 0x9AB8, 0xBAA1, 0x9AB9, 0xF366, 0x9ABA, 0xF7BF, + 0x9ABB, 0xF367, 0x9ABC, 0xF7C0, 0x9ABD, 0xF368, 0x9ABE, 0xF369, 0x9ABF, 0xF36A, 0x9AC0, 0xF7C2, 0x9AC1, 0xF7C1, 0x9AC2, 0xF7C4, + 0x9AC3, 0xF36B, 0x9AC4, 0xF36C, 0x9AC5, 0xF7C3, 0x9AC6, 0xF36D, 0x9AC7, 0xF36E, 0x9AC8, 0xF36F, 0x9AC9, 0xF370, 0x9ACA, 0xF371, + 0x9ACB, 0xF7C5, 0x9ACC, 0xF7C6, 0x9ACD, 0xF372, 0x9ACE, 0xF373, 0x9ACF, 0xF374, 0x9AD0, 0xF375, 0x9AD1, 0xF7C7, 0x9AD2, 0xF376, + 0x9AD3, 0xCBE8, 0x9AD4, 0xF377, 0x9AD5, 0xF378, 0x9AD6, 0xF379, 0x9AD7, 0xF37A, 0x9AD8, 0xB8DF, 0x9AD9, 0xF37B, 0x9ADA, 0xF37C, + 0x9ADB, 0xF37D, 0x9ADC, 0xF37E, 0x9ADD, 0xF380, 0x9ADE, 0xF381, 0x9ADF, 0xF7D4, 0x9AE0, 0xF382, 0x9AE1, 0xF7D5, 0x9AE2, 0xF383, + 0x9AE3, 0xF384, 0x9AE4, 0xF385, 0x9AE5, 0xF386, 0x9AE6, 0xF7D6, 0x9AE7, 0xF387, 0x9AE8, 0xF388, 0x9AE9, 0xF389, 0x9AEA, 0xF38A, + 0x9AEB, 0xF7D8, 0x9AEC, 0xF38B, 0x9AED, 0xF7DA, 0x9AEE, 0xF38C, 0x9AEF, 0xF7D7, 0x9AF0, 0xF38D, 0x9AF1, 0xF38E, 0x9AF2, 0xF38F, + 0x9AF3, 0xF390, 0x9AF4, 0xF391, 0x9AF5, 0xF392, 0x9AF6, 0xF393, 0x9AF7, 0xF394, 0x9AF8, 0xF395, 0x9AF9, 0xF7DB, 0x9AFA, 0xF396, + 0x9AFB, 0xF7D9, 0x9AFC, 0xF397, 0x9AFD, 0xF398, 0x9AFE, 0xF399, 0x9AFF, 0xF39A, 0x9B00, 0xF39B, 0x9B01, 0xF39C, 0x9B02, 0xF39D, + 0x9B03, 0xD7D7, 0x9B04, 0xF39E, 0x9B05, 0xF39F, 0x9B06, 0xF3A0, 0x9B07, 0xF440, 0x9B08, 0xF7DC, 0x9B09, 0xF441, 0x9B0A, 0xF442, + 0x9B0B, 0xF443, 0x9B0C, 0xF444, 0x9B0D, 0xF445, 0x9B0E, 0xF446, 0x9B0F, 0xF7DD, 0x9B10, 0xF447, 0x9B11, 0xF448, 0x9B12, 0xF449, + 0x9B13, 0xF7DE, 0x9B14, 0xF44A, 0x9B15, 0xF44B, 0x9B16, 0xF44C, 0x9B17, 0xF44D, 0x9B18, 0xF44E, 0x9B19, 0xF44F, 0x9B1A, 0xF450, + 0x9B1B, 0xF451, 0x9B1C, 0xF452, 0x9B1D, 0xF453, 0x9B1E, 0xF454, 0x9B1F, 0xF7DF, 0x9B20, 0xF455, 0x9B21, 0xF456, 0x9B22, 0xF457, + 0x9B23, 0xF7E0, 0x9B24, 0xF458, 0x9B25, 0xF459, 0x9B26, 0xF45A, 0x9B27, 0xF45B, 0x9B28, 0xF45C, 0x9B29, 0xF45D, 0x9B2A, 0xF45E, + 0x9B2B, 0xF45F, 0x9B2C, 0xF460, 0x9B2D, 0xF461, 0x9B2E, 0xF462, 0x9B2F, 0xDBCB, 0x9B30, 0xF463, 0x9B31, 0xF464, 0x9B32, 0xD8AA, + 0x9B33, 0xF465, 0x9B34, 0xF466, 0x9B35, 0xF467, 0x9B36, 0xF468, 0x9B37, 0xF469, 0x9B38, 0xF46A, 0x9B39, 0xF46B, 0x9B3A, 0xF46C, + 0x9B3B, 0xE5F7, 0x9B3C, 0xB9ED, 0x9B3D, 0xF46D, 0x9B3E, 0xF46E, 0x9B3F, 0xF46F, 0x9B40, 0xF470, 0x9B41, 0xBFFD, 0x9B42, 0xBBEA, + 0x9B43, 0xF7C9, 0x9B44, 0xC6C7, 0x9B45, 0xF7C8, 0x9B46, 0xF471, 0x9B47, 0xF7CA, 0x9B48, 0xF7CC, 0x9B49, 0xF7CB, 0x9B4A, 0xF472, + 0x9B4B, 0xF473, 0x9B4C, 0xF474, 0x9B4D, 0xF7CD, 0x9B4E, 0xF475, 0x9B4F, 0xCEBA, 0x9B50, 0xF476, 0x9B51, 0xF7CE, 0x9B52, 0xF477, + 0x9B53, 0xF478, 0x9B54, 0xC4A7, 0x9B55, 0xF479, 0x9B56, 0xF47A, 0x9B57, 0xF47B, 0x9B58, 0xF47C, 0x9B59, 0xF47D, 0x9B5A, 0xF47E, + 0x9B5B, 0xF480, 0x9B5C, 0xF481, 0x9B5D, 0xF482, 0x9B5E, 0xF483, 0x9B5F, 0xF484, 0x9B60, 0xF485, 0x9B61, 0xF486, 0x9B62, 0xF487, + 0x9B63, 0xF488, 0x9B64, 0xF489, 0x9B65, 0xF48A, 0x9B66, 0xF48B, 0x9B67, 0xF48C, 0x9B68, 0xF48D, 0x9B69, 0xF48E, 0x9B6A, 0xF48F, + 0x9B6B, 0xF490, 0x9B6C, 0xF491, 0x9B6D, 0xF492, 0x9B6E, 0xF493, 0x9B6F, 0xF494, 0x9B70, 0xF495, 0x9B71, 0xF496, 0x9B72, 0xF497, + 0x9B73, 0xF498, 0x9B74, 0xF499, 0x9B75, 0xF49A, 0x9B76, 0xF49B, 0x9B77, 0xF49C, 0x9B78, 0xF49D, 0x9B79, 0xF49E, 0x9B7A, 0xF49F, + 0x9B7B, 0xF4A0, 0x9B7C, 0xF540, 0x9B7D, 0xF541, 0x9B7E, 0xF542, 0x9B7F, 0xF543, 0x9B80, 0xF544, 0x9B81, 0xF545, 0x9B82, 0xF546, + 0x9B83, 0xF547, 0x9B84, 0xF548, 0x9B85, 0xF549, 0x9B86, 0xF54A, 0x9B87, 0xF54B, 0x9B88, 0xF54C, 0x9B89, 0xF54D, 0x9B8A, 0xF54E, + 0x9B8B, 0xF54F, 0x9B8C, 0xF550, 0x9B8D, 0xF551, 0x9B8E, 0xF552, 0x9B8F, 0xF553, 0x9B90, 0xF554, 0x9B91, 0xF555, 0x9B92, 0xF556, + 0x9B93, 0xF557, 0x9B94, 0xF558, 0x9B95, 0xF559, 0x9B96, 0xF55A, 0x9B97, 0xF55B, 0x9B98, 0xF55C, 0x9B99, 0xF55D, 0x9B9A, 0xF55E, + 0x9B9B, 0xF55F, 0x9B9C, 0xF560, 0x9B9D, 0xF561, 0x9B9E, 0xF562, 0x9B9F, 0xF563, 0x9BA0, 0xF564, 0x9BA1, 0xF565, 0x9BA2, 0xF566, + 0x9BA3, 0xF567, 0x9BA4, 0xF568, 0x9BA5, 0xF569, 0x9BA6, 0xF56A, 0x9BA7, 0xF56B, 0x9BA8, 0xF56C, 0x9BA9, 0xF56D, 0x9BAA, 0xF56E, + 0x9BAB, 0xF56F, 0x9BAC, 0xF570, 0x9BAD, 0xF571, 0x9BAE, 0xF572, 0x9BAF, 0xF573, 0x9BB0, 0xF574, 0x9BB1, 0xF575, 0x9BB2, 0xF576, + 0x9BB3, 0xF577, 0x9BB4, 0xF578, 0x9BB5, 0xF579, 0x9BB6, 0xF57A, 0x9BB7, 0xF57B, 0x9BB8, 0xF57C, 0x9BB9, 0xF57D, 0x9BBA, 0xF57E, + 0x9BBB, 0xF580, 0x9BBC, 0xF581, 0x9BBD, 0xF582, 0x9BBE, 0xF583, 0x9BBF, 0xF584, 0x9BC0, 0xF585, 0x9BC1, 0xF586, 0x9BC2, 0xF587, + 0x9BC3, 0xF588, 0x9BC4, 0xF589, 0x9BC5, 0xF58A, 0x9BC6, 0xF58B, 0x9BC7, 0xF58C, 0x9BC8, 0xF58D, 0x9BC9, 0xF58E, 0x9BCA, 0xF58F, + 0x9BCB, 0xF590, 0x9BCC, 0xF591, 0x9BCD, 0xF592, 0x9BCE, 0xF593, 0x9BCF, 0xF594, 0x9BD0, 0xF595, 0x9BD1, 0xF596, 0x9BD2, 0xF597, + 0x9BD3, 0xF598, 0x9BD4, 0xF599, 0x9BD5, 0xF59A, 0x9BD6, 0xF59B, 0x9BD7, 0xF59C, 0x9BD8, 0xF59D, 0x9BD9, 0xF59E, 0x9BDA, 0xF59F, + 0x9BDB, 0xF5A0, 0x9BDC, 0xF640, 0x9BDD, 0xF641, 0x9BDE, 0xF642, 0x9BDF, 0xF643, 0x9BE0, 0xF644, 0x9BE1, 0xF645, 0x9BE2, 0xF646, + 0x9BE3, 0xF647, 0x9BE4, 0xF648, 0x9BE5, 0xF649, 0x9BE6, 0xF64A, 0x9BE7, 0xF64B, 0x9BE8, 0xF64C, 0x9BE9, 0xF64D, 0x9BEA, 0xF64E, + 0x9BEB, 0xF64F, 0x9BEC, 0xF650, 0x9BED, 0xF651, 0x9BEE, 0xF652, 0x9BEF, 0xF653, 0x9BF0, 0xF654, 0x9BF1, 0xF655, 0x9BF2, 0xF656, + 0x9BF3, 0xF657, 0x9BF4, 0xF658, 0x9BF5, 0xF659, 0x9BF6, 0xF65A, 0x9BF7, 0xF65B, 0x9BF8, 0xF65C, 0x9BF9, 0xF65D, 0x9BFA, 0xF65E, + 0x9BFB, 0xF65F, 0x9BFC, 0xF660, 0x9BFD, 0xF661, 0x9BFE, 0xF662, 0x9BFF, 0xF663, 0x9C00, 0xF664, 0x9C01, 0xF665, 0x9C02, 0xF666, + 0x9C03, 0xF667, 0x9C04, 0xF668, 0x9C05, 0xF669, 0x9C06, 0xF66A, 0x9C07, 0xF66B, 0x9C08, 0xF66C, 0x9C09, 0xF66D, 0x9C0A, 0xF66E, + 0x9C0B, 0xF66F, 0x9C0C, 0xF670, 0x9C0D, 0xF671, 0x9C0E, 0xF672, 0x9C0F, 0xF673, 0x9C10, 0xF674, 0x9C11, 0xF675, 0x9C12, 0xF676, + 0x9C13, 0xF677, 0x9C14, 0xF678, 0x9C15, 0xF679, 0x9C16, 0xF67A, 0x9C17, 0xF67B, 0x9C18, 0xF67C, 0x9C19, 0xF67D, 0x9C1A, 0xF67E, + 0x9C1B, 0xF680, 0x9C1C, 0xF681, 0x9C1D, 0xF682, 0x9C1E, 0xF683, 0x9C1F, 0xF684, 0x9C20, 0xF685, 0x9C21, 0xF686, 0x9C22, 0xF687, + 0x9C23, 0xF688, 0x9C24, 0xF689, 0x9C25, 0xF68A, 0x9C26, 0xF68B, 0x9C27, 0xF68C, 0x9C28, 0xF68D, 0x9C29, 0xF68E, 0x9C2A, 0xF68F, + 0x9C2B, 0xF690, 0x9C2C, 0xF691, 0x9C2D, 0xF692, 0x9C2E, 0xF693, 0x9C2F, 0xF694, 0x9C30, 0xF695, 0x9C31, 0xF696, 0x9C32, 0xF697, + 0x9C33, 0xF698, 0x9C34, 0xF699, 0x9C35, 0xF69A, 0x9C36, 0xF69B, 0x9C37, 0xF69C, 0x9C38, 0xF69D, 0x9C39, 0xF69E, 0x9C3A, 0xF69F, + 0x9C3B, 0xF6A0, 0x9C3C, 0xF740, 0x9C3D, 0xF741, 0x9C3E, 0xF742, 0x9C3F, 0xF743, 0x9C40, 0xF744, 0x9C41, 0xF745, 0x9C42, 0xF746, + 0x9C43, 0xF747, 0x9C44, 0xF748, 0x9C45, 0xF749, 0x9C46, 0xF74A, 0x9C47, 0xF74B, 0x9C48, 0xF74C, 0x9C49, 0xF74D, 0x9C4A, 0xF74E, + 0x9C4B, 0xF74F, 0x9C4C, 0xF750, 0x9C4D, 0xF751, 0x9C4E, 0xF752, 0x9C4F, 0xF753, 0x9C50, 0xF754, 0x9C51, 0xF755, 0x9C52, 0xF756, + 0x9C53, 0xF757, 0x9C54, 0xF758, 0x9C55, 0xF759, 0x9C56, 0xF75A, 0x9C57, 0xF75B, 0x9C58, 0xF75C, 0x9C59, 0xF75D, 0x9C5A, 0xF75E, + 0x9C5B, 0xF75F, 0x9C5C, 0xF760, 0x9C5D, 0xF761, 0x9C5E, 0xF762, 0x9C5F, 0xF763, 0x9C60, 0xF764, 0x9C61, 0xF765, 0x9C62, 0xF766, + 0x9C63, 0xF767, 0x9C64, 0xF768, 0x9C65, 0xF769, 0x9C66, 0xF76A, 0x9C67, 0xF76B, 0x9C68, 0xF76C, 0x9C69, 0xF76D, 0x9C6A, 0xF76E, + 0x9C6B, 0xF76F, 0x9C6C, 0xF770, 0x9C6D, 0xF771, 0x9C6E, 0xF772, 0x9C6F, 0xF773, 0x9C70, 0xF774, 0x9C71, 0xF775, 0x9C72, 0xF776, + 0x9C73, 0xF777, 0x9C74, 0xF778, 0x9C75, 0xF779, 0x9C76, 0xF77A, 0x9C77, 0xF77B, 0x9C78, 0xF77C, 0x9C79, 0xF77D, 0x9C7A, 0xF77E, + 0x9C7B, 0xF780, 0x9C7C, 0xD3E3, 0x9C7D, 0xF781, 0x9C7E, 0xF782, 0x9C7F, 0xF6CF, 0x9C80, 0xF783, 0x9C81, 0xC2B3, 0x9C82, 0xF6D0, + 0x9C83, 0xF784, 0x9C84, 0xF785, 0x9C85, 0xF6D1, 0x9C86, 0xF6D2, 0x9C87, 0xF6D3, 0x9C88, 0xF6D4, 0x9C89, 0xF786, 0x9C8A, 0xF787, + 0x9C8B, 0xF6D6, 0x9C8C, 0xF788, 0x9C8D, 0xB1AB, 0x9C8E, 0xF6D7, 0x9C8F, 0xF789, 0x9C90, 0xF6D8, 0x9C91, 0xF6D9, 0x9C92, 0xF6DA, + 0x9C93, 0xF78A, 0x9C94, 0xF6DB, 0x9C95, 0xF6DC, 0x9C96, 0xF78B, 0x9C97, 0xF78C, 0x9C98, 0xF78D, 0x9C99, 0xF78E, 0x9C9A, 0xF6DD, + 0x9C9B, 0xF6DE, 0x9C9C, 0xCFCA, 0x9C9D, 0xF78F, 0x9C9E, 0xF6DF, 0x9C9F, 0xF6E0, 0x9CA0, 0xF6E1, 0x9CA1, 0xF6E2, 0x9CA2, 0xF6E3, + 0x9CA3, 0xF6E4, 0x9CA4, 0xC0F0, 0x9CA5, 0xF6E5, 0x9CA6, 0xF6E6, 0x9CA7, 0xF6E7, 0x9CA8, 0xF6E8, 0x9CA9, 0xF6E9, 0x9CAA, 0xF790, + 0x9CAB, 0xF6EA, 0x9CAC, 0xF791, 0x9CAD, 0xF6EB, 0x9CAE, 0xF6EC, 0x9CAF, 0xF792, 0x9CB0, 0xF6ED, 0x9CB1, 0xF6EE, 0x9CB2, 0xF6EF, + 0x9CB3, 0xF6F0, 0x9CB4, 0xF6F1, 0x9CB5, 0xF6F2, 0x9CB6, 0xF6F3, 0x9CB7, 0xF6F4, 0x9CB8, 0xBEA8, 0x9CB9, 0xF793, 0x9CBA, 0xF6F5, + 0x9CBB, 0xF6F6, 0x9CBC, 0xF6F7, 0x9CBD, 0xF6F8, 0x9CBE, 0xF794, 0x9CBF, 0xF795, 0x9CC0, 0xF796, 0x9CC1, 0xF797, 0x9CC2, 0xF798, + 0x9CC3, 0xC8FA, 0x9CC4, 0xF6F9, 0x9CC5, 0xF6FA, 0x9CC6, 0xF6FB, 0x9CC7, 0xF6FC, 0x9CC8, 0xF799, 0x9CC9, 0xF79A, 0x9CCA, 0xF6FD, + 0x9CCB, 0xF6FE, 0x9CCC, 0xF7A1, 0x9CCD, 0xF7A2, 0x9CCE, 0xF7A3, 0x9CCF, 0xF7A4, 0x9CD0, 0xF7A5, 0x9CD1, 0xF79B, 0x9CD2, 0xF79C, + 0x9CD3, 0xF7A6, 0x9CD4, 0xF7A7, 0x9CD5, 0xF7A8, 0x9CD6, 0xB1EE, 0x9CD7, 0xF7A9, 0x9CD8, 0xF7AA, 0x9CD9, 0xF7AB, 0x9CDA, 0xF79D, + 0x9CDB, 0xF79E, 0x9CDC, 0xF7AC, 0x9CDD, 0xF7AD, 0x9CDE, 0xC1DB, 0x9CDF, 0xF7AE, 0x9CE0, 0xF79F, 0x9CE1, 0xF7A0, 0x9CE2, 0xF7AF, + 0x9CE3, 0xF840, 0x9CE4, 0xF841, 0x9CE5, 0xF842, 0x9CE6, 0xF843, 0x9CE7, 0xF844, 0x9CE8, 0xF845, 0x9CE9, 0xF846, 0x9CEA, 0xF847, + 0x9CEB, 0xF848, 0x9CEC, 0xF849, 0x9CED, 0xF84A, 0x9CEE, 0xF84B, 0x9CEF, 0xF84C, 0x9CF0, 0xF84D, 0x9CF1, 0xF84E, 0x9CF2, 0xF84F, + 0x9CF3, 0xF850, 0x9CF4, 0xF851, 0x9CF5, 0xF852, 0x9CF6, 0xF853, 0x9CF7, 0xF854, 0x9CF8, 0xF855, 0x9CF9, 0xF856, 0x9CFA, 0xF857, + 0x9CFB, 0xF858, 0x9CFC, 0xF859, 0x9CFD, 0xF85A, 0x9CFE, 0xF85B, 0x9CFF, 0xF85C, 0x9D00, 0xF85D, 0x9D01, 0xF85E, 0x9D02, 0xF85F, + 0x9D03, 0xF860, 0x9D04, 0xF861, 0x9D05, 0xF862, 0x9D06, 0xF863, 0x9D07, 0xF864, 0x9D08, 0xF865, 0x9D09, 0xF866, 0x9D0A, 0xF867, + 0x9D0B, 0xF868, 0x9D0C, 0xF869, 0x9D0D, 0xF86A, 0x9D0E, 0xF86B, 0x9D0F, 0xF86C, 0x9D10, 0xF86D, 0x9D11, 0xF86E, 0x9D12, 0xF86F, + 0x9D13, 0xF870, 0x9D14, 0xF871, 0x9D15, 0xF872, 0x9D16, 0xF873, 0x9D17, 0xF874, 0x9D18, 0xF875, 0x9D19, 0xF876, 0x9D1A, 0xF877, + 0x9D1B, 0xF878, 0x9D1C, 0xF879, 0x9D1D, 0xF87A, 0x9D1E, 0xF87B, 0x9D1F, 0xF87C, 0x9D20, 0xF87D, 0x9D21, 0xF87E, 0x9D22, 0xF880, + 0x9D23, 0xF881, 0x9D24, 0xF882, 0x9D25, 0xF883, 0x9D26, 0xF884, 0x9D27, 0xF885, 0x9D28, 0xF886, 0x9D29, 0xF887, 0x9D2A, 0xF888, + 0x9D2B, 0xF889, 0x9D2C, 0xF88A, 0x9D2D, 0xF88B, 0x9D2E, 0xF88C, 0x9D2F, 0xF88D, 0x9D30, 0xF88E, 0x9D31, 0xF88F, 0x9D32, 0xF890, + 0x9D33, 0xF891, 0x9D34, 0xF892, 0x9D35, 0xF893, 0x9D36, 0xF894, 0x9D37, 0xF895, 0x9D38, 0xF896, 0x9D39, 0xF897, 0x9D3A, 0xF898, + 0x9D3B, 0xF899, 0x9D3C, 0xF89A, 0x9D3D, 0xF89B, 0x9D3E, 0xF89C, 0x9D3F, 0xF89D, 0x9D40, 0xF89E, 0x9D41, 0xF89F, 0x9D42, 0xF8A0, + 0x9D43, 0xF940, 0x9D44, 0xF941, 0x9D45, 0xF942, 0x9D46, 0xF943, 0x9D47, 0xF944, 0x9D48, 0xF945, 0x9D49, 0xF946, 0x9D4A, 0xF947, + 0x9D4B, 0xF948, 0x9D4C, 0xF949, 0x9D4D, 0xF94A, 0x9D4E, 0xF94B, 0x9D4F, 0xF94C, 0x9D50, 0xF94D, 0x9D51, 0xF94E, 0x9D52, 0xF94F, + 0x9D53, 0xF950, 0x9D54, 0xF951, 0x9D55, 0xF952, 0x9D56, 0xF953, 0x9D57, 0xF954, 0x9D58, 0xF955, 0x9D59, 0xF956, 0x9D5A, 0xF957, + 0x9D5B, 0xF958, 0x9D5C, 0xF959, 0x9D5D, 0xF95A, 0x9D5E, 0xF95B, 0x9D5F, 0xF95C, 0x9D60, 0xF95D, 0x9D61, 0xF95E, 0x9D62, 0xF95F, + 0x9D63, 0xF960, 0x9D64, 0xF961, 0x9D65, 0xF962, 0x9D66, 0xF963, 0x9D67, 0xF964, 0x9D68, 0xF965, 0x9D69, 0xF966, 0x9D6A, 0xF967, + 0x9D6B, 0xF968, 0x9D6C, 0xF969, 0x9D6D, 0xF96A, 0x9D6E, 0xF96B, 0x9D6F, 0xF96C, 0x9D70, 0xF96D, 0x9D71, 0xF96E, 0x9D72, 0xF96F, + 0x9D73, 0xF970, 0x9D74, 0xF971, 0x9D75, 0xF972, 0x9D76, 0xF973, 0x9D77, 0xF974, 0x9D78, 0xF975, 0x9D79, 0xF976, 0x9D7A, 0xF977, + 0x9D7B, 0xF978, 0x9D7C, 0xF979, 0x9D7D, 0xF97A, 0x9D7E, 0xF97B, 0x9D7F, 0xF97C, 0x9D80, 0xF97D, 0x9D81, 0xF97E, 0x9D82, 0xF980, + 0x9D83, 0xF981, 0x9D84, 0xF982, 0x9D85, 0xF983, 0x9D86, 0xF984, 0x9D87, 0xF985, 0x9D88, 0xF986, 0x9D89, 0xF987, 0x9D8A, 0xF988, + 0x9D8B, 0xF989, 0x9D8C, 0xF98A, 0x9D8D, 0xF98B, 0x9D8E, 0xF98C, 0x9D8F, 0xF98D, 0x9D90, 0xF98E, 0x9D91, 0xF98F, 0x9D92, 0xF990, + 0x9D93, 0xF991, 0x9D94, 0xF992, 0x9D95, 0xF993, 0x9D96, 0xF994, 0x9D97, 0xF995, 0x9D98, 0xF996, 0x9D99, 0xF997, 0x9D9A, 0xF998, + 0x9D9B, 0xF999, 0x9D9C, 0xF99A, 0x9D9D, 0xF99B, 0x9D9E, 0xF99C, 0x9D9F, 0xF99D, 0x9DA0, 0xF99E, 0x9DA1, 0xF99F, 0x9DA2, 0xF9A0, + 0x9DA3, 0xFA40, 0x9DA4, 0xFA41, 0x9DA5, 0xFA42, 0x9DA6, 0xFA43, 0x9DA7, 0xFA44, 0x9DA8, 0xFA45, 0x9DA9, 0xFA46, 0x9DAA, 0xFA47, + 0x9DAB, 0xFA48, 0x9DAC, 0xFA49, 0x9DAD, 0xFA4A, 0x9DAE, 0xFA4B, 0x9DAF, 0xFA4C, 0x9DB0, 0xFA4D, 0x9DB1, 0xFA4E, 0x9DB2, 0xFA4F, + 0x9DB3, 0xFA50, 0x9DB4, 0xFA51, 0x9DB5, 0xFA52, 0x9DB6, 0xFA53, 0x9DB7, 0xFA54, 0x9DB8, 0xFA55, 0x9DB9, 0xFA56, 0x9DBA, 0xFA57, + 0x9DBB, 0xFA58, 0x9DBC, 0xFA59, 0x9DBD, 0xFA5A, 0x9DBE, 0xFA5B, 0x9DBF, 0xFA5C, 0x9DC0, 0xFA5D, 0x9DC1, 0xFA5E, 0x9DC2, 0xFA5F, + 0x9DC3, 0xFA60, 0x9DC4, 0xFA61, 0x9DC5, 0xFA62, 0x9DC6, 0xFA63, 0x9DC7, 0xFA64, 0x9DC8, 0xFA65, 0x9DC9, 0xFA66, 0x9DCA, 0xFA67, + 0x9DCB, 0xFA68, 0x9DCC, 0xFA69, 0x9DCD, 0xFA6A, 0x9DCE, 0xFA6B, 0x9DCF, 0xFA6C, 0x9DD0, 0xFA6D, 0x9DD1, 0xFA6E, 0x9DD2, 0xFA6F, + 0x9DD3, 0xFA70, 0x9DD4, 0xFA71, 0x9DD5, 0xFA72, 0x9DD6, 0xFA73, 0x9DD7, 0xFA74, 0x9DD8, 0xFA75, 0x9DD9, 0xFA76, 0x9DDA, 0xFA77, + 0x9DDB, 0xFA78, 0x9DDC, 0xFA79, 0x9DDD, 0xFA7A, 0x9DDE, 0xFA7B, 0x9DDF, 0xFA7C, 0x9DE0, 0xFA7D, 0x9DE1, 0xFA7E, 0x9DE2, 0xFA80, + 0x9DE3, 0xFA81, 0x9DE4, 0xFA82, 0x9DE5, 0xFA83, 0x9DE6, 0xFA84, 0x9DE7, 0xFA85, 0x9DE8, 0xFA86, 0x9DE9, 0xFA87, 0x9DEA, 0xFA88, + 0x9DEB, 0xFA89, 0x9DEC, 0xFA8A, 0x9DED, 0xFA8B, 0x9DEE, 0xFA8C, 0x9DEF, 0xFA8D, 0x9DF0, 0xFA8E, 0x9DF1, 0xFA8F, 0x9DF2, 0xFA90, + 0x9DF3, 0xFA91, 0x9DF4, 0xFA92, 0x9DF5, 0xFA93, 0x9DF6, 0xFA94, 0x9DF7, 0xFA95, 0x9DF8, 0xFA96, 0x9DF9, 0xFA97, 0x9DFA, 0xFA98, + 0x9DFB, 0xFA99, 0x9DFC, 0xFA9A, 0x9DFD, 0xFA9B, 0x9DFE, 0xFA9C, 0x9DFF, 0xFA9D, 0x9E00, 0xFA9E, 0x9E01, 0xFA9F, 0x9E02, 0xFAA0, + 0x9E03, 0xFB40, 0x9E04, 0xFB41, 0x9E05, 0xFB42, 0x9E06, 0xFB43, 0x9E07, 0xFB44, 0x9E08, 0xFB45, 0x9E09, 0xFB46, 0x9E0A, 0xFB47, + 0x9E0B, 0xFB48, 0x9E0C, 0xFB49, 0x9E0D, 0xFB4A, 0x9E0E, 0xFB4B, 0x9E0F, 0xFB4C, 0x9E10, 0xFB4D, 0x9E11, 0xFB4E, 0x9E12, 0xFB4F, + 0x9E13, 0xFB50, 0x9E14, 0xFB51, 0x9E15, 0xFB52, 0x9E16, 0xFB53, 0x9E17, 0xFB54, 0x9E18, 0xFB55, 0x9E19, 0xFB56, 0x9E1A, 0xFB57, + 0x9E1B, 0xFB58, 0x9E1C, 0xFB59, 0x9E1D, 0xFB5A, 0x9E1E, 0xFB5B, 0x9E1F, 0xC4F1, 0x9E20, 0xF0AF, 0x9E21, 0xBCA6, 0x9E22, 0xF0B0, + 0x9E23, 0xC3F9, 0x9E24, 0xFB5C, 0x9E25, 0xC5B8, 0x9E26, 0xD1BB, 0x9E27, 0xFB5D, 0x9E28, 0xF0B1, 0x9E29, 0xF0B2, 0x9E2A, 0xF0B3, + 0x9E2B, 0xF0B4, 0x9E2C, 0xF0B5, 0x9E2D, 0xD1BC, 0x9E2E, 0xFB5E, 0x9E2F, 0xD1EC, 0x9E30, 0xFB5F, 0x9E31, 0xF0B7, 0x9E32, 0xF0B6, + 0x9E33, 0xD4A7, 0x9E34, 0xFB60, 0x9E35, 0xCDD2, 0x9E36, 0xF0B8, 0x9E37, 0xF0BA, 0x9E38, 0xF0B9, 0x9E39, 0xF0BB, 0x9E3A, 0xF0BC, + 0x9E3B, 0xFB61, 0x9E3C, 0xFB62, 0x9E3D, 0xB8EB, 0x9E3E, 0xF0BD, 0x9E3F, 0xBAE8, 0x9E40, 0xFB63, 0x9E41, 0xF0BE, 0x9E42, 0xF0BF, + 0x9E43, 0xBEE9, 0x9E44, 0xF0C0, 0x9E45, 0xB6EC, 0x9E46, 0xF0C1, 0x9E47, 0xF0C2, 0x9E48, 0xF0C3, 0x9E49, 0xF0C4, 0x9E4A, 0xC8B5, + 0x9E4B, 0xF0C5, 0x9E4C, 0xF0C6, 0x9E4D, 0xFB64, 0x9E4E, 0xF0C7, 0x9E4F, 0xC5F4, 0x9E50, 0xFB65, 0x9E51, 0xF0C8, 0x9E52, 0xFB66, + 0x9E53, 0xFB67, 0x9E54, 0xFB68, 0x9E55, 0xF0C9, 0x9E56, 0xFB69, 0x9E57, 0xF0CA, 0x9E58, 0xF7BD, 0x9E59, 0xFB6A, 0x9E5A, 0xF0CB, + 0x9E5B, 0xF0CC, 0x9E5C, 0xF0CD, 0x9E5D, 0xFB6B, 0x9E5E, 0xF0CE, 0x9E5F, 0xFB6C, 0x9E60, 0xFB6D, 0x9E61, 0xFB6E, 0x9E62, 0xFB6F, + 0x9E63, 0xF0CF, 0x9E64, 0xBAD7, 0x9E65, 0xFB70, 0x9E66, 0xF0D0, 0x9E67, 0xF0D1, 0x9E68, 0xF0D2, 0x9E69, 0xF0D3, 0x9E6A, 0xF0D4, + 0x9E6B, 0xF0D5, 0x9E6C, 0xF0D6, 0x9E6D, 0xF0D8, 0x9E6E, 0xFB71, 0x9E6F, 0xFB72, 0x9E70, 0xD3A5, 0x9E71, 0xF0D7, 0x9E72, 0xFB73, + 0x9E73, 0xF0D9, 0x9E74, 0xFB74, 0x9E75, 0xFB75, 0x9E76, 0xFB76, 0x9E77, 0xFB77, 0x9E78, 0xFB78, 0x9E79, 0xFB79, 0x9E7A, 0xFB7A, + 0x9E7B, 0xFB7B, 0x9E7C, 0xFB7C, 0x9E7D, 0xFB7D, 0x9E7E, 0xF5BA, 0x9E7F, 0xC2B9, 0x9E80, 0xFB7E, 0x9E81, 0xFB80, 0x9E82, 0xF7E4, + 0x9E83, 0xFB81, 0x9E84, 0xFB82, 0x9E85, 0xFB83, 0x9E86, 0xFB84, 0x9E87, 0xF7E5, 0x9E88, 0xF7E6, 0x9E89, 0xFB85, 0x9E8A, 0xFB86, + 0x9E8B, 0xF7E7, 0x9E8C, 0xFB87, 0x9E8D, 0xFB88, 0x9E8E, 0xFB89, 0x9E8F, 0xFB8A, 0x9E90, 0xFB8B, 0x9E91, 0xFB8C, 0x9E92, 0xF7E8, + 0x9E93, 0xC2B4, 0x9E94, 0xFB8D, 0x9E95, 0xFB8E, 0x9E96, 0xFB8F, 0x9E97, 0xFB90, 0x9E98, 0xFB91, 0x9E99, 0xFB92, 0x9E9A, 0xFB93, + 0x9E9B, 0xFB94, 0x9E9C, 0xFB95, 0x9E9D, 0xF7EA, 0x9E9E, 0xFB96, 0x9E9F, 0xF7EB, 0x9EA0, 0xFB97, 0x9EA1, 0xFB98, 0x9EA2, 0xFB99, + 0x9EA3, 0xFB9A, 0x9EA4, 0xFB9B, 0x9EA5, 0xFB9C, 0x9EA6, 0xC2F3, 0x9EA7, 0xFB9D, 0x9EA8, 0xFB9E, 0x9EA9, 0xFB9F, 0x9EAA, 0xFBA0, + 0x9EAB, 0xFC40, 0x9EAC, 0xFC41, 0x9EAD, 0xFC42, 0x9EAE, 0xFC43, 0x9EAF, 0xFC44, 0x9EB0, 0xFC45, 0x9EB1, 0xFC46, 0x9EB2, 0xFC47, + 0x9EB3, 0xFC48, 0x9EB4, 0xF4F0, 0x9EB5, 0xFC49, 0x9EB6, 0xFC4A, 0x9EB7, 0xFC4B, 0x9EB8, 0xF4EF, 0x9EB9, 0xFC4C, 0x9EBA, 0xFC4D, + 0x9EBB, 0xC2E9, 0x9EBC, 0xFC4E, 0x9EBD, 0xF7E1, 0x9EBE, 0xF7E2, 0x9EBF, 0xFC4F, 0x9EC0, 0xFC50, 0x9EC1, 0xFC51, 0x9EC2, 0xFC52, + 0x9EC3, 0xFC53, 0x9EC4, 0xBBC6, 0x9EC5, 0xFC54, 0x9EC6, 0xFC55, 0x9EC7, 0xFC56, 0x9EC8, 0xFC57, 0x9EC9, 0xD9E4, 0x9ECA, 0xFC58, + 0x9ECB, 0xFC59, 0x9ECC, 0xFC5A, 0x9ECD, 0xCAF2, 0x9ECE, 0xC0E8, 0x9ECF, 0xF0A4, 0x9ED0, 0xFC5B, 0x9ED1, 0xBADA, 0x9ED2, 0xFC5C, + 0x9ED3, 0xFC5D, 0x9ED4, 0xC7AD, 0x9ED5, 0xFC5E, 0x9ED6, 0xFC5F, 0x9ED7, 0xFC60, 0x9ED8, 0xC4AC, 0x9ED9, 0xFC61, 0x9EDA, 0xFC62, + 0x9EDB, 0xF7EC, 0x9EDC, 0xF7ED, 0x9EDD, 0xF7EE, 0x9EDE, 0xFC63, 0x9EDF, 0xF7F0, 0x9EE0, 0xF7EF, 0x9EE1, 0xFC64, 0x9EE2, 0xF7F1, + 0x9EE3, 0xFC65, 0x9EE4, 0xFC66, 0x9EE5, 0xF7F4, 0x9EE6, 0xFC67, 0x9EE7, 0xF7F3, 0x9EE8, 0xFC68, 0x9EE9, 0xF7F2, 0x9EEA, 0xF7F5, + 0x9EEB, 0xFC69, 0x9EEC, 0xFC6A, 0x9EED, 0xFC6B, 0x9EEE, 0xFC6C, 0x9EEF, 0xF7F6, 0x9EF0, 0xFC6D, 0x9EF1, 0xFC6E, 0x9EF2, 0xFC6F, + 0x9EF3, 0xFC70, 0x9EF4, 0xFC71, 0x9EF5, 0xFC72, 0x9EF6, 0xFC73, 0x9EF7, 0xFC74, 0x9EF8, 0xFC75, 0x9EF9, 0xEDE9, 0x9EFA, 0xFC76, + 0x9EFB, 0xEDEA, 0x9EFC, 0xEDEB, 0x9EFD, 0xFC77, 0x9EFE, 0xF6BC, 0x9EFF, 0xFC78, 0x9F00, 0xFC79, 0x9F01, 0xFC7A, 0x9F02, 0xFC7B, + 0x9F03, 0xFC7C, 0x9F04, 0xFC7D, 0x9F05, 0xFC7E, 0x9F06, 0xFC80, 0x9F07, 0xFC81, 0x9F08, 0xFC82, 0x9F09, 0xFC83, 0x9F0A, 0xFC84, + 0x9F0B, 0xF6BD, 0x9F0C, 0xFC85, 0x9F0D, 0xF6BE, 0x9F0E, 0xB6A6, 0x9F0F, 0xFC86, 0x9F10, 0xD8BE, 0x9F11, 0xFC87, 0x9F12, 0xFC88, + 0x9F13, 0xB9C4, 0x9F14, 0xFC89, 0x9F15, 0xFC8A, 0x9F16, 0xFC8B, 0x9F17, 0xD8BB, 0x9F18, 0xFC8C, 0x9F19, 0xDCB1, 0x9F1A, 0xFC8D, + 0x9F1B, 0xFC8E, 0x9F1C, 0xFC8F, 0x9F1D, 0xFC90, 0x9F1E, 0xFC91, 0x9F1F, 0xFC92, 0x9F20, 0xCAF3, 0x9F21, 0xFC93, 0x9F22, 0xF7F7, + 0x9F23, 0xFC94, 0x9F24, 0xFC95, 0x9F25, 0xFC96, 0x9F26, 0xFC97, 0x9F27, 0xFC98, 0x9F28, 0xFC99, 0x9F29, 0xFC9A, 0x9F2A, 0xFC9B, + 0x9F2B, 0xFC9C, 0x9F2C, 0xF7F8, 0x9F2D, 0xFC9D, 0x9F2E, 0xFC9E, 0x9F2F, 0xF7F9, 0x9F30, 0xFC9F, 0x9F31, 0xFCA0, 0x9F32, 0xFD40, + 0x9F33, 0xFD41, 0x9F34, 0xFD42, 0x9F35, 0xFD43, 0x9F36, 0xFD44, 0x9F37, 0xF7FB, 0x9F38, 0xFD45, 0x9F39, 0xF7FA, 0x9F3A, 0xFD46, + 0x9F3B, 0xB1C7, 0x9F3C, 0xFD47, 0x9F3D, 0xF7FC, 0x9F3E, 0xF7FD, 0x9F3F, 0xFD48, 0x9F40, 0xFD49, 0x9F41, 0xFD4A, 0x9F42, 0xFD4B, + 0x9F43, 0xFD4C, 0x9F44, 0xF7FE, 0x9F45, 0xFD4D, 0x9F46, 0xFD4E, 0x9F47, 0xFD4F, 0x9F48, 0xFD50, 0x9F49, 0xFD51, 0x9F4A, 0xFD52, + 0x9F4B, 0xFD53, 0x9F4C, 0xFD54, 0x9F4D, 0xFD55, 0x9F4E, 0xFD56, 0x9F4F, 0xFD57, 0x9F50, 0xC6EB, 0x9F51, 0xECB4, 0x9F52, 0xFD58, + 0x9F53, 0xFD59, 0x9F54, 0xFD5A, 0x9F55, 0xFD5B, 0x9F56, 0xFD5C, 0x9F57, 0xFD5D, 0x9F58, 0xFD5E, 0x9F59, 0xFD5F, 0x9F5A, 0xFD60, + 0x9F5B, 0xFD61, 0x9F5C, 0xFD62, 0x9F5D, 0xFD63, 0x9F5E, 0xFD64, 0x9F5F, 0xFD65, 0x9F60, 0xFD66, 0x9F61, 0xFD67, 0x9F62, 0xFD68, + 0x9F63, 0xFD69, 0x9F64, 0xFD6A, 0x9F65, 0xFD6B, 0x9F66, 0xFD6C, 0x9F67, 0xFD6D, 0x9F68, 0xFD6E, 0x9F69, 0xFD6F, 0x9F6A, 0xFD70, + 0x9F6B, 0xFD71, 0x9F6C, 0xFD72, 0x9F6D, 0xFD73, 0x9F6E, 0xFD74, 0x9F6F, 0xFD75, 0x9F70, 0xFD76, 0x9F71, 0xFD77, 0x9F72, 0xFD78, + 0x9F73, 0xFD79, 0x9F74, 0xFD7A, 0x9F75, 0xFD7B, 0x9F76, 0xFD7C, 0x9F77, 0xFD7D, 0x9F78, 0xFD7E, 0x9F79, 0xFD80, 0x9F7A, 0xFD81, + 0x9F7B, 0xFD82, 0x9F7C, 0xFD83, 0x9F7D, 0xFD84, 0x9F7E, 0xFD85, 0x9F7F, 0xB3DD, 0x9F80, 0xF6B3, 0x9F81, 0xFD86, 0x9F82, 0xFD87, + 0x9F83, 0xF6B4, 0x9F84, 0xC1E4, 0x9F85, 0xF6B5, 0x9F86, 0xF6B6, 0x9F87, 0xF6B7, 0x9F88, 0xF6B8, 0x9F89, 0xF6B9, 0x9F8A, 0xF6BA, + 0x9F8B, 0xC8A3, 0x9F8C, 0xF6BB, 0x9F8D, 0xFD88, 0x9F8E, 0xFD89, 0x9F8F, 0xFD8A, 0x9F90, 0xFD8B, 0x9F91, 0xFD8C, 0x9F92, 0xFD8D, + 0x9F93, 0xFD8E, 0x9F94, 0xFD8F, 0x9F95, 0xFD90, 0x9F96, 0xFD91, 0x9F97, 0xFD92, 0x9F98, 0xFD93, 0x9F99, 0xC1FA, 0x9F9A, 0xB9A8, + 0x9F9B, 0xEDE8, 0x9F9C, 0xFD94, 0x9F9D, 0xFD95, 0x9F9E, 0xFD96, 0x9F9F, 0xB9EA, 0x9FA0, 0xD9DF, 0x9FA1, 0xFD97, 0x9FA2, 0xFD98, + 0x9FA3, 0xFD99, 0x9FA4, 0xFD9A, 0x9FA5, 0xFD9B, 0xF92C, 0xFD9C, 0xF979, 0xFD9D, 0xF995, 0xFD9E, 0xF9E7, 0xFD9F, 0xF9F1, 0xFDA0, + 0xFA0C, 0xFE40, 0xFA0D, 0xFE41, 0xFA0E, 0xFE42, 0xFA0F, 0xFE43, 0xFA11, 0xFE44, 0xFA13, 0xFE45, 0xFA14, 0xFE46, 0xFA18, 0xFE47, + 0xFA1F, 0xFE48, 0xFA20, 0xFE49, 0xFA21, 0xFE4A, 0xFA23, 0xFE4B, 0xFA24, 0xFE4C, 0xFA27, 0xFE4D, 0xFA28, 0xFE4E, 0xFA29, 0xFE4F, + 0xFE30, 0xA955, 0xFE31, 0xA6F2, 0xFE33, 0xA6F4, 0xFE34, 0xA6F5, 0xFE35, 0xA6E0, 0xFE36, 0xA6E1, 0xFE37, 0xA6F0, 0xFE38, 0xA6F1, + 0xFE39, 0xA6E2, 0xFE3A, 0xA6E3, 0xFE3B, 0xA6EE, 0xFE3C, 0xA6EF, 0xFE3D, 0xA6E6, 0xFE3E, 0xA6E7, 0xFE3F, 0xA6E4, 0xFE40, 0xA6E5, + 0xFE41, 0xA6E8, 0xFE42, 0xA6E9, 0xFE43, 0xA6EA, 0xFE44, 0xA6EB, 0xFE49, 0xA968, 0xFE4A, 0xA969, 0xFE4B, 0xA96A, 0xFE4C, 0xA96B, + 0xFE4D, 0xA96C, 0xFE4E, 0xA96D, 0xFE4F, 0xA96E, 0xFE50, 0xA96F, 0xFE51, 0xA970, 0xFE52, 0xA971, 0xFE54, 0xA972, 0xFE55, 0xA973, + 0xFE56, 0xA974, 0xFE57, 0xA975, 0xFE59, 0xA976, 0xFE5A, 0xA977, 0xFE5B, 0xA978, 0xFE5C, 0xA979, 0xFE5D, 0xA97A, 0xFE5E, 0xA97B, + 0xFE5F, 0xA97C, 0xFE60, 0xA97D, 0xFE61, 0xA97E, 0xFE62, 0xA980, 0xFE63, 0xA981, 0xFE64, 0xA982, 0xFE65, 0xA983, 0xFE66, 0xA984, + 0xFE68, 0xA985, 0xFE69, 0xA986, 0xFE6A, 0xA987, 0xFE6B, 0xA988, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA1E7, + 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, + 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, + 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, + 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, + 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, + 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, + 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA3DC, + 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, + 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, + 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, + 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, + 0xFF5D, 0xA3FD, 0xFF5E, 0xA1AB, 0xFFE0, 0xA1E9, 0xFFE1, 0xA1EA, 0xFFE2, 0xA956, 0xFFE3, 0xA3FE, 0xFFE4, 0xA957, 0xFFE5, 0xA3A4, + 0, 0 +}; + +static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ + 0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17, + 0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F, + 0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42, + 0x8157, 0x4E44, 0x8158, 0x4E46, 0x8159, 0x4E4A, 0x815A, 0x4E51, 0x815B, 0x4E55, 0x815C, 0x4E57, 0x815D, 0x4E5A, 0x815E, 0x4E5B, + 0x815F, 0x4E62, 0x8160, 0x4E63, 0x8161, 0x4E64, 0x8162, 0x4E65, 0x8163, 0x4E67, 0x8164, 0x4E68, 0x8165, 0x4E6A, 0x8166, 0x4E6B, + 0x8167, 0x4E6C, 0x8168, 0x4E6D, 0x8169, 0x4E6E, 0x816A, 0x4E6F, 0x816B, 0x4E72, 0x816C, 0x4E74, 0x816D, 0x4E75, 0x816E, 0x4E76, + 0x816F, 0x4E77, 0x8170, 0x4E78, 0x8171, 0x4E79, 0x8172, 0x4E7A, 0x8173, 0x4E7B, 0x8174, 0x4E7C, 0x8175, 0x4E7D, 0x8176, 0x4E7F, + 0x8177, 0x4E80, 0x8178, 0x4E81, 0x8179, 0x4E82, 0x817A, 0x4E83, 0x817B, 0x4E84, 0x817C, 0x4E85, 0x817D, 0x4E87, 0x817E, 0x4E8A, + 0x8180, 0x4E90, 0x8181, 0x4E96, 0x8182, 0x4E97, 0x8183, 0x4E99, 0x8184, 0x4E9C, 0x8185, 0x4E9D, 0x8186, 0x4E9E, 0x8187, 0x4EA3, + 0x8188, 0x4EAA, 0x8189, 0x4EAF, 0x818A, 0x4EB0, 0x818B, 0x4EB1, 0x818C, 0x4EB4, 0x818D, 0x4EB6, 0x818E, 0x4EB7, 0x818F, 0x4EB8, + 0x8190, 0x4EB9, 0x8191, 0x4EBC, 0x8192, 0x4EBD, 0x8193, 0x4EBE, 0x8194, 0x4EC8, 0x8195, 0x4ECC, 0x8196, 0x4ECF, 0x8197, 0x4ED0, + 0x8198, 0x4ED2, 0x8199, 0x4EDA, 0x819A, 0x4EDB, 0x819B, 0x4EDC, 0x819C, 0x4EE0, 0x819D, 0x4EE2, 0x819E, 0x4EE6, 0x819F, 0x4EE7, + 0x81A0, 0x4EE9, 0x81A1, 0x4EED, 0x81A2, 0x4EEE, 0x81A3, 0x4EEF, 0x81A4, 0x4EF1, 0x81A5, 0x4EF4, 0x81A6, 0x4EF8, 0x81A7, 0x4EF9, + 0x81A8, 0x4EFA, 0x81A9, 0x4EFC, 0x81AA, 0x4EFE, 0x81AB, 0x4F00, 0x81AC, 0x4F02, 0x81AD, 0x4F03, 0x81AE, 0x4F04, 0x81AF, 0x4F05, + 0x81B0, 0x4F06, 0x81B1, 0x4F07, 0x81B2, 0x4F08, 0x81B3, 0x4F0B, 0x81B4, 0x4F0C, 0x81B5, 0x4F12, 0x81B6, 0x4F13, 0x81B7, 0x4F14, + 0x81B8, 0x4F15, 0x81B9, 0x4F16, 0x81BA, 0x4F1C, 0x81BB, 0x4F1D, 0x81BC, 0x4F21, 0x81BD, 0x4F23, 0x81BE, 0x4F28, 0x81BF, 0x4F29, + 0x81C0, 0x4F2C, 0x81C1, 0x4F2D, 0x81C2, 0x4F2E, 0x81C3, 0x4F31, 0x81C4, 0x4F33, 0x81C5, 0x4F35, 0x81C6, 0x4F37, 0x81C7, 0x4F39, + 0x81C8, 0x4F3B, 0x81C9, 0x4F3E, 0x81CA, 0x4F3F, 0x81CB, 0x4F40, 0x81CC, 0x4F41, 0x81CD, 0x4F42, 0x81CE, 0x4F44, 0x81CF, 0x4F45, + 0x81D0, 0x4F47, 0x81D1, 0x4F48, 0x81D2, 0x4F49, 0x81D3, 0x4F4A, 0x81D4, 0x4F4B, 0x81D5, 0x4F4C, 0x81D6, 0x4F52, 0x81D7, 0x4F54, + 0x81D8, 0x4F56, 0x81D9, 0x4F61, 0x81DA, 0x4F62, 0x81DB, 0x4F66, 0x81DC, 0x4F68, 0x81DD, 0x4F6A, 0x81DE, 0x4F6B, 0x81DF, 0x4F6D, + 0x81E0, 0x4F6E, 0x81E1, 0x4F71, 0x81E2, 0x4F72, 0x81E3, 0x4F75, 0x81E4, 0x4F77, 0x81E5, 0x4F78, 0x81E6, 0x4F79, 0x81E7, 0x4F7A, + 0x81E8, 0x4F7D, 0x81E9, 0x4F80, 0x81EA, 0x4F81, 0x81EB, 0x4F82, 0x81EC, 0x4F85, 0x81ED, 0x4F86, 0x81EE, 0x4F87, 0x81EF, 0x4F8A, + 0x81F0, 0x4F8C, 0x81F1, 0x4F8E, 0x81F2, 0x4F90, 0x81F3, 0x4F92, 0x81F4, 0x4F93, 0x81F5, 0x4F95, 0x81F6, 0x4F96, 0x81F7, 0x4F98, + 0x81F8, 0x4F99, 0x81F9, 0x4F9A, 0x81FA, 0x4F9C, 0x81FB, 0x4F9E, 0x81FC, 0x4F9F, 0x81FD, 0x4FA1, 0x81FE, 0x4FA2, 0x8240, 0x4FA4, + 0x8241, 0x4FAB, 0x8242, 0x4FAD, 0x8243, 0x4FB0, 0x8244, 0x4FB1, 0x8245, 0x4FB2, 0x8246, 0x4FB3, 0x8247, 0x4FB4, 0x8248, 0x4FB6, + 0x8249, 0x4FB7, 0x824A, 0x4FB8, 0x824B, 0x4FB9, 0x824C, 0x4FBA, 0x824D, 0x4FBB, 0x824E, 0x4FBC, 0x824F, 0x4FBD, 0x8250, 0x4FBE, + 0x8251, 0x4FC0, 0x8252, 0x4FC1, 0x8253, 0x4FC2, 0x8254, 0x4FC6, 0x8255, 0x4FC7, 0x8256, 0x4FC8, 0x8257, 0x4FC9, 0x8258, 0x4FCB, + 0x8259, 0x4FCC, 0x825A, 0x4FCD, 0x825B, 0x4FD2, 0x825C, 0x4FD3, 0x825D, 0x4FD4, 0x825E, 0x4FD5, 0x825F, 0x4FD6, 0x8260, 0x4FD9, + 0x8261, 0x4FDB, 0x8262, 0x4FE0, 0x8263, 0x4FE2, 0x8264, 0x4FE4, 0x8265, 0x4FE5, 0x8266, 0x4FE7, 0x8267, 0x4FEB, 0x8268, 0x4FEC, + 0x8269, 0x4FF0, 0x826A, 0x4FF2, 0x826B, 0x4FF4, 0x826C, 0x4FF5, 0x826D, 0x4FF6, 0x826E, 0x4FF7, 0x826F, 0x4FF9, 0x8270, 0x4FFB, + 0x8271, 0x4FFC, 0x8272, 0x4FFD, 0x8273, 0x4FFF, 0x8274, 0x5000, 0x8275, 0x5001, 0x8276, 0x5002, 0x8277, 0x5003, 0x8278, 0x5004, + 0x8279, 0x5005, 0x827A, 0x5006, 0x827B, 0x5007, 0x827C, 0x5008, 0x827D, 0x5009, 0x827E, 0x500A, 0x8280, 0x500B, 0x8281, 0x500E, + 0x8282, 0x5010, 0x8283, 0x5011, 0x8284, 0x5013, 0x8285, 0x5015, 0x8286, 0x5016, 0x8287, 0x5017, 0x8288, 0x501B, 0x8289, 0x501D, + 0x828A, 0x501E, 0x828B, 0x5020, 0x828C, 0x5022, 0x828D, 0x5023, 0x828E, 0x5024, 0x828F, 0x5027, 0x8290, 0x502B, 0x8291, 0x502F, + 0x8292, 0x5030, 0x8293, 0x5031, 0x8294, 0x5032, 0x8295, 0x5033, 0x8296, 0x5034, 0x8297, 0x5035, 0x8298, 0x5036, 0x8299, 0x5037, + 0x829A, 0x5038, 0x829B, 0x5039, 0x829C, 0x503B, 0x829D, 0x503D, 0x829E, 0x503F, 0x829F, 0x5040, 0x82A0, 0x5041, 0x82A1, 0x5042, + 0x82A2, 0x5044, 0x82A3, 0x5045, 0x82A4, 0x5046, 0x82A5, 0x5049, 0x82A6, 0x504A, 0x82A7, 0x504B, 0x82A8, 0x504D, 0x82A9, 0x5050, + 0x82AA, 0x5051, 0x82AB, 0x5052, 0x82AC, 0x5053, 0x82AD, 0x5054, 0x82AE, 0x5056, 0x82AF, 0x5057, 0x82B0, 0x5058, 0x82B1, 0x5059, + 0x82B2, 0x505B, 0x82B3, 0x505D, 0x82B4, 0x505E, 0x82B5, 0x505F, 0x82B6, 0x5060, 0x82B7, 0x5061, 0x82B8, 0x5062, 0x82B9, 0x5063, + 0x82BA, 0x5064, 0x82BB, 0x5066, 0x82BC, 0x5067, 0x82BD, 0x5068, 0x82BE, 0x5069, 0x82BF, 0x506A, 0x82C0, 0x506B, 0x82C1, 0x506D, + 0x82C2, 0x506E, 0x82C3, 0x506F, 0x82C4, 0x5070, 0x82C5, 0x5071, 0x82C6, 0x5072, 0x82C7, 0x5073, 0x82C8, 0x5074, 0x82C9, 0x5075, + 0x82CA, 0x5078, 0x82CB, 0x5079, 0x82CC, 0x507A, 0x82CD, 0x507C, 0x82CE, 0x507D, 0x82CF, 0x5081, 0x82D0, 0x5082, 0x82D1, 0x5083, + 0x82D2, 0x5084, 0x82D3, 0x5086, 0x82D4, 0x5087, 0x82D5, 0x5089, 0x82D6, 0x508A, 0x82D7, 0x508B, 0x82D8, 0x508C, 0x82D9, 0x508E, + 0x82DA, 0x508F, 0x82DB, 0x5090, 0x82DC, 0x5091, 0x82DD, 0x5092, 0x82DE, 0x5093, 0x82DF, 0x5094, 0x82E0, 0x5095, 0x82E1, 0x5096, + 0x82E2, 0x5097, 0x82E3, 0x5098, 0x82E4, 0x5099, 0x82E5, 0x509A, 0x82E6, 0x509B, 0x82E7, 0x509C, 0x82E8, 0x509D, 0x82E9, 0x509E, + 0x82EA, 0x509F, 0x82EB, 0x50A0, 0x82EC, 0x50A1, 0x82ED, 0x50A2, 0x82EE, 0x50A4, 0x82EF, 0x50A6, 0x82F0, 0x50AA, 0x82F1, 0x50AB, + 0x82F2, 0x50AD, 0x82F3, 0x50AE, 0x82F4, 0x50AF, 0x82F5, 0x50B0, 0x82F6, 0x50B1, 0x82F7, 0x50B3, 0x82F8, 0x50B4, 0x82F9, 0x50B5, + 0x82FA, 0x50B6, 0x82FB, 0x50B7, 0x82FC, 0x50B8, 0x82FD, 0x50B9, 0x82FE, 0x50BC, 0x8340, 0x50BD, 0x8341, 0x50BE, 0x8342, 0x50BF, + 0x8343, 0x50C0, 0x8344, 0x50C1, 0x8345, 0x50C2, 0x8346, 0x50C3, 0x8347, 0x50C4, 0x8348, 0x50C5, 0x8349, 0x50C6, 0x834A, 0x50C7, + 0x834B, 0x50C8, 0x834C, 0x50C9, 0x834D, 0x50CA, 0x834E, 0x50CB, 0x834F, 0x50CC, 0x8350, 0x50CD, 0x8351, 0x50CE, 0x8352, 0x50D0, + 0x8353, 0x50D1, 0x8354, 0x50D2, 0x8355, 0x50D3, 0x8356, 0x50D4, 0x8357, 0x50D5, 0x8358, 0x50D7, 0x8359, 0x50D8, 0x835A, 0x50D9, + 0x835B, 0x50DB, 0x835C, 0x50DC, 0x835D, 0x50DD, 0x835E, 0x50DE, 0x835F, 0x50DF, 0x8360, 0x50E0, 0x8361, 0x50E1, 0x8362, 0x50E2, + 0x8363, 0x50E3, 0x8364, 0x50E4, 0x8365, 0x50E5, 0x8366, 0x50E8, 0x8367, 0x50E9, 0x8368, 0x50EA, 0x8369, 0x50EB, 0x836A, 0x50EF, + 0x836B, 0x50F0, 0x836C, 0x50F1, 0x836D, 0x50F2, 0x836E, 0x50F4, 0x836F, 0x50F6, 0x8370, 0x50F7, 0x8371, 0x50F8, 0x8372, 0x50F9, + 0x8373, 0x50FA, 0x8374, 0x50FC, 0x8375, 0x50FD, 0x8376, 0x50FE, 0x8377, 0x50FF, 0x8378, 0x5100, 0x8379, 0x5101, 0x837A, 0x5102, + 0x837B, 0x5103, 0x837C, 0x5104, 0x837D, 0x5105, 0x837E, 0x5108, 0x8380, 0x5109, 0x8381, 0x510A, 0x8382, 0x510C, 0x8383, 0x510D, + 0x8384, 0x510E, 0x8385, 0x510F, 0x8386, 0x5110, 0x8387, 0x5111, 0x8388, 0x5113, 0x8389, 0x5114, 0x838A, 0x5115, 0x838B, 0x5116, + 0x838C, 0x5117, 0x838D, 0x5118, 0x838E, 0x5119, 0x838F, 0x511A, 0x8390, 0x511B, 0x8391, 0x511C, 0x8392, 0x511D, 0x8393, 0x511E, + 0x8394, 0x511F, 0x8395, 0x5120, 0x8396, 0x5122, 0x8397, 0x5123, 0x8398, 0x5124, 0x8399, 0x5125, 0x839A, 0x5126, 0x839B, 0x5127, + 0x839C, 0x5128, 0x839D, 0x5129, 0x839E, 0x512A, 0x839F, 0x512B, 0x83A0, 0x512C, 0x83A1, 0x512D, 0x83A2, 0x512E, 0x83A3, 0x512F, + 0x83A4, 0x5130, 0x83A5, 0x5131, 0x83A6, 0x5132, 0x83A7, 0x5133, 0x83A8, 0x5134, 0x83A9, 0x5135, 0x83AA, 0x5136, 0x83AB, 0x5137, + 0x83AC, 0x5138, 0x83AD, 0x5139, 0x83AE, 0x513A, 0x83AF, 0x513B, 0x83B0, 0x513C, 0x83B1, 0x513D, 0x83B2, 0x513E, 0x83B3, 0x5142, + 0x83B4, 0x5147, 0x83B5, 0x514A, 0x83B6, 0x514C, 0x83B7, 0x514E, 0x83B8, 0x514F, 0x83B9, 0x5150, 0x83BA, 0x5152, 0x83BB, 0x5153, + 0x83BC, 0x5157, 0x83BD, 0x5158, 0x83BE, 0x5159, 0x83BF, 0x515B, 0x83C0, 0x515D, 0x83C1, 0x515E, 0x83C2, 0x515F, 0x83C3, 0x5160, + 0x83C4, 0x5161, 0x83C5, 0x5163, 0x83C6, 0x5164, 0x83C7, 0x5166, 0x83C8, 0x5167, 0x83C9, 0x5169, 0x83CA, 0x516A, 0x83CB, 0x516F, + 0x83CC, 0x5172, 0x83CD, 0x517A, 0x83CE, 0x517E, 0x83CF, 0x517F, 0x83D0, 0x5183, 0x83D1, 0x5184, 0x83D2, 0x5186, 0x83D3, 0x5187, + 0x83D4, 0x518A, 0x83D5, 0x518B, 0x83D6, 0x518E, 0x83D7, 0x518F, 0x83D8, 0x5190, 0x83D9, 0x5191, 0x83DA, 0x5193, 0x83DB, 0x5194, + 0x83DC, 0x5198, 0x83DD, 0x519A, 0x83DE, 0x519D, 0x83DF, 0x519E, 0x83E0, 0x519F, 0x83E1, 0x51A1, 0x83E2, 0x51A3, 0x83E3, 0x51A6, + 0x83E4, 0x51A7, 0x83E5, 0x51A8, 0x83E6, 0x51A9, 0x83E7, 0x51AA, 0x83E8, 0x51AD, 0x83E9, 0x51AE, 0x83EA, 0x51B4, 0x83EB, 0x51B8, + 0x83EC, 0x51B9, 0x83ED, 0x51BA, 0x83EE, 0x51BE, 0x83EF, 0x51BF, 0x83F0, 0x51C1, 0x83F1, 0x51C2, 0x83F2, 0x51C3, 0x83F3, 0x51C5, + 0x83F4, 0x51C8, 0x83F5, 0x51CA, 0x83F6, 0x51CD, 0x83F7, 0x51CE, 0x83F8, 0x51D0, 0x83F9, 0x51D2, 0x83FA, 0x51D3, 0x83FB, 0x51D4, + 0x83FC, 0x51D5, 0x83FD, 0x51D6, 0x83FE, 0x51D7, 0x8440, 0x51D8, 0x8441, 0x51D9, 0x8442, 0x51DA, 0x8443, 0x51DC, 0x8444, 0x51DE, + 0x8445, 0x51DF, 0x8446, 0x51E2, 0x8447, 0x51E3, 0x8448, 0x51E5, 0x8449, 0x51E6, 0x844A, 0x51E7, 0x844B, 0x51E8, 0x844C, 0x51E9, + 0x844D, 0x51EA, 0x844E, 0x51EC, 0x844F, 0x51EE, 0x8450, 0x51F1, 0x8451, 0x51F2, 0x8452, 0x51F4, 0x8453, 0x51F7, 0x8454, 0x51FE, + 0x8455, 0x5204, 0x8456, 0x5205, 0x8457, 0x5209, 0x8458, 0x520B, 0x8459, 0x520C, 0x845A, 0x520F, 0x845B, 0x5210, 0x845C, 0x5213, + 0x845D, 0x5214, 0x845E, 0x5215, 0x845F, 0x521C, 0x8460, 0x521E, 0x8461, 0x521F, 0x8462, 0x5221, 0x8463, 0x5222, 0x8464, 0x5223, + 0x8465, 0x5225, 0x8466, 0x5226, 0x8467, 0x5227, 0x8468, 0x522A, 0x8469, 0x522C, 0x846A, 0x522F, 0x846B, 0x5231, 0x846C, 0x5232, + 0x846D, 0x5234, 0x846E, 0x5235, 0x846F, 0x523C, 0x8470, 0x523E, 0x8471, 0x5244, 0x8472, 0x5245, 0x8473, 0x5246, 0x8474, 0x5247, + 0x8475, 0x5248, 0x8476, 0x5249, 0x8477, 0x524B, 0x8478, 0x524E, 0x8479, 0x524F, 0x847A, 0x5252, 0x847B, 0x5253, 0x847C, 0x5255, + 0x847D, 0x5257, 0x847E, 0x5258, 0x8480, 0x5259, 0x8481, 0x525A, 0x8482, 0x525B, 0x8483, 0x525D, 0x8484, 0x525F, 0x8485, 0x5260, + 0x8486, 0x5262, 0x8487, 0x5263, 0x8488, 0x5264, 0x8489, 0x5266, 0x848A, 0x5268, 0x848B, 0x526B, 0x848C, 0x526C, 0x848D, 0x526D, + 0x848E, 0x526E, 0x848F, 0x5270, 0x8490, 0x5271, 0x8491, 0x5273, 0x8492, 0x5274, 0x8493, 0x5275, 0x8494, 0x5276, 0x8495, 0x5277, + 0x8496, 0x5278, 0x8497, 0x5279, 0x8498, 0x527A, 0x8499, 0x527B, 0x849A, 0x527C, 0x849B, 0x527E, 0x849C, 0x5280, 0x849D, 0x5283, + 0x849E, 0x5284, 0x849F, 0x5285, 0x84A0, 0x5286, 0x84A1, 0x5287, 0x84A2, 0x5289, 0x84A3, 0x528A, 0x84A4, 0x528B, 0x84A5, 0x528C, + 0x84A6, 0x528D, 0x84A7, 0x528E, 0x84A8, 0x528F, 0x84A9, 0x5291, 0x84AA, 0x5292, 0x84AB, 0x5294, 0x84AC, 0x5295, 0x84AD, 0x5296, + 0x84AE, 0x5297, 0x84AF, 0x5298, 0x84B0, 0x5299, 0x84B1, 0x529A, 0x84B2, 0x529C, 0x84B3, 0x52A4, 0x84B4, 0x52A5, 0x84B5, 0x52A6, + 0x84B6, 0x52A7, 0x84B7, 0x52AE, 0x84B8, 0x52AF, 0x84B9, 0x52B0, 0x84BA, 0x52B4, 0x84BB, 0x52B5, 0x84BC, 0x52B6, 0x84BD, 0x52B7, + 0x84BE, 0x52B8, 0x84BF, 0x52B9, 0x84C0, 0x52BA, 0x84C1, 0x52BB, 0x84C2, 0x52BC, 0x84C3, 0x52BD, 0x84C4, 0x52C0, 0x84C5, 0x52C1, + 0x84C6, 0x52C2, 0x84C7, 0x52C4, 0x84C8, 0x52C5, 0x84C9, 0x52C6, 0x84CA, 0x52C8, 0x84CB, 0x52CA, 0x84CC, 0x52CC, 0x84CD, 0x52CD, + 0x84CE, 0x52CE, 0x84CF, 0x52CF, 0x84D0, 0x52D1, 0x84D1, 0x52D3, 0x84D2, 0x52D4, 0x84D3, 0x52D5, 0x84D4, 0x52D7, 0x84D5, 0x52D9, + 0x84D6, 0x52DA, 0x84D7, 0x52DB, 0x84D8, 0x52DC, 0x84D9, 0x52DD, 0x84DA, 0x52DE, 0x84DB, 0x52E0, 0x84DC, 0x52E1, 0x84DD, 0x52E2, + 0x84DE, 0x52E3, 0x84DF, 0x52E5, 0x84E0, 0x52E6, 0x84E1, 0x52E7, 0x84E2, 0x52E8, 0x84E3, 0x52E9, 0x84E4, 0x52EA, 0x84E5, 0x52EB, + 0x84E6, 0x52EC, 0x84E7, 0x52ED, 0x84E8, 0x52EE, 0x84E9, 0x52EF, 0x84EA, 0x52F1, 0x84EB, 0x52F2, 0x84EC, 0x52F3, 0x84ED, 0x52F4, + 0x84EE, 0x52F5, 0x84EF, 0x52F6, 0x84F0, 0x52F7, 0x84F1, 0x52F8, 0x84F2, 0x52FB, 0x84F3, 0x52FC, 0x84F4, 0x52FD, 0x84F5, 0x5301, + 0x84F6, 0x5302, 0x84F7, 0x5303, 0x84F8, 0x5304, 0x84F9, 0x5307, 0x84FA, 0x5309, 0x84FB, 0x530A, 0x84FC, 0x530B, 0x84FD, 0x530C, + 0x84FE, 0x530E, 0x8540, 0x5311, 0x8541, 0x5312, 0x8542, 0x5313, 0x8543, 0x5314, 0x8544, 0x5318, 0x8545, 0x531B, 0x8546, 0x531C, + 0x8547, 0x531E, 0x8548, 0x531F, 0x8549, 0x5322, 0x854A, 0x5324, 0x854B, 0x5325, 0x854C, 0x5327, 0x854D, 0x5328, 0x854E, 0x5329, + 0x854F, 0x532B, 0x8550, 0x532C, 0x8551, 0x532D, 0x8552, 0x532F, 0x8553, 0x5330, 0x8554, 0x5331, 0x8555, 0x5332, 0x8556, 0x5333, + 0x8557, 0x5334, 0x8558, 0x5335, 0x8559, 0x5336, 0x855A, 0x5337, 0x855B, 0x5338, 0x855C, 0x533C, 0x855D, 0x533D, 0x855E, 0x5340, + 0x855F, 0x5342, 0x8560, 0x5344, 0x8561, 0x5346, 0x8562, 0x534B, 0x8563, 0x534C, 0x8564, 0x534D, 0x8565, 0x5350, 0x8566, 0x5354, + 0x8567, 0x5358, 0x8568, 0x5359, 0x8569, 0x535B, 0x856A, 0x535D, 0x856B, 0x5365, 0x856C, 0x5368, 0x856D, 0x536A, 0x856E, 0x536C, + 0x856F, 0x536D, 0x8570, 0x5372, 0x8571, 0x5376, 0x8572, 0x5379, 0x8573, 0x537B, 0x8574, 0x537C, 0x8575, 0x537D, 0x8576, 0x537E, + 0x8577, 0x5380, 0x8578, 0x5381, 0x8579, 0x5383, 0x857A, 0x5387, 0x857B, 0x5388, 0x857C, 0x538A, 0x857D, 0x538E, 0x857E, 0x538F, + 0x8580, 0x5390, 0x8581, 0x5391, 0x8582, 0x5392, 0x8583, 0x5393, 0x8584, 0x5394, 0x8585, 0x5396, 0x8586, 0x5397, 0x8587, 0x5399, + 0x8588, 0x539B, 0x8589, 0x539C, 0x858A, 0x539E, 0x858B, 0x53A0, 0x858C, 0x53A1, 0x858D, 0x53A4, 0x858E, 0x53A7, 0x858F, 0x53AA, + 0x8590, 0x53AB, 0x8591, 0x53AC, 0x8592, 0x53AD, 0x8593, 0x53AF, 0x8594, 0x53B0, 0x8595, 0x53B1, 0x8596, 0x53B2, 0x8597, 0x53B3, + 0x8598, 0x53B4, 0x8599, 0x53B5, 0x859A, 0x53B7, 0x859B, 0x53B8, 0x859C, 0x53B9, 0x859D, 0x53BA, 0x859E, 0x53BC, 0x859F, 0x53BD, + 0x85A0, 0x53BE, 0x85A1, 0x53C0, 0x85A2, 0x53C3, 0x85A3, 0x53C4, 0x85A4, 0x53C5, 0x85A5, 0x53C6, 0x85A6, 0x53C7, 0x85A7, 0x53CE, + 0x85A8, 0x53CF, 0x85A9, 0x53D0, 0x85AA, 0x53D2, 0x85AB, 0x53D3, 0x85AC, 0x53D5, 0x85AD, 0x53DA, 0x85AE, 0x53DC, 0x85AF, 0x53DD, + 0x85B0, 0x53DE, 0x85B1, 0x53E1, 0x85B2, 0x53E2, 0x85B3, 0x53E7, 0x85B4, 0x53F4, 0x85B5, 0x53FA, 0x85B6, 0x53FE, 0x85B7, 0x53FF, + 0x85B8, 0x5400, 0x85B9, 0x5402, 0x85BA, 0x5405, 0x85BB, 0x5407, 0x85BC, 0x540B, 0x85BD, 0x5414, 0x85BE, 0x5418, 0x85BF, 0x5419, + 0x85C0, 0x541A, 0x85C1, 0x541C, 0x85C2, 0x5422, 0x85C3, 0x5424, 0x85C4, 0x5425, 0x85C5, 0x542A, 0x85C6, 0x5430, 0x85C7, 0x5433, + 0x85C8, 0x5436, 0x85C9, 0x5437, 0x85CA, 0x543A, 0x85CB, 0x543D, 0x85CC, 0x543F, 0x85CD, 0x5441, 0x85CE, 0x5442, 0x85CF, 0x5444, + 0x85D0, 0x5445, 0x85D1, 0x5447, 0x85D2, 0x5449, 0x85D3, 0x544C, 0x85D4, 0x544D, 0x85D5, 0x544E, 0x85D6, 0x544F, 0x85D7, 0x5451, + 0x85D8, 0x545A, 0x85D9, 0x545D, 0x85DA, 0x545E, 0x85DB, 0x545F, 0x85DC, 0x5460, 0x85DD, 0x5461, 0x85DE, 0x5463, 0x85DF, 0x5465, + 0x85E0, 0x5467, 0x85E1, 0x5469, 0x85E2, 0x546A, 0x85E3, 0x546B, 0x85E4, 0x546C, 0x85E5, 0x546D, 0x85E6, 0x546E, 0x85E7, 0x546F, + 0x85E8, 0x5470, 0x85E9, 0x5474, 0x85EA, 0x5479, 0x85EB, 0x547A, 0x85EC, 0x547E, 0x85ED, 0x547F, 0x85EE, 0x5481, 0x85EF, 0x5483, + 0x85F0, 0x5485, 0x85F1, 0x5487, 0x85F2, 0x5488, 0x85F3, 0x5489, 0x85F4, 0x548A, 0x85F5, 0x548D, 0x85F6, 0x5491, 0x85F7, 0x5493, + 0x85F8, 0x5497, 0x85F9, 0x5498, 0x85FA, 0x549C, 0x85FB, 0x549E, 0x85FC, 0x549F, 0x85FD, 0x54A0, 0x85FE, 0x54A1, 0x8640, 0x54A2, + 0x8641, 0x54A5, 0x8642, 0x54AE, 0x8643, 0x54B0, 0x8644, 0x54B2, 0x8645, 0x54B5, 0x8646, 0x54B6, 0x8647, 0x54B7, 0x8648, 0x54B9, + 0x8649, 0x54BA, 0x864A, 0x54BC, 0x864B, 0x54BE, 0x864C, 0x54C3, 0x864D, 0x54C5, 0x864E, 0x54CA, 0x864F, 0x54CB, 0x8650, 0x54D6, + 0x8651, 0x54D8, 0x8652, 0x54DB, 0x8653, 0x54E0, 0x8654, 0x54E1, 0x8655, 0x54E2, 0x8656, 0x54E3, 0x8657, 0x54E4, 0x8658, 0x54EB, + 0x8659, 0x54EC, 0x865A, 0x54EF, 0x865B, 0x54F0, 0x865C, 0x54F1, 0x865D, 0x54F4, 0x865E, 0x54F5, 0x865F, 0x54F6, 0x8660, 0x54F7, + 0x8661, 0x54F8, 0x8662, 0x54F9, 0x8663, 0x54FB, 0x8664, 0x54FE, 0x8665, 0x5500, 0x8666, 0x5502, 0x8667, 0x5503, 0x8668, 0x5504, + 0x8669, 0x5505, 0x866A, 0x5508, 0x866B, 0x550A, 0x866C, 0x550B, 0x866D, 0x550C, 0x866E, 0x550D, 0x866F, 0x550E, 0x8670, 0x5512, + 0x8671, 0x5513, 0x8672, 0x5515, 0x8673, 0x5516, 0x8674, 0x5517, 0x8675, 0x5518, 0x8676, 0x5519, 0x8677, 0x551A, 0x8678, 0x551C, + 0x8679, 0x551D, 0x867A, 0x551E, 0x867B, 0x551F, 0x867C, 0x5521, 0x867D, 0x5525, 0x867E, 0x5526, 0x8680, 0x5528, 0x8681, 0x5529, + 0x8682, 0x552B, 0x8683, 0x552D, 0x8684, 0x5532, 0x8685, 0x5534, 0x8686, 0x5535, 0x8687, 0x5536, 0x8688, 0x5538, 0x8689, 0x5539, + 0x868A, 0x553A, 0x868B, 0x553B, 0x868C, 0x553D, 0x868D, 0x5540, 0x868E, 0x5542, 0x868F, 0x5545, 0x8690, 0x5547, 0x8691, 0x5548, + 0x8692, 0x554B, 0x8693, 0x554C, 0x8694, 0x554D, 0x8695, 0x554E, 0x8696, 0x554F, 0x8697, 0x5551, 0x8698, 0x5552, 0x8699, 0x5553, + 0x869A, 0x5554, 0x869B, 0x5557, 0x869C, 0x5558, 0x869D, 0x5559, 0x869E, 0x555A, 0x869F, 0x555B, 0x86A0, 0x555D, 0x86A1, 0x555E, + 0x86A2, 0x555F, 0x86A3, 0x5560, 0x86A4, 0x5562, 0x86A5, 0x5563, 0x86A6, 0x5568, 0x86A7, 0x5569, 0x86A8, 0x556B, 0x86A9, 0x556F, + 0x86AA, 0x5570, 0x86AB, 0x5571, 0x86AC, 0x5572, 0x86AD, 0x5573, 0x86AE, 0x5574, 0x86AF, 0x5579, 0x86B0, 0x557A, 0x86B1, 0x557D, + 0x86B2, 0x557F, 0x86B3, 0x5585, 0x86B4, 0x5586, 0x86B5, 0x558C, 0x86B6, 0x558D, 0x86B7, 0x558E, 0x86B8, 0x5590, 0x86B9, 0x5592, + 0x86BA, 0x5593, 0x86BB, 0x5595, 0x86BC, 0x5596, 0x86BD, 0x5597, 0x86BE, 0x559A, 0x86BF, 0x559B, 0x86C0, 0x559E, 0x86C1, 0x55A0, + 0x86C2, 0x55A1, 0x86C3, 0x55A2, 0x86C4, 0x55A3, 0x86C5, 0x55A4, 0x86C6, 0x55A5, 0x86C7, 0x55A6, 0x86C8, 0x55A8, 0x86C9, 0x55A9, + 0x86CA, 0x55AA, 0x86CB, 0x55AB, 0x86CC, 0x55AC, 0x86CD, 0x55AD, 0x86CE, 0x55AE, 0x86CF, 0x55AF, 0x86D0, 0x55B0, 0x86D1, 0x55B2, + 0x86D2, 0x55B4, 0x86D3, 0x55B6, 0x86D4, 0x55B8, 0x86D5, 0x55BA, 0x86D6, 0x55BC, 0x86D7, 0x55BF, 0x86D8, 0x55C0, 0x86D9, 0x55C1, + 0x86DA, 0x55C2, 0x86DB, 0x55C3, 0x86DC, 0x55C6, 0x86DD, 0x55C7, 0x86DE, 0x55C8, 0x86DF, 0x55CA, 0x86E0, 0x55CB, 0x86E1, 0x55CE, + 0x86E2, 0x55CF, 0x86E3, 0x55D0, 0x86E4, 0x55D5, 0x86E5, 0x55D7, 0x86E6, 0x55D8, 0x86E7, 0x55D9, 0x86E8, 0x55DA, 0x86E9, 0x55DB, + 0x86EA, 0x55DE, 0x86EB, 0x55E0, 0x86EC, 0x55E2, 0x86ED, 0x55E7, 0x86EE, 0x55E9, 0x86EF, 0x55ED, 0x86F0, 0x55EE, 0x86F1, 0x55F0, + 0x86F2, 0x55F1, 0x86F3, 0x55F4, 0x86F4, 0x55F6, 0x86F5, 0x55F8, 0x86F6, 0x55F9, 0x86F7, 0x55FA, 0x86F8, 0x55FB, 0x86F9, 0x55FC, + 0x86FA, 0x55FF, 0x86FB, 0x5602, 0x86FC, 0x5603, 0x86FD, 0x5604, 0x86FE, 0x5605, 0x8740, 0x5606, 0x8741, 0x5607, 0x8742, 0x560A, + 0x8743, 0x560B, 0x8744, 0x560D, 0x8745, 0x5610, 0x8746, 0x5611, 0x8747, 0x5612, 0x8748, 0x5613, 0x8749, 0x5614, 0x874A, 0x5615, + 0x874B, 0x5616, 0x874C, 0x5617, 0x874D, 0x5619, 0x874E, 0x561A, 0x874F, 0x561C, 0x8750, 0x561D, 0x8751, 0x5620, 0x8752, 0x5621, + 0x8753, 0x5622, 0x8754, 0x5625, 0x8755, 0x5626, 0x8756, 0x5628, 0x8757, 0x5629, 0x8758, 0x562A, 0x8759, 0x562B, 0x875A, 0x562E, + 0x875B, 0x562F, 0x875C, 0x5630, 0x875D, 0x5633, 0x875E, 0x5635, 0x875F, 0x5637, 0x8760, 0x5638, 0x8761, 0x563A, 0x8762, 0x563C, + 0x8763, 0x563D, 0x8764, 0x563E, 0x8765, 0x5640, 0x8766, 0x5641, 0x8767, 0x5642, 0x8768, 0x5643, 0x8769, 0x5644, 0x876A, 0x5645, + 0x876B, 0x5646, 0x876C, 0x5647, 0x876D, 0x5648, 0x876E, 0x5649, 0x876F, 0x564A, 0x8770, 0x564B, 0x8771, 0x564F, 0x8772, 0x5650, + 0x8773, 0x5651, 0x8774, 0x5652, 0x8775, 0x5653, 0x8776, 0x5655, 0x8777, 0x5656, 0x8778, 0x565A, 0x8779, 0x565B, 0x877A, 0x565D, + 0x877B, 0x565E, 0x877C, 0x565F, 0x877D, 0x5660, 0x877E, 0x5661, 0x8780, 0x5663, 0x8781, 0x5665, 0x8782, 0x5666, 0x8783, 0x5667, + 0x8784, 0x566D, 0x8785, 0x566E, 0x8786, 0x566F, 0x8787, 0x5670, 0x8788, 0x5672, 0x8789, 0x5673, 0x878A, 0x5674, 0x878B, 0x5675, + 0x878C, 0x5677, 0x878D, 0x5678, 0x878E, 0x5679, 0x878F, 0x567A, 0x8790, 0x567D, 0x8791, 0x567E, 0x8792, 0x567F, 0x8793, 0x5680, + 0x8794, 0x5681, 0x8795, 0x5682, 0x8796, 0x5683, 0x8797, 0x5684, 0x8798, 0x5687, 0x8799, 0x5688, 0x879A, 0x5689, 0x879B, 0x568A, + 0x879C, 0x568B, 0x879D, 0x568C, 0x879E, 0x568D, 0x879F, 0x5690, 0x87A0, 0x5691, 0x87A1, 0x5692, 0x87A2, 0x5694, 0x87A3, 0x5695, + 0x87A4, 0x5696, 0x87A5, 0x5697, 0x87A6, 0x5698, 0x87A7, 0x5699, 0x87A8, 0x569A, 0x87A9, 0x569B, 0x87AA, 0x569C, 0x87AB, 0x569D, + 0x87AC, 0x569E, 0x87AD, 0x569F, 0x87AE, 0x56A0, 0x87AF, 0x56A1, 0x87B0, 0x56A2, 0x87B1, 0x56A4, 0x87B2, 0x56A5, 0x87B3, 0x56A6, + 0x87B4, 0x56A7, 0x87B5, 0x56A8, 0x87B6, 0x56A9, 0x87B7, 0x56AA, 0x87B8, 0x56AB, 0x87B9, 0x56AC, 0x87BA, 0x56AD, 0x87BB, 0x56AE, + 0x87BC, 0x56B0, 0x87BD, 0x56B1, 0x87BE, 0x56B2, 0x87BF, 0x56B3, 0x87C0, 0x56B4, 0x87C1, 0x56B5, 0x87C2, 0x56B6, 0x87C3, 0x56B8, + 0x87C4, 0x56B9, 0x87C5, 0x56BA, 0x87C6, 0x56BB, 0x87C7, 0x56BD, 0x87C8, 0x56BE, 0x87C9, 0x56BF, 0x87CA, 0x56C0, 0x87CB, 0x56C1, + 0x87CC, 0x56C2, 0x87CD, 0x56C3, 0x87CE, 0x56C4, 0x87CF, 0x56C5, 0x87D0, 0x56C6, 0x87D1, 0x56C7, 0x87D2, 0x56C8, 0x87D3, 0x56C9, + 0x87D4, 0x56CB, 0x87D5, 0x56CC, 0x87D6, 0x56CD, 0x87D7, 0x56CE, 0x87D8, 0x56CF, 0x87D9, 0x56D0, 0x87DA, 0x56D1, 0x87DB, 0x56D2, + 0x87DC, 0x56D3, 0x87DD, 0x56D5, 0x87DE, 0x56D6, 0x87DF, 0x56D8, 0x87E0, 0x56D9, 0x87E1, 0x56DC, 0x87E2, 0x56E3, 0x87E3, 0x56E5, + 0x87E4, 0x56E6, 0x87E5, 0x56E7, 0x87E6, 0x56E8, 0x87E7, 0x56E9, 0x87E8, 0x56EA, 0x87E9, 0x56EC, 0x87EA, 0x56EE, 0x87EB, 0x56EF, + 0x87EC, 0x56F2, 0x87ED, 0x56F3, 0x87EE, 0x56F6, 0x87EF, 0x56F7, 0x87F0, 0x56F8, 0x87F1, 0x56FB, 0x87F2, 0x56FC, 0x87F3, 0x5700, + 0x87F4, 0x5701, 0x87F5, 0x5702, 0x87F6, 0x5705, 0x87F7, 0x5707, 0x87F8, 0x570B, 0x87F9, 0x570C, 0x87FA, 0x570D, 0x87FB, 0x570E, + 0x87FC, 0x570F, 0x87FD, 0x5710, 0x87FE, 0x5711, 0x8840, 0x5712, 0x8841, 0x5713, 0x8842, 0x5714, 0x8843, 0x5715, 0x8844, 0x5716, + 0x8845, 0x5717, 0x8846, 0x5718, 0x8847, 0x5719, 0x8848, 0x571A, 0x8849, 0x571B, 0x884A, 0x571D, 0x884B, 0x571E, 0x884C, 0x5720, + 0x884D, 0x5721, 0x884E, 0x5722, 0x884F, 0x5724, 0x8850, 0x5725, 0x8851, 0x5726, 0x8852, 0x5727, 0x8853, 0x572B, 0x8854, 0x5731, + 0x8855, 0x5732, 0x8856, 0x5734, 0x8857, 0x5735, 0x8858, 0x5736, 0x8859, 0x5737, 0x885A, 0x5738, 0x885B, 0x573C, 0x885C, 0x573D, + 0x885D, 0x573F, 0x885E, 0x5741, 0x885F, 0x5743, 0x8860, 0x5744, 0x8861, 0x5745, 0x8862, 0x5746, 0x8863, 0x5748, 0x8864, 0x5749, + 0x8865, 0x574B, 0x8866, 0x5752, 0x8867, 0x5753, 0x8868, 0x5754, 0x8869, 0x5755, 0x886A, 0x5756, 0x886B, 0x5758, 0x886C, 0x5759, + 0x886D, 0x5762, 0x886E, 0x5763, 0x886F, 0x5765, 0x8870, 0x5767, 0x8871, 0x576C, 0x8872, 0x576E, 0x8873, 0x5770, 0x8874, 0x5771, + 0x8875, 0x5772, 0x8876, 0x5774, 0x8877, 0x5775, 0x8878, 0x5778, 0x8879, 0x5779, 0x887A, 0x577A, 0x887B, 0x577D, 0x887C, 0x577E, + 0x887D, 0x577F, 0x887E, 0x5780, 0x8880, 0x5781, 0x8881, 0x5787, 0x8882, 0x5788, 0x8883, 0x5789, 0x8884, 0x578A, 0x8885, 0x578D, + 0x8886, 0x578E, 0x8887, 0x578F, 0x8888, 0x5790, 0x8889, 0x5791, 0x888A, 0x5794, 0x888B, 0x5795, 0x888C, 0x5796, 0x888D, 0x5797, + 0x888E, 0x5798, 0x888F, 0x5799, 0x8890, 0x579A, 0x8891, 0x579C, 0x8892, 0x579D, 0x8893, 0x579E, 0x8894, 0x579F, 0x8895, 0x57A5, + 0x8896, 0x57A8, 0x8897, 0x57AA, 0x8898, 0x57AC, 0x8899, 0x57AF, 0x889A, 0x57B0, 0x889B, 0x57B1, 0x889C, 0x57B3, 0x889D, 0x57B5, + 0x889E, 0x57B6, 0x889F, 0x57B7, 0x88A0, 0x57B9, 0x88A1, 0x57BA, 0x88A2, 0x57BB, 0x88A3, 0x57BC, 0x88A4, 0x57BD, 0x88A5, 0x57BE, + 0x88A6, 0x57BF, 0x88A7, 0x57C0, 0x88A8, 0x57C1, 0x88A9, 0x57C4, 0x88AA, 0x57C5, 0x88AB, 0x57C6, 0x88AC, 0x57C7, 0x88AD, 0x57C8, + 0x88AE, 0x57C9, 0x88AF, 0x57CA, 0x88B0, 0x57CC, 0x88B1, 0x57CD, 0x88B2, 0x57D0, 0x88B3, 0x57D1, 0x88B4, 0x57D3, 0x88B5, 0x57D6, + 0x88B6, 0x57D7, 0x88B7, 0x57DB, 0x88B8, 0x57DC, 0x88B9, 0x57DE, 0x88BA, 0x57E1, 0x88BB, 0x57E2, 0x88BC, 0x57E3, 0x88BD, 0x57E5, + 0x88BE, 0x57E6, 0x88BF, 0x57E7, 0x88C0, 0x57E8, 0x88C1, 0x57E9, 0x88C2, 0x57EA, 0x88C3, 0x57EB, 0x88C4, 0x57EC, 0x88C5, 0x57EE, + 0x88C6, 0x57F0, 0x88C7, 0x57F1, 0x88C8, 0x57F2, 0x88C9, 0x57F3, 0x88CA, 0x57F5, 0x88CB, 0x57F6, 0x88CC, 0x57F7, 0x88CD, 0x57FB, + 0x88CE, 0x57FC, 0x88CF, 0x57FE, 0x88D0, 0x57FF, 0x88D1, 0x5801, 0x88D2, 0x5803, 0x88D3, 0x5804, 0x88D4, 0x5805, 0x88D5, 0x5808, + 0x88D6, 0x5809, 0x88D7, 0x580A, 0x88D8, 0x580C, 0x88D9, 0x580E, 0x88DA, 0x580F, 0x88DB, 0x5810, 0x88DC, 0x5812, 0x88DD, 0x5813, + 0x88DE, 0x5814, 0x88DF, 0x5816, 0x88E0, 0x5817, 0x88E1, 0x5818, 0x88E2, 0x581A, 0x88E3, 0x581B, 0x88E4, 0x581C, 0x88E5, 0x581D, + 0x88E6, 0x581F, 0x88E7, 0x5822, 0x88E8, 0x5823, 0x88E9, 0x5825, 0x88EA, 0x5826, 0x88EB, 0x5827, 0x88EC, 0x5828, 0x88ED, 0x5829, + 0x88EE, 0x582B, 0x88EF, 0x582C, 0x88F0, 0x582D, 0x88F1, 0x582E, 0x88F2, 0x582F, 0x88F3, 0x5831, 0x88F4, 0x5832, 0x88F5, 0x5833, + 0x88F6, 0x5834, 0x88F7, 0x5836, 0x88F8, 0x5837, 0x88F9, 0x5838, 0x88FA, 0x5839, 0x88FB, 0x583A, 0x88FC, 0x583B, 0x88FD, 0x583C, + 0x88FE, 0x583D, 0x8940, 0x583E, 0x8941, 0x583F, 0x8942, 0x5840, 0x8943, 0x5841, 0x8944, 0x5842, 0x8945, 0x5843, 0x8946, 0x5845, + 0x8947, 0x5846, 0x8948, 0x5847, 0x8949, 0x5848, 0x894A, 0x5849, 0x894B, 0x584A, 0x894C, 0x584B, 0x894D, 0x584E, 0x894E, 0x584F, + 0x894F, 0x5850, 0x8950, 0x5852, 0x8951, 0x5853, 0x8952, 0x5855, 0x8953, 0x5856, 0x8954, 0x5857, 0x8955, 0x5859, 0x8956, 0x585A, + 0x8957, 0x585B, 0x8958, 0x585C, 0x8959, 0x585D, 0x895A, 0x585F, 0x895B, 0x5860, 0x895C, 0x5861, 0x895D, 0x5862, 0x895E, 0x5863, + 0x895F, 0x5864, 0x8960, 0x5866, 0x8961, 0x5867, 0x8962, 0x5868, 0x8963, 0x5869, 0x8964, 0x586A, 0x8965, 0x586D, 0x8966, 0x586E, + 0x8967, 0x586F, 0x8968, 0x5870, 0x8969, 0x5871, 0x896A, 0x5872, 0x896B, 0x5873, 0x896C, 0x5874, 0x896D, 0x5875, 0x896E, 0x5876, + 0x896F, 0x5877, 0x8970, 0x5878, 0x8971, 0x5879, 0x8972, 0x587A, 0x8973, 0x587B, 0x8974, 0x587C, 0x8975, 0x587D, 0x8976, 0x587F, + 0x8977, 0x5882, 0x8978, 0x5884, 0x8979, 0x5886, 0x897A, 0x5887, 0x897B, 0x5888, 0x897C, 0x588A, 0x897D, 0x588B, 0x897E, 0x588C, + 0x8980, 0x588D, 0x8981, 0x588E, 0x8982, 0x588F, 0x8983, 0x5890, 0x8984, 0x5891, 0x8985, 0x5894, 0x8986, 0x5895, 0x8987, 0x5896, + 0x8988, 0x5897, 0x8989, 0x5898, 0x898A, 0x589B, 0x898B, 0x589C, 0x898C, 0x589D, 0x898D, 0x58A0, 0x898E, 0x58A1, 0x898F, 0x58A2, + 0x8990, 0x58A3, 0x8991, 0x58A4, 0x8992, 0x58A5, 0x8993, 0x58A6, 0x8994, 0x58A7, 0x8995, 0x58AA, 0x8996, 0x58AB, 0x8997, 0x58AC, + 0x8998, 0x58AD, 0x8999, 0x58AE, 0x899A, 0x58AF, 0x899B, 0x58B0, 0x899C, 0x58B1, 0x899D, 0x58B2, 0x899E, 0x58B3, 0x899F, 0x58B4, + 0x89A0, 0x58B5, 0x89A1, 0x58B6, 0x89A2, 0x58B7, 0x89A3, 0x58B8, 0x89A4, 0x58B9, 0x89A5, 0x58BA, 0x89A6, 0x58BB, 0x89A7, 0x58BD, + 0x89A8, 0x58BE, 0x89A9, 0x58BF, 0x89AA, 0x58C0, 0x89AB, 0x58C2, 0x89AC, 0x58C3, 0x89AD, 0x58C4, 0x89AE, 0x58C6, 0x89AF, 0x58C7, + 0x89B0, 0x58C8, 0x89B1, 0x58C9, 0x89B2, 0x58CA, 0x89B3, 0x58CB, 0x89B4, 0x58CC, 0x89B5, 0x58CD, 0x89B6, 0x58CE, 0x89B7, 0x58CF, + 0x89B8, 0x58D0, 0x89B9, 0x58D2, 0x89BA, 0x58D3, 0x89BB, 0x58D4, 0x89BC, 0x58D6, 0x89BD, 0x58D7, 0x89BE, 0x58D8, 0x89BF, 0x58D9, + 0x89C0, 0x58DA, 0x89C1, 0x58DB, 0x89C2, 0x58DC, 0x89C3, 0x58DD, 0x89C4, 0x58DE, 0x89C5, 0x58DF, 0x89C6, 0x58E0, 0x89C7, 0x58E1, + 0x89C8, 0x58E2, 0x89C9, 0x58E3, 0x89CA, 0x58E5, 0x89CB, 0x58E6, 0x89CC, 0x58E7, 0x89CD, 0x58E8, 0x89CE, 0x58E9, 0x89CF, 0x58EA, + 0x89D0, 0x58ED, 0x89D1, 0x58EF, 0x89D2, 0x58F1, 0x89D3, 0x58F2, 0x89D4, 0x58F4, 0x89D5, 0x58F5, 0x89D6, 0x58F7, 0x89D7, 0x58F8, + 0x89D8, 0x58FA, 0x89D9, 0x58FB, 0x89DA, 0x58FC, 0x89DB, 0x58FD, 0x89DC, 0x58FE, 0x89DD, 0x58FF, 0x89DE, 0x5900, 0x89DF, 0x5901, + 0x89E0, 0x5903, 0x89E1, 0x5905, 0x89E2, 0x5906, 0x89E3, 0x5908, 0x89E4, 0x5909, 0x89E5, 0x590A, 0x89E6, 0x590B, 0x89E7, 0x590C, + 0x89E8, 0x590E, 0x89E9, 0x5910, 0x89EA, 0x5911, 0x89EB, 0x5912, 0x89EC, 0x5913, 0x89ED, 0x5917, 0x89EE, 0x5918, 0x89EF, 0x591B, + 0x89F0, 0x591D, 0x89F1, 0x591E, 0x89F2, 0x5920, 0x89F3, 0x5921, 0x89F4, 0x5922, 0x89F5, 0x5923, 0x89F6, 0x5926, 0x89F7, 0x5928, + 0x89F8, 0x592C, 0x89F9, 0x5930, 0x89FA, 0x5932, 0x89FB, 0x5933, 0x89FC, 0x5935, 0x89FD, 0x5936, 0x89FE, 0x593B, 0x8A40, 0x593D, + 0x8A41, 0x593E, 0x8A42, 0x593F, 0x8A43, 0x5940, 0x8A44, 0x5943, 0x8A45, 0x5945, 0x8A46, 0x5946, 0x8A47, 0x594A, 0x8A48, 0x594C, + 0x8A49, 0x594D, 0x8A4A, 0x5950, 0x8A4B, 0x5952, 0x8A4C, 0x5953, 0x8A4D, 0x5959, 0x8A4E, 0x595B, 0x8A4F, 0x595C, 0x8A50, 0x595D, + 0x8A51, 0x595E, 0x8A52, 0x595F, 0x8A53, 0x5961, 0x8A54, 0x5963, 0x8A55, 0x5964, 0x8A56, 0x5966, 0x8A57, 0x5967, 0x8A58, 0x5968, + 0x8A59, 0x5969, 0x8A5A, 0x596A, 0x8A5B, 0x596B, 0x8A5C, 0x596C, 0x8A5D, 0x596D, 0x8A5E, 0x596E, 0x8A5F, 0x596F, 0x8A60, 0x5970, + 0x8A61, 0x5971, 0x8A62, 0x5972, 0x8A63, 0x5975, 0x8A64, 0x5977, 0x8A65, 0x597A, 0x8A66, 0x597B, 0x8A67, 0x597C, 0x8A68, 0x597E, + 0x8A69, 0x597F, 0x8A6A, 0x5980, 0x8A6B, 0x5985, 0x8A6C, 0x5989, 0x8A6D, 0x598B, 0x8A6E, 0x598C, 0x8A6F, 0x598E, 0x8A70, 0x598F, + 0x8A71, 0x5990, 0x8A72, 0x5991, 0x8A73, 0x5994, 0x8A74, 0x5995, 0x8A75, 0x5998, 0x8A76, 0x599A, 0x8A77, 0x599B, 0x8A78, 0x599C, + 0x8A79, 0x599D, 0x8A7A, 0x599F, 0x8A7B, 0x59A0, 0x8A7C, 0x59A1, 0x8A7D, 0x59A2, 0x8A7E, 0x59A6, 0x8A80, 0x59A7, 0x8A81, 0x59AC, + 0x8A82, 0x59AD, 0x8A83, 0x59B0, 0x8A84, 0x59B1, 0x8A85, 0x59B3, 0x8A86, 0x59B4, 0x8A87, 0x59B5, 0x8A88, 0x59B6, 0x8A89, 0x59B7, + 0x8A8A, 0x59B8, 0x8A8B, 0x59BA, 0x8A8C, 0x59BC, 0x8A8D, 0x59BD, 0x8A8E, 0x59BF, 0x8A8F, 0x59C0, 0x8A90, 0x59C1, 0x8A91, 0x59C2, + 0x8A92, 0x59C3, 0x8A93, 0x59C4, 0x8A94, 0x59C5, 0x8A95, 0x59C7, 0x8A96, 0x59C8, 0x8A97, 0x59C9, 0x8A98, 0x59CC, 0x8A99, 0x59CD, + 0x8A9A, 0x59CE, 0x8A9B, 0x59CF, 0x8A9C, 0x59D5, 0x8A9D, 0x59D6, 0x8A9E, 0x59D9, 0x8A9F, 0x59DB, 0x8AA0, 0x59DE, 0x8AA1, 0x59DF, + 0x8AA2, 0x59E0, 0x8AA3, 0x59E1, 0x8AA4, 0x59E2, 0x8AA5, 0x59E4, 0x8AA6, 0x59E6, 0x8AA7, 0x59E7, 0x8AA8, 0x59E9, 0x8AA9, 0x59EA, + 0x8AAA, 0x59EB, 0x8AAB, 0x59ED, 0x8AAC, 0x59EE, 0x8AAD, 0x59EF, 0x8AAE, 0x59F0, 0x8AAF, 0x59F1, 0x8AB0, 0x59F2, 0x8AB1, 0x59F3, + 0x8AB2, 0x59F4, 0x8AB3, 0x59F5, 0x8AB4, 0x59F6, 0x8AB5, 0x59F7, 0x8AB6, 0x59F8, 0x8AB7, 0x59FA, 0x8AB8, 0x59FC, 0x8AB9, 0x59FD, + 0x8ABA, 0x59FE, 0x8ABB, 0x5A00, 0x8ABC, 0x5A02, 0x8ABD, 0x5A0A, 0x8ABE, 0x5A0B, 0x8ABF, 0x5A0D, 0x8AC0, 0x5A0E, 0x8AC1, 0x5A0F, + 0x8AC2, 0x5A10, 0x8AC3, 0x5A12, 0x8AC4, 0x5A14, 0x8AC5, 0x5A15, 0x8AC6, 0x5A16, 0x8AC7, 0x5A17, 0x8AC8, 0x5A19, 0x8AC9, 0x5A1A, + 0x8ACA, 0x5A1B, 0x8ACB, 0x5A1D, 0x8ACC, 0x5A1E, 0x8ACD, 0x5A21, 0x8ACE, 0x5A22, 0x8ACF, 0x5A24, 0x8AD0, 0x5A26, 0x8AD1, 0x5A27, + 0x8AD2, 0x5A28, 0x8AD3, 0x5A2A, 0x8AD4, 0x5A2B, 0x8AD5, 0x5A2C, 0x8AD6, 0x5A2D, 0x8AD7, 0x5A2E, 0x8AD8, 0x5A2F, 0x8AD9, 0x5A30, + 0x8ADA, 0x5A33, 0x8ADB, 0x5A35, 0x8ADC, 0x5A37, 0x8ADD, 0x5A38, 0x8ADE, 0x5A39, 0x8ADF, 0x5A3A, 0x8AE0, 0x5A3B, 0x8AE1, 0x5A3D, + 0x8AE2, 0x5A3E, 0x8AE3, 0x5A3F, 0x8AE4, 0x5A41, 0x8AE5, 0x5A42, 0x8AE6, 0x5A43, 0x8AE7, 0x5A44, 0x8AE8, 0x5A45, 0x8AE9, 0x5A47, + 0x8AEA, 0x5A48, 0x8AEB, 0x5A4B, 0x8AEC, 0x5A4C, 0x8AED, 0x5A4D, 0x8AEE, 0x5A4E, 0x8AEF, 0x5A4F, 0x8AF0, 0x5A50, 0x8AF1, 0x5A51, + 0x8AF2, 0x5A52, 0x8AF3, 0x5A53, 0x8AF4, 0x5A54, 0x8AF5, 0x5A56, 0x8AF6, 0x5A57, 0x8AF7, 0x5A58, 0x8AF8, 0x5A59, 0x8AF9, 0x5A5B, + 0x8AFA, 0x5A5C, 0x8AFB, 0x5A5D, 0x8AFC, 0x5A5E, 0x8AFD, 0x5A5F, 0x8AFE, 0x5A60, 0x8B40, 0x5A61, 0x8B41, 0x5A63, 0x8B42, 0x5A64, + 0x8B43, 0x5A65, 0x8B44, 0x5A66, 0x8B45, 0x5A68, 0x8B46, 0x5A69, 0x8B47, 0x5A6B, 0x8B48, 0x5A6C, 0x8B49, 0x5A6D, 0x8B4A, 0x5A6E, + 0x8B4B, 0x5A6F, 0x8B4C, 0x5A70, 0x8B4D, 0x5A71, 0x8B4E, 0x5A72, 0x8B4F, 0x5A73, 0x8B50, 0x5A78, 0x8B51, 0x5A79, 0x8B52, 0x5A7B, + 0x8B53, 0x5A7C, 0x8B54, 0x5A7D, 0x8B55, 0x5A7E, 0x8B56, 0x5A80, 0x8B57, 0x5A81, 0x8B58, 0x5A82, 0x8B59, 0x5A83, 0x8B5A, 0x5A84, + 0x8B5B, 0x5A85, 0x8B5C, 0x5A86, 0x8B5D, 0x5A87, 0x8B5E, 0x5A88, 0x8B5F, 0x5A89, 0x8B60, 0x5A8A, 0x8B61, 0x5A8B, 0x8B62, 0x5A8C, + 0x8B63, 0x5A8D, 0x8B64, 0x5A8E, 0x8B65, 0x5A8F, 0x8B66, 0x5A90, 0x8B67, 0x5A91, 0x8B68, 0x5A93, 0x8B69, 0x5A94, 0x8B6A, 0x5A95, + 0x8B6B, 0x5A96, 0x8B6C, 0x5A97, 0x8B6D, 0x5A98, 0x8B6E, 0x5A99, 0x8B6F, 0x5A9C, 0x8B70, 0x5A9D, 0x8B71, 0x5A9E, 0x8B72, 0x5A9F, + 0x8B73, 0x5AA0, 0x8B74, 0x5AA1, 0x8B75, 0x5AA2, 0x8B76, 0x5AA3, 0x8B77, 0x5AA4, 0x8B78, 0x5AA5, 0x8B79, 0x5AA6, 0x8B7A, 0x5AA7, + 0x8B7B, 0x5AA8, 0x8B7C, 0x5AA9, 0x8B7D, 0x5AAB, 0x8B7E, 0x5AAC, 0x8B80, 0x5AAD, 0x8B81, 0x5AAE, 0x8B82, 0x5AAF, 0x8B83, 0x5AB0, + 0x8B84, 0x5AB1, 0x8B85, 0x5AB4, 0x8B86, 0x5AB6, 0x8B87, 0x5AB7, 0x8B88, 0x5AB9, 0x8B89, 0x5ABA, 0x8B8A, 0x5ABB, 0x8B8B, 0x5ABC, + 0x8B8C, 0x5ABD, 0x8B8D, 0x5ABF, 0x8B8E, 0x5AC0, 0x8B8F, 0x5AC3, 0x8B90, 0x5AC4, 0x8B91, 0x5AC5, 0x8B92, 0x5AC6, 0x8B93, 0x5AC7, + 0x8B94, 0x5AC8, 0x8B95, 0x5ACA, 0x8B96, 0x5ACB, 0x8B97, 0x5ACD, 0x8B98, 0x5ACE, 0x8B99, 0x5ACF, 0x8B9A, 0x5AD0, 0x8B9B, 0x5AD1, + 0x8B9C, 0x5AD3, 0x8B9D, 0x5AD5, 0x8B9E, 0x5AD7, 0x8B9F, 0x5AD9, 0x8BA0, 0x5ADA, 0x8BA1, 0x5ADB, 0x8BA2, 0x5ADD, 0x8BA3, 0x5ADE, + 0x8BA4, 0x5ADF, 0x8BA5, 0x5AE2, 0x8BA6, 0x5AE4, 0x8BA7, 0x5AE5, 0x8BA8, 0x5AE7, 0x8BA9, 0x5AE8, 0x8BAA, 0x5AEA, 0x8BAB, 0x5AEC, + 0x8BAC, 0x5AED, 0x8BAD, 0x5AEE, 0x8BAE, 0x5AEF, 0x8BAF, 0x5AF0, 0x8BB0, 0x5AF2, 0x8BB1, 0x5AF3, 0x8BB2, 0x5AF4, 0x8BB3, 0x5AF5, + 0x8BB4, 0x5AF6, 0x8BB5, 0x5AF7, 0x8BB6, 0x5AF8, 0x8BB7, 0x5AF9, 0x8BB8, 0x5AFA, 0x8BB9, 0x5AFB, 0x8BBA, 0x5AFC, 0x8BBB, 0x5AFD, + 0x8BBC, 0x5AFE, 0x8BBD, 0x5AFF, 0x8BBE, 0x5B00, 0x8BBF, 0x5B01, 0x8BC0, 0x5B02, 0x8BC1, 0x5B03, 0x8BC2, 0x5B04, 0x8BC3, 0x5B05, + 0x8BC4, 0x5B06, 0x8BC5, 0x5B07, 0x8BC6, 0x5B08, 0x8BC7, 0x5B0A, 0x8BC8, 0x5B0B, 0x8BC9, 0x5B0C, 0x8BCA, 0x5B0D, 0x8BCB, 0x5B0E, + 0x8BCC, 0x5B0F, 0x8BCD, 0x5B10, 0x8BCE, 0x5B11, 0x8BCF, 0x5B12, 0x8BD0, 0x5B13, 0x8BD1, 0x5B14, 0x8BD2, 0x5B15, 0x8BD3, 0x5B18, + 0x8BD4, 0x5B19, 0x8BD5, 0x5B1A, 0x8BD6, 0x5B1B, 0x8BD7, 0x5B1C, 0x8BD8, 0x5B1D, 0x8BD9, 0x5B1E, 0x8BDA, 0x5B1F, 0x8BDB, 0x5B20, + 0x8BDC, 0x5B21, 0x8BDD, 0x5B22, 0x8BDE, 0x5B23, 0x8BDF, 0x5B24, 0x8BE0, 0x5B25, 0x8BE1, 0x5B26, 0x8BE2, 0x5B27, 0x8BE3, 0x5B28, + 0x8BE4, 0x5B29, 0x8BE5, 0x5B2A, 0x8BE6, 0x5B2B, 0x8BE7, 0x5B2C, 0x8BE8, 0x5B2D, 0x8BE9, 0x5B2E, 0x8BEA, 0x5B2F, 0x8BEB, 0x5B30, + 0x8BEC, 0x5B31, 0x8BED, 0x5B33, 0x8BEE, 0x5B35, 0x8BEF, 0x5B36, 0x8BF0, 0x5B38, 0x8BF1, 0x5B39, 0x8BF2, 0x5B3A, 0x8BF3, 0x5B3B, + 0x8BF4, 0x5B3C, 0x8BF5, 0x5B3D, 0x8BF6, 0x5B3E, 0x8BF7, 0x5B3F, 0x8BF8, 0x5B41, 0x8BF9, 0x5B42, 0x8BFA, 0x5B43, 0x8BFB, 0x5B44, + 0x8BFC, 0x5B45, 0x8BFD, 0x5B46, 0x8BFE, 0x5B47, 0x8C40, 0x5B48, 0x8C41, 0x5B49, 0x8C42, 0x5B4A, 0x8C43, 0x5B4B, 0x8C44, 0x5B4C, + 0x8C45, 0x5B4D, 0x8C46, 0x5B4E, 0x8C47, 0x5B4F, 0x8C48, 0x5B52, 0x8C49, 0x5B56, 0x8C4A, 0x5B5E, 0x8C4B, 0x5B60, 0x8C4C, 0x5B61, + 0x8C4D, 0x5B67, 0x8C4E, 0x5B68, 0x8C4F, 0x5B6B, 0x8C50, 0x5B6D, 0x8C51, 0x5B6E, 0x8C52, 0x5B6F, 0x8C53, 0x5B72, 0x8C54, 0x5B74, + 0x8C55, 0x5B76, 0x8C56, 0x5B77, 0x8C57, 0x5B78, 0x8C58, 0x5B79, 0x8C59, 0x5B7B, 0x8C5A, 0x5B7C, 0x8C5B, 0x5B7E, 0x8C5C, 0x5B7F, + 0x8C5D, 0x5B82, 0x8C5E, 0x5B86, 0x8C5F, 0x5B8A, 0x8C60, 0x5B8D, 0x8C61, 0x5B8E, 0x8C62, 0x5B90, 0x8C63, 0x5B91, 0x8C64, 0x5B92, + 0x8C65, 0x5B94, 0x8C66, 0x5B96, 0x8C67, 0x5B9F, 0x8C68, 0x5BA7, 0x8C69, 0x5BA8, 0x8C6A, 0x5BA9, 0x8C6B, 0x5BAC, 0x8C6C, 0x5BAD, + 0x8C6D, 0x5BAE, 0x8C6E, 0x5BAF, 0x8C6F, 0x5BB1, 0x8C70, 0x5BB2, 0x8C71, 0x5BB7, 0x8C72, 0x5BBA, 0x8C73, 0x5BBB, 0x8C74, 0x5BBC, + 0x8C75, 0x5BC0, 0x8C76, 0x5BC1, 0x8C77, 0x5BC3, 0x8C78, 0x5BC8, 0x8C79, 0x5BC9, 0x8C7A, 0x5BCA, 0x8C7B, 0x5BCB, 0x8C7C, 0x5BCD, + 0x8C7D, 0x5BCE, 0x8C7E, 0x5BCF, 0x8C80, 0x5BD1, 0x8C81, 0x5BD4, 0x8C82, 0x5BD5, 0x8C83, 0x5BD6, 0x8C84, 0x5BD7, 0x8C85, 0x5BD8, + 0x8C86, 0x5BD9, 0x8C87, 0x5BDA, 0x8C88, 0x5BDB, 0x8C89, 0x5BDC, 0x8C8A, 0x5BE0, 0x8C8B, 0x5BE2, 0x8C8C, 0x5BE3, 0x8C8D, 0x5BE6, + 0x8C8E, 0x5BE7, 0x8C8F, 0x5BE9, 0x8C90, 0x5BEA, 0x8C91, 0x5BEB, 0x8C92, 0x5BEC, 0x8C93, 0x5BED, 0x8C94, 0x5BEF, 0x8C95, 0x5BF1, + 0x8C96, 0x5BF2, 0x8C97, 0x5BF3, 0x8C98, 0x5BF4, 0x8C99, 0x5BF5, 0x8C9A, 0x5BF6, 0x8C9B, 0x5BF7, 0x8C9C, 0x5BFD, 0x8C9D, 0x5BFE, + 0x8C9E, 0x5C00, 0x8C9F, 0x5C02, 0x8CA0, 0x5C03, 0x8CA1, 0x5C05, 0x8CA2, 0x5C07, 0x8CA3, 0x5C08, 0x8CA4, 0x5C0B, 0x8CA5, 0x5C0C, + 0x8CA6, 0x5C0D, 0x8CA7, 0x5C0E, 0x8CA8, 0x5C10, 0x8CA9, 0x5C12, 0x8CAA, 0x5C13, 0x8CAB, 0x5C17, 0x8CAC, 0x5C19, 0x8CAD, 0x5C1B, + 0x8CAE, 0x5C1E, 0x8CAF, 0x5C1F, 0x8CB0, 0x5C20, 0x8CB1, 0x5C21, 0x8CB2, 0x5C23, 0x8CB3, 0x5C26, 0x8CB4, 0x5C28, 0x8CB5, 0x5C29, + 0x8CB6, 0x5C2A, 0x8CB7, 0x5C2B, 0x8CB8, 0x5C2D, 0x8CB9, 0x5C2E, 0x8CBA, 0x5C2F, 0x8CBB, 0x5C30, 0x8CBC, 0x5C32, 0x8CBD, 0x5C33, + 0x8CBE, 0x5C35, 0x8CBF, 0x5C36, 0x8CC0, 0x5C37, 0x8CC1, 0x5C43, 0x8CC2, 0x5C44, 0x8CC3, 0x5C46, 0x8CC4, 0x5C47, 0x8CC5, 0x5C4C, + 0x8CC6, 0x5C4D, 0x8CC7, 0x5C52, 0x8CC8, 0x5C53, 0x8CC9, 0x5C54, 0x8CCA, 0x5C56, 0x8CCB, 0x5C57, 0x8CCC, 0x5C58, 0x8CCD, 0x5C5A, + 0x8CCE, 0x5C5B, 0x8CCF, 0x5C5C, 0x8CD0, 0x5C5D, 0x8CD1, 0x5C5F, 0x8CD2, 0x5C62, 0x8CD3, 0x5C64, 0x8CD4, 0x5C67, 0x8CD5, 0x5C68, + 0x8CD6, 0x5C69, 0x8CD7, 0x5C6A, 0x8CD8, 0x5C6B, 0x8CD9, 0x5C6C, 0x8CDA, 0x5C6D, 0x8CDB, 0x5C70, 0x8CDC, 0x5C72, 0x8CDD, 0x5C73, + 0x8CDE, 0x5C74, 0x8CDF, 0x5C75, 0x8CE0, 0x5C76, 0x8CE1, 0x5C77, 0x8CE2, 0x5C78, 0x8CE3, 0x5C7B, 0x8CE4, 0x5C7C, 0x8CE5, 0x5C7D, + 0x8CE6, 0x5C7E, 0x8CE7, 0x5C80, 0x8CE8, 0x5C83, 0x8CE9, 0x5C84, 0x8CEA, 0x5C85, 0x8CEB, 0x5C86, 0x8CEC, 0x5C87, 0x8CED, 0x5C89, + 0x8CEE, 0x5C8A, 0x8CEF, 0x5C8B, 0x8CF0, 0x5C8E, 0x8CF1, 0x5C8F, 0x8CF2, 0x5C92, 0x8CF3, 0x5C93, 0x8CF4, 0x5C95, 0x8CF5, 0x5C9D, + 0x8CF6, 0x5C9E, 0x8CF7, 0x5C9F, 0x8CF8, 0x5CA0, 0x8CF9, 0x5CA1, 0x8CFA, 0x5CA4, 0x8CFB, 0x5CA5, 0x8CFC, 0x5CA6, 0x8CFD, 0x5CA7, + 0x8CFE, 0x5CA8, 0x8D40, 0x5CAA, 0x8D41, 0x5CAE, 0x8D42, 0x5CAF, 0x8D43, 0x5CB0, 0x8D44, 0x5CB2, 0x8D45, 0x5CB4, 0x8D46, 0x5CB6, + 0x8D47, 0x5CB9, 0x8D48, 0x5CBA, 0x8D49, 0x5CBB, 0x8D4A, 0x5CBC, 0x8D4B, 0x5CBE, 0x8D4C, 0x5CC0, 0x8D4D, 0x5CC2, 0x8D4E, 0x5CC3, + 0x8D4F, 0x5CC5, 0x8D50, 0x5CC6, 0x8D51, 0x5CC7, 0x8D52, 0x5CC8, 0x8D53, 0x5CC9, 0x8D54, 0x5CCA, 0x8D55, 0x5CCC, 0x8D56, 0x5CCD, + 0x8D57, 0x5CCE, 0x8D58, 0x5CCF, 0x8D59, 0x5CD0, 0x8D5A, 0x5CD1, 0x8D5B, 0x5CD3, 0x8D5C, 0x5CD4, 0x8D5D, 0x5CD5, 0x8D5E, 0x5CD6, + 0x8D5F, 0x5CD7, 0x8D60, 0x5CD8, 0x8D61, 0x5CDA, 0x8D62, 0x5CDB, 0x8D63, 0x5CDC, 0x8D64, 0x5CDD, 0x8D65, 0x5CDE, 0x8D66, 0x5CDF, + 0x8D67, 0x5CE0, 0x8D68, 0x5CE2, 0x8D69, 0x5CE3, 0x8D6A, 0x5CE7, 0x8D6B, 0x5CE9, 0x8D6C, 0x5CEB, 0x8D6D, 0x5CEC, 0x8D6E, 0x5CEE, + 0x8D6F, 0x5CEF, 0x8D70, 0x5CF1, 0x8D71, 0x5CF2, 0x8D72, 0x5CF3, 0x8D73, 0x5CF4, 0x8D74, 0x5CF5, 0x8D75, 0x5CF6, 0x8D76, 0x5CF7, + 0x8D77, 0x5CF8, 0x8D78, 0x5CF9, 0x8D79, 0x5CFA, 0x8D7A, 0x5CFC, 0x8D7B, 0x5CFD, 0x8D7C, 0x5CFE, 0x8D7D, 0x5CFF, 0x8D7E, 0x5D00, + 0x8D80, 0x5D01, 0x8D81, 0x5D04, 0x8D82, 0x5D05, 0x8D83, 0x5D08, 0x8D84, 0x5D09, 0x8D85, 0x5D0A, 0x8D86, 0x5D0B, 0x8D87, 0x5D0C, + 0x8D88, 0x5D0D, 0x8D89, 0x5D0F, 0x8D8A, 0x5D10, 0x8D8B, 0x5D11, 0x8D8C, 0x5D12, 0x8D8D, 0x5D13, 0x8D8E, 0x5D15, 0x8D8F, 0x5D17, + 0x8D90, 0x5D18, 0x8D91, 0x5D19, 0x8D92, 0x5D1A, 0x8D93, 0x5D1C, 0x8D94, 0x5D1D, 0x8D95, 0x5D1F, 0x8D96, 0x5D20, 0x8D97, 0x5D21, + 0x8D98, 0x5D22, 0x8D99, 0x5D23, 0x8D9A, 0x5D25, 0x8D9B, 0x5D28, 0x8D9C, 0x5D2A, 0x8D9D, 0x5D2B, 0x8D9E, 0x5D2C, 0x8D9F, 0x5D2F, + 0x8DA0, 0x5D30, 0x8DA1, 0x5D31, 0x8DA2, 0x5D32, 0x8DA3, 0x5D33, 0x8DA4, 0x5D35, 0x8DA5, 0x5D36, 0x8DA6, 0x5D37, 0x8DA7, 0x5D38, + 0x8DA8, 0x5D39, 0x8DA9, 0x5D3A, 0x8DAA, 0x5D3B, 0x8DAB, 0x5D3C, 0x8DAC, 0x5D3F, 0x8DAD, 0x5D40, 0x8DAE, 0x5D41, 0x8DAF, 0x5D42, + 0x8DB0, 0x5D43, 0x8DB1, 0x5D44, 0x8DB2, 0x5D45, 0x8DB3, 0x5D46, 0x8DB4, 0x5D48, 0x8DB5, 0x5D49, 0x8DB6, 0x5D4D, 0x8DB7, 0x5D4E, + 0x8DB8, 0x5D4F, 0x8DB9, 0x5D50, 0x8DBA, 0x5D51, 0x8DBB, 0x5D52, 0x8DBC, 0x5D53, 0x8DBD, 0x5D54, 0x8DBE, 0x5D55, 0x8DBF, 0x5D56, + 0x8DC0, 0x5D57, 0x8DC1, 0x5D59, 0x8DC2, 0x5D5A, 0x8DC3, 0x5D5C, 0x8DC4, 0x5D5E, 0x8DC5, 0x5D5F, 0x8DC6, 0x5D60, 0x8DC7, 0x5D61, + 0x8DC8, 0x5D62, 0x8DC9, 0x5D63, 0x8DCA, 0x5D64, 0x8DCB, 0x5D65, 0x8DCC, 0x5D66, 0x8DCD, 0x5D67, 0x8DCE, 0x5D68, 0x8DCF, 0x5D6A, + 0x8DD0, 0x5D6D, 0x8DD1, 0x5D6E, 0x8DD2, 0x5D70, 0x8DD3, 0x5D71, 0x8DD4, 0x5D72, 0x8DD5, 0x5D73, 0x8DD6, 0x5D75, 0x8DD7, 0x5D76, + 0x8DD8, 0x5D77, 0x8DD9, 0x5D78, 0x8DDA, 0x5D79, 0x8DDB, 0x5D7A, 0x8DDC, 0x5D7B, 0x8DDD, 0x5D7C, 0x8DDE, 0x5D7D, 0x8DDF, 0x5D7E, + 0x8DE0, 0x5D7F, 0x8DE1, 0x5D80, 0x8DE2, 0x5D81, 0x8DE3, 0x5D83, 0x8DE4, 0x5D84, 0x8DE5, 0x5D85, 0x8DE6, 0x5D86, 0x8DE7, 0x5D87, + 0x8DE8, 0x5D88, 0x8DE9, 0x5D89, 0x8DEA, 0x5D8A, 0x8DEB, 0x5D8B, 0x8DEC, 0x5D8C, 0x8DED, 0x5D8D, 0x8DEE, 0x5D8E, 0x8DEF, 0x5D8F, + 0x8DF0, 0x5D90, 0x8DF1, 0x5D91, 0x8DF2, 0x5D92, 0x8DF3, 0x5D93, 0x8DF4, 0x5D94, 0x8DF5, 0x5D95, 0x8DF6, 0x5D96, 0x8DF7, 0x5D97, + 0x8DF8, 0x5D98, 0x8DF9, 0x5D9A, 0x8DFA, 0x5D9B, 0x8DFB, 0x5D9C, 0x8DFC, 0x5D9E, 0x8DFD, 0x5D9F, 0x8DFE, 0x5DA0, 0x8E40, 0x5DA1, + 0x8E41, 0x5DA2, 0x8E42, 0x5DA3, 0x8E43, 0x5DA4, 0x8E44, 0x5DA5, 0x8E45, 0x5DA6, 0x8E46, 0x5DA7, 0x8E47, 0x5DA8, 0x8E48, 0x5DA9, + 0x8E49, 0x5DAA, 0x8E4A, 0x5DAB, 0x8E4B, 0x5DAC, 0x8E4C, 0x5DAD, 0x8E4D, 0x5DAE, 0x8E4E, 0x5DAF, 0x8E4F, 0x5DB0, 0x8E50, 0x5DB1, + 0x8E51, 0x5DB2, 0x8E52, 0x5DB3, 0x8E53, 0x5DB4, 0x8E54, 0x5DB5, 0x8E55, 0x5DB6, 0x8E56, 0x5DB8, 0x8E57, 0x5DB9, 0x8E58, 0x5DBA, + 0x8E59, 0x5DBB, 0x8E5A, 0x5DBC, 0x8E5B, 0x5DBD, 0x8E5C, 0x5DBE, 0x8E5D, 0x5DBF, 0x8E5E, 0x5DC0, 0x8E5F, 0x5DC1, 0x8E60, 0x5DC2, + 0x8E61, 0x5DC3, 0x8E62, 0x5DC4, 0x8E63, 0x5DC6, 0x8E64, 0x5DC7, 0x8E65, 0x5DC8, 0x8E66, 0x5DC9, 0x8E67, 0x5DCA, 0x8E68, 0x5DCB, + 0x8E69, 0x5DCC, 0x8E6A, 0x5DCE, 0x8E6B, 0x5DCF, 0x8E6C, 0x5DD0, 0x8E6D, 0x5DD1, 0x8E6E, 0x5DD2, 0x8E6F, 0x5DD3, 0x8E70, 0x5DD4, + 0x8E71, 0x5DD5, 0x8E72, 0x5DD6, 0x8E73, 0x5DD7, 0x8E74, 0x5DD8, 0x8E75, 0x5DD9, 0x8E76, 0x5DDA, 0x8E77, 0x5DDC, 0x8E78, 0x5DDF, + 0x8E79, 0x5DE0, 0x8E7A, 0x5DE3, 0x8E7B, 0x5DE4, 0x8E7C, 0x5DEA, 0x8E7D, 0x5DEC, 0x8E7E, 0x5DED, 0x8E80, 0x5DF0, 0x8E81, 0x5DF5, + 0x8E82, 0x5DF6, 0x8E83, 0x5DF8, 0x8E84, 0x5DF9, 0x8E85, 0x5DFA, 0x8E86, 0x5DFB, 0x8E87, 0x5DFC, 0x8E88, 0x5DFF, 0x8E89, 0x5E00, + 0x8E8A, 0x5E04, 0x8E8B, 0x5E07, 0x8E8C, 0x5E09, 0x8E8D, 0x5E0A, 0x8E8E, 0x5E0B, 0x8E8F, 0x5E0D, 0x8E90, 0x5E0E, 0x8E91, 0x5E12, + 0x8E92, 0x5E13, 0x8E93, 0x5E17, 0x8E94, 0x5E1E, 0x8E95, 0x5E1F, 0x8E96, 0x5E20, 0x8E97, 0x5E21, 0x8E98, 0x5E22, 0x8E99, 0x5E23, + 0x8E9A, 0x5E24, 0x8E9B, 0x5E25, 0x8E9C, 0x5E28, 0x8E9D, 0x5E29, 0x8E9E, 0x5E2A, 0x8E9F, 0x5E2B, 0x8EA0, 0x5E2C, 0x8EA1, 0x5E2F, + 0x8EA2, 0x5E30, 0x8EA3, 0x5E32, 0x8EA4, 0x5E33, 0x8EA5, 0x5E34, 0x8EA6, 0x5E35, 0x8EA7, 0x5E36, 0x8EA8, 0x5E39, 0x8EA9, 0x5E3A, + 0x8EAA, 0x5E3E, 0x8EAB, 0x5E3F, 0x8EAC, 0x5E40, 0x8EAD, 0x5E41, 0x8EAE, 0x5E43, 0x8EAF, 0x5E46, 0x8EB0, 0x5E47, 0x8EB1, 0x5E48, + 0x8EB2, 0x5E49, 0x8EB3, 0x5E4A, 0x8EB4, 0x5E4B, 0x8EB5, 0x5E4D, 0x8EB6, 0x5E4E, 0x8EB7, 0x5E4F, 0x8EB8, 0x5E50, 0x8EB9, 0x5E51, + 0x8EBA, 0x5E52, 0x8EBB, 0x5E53, 0x8EBC, 0x5E56, 0x8EBD, 0x5E57, 0x8EBE, 0x5E58, 0x8EBF, 0x5E59, 0x8EC0, 0x5E5A, 0x8EC1, 0x5E5C, + 0x8EC2, 0x5E5D, 0x8EC3, 0x5E5F, 0x8EC4, 0x5E60, 0x8EC5, 0x5E63, 0x8EC6, 0x5E64, 0x8EC7, 0x5E65, 0x8EC8, 0x5E66, 0x8EC9, 0x5E67, + 0x8ECA, 0x5E68, 0x8ECB, 0x5E69, 0x8ECC, 0x5E6A, 0x8ECD, 0x5E6B, 0x8ECE, 0x5E6C, 0x8ECF, 0x5E6D, 0x8ED0, 0x5E6E, 0x8ED1, 0x5E6F, + 0x8ED2, 0x5E70, 0x8ED3, 0x5E71, 0x8ED4, 0x5E75, 0x8ED5, 0x5E77, 0x8ED6, 0x5E79, 0x8ED7, 0x5E7E, 0x8ED8, 0x5E81, 0x8ED9, 0x5E82, + 0x8EDA, 0x5E83, 0x8EDB, 0x5E85, 0x8EDC, 0x5E88, 0x8EDD, 0x5E89, 0x8EDE, 0x5E8C, 0x8EDF, 0x5E8D, 0x8EE0, 0x5E8E, 0x8EE1, 0x5E92, + 0x8EE2, 0x5E98, 0x8EE3, 0x5E9B, 0x8EE4, 0x5E9D, 0x8EE5, 0x5EA1, 0x8EE6, 0x5EA2, 0x8EE7, 0x5EA3, 0x8EE8, 0x5EA4, 0x8EE9, 0x5EA8, + 0x8EEA, 0x5EA9, 0x8EEB, 0x5EAA, 0x8EEC, 0x5EAB, 0x8EED, 0x5EAC, 0x8EEE, 0x5EAE, 0x8EEF, 0x5EAF, 0x8EF0, 0x5EB0, 0x8EF1, 0x5EB1, + 0x8EF2, 0x5EB2, 0x8EF3, 0x5EB4, 0x8EF4, 0x5EBA, 0x8EF5, 0x5EBB, 0x8EF6, 0x5EBC, 0x8EF7, 0x5EBD, 0x8EF8, 0x5EBF, 0x8EF9, 0x5EC0, + 0x8EFA, 0x5EC1, 0x8EFB, 0x5EC2, 0x8EFC, 0x5EC3, 0x8EFD, 0x5EC4, 0x8EFE, 0x5EC5, 0x8F40, 0x5EC6, 0x8F41, 0x5EC7, 0x8F42, 0x5EC8, + 0x8F43, 0x5ECB, 0x8F44, 0x5ECC, 0x8F45, 0x5ECD, 0x8F46, 0x5ECE, 0x8F47, 0x5ECF, 0x8F48, 0x5ED0, 0x8F49, 0x5ED4, 0x8F4A, 0x5ED5, + 0x8F4B, 0x5ED7, 0x8F4C, 0x5ED8, 0x8F4D, 0x5ED9, 0x8F4E, 0x5EDA, 0x8F4F, 0x5EDC, 0x8F50, 0x5EDD, 0x8F51, 0x5EDE, 0x8F52, 0x5EDF, + 0x8F53, 0x5EE0, 0x8F54, 0x5EE1, 0x8F55, 0x5EE2, 0x8F56, 0x5EE3, 0x8F57, 0x5EE4, 0x8F58, 0x5EE5, 0x8F59, 0x5EE6, 0x8F5A, 0x5EE7, + 0x8F5B, 0x5EE9, 0x8F5C, 0x5EEB, 0x8F5D, 0x5EEC, 0x8F5E, 0x5EED, 0x8F5F, 0x5EEE, 0x8F60, 0x5EEF, 0x8F61, 0x5EF0, 0x8F62, 0x5EF1, + 0x8F63, 0x5EF2, 0x8F64, 0x5EF3, 0x8F65, 0x5EF5, 0x8F66, 0x5EF8, 0x8F67, 0x5EF9, 0x8F68, 0x5EFB, 0x8F69, 0x5EFC, 0x8F6A, 0x5EFD, + 0x8F6B, 0x5F05, 0x8F6C, 0x5F06, 0x8F6D, 0x5F07, 0x8F6E, 0x5F09, 0x8F6F, 0x5F0C, 0x8F70, 0x5F0D, 0x8F71, 0x5F0E, 0x8F72, 0x5F10, + 0x8F73, 0x5F12, 0x8F74, 0x5F14, 0x8F75, 0x5F16, 0x8F76, 0x5F19, 0x8F77, 0x5F1A, 0x8F78, 0x5F1C, 0x8F79, 0x5F1D, 0x8F7A, 0x5F1E, + 0x8F7B, 0x5F21, 0x8F7C, 0x5F22, 0x8F7D, 0x5F23, 0x8F7E, 0x5F24, 0x8F80, 0x5F28, 0x8F81, 0x5F2B, 0x8F82, 0x5F2C, 0x8F83, 0x5F2E, + 0x8F84, 0x5F30, 0x8F85, 0x5F32, 0x8F86, 0x5F33, 0x8F87, 0x5F34, 0x8F88, 0x5F35, 0x8F89, 0x5F36, 0x8F8A, 0x5F37, 0x8F8B, 0x5F38, + 0x8F8C, 0x5F3B, 0x8F8D, 0x5F3D, 0x8F8E, 0x5F3E, 0x8F8F, 0x5F3F, 0x8F90, 0x5F41, 0x8F91, 0x5F42, 0x8F92, 0x5F43, 0x8F93, 0x5F44, + 0x8F94, 0x5F45, 0x8F95, 0x5F46, 0x8F96, 0x5F47, 0x8F97, 0x5F48, 0x8F98, 0x5F49, 0x8F99, 0x5F4A, 0x8F9A, 0x5F4B, 0x8F9B, 0x5F4C, + 0x8F9C, 0x5F4D, 0x8F9D, 0x5F4E, 0x8F9E, 0x5F4F, 0x8F9F, 0x5F51, 0x8FA0, 0x5F54, 0x8FA1, 0x5F59, 0x8FA2, 0x5F5A, 0x8FA3, 0x5F5B, + 0x8FA4, 0x5F5C, 0x8FA5, 0x5F5E, 0x8FA6, 0x5F5F, 0x8FA7, 0x5F60, 0x8FA8, 0x5F63, 0x8FA9, 0x5F65, 0x8FAA, 0x5F67, 0x8FAB, 0x5F68, + 0x8FAC, 0x5F6B, 0x8FAD, 0x5F6E, 0x8FAE, 0x5F6F, 0x8FAF, 0x5F72, 0x8FB0, 0x5F74, 0x8FB1, 0x5F75, 0x8FB2, 0x5F76, 0x8FB3, 0x5F78, + 0x8FB4, 0x5F7A, 0x8FB5, 0x5F7D, 0x8FB6, 0x5F7E, 0x8FB7, 0x5F7F, 0x8FB8, 0x5F83, 0x8FB9, 0x5F86, 0x8FBA, 0x5F8D, 0x8FBB, 0x5F8E, + 0x8FBC, 0x5F8F, 0x8FBD, 0x5F91, 0x8FBE, 0x5F93, 0x8FBF, 0x5F94, 0x8FC0, 0x5F96, 0x8FC1, 0x5F9A, 0x8FC2, 0x5F9B, 0x8FC3, 0x5F9D, + 0x8FC4, 0x5F9E, 0x8FC5, 0x5F9F, 0x8FC6, 0x5FA0, 0x8FC7, 0x5FA2, 0x8FC8, 0x5FA3, 0x8FC9, 0x5FA4, 0x8FCA, 0x5FA5, 0x8FCB, 0x5FA6, + 0x8FCC, 0x5FA7, 0x8FCD, 0x5FA9, 0x8FCE, 0x5FAB, 0x8FCF, 0x5FAC, 0x8FD0, 0x5FAF, 0x8FD1, 0x5FB0, 0x8FD2, 0x5FB1, 0x8FD3, 0x5FB2, + 0x8FD4, 0x5FB3, 0x8FD5, 0x5FB4, 0x8FD6, 0x5FB6, 0x8FD7, 0x5FB8, 0x8FD8, 0x5FB9, 0x8FD9, 0x5FBA, 0x8FDA, 0x5FBB, 0x8FDB, 0x5FBE, + 0x8FDC, 0x5FBF, 0x8FDD, 0x5FC0, 0x8FDE, 0x5FC1, 0x8FDF, 0x5FC2, 0x8FE0, 0x5FC7, 0x8FE1, 0x5FC8, 0x8FE2, 0x5FCA, 0x8FE3, 0x5FCB, + 0x8FE4, 0x5FCE, 0x8FE5, 0x5FD3, 0x8FE6, 0x5FD4, 0x8FE7, 0x5FD5, 0x8FE8, 0x5FDA, 0x8FE9, 0x5FDB, 0x8FEA, 0x5FDC, 0x8FEB, 0x5FDE, + 0x8FEC, 0x5FDF, 0x8FED, 0x5FE2, 0x8FEE, 0x5FE3, 0x8FEF, 0x5FE5, 0x8FF0, 0x5FE6, 0x8FF1, 0x5FE8, 0x8FF2, 0x5FE9, 0x8FF3, 0x5FEC, + 0x8FF4, 0x5FEF, 0x8FF5, 0x5FF0, 0x8FF6, 0x5FF2, 0x8FF7, 0x5FF3, 0x8FF8, 0x5FF4, 0x8FF9, 0x5FF6, 0x8FFA, 0x5FF7, 0x8FFB, 0x5FF9, + 0x8FFC, 0x5FFA, 0x8FFD, 0x5FFC, 0x8FFE, 0x6007, 0x9040, 0x6008, 0x9041, 0x6009, 0x9042, 0x600B, 0x9043, 0x600C, 0x9044, 0x6010, + 0x9045, 0x6011, 0x9046, 0x6013, 0x9047, 0x6017, 0x9048, 0x6018, 0x9049, 0x601A, 0x904A, 0x601E, 0x904B, 0x601F, 0x904C, 0x6022, + 0x904D, 0x6023, 0x904E, 0x6024, 0x904F, 0x602C, 0x9050, 0x602D, 0x9051, 0x602E, 0x9052, 0x6030, 0x9053, 0x6031, 0x9054, 0x6032, + 0x9055, 0x6033, 0x9056, 0x6034, 0x9057, 0x6036, 0x9058, 0x6037, 0x9059, 0x6038, 0x905A, 0x6039, 0x905B, 0x603A, 0x905C, 0x603D, + 0x905D, 0x603E, 0x905E, 0x6040, 0x905F, 0x6044, 0x9060, 0x6045, 0x9061, 0x6046, 0x9062, 0x6047, 0x9063, 0x6048, 0x9064, 0x6049, + 0x9065, 0x604A, 0x9066, 0x604C, 0x9067, 0x604E, 0x9068, 0x604F, 0x9069, 0x6051, 0x906A, 0x6053, 0x906B, 0x6054, 0x906C, 0x6056, + 0x906D, 0x6057, 0x906E, 0x6058, 0x906F, 0x605B, 0x9070, 0x605C, 0x9071, 0x605E, 0x9072, 0x605F, 0x9073, 0x6060, 0x9074, 0x6061, + 0x9075, 0x6065, 0x9076, 0x6066, 0x9077, 0x606E, 0x9078, 0x6071, 0x9079, 0x6072, 0x907A, 0x6074, 0x907B, 0x6075, 0x907C, 0x6077, + 0x907D, 0x607E, 0x907E, 0x6080, 0x9080, 0x6081, 0x9081, 0x6082, 0x9082, 0x6085, 0x9083, 0x6086, 0x9084, 0x6087, 0x9085, 0x6088, + 0x9086, 0x608A, 0x9087, 0x608B, 0x9088, 0x608E, 0x9089, 0x608F, 0x908A, 0x6090, 0x908B, 0x6091, 0x908C, 0x6093, 0x908D, 0x6095, + 0x908E, 0x6097, 0x908F, 0x6098, 0x9090, 0x6099, 0x9091, 0x609C, 0x9092, 0x609E, 0x9093, 0x60A1, 0x9094, 0x60A2, 0x9095, 0x60A4, + 0x9096, 0x60A5, 0x9097, 0x60A7, 0x9098, 0x60A9, 0x9099, 0x60AA, 0x909A, 0x60AE, 0x909B, 0x60B0, 0x909C, 0x60B3, 0x909D, 0x60B5, + 0x909E, 0x60B6, 0x909F, 0x60B7, 0x90A0, 0x60B9, 0x90A1, 0x60BA, 0x90A2, 0x60BD, 0x90A3, 0x60BE, 0x90A4, 0x60BF, 0x90A5, 0x60C0, + 0x90A6, 0x60C1, 0x90A7, 0x60C2, 0x90A8, 0x60C3, 0x90A9, 0x60C4, 0x90AA, 0x60C7, 0x90AB, 0x60C8, 0x90AC, 0x60C9, 0x90AD, 0x60CC, + 0x90AE, 0x60CD, 0x90AF, 0x60CE, 0x90B0, 0x60CF, 0x90B1, 0x60D0, 0x90B2, 0x60D2, 0x90B3, 0x60D3, 0x90B4, 0x60D4, 0x90B5, 0x60D6, + 0x90B6, 0x60D7, 0x90B7, 0x60D9, 0x90B8, 0x60DB, 0x90B9, 0x60DE, 0x90BA, 0x60E1, 0x90BB, 0x60E2, 0x90BC, 0x60E3, 0x90BD, 0x60E4, + 0x90BE, 0x60E5, 0x90BF, 0x60EA, 0x90C0, 0x60F1, 0x90C1, 0x60F2, 0x90C2, 0x60F5, 0x90C3, 0x60F7, 0x90C4, 0x60F8, 0x90C5, 0x60FB, + 0x90C6, 0x60FC, 0x90C7, 0x60FD, 0x90C8, 0x60FE, 0x90C9, 0x60FF, 0x90CA, 0x6102, 0x90CB, 0x6103, 0x90CC, 0x6104, 0x90CD, 0x6105, + 0x90CE, 0x6107, 0x90CF, 0x610A, 0x90D0, 0x610B, 0x90D1, 0x610C, 0x90D2, 0x6110, 0x90D3, 0x6111, 0x90D4, 0x6112, 0x90D5, 0x6113, + 0x90D6, 0x6114, 0x90D7, 0x6116, 0x90D8, 0x6117, 0x90D9, 0x6118, 0x90DA, 0x6119, 0x90DB, 0x611B, 0x90DC, 0x611C, 0x90DD, 0x611D, + 0x90DE, 0x611E, 0x90DF, 0x6121, 0x90E0, 0x6122, 0x90E1, 0x6125, 0x90E2, 0x6128, 0x90E3, 0x6129, 0x90E4, 0x612A, 0x90E5, 0x612C, + 0x90E6, 0x612D, 0x90E7, 0x612E, 0x90E8, 0x612F, 0x90E9, 0x6130, 0x90EA, 0x6131, 0x90EB, 0x6132, 0x90EC, 0x6133, 0x90ED, 0x6134, + 0x90EE, 0x6135, 0x90EF, 0x6136, 0x90F0, 0x6137, 0x90F1, 0x6138, 0x90F2, 0x6139, 0x90F3, 0x613A, 0x90F4, 0x613B, 0x90F5, 0x613C, + 0x90F6, 0x613D, 0x90F7, 0x613E, 0x90F8, 0x6140, 0x90F9, 0x6141, 0x90FA, 0x6142, 0x90FB, 0x6143, 0x90FC, 0x6144, 0x90FD, 0x6145, + 0x90FE, 0x6146, 0x9140, 0x6147, 0x9141, 0x6149, 0x9142, 0x614B, 0x9143, 0x614D, 0x9144, 0x614F, 0x9145, 0x6150, 0x9146, 0x6152, + 0x9147, 0x6153, 0x9148, 0x6154, 0x9149, 0x6156, 0x914A, 0x6157, 0x914B, 0x6158, 0x914C, 0x6159, 0x914D, 0x615A, 0x914E, 0x615B, + 0x914F, 0x615C, 0x9150, 0x615E, 0x9151, 0x615F, 0x9152, 0x6160, 0x9153, 0x6161, 0x9154, 0x6163, 0x9155, 0x6164, 0x9156, 0x6165, + 0x9157, 0x6166, 0x9158, 0x6169, 0x9159, 0x616A, 0x915A, 0x616B, 0x915B, 0x616C, 0x915C, 0x616D, 0x915D, 0x616E, 0x915E, 0x616F, + 0x915F, 0x6171, 0x9160, 0x6172, 0x9161, 0x6173, 0x9162, 0x6174, 0x9163, 0x6176, 0x9164, 0x6178, 0x9165, 0x6179, 0x9166, 0x617A, + 0x9167, 0x617B, 0x9168, 0x617C, 0x9169, 0x617D, 0x916A, 0x617E, 0x916B, 0x617F, 0x916C, 0x6180, 0x916D, 0x6181, 0x916E, 0x6182, + 0x916F, 0x6183, 0x9170, 0x6184, 0x9171, 0x6185, 0x9172, 0x6186, 0x9173, 0x6187, 0x9174, 0x6188, 0x9175, 0x6189, 0x9176, 0x618A, + 0x9177, 0x618C, 0x9178, 0x618D, 0x9179, 0x618F, 0x917A, 0x6190, 0x917B, 0x6191, 0x917C, 0x6192, 0x917D, 0x6193, 0x917E, 0x6195, + 0x9180, 0x6196, 0x9181, 0x6197, 0x9182, 0x6198, 0x9183, 0x6199, 0x9184, 0x619A, 0x9185, 0x619B, 0x9186, 0x619C, 0x9187, 0x619E, + 0x9188, 0x619F, 0x9189, 0x61A0, 0x918A, 0x61A1, 0x918B, 0x61A2, 0x918C, 0x61A3, 0x918D, 0x61A4, 0x918E, 0x61A5, 0x918F, 0x61A6, + 0x9190, 0x61AA, 0x9191, 0x61AB, 0x9192, 0x61AD, 0x9193, 0x61AE, 0x9194, 0x61AF, 0x9195, 0x61B0, 0x9196, 0x61B1, 0x9197, 0x61B2, + 0x9198, 0x61B3, 0x9199, 0x61B4, 0x919A, 0x61B5, 0x919B, 0x61B6, 0x919C, 0x61B8, 0x919D, 0x61B9, 0x919E, 0x61BA, 0x919F, 0x61BB, + 0x91A0, 0x61BC, 0x91A1, 0x61BD, 0x91A2, 0x61BF, 0x91A3, 0x61C0, 0x91A4, 0x61C1, 0x91A5, 0x61C3, 0x91A6, 0x61C4, 0x91A7, 0x61C5, + 0x91A8, 0x61C6, 0x91A9, 0x61C7, 0x91AA, 0x61C9, 0x91AB, 0x61CC, 0x91AC, 0x61CD, 0x91AD, 0x61CE, 0x91AE, 0x61CF, 0x91AF, 0x61D0, + 0x91B0, 0x61D3, 0x91B1, 0x61D5, 0x91B2, 0x61D6, 0x91B3, 0x61D7, 0x91B4, 0x61D8, 0x91B5, 0x61D9, 0x91B6, 0x61DA, 0x91B7, 0x61DB, + 0x91B8, 0x61DC, 0x91B9, 0x61DD, 0x91BA, 0x61DE, 0x91BB, 0x61DF, 0x91BC, 0x61E0, 0x91BD, 0x61E1, 0x91BE, 0x61E2, 0x91BF, 0x61E3, + 0x91C0, 0x61E4, 0x91C1, 0x61E5, 0x91C2, 0x61E7, 0x91C3, 0x61E8, 0x91C4, 0x61E9, 0x91C5, 0x61EA, 0x91C6, 0x61EB, 0x91C7, 0x61EC, + 0x91C8, 0x61ED, 0x91C9, 0x61EE, 0x91CA, 0x61EF, 0x91CB, 0x61F0, 0x91CC, 0x61F1, 0x91CD, 0x61F2, 0x91CE, 0x61F3, 0x91CF, 0x61F4, + 0x91D0, 0x61F6, 0x91D1, 0x61F7, 0x91D2, 0x61F8, 0x91D3, 0x61F9, 0x91D4, 0x61FA, 0x91D5, 0x61FB, 0x91D6, 0x61FC, 0x91D7, 0x61FD, + 0x91D8, 0x61FE, 0x91D9, 0x6200, 0x91DA, 0x6201, 0x91DB, 0x6202, 0x91DC, 0x6203, 0x91DD, 0x6204, 0x91DE, 0x6205, 0x91DF, 0x6207, + 0x91E0, 0x6209, 0x91E1, 0x6213, 0x91E2, 0x6214, 0x91E3, 0x6219, 0x91E4, 0x621C, 0x91E5, 0x621D, 0x91E6, 0x621E, 0x91E7, 0x6220, + 0x91E8, 0x6223, 0x91E9, 0x6226, 0x91EA, 0x6227, 0x91EB, 0x6228, 0x91EC, 0x6229, 0x91ED, 0x622B, 0x91EE, 0x622D, 0x91EF, 0x622F, + 0x91F0, 0x6230, 0x91F1, 0x6231, 0x91F2, 0x6232, 0x91F3, 0x6235, 0x91F4, 0x6236, 0x91F5, 0x6238, 0x91F6, 0x6239, 0x91F7, 0x623A, + 0x91F8, 0x623B, 0x91F9, 0x623C, 0x91FA, 0x6242, 0x91FB, 0x6244, 0x91FC, 0x6245, 0x91FD, 0x6246, 0x91FE, 0x624A, 0x9240, 0x624F, + 0x9241, 0x6250, 0x9242, 0x6255, 0x9243, 0x6256, 0x9244, 0x6257, 0x9245, 0x6259, 0x9246, 0x625A, 0x9247, 0x625C, 0x9248, 0x625D, + 0x9249, 0x625E, 0x924A, 0x625F, 0x924B, 0x6260, 0x924C, 0x6261, 0x924D, 0x6262, 0x924E, 0x6264, 0x924F, 0x6265, 0x9250, 0x6268, + 0x9251, 0x6271, 0x9252, 0x6272, 0x9253, 0x6274, 0x9254, 0x6275, 0x9255, 0x6277, 0x9256, 0x6278, 0x9257, 0x627A, 0x9258, 0x627B, + 0x9259, 0x627D, 0x925A, 0x6281, 0x925B, 0x6282, 0x925C, 0x6283, 0x925D, 0x6285, 0x925E, 0x6286, 0x925F, 0x6287, 0x9260, 0x6288, + 0x9261, 0x628B, 0x9262, 0x628C, 0x9263, 0x628D, 0x9264, 0x628E, 0x9265, 0x628F, 0x9266, 0x6290, 0x9267, 0x6294, 0x9268, 0x6299, + 0x9269, 0x629C, 0x926A, 0x629D, 0x926B, 0x629E, 0x926C, 0x62A3, 0x926D, 0x62A6, 0x926E, 0x62A7, 0x926F, 0x62A9, 0x9270, 0x62AA, + 0x9271, 0x62AD, 0x9272, 0x62AE, 0x9273, 0x62AF, 0x9274, 0x62B0, 0x9275, 0x62B2, 0x9276, 0x62B3, 0x9277, 0x62B4, 0x9278, 0x62B6, + 0x9279, 0x62B7, 0x927A, 0x62B8, 0x927B, 0x62BA, 0x927C, 0x62BE, 0x927D, 0x62C0, 0x927E, 0x62C1, 0x9280, 0x62C3, 0x9281, 0x62CB, + 0x9282, 0x62CF, 0x9283, 0x62D1, 0x9284, 0x62D5, 0x9285, 0x62DD, 0x9286, 0x62DE, 0x9287, 0x62E0, 0x9288, 0x62E1, 0x9289, 0x62E4, + 0x928A, 0x62EA, 0x928B, 0x62EB, 0x928C, 0x62F0, 0x928D, 0x62F2, 0x928E, 0x62F5, 0x928F, 0x62F8, 0x9290, 0x62F9, 0x9291, 0x62FA, + 0x9292, 0x62FB, 0x9293, 0x6300, 0x9294, 0x6303, 0x9295, 0x6304, 0x9296, 0x6305, 0x9297, 0x6306, 0x9298, 0x630A, 0x9299, 0x630B, + 0x929A, 0x630C, 0x929B, 0x630D, 0x929C, 0x630F, 0x929D, 0x6310, 0x929E, 0x6312, 0x929F, 0x6313, 0x92A0, 0x6314, 0x92A1, 0x6315, + 0x92A2, 0x6317, 0x92A3, 0x6318, 0x92A4, 0x6319, 0x92A5, 0x631C, 0x92A6, 0x6326, 0x92A7, 0x6327, 0x92A8, 0x6329, 0x92A9, 0x632C, + 0x92AA, 0x632D, 0x92AB, 0x632E, 0x92AC, 0x6330, 0x92AD, 0x6331, 0x92AE, 0x6333, 0x92AF, 0x6334, 0x92B0, 0x6335, 0x92B1, 0x6336, + 0x92B2, 0x6337, 0x92B3, 0x6338, 0x92B4, 0x633B, 0x92B5, 0x633C, 0x92B6, 0x633E, 0x92B7, 0x633F, 0x92B8, 0x6340, 0x92B9, 0x6341, + 0x92BA, 0x6344, 0x92BB, 0x6347, 0x92BC, 0x6348, 0x92BD, 0x634A, 0x92BE, 0x6351, 0x92BF, 0x6352, 0x92C0, 0x6353, 0x92C1, 0x6354, + 0x92C2, 0x6356, 0x92C3, 0x6357, 0x92C4, 0x6358, 0x92C5, 0x6359, 0x92C6, 0x635A, 0x92C7, 0x635B, 0x92C8, 0x635C, 0x92C9, 0x635D, + 0x92CA, 0x6360, 0x92CB, 0x6364, 0x92CC, 0x6365, 0x92CD, 0x6366, 0x92CE, 0x6368, 0x92CF, 0x636A, 0x92D0, 0x636B, 0x92D1, 0x636C, + 0x92D2, 0x636F, 0x92D3, 0x6370, 0x92D4, 0x6372, 0x92D5, 0x6373, 0x92D6, 0x6374, 0x92D7, 0x6375, 0x92D8, 0x6378, 0x92D9, 0x6379, + 0x92DA, 0x637C, 0x92DB, 0x637D, 0x92DC, 0x637E, 0x92DD, 0x637F, 0x92DE, 0x6381, 0x92DF, 0x6383, 0x92E0, 0x6384, 0x92E1, 0x6385, + 0x92E2, 0x6386, 0x92E3, 0x638B, 0x92E4, 0x638D, 0x92E5, 0x6391, 0x92E6, 0x6393, 0x92E7, 0x6394, 0x92E8, 0x6395, 0x92E9, 0x6397, + 0x92EA, 0x6399, 0x92EB, 0x639A, 0x92EC, 0x639B, 0x92ED, 0x639C, 0x92EE, 0x639D, 0x92EF, 0x639E, 0x92F0, 0x639F, 0x92F1, 0x63A1, + 0x92F2, 0x63A4, 0x92F3, 0x63A6, 0x92F4, 0x63AB, 0x92F5, 0x63AF, 0x92F6, 0x63B1, 0x92F7, 0x63B2, 0x92F8, 0x63B5, 0x92F9, 0x63B6, + 0x92FA, 0x63B9, 0x92FB, 0x63BB, 0x92FC, 0x63BD, 0x92FD, 0x63BF, 0x92FE, 0x63C0, 0x9340, 0x63C1, 0x9341, 0x63C2, 0x9342, 0x63C3, + 0x9343, 0x63C5, 0x9344, 0x63C7, 0x9345, 0x63C8, 0x9346, 0x63CA, 0x9347, 0x63CB, 0x9348, 0x63CC, 0x9349, 0x63D1, 0x934A, 0x63D3, + 0x934B, 0x63D4, 0x934C, 0x63D5, 0x934D, 0x63D7, 0x934E, 0x63D8, 0x934F, 0x63D9, 0x9350, 0x63DA, 0x9351, 0x63DB, 0x9352, 0x63DC, + 0x9353, 0x63DD, 0x9354, 0x63DF, 0x9355, 0x63E2, 0x9356, 0x63E4, 0x9357, 0x63E5, 0x9358, 0x63E6, 0x9359, 0x63E7, 0x935A, 0x63E8, + 0x935B, 0x63EB, 0x935C, 0x63EC, 0x935D, 0x63EE, 0x935E, 0x63EF, 0x935F, 0x63F0, 0x9360, 0x63F1, 0x9361, 0x63F3, 0x9362, 0x63F5, + 0x9363, 0x63F7, 0x9364, 0x63F9, 0x9365, 0x63FA, 0x9366, 0x63FB, 0x9367, 0x63FC, 0x9368, 0x63FE, 0x9369, 0x6403, 0x936A, 0x6404, + 0x936B, 0x6406, 0x936C, 0x6407, 0x936D, 0x6408, 0x936E, 0x6409, 0x936F, 0x640A, 0x9370, 0x640D, 0x9371, 0x640E, 0x9372, 0x6411, + 0x9373, 0x6412, 0x9374, 0x6415, 0x9375, 0x6416, 0x9376, 0x6417, 0x9377, 0x6418, 0x9378, 0x6419, 0x9379, 0x641A, 0x937A, 0x641D, + 0x937B, 0x641F, 0x937C, 0x6422, 0x937D, 0x6423, 0x937E, 0x6424, 0x9380, 0x6425, 0x9381, 0x6427, 0x9382, 0x6428, 0x9383, 0x6429, + 0x9384, 0x642B, 0x9385, 0x642E, 0x9386, 0x642F, 0x9387, 0x6430, 0x9388, 0x6431, 0x9389, 0x6432, 0x938A, 0x6433, 0x938B, 0x6435, + 0x938C, 0x6436, 0x938D, 0x6437, 0x938E, 0x6438, 0x938F, 0x6439, 0x9390, 0x643B, 0x9391, 0x643C, 0x9392, 0x643E, 0x9393, 0x6440, + 0x9394, 0x6442, 0x9395, 0x6443, 0x9396, 0x6449, 0x9397, 0x644B, 0x9398, 0x644C, 0x9399, 0x644D, 0x939A, 0x644E, 0x939B, 0x644F, + 0x939C, 0x6450, 0x939D, 0x6451, 0x939E, 0x6453, 0x939F, 0x6455, 0x93A0, 0x6456, 0x93A1, 0x6457, 0x93A2, 0x6459, 0x93A3, 0x645A, + 0x93A4, 0x645B, 0x93A5, 0x645C, 0x93A6, 0x645D, 0x93A7, 0x645F, 0x93A8, 0x6460, 0x93A9, 0x6461, 0x93AA, 0x6462, 0x93AB, 0x6463, + 0x93AC, 0x6464, 0x93AD, 0x6465, 0x93AE, 0x6466, 0x93AF, 0x6468, 0x93B0, 0x646A, 0x93B1, 0x646B, 0x93B2, 0x646C, 0x93B3, 0x646E, + 0x93B4, 0x646F, 0x93B5, 0x6470, 0x93B6, 0x6471, 0x93B7, 0x6472, 0x93B8, 0x6473, 0x93B9, 0x6474, 0x93BA, 0x6475, 0x93BB, 0x6476, + 0x93BC, 0x6477, 0x93BD, 0x647B, 0x93BE, 0x647C, 0x93BF, 0x647D, 0x93C0, 0x647E, 0x93C1, 0x647F, 0x93C2, 0x6480, 0x93C3, 0x6481, + 0x93C4, 0x6483, 0x93C5, 0x6486, 0x93C6, 0x6488, 0x93C7, 0x6489, 0x93C8, 0x648A, 0x93C9, 0x648B, 0x93CA, 0x648C, 0x93CB, 0x648D, + 0x93CC, 0x648E, 0x93CD, 0x648F, 0x93CE, 0x6490, 0x93CF, 0x6493, 0x93D0, 0x6494, 0x93D1, 0x6497, 0x93D2, 0x6498, 0x93D3, 0x649A, + 0x93D4, 0x649B, 0x93D5, 0x649C, 0x93D6, 0x649D, 0x93D7, 0x649F, 0x93D8, 0x64A0, 0x93D9, 0x64A1, 0x93DA, 0x64A2, 0x93DB, 0x64A3, + 0x93DC, 0x64A5, 0x93DD, 0x64A6, 0x93DE, 0x64A7, 0x93DF, 0x64A8, 0x93E0, 0x64AA, 0x93E1, 0x64AB, 0x93E2, 0x64AF, 0x93E3, 0x64B1, + 0x93E4, 0x64B2, 0x93E5, 0x64B3, 0x93E6, 0x64B4, 0x93E7, 0x64B6, 0x93E8, 0x64B9, 0x93E9, 0x64BB, 0x93EA, 0x64BD, 0x93EB, 0x64BE, + 0x93EC, 0x64BF, 0x93ED, 0x64C1, 0x93EE, 0x64C3, 0x93EF, 0x64C4, 0x93F0, 0x64C6, 0x93F1, 0x64C7, 0x93F2, 0x64C8, 0x93F3, 0x64C9, + 0x93F4, 0x64CA, 0x93F5, 0x64CB, 0x93F6, 0x64CC, 0x93F7, 0x64CF, 0x93F8, 0x64D1, 0x93F9, 0x64D3, 0x93FA, 0x64D4, 0x93FB, 0x64D5, + 0x93FC, 0x64D6, 0x93FD, 0x64D9, 0x93FE, 0x64DA, 0x9440, 0x64DB, 0x9441, 0x64DC, 0x9442, 0x64DD, 0x9443, 0x64DF, 0x9444, 0x64E0, + 0x9445, 0x64E1, 0x9446, 0x64E3, 0x9447, 0x64E5, 0x9448, 0x64E7, 0x9449, 0x64E8, 0x944A, 0x64E9, 0x944B, 0x64EA, 0x944C, 0x64EB, + 0x944D, 0x64EC, 0x944E, 0x64ED, 0x944F, 0x64EE, 0x9450, 0x64EF, 0x9451, 0x64F0, 0x9452, 0x64F1, 0x9453, 0x64F2, 0x9454, 0x64F3, + 0x9455, 0x64F4, 0x9456, 0x64F5, 0x9457, 0x64F6, 0x9458, 0x64F7, 0x9459, 0x64F8, 0x945A, 0x64F9, 0x945B, 0x64FA, 0x945C, 0x64FB, + 0x945D, 0x64FC, 0x945E, 0x64FD, 0x945F, 0x64FE, 0x9460, 0x64FF, 0x9461, 0x6501, 0x9462, 0x6502, 0x9463, 0x6503, 0x9464, 0x6504, + 0x9465, 0x6505, 0x9466, 0x6506, 0x9467, 0x6507, 0x9468, 0x6508, 0x9469, 0x650A, 0x946A, 0x650B, 0x946B, 0x650C, 0x946C, 0x650D, + 0x946D, 0x650E, 0x946E, 0x650F, 0x946F, 0x6510, 0x9470, 0x6511, 0x9471, 0x6513, 0x9472, 0x6514, 0x9473, 0x6515, 0x9474, 0x6516, + 0x9475, 0x6517, 0x9476, 0x6519, 0x9477, 0x651A, 0x9478, 0x651B, 0x9479, 0x651C, 0x947A, 0x651D, 0x947B, 0x651E, 0x947C, 0x651F, + 0x947D, 0x6520, 0x947E, 0x6521, 0x9480, 0x6522, 0x9481, 0x6523, 0x9482, 0x6524, 0x9483, 0x6526, 0x9484, 0x6527, 0x9485, 0x6528, + 0x9486, 0x6529, 0x9487, 0x652A, 0x9488, 0x652C, 0x9489, 0x652D, 0x948A, 0x6530, 0x948B, 0x6531, 0x948C, 0x6532, 0x948D, 0x6533, + 0x948E, 0x6537, 0x948F, 0x653A, 0x9490, 0x653C, 0x9491, 0x653D, 0x9492, 0x6540, 0x9493, 0x6541, 0x9494, 0x6542, 0x9495, 0x6543, + 0x9496, 0x6544, 0x9497, 0x6546, 0x9498, 0x6547, 0x9499, 0x654A, 0x949A, 0x654B, 0x949B, 0x654D, 0x949C, 0x654E, 0x949D, 0x6550, + 0x949E, 0x6552, 0x949F, 0x6553, 0x94A0, 0x6554, 0x94A1, 0x6557, 0x94A2, 0x6558, 0x94A3, 0x655A, 0x94A4, 0x655C, 0x94A5, 0x655F, + 0x94A6, 0x6560, 0x94A7, 0x6561, 0x94A8, 0x6564, 0x94A9, 0x6565, 0x94AA, 0x6567, 0x94AB, 0x6568, 0x94AC, 0x6569, 0x94AD, 0x656A, + 0x94AE, 0x656D, 0x94AF, 0x656E, 0x94B0, 0x656F, 0x94B1, 0x6571, 0x94B2, 0x6573, 0x94B3, 0x6575, 0x94B4, 0x6576, 0x94B5, 0x6578, + 0x94B6, 0x6579, 0x94B7, 0x657A, 0x94B8, 0x657B, 0x94B9, 0x657C, 0x94BA, 0x657D, 0x94BB, 0x657E, 0x94BC, 0x657F, 0x94BD, 0x6580, + 0x94BE, 0x6581, 0x94BF, 0x6582, 0x94C0, 0x6583, 0x94C1, 0x6584, 0x94C2, 0x6585, 0x94C3, 0x6586, 0x94C4, 0x6588, 0x94C5, 0x6589, + 0x94C6, 0x658A, 0x94C7, 0x658D, 0x94C8, 0x658E, 0x94C9, 0x658F, 0x94CA, 0x6592, 0x94CB, 0x6594, 0x94CC, 0x6595, 0x94CD, 0x6596, + 0x94CE, 0x6598, 0x94CF, 0x659A, 0x94D0, 0x659D, 0x94D1, 0x659E, 0x94D2, 0x65A0, 0x94D3, 0x65A2, 0x94D4, 0x65A3, 0x94D5, 0x65A6, + 0x94D6, 0x65A8, 0x94D7, 0x65AA, 0x94D8, 0x65AC, 0x94D9, 0x65AE, 0x94DA, 0x65B1, 0x94DB, 0x65B2, 0x94DC, 0x65B3, 0x94DD, 0x65B4, + 0x94DE, 0x65B5, 0x94DF, 0x65B6, 0x94E0, 0x65B7, 0x94E1, 0x65B8, 0x94E2, 0x65BA, 0x94E3, 0x65BB, 0x94E4, 0x65BE, 0x94E5, 0x65BF, + 0x94E6, 0x65C0, 0x94E7, 0x65C2, 0x94E8, 0x65C7, 0x94E9, 0x65C8, 0x94EA, 0x65C9, 0x94EB, 0x65CA, 0x94EC, 0x65CD, 0x94ED, 0x65D0, + 0x94EE, 0x65D1, 0x94EF, 0x65D3, 0x94F0, 0x65D4, 0x94F1, 0x65D5, 0x94F2, 0x65D8, 0x94F3, 0x65D9, 0x94F4, 0x65DA, 0x94F5, 0x65DB, + 0x94F6, 0x65DC, 0x94F7, 0x65DD, 0x94F8, 0x65DE, 0x94F9, 0x65DF, 0x94FA, 0x65E1, 0x94FB, 0x65E3, 0x94FC, 0x65E4, 0x94FD, 0x65EA, + 0x94FE, 0x65EB, 0x9540, 0x65F2, 0x9541, 0x65F3, 0x9542, 0x65F4, 0x9543, 0x65F5, 0x9544, 0x65F8, 0x9545, 0x65F9, 0x9546, 0x65FB, + 0x9547, 0x65FC, 0x9548, 0x65FD, 0x9549, 0x65FE, 0x954A, 0x65FF, 0x954B, 0x6601, 0x954C, 0x6604, 0x954D, 0x6605, 0x954E, 0x6607, + 0x954F, 0x6608, 0x9550, 0x6609, 0x9551, 0x660B, 0x9552, 0x660D, 0x9553, 0x6610, 0x9554, 0x6611, 0x9555, 0x6612, 0x9556, 0x6616, + 0x9557, 0x6617, 0x9558, 0x6618, 0x9559, 0x661A, 0x955A, 0x661B, 0x955B, 0x661C, 0x955C, 0x661E, 0x955D, 0x6621, 0x955E, 0x6622, + 0x955F, 0x6623, 0x9560, 0x6624, 0x9561, 0x6626, 0x9562, 0x6629, 0x9563, 0x662A, 0x9564, 0x662B, 0x9565, 0x662C, 0x9566, 0x662E, + 0x9567, 0x6630, 0x9568, 0x6632, 0x9569, 0x6633, 0x956A, 0x6637, 0x956B, 0x6638, 0x956C, 0x6639, 0x956D, 0x663A, 0x956E, 0x663B, + 0x956F, 0x663D, 0x9570, 0x663F, 0x9571, 0x6640, 0x9572, 0x6642, 0x9573, 0x6644, 0x9574, 0x6645, 0x9575, 0x6646, 0x9576, 0x6647, + 0x9577, 0x6648, 0x9578, 0x6649, 0x9579, 0x664A, 0x957A, 0x664D, 0x957B, 0x664E, 0x957C, 0x6650, 0x957D, 0x6651, 0x957E, 0x6658, + 0x9580, 0x6659, 0x9581, 0x665B, 0x9582, 0x665C, 0x9583, 0x665D, 0x9584, 0x665E, 0x9585, 0x6660, 0x9586, 0x6662, 0x9587, 0x6663, + 0x9588, 0x6665, 0x9589, 0x6667, 0x958A, 0x6669, 0x958B, 0x666A, 0x958C, 0x666B, 0x958D, 0x666C, 0x958E, 0x666D, 0x958F, 0x6671, + 0x9590, 0x6672, 0x9591, 0x6673, 0x9592, 0x6675, 0x9593, 0x6678, 0x9594, 0x6679, 0x9595, 0x667B, 0x9596, 0x667C, 0x9597, 0x667D, + 0x9598, 0x667F, 0x9599, 0x6680, 0x959A, 0x6681, 0x959B, 0x6683, 0x959C, 0x6685, 0x959D, 0x6686, 0x959E, 0x6688, 0x959F, 0x6689, + 0x95A0, 0x668A, 0x95A1, 0x668B, 0x95A2, 0x668D, 0x95A3, 0x668E, 0x95A4, 0x668F, 0x95A5, 0x6690, 0x95A6, 0x6692, 0x95A7, 0x6693, + 0x95A8, 0x6694, 0x95A9, 0x6695, 0x95AA, 0x6698, 0x95AB, 0x6699, 0x95AC, 0x669A, 0x95AD, 0x669B, 0x95AE, 0x669C, 0x95AF, 0x669E, + 0x95B0, 0x669F, 0x95B1, 0x66A0, 0x95B2, 0x66A1, 0x95B3, 0x66A2, 0x95B4, 0x66A3, 0x95B5, 0x66A4, 0x95B6, 0x66A5, 0x95B7, 0x66A6, + 0x95B8, 0x66A9, 0x95B9, 0x66AA, 0x95BA, 0x66AB, 0x95BB, 0x66AC, 0x95BC, 0x66AD, 0x95BD, 0x66AF, 0x95BE, 0x66B0, 0x95BF, 0x66B1, + 0x95C0, 0x66B2, 0x95C1, 0x66B3, 0x95C2, 0x66B5, 0x95C3, 0x66B6, 0x95C4, 0x66B7, 0x95C5, 0x66B8, 0x95C6, 0x66BA, 0x95C7, 0x66BB, + 0x95C8, 0x66BC, 0x95C9, 0x66BD, 0x95CA, 0x66BF, 0x95CB, 0x66C0, 0x95CC, 0x66C1, 0x95CD, 0x66C2, 0x95CE, 0x66C3, 0x95CF, 0x66C4, + 0x95D0, 0x66C5, 0x95D1, 0x66C6, 0x95D2, 0x66C7, 0x95D3, 0x66C8, 0x95D4, 0x66C9, 0x95D5, 0x66CA, 0x95D6, 0x66CB, 0x95D7, 0x66CC, + 0x95D8, 0x66CD, 0x95D9, 0x66CE, 0x95DA, 0x66CF, 0x95DB, 0x66D0, 0x95DC, 0x66D1, 0x95DD, 0x66D2, 0x95DE, 0x66D3, 0x95DF, 0x66D4, + 0x95E0, 0x66D5, 0x95E1, 0x66D6, 0x95E2, 0x66D7, 0x95E3, 0x66D8, 0x95E4, 0x66DA, 0x95E5, 0x66DE, 0x95E6, 0x66DF, 0x95E7, 0x66E0, + 0x95E8, 0x66E1, 0x95E9, 0x66E2, 0x95EA, 0x66E3, 0x95EB, 0x66E4, 0x95EC, 0x66E5, 0x95ED, 0x66E7, 0x95EE, 0x66E8, 0x95EF, 0x66EA, + 0x95F0, 0x66EB, 0x95F1, 0x66EC, 0x95F2, 0x66ED, 0x95F3, 0x66EE, 0x95F4, 0x66EF, 0x95F5, 0x66F1, 0x95F6, 0x66F5, 0x95F7, 0x66F6, + 0x95F8, 0x66F8, 0x95F9, 0x66FA, 0x95FA, 0x66FB, 0x95FB, 0x66FD, 0x95FC, 0x6701, 0x95FD, 0x6702, 0x95FE, 0x6703, 0x9640, 0x6704, + 0x9641, 0x6705, 0x9642, 0x6706, 0x9643, 0x6707, 0x9644, 0x670C, 0x9645, 0x670E, 0x9646, 0x670F, 0x9647, 0x6711, 0x9648, 0x6712, + 0x9649, 0x6713, 0x964A, 0x6716, 0x964B, 0x6718, 0x964C, 0x6719, 0x964D, 0x671A, 0x964E, 0x671C, 0x964F, 0x671E, 0x9650, 0x6720, + 0x9651, 0x6721, 0x9652, 0x6722, 0x9653, 0x6723, 0x9654, 0x6724, 0x9655, 0x6725, 0x9656, 0x6727, 0x9657, 0x6729, 0x9658, 0x672E, + 0x9659, 0x6730, 0x965A, 0x6732, 0x965B, 0x6733, 0x965C, 0x6736, 0x965D, 0x6737, 0x965E, 0x6738, 0x965F, 0x6739, 0x9660, 0x673B, + 0x9661, 0x673C, 0x9662, 0x673E, 0x9663, 0x673F, 0x9664, 0x6741, 0x9665, 0x6744, 0x9666, 0x6745, 0x9667, 0x6747, 0x9668, 0x674A, + 0x9669, 0x674B, 0x966A, 0x674D, 0x966B, 0x6752, 0x966C, 0x6754, 0x966D, 0x6755, 0x966E, 0x6757, 0x966F, 0x6758, 0x9670, 0x6759, + 0x9671, 0x675A, 0x9672, 0x675B, 0x9673, 0x675D, 0x9674, 0x6762, 0x9675, 0x6763, 0x9676, 0x6764, 0x9677, 0x6766, 0x9678, 0x6767, + 0x9679, 0x676B, 0x967A, 0x676C, 0x967B, 0x676E, 0x967C, 0x6771, 0x967D, 0x6774, 0x967E, 0x6776, 0x9680, 0x6778, 0x9681, 0x6779, + 0x9682, 0x677A, 0x9683, 0x677B, 0x9684, 0x677D, 0x9685, 0x6780, 0x9686, 0x6782, 0x9687, 0x6783, 0x9688, 0x6785, 0x9689, 0x6786, + 0x968A, 0x6788, 0x968B, 0x678A, 0x968C, 0x678C, 0x968D, 0x678D, 0x968E, 0x678E, 0x968F, 0x678F, 0x9690, 0x6791, 0x9691, 0x6792, + 0x9692, 0x6793, 0x9693, 0x6794, 0x9694, 0x6796, 0x9695, 0x6799, 0x9696, 0x679B, 0x9697, 0x679F, 0x9698, 0x67A0, 0x9699, 0x67A1, + 0x969A, 0x67A4, 0x969B, 0x67A6, 0x969C, 0x67A9, 0x969D, 0x67AC, 0x969E, 0x67AE, 0x969F, 0x67B1, 0x96A0, 0x67B2, 0x96A1, 0x67B4, + 0x96A2, 0x67B9, 0x96A3, 0x67BA, 0x96A4, 0x67BB, 0x96A5, 0x67BC, 0x96A6, 0x67BD, 0x96A7, 0x67BE, 0x96A8, 0x67BF, 0x96A9, 0x67C0, + 0x96AA, 0x67C2, 0x96AB, 0x67C5, 0x96AC, 0x67C6, 0x96AD, 0x67C7, 0x96AE, 0x67C8, 0x96AF, 0x67C9, 0x96B0, 0x67CA, 0x96B1, 0x67CB, + 0x96B2, 0x67CC, 0x96B3, 0x67CD, 0x96B4, 0x67CE, 0x96B5, 0x67D5, 0x96B6, 0x67D6, 0x96B7, 0x67D7, 0x96B8, 0x67DB, 0x96B9, 0x67DF, + 0x96BA, 0x67E1, 0x96BB, 0x67E3, 0x96BC, 0x67E4, 0x96BD, 0x67E6, 0x96BE, 0x67E7, 0x96BF, 0x67E8, 0x96C0, 0x67EA, 0x96C1, 0x67EB, + 0x96C2, 0x67ED, 0x96C3, 0x67EE, 0x96C4, 0x67F2, 0x96C5, 0x67F5, 0x96C6, 0x67F6, 0x96C7, 0x67F7, 0x96C8, 0x67F8, 0x96C9, 0x67F9, + 0x96CA, 0x67FA, 0x96CB, 0x67FB, 0x96CC, 0x67FC, 0x96CD, 0x67FE, 0x96CE, 0x6801, 0x96CF, 0x6802, 0x96D0, 0x6803, 0x96D1, 0x6804, + 0x96D2, 0x6806, 0x96D3, 0x680D, 0x96D4, 0x6810, 0x96D5, 0x6812, 0x96D6, 0x6814, 0x96D7, 0x6815, 0x96D8, 0x6818, 0x96D9, 0x6819, + 0x96DA, 0x681A, 0x96DB, 0x681B, 0x96DC, 0x681C, 0x96DD, 0x681E, 0x96DE, 0x681F, 0x96DF, 0x6820, 0x96E0, 0x6822, 0x96E1, 0x6823, + 0x96E2, 0x6824, 0x96E3, 0x6825, 0x96E4, 0x6826, 0x96E5, 0x6827, 0x96E6, 0x6828, 0x96E7, 0x682B, 0x96E8, 0x682C, 0x96E9, 0x682D, + 0x96EA, 0x682E, 0x96EB, 0x682F, 0x96EC, 0x6830, 0x96ED, 0x6831, 0x96EE, 0x6834, 0x96EF, 0x6835, 0x96F0, 0x6836, 0x96F1, 0x683A, + 0x96F2, 0x683B, 0x96F3, 0x683F, 0x96F4, 0x6847, 0x96F5, 0x684B, 0x96F6, 0x684D, 0x96F7, 0x684F, 0x96F8, 0x6852, 0x96F9, 0x6856, + 0x96FA, 0x6857, 0x96FB, 0x6858, 0x96FC, 0x6859, 0x96FD, 0x685A, 0x96FE, 0x685B, 0x9740, 0x685C, 0x9741, 0x685D, 0x9742, 0x685E, + 0x9743, 0x685F, 0x9744, 0x686A, 0x9745, 0x686C, 0x9746, 0x686D, 0x9747, 0x686E, 0x9748, 0x686F, 0x9749, 0x6870, 0x974A, 0x6871, + 0x974B, 0x6872, 0x974C, 0x6873, 0x974D, 0x6875, 0x974E, 0x6878, 0x974F, 0x6879, 0x9750, 0x687A, 0x9751, 0x687B, 0x9752, 0x687C, + 0x9753, 0x687D, 0x9754, 0x687E, 0x9755, 0x687F, 0x9756, 0x6880, 0x9757, 0x6882, 0x9758, 0x6884, 0x9759, 0x6887, 0x975A, 0x6888, + 0x975B, 0x6889, 0x975C, 0x688A, 0x975D, 0x688B, 0x975E, 0x688C, 0x975F, 0x688D, 0x9760, 0x688E, 0x9761, 0x6890, 0x9762, 0x6891, + 0x9763, 0x6892, 0x9764, 0x6894, 0x9765, 0x6895, 0x9766, 0x6896, 0x9767, 0x6898, 0x9768, 0x6899, 0x9769, 0x689A, 0x976A, 0x689B, + 0x976B, 0x689C, 0x976C, 0x689D, 0x976D, 0x689E, 0x976E, 0x689F, 0x976F, 0x68A0, 0x9770, 0x68A1, 0x9771, 0x68A3, 0x9772, 0x68A4, + 0x9773, 0x68A5, 0x9774, 0x68A9, 0x9775, 0x68AA, 0x9776, 0x68AB, 0x9777, 0x68AC, 0x9778, 0x68AE, 0x9779, 0x68B1, 0x977A, 0x68B2, + 0x977B, 0x68B4, 0x977C, 0x68B6, 0x977D, 0x68B7, 0x977E, 0x68B8, 0x9780, 0x68B9, 0x9781, 0x68BA, 0x9782, 0x68BB, 0x9783, 0x68BC, + 0x9784, 0x68BD, 0x9785, 0x68BE, 0x9786, 0x68BF, 0x9787, 0x68C1, 0x9788, 0x68C3, 0x9789, 0x68C4, 0x978A, 0x68C5, 0x978B, 0x68C6, + 0x978C, 0x68C7, 0x978D, 0x68C8, 0x978E, 0x68CA, 0x978F, 0x68CC, 0x9790, 0x68CE, 0x9791, 0x68CF, 0x9792, 0x68D0, 0x9793, 0x68D1, + 0x9794, 0x68D3, 0x9795, 0x68D4, 0x9796, 0x68D6, 0x9797, 0x68D7, 0x9798, 0x68D9, 0x9799, 0x68DB, 0x979A, 0x68DC, 0x979B, 0x68DD, + 0x979C, 0x68DE, 0x979D, 0x68DF, 0x979E, 0x68E1, 0x979F, 0x68E2, 0x97A0, 0x68E4, 0x97A1, 0x68E5, 0x97A2, 0x68E6, 0x97A3, 0x68E7, + 0x97A4, 0x68E8, 0x97A5, 0x68E9, 0x97A6, 0x68EA, 0x97A7, 0x68EB, 0x97A8, 0x68EC, 0x97A9, 0x68ED, 0x97AA, 0x68EF, 0x97AB, 0x68F2, + 0x97AC, 0x68F3, 0x97AD, 0x68F4, 0x97AE, 0x68F6, 0x97AF, 0x68F7, 0x97B0, 0x68F8, 0x97B1, 0x68FB, 0x97B2, 0x68FD, 0x97B3, 0x68FE, + 0x97B4, 0x68FF, 0x97B5, 0x6900, 0x97B6, 0x6902, 0x97B7, 0x6903, 0x97B8, 0x6904, 0x97B9, 0x6906, 0x97BA, 0x6907, 0x97BB, 0x6908, + 0x97BC, 0x6909, 0x97BD, 0x690A, 0x97BE, 0x690C, 0x97BF, 0x690F, 0x97C0, 0x6911, 0x97C1, 0x6913, 0x97C2, 0x6914, 0x97C3, 0x6915, + 0x97C4, 0x6916, 0x97C5, 0x6917, 0x97C6, 0x6918, 0x97C7, 0x6919, 0x97C8, 0x691A, 0x97C9, 0x691B, 0x97CA, 0x691C, 0x97CB, 0x691D, + 0x97CC, 0x691E, 0x97CD, 0x6921, 0x97CE, 0x6922, 0x97CF, 0x6923, 0x97D0, 0x6925, 0x97D1, 0x6926, 0x97D2, 0x6927, 0x97D3, 0x6928, + 0x97D4, 0x6929, 0x97D5, 0x692A, 0x97D6, 0x692B, 0x97D7, 0x692C, 0x97D8, 0x692E, 0x97D9, 0x692F, 0x97DA, 0x6931, 0x97DB, 0x6932, + 0x97DC, 0x6933, 0x97DD, 0x6935, 0x97DE, 0x6936, 0x97DF, 0x6937, 0x97E0, 0x6938, 0x97E1, 0x693A, 0x97E2, 0x693B, 0x97E3, 0x693C, + 0x97E4, 0x693E, 0x97E5, 0x6940, 0x97E6, 0x6941, 0x97E7, 0x6943, 0x97E8, 0x6944, 0x97E9, 0x6945, 0x97EA, 0x6946, 0x97EB, 0x6947, + 0x97EC, 0x6948, 0x97ED, 0x6949, 0x97EE, 0x694A, 0x97EF, 0x694B, 0x97F0, 0x694C, 0x97F1, 0x694D, 0x97F2, 0x694E, 0x97F3, 0x694F, + 0x97F4, 0x6950, 0x97F5, 0x6951, 0x97F6, 0x6952, 0x97F7, 0x6953, 0x97F8, 0x6955, 0x97F9, 0x6956, 0x97FA, 0x6958, 0x97FB, 0x6959, + 0x97FC, 0x695B, 0x97FD, 0x695C, 0x97FE, 0x695F, 0x9840, 0x6961, 0x9841, 0x6962, 0x9842, 0x6964, 0x9843, 0x6965, 0x9844, 0x6967, + 0x9845, 0x6968, 0x9846, 0x6969, 0x9847, 0x696A, 0x9848, 0x696C, 0x9849, 0x696D, 0x984A, 0x696F, 0x984B, 0x6970, 0x984C, 0x6972, + 0x984D, 0x6973, 0x984E, 0x6974, 0x984F, 0x6975, 0x9850, 0x6976, 0x9851, 0x697A, 0x9852, 0x697B, 0x9853, 0x697D, 0x9854, 0x697E, + 0x9855, 0x697F, 0x9856, 0x6981, 0x9857, 0x6983, 0x9858, 0x6985, 0x9859, 0x698A, 0x985A, 0x698B, 0x985B, 0x698C, 0x985C, 0x698E, + 0x985D, 0x698F, 0x985E, 0x6990, 0x985F, 0x6991, 0x9860, 0x6992, 0x9861, 0x6993, 0x9862, 0x6996, 0x9863, 0x6997, 0x9864, 0x6999, + 0x9865, 0x699A, 0x9866, 0x699D, 0x9867, 0x699E, 0x9868, 0x699F, 0x9869, 0x69A0, 0x986A, 0x69A1, 0x986B, 0x69A2, 0x986C, 0x69A3, + 0x986D, 0x69A4, 0x986E, 0x69A5, 0x986F, 0x69A6, 0x9870, 0x69A9, 0x9871, 0x69AA, 0x9872, 0x69AC, 0x9873, 0x69AE, 0x9874, 0x69AF, + 0x9875, 0x69B0, 0x9876, 0x69B2, 0x9877, 0x69B3, 0x9878, 0x69B5, 0x9879, 0x69B6, 0x987A, 0x69B8, 0x987B, 0x69B9, 0x987C, 0x69BA, + 0x987D, 0x69BC, 0x987E, 0x69BD, 0x9880, 0x69BE, 0x9881, 0x69BF, 0x9882, 0x69C0, 0x9883, 0x69C2, 0x9884, 0x69C3, 0x9885, 0x69C4, + 0x9886, 0x69C5, 0x9887, 0x69C6, 0x9888, 0x69C7, 0x9889, 0x69C8, 0x988A, 0x69C9, 0x988B, 0x69CB, 0x988C, 0x69CD, 0x988D, 0x69CF, + 0x988E, 0x69D1, 0x988F, 0x69D2, 0x9890, 0x69D3, 0x9891, 0x69D5, 0x9892, 0x69D6, 0x9893, 0x69D7, 0x9894, 0x69D8, 0x9895, 0x69D9, + 0x9896, 0x69DA, 0x9897, 0x69DC, 0x9898, 0x69DD, 0x9899, 0x69DE, 0x989A, 0x69E1, 0x989B, 0x69E2, 0x989C, 0x69E3, 0x989D, 0x69E4, + 0x989E, 0x69E5, 0x989F, 0x69E6, 0x98A0, 0x69E7, 0x98A1, 0x69E8, 0x98A2, 0x69E9, 0x98A3, 0x69EA, 0x98A4, 0x69EB, 0x98A5, 0x69EC, + 0x98A6, 0x69EE, 0x98A7, 0x69EF, 0x98A8, 0x69F0, 0x98A9, 0x69F1, 0x98AA, 0x69F3, 0x98AB, 0x69F4, 0x98AC, 0x69F5, 0x98AD, 0x69F6, + 0x98AE, 0x69F7, 0x98AF, 0x69F8, 0x98B0, 0x69F9, 0x98B1, 0x69FA, 0x98B2, 0x69FB, 0x98B3, 0x69FC, 0x98B4, 0x69FE, 0x98B5, 0x6A00, + 0x98B6, 0x6A01, 0x98B7, 0x6A02, 0x98B8, 0x6A03, 0x98B9, 0x6A04, 0x98BA, 0x6A05, 0x98BB, 0x6A06, 0x98BC, 0x6A07, 0x98BD, 0x6A08, + 0x98BE, 0x6A09, 0x98BF, 0x6A0B, 0x98C0, 0x6A0C, 0x98C1, 0x6A0D, 0x98C2, 0x6A0E, 0x98C3, 0x6A0F, 0x98C4, 0x6A10, 0x98C5, 0x6A11, + 0x98C6, 0x6A12, 0x98C7, 0x6A13, 0x98C8, 0x6A14, 0x98C9, 0x6A15, 0x98CA, 0x6A16, 0x98CB, 0x6A19, 0x98CC, 0x6A1A, 0x98CD, 0x6A1B, + 0x98CE, 0x6A1C, 0x98CF, 0x6A1D, 0x98D0, 0x6A1E, 0x98D1, 0x6A20, 0x98D2, 0x6A22, 0x98D3, 0x6A23, 0x98D4, 0x6A24, 0x98D5, 0x6A25, + 0x98D6, 0x6A26, 0x98D7, 0x6A27, 0x98D8, 0x6A29, 0x98D9, 0x6A2B, 0x98DA, 0x6A2C, 0x98DB, 0x6A2D, 0x98DC, 0x6A2E, 0x98DD, 0x6A30, + 0x98DE, 0x6A32, 0x98DF, 0x6A33, 0x98E0, 0x6A34, 0x98E1, 0x6A36, 0x98E2, 0x6A37, 0x98E3, 0x6A38, 0x98E4, 0x6A39, 0x98E5, 0x6A3A, + 0x98E6, 0x6A3B, 0x98E7, 0x6A3C, 0x98E8, 0x6A3F, 0x98E9, 0x6A40, 0x98EA, 0x6A41, 0x98EB, 0x6A42, 0x98EC, 0x6A43, 0x98ED, 0x6A45, + 0x98EE, 0x6A46, 0x98EF, 0x6A48, 0x98F0, 0x6A49, 0x98F1, 0x6A4A, 0x98F2, 0x6A4B, 0x98F3, 0x6A4C, 0x98F4, 0x6A4D, 0x98F5, 0x6A4E, + 0x98F6, 0x6A4F, 0x98F7, 0x6A51, 0x98F8, 0x6A52, 0x98F9, 0x6A53, 0x98FA, 0x6A54, 0x98FB, 0x6A55, 0x98FC, 0x6A56, 0x98FD, 0x6A57, + 0x98FE, 0x6A5A, 0x9940, 0x6A5C, 0x9941, 0x6A5D, 0x9942, 0x6A5E, 0x9943, 0x6A5F, 0x9944, 0x6A60, 0x9945, 0x6A62, 0x9946, 0x6A63, + 0x9947, 0x6A64, 0x9948, 0x6A66, 0x9949, 0x6A67, 0x994A, 0x6A68, 0x994B, 0x6A69, 0x994C, 0x6A6A, 0x994D, 0x6A6B, 0x994E, 0x6A6C, + 0x994F, 0x6A6D, 0x9950, 0x6A6E, 0x9951, 0x6A6F, 0x9952, 0x6A70, 0x9953, 0x6A72, 0x9954, 0x6A73, 0x9955, 0x6A74, 0x9956, 0x6A75, + 0x9957, 0x6A76, 0x9958, 0x6A77, 0x9959, 0x6A78, 0x995A, 0x6A7A, 0x995B, 0x6A7B, 0x995C, 0x6A7D, 0x995D, 0x6A7E, 0x995E, 0x6A7F, + 0x995F, 0x6A81, 0x9960, 0x6A82, 0x9961, 0x6A83, 0x9962, 0x6A85, 0x9963, 0x6A86, 0x9964, 0x6A87, 0x9965, 0x6A88, 0x9966, 0x6A89, + 0x9967, 0x6A8A, 0x9968, 0x6A8B, 0x9969, 0x6A8C, 0x996A, 0x6A8D, 0x996B, 0x6A8F, 0x996C, 0x6A92, 0x996D, 0x6A93, 0x996E, 0x6A94, + 0x996F, 0x6A95, 0x9970, 0x6A96, 0x9971, 0x6A98, 0x9972, 0x6A99, 0x9973, 0x6A9A, 0x9974, 0x6A9B, 0x9975, 0x6A9C, 0x9976, 0x6A9D, + 0x9977, 0x6A9E, 0x9978, 0x6A9F, 0x9979, 0x6AA1, 0x997A, 0x6AA2, 0x997B, 0x6AA3, 0x997C, 0x6AA4, 0x997D, 0x6AA5, 0x997E, 0x6AA6, + 0x9980, 0x6AA7, 0x9981, 0x6AA8, 0x9982, 0x6AAA, 0x9983, 0x6AAD, 0x9984, 0x6AAE, 0x9985, 0x6AAF, 0x9986, 0x6AB0, 0x9987, 0x6AB1, + 0x9988, 0x6AB2, 0x9989, 0x6AB3, 0x998A, 0x6AB4, 0x998B, 0x6AB5, 0x998C, 0x6AB6, 0x998D, 0x6AB7, 0x998E, 0x6AB8, 0x998F, 0x6AB9, + 0x9990, 0x6ABA, 0x9991, 0x6ABB, 0x9992, 0x6ABC, 0x9993, 0x6ABD, 0x9994, 0x6ABE, 0x9995, 0x6ABF, 0x9996, 0x6AC0, 0x9997, 0x6AC1, + 0x9998, 0x6AC2, 0x9999, 0x6AC3, 0x999A, 0x6AC4, 0x999B, 0x6AC5, 0x999C, 0x6AC6, 0x999D, 0x6AC7, 0x999E, 0x6AC8, 0x999F, 0x6AC9, + 0x99A0, 0x6ACA, 0x99A1, 0x6ACB, 0x99A2, 0x6ACC, 0x99A3, 0x6ACD, 0x99A4, 0x6ACE, 0x99A5, 0x6ACF, 0x99A6, 0x6AD0, 0x99A7, 0x6AD1, + 0x99A8, 0x6AD2, 0x99A9, 0x6AD3, 0x99AA, 0x6AD4, 0x99AB, 0x6AD5, 0x99AC, 0x6AD6, 0x99AD, 0x6AD7, 0x99AE, 0x6AD8, 0x99AF, 0x6AD9, + 0x99B0, 0x6ADA, 0x99B1, 0x6ADB, 0x99B2, 0x6ADC, 0x99B3, 0x6ADD, 0x99B4, 0x6ADE, 0x99B5, 0x6ADF, 0x99B6, 0x6AE0, 0x99B7, 0x6AE1, + 0x99B8, 0x6AE2, 0x99B9, 0x6AE3, 0x99BA, 0x6AE4, 0x99BB, 0x6AE5, 0x99BC, 0x6AE6, 0x99BD, 0x6AE7, 0x99BE, 0x6AE8, 0x99BF, 0x6AE9, + 0x99C0, 0x6AEA, 0x99C1, 0x6AEB, 0x99C2, 0x6AEC, 0x99C3, 0x6AED, 0x99C4, 0x6AEE, 0x99C5, 0x6AEF, 0x99C6, 0x6AF0, 0x99C7, 0x6AF1, + 0x99C8, 0x6AF2, 0x99C9, 0x6AF3, 0x99CA, 0x6AF4, 0x99CB, 0x6AF5, 0x99CC, 0x6AF6, 0x99CD, 0x6AF7, 0x99CE, 0x6AF8, 0x99CF, 0x6AF9, + 0x99D0, 0x6AFA, 0x99D1, 0x6AFB, 0x99D2, 0x6AFC, 0x99D3, 0x6AFD, 0x99D4, 0x6AFE, 0x99D5, 0x6AFF, 0x99D6, 0x6B00, 0x99D7, 0x6B01, + 0x99D8, 0x6B02, 0x99D9, 0x6B03, 0x99DA, 0x6B04, 0x99DB, 0x6B05, 0x99DC, 0x6B06, 0x99DD, 0x6B07, 0x99DE, 0x6B08, 0x99DF, 0x6B09, + 0x99E0, 0x6B0A, 0x99E1, 0x6B0B, 0x99E2, 0x6B0C, 0x99E3, 0x6B0D, 0x99E4, 0x6B0E, 0x99E5, 0x6B0F, 0x99E6, 0x6B10, 0x99E7, 0x6B11, + 0x99E8, 0x6B12, 0x99E9, 0x6B13, 0x99EA, 0x6B14, 0x99EB, 0x6B15, 0x99EC, 0x6B16, 0x99ED, 0x6B17, 0x99EE, 0x6B18, 0x99EF, 0x6B19, + 0x99F0, 0x6B1A, 0x99F1, 0x6B1B, 0x99F2, 0x6B1C, 0x99F3, 0x6B1D, 0x99F4, 0x6B1E, 0x99F5, 0x6B1F, 0x99F6, 0x6B25, 0x99F7, 0x6B26, + 0x99F8, 0x6B28, 0x99F9, 0x6B29, 0x99FA, 0x6B2A, 0x99FB, 0x6B2B, 0x99FC, 0x6B2C, 0x99FD, 0x6B2D, 0x99FE, 0x6B2E, 0x9A40, 0x6B2F, + 0x9A41, 0x6B30, 0x9A42, 0x6B31, 0x9A43, 0x6B33, 0x9A44, 0x6B34, 0x9A45, 0x6B35, 0x9A46, 0x6B36, 0x9A47, 0x6B38, 0x9A48, 0x6B3B, + 0x9A49, 0x6B3C, 0x9A4A, 0x6B3D, 0x9A4B, 0x6B3F, 0x9A4C, 0x6B40, 0x9A4D, 0x6B41, 0x9A4E, 0x6B42, 0x9A4F, 0x6B44, 0x9A50, 0x6B45, + 0x9A51, 0x6B48, 0x9A52, 0x6B4A, 0x9A53, 0x6B4B, 0x9A54, 0x6B4D, 0x9A55, 0x6B4E, 0x9A56, 0x6B4F, 0x9A57, 0x6B50, 0x9A58, 0x6B51, + 0x9A59, 0x6B52, 0x9A5A, 0x6B53, 0x9A5B, 0x6B54, 0x9A5C, 0x6B55, 0x9A5D, 0x6B56, 0x9A5E, 0x6B57, 0x9A5F, 0x6B58, 0x9A60, 0x6B5A, + 0x9A61, 0x6B5B, 0x9A62, 0x6B5C, 0x9A63, 0x6B5D, 0x9A64, 0x6B5E, 0x9A65, 0x6B5F, 0x9A66, 0x6B60, 0x9A67, 0x6B61, 0x9A68, 0x6B68, + 0x9A69, 0x6B69, 0x9A6A, 0x6B6B, 0x9A6B, 0x6B6C, 0x9A6C, 0x6B6D, 0x9A6D, 0x6B6E, 0x9A6E, 0x6B6F, 0x9A6F, 0x6B70, 0x9A70, 0x6B71, + 0x9A71, 0x6B72, 0x9A72, 0x6B73, 0x9A73, 0x6B74, 0x9A74, 0x6B75, 0x9A75, 0x6B76, 0x9A76, 0x6B77, 0x9A77, 0x6B78, 0x9A78, 0x6B7A, + 0x9A79, 0x6B7D, 0x9A7A, 0x6B7E, 0x9A7B, 0x6B7F, 0x9A7C, 0x6B80, 0x9A7D, 0x6B85, 0x9A7E, 0x6B88, 0x9A80, 0x6B8C, 0x9A81, 0x6B8E, + 0x9A82, 0x6B8F, 0x9A83, 0x6B90, 0x9A84, 0x6B91, 0x9A85, 0x6B94, 0x9A86, 0x6B95, 0x9A87, 0x6B97, 0x9A88, 0x6B98, 0x9A89, 0x6B99, + 0x9A8A, 0x6B9C, 0x9A8B, 0x6B9D, 0x9A8C, 0x6B9E, 0x9A8D, 0x6B9F, 0x9A8E, 0x6BA0, 0x9A8F, 0x6BA2, 0x9A90, 0x6BA3, 0x9A91, 0x6BA4, + 0x9A92, 0x6BA5, 0x9A93, 0x6BA6, 0x9A94, 0x6BA7, 0x9A95, 0x6BA8, 0x9A96, 0x6BA9, 0x9A97, 0x6BAB, 0x9A98, 0x6BAC, 0x9A99, 0x6BAD, + 0x9A9A, 0x6BAE, 0x9A9B, 0x6BAF, 0x9A9C, 0x6BB0, 0x9A9D, 0x6BB1, 0x9A9E, 0x6BB2, 0x9A9F, 0x6BB6, 0x9AA0, 0x6BB8, 0x9AA1, 0x6BB9, + 0x9AA2, 0x6BBA, 0x9AA3, 0x6BBB, 0x9AA4, 0x6BBC, 0x9AA5, 0x6BBD, 0x9AA6, 0x6BBE, 0x9AA7, 0x6BC0, 0x9AA8, 0x6BC3, 0x9AA9, 0x6BC4, + 0x9AAA, 0x6BC6, 0x9AAB, 0x6BC7, 0x9AAC, 0x6BC8, 0x9AAD, 0x6BC9, 0x9AAE, 0x6BCA, 0x9AAF, 0x6BCC, 0x9AB0, 0x6BCE, 0x9AB1, 0x6BD0, + 0x9AB2, 0x6BD1, 0x9AB3, 0x6BD8, 0x9AB4, 0x6BDA, 0x9AB5, 0x6BDC, 0x9AB6, 0x6BDD, 0x9AB7, 0x6BDE, 0x9AB8, 0x6BDF, 0x9AB9, 0x6BE0, + 0x9ABA, 0x6BE2, 0x9ABB, 0x6BE3, 0x9ABC, 0x6BE4, 0x9ABD, 0x6BE5, 0x9ABE, 0x6BE6, 0x9ABF, 0x6BE7, 0x9AC0, 0x6BE8, 0x9AC1, 0x6BE9, + 0x9AC2, 0x6BEC, 0x9AC3, 0x6BED, 0x9AC4, 0x6BEE, 0x9AC5, 0x6BF0, 0x9AC6, 0x6BF1, 0x9AC7, 0x6BF2, 0x9AC8, 0x6BF4, 0x9AC9, 0x6BF6, + 0x9ACA, 0x6BF7, 0x9ACB, 0x6BF8, 0x9ACC, 0x6BFA, 0x9ACD, 0x6BFB, 0x9ACE, 0x6BFC, 0x9ACF, 0x6BFE, 0x9AD0, 0x6BFF, 0x9AD1, 0x6C00, + 0x9AD2, 0x6C01, 0x9AD3, 0x6C02, 0x9AD4, 0x6C03, 0x9AD5, 0x6C04, 0x9AD6, 0x6C08, 0x9AD7, 0x6C09, 0x9AD8, 0x6C0A, 0x9AD9, 0x6C0B, + 0x9ADA, 0x6C0C, 0x9ADB, 0x6C0E, 0x9ADC, 0x6C12, 0x9ADD, 0x6C17, 0x9ADE, 0x6C1C, 0x9ADF, 0x6C1D, 0x9AE0, 0x6C1E, 0x9AE1, 0x6C20, + 0x9AE2, 0x6C23, 0x9AE3, 0x6C25, 0x9AE4, 0x6C2B, 0x9AE5, 0x6C2C, 0x9AE6, 0x6C2D, 0x9AE7, 0x6C31, 0x9AE8, 0x6C33, 0x9AE9, 0x6C36, + 0x9AEA, 0x6C37, 0x9AEB, 0x6C39, 0x9AEC, 0x6C3A, 0x9AED, 0x6C3B, 0x9AEE, 0x6C3C, 0x9AEF, 0x6C3E, 0x9AF0, 0x6C3F, 0x9AF1, 0x6C43, + 0x9AF2, 0x6C44, 0x9AF3, 0x6C45, 0x9AF4, 0x6C48, 0x9AF5, 0x6C4B, 0x9AF6, 0x6C4C, 0x9AF7, 0x6C4D, 0x9AF8, 0x6C4E, 0x9AF9, 0x6C4F, + 0x9AFA, 0x6C51, 0x9AFB, 0x6C52, 0x9AFC, 0x6C53, 0x9AFD, 0x6C56, 0x9AFE, 0x6C58, 0x9B40, 0x6C59, 0x9B41, 0x6C5A, 0x9B42, 0x6C62, + 0x9B43, 0x6C63, 0x9B44, 0x6C65, 0x9B45, 0x6C66, 0x9B46, 0x6C67, 0x9B47, 0x6C6B, 0x9B48, 0x6C6C, 0x9B49, 0x6C6D, 0x9B4A, 0x6C6E, + 0x9B4B, 0x6C6F, 0x9B4C, 0x6C71, 0x9B4D, 0x6C73, 0x9B4E, 0x6C75, 0x9B4F, 0x6C77, 0x9B50, 0x6C78, 0x9B51, 0x6C7A, 0x9B52, 0x6C7B, + 0x9B53, 0x6C7C, 0x9B54, 0x6C7F, 0x9B55, 0x6C80, 0x9B56, 0x6C84, 0x9B57, 0x6C87, 0x9B58, 0x6C8A, 0x9B59, 0x6C8B, 0x9B5A, 0x6C8D, + 0x9B5B, 0x6C8E, 0x9B5C, 0x6C91, 0x9B5D, 0x6C92, 0x9B5E, 0x6C95, 0x9B5F, 0x6C96, 0x9B60, 0x6C97, 0x9B61, 0x6C98, 0x9B62, 0x6C9A, + 0x9B63, 0x6C9C, 0x9B64, 0x6C9D, 0x9B65, 0x6C9E, 0x9B66, 0x6CA0, 0x9B67, 0x6CA2, 0x9B68, 0x6CA8, 0x9B69, 0x6CAC, 0x9B6A, 0x6CAF, + 0x9B6B, 0x6CB0, 0x9B6C, 0x6CB4, 0x9B6D, 0x6CB5, 0x9B6E, 0x6CB6, 0x9B6F, 0x6CB7, 0x9B70, 0x6CBA, 0x9B71, 0x6CC0, 0x9B72, 0x6CC1, + 0x9B73, 0x6CC2, 0x9B74, 0x6CC3, 0x9B75, 0x6CC6, 0x9B76, 0x6CC7, 0x9B77, 0x6CC8, 0x9B78, 0x6CCB, 0x9B79, 0x6CCD, 0x9B7A, 0x6CCE, + 0x9B7B, 0x6CCF, 0x9B7C, 0x6CD1, 0x9B7D, 0x6CD2, 0x9B7E, 0x6CD8, 0x9B80, 0x6CD9, 0x9B81, 0x6CDA, 0x9B82, 0x6CDC, 0x9B83, 0x6CDD, + 0x9B84, 0x6CDF, 0x9B85, 0x6CE4, 0x9B86, 0x6CE6, 0x9B87, 0x6CE7, 0x9B88, 0x6CE9, 0x9B89, 0x6CEC, 0x9B8A, 0x6CED, 0x9B8B, 0x6CF2, + 0x9B8C, 0x6CF4, 0x9B8D, 0x6CF9, 0x9B8E, 0x6CFF, 0x9B8F, 0x6D00, 0x9B90, 0x6D02, 0x9B91, 0x6D03, 0x9B92, 0x6D05, 0x9B93, 0x6D06, + 0x9B94, 0x6D08, 0x9B95, 0x6D09, 0x9B96, 0x6D0A, 0x9B97, 0x6D0D, 0x9B98, 0x6D0F, 0x9B99, 0x6D10, 0x9B9A, 0x6D11, 0x9B9B, 0x6D13, + 0x9B9C, 0x6D14, 0x9B9D, 0x6D15, 0x9B9E, 0x6D16, 0x9B9F, 0x6D18, 0x9BA0, 0x6D1C, 0x9BA1, 0x6D1D, 0x9BA2, 0x6D1F, 0x9BA3, 0x6D20, + 0x9BA4, 0x6D21, 0x9BA5, 0x6D22, 0x9BA6, 0x6D23, 0x9BA7, 0x6D24, 0x9BA8, 0x6D26, 0x9BA9, 0x6D28, 0x9BAA, 0x6D29, 0x9BAB, 0x6D2C, + 0x9BAC, 0x6D2D, 0x9BAD, 0x6D2F, 0x9BAE, 0x6D30, 0x9BAF, 0x6D34, 0x9BB0, 0x6D36, 0x9BB1, 0x6D37, 0x9BB2, 0x6D38, 0x9BB3, 0x6D3A, + 0x9BB4, 0x6D3F, 0x9BB5, 0x6D40, 0x9BB6, 0x6D42, 0x9BB7, 0x6D44, 0x9BB8, 0x6D49, 0x9BB9, 0x6D4C, 0x9BBA, 0x6D50, 0x9BBB, 0x6D55, + 0x9BBC, 0x6D56, 0x9BBD, 0x6D57, 0x9BBE, 0x6D58, 0x9BBF, 0x6D5B, 0x9BC0, 0x6D5D, 0x9BC1, 0x6D5F, 0x9BC2, 0x6D61, 0x9BC3, 0x6D62, + 0x9BC4, 0x6D64, 0x9BC5, 0x6D65, 0x9BC6, 0x6D67, 0x9BC7, 0x6D68, 0x9BC8, 0x6D6B, 0x9BC9, 0x6D6C, 0x9BCA, 0x6D6D, 0x9BCB, 0x6D70, + 0x9BCC, 0x6D71, 0x9BCD, 0x6D72, 0x9BCE, 0x6D73, 0x9BCF, 0x6D75, 0x9BD0, 0x6D76, 0x9BD1, 0x6D79, 0x9BD2, 0x6D7A, 0x9BD3, 0x6D7B, + 0x9BD4, 0x6D7D, 0x9BD5, 0x6D7E, 0x9BD6, 0x6D7F, 0x9BD7, 0x6D80, 0x9BD8, 0x6D81, 0x9BD9, 0x6D83, 0x9BDA, 0x6D84, 0x9BDB, 0x6D86, + 0x9BDC, 0x6D87, 0x9BDD, 0x6D8A, 0x9BDE, 0x6D8B, 0x9BDF, 0x6D8D, 0x9BE0, 0x6D8F, 0x9BE1, 0x6D90, 0x9BE2, 0x6D92, 0x9BE3, 0x6D96, + 0x9BE4, 0x6D97, 0x9BE5, 0x6D98, 0x9BE6, 0x6D99, 0x9BE7, 0x6D9A, 0x9BE8, 0x6D9C, 0x9BE9, 0x6DA2, 0x9BEA, 0x6DA5, 0x9BEB, 0x6DAC, + 0x9BEC, 0x6DAD, 0x9BED, 0x6DB0, 0x9BEE, 0x6DB1, 0x9BEF, 0x6DB3, 0x9BF0, 0x6DB4, 0x9BF1, 0x6DB6, 0x9BF2, 0x6DB7, 0x9BF3, 0x6DB9, + 0x9BF4, 0x6DBA, 0x9BF5, 0x6DBB, 0x9BF6, 0x6DBC, 0x9BF7, 0x6DBD, 0x9BF8, 0x6DBE, 0x9BF9, 0x6DC1, 0x9BFA, 0x6DC2, 0x9BFB, 0x6DC3, + 0x9BFC, 0x6DC8, 0x9BFD, 0x6DC9, 0x9BFE, 0x6DCA, 0x9C40, 0x6DCD, 0x9C41, 0x6DCE, 0x9C42, 0x6DCF, 0x9C43, 0x6DD0, 0x9C44, 0x6DD2, + 0x9C45, 0x6DD3, 0x9C46, 0x6DD4, 0x9C47, 0x6DD5, 0x9C48, 0x6DD7, 0x9C49, 0x6DDA, 0x9C4A, 0x6DDB, 0x9C4B, 0x6DDC, 0x9C4C, 0x6DDF, + 0x9C4D, 0x6DE2, 0x9C4E, 0x6DE3, 0x9C4F, 0x6DE5, 0x9C50, 0x6DE7, 0x9C51, 0x6DE8, 0x9C52, 0x6DE9, 0x9C53, 0x6DEA, 0x9C54, 0x6DED, + 0x9C55, 0x6DEF, 0x9C56, 0x6DF0, 0x9C57, 0x6DF2, 0x9C58, 0x6DF4, 0x9C59, 0x6DF5, 0x9C5A, 0x6DF6, 0x9C5B, 0x6DF8, 0x9C5C, 0x6DFA, + 0x9C5D, 0x6DFD, 0x9C5E, 0x6DFE, 0x9C5F, 0x6DFF, 0x9C60, 0x6E00, 0x9C61, 0x6E01, 0x9C62, 0x6E02, 0x9C63, 0x6E03, 0x9C64, 0x6E04, + 0x9C65, 0x6E06, 0x9C66, 0x6E07, 0x9C67, 0x6E08, 0x9C68, 0x6E09, 0x9C69, 0x6E0B, 0x9C6A, 0x6E0F, 0x9C6B, 0x6E12, 0x9C6C, 0x6E13, + 0x9C6D, 0x6E15, 0x9C6E, 0x6E18, 0x9C6F, 0x6E19, 0x9C70, 0x6E1B, 0x9C71, 0x6E1C, 0x9C72, 0x6E1E, 0x9C73, 0x6E1F, 0x9C74, 0x6E22, + 0x9C75, 0x6E26, 0x9C76, 0x6E27, 0x9C77, 0x6E28, 0x9C78, 0x6E2A, 0x9C79, 0x6E2C, 0x9C7A, 0x6E2E, 0x9C7B, 0x6E30, 0x9C7C, 0x6E31, + 0x9C7D, 0x6E33, 0x9C7E, 0x6E35, 0x9C80, 0x6E36, 0x9C81, 0x6E37, 0x9C82, 0x6E39, 0x9C83, 0x6E3B, 0x9C84, 0x6E3C, 0x9C85, 0x6E3D, + 0x9C86, 0x6E3E, 0x9C87, 0x6E3F, 0x9C88, 0x6E40, 0x9C89, 0x6E41, 0x9C8A, 0x6E42, 0x9C8B, 0x6E45, 0x9C8C, 0x6E46, 0x9C8D, 0x6E47, + 0x9C8E, 0x6E48, 0x9C8F, 0x6E49, 0x9C90, 0x6E4A, 0x9C91, 0x6E4B, 0x9C92, 0x6E4C, 0x9C93, 0x6E4F, 0x9C94, 0x6E50, 0x9C95, 0x6E51, + 0x9C96, 0x6E52, 0x9C97, 0x6E55, 0x9C98, 0x6E57, 0x9C99, 0x6E59, 0x9C9A, 0x6E5A, 0x9C9B, 0x6E5C, 0x9C9C, 0x6E5D, 0x9C9D, 0x6E5E, + 0x9C9E, 0x6E60, 0x9C9F, 0x6E61, 0x9CA0, 0x6E62, 0x9CA1, 0x6E63, 0x9CA2, 0x6E64, 0x9CA3, 0x6E65, 0x9CA4, 0x6E66, 0x9CA5, 0x6E67, + 0x9CA6, 0x6E68, 0x9CA7, 0x6E69, 0x9CA8, 0x6E6A, 0x9CA9, 0x6E6C, 0x9CAA, 0x6E6D, 0x9CAB, 0x6E6F, 0x9CAC, 0x6E70, 0x9CAD, 0x6E71, + 0x9CAE, 0x6E72, 0x9CAF, 0x6E73, 0x9CB0, 0x6E74, 0x9CB1, 0x6E75, 0x9CB2, 0x6E76, 0x9CB3, 0x6E77, 0x9CB4, 0x6E78, 0x9CB5, 0x6E79, + 0x9CB6, 0x6E7A, 0x9CB7, 0x6E7B, 0x9CB8, 0x6E7C, 0x9CB9, 0x6E7D, 0x9CBA, 0x6E80, 0x9CBB, 0x6E81, 0x9CBC, 0x6E82, 0x9CBD, 0x6E84, + 0x9CBE, 0x6E87, 0x9CBF, 0x6E88, 0x9CC0, 0x6E8A, 0x9CC1, 0x6E8B, 0x9CC2, 0x6E8C, 0x9CC3, 0x6E8D, 0x9CC4, 0x6E8E, 0x9CC5, 0x6E91, + 0x9CC6, 0x6E92, 0x9CC7, 0x6E93, 0x9CC8, 0x6E94, 0x9CC9, 0x6E95, 0x9CCA, 0x6E96, 0x9CCB, 0x6E97, 0x9CCC, 0x6E99, 0x9CCD, 0x6E9A, + 0x9CCE, 0x6E9B, 0x9CCF, 0x6E9D, 0x9CD0, 0x6E9E, 0x9CD1, 0x6EA0, 0x9CD2, 0x6EA1, 0x9CD3, 0x6EA3, 0x9CD4, 0x6EA4, 0x9CD5, 0x6EA6, + 0x9CD6, 0x6EA8, 0x9CD7, 0x6EA9, 0x9CD8, 0x6EAB, 0x9CD9, 0x6EAC, 0x9CDA, 0x6EAD, 0x9CDB, 0x6EAE, 0x9CDC, 0x6EB0, 0x9CDD, 0x6EB3, + 0x9CDE, 0x6EB5, 0x9CDF, 0x6EB8, 0x9CE0, 0x6EB9, 0x9CE1, 0x6EBC, 0x9CE2, 0x6EBE, 0x9CE3, 0x6EBF, 0x9CE4, 0x6EC0, 0x9CE5, 0x6EC3, + 0x9CE6, 0x6EC4, 0x9CE7, 0x6EC5, 0x9CE8, 0x6EC6, 0x9CE9, 0x6EC8, 0x9CEA, 0x6EC9, 0x9CEB, 0x6ECA, 0x9CEC, 0x6ECC, 0x9CED, 0x6ECD, + 0x9CEE, 0x6ECE, 0x9CEF, 0x6ED0, 0x9CF0, 0x6ED2, 0x9CF1, 0x6ED6, 0x9CF2, 0x6ED8, 0x9CF3, 0x6ED9, 0x9CF4, 0x6EDB, 0x9CF5, 0x6EDC, + 0x9CF6, 0x6EDD, 0x9CF7, 0x6EE3, 0x9CF8, 0x6EE7, 0x9CF9, 0x6EEA, 0x9CFA, 0x6EEB, 0x9CFB, 0x6EEC, 0x9CFC, 0x6EED, 0x9CFD, 0x6EEE, + 0x9CFE, 0x6EEF, 0x9D40, 0x6EF0, 0x9D41, 0x6EF1, 0x9D42, 0x6EF2, 0x9D43, 0x6EF3, 0x9D44, 0x6EF5, 0x9D45, 0x6EF6, 0x9D46, 0x6EF7, + 0x9D47, 0x6EF8, 0x9D48, 0x6EFA, 0x9D49, 0x6EFB, 0x9D4A, 0x6EFC, 0x9D4B, 0x6EFD, 0x9D4C, 0x6EFE, 0x9D4D, 0x6EFF, 0x9D4E, 0x6F00, + 0x9D4F, 0x6F01, 0x9D50, 0x6F03, 0x9D51, 0x6F04, 0x9D52, 0x6F05, 0x9D53, 0x6F07, 0x9D54, 0x6F08, 0x9D55, 0x6F0A, 0x9D56, 0x6F0B, + 0x9D57, 0x6F0C, 0x9D58, 0x6F0D, 0x9D59, 0x6F0E, 0x9D5A, 0x6F10, 0x9D5B, 0x6F11, 0x9D5C, 0x6F12, 0x9D5D, 0x6F16, 0x9D5E, 0x6F17, + 0x9D5F, 0x6F18, 0x9D60, 0x6F19, 0x9D61, 0x6F1A, 0x9D62, 0x6F1B, 0x9D63, 0x6F1C, 0x9D64, 0x6F1D, 0x9D65, 0x6F1E, 0x9D66, 0x6F1F, + 0x9D67, 0x6F21, 0x9D68, 0x6F22, 0x9D69, 0x6F23, 0x9D6A, 0x6F25, 0x9D6B, 0x6F26, 0x9D6C, 0x6F27, 0x9D6D, 0x6F28, 0x9D6E, 0x6F2C, + 0x9D6F, 0x6F2E, 0x9D70, 0x6F30, 0x9D71, 0x6F32, 0x9D72, 0x6F34, 0x9D73, 0x6F35, 0x9D74, 0x6F37, 0x9D75, 0x6F38, 0x9D76, 0x6F39, + 0x9D77, 0x6F3A, 0x9D78, 0x6F3B, 0x9D79, 0x6F3C, 0x9D7A, 0x6F3D, 0x9D7B, 0x6F3F, 0x9D7C, 0x6F40, 0x9D7D, 0x6F41, 0x9D7E, 0x6F42, + 0x9D80, 0x6F43, 0x9D81, 0x6F44, 0x9D82, 0x6F45, 0x9D83, 0x6F48, 0x9D84, 0x6F49, 0x9D85, 0x6F4A, 0x9D86, 0x6F4C, 0x9D87, 0x6F4E, + 0x9D88, 0x6F4F, 0x9D89, 0x6F50, 0x9D8A, 0x6F51, 0x9D8B, 0x6F52, 0x9D8C, 0x6F53, 0x9D8D, 0x6F54, 0x9D8E, 0x6F55, 0x9D8F, 0x6F56, + 0x9D90, 0x6F57, 0x9D91, 0x6F59, 0x9D92, 0x6F5A, 0x9D93, 0x6F5B, 0x9D94, 0x6F5D, 0x9D95, 0x6F5F, 0x9D96, 0x6F60, 0x9D97, 0x6F61, + 0x9D98, 0x6F63, 0x9D99, 0x6F64, 0x9D9A, 0x6F65, 0x9D9B, 0x6F67, 0x9D9C, 0x6F68, 0x9D9D, 0x6F69, 0x9D9E, 0x6F6A, 0x9D9F, 0x6F6B, + 0x9DA0, 0x6F6C, 0x9DA1, 0x6F6F, 0x9DA2, 0x6F70, 0x9DA3, 0x6F71, 0x9DA4, 0x6F73, 0x9DA5, 0x6F75, 0x9DA6, 0x6F76, 0x9DA7, 0x6F77, + 0x9DA8, 0x6F79, 0x9DA9, 0x6F7B, 0x9DAA, 0x6F7D, 0x9DAB, 0x6F7E, 0x9DAC, 0x6F7F, 0x9DAD, 0x6F80, 0x9DAE, 0x6F81, 0x9DAF, 0x6F82, + 0x9DB0, 0x6F83, 0x9DB1, 0x6F85, 0x9DB2, 0x6F86, 0x9DB3, 0x6F87, 0x9DB4, 0x6F8A, 0x9DB5, 0x6F8B, 0x9DB6, 0x6F8F, 0x9DB7, 0x6F90, + 0x9DB8, 0x6F91, 0x9DB9, 0x6F92, 0x9DBA, 0x6F93, 0x9DBB, 0x6F94, 0x9DBC, 0x6F95, 0x9DBD, 0x6F96, 0x9DBE, 0x6F97, 0x9DBF, 0x6F98, + 0x9DC0, 0x6F99, 0x9DC1, 0x6F9A, 0x9DC2, 0x6F9B, 0x9DC3, 0x6F9D, 0x9DC4, 0x6F9E, 0x9DC5, 0x6F9F, 0x9DC6, 0x6FA0, 0x9DC7, 0x6FA2, + 0x9DC8, 0x6FA3, 0x9DC9, 0x6FA4, 0x9DCA, 0x6FA5, 0x9DCB, 0x6FA6, 0x9DCC, 0x6FA8, 0x9DCD, 0x6FA9, 0x9DCE, 0x6FAA, 0x9DCF, 0x6FAB, + 0x9DD0, 0x6FAC, 0x9DD1, 0x6FAD, 0x9DD2, 0x6FAE, 0x9DD3, 0x6FAF, 0x9DD4, 0x6FB0, 0x9DD5, 0x6FB1, 0x9DD6, 0x6FB2, 0x9DD7, 0x6FB4, + 0x9DD8, 0x6FB5, 0x9DD9, 0x6FB7, 0x9DDA, 0x6FB8, 0x9DDB, 0x6FBA, 0x9DDC, 0x6FBB, 0x9DDD, 0x6FBC, 0x9DDE, 0x6FBD, 0x9DDF, 0x6FBE, + 0x9DE0, 0x6FBF, 0x9DE1, 0x6FC1, 0x9DE2, 0x6FC3, 0x9DE3, 0x6FC4, 0x9DE4, 0x6FC5, 0x9DE5, 0x6FC6, 0x9DE6, 0x6FC7, 0x9DE7, 0x6FC8, + 0x9DE8, 0x6FCA, 0x9DE9, 0x6FCB, 0x9DEA, 0x6FCC, 0x9DEB, 0x6FCD, 0x9DEC, 0x6FCE, 0x9DED, 0x6FCF, 0x9DEE, 0x6FD0, 0x9DEF, 0x6FD3, + 0x9DF0, 0x6FD4, 0x9DF1, 0x6FD5, 0x9DF2, 0x6FD6, 0x9DF3, 0x6FD7, 0x9DF4, 0x6FD8, 0x9DF5, 0x6FD9, 0x9DF6, 0x6FDA, 0x9DF7, 0x6FDB, + 0x9DF8, 0x6FDC, 0x9DF9, 0x6FDD, 0x9DFA, 0x6FDF, 0x9DFB, 0x6FE2, 0x9DFC, 0x6FE3, 0x9DFD, 0x6FE4, 0x9DFE, 0x6FE5, 0x9E40, 0x6FE6, + 0x9E41, 0x6FE7, 0x9E42, 0x6FE8, 0x9E43, 0x6FE9, 0x9E44, 0x6FEA, 0x9E45, 0x6FEB, 0x9E46, 0x6FEC, 0x9E47, 0x6FED, 0x9E48, 0x6FF0, + 0x9E49, 0x6FF1, 0x9E4A, 0x6FF2, 0x9E4B, 0x6FF3, 0x9E4C, 0x6FF4, 0x9E4D, 0x6FF5, 0x9E4E, 0x6FF6, 0x9E4F, 0x6FF7, 0x9E50, 0x6FF8, + 0x9E51, 0x6FF9, 0x9E52, 0x6FFA, 0x9E53, 0x6FFB, 0x9E54, 0x6FFC, 0x9E55, 0x6FFD, 0x9E56, 0x6FFE, 0x9E57, 0x6FFF, 0x9E58, 0x7000, + 0x9E59, 0x7001, 0x9E5A, 0x7002, 0x9E5B, 0x7003, 0x9E5C, 0x7004, 0x9E5D, 0x7005, 0x9E5E, 0x7006, 0x9E5F, 0x7007, 0x9E60, 0x7008, + 0x9E61, 0x7009, 0x9E62, 0x700A, 0x9E63, 0x700B, 0x9E64, 0x700C, 0x9E65, 0x700D, 0x9E66, 0x700E, 0x9E67, 0x700F, 0x9E68, 0x7010, + 0x9E69, 0x7012, 0x9E6A, 0x7013, 0x9E6B, 0x7014, 0x9E6C, 0x7015, 0x9E6D, 0x7016, 0x9E6E, 0x7017, 0x9E6F, 0x7018, 0x9E70, 0x7019, + 0x9E71, 0x701C, 0x9E72, 0x701D, 0x9E73, 0x701E, 0x9E74, 0x701F, 0x9E75, 0x7020, 0x9E76, 0x7021, 0x9E77, 0x7022, 0x9E78, 0x7024, + 0x9E79, 0x7025, 0x9E7A, 0x7026, 0x9E7B, 0x7027, 0x9E7C, 0x7028, 0x9E7D, 0x7029, 0x9E7E, 0x702A, 0x9E80, 0x702B, 0x9E81, 0x702C, + 0x9E82, 0x702D, 0x9E83, 0x702E, 0x9E84, 0x702F, 0x9E85, 0x7030, 0x9E86, 0x7031, 0x9E87, 0x7032, 0x9E88, 0x7033, 0x9E89, 0x7034, + 0x9E8A, 0x7036, 0x9E8B, 0x7037, 0x9E8C, 0x7038, 0x9E8D, 0x703A, 0x9E8E, 0x703B, 0x9E8F, 0x703C, 0x9E90, 0x703D, 0x9E91, 0x703E, + 0x9E92, 0x703F, 0x9E93, 0x7040, 0x9E94, 0x7041, 0x9E95, 0x7042, 0x9E96, 0x7043, 0x9E97, 0x7044, 0x9E98, 0x7045, 0x9E99, 0x7046, + 0x9E9A, 0x7047, 0x9E9B, 0x7048, 0x9E9C, 0x7049, 0x9E9D, 0x704A, 0x9E9E, 0x704B, 0x9E9F, 0x704D, 0x9EA0, 0x704E, 0x9EA1, 0x7050, + 0x9EA2, 0x7051, 0x9EA3, 0x7052, 0x9EA4, 0x7053, 0x9EA5, 0x7054, 0x9EA6, 0x7055, 0x9EA7, 0x7056, 0x9EA8, 0x7057, 0x9EA9, 0x7058, + 0x9EAA, 0x7059, 0x9EAB, 0x705A, 0x9EAC, 0x705B, 0x9EAD, 0x705C, 0x9EAE, 0x705D, 0x9EAF, 0x705F, 0x9EB0, 0x7060, 0x9EB1, 0x7061, + 0x9EB2, 0x7062, 0x9EB3, 0x7063, 0x9EB4, 0x7064, 0x9EB5, 0x7065, 0x9EB6, 0x7066, 0x9EB7, 0x7067, 0x9EB8, 0x7068, 0x9EB9, 0x7069, + 0x9EBA, 0x706A, 0x9EBB, 0x706E, 0x9EBC, 0x7071, 0x9EBD, 0x7072, 0x9EBE, 0x7073, 0x9EBF, 0x7074, 0x9EC0, 0x7077, 0x9EC1, 0x7079, + 0x9EC2, 0x707A, 0x9EC3, 0x707B, 0x9EC4, 0x707D, 0x9EC5, 0x7081, 0x9EC6, 0x7082, 0x9EC7, 0x7083, 0x9EC8, 0x7084, 0x9EC9, 0x7086, + 0x9ECA, 0x7087, 0x9ECB, 0x7088, 0x9ECC, 0x708B, 0x9ECD, 0x708C, 0x9ECE, 0x708D, 0x9ECF, 0x708F, 0x9ED0, 0x7090, 0x9ED1, 0x7091, + 0x9ED2, 0x7093, 0x9ED3, 0x7097, 0x9ED4, 0x7098, 0x9ED5, 0x709A, 0x9ED6, 0x709B, 0x9ED7, 0x709E, 0x9ED8, 0x709F, 0x9ED9, 0x70A0, + 0x9EDA, 0x70A1, 0x9EDB, 0x70A2, 0x9EDC, 0x70A3, 0x9EDD, 0x70A4, 0x9EDE, 0x70A5, 0x9EDF, 0x70A6, 0x9EE0, 0x70A7, 0x9EE1, 0x70A8, + 0x9EE2, 0x70A9, 0x9EE3, 0x70AA, 0x9EE4, 0x70B0, 0x9EE5, 0x70B2, 0x9EE6, 0x70B4, 0x9EE7, 0x70B5, 0x9EE8, 0x70B6, 0x9EE9, 0x70BA, + 0x9EEA, 0x70BE, 0x9EEB, 0x70BF, 0x9EEC, 0x70C4, 0x9EED, 0x70C5, 0x9EEE, 0x70C6, 0x9EEF, 0x70C7, 0x9EF0, 0x70C9, 0x9EF1, 0x70CB, + 0x9EF2, 0x70CC, 0x9EF3, 0x70CD, 0x9EF4, 0x70CE, 0x9EF5, 0x70CF, 0x9EF6, 0x70D0, 0x9EF7, 0x70D1, 0x9EF8, 0x70D2, 0x9EF9, 0x70D3, + 0x9EFA, 0x70D4, 0x9EFB, 0x70D5, 0x9EFC, 0x70D6, 0x9EFD, 0x70D7, 0x9EFE, 0x70DA, 0x9F40, 0x70DC, 0x9F41, 0x70DD, 0x9F42, 0x70DE, + 0x9F43, 0x70E0, 0x9F44, 0x70E1, 0x9F45, 0x70E2, 0x9F46, 0x70E3, 0x9F47, 0x70E5, 0x9F48, 0x70EA, 0x9F49, 0x70EE, 0x9F4A, 0x70F0, + 0x9F4B, 0x70F1, 0x9F4C, 0x70F2, 0x9F4D, 0x70F3, 0x9F4E, 0x70F4, 0x9F4F, 0x70F5, 0x9F50, 0x70F6, 0x9F51, 0x70F8, 0x9F52, 0x70FA, + 0x9F53, 0x70FB, 0x9F54, 0x70FC, 0x9F55, 0x70FE, 0x9F56, 0x70FF, 0x9F57, 0x7100, 0x9F58, 0x7101, 0x9F59, 0x7102, 0x9F5A, 0x7103, + 0x9F5B, 0x7104, 0x9F5C, 0x7105, 0x9F5D, 0x7106, 0x9F5E, 0x7107, 0x9F5F, 0x7108, 0x9F60, 0x710B, 0x9F61, 0x710C, 0x9F62, 0x710D, + 0x9F63, 0x710E, 0x9F64, 0x710F, 0x9F65, 0x7111, 0x9F66, 0x7112, 0x9F67, 0x7114, 0x9F68, 0x7117, 0x9F69, 0x711B, 0x9F6A, 0x711C, + 0x9F6B, 0x711D, 0x9F6C, 0x711E, 0x9F6D, 0x711F, 0x9F6E, 0x7120, 0x9F6F, 0x7121, 0x9F70, 0x7122, 0x9F71, 0x7123, 0x9F72, 0x7124, + 0x9F73, 0x7125, 0x9F74, 0x7127, 0x9F75, 0x7128, 0x9F76, 0x7129, 0x9F77, 0x712A, 0x9F78, 0x712B, 0x9F79, 0x712C, 0x9F7A, 0x712D, + 0x9F7B, 0x712E, 0x9F7C, 0x7132, 0x9F7D, 0x7133, 0x9F7E, 0x7134, 0x9F80, 0x7135, 0x9F81, 0x7137, 0x9F82, 0x7138, 0x9F83, 0x7139, + 0x9F84, 0x713A, 0x9F85, 0x713B, 0x9F86, 0x713C, 0x9F87, 0x713D, 0x9F88, 0x713E, 0x9F89, 0x713F, 0x9F8A, 0x7140, 0x9F8B, 0x7141, + 0x9F8C, 0x7142, 0x9F8D, 0x7143, 0x9F8E, 0x7144, 0x9F8F, 0x7146, 0x9F90, 0x7147, 0x9F91, 0x7148, 0x9F92, 0x7149, 0x9F93, 0x714B, + 0x9F94, 0x714D, 0x9F95, 0x714F, 0x9F96, 0x7150, 0x9F97, 0x7151, 0x9F98, 0x7152, 0x9F99, 0x7153, 0x9F9A, 0x7154, 0x9F9B, 0x7155, + 0x9F9C, 0x7156, 0x9F9D, 0x7157, 0x9F9E, 0x7158, 0x9F9F, 0x7159, 0x9FA0, 0x715A, 0x9FA1, 0x715B, 0x9FA2, 0x715D, 0x9FA3, 0x715F, + 0x9FA4, 0x7160, 0x9FA5, 0x7161, 0x9FA6, 0x7162, 0x9FA7, 0x7163, 0x9FA8, 0x7165, 0x9FA9, 0x7169, 0x9FAA, 0x716A, 0x9FAB, 0x716B, + 0x9FAC, 0x716C, 0x9FAD, 0x716D, 0x9FAE, 0x716F, 0x9FAF, 0x7170, 0x9FB0, 0x7171, 0x9FB1, 0x7174, 0x9FB2, 0x7175, 0x9FB3, 0x7176, + 0x9FB4, 0x7177, 0x9FB5, 0x7179, 0x9FB6, 0x717B, 0x9FB7, 0x717C, 0x9FB8, 0x717E, 0x9FB9, 0x717F, 0x9FBA, 0x7180, 0x9FBB, 0x7181, + 0x9FBC, 0x7182, 0x9FBD, 0x7183, 0x9FBE, 0x7185, 0x9FBF, 0x7186, 0x9FC0, 0x7187, 0x9FC1, 0x7188, 0x9FC2, 0x7189, 0x9FC3, 0x718B, + 0x9FC4, 0x718C, 0x9FC5, 0x718D, 0x9FC6, 0x718E, 0x9FC7, 0x7190, 0x9FC8, 0x7191, 0x9FC9, 0x7192, 0x9FCA, 0x7193, 0x9FCB, 0x7195, + 0x9FCC, 0x7196, 0x9FCD, 0x7197, 0x9FCE, 0x719A, 0x9FCF, 0x719B, 0x9FD0, 0x719C, 0x9FD1, 0x719D, 0x9FD2, 0x719E, 0x9FD3, 0x71A1, + 0x9FD4, 0x71A2, 0x9FD5, 0x71A3, 0x9FD6, 0x71A4, 0x9FD7, 0x71A5, 0x9FD8, 0x71A6, 0x9FD9, 0x71A7, 0x9FDA, 0x71A9, 0x9FDB, 0x71AA, + 0x9FDC, 0x71AB, 0x9FDD, 0x71AD, 0x9FDE, 0x71AE, 0x9FDF, 0x71AF, 0x9FE0, 0x71B0, 0x9FE1, 0x71B1, 0x9FE2, 0x71B2, 0x9FE3, 0x71B4, + 0x9FE4, 0x71B6, 0x9FE5, 0x71B7, 0x9FE6, 0x71B8, 0x9FE7, 0x71BA, 0x9FE8, 0x71BB, 0x9FE9, 0x71BC, 0x9FEA, 0x71BD, 0x9FEB, 0x71BE, + 0x9FEC, 0x71BF, 0x9FED, 0x71C0, 0x9FEE, 0x71C1, 0x9FEF, 0x71C2, 0x9FF0, 0x71C4, 0x9FF1, 0x71C5, 0x9FF2, 0x71C6, 0x9FF3, 0x71C7, + 0x9FF4, 0x71C8, 0x9FF5, 0x71C9, 0x9FF6, 0x71CA, 0x9FF7, 0x71CB, 0x9FF8, 0x71CC, 0x9FF9, 0x71CD, 0x9FFA, 0x71CF, 0x9FFB, 0x71D0, + 0x9FFC, 0x71D1, 0x9FFD, 0x71D2, 0x9FFE, 0x71D3, 0xA040, 0x71D6, 0xA041, 0x71D7, 0xA042, 0x71D8, 0xA043, 0x71D9, 0xA044, 0x71DA, + 0xA045, 0x71DB, 0xA046, 0x71DC, 0xA047, 0x71DD, 0xA048, 0x71DE, 0xA049, 0x71DF, 0xA04A, 0x71E1, 0xA04B, 0x71E2, 0xA04C, 0x71E3, + 0xA04D, 0x71E4, 0xA04E, 0x71E6, 0xA04F, 0x71E8, 0xA050, 0x71E9, 0xA051, 0x71EA, 0xA052, 0x71EB, 0xA053, 0x71EC, 0xA054, 0x71ED, + 0xA055, 0x71EF, 0xA056, 0x71F0, 0xA057, 0x71F1, 0xA058, 0x71F2, 0xA059, 0x71F3, 0xA05A, 0x71F4, 0xA05B, 0x71F5, 0xA05C, 0x71F6, + 0xA05D, 0x71F7, 0xA05E, 0x71F8, 0xA05F, 0x71FA, 0xA060, 0x71FB, 0xA061, 0x71FC, 0xA062, 0x71FD, 0xA063, 0x71FE, 0xA064, 0x71FF, + 0xA065, 0x7200, 0xA066, 0x7201, 0xA067, 0x7202, 0xA068, 0x7203, 0xA069, 0x7204, 0xA06A, 0x7205, 0xA06B, 0x7207, 0xA06C, 0x7208, + 0xA06D, 0x7209, 0xA06E, 0x720A, 0xA06F, 0x720B, 0xA070, 0x720C, 0xA071, 0x720D, 0xA072, 0x720E, 0xA073, 0x720F, 0xA074, 0x7210, + 0xA075, 0x7211, 0xA076, 0x7212, 0xA077, 0x7213, 0xA078, 0x7214, 0xA079, 0x7215, 0xA07A, 0x7216, 0xA07B, 0x7217, 0xA07C, 0x7218, + 0xA07D, 0x7219, 0xA07E, 0x721A, 0xA080, 0x721B, 0xA081, 0x721C, 0xA082, 0x721E, 0xA083, 0x721F, 0xA084, 0x7220, 0xA085, 0x7221, + 0xA086, 0x7222, 0xA087, 0x7223, 0xA088, 0x7224, 0xA089, 0x7225, 0xA08A, 0x7226, 0xA08B, 0x7227, 0xA08C, 0x7229, 0xA08D, 0x722B, + 0xA08E, 0x722D, 0xA08F, 0x722E, 0xA090, 0x722F, 0xA091, 0x7232, 0xA092, 0x7233, 0xA093, 0x7234, 0xA094, 0x723A, 0xA095, 0x723C, + 0xA096, 0x723E, 0xA097, 0x7240, 0xA098, 0x7241, 0xA099, 0x7242, 0xA09A, 0x7243, 0xA09B, 0x7244, 0xA09C, 0x7245, 0xA09D, 0x7246, + 0xA09E, 0x7249, 0xA09F, 0x724A, 0xA0A0, 0x724B, 0xA0A1, 0x724E, 0xA0A2, 0x724F, 0xA0A3, 0x7250, 0xA0A4, 0x7251, 0xA0A5, 0x7253, + 0xA0A6, 0x7254, 0xA0A7, 0x7255, 0xA0A8, 0x7257, 0xA0A9, 0x7258, 0xA0AA, 0x725A, 0xA0AB, 0x725C, 0xA0AC, 0x725E, 0xA0AD, 0x7260, + 0xA0AE, 0x7263, 0xA0AF, 0x7264, 0xA0B0, 0x7265, 0xA0B1, 0x7268, 0xA0B2, 0x726A, 0xA0B3, 0x726B, 0xA0B4, 0x726C, 0xA0B5, 0x726D, + 0xA0B6, 0x7270, 0xA0B7, 0x7271, 0xA0B8, 0x7273, 0xA0B9, 0x7274, 0xA0BA, 0x7276, 0xA0BB, 0x7277, 0xA0BC, 0x7278, 0xA0BD, 0x727B, + 0xA0BE, 0x727C, 0xA0BF, 0x727D, 0xA0C0, 0x7282, 0xA0C1, 0x7283, 0xA0C2, 0x7285, 0xA0C3, 0x7286, 0xA0C4, 0x7287, 0xA0C5, 0x7288, + 0xA0C6, 0x7289, 0xA0C7, 0x728C, 0xA0C8, 0x728E, 0xA0C9, 0x7290, 0xA0CA, 0x7291, 0xA0CB, 0x7293, 0xA0CC, 0x7294, 0xA0CD, 0x7295, + 0xA0CE, 0x7296, 0xA0CF, 0x7297, 0xA0D0, 0x7298, 0xA0D1, 0x7299, 0xA0D2, 0x729A, 0xA0D3, 0x729B, 0xA0D4, 0x729C, 0xA0D5, 0x729D, + 0xA0D6, 0x729E, 0xA0D7, 0x72A0, 0xA0D8, 0x72A1, 0xA0D9, 0x72A2, 0xA0DA, 0x72A3, 0xA0DB, 0x72A4, 0xA0DC, 0x72A5, 0xA0DD, 0x72A6, + 0xA0DE, 0x72A7, 0xA0DF, 0x72A8, 0xA0E0, 0x72A9, 0xA0E1, 0x72AA, 0xA0E2, 0x72AB, 0xA0E3, 0x72AE, 0xA0E4, 0x72B1, 0xA0E5, 0x72B2, + 0xA0E6, 0x72B3, 0xA0E7, 0x72B5, 0xA0E8, 0x72BA, 0xA0E9, 0x72BB, 0xA0EA, 0x72BC, 0xA0EB, 0x72BD, 0xA0EC, 0x72BE, 0xA0ED, 0x72BF, + 0xA0EE, 0x72C0, 0xA0EF, 0x72C5, 0xA0F0, 0x72C6, 0xA0F1, 0x72C7, 0xA0F2, 0x72C9, 0xA0F3, 0x72CA, 0xA0F4, 0x72CB, 0xA0F5, 0x72CC, + 0xA0F6, 0x72CF, 0xA0F7, 0x72D1, 0xA0F8, 0x72D3, 0xA0F9, 0x72D4, 0xA0FA, 0x72D5, 0xA0FB, 0x72D6, 0xA0FC, 0x72D8, 0xA0FD, 0x72DA, + 0xA0FE, 0x72DB, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, 0xA1A5, 0x02C9, 0xA1A6, 0x02C7, 0xA1A7, 0x00A8, + 0xA1A8, 0x3003, 0xA1A9, 0x3005, 0xA1AA, 0x2014, 0xA1AB, 0xFF5E, 0xA1AC, 0x2016, 0xA1AD, 0x2026, 0xA1AE, 0x2018, 0xA1AF, 0x2019, + 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, + 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3016, 0xA1BD, 0x3017, 0xA1BE, 0x3010, 0xA1BF, 0x3011, + 0xA1C0, 0x00B1, 0xA1C1, 0x00D7, 0xA1C2, 0x00F7, 0xA1C3, 0x2236, 0xA1C4, 0x2227, 0xA1C5, 0x2228, 0xA1C6, 0x2211, 0xA1C7, 0x220F, + 0xA1C8, 0x222A, 0xA1C9, 0x2229, 0xA1CA, 0x2208, 0xA1CB, 0x2237, 0xA1CC, 0x221A, 0xA1CD, 0x22A5, 0xA1CE, 0x2225, 0xA1CF, 0x2220, + 0xA1D0, 0x2312, 0xA1D1, 0x2299, 0xA1D2, 0x222B, 0xA1D3, 0x222E, 0xA1D4, 0x2261, 0xA1D5, 0x224C, 0xA1D6, 0x2248, 0xA1D7, 0x223D, + 0xA1D8, 0x221D, 0xA1D9, 0x2260, 0xA1DA, 0x226E, 0xA1DB, 0x226F, 0xA1DC, 0x2264, 0xA1DD, 0x2265, 0xA1DE, 0x221E, 0xA1DF, 0x2235, + 0xA1E0, 0x2234, 0xA1E1, 0x2642, 0xA1E2, 0x2640, 0xA1E3, 0x00B0, 0xA1E4, 0x2032, 0xA1E5, 0x2033, 0xA1E6, 0x2103, 0xA1E7, 0xFF04, + 0xA1E8, 0x00A4, 0xA1E9, 0xFFE0, 0xA1EA, 0xFFE1, 0xA1EB, 0x2030, 0xA1EC, 0x00A7, 0xA1ED, 0x2116, 0xA1EE, 0x2606, 0xA1EF, 0x2605, + 0xA1F0, 0x25CB, 0xA1F1, 0x25CF, 0xA1F2, 0x25CE, 0xA1F3, 0x25C7, 0xA1F4, 0x25C6, 0xA1F5, 0x25A1, 0xA1F6, 0x25A0, 0xA1F7, 0x25B3, + 0xA1F8, 0x25B2, 0xA1F9, 0x203B, 0xA1FA, 0x2192, 0xA1FB, 0x2190, 0xA1FC, 0x2191, 0xA1FD, 0x2193, 0xA1FE, 0x3013, 0xA2A1, 0x2170, + 0xA2A2, 0x2171, 0xA2A3, 0x2172, 0xA2A4, 0x2173, 0xA2A5, 0x2174, 0xA2A6, 0x2175, 0xA2A7, 0x2176, 0xA2A8, 0x2177, 0xA2A9, 0x2178, + 0xA2AA, 0x2179, 0xA2B1, 0x2488, 0xA2B2, 0x2489, 0xA2B3, 0x248A, 0xA2B4, 0x248B, 0xA2B5, 0x248C, 0xA2B6, 0x248D, 0xA2B7, 0x248E, + 0xA2B8, 0x248F, 0xA2B9, 0x2490, 0xA2BA, 0x2491, 0xA2BB, 0x2492, 0xA2BC, 0x2493, 0xA2BD, 0x2494, 0xA2BE, 0x2495, 0xA2BF, 0x2496, + 0xA2C0, 0x2497, 0xA2C1, 0x2498, 0xA2C2, 0x2499, 0xA2C3, 0x249A, 0xA2C4, 0x249B, 0xA2C5, 0x2474, 0xA2C6, 0x2475, 0xA2C7, 0x2476, + 0xA2C8, 0x2477, 0xA2C9, 0x2478, 0xA2CA, 0x2479, 0xA2CB, 0x247A, 0xA2CC, 0x247B, 0xA2CD, 0x247C, 0xA2CE, 0x247D, 0xA2CF, 0x247E, + 0xA2D0, 0x247F, 0xA2D1, 0x2480, 0xA2D2, 0x2481, 0xA2D3, 0x2482, 0xA2D4, 0x2483, 0xA2D5, 0x2484, 0xA2D6, 0x2485, 0xA2D7, 0x2486, + 0xA2D8, 0x2487, 0xA2D9, 0x2460, 0xA2DA, 0x2461, 0xA2DB, 0x2462, 0xA2DC, 0x2463, 0xA2DD, 0x2464, 0xA2DE, 0x2465, 0xA2DF, 0x2466, + 0xA2E0, 0x2467, 0xA2E1, 0x2468, 0xA2E2, 0x2469, 0xA2E5, 0x3220, 0xA2E6, 0x3221, 0xA2E7, 0x3222, 0xA2E8, 0x3223, 0xA2E9, 0x3224, + 0xA2EA, 0x3225, 0xA2EB, 0x3226, 0xA2EC, 0x3227, 0xA2ED, 0x3228, 0xA2EE, 0x3229, 0xA2F1, 0x2160, 0xA2F2, 0x2161, 0xA2F3, 0x2162, + 0xA2F4, 0x2163, 0xA2F5, 0x2164, 0xA2F6, 0x2165, 0xA2F7, 0x2166, 0xA2F8, 0x2167, 0xA2F9, 0x2168, 0xA2FA, 0x2169, 0xA2FB, 0x216A, + 0xA2FC, 0x216B, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFFE5, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, + 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, + 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, + 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, + 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, + 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, + 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, + 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFF3C, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, + 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, + 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, + 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, + 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA4A1, 0x3041, + 0xA4A2, 0x3042, 0xA4A3, 0x3043, 0xA4A4, 0x3044, 0xA4A5, 0x3045, 0xA4A6, 0x3046, 0xA4A7, 0x3047, 0xA4A8, 0x3048, 0xA4A9, 0x3049, + 0xA4AA, 0x304A, 0xA4AB, 0x304B, 0xA4AC, 0x304C, 0xA4AD, 0x304D, 0xA4AE, 0x304E, 0xA4AF, 0x304F, 0xA4B0, 0x3050, 0xA4B1, 0x3051, + 0xA4B2, 0x3052, 0xA4B3, 0x3053, 0xA4B4, 0x3054, 0xA4B5, 0x3055, 0xA4B6, 0x3056, 0xA4B7, 0x3057, 0xA4B8, 0x3058, 0xA4B9, 0x3059, + 0xA4BA, 0x305A, 0xA4BB, 0x305B, 0xA4BC, 0x305C, 0xA4BD, 0x305D, 0xA4BE, 0x305E, 0xA4BF, 0x305F, 0xA4C0, 0x3060, 0xA4C1, 0x3061, + 0xA4C2, 0x3062, 0xA4C3, 0x3063, 0xA4C4, 0x3064, 0xA4C5, 0x3065, 0xA4C6, 0x3066, 0xA4C7, 0x3067, 0xA4C8, 0x3068, 0xA4C9, 0x3069, + 0xA4CA, 0x306A, 0xA4CB, 0x306B, 0xA4CC, 0x306C, 0xA4CD, 0x306D, 0xA4CE, 0x306E, 0xA4CF, 0x306F, 0xA4D0, 0x3070, 0xA4D1, 0x3071, + 0xA4D2, 0x3072, 0xA4D3, 0x3073, 0xA4D4, 0x3074, 0xA4D5, 0x3075, 0xA4D6, 0x3076, 0xA4D7, 0x3077, 0xA4D8, 0x3078, 0xA4D9, 0x3079, + 0xA4DA, 0x307A, 0xA4DB, 0x307B, 0xA4DC, 0x307C, 0xA4DD, 0x307D, 0xA4DE, 0x307E, 0xA4DF, 0x307F, 0xA4E0, 0x3080, 0xA4E1, 0x3081, + 0xA4E2, 0x3082, 0xA4E3, 0x3083, 0xA4E4, 0x3084, 0xA4E5, 0x3085, 0xA4E6, 0x3086, 0xA4E7, 0x3087, 0xA4E8, 0x3088, 0xA4E9, 0x3089, + 0xA4EA, 0x308A, 0xA4EB, 0x308B, 0xA4EC, 0x308C, 0xA4ED, 0x308D, 0xA4EE, 0x308E, 0xA4EF, 0x308F, 0xA4F0, 0x3090, 0xA4F1, 0x3091, + 0xA4F2, 0x3092, 0xA4F3, 0x3093, 0xA5A1, 0x30A1, 0xA5A2, 0x30A2, 0xA5A3, 0x30A3, 0xA5A4, 0x30A4, 0xA5A5, 0x30A5, 0xA5A6, 0x30A6, + 0xA5A7, 0x30A7, 0xA5A8, 0x30A8, 0xA5A9, 0x30A9, 0xA5AA, 0x30AA, 0xA5AB, 0x30AB, 0xA5AC, 0x30AC, 0xA5AD, 0x30AD, 0xA5AE, 0x30AE, + 0xA5AF, 0x30AF, 0xA5B0, 0x30B0, 0xA5B1, 0x30B1, 0xA5B2, 0x30B2, 0xA5B3, 0x30B3, 0xA5B4, 0x30B4, 0xA5B5, 0x30B5, 0xA5B6, 0x30B6, + 0xA5B7, 0x30B7, 0xA5B8, 0x30B8, 0xA5B9, 0x30B9, 0xA5BA, 0x30BA, 0xA5BB, 0x30BB, 0xA5BC, 0x30BC, 0xA5BD, 0x30BD, 0xA5BE, 0x30BE, + 0xA5BF, 0x30BF, 0xA5C0, 0x30C0, 0xA5C1, 0x30C1, 0xA5C2, 0x30C2, 0xA5C3, 0x30C3, 0xA5C4, 0x30C4, 0xA5C5, 0x30C5, 0xA5C6, 0x30C6, + 0xA5C7, 0x30C7, 0xA5C8, 0x30C8, 0xA5C9, 0x30C9, 0xA5CA, 0x30CA, 0xA5CB, 0x30CB, 0xA5CC, 0x30CC, 0xA5CD, 0x30CD, 0xA5CE, 0x30CE, + 0xA5CF, 0x30CF, 0xA5D0, 0x30D0, 0xA5D1, 0x30D1, 0xA5D2, 0x30D2, 0xA5D3, 0x30D3, 0xA5D4, 0x30D4, 0xA5D5, 0x30D5, 0xA5D6, 0x30D6, + 0xA5D7, 0x30D7, 0xA5D8, 0x30D8, 0xA5D9, 0x30D9, 0xA5DA, 0x30DA, 0xA5DB, 0x30DB, 0xA5DC, 0x30DC, 0xA5DD, 0x30DD, 0xA5DE, 0x30DE, + 0xA5DF, 0x30DF, 0xA5E0, 0x30E0, 0xA5E1, 0x30E1, 0xA5E2, 0x30E2, 0xA5E3, 0x30E3, 0xA5E4, 0x30E4, 0xA5E5, 0x30E5, 0xA5E6, 0x30E6, + 0xA5E7, 0x30E7, 0xA5E8, 0x30E8, 0xA5E9, 0x30E9, 0xA5EA, 0x30EA, 0xA5EB, 0x30EB, 0xA5EC, 0x30EC, 0xA5ED, 0x30ED, 0xA5EE, 0x30EE, + 0xA5EF, 0x30EF, 0xA5F0, 0x30F0, 0xA5F1, 0x30F1, 0xA5F2, 0x30F2, 0xA5F3, 0x30F3, 0xA5F4, 0x30F4, 0xA5F5, 0x30F5, 0xA5F6, 0x30F6, + 0xA6A1, 0x0391, 0xA6A2, 0x0392, 0xA6A3, 0x0393, 0xA6A4, 0x0394, 0xA6A5, 0x0395, 0xA6A6, 0x0396, 0xA6A7, 0x0397, 0xA6A8, 0x0398, + 0xA6A9, 0x0399, 0xA6AA, 0x039A, 0xA6AB, 0x039B, 0xA6AC, 0x039C, 0xA6AD, 0x039D, 0xA6AE, 0x039E, 0xA6AF, 0x039F, 0xA6B0, 0x03A0, + 0xA6B1, 0x03A1, 0xA6B2, 0x03A3, 0xA6B3, 0x03A4, 0xA6B4, 0x03A5, 0xA6B5, 0x03A6, 0xA6B6, 0x03A7, 0xA6B7, 0x03A8, 0xA6B8, 0x03A9, + 0xA6C1, 0x03B1, 0xA6C2, 0x03B2, 0xA6C3, 0x03B3, 0xA6C4, 0x03B4, 0xA6C5, 0x03B5, 0xA6C6, 0x03B6, 0xA6C7, 0x03B7, 0xA6C8, 0x03B8, + 0xA6C9, 0x03B9, 0xA6CA, 0x03BA, 0xA6CB, 0x03BB, 0xA6CC, 0x03BC, 0xA6CD, 0x03BD, 0xA6CE, 0x03BE, 0xA6CF, 0x03BF, 0xA6D0, 0x03C0, + 0xA6D1, 0x03C1, 0xA6D2, 0x03C3, 0xA6D3, 0x03C4, 0xA6D4, 0x03C5, 0xA6D5, 0x03C6, 0xA6D6, 0x03C7, 0xA6D7, 0x03C8, 0xA6D8, 0x03C9, + 0xA6E0, 0xFE35, 0xA6E1, 0xFE36, 0xA6E2, 0xFE39, 0xA6E3, 0xFE3A, 0xA6E4, 0xFE3F, 0xA6E5, 0xFE40, 0xA6E6, 0xFE3D, 0xA6E7, 0xFE3E, + 0xA6E8, 0xFE41, 0xA6E9, 0xFE42, 0xA6EA, 0xFE43, 0xA6EB, 0xFE44, 0xA6EE, 0xFE3B, 0xA6EF, 0xFE3C, 0xA6F0, 0xFE37, 0xA6F1, 0xFE38, + 0xA6F2, 0xFE31, 0xA6F4, 0xFE33, 0xA6F5, 0xFE34, 0xA7A1, 0x0410, 0xA7A2, 0x0411, 0xA7A3, 0x0412, 0xA7A4, 0x0413, 0xA7A5, 0x0414, + 0xA7A6, 0x0415, 0xA7A7, 0x0401, 0xA7A8, 0x0416, 0xA7A9, 0x0417, 0xA7AA, 0x0418, 0xA7AB, 0x0419, 0xA7AC, 0x041A, 0xA7AD, 0x041B, + 0xA7AE, 0x041C, 0xA7AF, 0x041D, 0xA7B0, 0x041E, 0xA7B1, 0x041F, 0xA7B2, 0x0420, 0xA7B3, 0x0421, 0xA7B4, 0x0422, 0xA7B5, 0x0423, + 0xA7B6, 0x0424, 0xA7B7, 0x0425, 0xA7B8, 0x0426, 0xA7B9, 0x0427, 0xA7BA, 0x0428, 0xA7BB, 0x0429, 0xA7BC, 0x042A, 0xA7BD, 0x042B, + 0xA7BE, 0x042C, 0xA7BF, 0x042D, 0xA7C0, 0x042E, 0xA7C1, 0x042F, 0xA7D1, 0x0430, 0xA7D2, 0x0431, 0xA7D3, 0x0432, 0xA7D4, 0x0433, + 0xA7D5, 0x0434, 0xA7D6, 0x0435, 0xA7D7, 0x0451, 0xA7D8, 0x0436, 0xA7D9, 0x0437, 0xA7DA, 0x0438, 0xA7DB, 0x0439, 0xA7DC, 0x043A, + 0xA7DD, 0x043B, 0xA7DE, 0x043C, 0xA7DF, 0x043D, 0xA7E0, 0x043E, 0xA7E1, 0x043F, 0xA7E2, 0x0440, 0xA7E3, 0x0441, 0xA7E4, 0x0442, + 0xA7E5, 0x0443, 0xA7E6, 0x0444, 0xA7E7, 0x0445, 0xA7E8, 0x0446, 0xA7E9, 0x0447, 0xA7EA, 0x0448, 0xA7EB, 0x0449, 0xA7EC, 0x044A, + 0xA7ED, 0x044B, 0xA7EE, 0x044C, 0xA7EF, 0x044D, 0xA7F0, 0x044E, 0xA7F1, 0x044F, 0xA840, 0x02CA, 0xA841, 0x02CB, 0xA842, 0x02D9, + 0xA843, 0x2013, 0xA844, 0x2015, 0xA845, 0x2025, 0xA846, 0x2035, 0xA847, 0x2105, 0xA848, 0x2109, 0xA849, 0x2196, 0xA84A, 0x2197, + 0xA84B, 0x2198, 0xA84C, 0x2199, 0xA84D, 0x2215, 0xA84E, 0x221F, 0xA84F, 0x2223, 0xA850, 0x2252, 0xA851, 0x2266, 0xA852, 0x2267, + 0xA853, 0x22BF, 0xA854, 0x2550, 0xA855, 0x2551, 0xA856, 0x2552, 0xA857, 0x2553, 0xA858, 0x2554, 0xA859, 0x2555, 0xA85A, 0x2556, + 0xA85B, 0x2557, 0xA85C, 0x2558, 0xA85D, 0x2559, 0xA85E, 0x255A, 0xA85F, 0x255B, 0xA860, 0x255C, 0xA861, 0x255D, 0xA862, 0x255E, + 0xA863, 0x255F, 0xA864, 0x2560, 0xA865, 0x2561, 0xA866, 0x2562, 0xA867, 0x2563, 0xA868, 0x2564, 0xA869, 0x2565, 0xA86A, 0x2566, + 0xA86B, 0x2567, 0xA86C, 0x2568, 0xA86D, 0x2569, 0xA86E, 0x256A, 0xA86F, 0x256B, 0xA870, 0x256C, 0xA871, 0x256D, 0xA872, 0x256E, + 0xA873, 0x256F, 0xA874, 0x2570, 0xA875, 0x2571, 0xA876, 0x2572, 0xA877, 0x2573, 0xA878, 0x2581, 0xA879, 0x2582, 0xA87A, 0x2583, + 0xA87B, 0x2584, 0xA87C, 0x2585, 0xA87D, 0x2586, 0xA87E, 0x2587, 0xA880, 0x2588, 0xA881, 0x2589, 0xA882, 0x258A, 0xA883, 0x258B, + 0xA884, 0x258C, 0xA885, 0x258D, 0xA886, 0x258E, 0xA887, 0x258F, 0xA888, 0x2593, 0xA889, 0x2594, 0xA88A, 0x2595, 0xA88B, 0x25BC, + 0xA88C, 0x25BD, 0xA88D, 0x25E2, 0xA88E, 0x25E3, 0xA88F, 0x25E4, 0xA890, 0x25E5, 0xA891, 0x2609, 0xA892, 0x2295, 0xA893, 0x3012, + 0xA894, 0x301D, 0xA895, 0x301E, 0xA8A1, 0x0101, 0xA8A2, 0x00E1, 0xA8A3, 0x01CE, 0xA8A4, 0x00E0, 0xA8A5, 0x0113, 0xA8A6, 0x00E9, + 0xA8A7, 0x011B, 0xA8A8, 0x00E8, 0xA8A9, 0x012B, 0xA8AA, 0x00ED, 0xA8AB, 0x01D0, 0xA8AC, 0x00EC, 0xA8AD, 0x014D, 0xA8AE, 0x00F3, + 0xA8AF, 0x01D2, 0xA8B0, 0x00F2, 0xA8B1, 0x016B, 0xA8B2, 0x00FA, 0xA8B3, 0x01D4, 0xA8B4, 0x00F9, 0xA8B5, 0x01D6, 0xA8B6, 0x01D8, + 0xA8B7, 0x01DA, 0xA8B8, 0x01DC, 0xA8B9, 0x00FC, 0xA8BA, 0x00EA, 0xA8BB, 0x0251, 0xA8BD, 0x0144, 0xA8BE, 0x0148, 0xA8C0, 0x0261, + 0xA8C5, 0x3105, 0xA8C6, 0x3106, 0xA8C7, 0x3107, 0xA8C8, 0x3108, 0xA8C9, 0x3109, 0xA8CA, 0x310A, 0xA8CB, 0x310B, 0xA8CC, 0x310C, + 0xA8CD, 0x310D, 0xA8CE, 0x310E, 0xA8CF, 0x310F, 0xA8D0, 0x3110, 0xA8D1, 0x3111, 0xA8D2, 0x3112, 0xA8D3, 0x3113, 0xA8D4, 0x3114, + 0xA8D5, 0x3115, 0xA8D6, 0x3116, 0xA8D7, 0x3117, 0xA8D8, 0x3118, 0xA8D9, 0x3119, 0xA8DA, 0x311A, 0xA8DB, 0x311B, 0xA8DC, 0x311C, + 0xA8DD, 0x311D, 0xA8DE, 0x311E, 0xA8DF, 0x311F, 0xA8E0, 0x3120, 0xA8E1, 0x3121, 0xA8E2, 0x3122, 0xA8E3, 0x3123, 0xA8E4, 0x3124, + 0xA8E5, 0x3125, 0xA8E6, 0x3126, 0xA8E7, 0x3127, 0xA8E8, 0x3128, 0xA8E9, 0x3129, 0xA940, 0x3021, 0xA941, 0x3022, 0xA942, 0x3023, + 0xA943, 0x3024, 0xA944, 0x3025, 0xA945, 0x3026, 0xA946, 0x3027, 0xA947, 0x3028, 0xA948, 0x3029, 0xA949, 0x32A3, 0xA94A, 0x338E, + 0xA94B, 0x338F, 0xA94C, 0x339C, 0xA94D, 0x339D, 0xA94E, 0x339E, 0xA94F, 0x33A1, 0xA950, 0x33C4, 0xA951, 0x33CE, 0xA952, 0x33D1, + 0xA953, 0x33D2, 0xA954, 0x33D5, 0xA955, 0xFE30, 0xA956, 0xFFE2, 0xA957, 0xFFE4, 0xA959, 0x2121, 0xA95A, 0x3231, 0xA95C, 0x2010, + 0xA960, 0x30FC, 0xA961, 0x309B, 0xA962, 0x309C, 0xA963, 0x30FD, 0xA964, 0x30FE, 0xA965, 0x3006, 0xA966, 0x309D, 0xA967, 0x309E, + 0xA968, 0xFE49, 0xA969, 0xFE4A, 0xA96A, 0xFE4B, 0xA96B, 0xFE4C, 0xA96C, 0xFE4D, 0xA96D, 0xFE4E, 0xA96E, 0xFE4F, 0xA96F, 0xFE50, + 0xA970, 0xFE51, 0xA971, 0xFE52, 0xA972, 0xFE54, 0xA973, 0xFE55, 0xA974, 0xFE56, 0xA975, 0xFE57, 0xA976, 0xFE59, 0xA977, 0xFE5A, + 0xA978, 0xFE5B, 0xA979, 0xFE5C, 0xA97A, 0xFE5D, 0xA97B, 0xFE5E, 0xA97C, 0xFE5F, 0xA97D, 0xFE60, 0xA97E, 0xFE61, 0xA980, 0xFE62, + 0xA981, 0xFE63, 0xA982, 0xFE64, 0xA983, 0xFE65, 0xA984, 0xFE66, 0xA985, 0xFE68, 0xA986, 0xFE69, 0xA987, 0xFE6A, 0xA988, 0xFE6B, + 0xA996, 0x3007, 0xA9A4, 0x2500, 0xA9A5, 0x2501, 0xA9A6, 0x2502, 0xA9A7, 0x2503, 0xA9A8, 0x2504, 0xA9A9, 0x2505, 0xA9AA, 0x2506, + 0xA9AB, 0x2507, 0xA9AC, 0x2508, 0xA9AD, 0x2509, 0xA9AE, 0x250A, 0xA9AF, 0x250B, 0xA9B0, 0x250C, 0xA9B1, 0x250D, 0xA9B2, 0x250E, + 0xA9B3, 0x250F, 0xA9B4, 0x2510, 0xA9B5, 0x2511, 0xA9B6, 0x2512, 0xA9B7, 0x2513, 0xA9B8, 0x2514, 0xA9B9, 0x2515, 0xA9BA, 0x2516, + 0xA9BB, 0x2517, 0xA9BC, 0x2518, 0xA9BD, 0x2519, 0xA9BE, 0x251A, 0xA9BF, 0x251B, 0xA9C0, 0x251C, 0xA9C1, 0x251D, 0xA9C2, 0x251E, + 0xA9C3, 0x251F, 0xA9C4, 0x2520, 0xA9C5, 0x2521, 0xA9C6, 0x2522, 0xA9C7, 0x2523, 0xA9C8, 0x2524, 0xA9C9, 0x2525, 0xA9CA, 0x2526, + 0xA9CB, 0x2527, 0xA9CC, 0x2528, 0xA9CD, 0x2529, 0xA9CE, 0x252A, 0xA9CF, 0x252B, 0xA9D0, 0x252C, 0xA9D1, 0x252D, 0xA9D2, 0x252E, + 0xA9D3, 0x252F, 0xA9D4, 0x2530, 0xA9D5, 0x2531, 0xA9D6, 0x2532, 0xA9D7, 0x2533, 0xA9D8, 0x2534, 0xA9D9, 0x2535, 0xA9DA, 0x2536, + 0xA9DB, 0x2537, 0xA9DC, 0x2538, 0xA9DD, 0x2539, 0xA9DE, 0x253A, 0xA9DF, 0x253B, 0xA9E0, 0x253C, 0xA9E1, 0x253D, 0xA9E2, 0x253E, + 0xA9E3, 0x253F, 0xA9E4, 0x2540, 0xA9E5, 0x2541, 0xA9E6, 0x2542, 0xA9E7, 0x2543, 0xA9E8, 0x2544, 0xA9E9, 0x2545, 0xA9EA, 0x2546, + 0xA9EB, 0x2547, 0xA9EC, 0x2548, 0xA9ED, 0x2549, 0xA9EE, 0x254A, 0xA9EF, 0x254B, 0xAA40, 0x72DC, 0xAA41, 0x72DD, 0xAA42, 0x72DF, + 0xAA43, 0x72E2, 0xAA44, 0x72E3, 0xAA45, 0x72E4, 0xAA46, 0x72E5, 0xAA47, 0x72E6, 0xAA48, 0x72E7, 0xAA49, 0x72EA, 0xAA4A, 0x72EB, + 0xAA4B, 0x72F5, 0xAA4C, 0x72F6, 0xAA4D, 0x72F9, 0xAA4E, 0x72FD, 0xAA4F, 0x72FE, 0xAA50, 0x72FF, 0xAA51, 0x7300, 0xAA52, 0x7302, + 0xAA53, 0x7304, 0xAA54, 0x7305, 0xAA55, 0x7306, 0xAA56, 0x7307, 0xAA57, 0x7308, 0xAA58, 0x7309, 0xAA59, 0x730B, 0xAA5A, 0x730C, + 0xAA5B, 0x730D, 0xAA5C, 0x730F, 0xAA5D, 0x7310, 0xAA5E, 0x7311, 0xAA5F, 0x7312, 0xAA60, 0x7314, 0xAA61, 0x7318, 0xAA62, 0x7319, + 0xAA63, 0x731A, 0xAA64, 0x731F, 0xAA65, 0x7320, 0xAA66, 0x7323, 0xAA67, 0x7324, 0xAA68, 0x7326, 0xAA69, 0x7327, 0xAA6A, 0x7328, + 0xAA6B, 0x732D, 0xAA6C, 0x732F, 0xAA6D, 0x7330, 0xAA6E, 0x7332, 0xAA6F, 0x7333, 0xAA70, 0x7335, 0xAA71, 0x7336, 0xAA72, 0x733A, + 0xAA73, 0x733B, 0xAA74, 0x733C, 0xAA75, 0x733D, 0xAA76, 0x7340, 0xAA77, 0x7341, 0xAA78, 0x7342, 0xAA79, 0x7343, 0xAA7A, 0x7344, + 0xAA7B, 0x7345, 0xAA7C, 0x7346, 0xAA7D, 0x7347, 0xAA7E, 0x7348, 0xAA80, 0x7349, 0xAA81, 0x734A, 0xAA82, 0x734B, 0xAA83, 0x734C, + 0xAA84, 0x734E, 0xAA85, 0x734F, 0xAA86, 0x7351, 0xAA87, 0x7353, 0xAA88, 0x7354, 0xAA89, 0x7355, 0xAA8A, 0x7356, 0xAA8B, 0x7358, + 0xAA8C, 0x7359, 0xAA8D, 0x735A, 0xAA8E, 0x735B, 0xAA8F, 0x735C, 0xAA90, 0x735D, 0xAA91, 0x735E, 0xAA92, 0x735F, 0xAA93, 0x7361, + 0xAA94, 0x7362, 0xAA95, 0x7363, 0xAA96, 0x7364, 0xAA97, 0x7365, 0xAA98, 0x7366, 0xAA99, 0x7367, 0xAA9A, 0x7368, 0xAA9B, 0x7369, + 0xAA9C, 0x736A, 0xAA9D, 0x736B, 0xAA9E, 0x736E, 0xAA9F, 0x7370, 0xAAA0, 0x7371, 0xAB40, 0x7372, 0xAB41, 0x7373, 0xAB42, 0x7374, + 0xAB43, 0x7375, 0xAB44, 0x7376, 0xAB45, 0x7377, 0xAB46, 0x7378, 0xAB47, 0x7379, 0xAB48, 0x737A, 0xAB49, 0x737B, 0xAB4A, 0x737C, + 0xAB4B, 0x737D, 0xAB4C, 0x737F, 0xAB4D, 0x7380, 0xAB4E, 0x7381, 0xAB4F, 0x7382, 0xAB50, 0x7383, 0xAB51, 0x7385, 0xAB52, 0x7386, + 0xAB53, 0x7388, 0xAB54, 0x738A, 0xAB55, 0x738C, 0xAB56, 0x738D, 0xAB57, 0x738F, 0xAB58, 0x7390, 0xAB59, 0x7392, 0xAB5A, 0x7393, + 0xAB5B, 0x7394, 0xAB5C, 0x7395, 0xAB5D, 0x7397, 0xAB5E, 0x7398, 0xAB5F, 0x7399, 0xAB60, 0x739A, 0xAB61, 0x739C, 0xAB62, 0x739D, + 0xAB63, 0x739E, 0xAB64, 0x73A0, 0xAB65, 0x73A1, 0xAB66, 0x73A3, 0xAB67, 0x73A4, 0xAB68, 0x73A5, 0xAB69, 0x73A6, 0xAB6A, 0x73A7, + 0xAB6B, 0x73A8, 0xAB6C, 0x73AA, 0xAB6D, 0x73AC, 0xAB6E, 0x73AD, 0xAB6F, 0x73B1, 0xAB70, 0x73B4, 0xAB71, 0x73B5, 0xAB72, 0x73B6, + 0xAB73, 0x73B8, 0xAB74, 0x73B9, 0xAB75, 0x73BC, 0xAB76, 0x73BD, 0xAB77, 0x73BE, 0xAB78, 0x73BF, 0xAB79, 0x73C1, 0xAB7A, 0x73C3, + 0xAB7B, 0x73C4, 0xAB7C, 0x73C5, 0xAB7D, 0x73C6, 0xAB7E, 0x73C7, 0xAB80, 0x73CB, 0xAB81, 0x73CC, 0xAB82, 0x73CE, 0xAB83, 0x73D2, + 0xAB84, 0x73D3, 0xAB85, 0x73D4, 0xAB86, 0x73D5, 0xAB87, 0x73D6, 0xAB88, 0x73D7, 0xAB89, 0x73D8, 0xAB8A, 0x73DA, 0xAB8B, 0x73DB, + 0xAB8C, 0x73DC, 0xAB8D, 0x73DD, 0xAB8E, 0x73DF, 0xAB8F, 0x73E1, 0xAB90, 0x73E2, 0xAB91, 0x73E3, 0xAB92, 0x73E4, 0xAB93, 0x73E6, + 0xAB94, 0x73E8, 0xAB95, 0x73EA, 0xAB96, 0x73EB, 0xAB97, 0x73EC, 0xAB98, 0x73EE, 0xAB99, 0x73EF, 0xAB9A, 0x73F0, 0xAB9B, 0x73F1, + 0xAB9C, 0x73F3, 0xAB9D, 0x73F4, 0xAB9E, 0x73F5, 0xAB9F, 0x73F6, 0xABA0, 0x73F7, 0xAC40, 0x73F8, 0xAC41, 0x73F9, 0xAC42, 0x73FA, + 0xAC43, 0x73FB, 0xAC44, 0x73FC, 0xAC45, 0x73FD, 0xAC46, 0x73FE, 0xAC47, 0x73FF, 0xAC48, 0x7400, 0xAC49, 0x7401, 0xAC4A, 0x7402, + 0xAC4B, 0x7404, 0xAC4C, 0x7407, 0xAC4D, 0x7408, 0xAC4E, 0x740B, 0xAC4F, 0x740C, 0xAC50, 0x740D, 0xAC51, 0x740E, 0xAC52, 0x7411, + 0xAC53, 0x7412, 0xAC54, 0x7413, 0xAC55, 0x7414, 0xAC56, 0x7415, 0xAC57, 0x7416, 0xAC58, 0x7417, 0xAC59, 0x7418, 0xAC5A, 0x7419, + 0xAC5B, 0x741C, 0xAC5C, 0x741D, 0xAC5D, 0x741E, 0xAC5E, 0x741F, 0xAC5F, 0x7420, 0xAC60, 0x7421, 0xAC61, 0x7423, 0xAC62, 0x7424, + 0xAC63, 0x7427, 0xAC64, 0x7429, 0xAC65, 0x742B, 0xAC66, 0x742D, 0xAC67, 0x742F, 0xAC68, 0x7431, 0xAC69, 0x7432, 0xAC6A, 0x7437, + 0xAC6B, 0x7438, 0xAC6C, 0x7439, 0xAC6D, 0x743A, 0xAC6E, 0x743B, 0xAC6F, 0x743D, 0xAC70, 0x743E, 0xAC71, 0x743F, 0xAC72, 0x7440, + 0xAC73, 0x7442, 0xAC74, 0x7443, 0xAC75, 0x7444, 0xAC76, 0x7445, 0xAC77, 0x7446, 0xAC78, 0x7447, 0xAC79, 0x7448, 0xAC7A, 0x7449, + 0xAC7B, 0x744A, 0xAC7C, 0x744B, 0xAC7D, 0x744C, 0xAC7E, 0x744D, 0xAC80, 0x744E, 0xAC81, 0x744F, 0xAC82, 0x7450, 0xAC83, 0x7451, + 0xAC84, 0x7452, 0xAC85, 0x7453, 0xAC86, 0x7454, 0xAC87, 0x7456, 0xAC88, 0x7458, 0xAC89, 0x745D, 0xAC8A, 0x7460, 0xAC8B, 0x7461, + 0xAC8C, 0x7462, 0xAC8D, 0x7463, 0xAC8E, 0x7464, 0xAC8F, 0x7465, 0xAC90, 0x7466, 0xAC91, 0x7467, 0xAC92, 0x7468, 0xAC93, 0x7469, + 0xAC94, 0x746A, 0xAC95, 0x746B, 0xAC96, 0x746C, 0xAC97, 0x746E, 0xAC98, 0x746F, 0xAC99, 0x7471, 0xAC9A, 0x7472, 0xAC9B, 0x7473, + 0xAC9C, 0x7474, 0xAC9D, 0x7475, 0xAC9E, 0x7478, 0xAC9F, 0x7479, 0xACA0, 0x747A, 0xAD40, 0x747B, 0xAD41, 0x747C, 0xAD42, 0x747D, + 0xAD43, 0x747F, 0xAD44, 0x7482, 0xAD45, 0x7484, 0xAD46, 0x7485, 0xAD47, 0x7486, 0xAD48, 0x7488, 0xAD49, 0x7489, 0xAD4A, 0x748A, + 0xAD4B, 0x748C, 0xAD4C, 0x748D, 0xAD4D, 0x748F, 0xAD4E, 0x7491, 0xAD4F, 0x7492, 0xAD50, 0x7493, 0xAD51, 0x7494, 0xAD52, 0x7495, + 0xAD53, 0x7496, 0xAD54, 0x7497, 0xAD55, 0x7498, 0xAD56, 0x7499, 0xAD57, 0x749A, 0xAD58, 0x749B, 0xAD59, 0x749D, 0xAD5A, 0x749F, + 0xAD5B, 0x74A0, 0xAD5C, 0x74A1, 0xAD5D, 0x74A2, 0xAD5E, 0x74A3, 0xAD5F, 0x74A4, 0xAD60, 0x74A5, 0xAD61, 0x74A6, 0xAD62, 0x74AA, + 0xAD63, 0x74AB, 0xAD64, 0x74AC, 0xAD65, 0x74AD, 0xAD66, 0x74AE, 0xAD67, 0x74AF, 0xAD68, 0x74B0, 0xAD69, 0x74B1, 0xAD6A, 0x74B2, + 0xAD6B, 0x74B3, 0xAD6C, 0x74B4, 0xAD6D, 0x74B5, 0xAD6E, 0x74B6, 0xAD6F, 0x74B7, 0xAD70, 0x74B8, 0xAD71, 0x74B9, 0xAD72, 0x74BB, + 0xAD73, 0x74BC, 0xAD74, 0x74BD, 0xAD75, 0x74BE, 0xAD76, 0x74BF, 0xAD77, 0x74C0, 0xAD78, 0x74C1, 0xAD79, 0x74C2, 0xAD7A, 0x74C3, + 0xAD7B, 0x74C4, 0xAD7C, 0x74C5, 0xAD7D, 0x74C6, 0xAD7E, 0x74C7, 0xAD80, 0x74C8, 0xAD81, 0x74C9, 0xAD82, 0x74CA, 0xAD83, 0x74CB, + 0xAD84, 0x74CC, 0xAD85, 0x74CD, 0xAD86, 0x74CE, 0xAD87, 0x74CF, 0xAD88, 0x74D0, 0xAD89, 0x74D1, 0xAD8A, 0x74D3, 0xAD8B, 0x74D4, + 0xAD8C, 0x74D5, 0xAD8D, 0x74D6, 0xAD8E, 0x74D7, 0xAD8F, 0x74D8, 0xAD90, 0x74D9, 0xAD91, 0x74DA, 0xAD92, 0x74DB, 0xAD93, 0x74DD, + 0xAD94, 0x74DF, 0xAD95, 0x74E1, 0xAD96, 0x74E5, 0xAD97, 0x74E7, 0xAD98, 0x74E8, 0xAD99, 0x74E9, 0xAD9A, 0x74EA, 0xAD9B, 0x74EB, + 0xAD9C, 0x74EC, 0xAD9D, 0x74ED, 0xAD9E, 0x74F0, 0xAD9F, 0x74F1, 0xADA0, 0x74F2, 0xAE40, 0x74F3, 0xAE41, 0x74F5, 0xAE42, 0x74F8, + 0xAE43, 0x74F9, 0xAE44, 0x74FA, 0xAE45, 0x74FB, 0xAE46, 0x74FC, 0xAE47, 0x74FD, 0xAE48, 0x74FE, 0xAE49, 0x7500, 0xAE4A, 0x7501, + 0xAE4B, 0x7502, 0xAE4C, 0x7503, 0xAE4D, 0x7505, 0xAE4E, 0x7506, 0xAE4F, 0x7507, 0xAE50, 0x7508, 0xAE51, 0x7509, 0xAE52, 0x750A, + 0xAE53, 0x750B, 0xAE54, 0x750C, 0xAE55, 0x750E, 0xAE56, 0x7510, 0xAE57, 0x7512, 0xAE58, 0x7514, 0xAE59, 0x7515, 0xAE5A, 0x7516, + 0xAE5B, 0x7517, 0xAE5C, 0x751B, 0xAE5D, 0x751D, 0xAE5E, 0x751E, 0xAE5F, 0x7520, 0xAE60, 0x7521, 0xAE61, 0x7522, 0xAE62, 0x7523, + 0xAE63, 0x7524, 0xAE64, 0x7526, 0xAE65, 0x7527, 0xAE66, 0x752A, 0xAE67, 0x752E, 0xAE68, 0x7534, 0xAE69, 0x7536, 0xAE6A, 0x7539, + 0xAE6B, 0x753C, 0xAE6C, 0x753D, 0xAE6D, 0x753F, 0xAE6E, 0x7541, 0xAE6F, 0x7542, 0xAE70, 0x7543, 0xAE71, 0x7544, 0xAE72, 0x7546, + 0xAE73, 0x7547, 0xAE74, 0x7549, 0xAE75, 0x754A, 0xAE76, 0x754D, 0xAE77, 0x7550, 0xAE78, 0x7551, 0xAE79, 0x7552, 0xAE7A, 0x7553, + 0xAE7B, 0x7555, 0xAE7C, 0x7556, 0xAE7D, 0x7557, 0xAE7E, 0x7558, 0xAE80, 0x755D, 0xAE81, 0x755E, 0xAE82, 0x755F, 0xAE83, 0x7560, + 0xAE84, 0x7561, 0xAE85, 0x7562, 0xAE86, 0x7563, 0xAE87, 0x7564, 0xAE88, 0x7567, 0xAE89, 0x7568, 0xAE8A, 0x7569, 0xAE8B, 0x756B, + 0xAE8C, 0x756C, 0xAE8D, 0x756D, 0xAE8E, 0x756E, 0xAE8F, 0x756F, 0xAE90, 0x7570, 0xAE91, 0x7571, 0xAE92, 0x7573, 0xAE93, 0x7575, + 0xAE94, 0x7576, 0xAE95, 0x7577, 0xAE96, 0x757A, 0xAE97, 0x757B, 0xAE98, 0x757C, 0xAE99, 0x757D, 0xAE9A, 0x757E, 0xAE9B, 0x7580, + 0xAE9C, 0x7581, 0xAE9D, 0x7582, 0xAE9E, 0x7584, 0xAE9F, 0x7585, 0xAEA0, 0x7587, 0xAF40, 0x7588, 0xAF41, 0x7589, 0xAF42, 0x758A, + 0xAF43, 0x758C, 0xAF44, 0x758D, 0xAF45, 0x758E, 0xAF46, 0x7590, 0xAF47, 0x7593, 0xAF48, 0x7595, 0xAF49, 0x7598, 0xAF4A, 0x759B, + 0xAF4B, 0x759C, 0xAF4C, 0x759E, 0xAF4D, 0x75A2, 0xAF4E, 0x75A6, 0xAF4F, 0x75A7, 0xAF50, 0x75A8, 0xAF51, 0x75A9, 0xAF52, 0x75AA, + 0xAF53, 0x75AD, 0xAF54, 0x75B6, 0xAF55, 0x75B7, 0xAF56, 0x75BA, 0xAF57, 0x75BB, 0xAF58, 0x75BF, 0xAF59, 0x75C0, 0xAF5A, 0x75C1, + 0xAF5B, 0x75C6, 0xAF5C, 0x75CB, 0xAF5D, 0x75CC, 0xAF5E, 0x75CE, 0xAF5F, 0x75CF, 0xAF60, 0x75D0, 0xAF61, 0x75D1, 0xAF62, 0x75D3, + 0xAF63, 0x75D7, 0xAF64, 0x75D9, 0xAF65, 0x75DA, 0xAF66, 0x75DC, 0xAF67, 0x75DD, 0xAF68, 0x75DF, 0xAF69, 0x75E0, 0xAF6A, 0x75E1, + 0xAF6B, 0x75E5, 0xAF6C, 0x75E9, 0xAF6D, 0x75EC, 0xAF6E, 0x75ED, 0xAF6F, 0x75EE, 0xAF70, 0x75EF, 0xAF71, 0x75F2, 0xAF72, 0x75F3, + 0xAF73, 0x75F5, 0xAF74, 0x75F6, 0xAF75, 0x75F7, 0xAF76, 0x75F8, 0xAF77, 0x75FA, 0xAF78, 0x75FB, 0xAF79, 0x75FD, 0xAF7A, 0x75FE, + 0xAF7B, 0x7602, 0xAF7C, 0x7604, 0xAF7D, 0x7606, 0xAF7E, 0x7607, 0xAF80, 0x7608, 0xAF81, 0x7609, 0xAF82, 0x760B, 0xAF83, 0x760D, + 0xAF84, 0x760E, 0xAF85, 0x760F, 0xAF86, 0x7611, 0xAF87, 0x7612, 0xAF88, 0x7613, 0xAF89, 0x7614, 0xAF8A, 0x7616, 0xAF8B, 0x761A, + 0xAF8C, 0x761C, 0xAF8D, 0x761D, 0xAF8E, 0x761E, 0xAF8F, 0x7621, 0xAF90, 0x7623, 0xAF91, 0x7627, 0xAF92, 0x7628, 0xAF93, 0x762C, + 0xAF94, 0x762E, 0xAF95, 0x762F, 0xAF96, 0x7631, 0xAF97, 0x7632, 0xAF98, 0x7636, 0xAF99, 0x7637, 0xAF9A, 0x7639, 0xAF9B, 0x763A, + 0xAF9C, 0x763B, 0xAF9D, 0x763D, 0xAF9E, 0x7641, 0xAF9F, 0x7642, 0xAFA0, 0x7644, 0xB040, 0x7645, 0xB041, 0x7646, 0xB042, 0x7647, + 0xB043, 0x7648, 0xB044, 0x7649, 0xB045, 0x764A, 0xB046, 0x764B, 0xB047, 0x764E, 0xB048, 0x764F, 0xB049, 0x7650, 0xB04A, 0x7651, + 0xB04B, 0x7652, 0xB04C, 0x7653, 0xB04D, 0x7655, 0xB04E, 0x7657, 0xB04F, 0x7658, 0xB050, 0x7659, 0xB051, 0x765A, 0xB052, 0x765B, + 0xB053, 0x765D, 0xB054, 0x765F, 0xB055, 0x7660, 0xB056, 0x7661, 0xB057, 0x7662, 0xB058, 0x7664, 0xB059, 0x7665, 0xB05A, 0x7666, + 0xB05B, 0x7667, 0xB05C, 0x7668, 0xB05D, 0x7669, 0xB05E, 0x766A, 0xB05F, 0x766C, 0xB060, 0x766D, 0xB061, 0x766E, 0xB062, 0x7670, + 0xB063, 0x7671, 0xB064, 0x7672, 0xB065, 0x7673, 0xB066, 0x7674, 0xB067, 0x7675, 0xB068, 0x7676, 0xB069, 0x7677, 0xB06A, 0x7679, + 0xB06B, 0x767A, 0xB06C, 0x767C, 0xB06D, 0x767F, 0xB06E, 0x7680, 0xB06F, 0x7681, 0xB070, 0x7683, 0xB071, 0x7685, 0xB072, 0x7689, + 0xB073, 0x768A, 0xB074, 0x768C, 0xB075, 0x768D, 0xB076, 0x768F, 0xB077, 0x7690, 0xB078, 0x7692, 0xB079, 0x7694, 0xB07A, 0x7695, + 0xB07B, 0x7697, 0xB07C, 0x7698, 0xB07D, 0x769A, 0xB07E, 0x769B, 0xB080, 0x769C, 0xB081, 0x769D, 0xB082, 0x769E, 0xB083, 0x769F, + 0xB084, 0x76A0, 0xB085, 0x76A1, 0xB086, 0x76A2, 0xB087, 0x76A3, 0xB088, 0x76A5, 0xB089, 0x76A6, 0xB08A, 0x76A7, 0xB08B, 0x76A8, + 0xB08C, 0x76A9, 0xB08D, 0x76AA, 0xB08E, 0x76AB, 0xB08F, 0x76AC, 0xB090, 0x76AD, 0xB091, 0x76AF, 0xB092, 0x76B0, 0xB093, 0x76B3, + 0xB094, 0x76B5, 0xB095, 0x76B6, 0xB096, 0x76B7, 0xB097, 0x76B8, 0xB098, 0x76B9, 0xB099, 0x76BA, 0xB09A, 0x76BB, 0xB09B, 0x76BC, + 0xB09C, 0x76BD, 0xB09D, 0x76BE, 0xB09E, 0x76C0, 0xB09F, 0x76C1, 0xB0A0, 0x76C3, 0xB0A1, 0x554A, 0xB0A2, 0x963F, 0xB0A3, 0x57C3, + 0xB0A4, 0x6328, 0xB0A5, 0x54CE, 0xB0A6, 0x5509, 0xB0A7, 0x54C0, 0xB0A8, 0x7691, 0xB0A9, 0x764C, 0xB0AA, 0x853C, 0xB0AB, 0x77EE, + 0xB0AC, 0x827E, 0xB0AD, 0x788D, 0xB0AE, 0x7231, 0xB0AF, 0x9698, 0xB0B0, 0x978D, 0xB0B1, 0x6C28, 0xB0B2, 0x5B89, 0xB0B3, 0x4FFA, + 0xB0B4, 0x6309, 0xB0B5, 0x6697, 0xB0B6, 0x5CB8, 0xB0B7, 0x80FA, 0xB0B8, 0x6848, 0xB0B9, 0x80AE, 0xB0BA, 0x6602, 0xB0BB, 0x76CE, + 0xB0BC, 0x51F9, 0xB0BD, 0x6556, 0xB0BE, 0x71AC, 0xB0BF, 0x7FF1, 0xB0C0, 0x8884, 0xB0C1, 0x50B2, 0xB0C2, 0x5965, 0xB0C3, 0x61CA, + 0xB0C4, 0x6FB3, 0xB0C5, 0x82AD, 0xB0C6, 0x634C, 0xB0C7, 0x6252, 0xB0C8, 0x53ED, 0xB0C9, 0x5427, 0xB0CA, 0x7B06, 0xB0CB, 0x516B, + 0xB0CC, 0x75A4, 0xB0CD, 0x5DF4, 0xB0CE, 0x62D4, 0xB0CF, 0x8DCB, 0xB0D0, 0x9776, 0xB0D1, 0x628A, 0xB0D2, 0x8019, 0xB0D3, 0x575D, + 0xB0D4, 0x9738, 0xB0D5, 0x7F62, 0xB0D6, 0x7238, 0xB0D7, 0x767D, 0xB0D8, 0x67CF, 0xB0D9, 0x767E, 0xB0DA, 0x6446, 0xB0DB, 0x4F70, + 0xB0DC, 0x8D25, 0xB0DD, 0x62DC, 0xB0DE, 0x7A17, 0xB0DF, 0x6591, 0xB0E0, 0x73ED, 0xB0E1, 0x642C, 0xB0E2, 0x6273, 0xB0E3, 0x822C, + 0xB0E4, 0x9881, 0xB0E5, 0x677F, 0xB0E6, 0x7248, 0xB0E7, 0x626E, 0xB0E8, 0x62CC, 0xB0E9, 0x4F34, 0xB0EA, 0x74E3, 0xB0EB, 0x534A, + 0xB0EC, 0x529E, 0xB0ED, 0x7ECA, 0xB0EE, 0x90A6, 0xB0EF, 0x5E2E, 0xB0F0, 0x6886, 0xB0F1, 0x699C, 0xB0F2, 0x8180, 0xB0F3, 0x7ED1, + 0xB0F4, 0x68D2, 0xB0F5, 0x78C5, 0xB0F6, 0x868C, 0xB0F7, 0x9551, 0xB0F8, 0x508D, 0xB0F9, 0x8C24, 0xB0FA, 0x82DE, 0xB0FB, 0x80DE, + 0xB0FC, 0x5305, 0xB0FD, 0x8912, 0xB0FE, 0x5265, 0xB140, 0x76C4, 0xB141, 0x76C7, 0xB142, 0x76C9, 0xB143, 0x76CB, 0xB144, 0x76CC, + 0xB145, 0x76D3, 0xB146, 0x76D5, 0xB147, 0x76D9, 0xB148, 0x76DA, 0xB149, 0x76DC, 0xB14A, 0x76DD, 0xB14B, 0x76DE, 0xB14C, 0x76E0, + 0xB14D, 0x76E1, 0xB14E, 0x76E2, 0xB14F, 0x76E3, 0xB150, 0x76E4, 0xB151, 0x76E6, 0xB152, 0x76E7, 0xB153, 0x76E8, 0xB154, 0x76E9, + 0xB155, 0x76EA, 0xB156, 0x76EB, 0xB157, 0x76EC, 0xB158, 0x76ED, 0xB159, 0x76F0, 0xB15A, 0x76F3, 0xB15B, 0x76F5, 0xB15C, 0x76F6, + 0xB15D, 0x76F7, 0xB15E, 0x76FA, 0xB15F, 0x76FB, 0xB160, 0x76FD, 0xB161, 0x76FF, 0xB162, 0x7700, 0xB163, 0x7702, 0xB164, 0x7703, + 0xB165, 0x7705, 0xB166, 0x7706, 0xB167, 0x770A, 0xB168, 0x770C, 0xB169, 0x770E, 0xB16A, 0x770F, 0xB16B, 0x7710, 0xB16C, 0x7711, + 0xB16D, 0x7712, 0xB16E, 0x7713, 0xB16F, 0x7714, 0xB170, 0x7715, 0xB171, 0x7716, 0xB172, 0x7717, 0xB173, 0x7718, 0xB174, 0x771B, + 0xB175, 0x771C, 0xB176, 0x771D, 0xB177, 0x771E, 0xB178, 0x7721, 0xB179, 0x7723, 0xB17A, 0x7724, 0xB17B, 0x7725, 0xB17C, 0x7727, + 0xB17D, 0x772A, 0xB17E, 0x772B, 0xB180, 0x772C, 0xB181, 0x772E, 0xB182, 0x7730, 0xB183, 0x7731, 0xB184, 0x7732, 0xB185, 0x7733, + 0xB186, 0x7734, 0xB187, 0x7739, 0xB188, 0x773B, 0xB189, 0x773D, 0xB18A, 0x773E, 0xB18B, 0x773F, 0xB18C, 0x7742, 0xB18D, 0x7744, + 0xB18E, 0x7745, 0xB18F, 0x7746, 0xB190, 0x7748, 0xB191, 0x7749, 0xB192, 0x774A, 0xB193, 0x774B, 0xB194, 0x774C, 0xB195, 0x774D, + 0xB196, 0x774E, 0xB197, 0x774F, 0xB198, 0x7752, 0xB199, 0x7753, 0xB19A, 0x7754, 0xB19B, 0x7755, 0xB19C, 0x7756, 0xB19D, 0x7757, + 0xB19E, 0x7758, 0xB19F, 0x7759, 0xB1A0, 0x775C, 0xB1A1, 0x8584, 0xB1A2, 0x96F9, 0xB1A3, 0x4FDD, 0xB1A4, 0x5821, 0xB1A5, 0x9971, + 0xB1A6, 0x5B9D, 0xB1A7, 0x62B1, 0xB1A8, 0x62A5, 0xB1A9, 0x66B4, 0xB1AA, 0x8C79, 0xB1AB, 0x9C8D, 0xB1AC, 0x7206, 0xB1AD, 0x676F, + 0xB1AE, 0x7891, 0xB1AF, 0x60B2, 0xB1B0, 0x5351, 0xB1B1, 0x5317, 0xB1B2, 0x8F88, 0xB1B3, 0x80CC, 0xB1B4, 0x8D1D, 0xB1B5, 0x94A1, + 0xB1B6, 0x500D, 0xB1B7, 0x72C8, 0xB1B8, 0x5907, 0xB1B9, 0x60EB, 0xB1BA, 0x7119, 0xB1BB, 0x88AB, 0xB1BC, 0x5954, 0xB1BD, 0x82EF, + 0xB1BE, 0x672C, 0xB1BF, 0x7B28, 0xB1C0, 0x5D29, 0xB1C1, 0x7EF7, 0xB1C2, 0x752D, 0xB1C3, 0x6CF5, 0xB1C4, 0x8E66, 0xB1C5, 0x8FF8, + 0xB1C6, 0x903C, 0xB1C7, 0x9F3B, 0xB1C8, 0x6BD4, 0xB1C9, 0x9119, 0xB1CA, 0x7B14, 0xB1CB, 0x5F7C, 0xB1CC, 0x78A7, 0xB1CD, 0x84D6, + 0xB1CE, 0x853D, 0xB1CF, 0x6BD5, 0xB1D0, 0x6BD9, 0xB1D1, 0x6BD6, 0xB1D2, 0x5E01, 0xB1D3, 0x5E87, 0xB1D4, 0x75F9, 0xB1D5, 0x95ED, + 0xB1D6, 0x655D, 0xB1D7, 0x5F0A, 0xB1D8, 0x5FC5, 0xB1D9, 0x8F9F, 0xB1DA, 0x58C1, 0xB1DB, 0x81C2, 0xB1DC, 0x907F, 0xB1DD, 0x965B, + 0xB1DE, 0x97AD, 0xB1DF, 0x8FB9, 0xB1E0, 0x7F16, 0xB1E1, 0x8D2C, 0xB1E2, 0x6241, 0xB1E3, 0x4FBF, 0xB1E4, 0x53D8, 0xB1E5, 0x535E, + 0xB1E6, 0x8FA8, 0xB1E7, 0x8FA9, 0xB1E8, 0x8FAB, 0xB1E9, 0x904D, 0xB1EA, 0x6807, 0xB1EB, 0x5F6A, 0xB1EC, 0x8198, 0xB1ED, 0x8868, + 0xB1EE, 0x9CD6, 0xB1EF, 0x618B, 0xB1F0, 0x522B, 0xB1F1, 0x762A, 0xB1F2, 0x5F6C, 0xB1F3, 0x658C, 0xB1F4, 0x6FD2, 0xB1F5, 0x6EE8, + 0xB1F6, 0x5BBE, 0xB1F7, 0x6448, 0xB1F8, 0x5175, 0xB1F9, 0x51B0, 0xB1FA, 0x67C4, 0xB1FB, 0x4E19, 0xB1FC, 0x79C9, 0xB1FD, 0x997C, + 0xB1FE, 0x70B3, 0xB240, 0x775D, 0xB241, 0x775E, 0xB242, 0x775F, 0xB243, 0x7760, 0xB244, 0x7764, 0xB245, 0x7767, 0xB246, 0x7769, + 0xB247, 0x776A, 0xB248, 0x776D, 0xB249, 0x776E, 0xB24A, 0x776F, 0xB24B, 0x7770, 0xB24C, 0x7771, 0xB24D, 0x7772, 0xB24E, 0x7773, + 0xB24F, 0x7774, 0xB250, 0x7775, 0xB251, 0x7776, 0xB252, 0x7777, 0xB253, 0x7778, 0xB254, 0x777A, 0xB255, 0x777B, 0xB256, 0x777C, + 0xB257, 0x7781, 0xB258, 0x7782, 0xB259, 0x7783, 0xB25A, 0x7786, 0xB25B, 0x7787, 0xB25C, 0x7788, 0xB25D, 0x7789, 0xB25E, 0x778A, + 0xB25F, 0x778B, 0xB260, 0x778F, 0xB261, 0x7790, 0xB262, 0x7793, 0xB263, 0x7794, 0xB264, 0x7795, 0xB265, 0x7796, 0xB266, 0x7797, + 0xB267, 0x7798, 0xB268, 0x7799, 0xB269, 0x779A, 0xB26A, 0x779B, 0xB26B, 0x779C, 0xB26C, 0x779D, 0xB26D, 0x779E, 0xB26E, 0x77A1, + 0xB26F, 0x77A3, 0xB270, 0x77A4, 0xB271, 0x77A6, 0xB272, 0x77A8, 0xB273, 0x77AB, 0xB274, 0x77AD, 0xB275, 0x77AE, 0xB276, 0x77AF, + 0xB277, 0x77B1, 0xB278, 0x77B2, 0xB279, 0x77B4, 0xB27A, 0x77B6, 0xB27B, 0x77B7, 0xB27C, 0x77B8, 0xB27D, 0x77B9, 0xB27E, 0x77BA, + 0xB280, 0x77BC, 0xB281, 0x77BE, 0xB282, 0x77C0, 0xB283, 0x77C1, 0xB284, 0x77C2, 0xB285, 0x77C3, 0xB286, 0x77C4, 0xB287, 0x77C5, + 0xB288, 0x77C6, 0xB289, 0x77C7, 0xB28A, 0x77C8, 0xB28B, 0x77C9, 0xB28C, 0x77CA, 0xB28D, 0x77CB, 0xB28E, 0x77CC, 0xB28F, 0x77CE, + 0xB290, 0x77CF, 0xB291, 0x77D0, 0xB292, 0x77D1, 0xB293, 0x77D2, 0xB294, 0x77D3, 0xB295, 0x77D4, 0xB296, 0x77D5, 0xB297, 0x77D6, + 0xB298, 0x77D8, 0xB299, 0x77D9, 0xB29A, 0x77DA, 0xB29B, 0x77DD, 0xB29C, 0x77DE, 0xB29D, 0x77DF, 0xB29E, 0x77E0, 0xB29F, 0x77E1, + 0xB2A0, 0x77E4, 0xB2A1, 0x75C5, 0xB2A2, 0x5E76, 0xB2A3, 0x73BB, 0xB2A4, 0x83E0, 0xB2A5, 0x64AD, 0xB2A6, 0x62E8, 0xB2A7, 0x94B5, + 0xB2A8, 0x6CE2, 0xB2A9, 0x535A, 0xB2AA, 0x52C3, 0xB2AB, 0x640F, 0xB2AC, 0x94C2, 0xB2AD, 0x7B94, 0xB2AE, 0x4F2F, 0xB2AF, 0x5E1B, + 0xB2B0, 0x8236, 0xB2B1, 0x8116, 0xB2B2, 0x818A, 0xB2B3, 0x6E24, 0xB2B4, 0x6CCA, 0xB2B5, 0x9A73, 0xB2B6, 0x6355, 0xB2B7, 0x535C, + 0xB2B8, 0x54FA, 0xB2B9, 0x8865, 0xB2BA, 0x57E0, 0xB2BB, 0x4E0D, 0xB2BC, 0x5E03, 0xB2BD, 0x6B65, 0xB2BE, 0x7C3F, 0xB2BF, 0x90E8, + 0xB2C0, 0x6016, 0xB2C1, 0x64E6, 0xB2C2, 0x731C, 0xB2C3, 0x88C1, 0xB2C4, 0x6750, 0xB2C5, 0x624D, 0xB2C6, 0x8D22, 0xB2C7, 0x776C, + 0xB2C8, 0x8E29, 0xB2C9, 0x91C7, 0xB2CA, 0x5F69, 0xB2CB, 0x83DC, 0xB2CC, 0x8521, 0xB2CD, 0x9910, 0xB2CE, 0x53C2, 0xB2CF, 0x8695, + 0xB2D0, 0x6B8B, 0xB2D1, 0x60ED, 0xB2D2, 0x60E8, 0xB2D3, 0x707F, 0xB2D4, 0x82CD, 0xB2D5, 0x8231, 0xB2D6, 0x4ED3, 0xB2D7, 0x6CA7, + 0xB2D8, 0x85CF, 0xB2D9, 0x64CD, 0xB2DA, 0x7CD9, 0xB2DB, 0x69FD, 0xB2DC, 0x66F9, 0xB2DD, 0x8349, 0xB2DE, 0x5395, 0xB2DF, 0x7B56, + 0xB2E0, 0x4FA7, 0xB2E1, 0x518C, 0xB2E2, 0x6D4B, 0xB2E3, 0x5C42, 0xB2E4, 0x8E6D, 0xB2E5, 0x63D2, 0xB2E6, 0x53C9, 0xB2E7, 0x832C, + 0xB2E8, 0x8336, 0xB2E9, 0x67E5, 0xB2EA, 0x78B4, 0xB2EB, 0x643D, 0xB2EC, 0x5BDF, 0xB2ED, 0x5C94, 0xB2EE, 0x5DEE, 0xB2EF, 0x8BE7, + 0xB2F0, 0x62C6, 0xB2F1, 0x67F4, 0xB2F2, 0x8C7A, 0xB2F3, 0x6400, 0xB2F4, 0x63BA, 0xB2F5, 0x8749, 0xB2F6, 0x998B, 0xB2F7, 0x8C17, + 0xB2F8, 0x7F20, 0xB2F9, 0x94F2, 0xB2FA, 0x4EA7, 0xB2FB, 0x9610, 0xB2FC, 0x98A4, 0xB2FD, 0x660C, 0xB2FE, 0x7316, 0xB340, 0x77E6, + 0xB341, 0x77E8, 0xB342, 0x77EA, 0xB343, 0x77EF, 0xB344, 0x77F0, 0xB345, 0x77F1, 0xB346, 0x77F2, 0xB347, 0x77F4, 0xB348, 0x77F5, + 0xB349, 0x77F7, 0xB34A, 0x77F9, 0xB34B, 0x77FA, 0xB34C, 0x77FB, 0xB34D, 0x77FC, 0xB34E, 0x7803, 0xB34F, 0x7804, 0xB350, 0x7805, + 0xB351, 0x7806, 0xB352, 0x7807, 0xB353, 0x7808, 0xB354, 0x780A, 0xB355, 0x780B, 0xB356, 0x780E, 0xB357, 0x780F, 0xB358, 0x7810, + 0xB359, 0x7813, 0xB35A, 0x7815, 0xB35B, 0x7819, 0xB35C, 0x781B, 0xB35D, 0x781E, 0xB35E, 0x7820, 0xB35F, 0x7821, 0xB360, 0x7822, + 0xB361, 0x7824, 0xB362, 0x7828, 0xB363, 0x782A, 0xB364, 0x782B, 0xB365, 0x782E, 0xB366, 0x782F, 0xB367, 0x7831, 0xB368, 0x7832, + 0xB369, 0x7833, 0xB36A, 0x7835, 0xB36B, 0x7836, 0xB36C, 0x783D, 0xB36D, 0x783F, 0xB36E, 0x7841, 0xB36F, 0x7842, 0xB370, 0x7843, + 0xB371, 0x7844, 0xB372, 0x7846, 0xB373, 0x7848, 0xB374, 0x7849, 0xB375, 0x784A, 0xB376, 0x784B, 0xB377, 0x784D, 0xB378, 0x784F, + 0xB379, 0x7851, 0xB37A, 0x7853, 0xB37B, 0x7854, 0xB37C, 0x7858, 0xB37D, 0x7859, 0xB37E, 0x785A, 0xB380, 0x785B, 0xB381, 0x785C, + 0xB382, 0x785E, 0xB383, 0x785F, 0xB384, 0x7860, 0xB385, 0x7861, 0xB386, 0x7862, 0xB387, 0x7863, 0xB388, 0x7864, 0xB389, 0x7865, + 0xB38A, 0x7866, 0xB38B, 0x7867, 0xB38C, 0x7868, 0xB38D, 0x7869, 0xB38E, 0x786F, 0xB38F, 0x7870, 0xB390, 0x7871, 0xB391, 0x7872, + 0xB392, 0x7873, 0xB393, 0x7874, 0xB394, 0x7875, 0xB395, 0x7876, 0xB396, 0x7878, 0xB397, 0x7879, 0xB398, 0x787A, 0xB399, 0x787B, + 0xB39A, 0x787D, 0xB39B, 0x787E, 0xB39C, 0x787F, 0xB39D, 0x7880, 0xB39E, 0x7881, 0xB39F, 0x7882, 0xB3A0, 0x7883, 0xB3A1, 0x573A, + 0xB3A2, 0x5C1D, 0xB3A3, 0x5E38, 0xB3A4, 0x957F, 0xB3A5, 0x507F, 0xB3A6, 0x80A0, 0xB3A7, 0x5382, 0xB3A8, 0x655E, 0xB3A9, 0x7545, + 0xB3AA, 0x5531, 0xB3AB, 0x5021, 0xB3AC, 0x8D85, 0xB3AD, 0x6284, 0xB3AE, 0x949E, 0xB3AF, 0x671D, 0xB3B0, 0x5632, 0xB3B1, 0x6F6E, + 0xB3B2, 0x5DE2, 0xB3B3, 0x5435, 0xB3B4, 0x7092, 0xB3B5, 0x8F66, 0xB3B6, 0x626F, 0xB3B7, 0x64A4, 0xB3B8, 0x63A3, 0xB3B9, 0x5F7B, + 0xB3BA, 0x6F88, 0xB3BB, 0x90F4, 0xB3BC, 0x81E3, 0xB3BD, 0x8FB0, 0xB3BE, 0x5C18, 0xB3BF, 0x6668, 0xB3C0, 0x5FF1, 0xB3C1, 0x6C89, + 0xB3C2, 0x9648, 0xB3C3, 0x8D81, 0xB3C4, 0x886C, 0xB3C5, 0x6491, 0xB3C6, 0x79F0, 0xB3C7, 0x57CE, 0xB3C8, 0x6A59, 0xB3C9, 0x6210, + 0xB3CA, 0x5448, 0xB3CB, 0x4E58, 0xB3CC, 0x7A0B, 0xB3CD, 0x60E9, 0xB3CE, 0x6F84, 0xB3CF, 0x8BDA, 0xB3D0, 0x627F, 0xB3D1, 0x901E, + 0xB3D2, 0x9A8B, 0xB3D3, 0x79E4, 0xB3D4, 0x5403, 0xB3D5, 0x75F4, 0xB3D6, 0x6301, 0xB3D7, 0x5319, 0xB3D8, 0x6C60, 0xB3D9, 0x8FDF, + 0xB3DA, 0x5F1B, 0xB3DB, 0x9A70, 0xB3DC, 0x803B, 0xB3DD, 0x9F7F, 0xB3DE, 0x4F88, 0xB3DF, 0x5C3A, 0xB3E0, 0x8D64, 0xB3E1, 0x7FC5, + 0xB3E2, 0x65A5, 0xB3E3, 0x70BD, 0xB3E4, 0x5145, 0xB3E5, 0x51B2, 0xB3E6, 0x866B, 0xB3E7, 0x5D07, 0xB3E8, 0x5BA0, 0xB3E9, 0x62BD, + 0xB3EA, 0x916C, 0xB3EB, 0x7574, 0xB3EC, 0x8E0C, 0xB3ED, 0x7A20, 0xB3EE, 0x6101, 0xB3EF, 0x7B79, 0xB3F0, 0x4EC7, 0xB3F1, 0x7EF8, + 0xB3F2, 0x7785, 0xB3F3, 0x4E11, 0xB3F4, 0x81ED, 0xB3F5, 0x521D, 0xB3F6, 0x51FA, 0xB3F7, 0x6A71, 0xB3F8, 0x53A8, 0xB3F9, 0x8E87, + 0xB3FA, 0x9504, 0xB3FB, 0x96CF, 0xB3FC, 0x6EC1, 0xB3FD, 0x9664, 0xB3FE, 0x695A, 0xB440, 0x7884, 0xB441, 0x7885, 0xB442, 0x7886, + 0xB443, 0x7888, 0xB444, 0x788A, 0xB445, 0x788B, 0xB446, 0x788F, 0xB447, 0x7890, 0xB448, 0x7892, 0xB449, 0x7894, 0xB44A, 0x7895, + 0xB44B, 0x7896, 0xB44C, 0x7899, 0xB44D, 0x789D, 0xB44E, 0x789E, 0xB44F, 0x78A0, 0xB450, 0x78A2, 0xB451, 0x78A4, 0xB452, 0x78A6, + 0xB453, 0x78A8, 0xB454, 0x78A9, 0xB455, 0x78AA, 0xB456, 0x78AB, 0xB457, 0x78AC, 0xB458, 0x78AD, 0xB459, 0x78AE, 0xB45A, 0x78AF, + 0xB45B, 0x78B5, 0xB45C, 0x78B6, 0xB45D, 0x78B7, 0xB45E, 0x78B8, 0xB45F, 0x78BA, 0xB460, 0x78BB, 0xB461, 0x78BC, 0xB462, 0x78BD, + 0xB463, 0x78BF, 0xB464, 0x78C0, 0xB465, 0x78C2, 0xB466, 0x78C3, 0xB467, 0x78C4, 0xB468, 0x78C6, 0xB469, 0x78C7, 0xB46A, 0x78C8, + 0xB46B, 0x78CC, 0xB46C, 0x78CD, 0xB46D, 0x78CE, 0xB46E, 0x78CF, 0xB46F, 0x78D1, 0xB470, 0x78D2, 0xB471, 0x78D3, 0xB472, 0x78D6, + 0xB473, 0x78D7, 0xB474, 0x78D8, 0xB475, 0x78DA, 0xB476, 0x78DB, 0xB477, 0x78DC, 0xB478, 0x78DD, 0xB479, 0x78DE, 0xB47A, 0x78DF, + 0xB47B, 0x78E0, 0xB47C, 0x78E1, 0xB47D, 0x78E2, 0xB47E, 0x78E3, 0xB480, 0x78E4, 0xB481, 0x78E5, 0xB482, 0x78E6, 0xB483, 0x78E7, + 0xB484, 0x78E9, 0xB485, 0x78EA, 0xB486, 0x78EB, 0xB487, 0x78ED, 0xB488, 0x78EE, 0xB489, 0x78EF, 0xB48A, 0x78F0, 0xB48B, 0x78F1, + 0xB48C, 0x78F3, 0xB48D, 0x78F5, 0xB48E, 0x78F6, 0xB48F, 0x78F8, 0xB490, 0x78F9, 0xB491, 0x78FB, 0xB492, 0x78FC, 0xB493, 0x78FD, + 0xB494, 0x78FE, 0xB495, 0x78FF, 0xB496, 0x7900, 0xB497, 0x7902, 0xB498, 0x7903, 0xB499, 0x7904, 0xB49A, 0x7906, 0xB49B, 0x7907, + 0xB49C, 0x7908, 0xB49D, 0x7909, 0xB49E, 0x790A, 0xB49F, 0x790B, 0xB4A0, 0x790C, 0xB4A1, 0x7840, 0xB4A2, 0x50A8, 0xB4A3, 0x77D7, + 0xB4A4, 0x6410, 0xB4A5, 0x89E6, 0xB4A6, 0x5904, 0xB4A7, 0x63E3, 0xB4A8, 0x5DDD, 0xB4A9, 0x7A7F, 0xB4AA, 0x693D, 0xB4AB, 0x4F20, + 0xB4AC, 0x8239, 0xB4AD, 0x5598, 0xB4AE, 0x4E32, 0xB4AF, 0x75AE, 0xB4B0, 0x7A97, 0xB4B1, 0x5E62, 0xB4B2, 0x5E8A, 0xB4B3, 0x95EF, + 0xB4B4, 0x521B, 0xB4B5, 0x5439, 0xB4B6, 0x708A, 0xB4B7, 0x6376, 0xB4B8, 0x9524, 0xB4B9, 0x5782, 0xB4BA, 0x6625, 0xB4BB, 0x693F, + 0xB4BC, 0x9187, 0xB4BD, 0x5507, 0xB4BE, 0x6DF3, 0xB4BF, 0x7EAF, 0xB4C0, 0x8822, 0xB4C1, 0x6233, 0xB4C2, 0x7EF0, 0xB4C3, 0x75B5, + 0xB4C4, 0x8328, 0xB4C5, 0x78C1, 0xB4C6, 0x96CC, 0xB4C7, 0x8F9E, 0xB4C8, 0x6148, 0xB4C9, 0x74F7, 0xB4CA, 0x8BCD, 0xB4CB, 0x6B64, + 0xB4CC, 0x523A, 0xB4CD, 0x8D50, 0xB4CE, 0x6B21, 0xB4CF, 0x806A, 0xB4D0, 0x8471, 0xB4D1, 0x56F1, 0xB4D2, 0x5306, 0xB4D3, 0x4ECE, + 0xB4D4, 0x4E1B, 0xB4D5, 0x51D1, 0xB4D6, 0x7C97, 0xB4D7, 0x918B, 0xB4D8, 0x7C07, 0xB4D9, 0x4FC3, 0xB4DA, 0x8E7F, 0xB4DB, 0x7BE1, + 0xB4DC, 0x7A9C, 0xB4DD, 0x6467, 0xB4DE, 0x5D14, 0xB4DF, 0x50AC, 0xB4E0, 0x8106, 0xB4E1, 0x7601, 0xB4E2, 0x7CB9, 0xB4E3, 0x6DEC, + 0xB4E4, 0x7FE0, 0xB4E5, 0x6751, 0xB4E6, 0x5B58, 0xB4E7, 0x5BF8, 0xB4E8, 0x78CB, 0xB4E9, 0x64AE, 0xB4EA, 0x6413, 0xB4EB, 0x63AA, + 0xB4EC, 0x632B, 0xB4ED, 0x9519, 0xB4EE, 0x642D, 0xB4EF, 0x8FBE, 0xB4F0, 0x7B54, 0xB4F1, 0x7629, 0xB4F2, 0x6253, 0xB4F3, 0x5927, + 0xB4F4, 0x5446, 0xB4F5, 0x6B79, 0xB4F6, 0x50A3, 0xB4F7, 0x6234, 0xB4F8, 0x5E26, 0xB4F9, 0x6B86, 0xB4FA, 0x4EE3, 0xB4FB, 0x8D37, + 0xB4FC, 0x888B, 0xB4FD, 0x5F85, 0xB4FE, 0x902E, 0xB540, 0x790D, 0xB541, 0x790E, 0xB542, 0x790F, 0xB543, 0x7910, 0xB544, 0x7911, + 0xB545, 0x7912, 0xB546, 0x7914, 0xB547, 0x7915, 0xB548, 0x7916, 0xB549, 0x7917, 0xB54A, 0x7918, 0xB54B, 0x7919, 0xB54C, 0x791A, + 0xB54D, 0x791B, 0xB54E, 0x791C, 0xB54F, 0x791D, 0xB550, 0x791F, 0xB551, 0x7920, 0xB552, 0x7921, 0xB553, 0x7922, 0xB554, 0x7923, + 0xB555, 0x7925, 0xB556, 0x7926, 0xB557, 0x7927, 0xB558, 0x7928, 0xB559, 0x7929, 0xB55A, 0x792A, 0xB55B, 0x792B, 0xB55C, 0x792C, + 0xB55D, 0x792D, 0xB55E, 0x792E, 0xB55F, 0x792F, 0xB560, 0x7930, 0xB561, 0x7931, 0xB562, 0x7932, 0xB563, 0x7933, 0xB564, 0x7935, + 0xB565, 0x7936, 0xB566, 0x7937, 0xB567, 0x7938, 0xB568, 0x7939, 0xB569, 0x793D, 0xB56A, 0x793F, 0xB56B, 0x7942, 0xB56C, 0x7943, + 0xB56D, 0x7944, 0xB56E, 0x7945, 0xB56F, 0x7947, 0xB570, 0x794A, 0xB571, 0x794B, 0xB572, 0x794C, 0xB573, 0x794D, 0xB574, 0x794E, + 0xB575, 0x794F, 0xB576, 0x7950, 0xB577, 0x7951, 0xB578, 0x7952, 0xB579, 0x7954, 0xB57A, 0x7955, 0xB57B, 0x7958, 0xB57C, 0x7959, + 0xB57D, 0x7961, 0xB57E, 0x7963, 0xB580, 0x7964, 0xB581, 0x7966, 0xB582, 0x7969, 0xB583, 0x796A, 0xB584, 0x796B, 0xB585, 0x796C, + 0xB586, 0x796E, 0xB587, 0x7970, 0xB588, 0x7971, 0xB589, 0x7972, 0xB58A, 0x7973, 0xB58B, 0x7974, 0xB58C, 0x7975, 0xB58D, 0x7976, + 0xB58E, 0x7979, 0xB58F, 0x797B, 0xB590, 0x797C, 0xB591, 0x797D, 0xB592, 0x797E, 0xB593, 0x797F, 0xB594, 0x7982, 0xB595, 0x7983, + 0xB596, 0x7986, 0xB597, 0x7987, 0xB598, 0x7988, 0xB599, 0x7989, 0xB59A, 0x798B, 0xB59B, 0x798C, 0xB59C, 0x798D, 0xB59D, 0x798E, + 0xB59E, 0x7990, 0xB59F, 0x7991, 0xB5A0, 0x7992, 0xB5A1, 0x6020, 0xB5A2, 0x803D, 0xB5A3, 0x62C5, 0xB5A4, 0x4E39, 0xB5A5, 0x5355, + 0xB5A6, 0x90F8, 0xB5A7, 0x63B8, 0xB5A8, 0x80C6, 0xB5A9, 0x65E6, 0xB5AA, 0x6C2E, 0xB5AB, 0x4F46, 0xB5AC, 0x60EE, 0xB5AD, 0x6DE1, + 0xB5AE, 0x8BDE, 0xB5AF, 0x5F39, 0xB5B0, 0x86CB, 0xB5B1, 0x5F53, 0xB5B2, 0x6321, 0xB5B3, 0x515A, 0xB5B4, 0x8361, 0xB5B5, 0x6863, + 0xB5B6, 0x5200, 0xB5B7, 0x6363, 0xB5B8, 0x8E48, 0xB5B9, 0x5012, 0xB5BA, 0x5C9B, 0xB5BB, 0x7977, 0xB5BC, 0x5BFC, 0xB5BD, 0x5230, + 0xB5BE, 0x7A3B, 0xB5BF, 0x60BC, 0xB5C0, 0x9053, 0xB5C1, 0x76D7, 0xB5C2, 0x5FB7, 0xB5C3, 0x5F97, 0xB5C4, 0x7684, 0xB5C5, 0x8E6C, + 0xB5C6, 0x706F, 0xB5C7, 0x767B, 0xB5C8, 0x7B49, 0xB5C9, 0x77AA, 0xB5CA, 0x51F3, 0xB5CB, 0x9093, 0xB5CC, 0x5824, 0xB5CD, 0x4F4E, + 0xB5CE, 0x6EF4, 0xB5CF, 0x8FEA, 0xB5D0, 0x654C, 0xB5D1, 0x7B1B, 0xB5D2, 0x72C4, 0xB5D3, 0x6DA4, 0xB5D4, 0x7FDF, 0xB5D5, 0x5AE1, + 0xB5D6, 0x62B5, 0xB5D7, 0x5E95, 0xB5D8, 0x5730, 0xB5D9, 0x8482, 0xB5DA, 0x7B2C, 0xB5DB, 0x5E1D, 0xB5DC, 0x5F1F, 0xB5DD, 0x9012, + 0xB5DE, 0x7F14, 0xB5DF, 0x98A0, 0xB5E0, 0x6382, 0xB5E1, 0x6EC7, 0xB5E2, 0x7898, 0xB5E3, 0x70B9, 0xB5E4, 0x5178, 0xB5E5, 0x975B, + 0xB5E6, 0x57AB, 0xB5E7, 0x7535, 0xB5E8, 0x4F43, 0xB5E9, 0x7538, 0xB5EA, 0x5E97, 0xB5EB, 0x60E6, 0xB5EC, 0x5960, 0xB5ED, 0x6DC0, + 0xB5EE, 0x6BBF, 0xB5EF, 0x7889, 0xB5F0, 0x53FC, 0xB5F1, 0x96D5, 0xB5F2, 0x51CB, 0xB5F3, 0x5201, 0xB5F4, 0x6389, 0xB5F5, 0x540A, + 0xB5F6, 0x9493, 0xB5F7, 0x8C03, 0xB5F8, 0x8DCC, 0xB5F9, 0x7239, 0xB5FA, 0x789F, 0xB5FB, 0x8776, 0xB5FC, 0x8FED, 0xB5FD, 0x8C0D, + 0xB5FE, 0x53E0, 0xB640, 0x7993, 0xB641, 0x7994, 0xB642, 0x7995, 0xB643, 0x7996, 0xB644, 0x7997, 0xB645, 0x7998, 0xB646, 0x7999, + 0xB647, 0x799B, 0xB648, 0x799C, 0xB649, 0x799D, 0xB64A, 0x799E, 0xB64B, 0x799F, 0xB64C, 0x79A0, 0xB64D, 0x79A1, 0xB64E, 0x79A2, + 0xB64F, 0x79A3, 0xB650, 0x79A4, 0xB651, 0x79A5, 0xB652, 0x79A6, 0xB653, 0x79A8, 0xB654, 0x79A9, 0xB655, 0x79AA, 0xB656, 0x79AB, + 0xB657, 0x79AC, 0xB658, 0x79AD, 0xB659, 0x79AE, 0xB65A, 0x79AF, 0xB65B, 0x79B0, 0xB65C, 0x79B1, 0xB65D, 0x79B2, 0xB65E, 0x79B4, + 0xB65F, 0x79B5, 0xB660, 0x79B6, 0xB661, 0x79B7, 0xB662, 0x79B8, 0xB663, 0x79BC, 0xB664, 0x79BF, 0xB665, 0x79C2, 0xB666, 0x79C4, + 0xB667, 0x79C5, 0xB668, 0x79C7, 0xB669, 0x79C8, 0xB66A, 0x79CA, 0xB66B, 0x79CC, 0xB66C, 0x79CE, 0xB66D, 0x79CF, 0xB66E, 0x79D0, + 0xB66F, 0x79D3, 0xB670, 0x79D4, 0xB671, 0x79D6, 0xB672, 0x79D7, 0xB673, 0x79D9, 0xB674, 0x79DA, 0xB675, 0x79DB, 0xB676, 0x79DC, + 0xB677, 0x79DD, 0xB678, 0x79DE, 0xB679, 0x79E0, 0xB67A, 0x79E1, 0xB67B, 0x79E2, 0xB67C, 0x79E5, 0xB67D, 0x79E8, 0xB67E, 0x79EA, + 0xB680, 0x79EC, 0xB681, 0x79EE, 0xB682, 0x79F1, 0xB683, 0x79F2, 0xB684, 0x79F3, 0xB685, 0x79F4, 0xB686, 0x79F5, 0xB687, 0x79F6, + 0xB688, 0x79F7, 0xB689, 0x79F9, 0xB68A, 0x79FA, 0xB68B, 0x79FC, 0xB68C, 0x79FE, 0xB68D, 0x79FF, 0xB68E, 0x7A01, 0xB68F, 0x7A04, + 0xB690, 0x7A05, 0xB691, 0x7A07, 0xB692, 0x7A08, 0xB693, 0x7A09, 0xB694, 0x7A0A, 0xB695, 0x7A0C, 0xB696, 0x7A0F, 0xB697, 0x7A10, + 0xB698, 0x7A11, 0xB699, 0x7A12, 0xB69A, 0x7A13, 0xB69B, 0x7A15, 0xB69C, 0x7A16, 0xB69D, 0x7A18, 0xB69E, 0x7A19, 0xB69F, 0x7A1B, + 0xB6A0, 0x7A1C, 0xB6A1, 0x4E01, 0xB6A2, 0x76EF, 0xB6A3, 0x53EE, 0xB6A4, 0x9489, 0xB6A5, 0x9876, 0xB6A6, 0x9F0E, 0xB6A7, 0x952D, + 0xB6A8, 0x5B9A, 0xB6A9, 0x8BA2, 0xB6AA, 0x4E22, 0xB6AB, 0x4E1C, 0xB6AC, 0x51AC, 0xB6AD, 0x8463, 0xB6AE, 0x61C2, 0xB6AF, 0x52A8, + 0xB6B0, 0x680B, 0xB6B1, 0x4F97, 0xB6B2, 0x606B, 0xB6B3, 0x51BB, 0xB6B4, 0x6D1E, 0xB6B5, 0x515C, 0xB6B6, 0x6296, 0xB6B7, 0x6597, + 0xB6B8, 0x9661, 0xB6B9, 0x8C46, 0xB6BA, 0x9017, 0xB6BB, 0x75D8, 0xB6BC, 0x90FD, 0xB6BD, 0x7763, 0xB6BE, 0x6BD2, 0xB6BF, 0x728A, + 0xB6C0, 0x72EC, 0xB6C1, 0x8BFB, 0xB6C2, 0x5835, 0xB6C3, 0x7779, 0xB6C4, 0x8D4C, 0xB6C5, 0x675C, 0xB6C6, 0x9540, 0xB6C7, 0x809A, + 0xB6C8, 0x5EA6, 0xB6C9, 0x6E21, 0xB6CA, 0x5992, 0xB6CB, 0x7AEF, 0xB6CC, 0x77ED, 0xB6CD, 0x953B, 0xB6CE, 0x6BB5, 0xB6CF, 0x65AD, + 0xB6D0, 0x7F0E, 0xB6D1, 0x5806, 0xB6D2, 0x5151, 0xB6D3, 0x961F, 0xB6D4, 0x5BF9, 0xB6D5, 0x58A9, 0xB6D6, 0x5428, 0xB6D7, 0x8E72, + 0xB6D8, 0x6566, 0xB6D9, 0x987F, 0xB6DA, 0x56E4, 0xB6DB, 0x949D, 0xB6DC, 0x76FE, 0xB6DD, 0x9041, 0xB6DE, 0x6387, 0xB6DF, 0x54C6, + 0xB6E0, 0x591A, 0xB6E1, 0x593A, 0xB6E2, 0x579B, 0xB6E3, 0x8EB2, 0xB6E4, 0x6735, 0xB6E5, 0x8DFA, 0xB6E6, 0x8235, 0xB6E7, 0x5241, + 0xB6E8, 0x60F0, 0xB6E9, 0x5815, 0xB6EA, 0x86FE, 0xB6EB, 0x5CE8, 0xB6EC, 0x9E45, 0xB6ED, 0x4FC4, 0xB6EE, 0x989D, 0xB6EF, 0x8BB9, + 0xB6F0, 0x5A25, 0xB6F1, 0x6076, 0xB6F2, 0x5384, 0xB6F3, 0x627C, 0xB6F4, 0x904F, 0xB6F5, 0x9102, 0xB6F6, 0x997F, 0xB6F7, 0x6069, + 0xB6F8, 0x800C, 0xB6F9, 0x513F, 0xB6FA, 0x8033, 0xB6FB, 0x5C14, 0xB6FC, 0x9975, 0xB6FD, 0x6D31, 0xB6FE, 0x4E8C, 0xB740, 0x7A1D, + 0xB741, 0x7A1F, 0xB742, 0x7A21, 0xB743, 0x7A22, 0xB744, 0x7A24, 0xB745, 0x7A25, 0xB746, 0x7A26, 0xB747, 0x7A27, 0xB748, 0x7A28, + 0xB749, 0x7A29, 0xB74A, 0x7A2A, 0xB74B, 0x7A2B, 0xB74C, 0x7A2C, 0xB74D, 0x7A2D, 0xB74E, 0x7A2E, 0xB74F, 0x7A2F, 0xB750, 0x7A30, + 0xB751, 0x7A31, 0xB752, 0x7A32, 0xB753, 0x7A34, 0xB754, 0x7A35, 0xB755, 0x7A36, 0xB756, 0x7A38, 0xB757, 0x7A3A, 0xB758, 0x7A3E, + 0xB759, 0x7A40, 0xB75A, 0x7A41, 0xB75B, 0x7A42, 0xB75C, 0x7A43, 0xB75D, 0x7A44, 0xB75E, 0x7A45, 0xB75F, 0x7A47, 0xB760, 0x7A48, + 0xB761, 0x7A49, 0xB762, 0x7A4A, 0xB763, 0x7A4B, 0xB764, 0x7A4C, 0xB765, 0x7A4D, 0xB766, 0x7A4E, 0xB767, 0x7A4F, 0xB768, 0x7A50, + 0xB769, 0x7A52, 0xB76A, 0x7A53, 0xB76B, 0x7A54, 0xB76C, 0x7A55, 0xB76D, 0x7A56, 0xB76E, 0x7A58, 0xB76F, 0x7A59, 0xB770, 0x7A5A, + 0xB771, 0x7A5B, 0xB772, 0x7A5C, 0xB773, 0x7A5D, 0xB774, 0x7A5E, 0xB775, 0x7A5F, 0xB776, 0x7A60, 0xB777, 0x7A61, 0xB778, 0x7A62, + 0xB779, 0x7A63, 0xB77A, 0x7A64, 0xB77B, 0x7A65, 0xB77C, 0x7A66, 0xB77D, 0x7A67, 0xB77E, 0x7A68, 0xB780, 0x7A69, 0xB781, 0x7A6A, + 0xB782, 0x7A6B, 0xB783, 0x7A6C, 0xB784, 0x7A6D, 0xB785, 0x7A6E, 0xB786, 0x7A6F, 0xB787, 0x7A71, 0xB788, 0x7A72, 0xB789, 0x7A73, + 0xB78A, 0x7A75, 0xB78B, 0x7A7B, 0xB78C, 0x7A7C, 0xB78D, 0x7A7D, 0xB78E, 0x7A7E, 0xB78F, 0x7A82, 0xB790, 0x7A85, 0xB791, 0x7A87, + 0xB792, 0x7A89, 0xB793, 0x7A8A, 0xB794, 0x7A8B, 0xB795, 0x7A8C, 0xB796, 0x7A8E, 0xB797, 0x7A8F, 0xB798, 0x7A90, 0xB799, 0x7A93, + 0xB79A, 0x7A94, 0xB79B, 0x7A99, 0xB79C, 0x7A9A, 0xB79D, 0x7A9B, 0xB79E, 0x7A9E, 0xB79F, 0x7AA1, 0xB7A0, 0x7AA2, 0xB7A1, 0x8D30, + 0xB7A2, 0x53D1, 0xB7A3, 0x7F5A, 0xB7A4, 0x7B4F, 0xB7A5, 0x4F10, 0xB7A6, 0x4E4F, 0xB7A7, 0x9600, 0xB7A8, 0x6CD5, 0xB7A9, 0x73D0, + 0xB7AA, 0x85E9, 0xB7AB, 0x5E06, 0xB7AC, 0x756A, 0xB7AD, 0x7FFB, 0xB7AE, 0x6A0A, 0xB7AF, 0x77FE, 0xB7B0, 0x9492, 0xB7B1, 0x7E41, + 0xB7B2, 0x51E1, 0xB7B3, 0x70E6, 0xB7B4, 0x53CD, 0xB7B5, 0x8FD4, 0xB7B6, 0x8303, 0xB7B7, 0x8D29, 0xB7B8, 0x72AF, 0xB7B9, 0x996D, + 0xB7BA, 0x6CDB, 0xB7BB, 0x574A, 0xB7BC, 0x82B3, 0xB7BD, 0x65B9, 0xB7BE, 0x80AA, 0xB7BF, 0x623F, 0xB7C0, 0x9632, 0xB7C1, 0x59A8, + 0xB7C2, 0x4EFF, 0xB7C3, 0x8BBF, 0xB7C4, 0x7EBA, 0xB7C5, 0x653E, 0xB7C6, 0x83F2, 0xB7C7, 0x975E, 0xB7C8, 0x5561, 0xB7C9, 0x98DE, + 0xB7CA, 0x80A5, 0xB7CB, 0x532A, 0xB7CC, 0x8BFD, 0xB7CD, 0x5420, 0xB7CE, 0x80BA, 0xB7CF, 0x5E9F, 0xB7D0, 0x6CB8, 0xB7D1, 0x8D39, + 0xB7D2, 0x82AC, 0xB7D3, 0x915A, 0xB7D4, 0x5429, 0xB7D5, 0x6C1B, 0xB7D6, 0x5206, 0xB7D7, 0x7EB7, 0xB7D8, 0x575F, 0xB7D9, 0x711A, + 0xB7DA, 0x6C7E, 0xB7DB, 0x7C89, 0xB7DC, 0x594B, 0xB7DD, 0x4EFD, 0xB7DE, 0x5FFF, 0xB7DF, 0x6124, 0xB7E0, 0x7CAA, 0xB7E1, 0x4E30, + 0xB7E2, 0x5C01, 0xB7E3, 0x67AB, 0xB7E4, 0x8702, 0xB7E5, 0x5CF0, 0xB7E6, 0x950B, 0xB7E7, 0x98CE, 0xB7E8, 0x75AF, 0xB7E9, 0x70FD, + 0xB7EA, 0x9022, 0xB7EB, 0x51AF, 0xB7EC, 0x7F1D, 0xB7ED, 0x8BBD, 0xB7EE, 0x5949, 0xB7EF, 0x51E4, 0xB7F0, 0x4F5B, 0xB7F1, 0x5426, + 0xB7F2, 0x592B, 0xB7F3, 0x6577, 0xB7F4, 0x80A4, 0xB7F5, 0x5B75, 0xB7F6, 0x6276, 0xB7F7, 0x62C2, 0xB7F8, 0x8F90, 0xB7F9, 0x5E45, + 0xB7FA, 0x6C1F, 0xB7FB, 0x7B26, 0xB7FC, 0x4F0F, 0xB7FD, 0x4FD8, 0xB7FE, 0x670D, 0xB840, 0x7AA3, 0xB841, 0x7AA4, 0xB842, 0x7AA7, + 0xB843, 0x7AA9, 0xB844, 0x7AAA, 0xB845, 0x7AAB, 0xB846, 0x7AAE, 0xB847, 0x7AAF, 0xB848, 0x7AB0, 0xB849, 0x7AB1, 0xB84A, 0x7AB2, + 0xB84B, 0x7AB4, 0xB84C, 0x7AB5, 0xB84D, 0x7AB6, 0xB84E, 0x7AB7, 0xB84F, 0x7AB8, 0xB850, 0x7AB9, 0xB851, 0x7ABA, 0xB852, 0x7ABB, + 0xB853, 0x7ABC, 0xB854, 0x7ABD, 0xB855, 0x7ABE, 0xB856, 0x7AC0, 0xB857, 0x7AC1, 0xB858, 0x7AC2, 0xB859, 0x7AC3, 0xB85A, 0x7AC4, + 0xB85B, 0x7AC5, 0xB85C, 0x7AC6, 0xB85D, 0x7AC7, 0xB85E, 0x7AC8, 0xB85F, 0x7AC9, 0xB860, 0x7ACA, 0xB861, 0x7ACC, 0xB862, 0x7ACD, + 0xB863, 0x7ACE, 0xB864, 0x7ACF, 0xB865, 0x7AD0, 0xB866, 0x7AD1, 0xB867, 0x7AD2, 0xB868, 0x7AD3, 0xB869, 0x7AD4, 0xB86A, 0x7AD5, + 0xB86B, 0x7AD7, 0xB86C, 0x7AD8, 0xB86D, 0x7ADA, 0xB86E, 0x7ADB, 0xB86F, 0x7ADC, 0xB870, 0x7ADD, 0xB871, 0x7AE1, 0xB872, 0x7AE2, + 0xB873, 0x7AE4, 0xB874, 0x7AE7, 0xB875, 0x7AE8, 0xB876, 0x7AE9, 0xB877, 0x7AEA, 0xB878, 0x7AEB, 0xB879, 0x7AEC, 0xB87A, 0x7AEE, + 0xB87B, 0x7AF0, 0xB87C, 0x7AF1, 0xB87D, 0x7AF2, 0xB87E, 0x7AF3, 0xB880, 0x7AF4, 0xB881, 0x7AF5, 0xB882, 0x7AF6, 0xB883, 0x7AF7, + 0xB884, 0x7AF8, 0xB885, 0x7AFB, 0xB886, 0x7AFC, 0xB887, 0x7AFE, 0xB888, 0x7B00, 0xB889, 0x7B01, 0xB88A, 0x7B02, 0xB88B, 0x7B05, + 0xB88C, 0x7B07, 0xB88D, 0x7B09, 0xB88E, 0x7B0C, 0xB88F, 0x7B0D, 0xB890, 0x7B0E, 0xB891, 0x7B10, 0xB892, 0x7B12, 0xB893, 0x7B13, + 0xB894, 0x7B16, 0xB895, 0x7B17, 0xB896, 0x7B18, 0xB897, 0x7B1A, 0xB898, 0x7B1C, 0xB899, 0x7B1D, 0xB89A, 0x7B1F, 0xB89B, 0x7B21, + 0xB89C, 0x7B22, 0xB89D, 0x7B23, 0xB89E, 0x7B27, 0xB89F, 0x7B29, 0xB8A0, 0x7B2D, 0xB8A1, 0x6D6E, 0xB8A2, 0x6DAA, 0xB8A3, 0x798F, + 0xB8A4, 0x88B1, 0xB8A5, 0x5F17, 0xB8A6, 0x752B, 0xB8A7, 0x629A, 0xB8A8, 0x8F85, 0xB8A9, 0x4FEF, 0xB8AA, 0x91DC, 0xB8AB, 0x65A7, + 0xB8AC, 0x812F, 0xB8AD, 0x8151, 0xB8AE, 0x5E9C, 0xB8AF, 0x8150, 0xB8B0, 0x8D74, 0xB8B1, 0x526F, 0xB8B2, 0x8986, 0xB8B3, 0x8D4B, + 0xB8B4, 0x590D, 0xB8B5, 0x5085, 0xB8B6, 0x4ED8, 0xB8B7, 0x961C, 0xB8B8, 0x7236, 0xB8B9, 0x8179, 0xB8BA, 0x8D1F, 0xB8BB, 0x5BCC, + 0xB8BC, 0x8BA3, 0xB8BD, 0x9644, 0xB8BE, 0x5987, 0xB8BF, 0x7F1A, 0xB8C0, 0x5490, 0xB8C1, 0x5676, 0xB8C2, 0x560E, 0xB8C3, 0x8BE5, + 0xB8C4, 0x6539, 0xB8C5, 0x6982, 0xB8C6, 0x9499, 0xB8C7, 0x76D6, 0xB8C8, 0x6E89, 0xB8C9, 0x5E72, 0xB8CA, 0x7518, 0xB8CB, 0x6746, + 0xB8CC, 0x67D1, 0xB8CD, 0x7AFF, 0xB8CE, 0x809D, 0xB8CF, 0x8D76, 0xB8D0, 0x611F, 0xB8D1, 0x79C6, 0xB8D2, 0x6562, 0xB8D3, 0x8D63, + 0xB8D4, 0x5188, 0xB8D5, 0x521A, 0xB8D6, 0x94A2, 0xB8D7, 0x7F38, 0xB8D8, 0x809B, 0xB8D9, 0x7EB2, 0xB8DA, 0x5C97, 0xB8DB, 0x6E2F, + 0xB8DC, 0x6760, 0xB8DD, 0x7BD9, 0xB8DE, 0x768B, 0xB8DF, 0x9AD8, 0xB8E0, 0x818F, 0xB8E1, 0x7F94, 0xB8E2, 0x7CD5, 0xB8E3, 0x641E, + 0xB8E4, 0x9550, 0xB8E5, 0x7A3F, 0xB8E6, 0x544A, 0xB8E7, 0x54E5, 0xB8E8, 0x6B4C, 0xB8E9, 0x6401, 0xB8EA, 0x6208, 0xB8EB, 0x9E3D, + 0xB8EC, 0x80F3, 0xB8ED, 0x7599, 0xB8EE, 0x5272, 0xB8EF, 0x9769, 0xB8F0, 0x845B, 0xB8F1, 0x683C, 0xB8F2, 0x86E4, 0xB8F3, 0x9601, + 0xB8F4, 0x9694, 0xB8F5, 0x94EC, 0xB8F6, 0x4E2A, 0xB8F7, 0x5404, 0xB8F8, 0x7ED9, 0xB8F9, 0x6839, 0xB8FA, 0x8DDF, 0xB8FB, 0x8015, + 0xB8FC, 0x66F4, 0xB8FD, 0x5E9A, 0xB8FE, 0x7FB9, 0xB940, 0x7B2F, 0xB941, 0x7B30, 0xB942, 0x7B32, 0xB943, 0x7B34, 0xB944, 0x7B35, + 0xB945, 0x7B36, 0xB946, 0x7B37, 0xB947, 0x7B39, 0xB948, 0x7B3B, 0xB949, 0x7B3D, 0xB94A, 0x7B3F, 0xB94B, 0x7B40, 0xB94C, 0x7B41, + 0xB94D, 0x7B42, 0xB94E, 0x7B43, 0xB94F, 0x7B44, 0xB950, 0x7B46, 0xB951, 0x7B48, 0xB952, 0x7B4A, 0xB953, 0x7B4D, 0xB954, 0x7B4E, + 0xB955, 0x7B53, 0xB956, 0x7B55, 0xB957, 0x7B57, 0xB958, 0x7B59, 0xB959, 0x7B5C, 0xB95A, 0x7B5E, 0xB95B, 0x7B5F, 0xB95C, 0x7B61, + 0xB95D, 0x7B63, 0xB95E, 0x7B64, 0xB95F, 0x7B65, 0xB960, 0x7B66, 0xB961, 0x7B67, 0xB962, 0x7B68, 0xB963, 0x7B69, 0xB964, 0x7B6A, + 0xB965, 0x7B6B, 0xB966, 0x7B6C, 0xB967, 0x7B6D, 0xB968, 0x7B6F, 0xB969, 0x7B70, 0xB96A, 0x7B73, 0xB96B, 0x7B74, 0xB96C, 0x7B76, + 0xB96D, 0x7B78, 0xB96E, 0x7B7A, 0xB96F, 0x7B7C, 0xB970, 0x7B7D, 0xB971, 0x7B7F, 0xB972, 0x7B81, 0xB973, 0x7B82, 0xB974, 0x7B83, + 0xB975, 0x7B84, 0xB976, 0x7B86, 0xB977, 0x7B87, 0xB978, 0x7B88, 0xB979, 0x7B89, 0xB97A, 0x7B8A, 0xB97B, 0x7B8B, 0xB97C, 0x7B8C, + 0xB97D, 0x7B8E, 0xB97E, 0x7B8F, 0xB980, 0x7B91, 0xB981, 0x7B92, 0xB982, 0x7B93, 0xB983, 0x7B96, 0xB984, 0x7B98, 0xB985, 0x7B99, + 0xB986, 0x7B9A, 0xB987, 0x7B9B, 0xB988, 0x7B9E, 0xB989, 0x7B9F, 0xB98A, 0x7BA0, 0xB98B, 0x7BA3, 0xB98C, 0x7BA4, 0xB98D, 0x7BA5, + 0xB98E, 0x7BAE, 0xB98F, 0x7BAF, 0xB990, 0x7BB0, 0xB991, 0x7BB2, 0xB992, 0x7BB3, 0xB993, 0x7BB5, 0xB994, 0x7BB6, 0xB995, 0x7BB7, + 0xB996, 0x7BB9, 0xB997, 0x7BBA, 0xB998, 0x7BBB, 0xB999, 0x7BBC, 0xB99A, 0x7BBD, 0xB99B, 0x7BBE, 0xB99C, 0x7BBF, 0xB99D, 0x7BC0, + 0xB99E, 0x7BC2, 0xB99F, 0x7BC3, 0xB9A0, 0x7BC4, 0xB9A1, 0x57C2, 0xB9A2, 0x803F, 0xB9A3, 0x6897, 0xB9A4, 0x5DE5, 0xB9A5, 0x653B, + 0xB9A6, 0x529F, 0xB9A7, 0x606D, 0xB9A8, 0x9F9A, 0xB9A9, 0x4F9B, 0xB9AA, 0x8EAC, 0xB9AB, 0x516C, 0xB9AC, 0x5BAB, 0xB9AD, 0x5F13, + 0xB9AE, 0x5DE9, 0xB9AF, 0x6C5E, 0xB9B0, 0x62F1, 0xB9B1, 0x8D21, 0xB9B2, 0x5171, 0xB9B3, 0x94A9, 0xB9B4, 0x52FE, 0xB9B5, 0x6C9F, + 0xB9B6, 0x82DF, 0xB9B7, 0x72D7, 0xB9B8, 0x57A2, 0xB9B9, 0x6784, 0xB9BA, 0x8D2D, 0xB9BB, 0x591F, 0xB9BC, 0x8F9C, 0xB9BD, 0x83C7, + 0xB9BE, 0x5495, 0xB9BF, 0x7B8D, 0xB9C0, 0x4F30, 0xB9C1, 0x6CBD, 0xB9C2, 0x5B64, 0xB9C3, 0x59D1, 0xB9C4, 0x9F13, 0xB9C5, 0x53E4, + 0xB9C6, 0x86CA, 0xB9C7, 0x9AA8, 0xB9C8, 0x8C37, 0xB9C9, 0x80A1, 0xB9CA, 0x6545, 0xB9CB, 0x987E, 0xB9CC, 0x56FA, 0xB9CD, 0x96C7, + 0xB9CE, 0x522E, 0xB9CF, 0x74DC, 0xB9D0, 0x5250, 0xB9D1, 0x5BE1, 0xB9D2, 0x6302, 0xB9D3, 0x8902, 0xB9D4, 0x4E56, 0xB9D5, 0x62D0, + 0xB9D6, 0x602A, 0xB9D7, 0x68FA, 0xB9D8, 0x5173, 0xB9D9, 0x5B98, 0xB9DA, 0x51A0, 0xB9DB, 0x89C2, 0xB9DC, 0x7BA1, 0xB9DD, 0x9986, + 0xB9DE, 0x7F50, 0xB9DF, 0x60EF, 0xB9E0, 0x704C, 0xB9E1, 0x8D2F, 0xB9E2, 0x5149, 0xB9E3, 0x5E7F, 0xB9E4, 0x901B, 0xB9E5, 0x7470, + 0xB9E6, 0x89C4, 0xB9E7, 0x572D, 0xB9E8, 0x7845, 0xB9E9, 0x5F52, 0xB9EA, 0x9F9F, 0xB9EB, 0x95FA, 0xB9EC, 0x8F68, 0xB9ED, 0x9B3C, + 0xB9EE, 0x8BE1, 0xB9EF, 0x7678, 0xB9F0, 0x6842, 0xB9F1, 0x67DC, 0xB9F2, 0x8DEA, 0xB9F3, 0x8D35, 0xB9F4, 0x523D, 0xB9F5, 0x8F8A, + 0xB9F6, 0x6EDA, 0xB9F7, 0x68CD, 0xB9F8, 0x9505, 0xB9F9, 0x90ED, 0xB9FA, 0x56FD, 0xB9FB, 0x679C, 0xB9FC, 0x88F9, 0xB9FD, 0x8FC7, + 0xB9FE, 0x54C8, 0xBA40, 0x7BC5, 0xBA41, 0x7BC8, 0xBA42, 0x7BC9, 0xBA43, 0x7BCA, 0xBA44, 0x7BCB, 0xBA45, 0x7BCD, 0xBA46, 0x7BCE, + 0xBA47, 0x7BCF, 0xBA48, 0x7BD0, 0xBA49, 0x7BD2, 0xBA4A, 0x7BD4, 0xBA4B, 0x7BD5, 0xBA4C, 0x7BD6, 0xBA4D, 0x7BD7, 0xBA4E, 0x7BD8, + 0xBA4F, 0x7BDB, 0xBA50, 0x7BDC, 0xBA51, 0x7BDE, 0xBA52, 0x7BDF, 0xBA53, 0x7BE0, 0xBA54, 0x7BE2, 0xBA55, 0x7BE3, 0xBA56, 0x7BE4, + 0xBA57, 0x7BE7, 0xBA58, 0x7BE8, 0xBA59, 0x7BE9, 0xBA5A, 0x7BEB, 0xBA5B, 0x7BEC, 0xBA5C, 0x7BED, 0xBA5D, 0x7BEF, 0xBA5E, 0x7BF0, + 0xBA5F, 0x7BF2, 0xBA60, 0x7BF3, 0xBA61, 0x7BF4, 0xBA62, 0x7BF5, 0xBA63, 0x7BF6, 0xBA64, 0x7BF8, 0xBA65, 0x7BF9, 0xBA66, 0x7BFA, + 0xBA67, 0x7BFB, 0xBA68, 0x7BFD, 0xBA69, 0x7BFF, 0xBA6A, 0x7C00, 0xBA6B, 0x7C01, 0xBA6C, 0x7C02, 0xBA6D, 0x7C03, 0xBA6E, 0x7C04, + 0xBA6F, 0x7C05, 0xBA70, 0x7C06, 0xBA71, 0x7C08, 0xBA72, 0x7C09, 0xBA73, 0x7C0A, 0xBA74, 0x7C0D, 0xBA75, 0x7C0E, 0xBA76, 0x7C10, + 0xBA77, 0x7C11, 0xBA78, 0x7C12, 0xBA79, 0x7C13, 0xBA7A, 0x7C14, 0xBA7B, 0x7C15, 0xBA7C, 0x7C17, 0xBA7D, 0x7C18, 0xBA7E, 0x7C19, + 0xBA80, 0x7C1A, 0xBA81, 0x7C1B, 0xBA82, 0x7C1C, 0xBA83, 0x7C1D, 0xBA84, 0x7C1E, 0xBA85, 0x7C20, 0xBA86, 0x7C21, 0xBA87, 0x7C22, + 0xBA88, 0x7C23, 0xBA89, 0x7C24, 0xBA8A, 0x7C25, 0xBA8B, 0x7C28, 0xBA8C, 0x7C29, 0xBA8D, 0x7C2B, 0xBA8E, 0x7C2C, 0xBA8F, 0x7C2D, + 0xBA90, 0x7C2E, 0xBA91, 0x7C2F, 0xBA92, 0x7C30, 0xBA93, 0x7C31, 0xBA94, 0x7C32, 0xBA95, 0x7C33, 0xBA96, 0x7C34, 0xBA97, 0x7C35, + 0xBA98, 0x7C36, 0xBA99, 0x7C37, 0xBA9A, 0x7C39, 0xBA9B, 0x7C3A, 0xBA9C, 0x7C3B, 0xBA9D, 0x7C3C, 0xBA9E, 0x7C3D, 0xBA9F, 0x7C3E, + 0xBAA0, 0x7C42, 0xBAA1, 0x9AB8, 0xBAA2, 0x5B69, 0xBAA3, 0x6D77, 0xBAA4, 0x6C26, 0xBAA5, 0x4EA5, 0xBAA6, 0x5BB3, 0xBAA7, 0x9A87, + 0xBAA8, 0x9163, 0xBAA9, 0x61A8, 0xBAAA, 0x90AF, 0xBAAB, 0x97E9, 0xBAAC, 0x542B, 0xBAAD, 0x6DB5, 0xBAAE, 0x5BD2, 0xBAAF, 0x51FD, + 0xBAB0, 0x558A, 0xBAB1, 0x7F55, 0xBAB2, 0x7FF0, 0xBAB3, 0x64BC, 0xBAB4, 0x634D, 0xBAB5, 0x65F1, 0xBAB6, 0x61BE, 0xBAB7, 0x608D, + 0xBAB8, 0x710A, 0xBAB9, 0x6C57, 0xBABA, 0x6C49, 0xBABB, 0x592F, 0xBABC, 0x676D, 0xBABD, 0x822A, 0xBABE, 0x58D5, 0xBABF, 0x568E, + 0xBAC0, 0x8C6A, 0xBAC1, 0x6BEB, 0xBAC2, 0x90DD, 0xBAC3, 0x597D, 0xBAC4, 0x8017, 0xBAC5, 0x53F7, 0xBAC6, 0x6D69, 0xBAC7, 0x5475, + 0xBAC8, 0x559D, 0xBAC9, 0x8377, 0xBACA, 0x83CF, 0xBACB, 0x6838, 0xBACC, 0x79BE, 0xBACD, 0x548C, 0xBACE, 0x4F55, 0xBACF, 0x5408, + 0xBAD0, 0x76D2, 0xBAD1, 0x8C89, 0xBAD2, 0x9602, 0xBAD3, 0x6CB3, 0xBAD4, 0x6DB8, 0xBAD5, 0x8D6B, 0xBAD6, 0x8910, 0xBAD7, 0x9E64, + 0xBAD8, 0x8D3A, 0xBAD9, 0x563F, 0xBADA, 0x9ED1, 0xBADB, 0x75D5, 0xBADC, 0x5F88, 0xBADD, 0x72E0, 0xBADE, 0x6068, 0xBADF, 0x54FC, + 0xBAE0, 0x4EA8, 0xBAE1, 0x6A2A, 0xBAE2, 0x8861, 0xBAE3, 0x6052, 0xBAE4, 0x8F70, 0xBAE5, 0x54C4, 0xBAE6, 0x70D8, 0xBAE7, 0x8679, + 0xBAE8, 0x9E3F, 0xBAE9, 0x6D2A, 0xBAEA, 0x5B8F, 0xBAEB, 0x5F18, 0xBAEC, 0x7EA2, 0xBAED, 0x5589, 0xBAEE, 0x4FAF, 0xBAEF, 0x7334, + 0xBAF0, 0x543C, 0xBAF1, 0x539A, 0xBAF2, 0x5019, 0xBAF3, 0x540E, 0xBAF4, 0x547C, 0xBAF5, 0x4E4E, 0xBAF6, 0x5FFD, 0xBAF7, 0x745A, + 0xBAF8, 0x58F6, 0xBAF9, 0x846B, 0xBAFA, 0x80E1, 0xBAFB, 0x8774, 0xBAFC, 0x72D0, 0xBAFD, 0x7CCA, 0xBAFE, 0x6E56, 0xBB40, 0x7C43, + 0xBB41, 0x7C44, 0xBB42, 0x7C45, 0xBB43, 0x7C46, 0xBB44, 0x7C47, 0xBB45, 0x7C48, 0xBB46, 0x7C49, 0xBB47, 0x7C4A, 0xBB48, 0x7C4B, + 0xBB49, 0x7C4C, 0xBB4A, 0x7C4E, 0xBB4B, 0x7C4F, 0xBB4C, 0x7C50, 0xBB4D, 0x7C51, 0xBB4E, 0x7C52, 0xBB4F, 0x7C53, 0xBB50, 0x7C54, + 0xBB51, 0x7C55, 0xBB52, 0x7C56, 0xBB53, 0x7C57, 0xBB54, 0x7C58, 0xBB55, 0x7C59, 0xBB56, 0x7C5A, 0xBB57, 0x7C5B, 0xBB58, 0x7C5C, + 0xBB59, 0x7C5D, 0xBB5A, 0x7C5E, 0xBB5B, 0x7C5F, 0xBB5C, 0x7C60, 0xBB5D, 0x7C61, 0xBB5E, 0x7C62, 0xBB5F, 0x7C63, 0xBB60, 0x7C64, + 0xBB61, 0x7C65, 0xBB62, 0x7C66, 0xBB63, 0x7C67, 0xBB64, 0x7C68, 0xBB65, 0x7C69, 0xBB66, 0x7C6A, 0xBB67, 0x7C6B, 0xBB68, 0x7C6C, + 0xBB69, 0x7C6D, 0xBB6A, 0x7C6E, 0xBB6B, 0x7C6F, 0xBB6C, 0x7C70, 0xBB6D, 0x7C71, 0xBB6E, 0x7C72, 0xBB6F, 0x7C75, 0xBB70, 0x7C76, + 0xBB71, 0x7C77, 0xBB72, 0x7C78, 0xBB73, 0x7C79, 0xBB74, 0x7C7A, 0xBB75, 0x7C7E, 0xBB76, 0x7C7F, 0xBB77, 0x7C80, 0xBB78, 0x7C81, + 0xBB79, 0x7C82, 0xBB7A, 0x7C83, 0xBB7B, 0x7C84, 0xBB7C, 0x7C85, 0xBB7D, 0x7C86, 0xBB7E, 0x7C87, 0xBB80, 0x7C88, 0xBB81, 0x7C8A, + 0xBB82, 0x7C8B, 0xBB83, 0x7C8C, 0xBB84, 0x7C8D, 0xBB85, 0x7C8E, 0xBB86, 0x7C8F, 0xBB87, 0x7C90, 0xBB88, 0x7C93, 0xBB89, 0x7C94, + 0xBB8A, 0x7C96, 0xBB8B, 0x7C99, 0xBB8C, 0x7C9A, 0xBB8D, 0x7C9B, 0xBB8E, 0x7CA0, 0xBB8F, 0x7CA1, 0xBB90, 0x7CA3, 0xBB91, 0x7CA6, + 0xBB92, 0x7CA7, 0xBB93, 0x7CA8, 0xBB94, 0x7CA9, 0xBB95, 0x7CAB, 0xBB96, 0x7CAC, 0xBB97, 0x7CAD, 0xBB98, 0x7CAF, 0xBB99, 0x7CB0, + 0xBB9A, 0x7CB4, 0xBB9B, 0x7CB5, 0xBB9C, 0x7CB6, 0xBB9D, 0x7CB7, 0xBB9E, 0x7CB8, 0xBB9F, 0x7CBA, 0xBBA0, 0x7CBB, 0xBBA1, 0x5F27, + 0xBBA2, 0x864E, 0xBBA3, 0x552C, 0xBBA4, 0x62A4, 0xBBA5, 0x4E92, 0xBBA6, 0x6CAA, 0xBBA7, 0x6237, 0xBBA8, 0x82B1, 0xBBA9, 0x54D7, + 0xBBAA, 0x534E, 0xBBAB, 0x733E, 0xBBAC, 0x6ED1, 0xBBAD, 0x753B, 0xBBAE, 0x5212, 0xBBAF, 0x5316, 0xBBB0, 0x8BDD, 0xBBB1, 0x69D0, + 0xBBB2, 0x5F8A, 0xBBB3, 0x6000, 0xBBB4, 0x6DEE, 0xBBB5, 0x574F, 0xBBB6, 0x6B22, 0xBBB7, 0x73AF, 0xBBB8, 0x6853, 0xBBB9, 0x8FD8, + 0xBBBA, 0x7F13, 0xBBBB, 0x6362, 0xBBBC, 0x60A3, 0xBBBD, 0x5524, 0xBBBE, 0x75EA, 0xBBBF, 0x8C62, 0xBBC0, 0x7115, 0xBBC1, 0x6DA3, + 0xBBC2, 0x5BA6, 0xBBC3, 0x5E7B, 0xBBC4, 0x8352, 0xBBC5, 0x614C, 0xBBC6, 0x9EC4, 0xBBC7, 0x78FA, 0xBBC8, 0x8757, 0xBBC9, 0x7C27, + 0xBBCA, 0x7687, 0xBBCB, 0x51F0, 0xBBCC, 0x60F6, 0xBBCD, 0x714C, 0xBBCE, 0x6643, 0xBBCF, 0x5E4C, 0xBBD0, 0x604D, 0xBBD1, 0x8C0E, + 0xBBD2, 0x7070, 0xBBD3, 0x6325, 0xBBD4, 0x8F89, 0xBBD5, 0x5FBD, 0xBBD6, 0x6062, 0xBBD7, 0x86D4, 0xBBD8, 0x56DE, 0xBBD9, 0x6BC1, + 0xBBDA, 0x6094, 0xBBDB, 0x6167, 0xBBDC, 0x5349, 0xBBDD, 0x60E0, 0xBBDE, 0x6666, 0xBBDF, 0x8D3F, 0xBBE0, 0x79FD, 0xBBE1, 0x4F1A, + 0xBBE2, 0x70E9, 0xBBE3, 0x6C47, 0xBBE4, 0x8BB3, 0xBBE5, 0x8BF2, 0xBBE6, 0x7ED8, 0xBBE7, 0x8364, 0xBBE8, 0x660F, 0xBBE9, 0x5A5A, + 0xBBEA, 0x9B42, 0xBBEB, 0x6D51, 0xBBEC, 0x6DF7, 0xBBED, 0x8C41, 0xBBEE, 0x6D3B, 0xBBEF, 0x4F19, 0xBBF0, 0x706B, 0xBBF1, 0x83B7, + 0xBBF2, 0x6216, 0xBBF3, 0x60D1, 0xBBF4, 0x970D, 0xBBF5, 0x8D27, 0xBBF6, 0x7978, 0xBBF7, 0x51FB, 0xBBF8, 0x573E, 0xBBF9, 0x57FA, + 0xBBFA, 0x673A, 0xBBFB, 0x7578, 0xBBFC, 0x7A3D, 0xBBFD, 0x79EF, 0xBBFE, 0x7B95, 0xBC40, 0x7CBF, 0xBC41, 0x7CC0, 0xBC42, 0x7CC2, + 0xBC43, 0x7CC3, 0xBC44, 0x7CC4, 0xBC45, 0x7CC6, 0xBC46, 0x7CC9, 0xBC47, 0x7CCB, 0xBC48, 0x7CCE, 0xBC49, 0x7CCF, 0xBC4A, 0x7CD0, + 0xBC4B, 0x7CD1, 0xBC4C, 0x7CD2, 0xBC4D, 0x7CD3, 0xBC4E, 0x7CD4, 0xBC4F, 0x7CD8, 0xBC50, 0x7CDA, 0xBC51, 0x7CDB, 0xBC52, 0x7CDD, + 0xBC53, 0x7CDE, 0xBC54, 0x7CE1, 0xBC55, 0x7CE2, 0xBC56, 0x7CE3, 0xBC57, 0x7CE4, 0xBC58, 0x7CE5, 0xBC59, 0x7CE6, 0xBC5A, 0x7CE7, + 0xBC5B, 0x7CE9, 0xBC5C, 0x7CEA, 0xBC5D, 0x7CEB, 0xBC5E, 0x7CEC, 0xBC5F, 0x7CED, 0xBC60, 0x7CEE, 0xBC61, 0x7CF0, 0xBC62, 0x7CF1, + 0xBC63, 0x7CF2, 0xBC64, 0x7CF3, 0xBC65, 0x7CF4, 0xBC66, 0x7CF5, 0xBC67, 0x7CF6, 0xBC68, 0x7CF7, 0xBC69, 0x7CF9, 0xBC6A, 0x7CFA, + 0xBC6B, 0x7CFC, 0xBC6C, 0x7CFD, 0xBC6D, 0x7CFE, 0xBC6E, 0x7CFF, 0xBC6F, 0x7D00, 0xBC70, 0x7D01, 0xBC71, 0x7D02, 0xBC72, 0x7D03, + 0xBC73, 0x7D04, 0xBC74, 0x7D05, 0xBC75, 0x7D06, 0xBC76, 0x7D07, 0xBC77, 0x7D08, 0xBC78, 0x7D09, 0xBC79, 0x7D0B, 0xBC7A, 0x7D0C, + 0xBC7B, 0x7D0D, 0xBC7C, 0x7D0E, 0xBC7D, 0x7D0F, 0xBC7E, 0x7D10, 0xBC80, 0x7D11, 0xBC81, 0x7D12, 0xBC82, 0x7D13, 0xBC83, 0x7D14, + 0xBC84, 0x7D15, 0xBC85, 0x7D16, 0xBC86, 0x7D17, 0xBC87, 0x7D18, 0xBC88, 0x7D19, 0xBC89, 0x7D1A, 0xBC8A, 0x7D1B, 0xBC8B, 0x7D1C, + 0xBC8C, 0x7D1D, 0xBC8D, 0x7D1E, 0xBC8E, 0x7D1F, 0xBC8F, 0x7D21, 0xBC90, 0x7D23, 0xBC91, 0x7D24, 0xBC92, 0x7D25, 0xBC93, 0x7D26, + 0xBC94, 0x7D28, 0xBC95, 0x7D29, 0xBC96, 0x7D2A, 0xBC97, 0x7D2C, 0xBC98, 0x7D2D, 0xBC99, 0x7D2E, 0xBC9A, 0x7D30, 0xBC9B, 0x7D31, + 0xBC9C, 0x7D32, 0xBC9D, 0x7D33, 0xBC9E, 0x7D34, 0xBC9F, 0x7D35, 0xBCA0, 0x7D36, 0xBCA1, 0x808C, 0xBCA2, 0x9965, 0xBCA3, 0x8FF9, + 0xBCA4, 0x6FC0, 0xBCA5, 0x8BA5, 0xBCA6, 0x9E21, 0xBCA7, 0x59EC, 0xBCA8, 0x7EE9, 0xBCA9, 0x7F09, 0xBCAA, 0x5409, 0xBCAB, 0x6781, + 0xBCAC, 0x68D8, 0xBCAD, 0x8F91, 0xBCAE, 0x7C4D, 0xBCAF, 0x96C6, 0xBCB0, 0x53CA, 0xBCB1, 0x6025, 0xBCB2, 0x75BE, 0xBCB3, 0x6C72, + 0xBCB4, 0x5373, 0xBCB5, 0x5AC9, 0xBCB6, 0x7EA7, 0xBCB7, 0x6324, 0xBCB8, 0x51E0, 0xBCB9, 0x810A, 0xBCBA, 0x5DF1, 0xBCBB, 0x84DF, + 0xBCBC, 0x6280, 0xBCBD, 0x5180, 0xBCBE, 0x5B63, 0xBCBF, 0x4F0E, 0xBCC0, 0x796D, 0xBCC1, 0x5242, 0xBCC2, 0x60B8, 0xBCC3, 0x6D4E, + 0xBCC4, 0x5BC4, 0xBCC5, 0x5BC2, 0xBCC6, 0x8BA1, 0xBCC7, 0x8BB0, 0xBCC8, 0x65E2, 0xBCC9, 0x5FCC, 0xBCCA, 0x9645, 0xBCCB, 0x5993, + 0xBCCC, 0x7EE7, 0xBCCD, 0x7EAA, 0xBCCE, 0x5609, 0xBCCF, 0x67B7, 0xBCD0, 0x5939, 0xBCD1, 0x4F73, 0xBCD2, 0x5BB6, 0xBCD3, 0x52A0, + 0xBCD4, 0x835A, 0xBCD5, 0x988A, 0xBCD6, 0x8D3E, 0xBCD7, 0x7532, 0xBCD8, 0x94BE, 0xBCD9, 0x5047, 0xBCDA, 0x7A3C, 0xBCDB, 0x4EF7, + 0xBCDC, 0x67B6, 0xBCDD, 0x9A7E, 0xBCDE, 0x5AC1, 0xBCDF, 0x6B7C, 0xBCE0, 0x76D1, 0xBCE1, 0x575A, 0xBCE2, 0x5C16, 0xBCE3, 0x7B3A, + 0xBCE4, 0x95F4, 0xBCE5, 0x714E, 0xBCE6, 0x517C, 0xBCE7, 0x80A9, 0xBCE8, 0x8270, 0xBCE9, 0x5978, 0xBCEA, 0x7F04, 0xBCEB, 0x8327, + 0xBCEC, 0x68C0, 0xBCED, 0x67EC, 0xBCEE, 0x78B1, 0xBCEF, 0x7877, 0xBCF0, 0x62E3, 0xBCF1, 0x6361, 0xBCF2, 0x7B80, 0xBCF3, 0x4FED, + 0xBCF4, 0x526A, 0xBCF5, 0x51CF, 0xBCF6, 0x8350, 0xBCF7, 0x69DB, 0xBCF8, 0x9274, 0xBCF9, 0x8DF5, 0xBCFA, 0x8D31, 0xBCFB, 0x89C1, + 0xBCFC, 0x952E, 0xBCFD, 0x7BAD, 0xBCFE, 0x4EF6, 0xBD40, 0x7D37, 0xBD41, 0x7D38, 0xBD42, 0x7D39, 0xBD43, 0x7D3A, 0xBD44, 0x7D3B, + 0xBD45, 0x7D3C, 0xBD46, 0x7D3D, 0xBD47, 0x7D3E, 0xBD48, 0x7D3F, 0xBD49, 0x7D40, 0xBD4A, 0x7D41, 0xBD4B, 0x7D42, 0xBD4C, 0x7D43, + 0xBD4D, 0x7D44, 0xBD4E, 0x7D45, 0xBD4F, 0x7D46, 0xBD50, 0x7D47, 0xBD51, 0x7D48, 0xBD52, 0x7D49, 0xBD53, 0x7D4A, 0xBD54, 0x7D4B, + 0xBD55, 0x7D4C, 0xBD56, 0x7D4D, 0xBD57, 0x7D4E, 0xBD58, 0x7D4F, 0xBD59, 0x7D50, 0xBD5A, 0x7D51, 0xBD5B, 0x7D52, 0xBD5C, 0x7D53, + 0xBD5D, 0x7D54, 0xBD5E, 0x7D55, 0xBD5F, 0x7D56, 0xBD60, 0x7D57, 0xBD61, 0x7D58, 0xBD62, 0x7D59, 0xBD63, 0x7D5A, 0xBD64, 0x7D5B, + 0xBD65, 0x7D5C, 0xBD66, 0x7D5D, 0xBD67, 0x7D5E, 0xBD68, 0x7D5F, 0xBD69, 0x7D60, 0xBD6A, 0x7D61, 0xBD6B, 0x7D62, 0xBD6C, 0x7D63, + 0xBD6D, 0x7D64, 0xBD6E, 0x7D65, 0xBD6F, 0x7D66, 0xBD70, 0x7D67, 0xBD71, 0x7D68, 0xBD72, 0x7D69, 0xBD73, 0x7D6A, 0xBD74, 0x7D6B, + 0xBD75, 0x7D6C, 0xBD76, 0x7D6D, 0xBD77, 0x7D6F, 0xBD78, 0x7D70, 0xBD79, 0x7D71, 0xBD7A, 0x7D72, 0xBD7B, 0x7D73, 0xBD7C, 0x7D74, + 0xBD7D, 0x7D75, 0xBD7E, 0x7D76, 0xBD80, 0x7D78, 0xBD81, 0x7D79, 0xBD82, 0x7D7A, 0xBD83, 0x7D7B, 0xBD84, 0x7D7C, 0xBD85, 0x7D7D, + 0xBD86, 0x7D7E, 0xBD87, 0x7D7F, 0xBD88, 0x7D80, 0xBD89, 0x7D81, 0xBD8A, 0x7D82, 0xBD8B, 0x7D83, 0xBD8C, 0x7D84, 0xBD8D, 0x7D85, + 0xBD8E, 0x7D86, 0xBD8F, 0x7D87, 0xBD90, 0x7D88, 0xBD91, 0x7D89, 0xBD92, 0x7D8A, 0xBD93, 0x7D8B, 0xBD94, 0x7D8C, 0xBD95, 0x7D8D, + 0xBD96, 0x7D8E, 0xBD97, 0x7D8F, 0xBD98, 0x7D90, 0xBD99, 0x7D91, 0xBD9A, 0x7D92, 0xBD9B, 0x7D93, 0xBD9C, 0x7D94, 0xBD9D, 0x7D95, + 0xBD9E, 0x7D96, 0xBD9F, 0x7D97, 0xBDA0, 0x7D98, 0xBDA1, 0x5065, 0xBDA2, 0x8230, 0xBDA3, 0x5251, 0xBDA4, 0x996F, 0xBDA5, 0x6E10, + 0xBDA6, 0x6E85, 0xBDA7, 0x6DA7, 0xBDA8, 0x5EFA, 0xBDA9, 0x50F5, 0xBDAA, 0x59DC, 0xBDAB, 0x5C06, 0xBDAC, 0x6D46, 0xBDAD, 0x6C5F, + 0xBDAE, 0x7586, 0xBDAF, 0x848B, 0xBDB0, 0x6868, 0xBDB1, 0x5956, 0xBDB2, 0x8BB2, 0xBDB3, 0x5320, 0xBDB4, 0x9171, 0xBDB5, 0x964D, + 0xBDB6, 0x8549, 0xBDB7, 0x6912, 0xBDB8, 0x7901, 0xBDB9, 0x7126, 0xBDBA, 0x80F6, 0xBDBB, 0x4EA4, 0xBDBC, 0x90CA, 0xBDBD, 0x6D47, + 0xBDBE, 0x9A84, 0xBDBF, 0x5A07, 0xBDC0, 0x56BC, 0xBDC1, 0x6405, 0xBDC2, 0x94F0, 0xBDC3, 0x77EB, 0xBDC4, 0x4FA5, 0xBDC5, 0x811A, + 0xBDC6, 0x72E1, 0xBDC7, 0x89D2, 0xBDC8, 0x997A, 0xBDC9, 0x7F34, 0xBDCA, 0x7EDE, 0xBDCB, 0x527F, 0xBDCC, 0x6559, 0xBDCD, 0x9175, + 0xBDCE, 0x8F7F, 0xBDCF, 0x8F83, 0xBDD0, 0x53EB, 0xBDD1, 0x7A96, 0xBDD2, 0x63ED, 0xBDD3, 0x63A5, 0xBDD4, 0x7686, 0xBDD5, 0x79F8, + 0xBDD6, 0x8857, 0xBDD7, 0x9636, 0xBDD8, 0x622A, 0xBDD9, 0x52AB, 0xBDDA, 0x8282, 0xBDDB, 0x6854, 0xBDDC, 0x6770, 0xBDDD, 0x6377, + 0xBDDE, 0x776B, 0xBDDF, 0x7AED, 0xBDE0, 0x6D01, 0xBDE1, 0x7ED3, 0xBDE2, 0x89E3, 0xBDE3, 0x59D0, 0xBDE4, 0x6212, 0xBDE5, 0x85C9, + 0xBDE6, 0x82A5, 0xBDE7, 0x754C, 0xBDE8, 0x501F, 0xBDE9, 0x4ECB, 0xBDEA, 0x75A5, 0xBDEB, 0x8BEB, 0xBDEC, 0x5C4A, 0xBDED, 0x5DFE, + 0xBDEE, 0x7B4B, 0xBDEF, 0x65A4, 0xBDF0, 0x91D1, 0xBDF1, 0x4ECA, 0xBDF2, 0x6D25, 0xBDF3, 0x895F, 0xBDF4, 0x7D27, 0xBDF5, 0x9526, + 0xBDF6, 0x4EC5, 0xBDF7, 0x8C28, 0xBDF8, 0x8FDB, 0xBDF9, 0x9773, 0xBDFA, 0x664B, 0xBDFB, 0x7981, 0xBDFC, 0x8FD1, 0xBDFD, 0x70EC, + 0xBDFE, 0x6D78, 0xBE40, 0x7D99, 0xBE41, 0x7D9A, 0xBE42, 0x7D9B, 0xBE43, 0x7D9C, 0xBE44, 0x7D9D, 0xBE45, 0x7D9E, 0xBE46, 0x7D9F, + 0xBE47, 0x7DA0, 0xBE48, 0x7DA1, 0xBE49, 0x7DA2, 0xBE4A, 0x7DA3, 0xBE4B, 0x7DA4, 0xBE4C, 0x7DA5, 0xBE4D, 0x7DA7, 0xBE4E, 0x7DA8, + 0xBE4F, 0x7DA9, 0xBE50, 0x7DAA, 0xBE51, 0x7DAB, 0xBE52, 0x7DAC, 0xBE53, 0x7DAD, 0xBE54, 0x7DAF, 0xBE55, 0x7DB0, 0xBE56, 0x7DB1, + 0xBE57, 0x7DB2, 0xBE58, 0x7DB3, 0xBE59, 0x7DB4, 0xBE5A, 0x7DB5, 0xBE5B, 0x7DB6, 0xBE5C, 0x7DB7, 0xBE5D, 0x7DB8, 0xBE5E, 0x7DB9, + 0xBE5F, 0x7DBA, 0xBE60, 0x7DBB, 0xBE61, 0x7DBC, 0xBE62, 0x7DBD, 0xBE63, 0x7DBE, 0xBE64, 0x7DBF, 0xBE65, 0x7DC0, 0xBE66, 0x7DC1, + 0xBE67, 0x7DC2, 0xBE68, 0x7DC3, 0xBE69, 0x7DC4, 0xBE6A, 0x7DC5, 0xBE6B, 0x7DC6, 0xBE6C, 0x7DC7, 0xBE6D, 0x7DC8, 0xBE6E, 0x7DC9, + 0xBE6F, 0x7DCA, 0xBE70, 0x7DCB, 0xBE71, 0x7DCC, 0xBE72, 0x7DCD, 0xBE73, 0x7DCE, 0xBE74, 0x7DCF, 0xBE75, 0x7DD0, 0xBE76, 0x7DD1, + 0xBE77, 0x7DD2, 0xBE78, 0x7DD3, 0xBE79, 0x7DD4, 0xBE7A, 0x7DD5, 0xBE7B, 0x7DD6, 0xBE7C, 0x7DD7, 0xBE7D, 0x7DD8, 0xBE7E, 0x7DD9, + 0xBE80, 0x7DDA, 0xBE81, 0x7DDB, 0xBE82, 0x7DDC, 0xBE83, 0x7DDD, 0xBE84, 0x7DDE, 0xBE85, 0x7DDF, 0xBE86, 0x7DE0, 0xBE87, 0x7DE1, + 0xBE88, 0x7DE2, 0xBE89, 0x7DE3, 0xBE8A, 0x7DE4, 0xBE8B, 0x7DE5, 0xBE8C, 0x7DE6, 0xBE8D, 0x7DE7, 0xBE8E, 0x7DE8, 0xBE8F, 0x7DE9, + 0xBE90, 0x7DEA, 0xBE91, 0x7DEB, 0xBE92, 0x7DEC, 0xBE93, 0x7DED, 0xBE94, 0x7DEE, 0xBE95, 0x7DEF, 0xBE96, 0x7DF0, 0xBE97, 0x7DF1, + 0xBE98, 0x7DF2, 0xBE99, 0x7DF3, 0xBE9A, 0x7DF4, 0xBE9B, 0x7DF5, 0xBE9C, 0x7DF6, 0xBE9D, 0x7DF7, 0xBE9E, 0x7DF8, 0xBE9F, 0x7DF9, + 0xBEA0, 0x7DFA, 0xBEA1, 0x5C3D, 0xBEA2, 0x52B2, 0xBEA3, 0x8346, 0xBEA4, 0x5162, 0xBEA5, 0x830E, 0xBEA6, 0x775B, 0xBEA7, 0x6676, + 0xBEA8, 0x9CB8, 0xBEA9, 0x4EAC, 0xBEAA, 0x60CA, 0xBEAB, 0x7CBE, 0xBEAC, 0x7CB3, 0xBEAD, 0x7ECF, 0xBEAE, 0x4E95, 0xBEAF, 0x8B66, + 0xBEB0, 0x666F, 0xBEB1, 0x9888, 0xBEB2, 0x9759, 0xBEB3, 0x5883, 0xBEB4, 0x656C, 0xBEB5, 0x955C, 0xBEB6, 0x5F84, 0xBEB7, 0x75C9, + 0xBEB8, 0x9756, 0xBEB9, 0x7ADF, 0xBEBA, 0x7ADE, 0xBEBB, 0x51C0, 0xBEBC, 0x70AF, 0xBEBD, 0x7A98, 0xBEBE, 0x63EA, 0xBEBF, 0x7A76, + 0xBEC0, 0x7EA0, 0xBEC1, 0x7396, 0xBEC2, 0x97ED, 0xBEC3, 0x4E45, 0xBEC4, 0x7078, 0xBEC5, 0x4E5D, 0xBEC6, 0x9152, 0xBEC7, 0x53A9, + 0xBEC8, 0x6551, 0xBEC9, 0x65E7, 0xBECA, 0x81FC, 0xBECB, 0x8205, 0xBECC, 0x548E, 0xBECD, 0x5C31, 0xBECE, 0x759A, 0xBECF, 0x97A0, + 0xBED0, 0x62D8, 0xBED1, 0x72D9, 0xBED2, 0x75BD, 0xBED3, 0x5C45, 0xBED4, 0x9A79, 0xBED5, 0x83CA, 0xBED6, 0x5C40, 0xBED7, 0x5480, + 0xBED8, 0x77E9, 0xBED9, 0x4E3E, 0xBEDA, 0x6CAE, 0xBEDB, 0x805A, 0xBEDC, 0x62D2, 0xBEDD, 0x636E, 0xBEDE, 0x5DE8, 0xBEDF, 0x5177, + 0xBEE0, 0x8DDD, 0xBEE1, 0x8E1E, 0xBEE2, 0x952F, 0xBEE3, 0x4FF1, 0xBEE4, 0x53E5, 0xBEE5, 0x60E7, 0xBEE6, 0x70AC, 0xBEE7, 0x5267, + 0xBEE8, 0x6350, 0xBEE9, 0x9E43, 0xBEEA, 0x5A1F, 0xBEEB, 0x5026, 0xBEEC, 0x7737, 0xBEED, 0x5377, 0xBEEE, 0x7EE2, 0xBEEF, 0x6485, + 0xBEF0, 0x652B, 0xBEF1, 0x6289, 0xBEF2, 0x6398, 0xBEF3, 0x5014, 0xBEF4, 0x7235, 0xBEF5, 0x89C9, 0xBEF6, 0x51B3, 0xBEF7, 0x8BC0, + 0xBEF8, 0x7EDD, 0xBEF9, 0x5747, 0xBEFA, 0x83CC, 0xBEFB, 0x94A7, 0xBEFC, 0x519B, 0xBEFD, 0x541B, 0xBEFE, 0x5CFB, 0xBF40, 0x7DFB, + 0xBF41, 0x7DFC, 0xBF42, 0x7DFD, 0xBF43, 0x7DFE, 0xBF44, 0x7DFF, 0xBF45, 0x7E00, 0xBF46, 0x7E01, 0xBF47, 0x7E02, 0xBF48, 0x7E03, + 0xBF49, 0x7E04, 0xBF4A, 0x7E05, 0xBF4B, 0x7E06, 0xBF4C, 0x7E07, 0xBF4D, 0x7E08, 0xBF4E, 0x7E09, 0xBF4F, 0x7E0A, 0xBF50, 0x7E0B, + 0xBF51, 0x7E0C, 0xBF52, 0x7E0D, 0xBF53, 0x7E0E, 0xBF54, 0x7E0F, 0xBF55, 0x7E10, 0xBF56, 0x7E11, 0xBF57, 0x7E12, 0xBF58, 0x7E13, + 0xBF59, 0x7E14, 0xBF5A, 0x7E15, 0xBF5B, 0x7E16, 0xBF5C, 0x7E17, 0xBF5D, 0x7E18, 0xBF5E, 0x7E19, 0xBF5F, 0x7E1A, 0xBF60, 0x7E1B, + 0xBF61, 0x7E1C, 0xBF62, 0x7E1D, 0xBF63, 0x7E1E, 0xBF64, 0x7E1F, 0xBF65, 0x7E20, 0xBF66, 0x7E21, 0xBF67, 0x7E22, 0xBF68, 0x7E23, + 0xBF69, 0x7E24, 0xBF6A, 0x7E25, 0xBF6B, 0x7E26, 0xBF6C, 0x7E27, 0xBF6D, 0x7E28, 0xBF6E, 0x7E29, 0xBF6F, 0x7E2A, 0xBF70, 0x7E2B, + 0xBF71, 0x7E2C, 0xBF72, 0x7E2D, 0xBF73, 0x7E2E, 0xBF74, 0x7E2F, 0xBF75, 0x7E30, 0xBF76, 0x7E31, 0xBF77, 0x7E32, 0xBF78, 0x7E33, + 0xBF79, 0x7E34, 0xBF7A, 0x7E35, 0xBF7B, 0x7E36, 0xBF7C, 0x7E37, 0xBF7D, 0x7E38, 0xBF7E, 0x7E39, 0xBF80, 0x7E3A, 0xBF81, 0x7E3C, + 0xBF82, 0x7E3D, 0xBF83, 0x7E3E, 0xBF84, 0x7E3F, 0xBF85, 0x7E40, 0xBF86, 0x7E42, 0xBF87, 0x7E43, 0xBF88, 0x7E44, 0xBF89, 0x7E45, + 0xBF8A, 0x7E46, 0xBF8B, 0x7E48, 0xBF8C, 0x7E49, 0xBF8D, 0x7E4A, 0xBF8E, 0x7E4B, 0xBF8F, 0x7E4C, 0xBF90, 0x7E4D, 0xBF91, 0x7E4E, + 0xBF92, 0x7E4F, 0xBF93, 0x7E50, 0xBF94, 0x7E51, 0xBF95, 0x7E52, 0xBF96, 0x7E53, 0xBF97, 0x7E54, 0xBF98, 0x7E55, 0xBF99, 0x7E56, + 0xBF9A, 0x7E57, 0xBF9B, 0x7E58, 0xBF9C, 0x7E59, 0xBF9D, 0x7E5A, 0xBF9E, 0x7E5B, 0xBF9F, 0x7E5C, 0xBFA0, 0x7E5D, 0xBFA1, 0x4FCA, + 0xBFA2, 0x7AE3, 0xBFA3, 0x6D5A, 0xBFA4, 0x90E1, 0xBFA5, 0x9A8F, 0xBFA6, 0x5580, 0xBFA7, 0x5496, 0xBFA8, 0x5361, 0xBFA9, 0x54AF, + 0xBFAA, 0x5F00, 0xBFAB, 0x63E9, 0xBFAC, 0x6977, 0xBFAD, 0x51EF, 0xBFAE, 0x6168, 0xBFAF, 0x520A, 0xBFB0, 0x582A, 0xBFB1, 0x52D8, + 0xBFB2, 0x574E, 0xBFB3, 0x780D, 0xBFB4, 0x770B, 0xBFB5, 0x5EB7, 0xBFB6, 0x6177, 0xBFB7, 0x7CE0, 0xBFB8, 0x625B, 0xBFB9, 0x6297, + 0xBFBA, 0x4EA2, 0xBFBB, 0x7095, 0xBFBC, 0x8003, 0xBFBD, 0x62F7, 0xBFBE, 0x70E4, 0xBFBF, 0x9760, 0xBFC0, 0x5777, 0xBFC1, 0x82DB, + 0xBFC2, 0x67EF, 0xBFC3, 0x68F5, 0xBFC4, 0x78D5, 0xBFC5, 0x9897, 0xBFC6, 0x79D1, 0xBFC7, 0x58F3, 0xBFC8, 0x54B3, 0xBFC9, 0x53EF, + 0xBFCA, 0x6E34, 0xBFCB, 0x514B, 0xBFCC, 0x523B, 0xBFCD, 0x5BA2, 0xBFCE, 0x8BFE, 0xBFCF, 0x80AF, 0xBFD0, 0x5543, 0xBFD1, 0x57A6, + 0xBFD2, 0x6073, 0xBFD3, 0x5751, 0xBFD4, 0x542D, 0xBFD5, 0x7A7A, 0xBFD6, 0x6050, 0xBFD7, 0x5B54, 0xBFD8, 0x63A7, 0xBFD9, 0x62A0, + 0xBFDA, 0x53E3, 0xBFDB, 0x6263, 0xBFDC, 0x5BC7, 0xBFDD, 0x67AF, 0xBFDE, 0x54ED, 0xBFDF, 0x7A9F, 0xBFE0, 0x82E6, 0xBFE1, 0x9177, + 0xBFE2, 0x5E93, 0xBFE3, 0x88E4, 0xBFE4, 0x5938, 0xBFE5, 0x57AE, 0xBFE6, 0x630E, 0xBFE7, 0x8DE8, 0xBFE8, 0x80EF, 0xBFE9, 0x5757, + 0xBFEA, 0x7B77, 0xBFEB, 0x4FA9, 0xBFEC, 0x5FEB, 0xBFED, 0x5BBD, 0xBFEE, 0x6B3E, 0xBFEF, 0x5321, 0xBFF0, 0x7B50, 0xBFF1, 0x72C2, + 0xBFF2, 0x6846, 0xBFF3, 0x77FF, 0xBFF4, 0x7736, 0xBFF5, 0x65F7, 0xBFF6, 0x51B5, 0xBFF7, 0x4E8F, 0xBFF8, 0x76D4, 0xBFF9, 0x5CBF, + 0xBFFA, 0x7AA5, 0xBFFB, 0x8475, 0xBFFC, 0x594E, 0xBFFD, 0x9B41, 0xBFFE, 0x5080, 0xC040, 0x7E5E, 0xC041, 0x7E5F, 0xC042, 0x7E60, + 0xC043, 0x7E61, 0xC044, 0x7E62, 0xC045, 0x7E63, 0xC046, 0x7E64, 0xC047, 0x7E65, 0xC048, 0x7E66, 0xC049, 0x7E67, 0xC04A, 0x7E68, + 0xC04B, 0x7E69, 0xC04C, 0x7E6A, 0xC04D, 0x7E6B, 0xC04E, 0x7E6C, 0xC04F, 0x7E6D, 0xC050, 0x7E6E, 0xC051, 0x7E6F, 0xC052, 0x7E70, + 0xC053, 0x7E71, 0xC054, 0x7E72, 0xC055, 0x7E73, 0xC056, 0x7E74, 0xC057, 0x7E75, 0xC058, 0x7E76, 0xC059, 0x7E77, 0xC05A, 0x7E78, + 0xC05B, 0x7E79, 0xC05C, 0x7E7A, 0xC05D, 0x7E7B, 0xC05E, 0x7E7C, 0xC05F, 0x7E7D, 0xC060, 0x7E7E, 0xC061, 0x7E7F, 0xC062, 0x7E80, + 0xC063, 0x7E81, 0xC064, 0x7E83, 0xC065, 0x7E84, 0xC066, 0x7E85, 0xC067, 0x7E86, 0xC068, 0x7E87, 0xC069, 0x7E88, 0xC06A, 0x7E89, + 0xC06B, 0x7E8A, 0xC06C, 0x7E8B, 0xC06D, 0x7E8C, 0xC06E, 0x7E8D, 0xC06F, 0x7E8E, 0xC070, 0x7E8F, 0xC071, 0x7E90, 0xC072, 0x7E91, + 0xC073, 0x7E92, 0xC074, 0x7E93, 0xC075, 0x7E94, 0xC076, 0x7E95, 0xC077, 0x7E96, 0xC078, 0x7E97, 0xC079, 0x7E98, 0xC07A, 0x7E99, + 0xC07B, 0x7E9A, 0xC07C, 0x7E9C, 0xC07D, 0x7E9D, 0xC07E, 0x7E9E, 0xC080, 0x7EAE, 0xC081, 0x7EB4, 0xC082, 0x7EBB, 0xC083, 0x7EBC, + 0xC084, 0x7ED6, 0xC085, 0x7EE4, 0xC086, 0x7EEC, 0xC087, 0x7EF9, 0xC088, 0x7F0A, 0xC089, 0x7F10, 0xC08A, 0x7F1E, 0xC08B, 0x7F37, + 0xC08C, 0x7F39, 0xC08D, 0x7F3B, 0xC08E, 0x7F3C, 0xC08F, 0x7F3D, 0xC090, 0x7F3E, 0xC091, 0x7F3F, 0xC092, 0x7F40, 0xC093, 0x7F41, + 0xC094, 0x7F43, 0xC095, 0x7F46, 0xC096, 0x7F47, 0xC097, 0x7F48, 0xC098, 0x7F49, 0xC099, 0x7F4A, 0xC09A, 0x7F4B, 0xC09B, 0x7F4C, + 0xC09C, 0x7F4D, 0xC09D, 0x7F4E, 0xC09E, 0x7F4F, 0xC09F, 0x7F52, 0xC0A0, 0x7F53, 0xC0A1, 0x9988, 0xC0A2, 0x6127, 0xC0A3, 0x6E83, + 0xC0A4, 0x5764, 0xC0A5, 0x6606, 0xC0A6, 0x6346, 0xC0A7, 0x56F0, 0xC0A8, 0x62EC, 0xC0A9, 0x6269, 0xC0AA, 0x5ED3, 0xC0AB, 0x9614, + 0xC0AC, 0x5783, 0xC0AD, 0x62C9, 0xC0AE, 0x5587, 0xC0AF, 0x8721, 0xC0B0, 0x814A, 0xC0B1, 0x8FA3, 0xC0B2, 0x5566, 0xC0B3, 0x83B1, + 0xC0B4, 0x6765, 0xC0B5, 0x8D56, 0xC0B6, 0x84DD, 0xC0B7, 0x5A6A, 0xC0B8, 0x680F, 0xC0B9, 0x62E6, 0xC0BA, 0x7BEE, 0xC0BB, 0x9611, + 0xC0BC, 0x5170, 0xC0BD, 0x6F9C, 0xC0BE, 0x8C30, 0xC0BF, 0x63FD, 0xC0C0, 0x89C8, 0xC0C1, 0x61D2, 0xC0C2, 0x7F06, 0xC0C3, 0x70C2, + 0xC0C4, 0x6EE5, 0xC0C5, 0x7405, 0xC0C6, 0x6994, 0xC0C7, 0x72FC, 0xC0C8, 0x5ECA, 0xC0C9, 0x90CE, 0xC0CA, 0x6717, 0xC0CB, 0x6D6A, + 0xC0CC, 0x635E, 0xC0CD, 0x52B3, 0xC0CE, 0x7262, 0xC0CF, 0x8001, 0xC0D0, 0x4F6C, 0xC0D1, 0x59E5, 0xC0D2, 0x916A, 0xC0D3, 0x70D9, + 0xC0D4, 0x6D9D, 0xC0D5, 0x52D2, 0xC0D6, 0x4E50, 0xC0D7, 0x96F7, 0xC0D8, 0x956D, 0xC0D9, 0x857E, 0xC0DA, 0x78CA, 0xC0DB, 0x7D2F, + 0xC0DC, 0x5121, 0xC0DD, 0x5792, 0xC0DE, 0x64C2, 0xC0DF, 0x808B, 0xC0E0, 0x7C7B, 0xC0E1, 0x6CEA, 0xC0E2, 0x68F1, 0xC0E3, 0x695E, + 0xC0E4, 0x51B7, 0xC0E5, 0x5398, 0xC0E6, 0x68A8, 0xC0E7, 0x7281, 0xC0E8, 0x9ECE, 0xC0E9, 0x7BF1, 0xC0EA, 0x72F8, 0xC0EB, 0x79BB, + 0xC0EC, 0x6F13, 0xC0ED, 0x7406, 0xC0EE, 0x674E, 0xC0EF, 0x91CC, 0xC0F0, 0x9CA4, 0xC0F1, 0x793C, 0xC0F2, 0x8389, 0xC0F3, 0x8354, + 0xC0F4, 0x540F, 0xC0F5, 0x6817, 0xC0F6, 0x4E3D, 0xC0F7, 0x5389, 0xC0F8, 0x52B1, 0xC0F9, 0x783E, 0xC0FA, 0x5386, 0xC0FB, 0x5229, + 0xC0FC, 0x5088, 0xC0FD, 0x4F8B, 0xC0FE, 0x4FD0, 0xC140, 0x7F56, 0xC141, 0x7F59, 0xC142, 0x7F5B, 0xC143, 0x7F5C, 0xC144, 0x7F5D, + 0xC145, 0x7F5E, 0xC146, 0x7F60, 0xC147, 0x7F63, 0xC148, 0x7F64, 0xC149, 0x7F65, 0xC14A, 0x7F66, 0xC14B, 0x7F67, 0xC14C, 0x7F6B, + 0xC14D, 0x7F6C, 0xC14E, 0x7F6D, 0xC14F, 0x7F6F, 0xC150, 0x7F70, 0xC151, 0x7F73, 0xC152, 0x7F75, 0xC153, 0x7F76, 0xC154, 0x7F77, + 0xC155, 0x7F78, 0xC156, 0x7F7A, 0xC157, 0x7F7B, 0xC158, 0x7F7C, 0xC159, 0x7F7D, 0xC15A, 0x7F7F, 0xC15B, 0x7F80, 0xC15C, 0x7F82, + 0xC15D, 0x7F83, 0xC15E, 0x7F84, 0xC15F, 0x7F85, 0xC160, 0x7F86, 0xC161, 0x7F87, 0xC162, 0x7F88, 0xC163, 0x7F89, 0xC164, 0x7F8B, + 0xC165, 0x7F8D, 0xC166, 0x7F8F, 0xC167, 0x7F90, 0xC168, 0x7F91, 0xC169, 0x7F92, 0xC16A, 0x7F93, 0xC16B, 0x7F95, 0xC16C, 0x7F96, + 0xC16D, 0x7F97, 0xC16E, 0x7F98, 0xC16F, 0x7F99, 0xC170, 0x7F9B, 0xC171, 0x7F9C, 0xC172, 0x7FA0, 0xC173, 0x7FA2, 0xC174, 0x7FA3, + 0xC175, 0x7FA5, 0xC176, 0x7FA6, 0xC177, 0x7FA8, 0xC178, 0x7FA9, 0xC179, 0x7FAA, 0xC17A, 0x7FAB, 0xC17B, 0x7FAC, 0xC17C, 0x7FAD, + 0xC17D, 0x7FAE, 0xC17E, 0x7FB1, 0xC180, 0x7FB3, 0xC181, 0x7FB4, 0xC182, 0x7FB5, 0xC183, 0x7FB6, 0xC184, 0x7FB7, 0xC185, 0x7FBA, + 0xC186, 0x7FBB, 0xC187, 0x7FBE, 0xC188, 0x7FC0, 0xC189, 0x7FC2, 0xC18A, 0x7FC3, 0xC18B, 0x7FC4, 0xC18C, 0x7FC6, 0xC18D, 0x7FC7, + 0xC18E, 0x7FC8, 0xC18F, 0x7FC9, 0xC190, 0x7FCB, 0xC191, 0x7FCD, 0xC192, 0x7FCF, 0xC193, 0x7FD0, 0xC194, 0x7FD1, 0xC195, 0x7FD2, + 0xC196, 0x7FD3, 0xC197, 0x7FD6, 0xC198, 0x7FD7, 0xC199, 0x7FD9, 0xC19A, 0x7FDA, 0xC19B, 0x7FDB, 0xC19C, 0x7FDC, 0xC19D, 0x7FDD, + 0xC19E, 0x7FDE, 0xC19F, 0x7FE2, 0xC1A0, 0x7FE3, 0xC1A1, 0x75E2, 0xC1A2, 0x7ACB, 0xC1A3, 0x7C92, 0xC1A4, 0x6CA5, 0xC1A5, 0x96B6, + 0xC1A6, 0x529B, 0xC1A7, 0x7483, 0xC1A8, 0x54E9, 0xC1A9, 0x4FE9, 0xC1AA, 0x8054, 0xC1AB, 0x83B2, 0xC1AC, 0x8FDE, 0xC1AD, 0x9570, + 0xC1AE, 0x5EC9, 0xC1AF, 0x601C, 0xC1B0, 0x6D9F, 0xC1B1, 0x5E18, 0xC1B2, 0x655B, 0xC1B3, 0x8138, 0xC1B4, 0x94FE, 0xC1B5, 0x604B, + 0xC1B6, 0x70BC, 0xC1B7, 0x7EC3, 0xC1B8, 0x7CAE, 0xC1B9, 0x51C9, 0xC1BA, 0x6881, 0xC1BB, 0x7CB1, 0xC1BC, 0x826F, 0xC1BD, 0x4E24, + 0xC1BE, 0x8F86, 0xC1BF, 0x91CF, 0xC1C0, 0x667E, 0xC1C1, 0x4EAE, 0xC1C2, 0x8C05, 0xC1C3, 0x64A9, 0xC1C4, 0x804A, 0xC1C5, 0x50DA, + 0xC1C6, 0x7597, 0xC1C7, 0x71CE, 0xC1C8, 0x5BE5, 0xC1C9, 0x8FBD, 0xC1CA, 0x6F66, 0xC1CB, 0x4E86, 0xC1CC, 0x6482, 0xC1CD, 0x9563, + 0xC1CE, 0x5ED6, 0xC1CF, 0x6599, 0xC1D0, 0x5217, 0xC1D1, 0x88C2, 0xC1D2, 0x70C8, 0xC1D3, 0x52A3, 0xC1D4, 0x730E, 0xC1D5, 0x7433, + 0xC1D6, 0x6797, 0xC1D7, 0x78F7, 0xC1D8, 0x9716, 0xC1D9, 0x4E34, 0xC1DA, 0x90BB, 0xC1DB, 0x9CDE, 0xC1DC, 0x6DCB, 0xC1DD, 0x51DB, + 0xC1DE, 0x8D41, 0xC1DF, 0x541D, 0xC1E0, 0x62CE, 0xC1E1, 0x73B2, 0xC1E2, 0x83F1, 0xC1E3, 0x96F6, 0xC1E4, 0x9F84, 0xC1E5, 0x94C3, + 0xC1E6, 0x4F36, 0xC1E7, 0x7F9A, 0xC1E8, 0x51CC, 0xC1E9, 0x7075, 0xC1EA, 0x9675, 0xC1EB, 0x5CAD, 0xC1EC, 0x9886, 0xC1ED, 0x53E6, + 0xC1EE, 0x4EE4, 0xC1EF, 0x6E9C, 0xC1F0, 0x7409, 0xC1F1, 0x69B4, 0xC1F2, 0x786B, 0xC1F3, 0x998F, 0xC1F4, 0x7559, 0xC1F5, 0x5218, + 0xC1F6, 0x7624, 0xC1F7, 0x6D41, 0xC1F8, 0x67F3, 0xC1F9, 0x516D, 0xC1FA, 0x9F99, 0xC1FB, 0x804B, 0xC1FC, 0x5499, 0xC1FD, 0x7B3C, + 0xC1FE, 0x7ABF, 0xC240, 0x7FE4, 0xC241, 0x7FE7, 0xC242, 0x7FE8, 0xC243, 0x7FEA, 0xC244, 0x7FEB, 0xC245, 0x7FEC, 0xC246, 0x7FED, + 0xC247, 0x7FEF, 0xC248, 0x7FF2, 0xC249, 0x7FF4, 0xC24A, 0x7FF5, 0xC24B, 0x7FF6, 0xC24C, 0x7FF7, 0xC24D, 0x7FF8, 0xC24E, 0x7FF9, + 0xC24F, 0x7FFA, 0xC250, 0x7FFD, 0xC251, 0x7FFE, 0xC252, 0x7FFF, 0xC253, 0x8002, 0xC254, 0x8007, 0xC255, 0x8008, 0xC256, 0x8009, + 0xC257, 0x800A, 0xC258, 0x800E, 0xC259, 0x800F, 0xC25A, 0x8011, 0xC25B, 0x8013, 0xC25C, 0x801A, 0xC25D, 0x801B, 0xC25E, 0x801D, + 0xC25F, 0x801E, 0xC260, 0x801F, 0xC261, 0x8021, 0xC262, 0x8023, 0xC263, 0x8024, 0xC264, 0x802B, 0xC265, 0x802C, 0xC266, 0x802D, + 0xC267, 0x802E, 0xC268, 0x802F, 0xC269, 0x8030, 0xC26A, 0x8032, 0xC26B, 0x8034, 0xC26C, 0x8039, 0xC26D, 0x803A, 0xC26E, 0x803C, + 0xC26F, 0x803E, 0xC270, 0x8040, 0xC271, 0x8041, 0xC272, 0x8044, 0xC273, 0x8045, 0xC274, 0x8047, 0xC275, 0x8048, 0xC276, 0x8049, + 0xC277, 0x804E, 0xC278, 0x804F, 0xC279, 0x8050, 0xC27A, 0x8051, 0xC27B, 0x8053, 0xC27C, 0x8055, 0xC27D, 0x8056, 0xC27E, 0x8057, + 0xC280, 0x8059, 0xC281, 0x805B, 0xC282, 0x805C, 0xC283, 0x805D, 0xC284, 0x805E, 0xC285, 0x805F, 0xC286, 0x8060, 0xC287, 0x8061, + 0xC288, 0x8062, 0xC289, 0x8063, 0xC28A, 0x8064, 0xC28B, 0x8065, 0xC28C, 0x8066, 0xC28D, 0x8067, 0xC28E, 0x8068, 0xC28F, 0x806B, + 0xC290, 0x806C, 0xC291, 0x806D, 0xC292, 0x806E, 0xC293, 0x806F, 0xC294, 0x8070, 0xC295, 0x8072, 0xC296, 0x8073, 0xC297, 0x8074, + 0xC298, 0x8075, 0xC299, 0x8076, 0xC29A, 0x8077, 0xC29B, 0x8078, 0xC29C, 0x8079, 0xC29D, 0x807A, 0xC29E, 0x807B, 0xC29F, 0x807C, + 0xC2A0, 0x807D, 0xC2A1, 0x9686, 0xC2A2, 0x5784, 0xC2A3, 0x62E2, 0xC2A4, 0x9647, 0xC2A5, 0x697C, 0xC2A6, 0x5A04, 0xC2A7, 0x6402, + 0xC2A8, 0x7BD3, 0xC2A9, 0x6F0F, 0xC2AA, 0x964B, 0xC2AB, 0x82A6, 0xC2AC, 0x5362, 0xC2AD, 0x9885, 0xC2AE, 0x5E90, 0xC2AF, 0x7089, + 0xC2B0, 0x63B3, 0xC2B1, 0x5364, 0xC2B2, 0x864F, 0xC2B3, 0x9C81, 0xC2B4, 0x9E93, 0xC2B5, 0x788C, 0xC2B6, 0x9732, 0xC2B7, 0x8DEF, + 0xC2B8, 0x8D42, 0xC2B9, 0x9E7F, 0xC2BA, 0x6F5E, 0xC2BB, 0x7984, 0xC2BC, 0x5F55, 0xC2BD, 0x9646, 0xC2BE, 0x622E, 0xC2BF, 0x9A74, + 0xC2C0, 0x5415, 0xC2C1, 0x94DD, 0xC2C2, 0x4FA3, 0xC2C3, 0x65C5, 0xC2C4, 0x5C65, 0xC2C5, 0x5C61, 0xC2C6, 0x7F15, 0xC2C7, 0x8651, + 0xC2C8, 0x6C2F, 0xC2C9, 0x5F8B, 0xC2CA, 0x7387, 0xC2CB, 0x6EE4, 0xC2CC, 0x7EFF, 0xC2CD, 0x5CE6, 0xC2CE, 0x631B, 0xC2CF, 0x5B6A, + 0xC2D0, 0x6EE6, 0xC2D1, 0x5375, 0xC2D2, 0x4E71, 0xC2D3, 0x63A0, 0xC2D4, 0x7565, 0xC2D5, 0x62A1, 0xC2D6, 0x8F6E, 0xC2D7, 0x4F26, + 0xC2D8, 0x4ED1, 0xC2D9, 0x6CA6, 0xC2DA, 0x7EB6, 0xC2DB, 0x8BBA, 0xC2DC, 0x841D, 0xC2DD, 0x87BA, 0xC2DE, 0x7F57, 0xC2DF, 0x903B, + 0xC2E0, 0x9523, 0xC2E1, 0x7BA9, 0xC2E2, 0x9AA1, 0xC2E3, 0x88F8, 0xC2E4, 0x843D, 0xC2E5, 0x6D1B, 0xC2E6, 0x9A86, 0xC2E7, 0x7EDC, + 0xC2E8, 0x5988, 0xC2E9, 0x9EBB, 0xC2EA, 0x739B, 0xC2EB, 0x7801, 0xC2EC, 0x8682, 0xC2ED, 0x9A6C, 0xC2EE, 0x9A82, 0xC2EF, 0x561B, + 0xC2F0, 0x5417, 0xC2F1, 0x57CB, 0xC2F2, 0x4E70, 0xC2F3, 0x9EA6, 0xC2F4, 0x5356, 0xC2F5, 0x8FC8, 0xC2F6, 0x8109, 0xC2F7, 0x7792, + 0xC2F8, 0x9992, 0xC2F9, 0x86EE, 0xC2FA, 0x6EE1, 0xC2FB, 0x8513, 0xC2FC, 0x66FC, 0xC2FD, 0x6162, 0xC2FE, 0x6F2B, 0xC340, 0x807E, + 0xC341, 0x8081, 0xC342, 0x8082, 0xC343, 0x8085, 0xC344, 0x8088, 0xC345, 0x808A, 0xC346, 0x808D, 0xC347, 0x808E, 0xC348, 0x808F, + 0xC349, 0x8090, 0xC34A, 0x8091, 0xC34B, 0x8092, 0xC34C, 0x8094, 0xC34D, 0x8095, 0xC34E, 0x8097, 0xC34F, 0x8099, 0xC350, 0x809E, + 0xC351, 0x80A3, 0xC352, 0x80A6, 0xC353, 0x80A7, 0xC354, 0x80A8, 0xC355, 0x80AC, 0xC356, 0x80B0, 0xC357, 0x80B3, 0xC358, 0x80B5, + 0xC359, 0x80B6, 0xC35A, 0x80B8, 0xC35B, 0x80B9, 0xC35C, 0x80BB, 0xC35D, 0x80C5, 0xC35E, 0x80C7, 0xC35F, 0x80C8, 0xC360, 0x80C9, + 0xC361, 0x80CA, 0xC362, 0x80CB, 0xC363, 0x80CF, 0xC364, 0x80D0, 0xC365, 0x80D1, 0xC366, 0x80D2, 0xC367, 0x80D3, 0xC368, 0x80D4, + 0xC369, 0x80D5, 0xC36A, 0x80D8, 0xC36B, 0x80DF, 0xC36C, 0x80E0, 0xC36D, 0x80E2, 0xC36E, 0x80E3, 0xC36F, 0x80E6, 0xC370, 0x80EE, + 0xC371, 0x80F5, 0xC372, 0x80F7, 0xC373, 0x80F9, 0xC374, 0x80FB, 0xC375, 0x80FE, 0xC376, 0x80FF, 0xC377, 0x8100, 0xC378, 0x8101, + 0xC379, 0x8103, 0xC37A, 0x8104, 0xC37B, 0x8105, 0xC37C, 0x8107, 0xC37D, 0x8108, 0xC37E, 0x810B, 0xC380, 0x810C, 0xC381, 0x8115, + 0xC382, 0x8117, 0xC383, 0x8119, 0xC384, 0x811B, 0xC385, 0x811C, 0xC386, 0x811D, 0xC387, 0x811F, 0xC388, 0x8120, 0xC389, 0x8121, + 0xC38A, 0x8122, 0xC38B, 0x8123, 0xC38C, 0x8124, 0xC38D, 0x8125, 0xC38E, 0x8126, 0xC38F, 0x8127, 0xC390, 0x8128, 0xC391, 0x8129, + 0xC392, 0x812A, 0xC393, 0x812B, 0xC394, 0x812D, 0xC395, 0x812E, 0xC396, 0x8130, 0xC397, 0x8133, 0xC398, 0x8134, 0xC399, 0x8135, + 0xC39A, 0x8137, 0xC39B, 0x8139, 0xC39C, 0x813A, 0xC39D, 0x813B, 0xC39E, 0x813C, 0xC39F, 0x813D, 0xC3A0, 0x813F, 0xC3A1, 0x8C29, + 0xC3A2, 0x8292, 0xC3A3, 0x832B, 0xC3A4, 0x76F2, 0xC3A5, 0x6C13, 0xC3A6, 0x5FD9, 0xC3A7, 0x83BD, 0xC3A8, 0x732B, 0xC3A9, 0x8305, + 0xC3AA, 0x951A, 0xC3AB, 0x6BDB, 0xC3AC, 0x77DB, 0xC3AD, 0x94C6, 0xC3AE, 0x536F, 0xC3AF, 0x8302, 0xC3B0, 0x5192, 0xC3B1, 0x5E3D, + 0xC3B2, 0x8C8C, 0xC3B3, 0x8D38, 0xC3B4, 0x4E48, 0xC3B5, 0x73AB, 0xC3B6, 0x679A, 0xC3B7, 0x6885, 0xC3B8, 0x9176, 0xC3B9, 0x9709, + 0xC3BA, 0x7164, 0xC3BB, 0x6CA1, 0xC3BC, 0x7709, 0xC3BD, 0x5A92, 0xC3BE, 0x9541, 0xC3BF, 0x6BCF, 0xC3C0, 0x7F8E, 0xC3C1, 0x6627, + 0xC3C2, 0x5BD0, 0xC3C3, 0x59B9, 0xC3C4, 0x5A9A, 0xC3C5, 0x95E8, 0xC3C6, 0x95F7, 0xC3C7, 0x4EEC, 0xC3C8, 0x840C, 0xC3C9, 0x8499, + 0xC3CA, 0x6AAC, 0xC3CB, 0x76DF, 0xC3CC, 0x9530, 0xC3CD, 0x731B, 0xC3CE, 0x68A6, 0xC3CF, 0x5B5F, 0xC3D0, 0x772F, 0xC3D1, 0x919A, + 0xC3D2, 0x9761, 0xC3D3, 0x7CDC, 0xC3D4, 0x8FF7, 0xC3D5, 0x8C1C, 0xC3D6, 0x5F25, 0xC3D7, 0x7C73, 0xC3D8, 0x79D8, 0xC3D9, 0x89C5, + 0xC3DA, 0x6CCC, 0xC3DB, 0x871C, 0xC3DC, 0x5BC6, 0xC3DD, 0x5E42, 0xC3DE, 0x68C9, 0xC3DF, 0x7720, 0xC3E0, 0x7EF5, 0xC3E1, 0x5195, + 0xC3E2, 0x514D, 0xC3E3, 0x52C9, 0xC3E4, 0x5A29, 0xC3E5, 0x7F05, 0xC3E6, 0x9762, 0xC3E7, 0x82D7, 0xC3E8, 0x63CF, 0xC3E9, 0x7784, + 0xC3EA, 0x85D0, 0xC3EB, 0x79D2, 0xC3EC, 0x6E3A, 0xC3ED, 0x5E99, 0xC3EE, 0x5999, 0xC3EF, 0x8511, 0xC3F0, 0x706D, 0xC3F1, 0x6C11, + 0xC3F2, 0x62BF, 0xC3F3, 0x76BF, 0xC3F4, 0x654F, 0xC3F5, 0x60AF, 0xC3F6, 0x95FD, 0xC3F7, 0x660E, 0xC3F8, 0x879F, 0xC3F9, 0x9E23, + 0xC3FA, 0x94ED, 0xC3FB, 0x540D, 0xC3FC, 0x547D, 0xC3FD, 0x8C2C, 0xC3FE, 0x6478, 0xC440, 0x8140, 0xC441, 0x8141, 0xC442, 0x8142, + 0xC443, 0x8143, 0xC444, 0x8144, 0xC445, 0x8145, 0xC446, 0x8147, 0xC447, 0x8149, 0xC448, 0x814D, 0xC449, 0x814E, 0xC44A, 0x814F, + 0xC44B, 0x8152, 0xC44C, 0x8156, 0xC44D, 0x8157, 0xC44E, 0x8158, 0xC44F, 0x815B, 0xC450, 0x815C, 0xC451, 0x815D, 0xC452, 0x815E, + 0xC453, 0x815F, 0xC454, 0x8161, 0xC455, 0x8162, 0xC456, 0x8163, 0xC457, 0x8164, 0xC458, 0x8166, 0xC459, 0x8168, 0xC45A, 0x816A, + 0xC45B, 0x816B, 0xC45C, 0x816C, 0xC45D, 0x816F, 0xC45E, 0x8172, 0xC45F, 0x8173, 0xC460, 0x8175, 0xC461, 0x8176, 0xC462, 0x8177, + 0xC463, 0x8178, 0xC464, 0x8181, 0xC465, 0x8183, 0xC466, 0x8184, 0xC467, 0x8185, 0xC468, 0x8186, 0xC469, 0x8187, 0xC46A, 0x8189, + 0xC46B, 0x818B, 0xC46C, 0x818C, 0xC46D, 0x818D, 0xC46E, 0x818E, 0xC46F, 0x8190, 0xC470, 0x8192, 0xC471, 0x8193, 0xC472, 0x8194, + 0xC473, 0x8195, 0xC474, 0x8196, 0xC475, 0x8197, 0xC476, 0x8199, 0xC477, 0x819A, 0xC478, 0x819E, 0xC479, 0x819F, 0xC47A, 0x81A0, + 0xC47B, 0x81A1, 0xC47C, 0x81A2, 0xC47D, 0x81A4, 0xC47E, 0x81A5, 0xC480, 0x81A7, 0xC481, 0x81A9, 0xC482, 0x81AB, 0xC483, 0x81AC, + 0xC484, 0x81AD, 0xC485, 0x81AE, 0xC486, 0x81AF, 0xC487, 0x81B0, 0xC488, 0x81B1, 0xC489, 0x81B2, 0xC48A, 0x81B4, 0xC48B, 0x81B5, + 0xC48C, 0x81B6, 0xC48D, 0x81B7, 0xC48E, 0x81B8, 0xC48F, 0x81B9, 0xC490, 0x81BC, 0xC491, 0x81BD, 0xC492, 0x81BE, 0xC493, 0x81BF, + 0xC494, 0x81C4, 0xC495, 0x81C5, 0xC496, 0x81C7, 0xC497, 0x81C8, 0xC498, 0x81C9, 0xC499, 0x81CB, 0xC49A, 0x81CD, 0xC49B, 0x81CE, + 0xC49C, 0x81CF, 0xC49D, 0x81D0, 0xC49E, 0x81D1, 0xC49F, 0x81D2, 0xC4A0, 0x81D3, 0xC4A1, 0x6479, 0xC4A2, 0x8611, 0xC4A3, 0x6A21, + 0xC4A4, 0x819C, 0xC4A5, 0x78E8, 0xC4A6, 0x6469, 0xC4A7, 0x9B54, 0xC4A8, 0x62B9, 0xC4A9, 0x672B, 0xC4AA, 0x83AB, 0xC4AB, 0x58A8, + 0xC4AC, 0x9ED8, 0xC4AD, 0x6CAB, 0xC4AE, 0x6F20, 0xC4AF, 0x5BDE, 0xC4B0, 0x964C, 0xC4B1, 0x8C0B, 0xC4B2, 0x725F, 0xC4B3, 0x67D0, + 0xC4B4, 0x62C7, 0xC4B5, 0x7261, 0xC4B6, 0x4EA9, 0xC4B7, 0x59C6, 0xC4B8, 0x6BCD, 0xC4B9, 0x5893, 0xC4BA, 0x66AE, 0xC4BB, 0x5E55, + 0xC4BC, 0x52DF, 0xC4BD, 0x6155, 0xC4BE, 0x6728, 0xC4BF, 0x76EE, 0xC4C0, 0x7766, 0xC4C1, 0x7267, 0xC4C2, 0x7A46, 0xC4C3, 0x62FF, + 0xC4C4, 0x54EA, 0xC4C5, 0x5450, 0xC4C6, 0x94A0, 0xC4C7, 0x90A3, 0xC4C8, 0x5A1C, 0xC4C9, 0x7EB3, 0xC4CA, 0x6C16, 0xC4CB, 0x4E43, + 0xC4CC, 0x5976, 0xC4CD, 0x8010, 0xC4CE, 0x5948, 0xC4CF, 0x5357, 0xC4D0, 0x7537, 0xC4D1, 0x96BE, 0xC4D2, 0x56CA, 0xC4D3, 0x6320, + 0xC4D4, 0x8111, 0xC4D5, 0x607C, 0xC4D6, 0x95F9, 0xC4D7, 0x6DD6, 0xC4D8, 0x5462, 0xC4D9, 0x9981, 0xC4DA, 0x5185, 0xC4DB, 0x5AE9, + 0xC4DC, 0x80FD, 0xC4DD, 0x59AE, 0xC4DE, 0x9713, 0xC4DF, 0x502A, 0xC4E0, 0x6CE5, 0xC4E1, 0x5C3C, 0xC4E2, 0x62DF, 0xC4E3, 0x4F60, + 0xC4E4, 0x533F, 0xC4E5, 0x817B, 0xC4E6, 0x9006, 0xC4E7, 0x6EBA, 0xC4E8, 0x852B, 0xC4E9, 0x62C8, 0xC4EA, 0x5E74, 0xC4EB, 0x78BE, + 0xC4EC, 0x64B5, 0xC4ED, 0x637B, 0xC4EE, 0x5FF5, 0xC4EF, 0x5A18, 0xC4F0, 0x917F, 0xC4F1, 0x9E1F, 0xC4F2, 0x5C3F, 0xC4F3, 0x634F, + 0xC4F4, 0x8042, 0xC4F5, 0x5B7D, 0xC4F6, 0x556E, 0xC4F7, 0x954A, 0xC4F8, 0x954D, 0xC4F9, 0x6D85, 0xC4FA, 0x60A8, 0xC4FB, 0x67E0, + 0xC4FC, 0x72DE, 0xC4FD, 0x51DD, 0xC4FE, 0x5B81, 0xC540, 0x81D4, 0xC541, 0x81D5, 0xC542, 0x81D6, 0xC543, 0x81D7, 0xC544, 0x81D8, + 0xC545, 0x81D9, 0xC546, 0x81DA, 0xC547, 0x81DB, 0xC548, 0x81DC, 0xC549, 0x81DD, 0xC54A, 0x81DE, 0xC54B, 0x81DF, 0xC54C, 0x81E0, + 0xC54D, 0x81E1, 0xC54E, 0x81E2, 0xC54F, 0x81E4, 0xC550, 0x81E5, 0xC551, 0x81E6, 0xC552, 0x81E8, 0xC553, 0x81E9, 0xC554, 0x81EB, + 0xC555, 0x81EE, 0xC556, 0x81EF, 0xC557, 0x81F0, 0xC558, 0x81F1, 0xC559, 0x81F2, 0xC55A, 0x81F5, 0xC55B, 0x81F6, 0xC55C, 0x81F7, + 0xC55D, 0x81F8, 0xC55E, 0x81F9, 0xC55F, 0x81FA, 0xC560, 0x81FD, 0xC561, 0x81FF, 0xC562, 0x8203, 0xC563, 0x8207, 0xC564, 0x8208, + 0xC565, 0x8209, 0xC566, 0x820A, 0xC567, 0x820B, 0xC568, 0x820E, 0xC569, 0x820F, 0xC56A, 0x8211, 0xC56B, 0x8213, 0xC56C, 0x8215, + 0xC56D, 0x8216, 0xC56E, 0x8217, 0xC56F, 0x8218, 0xC570, 0x8219, 0xC571, 0x821A, 0xC572, 0x821D, 0xC573, 0x8220, 0xC574, 0x8224, + 0xC575, 0x8225, 0xC576, 0x8226, 0xC577, 0x8227, 0xC578, 0x8229, 0xC579, 0x822E, 0xC57A, 0x8232, 0xC57B, 0x823A, 0xC57C, 0x823C, + 0xC57D, 0x823D, 0xC57E, 0x823F, 0xC580, 0x8240, 0xC581, 0x8241, 0xC582, 0x8242, 0xC583, 0x8243, 0xC584, 0x8245, 0xC585, 0x8246, + 0xC586, 0x8248, 0xC587, 0x824A, 0xC588, 0x824C, 0xC589, 0x824D, 0xC58A, 0x824E, 0xC58B, 0x8250, 0xC58C, 0x8251, 0xC58D, 0x8252, + 0xC58E, 0x8253, 0xC58F, 0x8254, 0xC590, 0x8255, 0xC591, 0x8256, 0xC592, 0x8257, 0xC593, 0x8259, 0xC594, 0x825B, 0xC595, 0x825C, + 0xC596, 0x825D, 0xC597, 0x825E, 0xC598, 0x8260, 0xC599, 0x8261, 0xC59A, 0x8262, 0xC59B, 0x8263, 0xC59C, 0x8264, 0xC59D, 0x8265, + 0xC59E, 0x8266, 0xC59F, 0x8267, 0xC5A0, 0x8269, 0xC5A1, 0x62E7, 0xC5A2, 0x6CDE, 0xC5A3, 0x725B, 0xC5A4, 0x626D, 0xC5A5, 0x94AE, + 0xC5A6, 0x7EBD, 0xC5A7, 0x8113, 0xC5A8, 0x6D53, 0xC5A9, 0x519C, 0xC5AA, 0x5F04, 0xC5AB, 0x5974, 0xC5AC, 0x52AA, 0xC5AD, 0x6012, + 0xC5AE, 0x5973, 0xC5AF, 0x6696, 0xC5B0, 0x8650, 0xC5B1, 0x759F, 0xC5B2, 0x632A, 0xC5B3, 0x61E6, 0xC5B4, 0x7CEF, 0xC5B5, 0x8BFA, + 0xC5B6, 0x54E6, 0xC5B7, 0x6B27, 0xC5B8, 0x9E25, 0xC5B9, 0x6BB4, 0xC5BA, 0x85D5, 0xC5BB, 0x5455, 0xC5BC, 0x5076, 0xC5BD, 0x6CA4, + 0xC5BE, 0x556A, 0xC5BF, 0x8DB4, 0xC5C0, 0x722C, 0xC5C1, 0x5E15, 0xC5C2, 0x6015, 0xC5C3, 0x7436, 0xC5C4, 0x62CD, 0xC5C5, 0x6392, + 0xC5C6, 0x724C, 0xC5C7, 0x5F98, 0xC5C8, 0x6E43, 0xC5C9, 0x6D3E, 0xC5CA, 0x6500, 0xC5CB, 0x6F58, 0xC5CC, 0x76D8, 0xC5CD, 0x78D0, + 0xC5CE, 0x76FC, 0xC5CF, 0x7554, 0xC5D0, 0x5224, 0xC5D1, 0x53DB, 0xC5D2, 0x4E53, 0xC5D3, 0x5E9E, 0xC5D4, 0x65C1, 0xC5D5, 0x802A, + 0xC5D6, 0x80D6, 0xC5D7, 0x629B, 0xC5D8, 0x5486, 0xC5D9, 0x5228, 0xC5DA, 0x70AE, 0xC5DB, 0x888D, 0xC5DC, 0x8DD1, 0xC5DD, 0x6CE1, + 0xC5DE, 0x5478, 0xC5DF, 0x80DA, 0xC5E0, 0x57F9, 0xC5E1, 0x88F4, 0xC5E2, 0x8D54, 0xC5E3, 0x966A, 0xC5E4, 0x914D, 0xC5E5, 0x4F69, + 0xC5E6, 0x6C9B, 0xC5E7, 0x55B7, 0xC5E8, 0x76C6, 0xC5E9, 0x7830, 0xC5EA, 0x62A8, 0xC5EB, 0x70F9, 0xC5EC, 0x6F8E, 0xC5ED, 0x5F6D, + 0xC5EE, 0x84EC, 0xC5EF, 0x68DA, 0xC5F0, 0x787C, 0xC5F1, 0x7BF7, 0xC5F2, 0x81A8, 0xC5F3, 0x670B, 0xC5F4, 0x9E4F, 0xC5F5, 0x6367, + 0xC5F6, 0x78B0, 0xC5F7, 0x576F, 0xC5F8, 0x7812, 0xC5F9, 0x9739, 0xC5FA, 0x6279, 0xC5FB, 0x62AB, 0xC5FC, 0x5288, 0xC5FD, 0x7435, + 0xC5FE, 0x6BD7, 0xC640, 0x826A, 0xC641, 0x826B, 0xC642, 0x826C, 0xC643, 0x826D, 0xC644, 0x8271, 0xC645, 0x8275, 0xC646, 0x8276, + 0xC647, 0x8277, 0xC648, 0x8278, 0xC649, 0x827B, 0xC64A, 0x827C, 0xC64B, 0x8280, 0xC64C, 0x8281, 0xC64D, 0x8283, 0xC64E, 0x8285, + 0xC64F, 0x8286, 0xC650, 0x8287, 0xC651, 0x8289, 0xC652, 0x828C, 0xC653, 0x8290, 0xC654, 0x8293, 0xC655, 0x8294, 0xC656, 0x8295, + 0xC657, 0x8296, 0xC658, 0x829A, 0xC659, 0x829B, 0xC65A, 0x829E, 0xC65B, 0x82A0, 0xC65C, 0x82A2, 0xC65D, 0x82A3, 0xC65E, 0x82A7, + 0xC65F, 0x82B2, 0xC660, 0x82B5, 0xC661, 0x82B6, 0xC662, 0x82BA, 0xC663, 0x82BB, 0xC664, 0x82BC, 0xC665, 0x82BF, 0xC666, 0x82C0, + 0xC667, 0x82C2, 0xC668, 0x82C3, 0xC669, 0x82C5, 0xC66A, 0x82C6, 0xC66B, 0x82C9, 0xC66C, 0x82D0, 0xC66D, 0x82D6, 0xC66E, 0x82D9, + 0xC66F, 0x82DA, 0xC670, 0x82DD, 0xC671, 0x82E2, 0xC672, 0x82E7, 0xC673, 0x82E8, 0xC674, 0x82E9, 0xC675, 0x82EA, 0xC676, 0x82EC, + 0xC677, 0x82ED, 0xC678, 0x82EE, 0xC679, 0x82F0, 0xC67A, 0x82F2, 0xC67B, 0x82F3, 0xC67C, 0x82F5, 0xC67D, 0x82F6, 0xC67E, 0x82F8, + 0xC680, 0x82FA, 0xC681, 0x82FC, 0xC682, 0x82FD, 0xC683, 0x82FE, 0xC684, 0x82FF, 0xC685, 0x8300, 0xC686, 0x830A, 0xC687, 0x830B, + 0xC688, 0x830D, 0xC689, 0x8310, 0xC68A, 0x8312, 0xC68B, 0x8313, 0xC68C, 0x8316, 0xC68D, 0x8318, 0xC68E, 0x8319, 0xC68F, 0x831D, + 0xC690, 0x831E, 0xC691, 0x831F, 0xC692, 0x8320, 0xC693, 0x8321, 0xC694, 0x8322, 0xC695, 0x8323, 0xC696, 0x8324, 0xC697, 0x8325, + 0xC698, 0x8326, 0xC699, 0x8329, 0xC69A, 0x832A, 0xC69B, 0x832E, 0xC69C, 0x8330, 0xC69D, 0x8332, 0xC69E, 0x8337, 0xC69F, 0x833B, + 0xC6A0, 0x833D, 0xC6A1, 0x5564, 0xC6A2, 0x813E, 0xC6A3, 0x75B2, 0xC6A4, 0x76AE, 0xC6A5, 0x5339, 0xC6A6, 0x75DE, 0xC6A7, 0x50FB, + 0xC6A8, 0x5C41, 0xC6A9, 0x8B6C, 0xC6AA, 0x7BC7, 0xC6AB, 0x504F, 0xC6AC, 0x7247, 0xC6AD, 0x9A97, 0xC6AE, 0x98D8, 0xC6AF, 0x6F02, + 0xC6B0, 0x74E2, 0xC6B1, 0x7968, 0xC6B2, 0x6487, 0xC6B3, 0x77A5, 0xC6B4, 0x62FC, 0xC6B5, 0x9891, 0xC6B6, 0x8D2B, 0xC6B7, 0x54C1, + 0xC6B8, 0x8058, 0xC6B9, 0x4E52, 0xC6BA, 0x576A, 0xC6BB, 0x82F9, 0xC6BC, 0x840D, 0xC6BD, 0x5E73, 0xC6BE, 0x51ED, 0xC6BF, 0x74F6, + 0xC6C0, 0x8BC4, 0xC6C1, 0x5C4F, 0xC6C2, 0x5761, 0xC6C3, 0x6CFC, 0xC6C4, 0x9887, 0xC6C5, 0x5A46, 0xC6C6, 0x7834, 0xC6C7, 0x9B44, + 0xC6C8, 0x8FEB, 0xC6C9, 0x7C95, 0xC6CA, 0x5256, 0xC6CB, 0x6251, 0xC6CC, 0x94FA, 0xC6CD, 0x4EC6, 0xC6CE, 0x8386, 0xC6CF, 0x8461, + 0xC6D0, 0x83E9, 0xC6D1, 0x84B2, 0xC6D2, 0x57D4, 0xC6D3, 0x6734, 0xC6D4, 0x5703, 0xC6D5, 0x666E, 0xC6D6, 0x6D66, 0xC6D7, 0x8C31, + 0xC6D8, 0x66DD, 0xC6D9, 0x7011, 0xC6DA, 0x671F, 0xC6DB, 0x6B3A, 0xC6DC, 0x6816, 0xC6DD, 0x621A, 0xC6DE, 0x59BB, 0xC6DF, 0x4E03, + 0xC6E0, 0x51C4, 0xC6E1, 0x6F06, 0xC6E2, 0x67D2, 0xC6E3, 0x6C8F, 0xC6E4, 0x5176, 0xC6E5, 0x68CB, 0xC6E6, 0x5947, 0xC6E7, 0x6B67, + 0xC6E8, 0x7566, 0xC6E9, 0x5D0E, 0xC6EA, 0x8110, 0xC6EB, 0x9F50, 0xC6EC, 0x65D7, 0xC6ED, 0x7948, 0xC6EE, 0x7941, 0xC6EF, 0x9A91, + 0xC6F0, 0x8D77, 0xC6F1, 0x5C82, 0xC6F2, 0x4E5E, 0xC6F3, 0x4F01, 0xC6F4, 0x542F, 0xC6F5, 0x5951, 0xC6F6, 0x780C, 0xC6F7, 0x5668, + 0xC6F8, 0x6C14, 0xC6F9, 0x8FC4, 0xC6FA, 0x5F03, 0xC6FB, 0x6C7D, 0xC6FC, 0x6CE3, 0xC6FD, 0x8BAB, 0xC6FE, 0x6390, 0xC740, 0x833E, + 0xC741, 0x833F, 0xC742, 0x8341, 0xC743, 0x8342, 0xC744, 0x8344, 0xC745, 0x8345, 0xC746, 0x8348, 0xC747, 0x834A, 0xC748, 0x834B, + 0xC749, 0x834C, 0xC74A, 0x834D, 0xC74B, 0x834E, 0xC74C, 0x8353, 0xC74D, 0x8355, 0xC74E, 0x8356, 0xC74F, 0x8357, 0xC750, 0x8358, + 0xC751, 0x8359, 0xC752, 0x835D, 0xC753, 0x8362, 0xC754, 0x8370, 0xC755, 0x8371, 0xC756, 0x8372, 0xC757, 0x8373, 0xC758, 0x8374, + 0xC759, 0x8375, 0xC75A, 0x8376, 0xC75B, 0x8379, 0xC75C, 0x837A, 0xC75D, 0x837E, 0xC75E, 0x837F, 0xC75F, 0x8380, 0xC760, 0x8381, + 0xC761, 0x8382, 0xC762, 0x8383, 0xC763, 0x8384, 0xC764, 0x8387, 0xC765, 0x8388, 0xC766, 0x838A, 0xC767, 0x838B, 0xC768, 0x838C, + 0xC769, 0x838D, 0xC76A, 0x838F, 0xC76B, 0x8390, 0xC76C, 0x8391, 0xC76D, 0x8394, 0xC76E, 0x8395, 0xC76F, 0x8396, 0xC770, 0x8397, + 0xC771, 0x8399, 0xC772, 0x839A, 0xC773, 0x839D, 0xC774, 0x839F, 0xC775, 0x83A1, 0xC776, 0x83A2, 0xC777, 0x83A3, 0xC778, 0x83A4, + 0xC779, 0x83A5, 0xC77A, 0x83A6, 0xC77B, 0x83A7, 0xC77C, 0x83AC, 0xC77D, 0x83AD, 0xC77E, 0x83AE, 0xC780, 0x83AF, 0xC781, 0x83B5, + 0xC782, 0x83BB, 0xC783, 0x83BE, 0xC784, 0x83BF, 0xC785, 0x83C2, 0xC786, 0x83C3, 0xC787, 0x83C4, 0xC788, 0x83C6, 0xC789, 0x83C8, + 0xC78A, 0x83C9, 0xC78B, 0x83CB, 0xC78C, 0x83CD, 0xC78D, 0x83CE, 0xC78E, 0x83D0, 0xC78F, 0x83D1, 0xC790, 0x83D2, 0xC791, 0x83D3, + 0xC792, 0x83D5, 0xC793, 0x83D7, 0xC794, 0x83D9, 0xC795, 0x83DA, 0xC796, 0x83DB, 0xC797, 0x83DE, 0xC798, 0x83E2, 0xC799, 0x83E3, + 0xC79A, 0x83E4, 0xC79B, 0x83E6, 0xC79C, 0x83E7, 0xC79D, 0x83E8, 0xC79E, 0x83EB, 0xC79F, 0x83EC, 0xC7A0, 0x83ED, 0xC7A1, 0x6070, + 0xC7A2, 0x6D3D, 0xC7A3, 0x7275, 0xC7A4, 0x6266, 0xC7A5, 0x948E, 0xC7A6, 0x94C5, 0xC7A7, 0x5343, 0xC7A8, 0x8FC1, 0xC7A9, 0x7B7E, + 0xC7AA, 0x4EDF, 0xC7AB, 0x8C26, 0xC7AC, 0x4E7E, 0xC7AD, 0x9ED4, 0xC7AE, 0x94B1, 0xC7AF, 0x94B3, 0xC7B0, 0x524D, 0xC7B1, 0x6F5C, + 0xC7B2, 0x9063, 0xC7B3, 0x6D45, 0xC7B4, 0x8C34, 0xC7B5, 0x5811, 0xC7B6, 0x5D4C, 0xC7B7, 0x6B20, 0xC7B8, 0x6B49, 0xC7B9, 0x67AA, + 0xC7BA, 0x545B, 0xC7BB, 0x8154, 0xC7BC, 0x7F8C, 0xC7BD, 0x5899, 0xC7BE, 0x8537, 0xC7BF, 0x5F3A, 0xC7C0, 0x62A2, 0xC7C1, 0x6A47, + 0xC7C2, 0x9539, 0xC7C3, 0x6572, 0xC7C4, 0x6084, 0xC7C5, 0x6865, 0xC7C6, 0x77A7, 0xC7C7, 0x4E54, 0xC7C8, 0x4FA8, 0xC7C9, 0x5DE7, + 0xC7CA, 0x9798, 0xC7CB, 0x64AC, 0xC7CC, 0x7FD8, 0xC7CD, 0x5CED, 0xC7CE, 0x4FCF, 0xC7CF, 0x7A8D, 0xC7D0, 0x5207, 0xC7D1, 0x8304, + 0xC7D2, 0x4E14, 0xC7D3, 0x602F, 0xC7D4, 0x7A83, 0xC7D5, 0x94A6, 0xC7D6, 0x4FB5, 0xC7D7, 0x4EB2, 0xC7D8, 0x79E6, 0xC7D9, 0x7434, + 0xC7DA, 0x52E4, 0xC7DB, 0x82B9, 0xC7DC, 0x64D2, 0xC7DD, 0x79BD, 0xC7DE, 0x5BDD, 0xC7DF, 0x6C81, 0xC7E0, 0x9752, 0xC7E1, 0x8F7B, + 0xC7E2, 0x6C22, 0xC7E3, 0x503E, 0xC7E4, 0x537F, 0xC7E5, 0x6E05, 0xC7E6, 0x64CE, 0xC7E7, 0x6674, 0xC7E8, 0x6C30, 0xC7E9, 0x60C5, + 0xC7EA, 0x9877, 0xC7EB, 0x8BF7, 0xC7EC, 0x5E86, 0xC7ED, 0x743C, 0xC7EE, 0x7A77, 0xC7EF, 0x79CB, 0xC7F0, 0x4E18, 0xC7F1, 0x90B1, + 0xC7F2, 0x7403, 0xC7F3, 0x6C42, 0xC7F4, 0x56DA, 0xC7F5, 0x914B, 0xC7F6, 0x6CC5, 0xC7F7, 0x8D8B, 0xC7F8, 0x533A, 0xC7F9, 0x86C6, + 0xC7FA, 0x66F2, 0xC7FB, 0x8EAF, 0xC7FC, 0x5C48, 0xC7FD, 0x9A71, 0xC7FE, 0x6E20, 0xC840, 0x83EE, 0xC841, 0x83EF, 0xC842, 0x83F3, + 0xC843, 0x83F4, 0xC844, 0x83F5, 0xC845, 0x83F6, 0xC846, 0x83F7, 0xC847, 0x83FA, 0xC848, 0x83FB, 0xC849, 0x83FC, 0xC84A, 0x83FE, + 0xC84B, 0x83FF, 0xC84C, 0x8400, 0xC84D, 0x8402, 0xC84E, 0x8405, 0xC84F, 0x8407, 0xC850, 0x8408, 0xC851, 0x8409, 0xC852, 0x840A, + 0xC853, 0x8410, 0xC854, 0x8412, 0xC855, 0x8413, 0xC856, 0x8414, 0xC857, 0x8415, 0xC858, 0x8416, 0xC859, 0x8417, 0xC85A, 0x8419, + 0xC85B, 0x841A, 0xC85C, 0x841B, 0xC85D, 0x841E, 0xC85E, 0x841F, 0xC85F, 0x8420, 0xC860, 0x8421, 0xC861, 0x8422, 0xC862, 0x8423, + 0xC863, 0x8429, 0xC864, 0x842A, 0xC865, 0x842B, 0xC866, 0x842C, 0xC867, 0x842D, 0xC868, 0x842E, 0xC869, 0x842F, 0xC86A, 0x8430, + 0xC86B, 0x8432, 0xC86C, 0x8433, 0xC86D, 0x8434, 0xC86E, 0x8435, 0xC86F, 0x8436, 0xC870, 0x8437, 0xC871, 0x8439, 0xC872, 0x843A, + 0xC873, 0x843B, 0xC874, 0x843E, 0xC875, 0x843F, 0xC876, 0x8440, 0xC877, 0x8441, 0xC878, 0x8442, 0xC879, 0x8443, 0xC87A, 0x8444, + 0xC87B, 0x8445, 0xC87C, 0x8447, 0xC87D, 0x8448, 0xC87E, 0x8449, 0xC880, 0x844A, 0xC881, 0x844B, 0xC882, 0x844C, 0xC883, 0x844D, + 0xC884, 0x844E, 0xC885, 0x844F, 0xC886, 0x8450, 0xC887, 0x8452, 0xC888, 0x8453, 0xC889, 0x8454, 0xC88A, 0x8455, 0xC88B, 0x8456, + 0xC88C, 0x8458, 0xC88D, 0x845D, 0xC88E, 0x845E, 0xC88F, 0x845F, 0xC890, 0x8460, 0xC891, 0x8462, 0xC892, 0x8464, 0xC893, 0x8465, + 0xC894, 0x8466, 0xC895, 0x8467, 0xC896, 0x8468, 0xC897, 0x846A, 0xC898, 0x846E, 0xC899, 0x846F, 0xC89A, 0x8470, 0xC89B, 0x8472, + 0xC89C, 0x8474, 0xC89D, 0x8477, 0xC89E, 0x8479, 0xC89F, 0x847B, 0xC8A0, 0x847C, 0xC8A1, 0x53D6, 0xC8A2, 0x5A36, 0xC8A3, 0x9F8B, + 0xC8A4, 0x8DA3, 0xC8A5, 0x53BB, 0xC8A6, 0x5708, 0xC8A7, 0x98A7, 0xC8A8, 0x6743, 0xC8A9, 0x919B, 0xC8AA, 0x6CC9, 0xC8AB, 0x5168, + 0xC8AC, 0x75CA, 0xC8AD, 0x62F3, 0xC8AE, 0x72AC, 0xC8AF, 0x5238, 0xC8B0, 0x529D, 0xC8B1, 0x7F3A, 0xC8B2, 0x7094, 0xC8B3, 0x7638, + 0xC8B4, 0x5374, 0xC8B5, 0x9E4A, 0xC8B6, 0x69B7, 0xC8B7, 0x786E, 0xC8B8, 0x96C0, 0xC8B9, 0x88D9, 0xC8BA, 0x7FA4, 0xC8BB, 0x7136, + 0xC8BC, 0x71C3, 0xC8BD, 0x5189, 0xC8BE, 0x67D3, 0xC8BF, 0x74E4, 0xC8C0, 0x58E4, 0xC8C1, 0x6518, 0xC8C2, 0x56B7, 0xC8C3, 0x8BA9, + 0xC8C4, 0x9976, 0xC8C5, 0x6270, 0xC8C6, 0x7ED5, 0xC8C7, 0x60F9, 0xC8C8, 0x70ED, 0xC8C9, 0x58EC, 0xC8CA, 0x4EC1, 0xC8CB, 0x4EBA, + 0xC8CC, 0x5FCD, 0xC8CD, 0x97E7, 0xC8CE, 0x4EFB, 0xC8CF, 0x8BA4, 0xC8D0, 0x5203, 0xC8D1, 0x598A, 0xC8D2, 0x7EAB, 0xC8D3, 0x6254, + 0xC8D4, 0x4ECD, 0xC8D5, 0x65E5, 0xC8D6, 0x620E, 0xC8D7, 0x8338, 0xC8D8, 0x84C9, 0xC8D9, 0x8363, 0xC8DA, 0x878D, 0xC8DB, 0x7194, + 0xC8DC, 0x6EB6, 0xC8DD, 0x5BB9, 0xC8DE, 0x7ED2, 0xC8DF, 0x5197, 0xC8E0, 0x63C9, 0xC8E1, 0x67D4, 0xC8E2, 0x8089, 0xC8E3, 0x8339, + 0xC8E4, 0x8815, 0xC8E5, 0x5112, 0xC8E6, 0x5B7A, 0xC8E7, 0x5982, 0xC8E8, 0x8FB1, 0xC8E9, 0x4E73, 0xC8EA, 0x6C5D, 0xC8EB, 0x5165, + 0xC8EC, 0x8925, 0xC8ED, 0x8F6F, 0xC8EE, 0x962E, 0xC8EF, 0x854A, 0xC8F0, 0x745E, 0xC8F1, 0x9510, 0xC8F2, 0x95F0, 0xC8F3, 0x6DA6, + 0xC8F4, 0x82E5, 0xC8F5, 0x5F31, 0xC8F6, 0x6492, 0xC8F7, 0x6D12, 0xC8F8, 0x8428, 0xC8F9, 0x816E, 0xC8FA, 0x9CC3, 0xC8FB, 0x585E, + 0xC8FC, 0x8D5B, 0xC8FD, 0x4E09, 0xC8FE, 0x53C1, 0xC940, 0x847D, 0xC941, 0x847E, 0xC942, 0x847F, 0xC943, 0x8480, 0xC944, 0x8481, + 0xC945, 0x8483, 0xC946, 0x8484, 0xC947, 0x8485, 0xC948, 0x8486, 0xC949, 0x848A, 0xC94A, 0x848D, 0xC94B, 0x848F, 0xC94C, 0x8490, + 0xC94D, 0x8491, 0xC94E, 0x8492, 0xC94F, 0x8493, 0xC950, 0x8494, 0xC951, 0x8495, 0xC952, 0x8496, 0xC953, 0x8498, 0xC954, 0x849A, + 0xC955, 0x849B, 0xC956, 0x849D, 0xC957, 0x849E, 0xC958, 0x849F, 0xC959, 0x84A0, 0xC95A, 0x84A2, 0xC95B, 0x84A3, 0xC95C, 0x84A4, + 0xC95D, 0x84A5, 0xC95E, 0x84A6, 0xC95F, 0x84A7, 0xC960, 0x84A8, 0xC961, 0x84A9, 0xC962, 0x84AA, 0xC963, 0x84AB, 0xC964, 0x84AC, + 0xC965, 0x84AD, 0xC966, 0x84AE, 0xC967, 0x84B0, 0xC968, 0x84B1, 0xC969, 0x84B3, 0xC96A, 0x84B5, 0xC96B, 0x84B6, 0xC96C, 0x84B7, + 0xC96D, 0x84BB, 0xC96E, 0x84BC, 0xC96F, 0x84BE, 0xC970, 0x84C0, 0xC971, 0x84C2, 0xC972, 0x84C3, 0xC973, 0x84C5, 0xC974, 0x84C6, + 0xC975, 0x84C7, 0xC976, 0x84C8, 0xC977, 0x84CB, 0xC978, 0x84CC, 0xC979, 0x84CE, 0xC97A, 0x84CF, 0xC97B, 0x84D2, 0xC97C, 0x84D4, + 0xC97D, 0x84D5, 0xC97E, 0x84D7, 0xC980, 0x84D8, 0xC981, 0x84D9, 0xC982, 0x84DA, 0xC983, 0x84DB, 0xC984, 0x84DC, 0xC985, 0x84DE, + 0xC986, 0x84E1, 0xC987, 0x84E2, 0xC988, 0x84E4, 0xC989, 0x84E7, 0xC98A, 0x84E8, 0xC98B, 0x84E9, 0xC98C, 0x84EA, 0xC98D, 0x84EB, + 0xC98E, 0x84ED, 0xC98F, 0x84EE, 0xC990, 0x84EF, 0xC991, 0x84F1, 0xC992, 0x84F2, 0xC993, 0x84F3, 0xC994, 0x84F4, 0xC995, 0x84F5, + 0xC996, 0x84F6, 0xC997, 0x84F7, 0xC998, 0x84F8, 0xC999, 0x84F9, 0xC99A, 0x84FA, 0xC99B, 0x84FB, 0xC99C, 0x84FD, 0xC99D, 0x84FE, + 0xC99E, 0x8500, 0xC99F, 0x8501, 0xC9A0, 0x8502, 0xC9A1, 0x4F1E, 0xC9A2, 0x6563, 0xC9A3, 0x6851, 0xC9A4, 0x55D3, 0xC9A5, 0x4E27, + 0xC9A6, 0x6414, 0xC9A7, 0x9A9A, 0xC9A8, 0x626B, 0xC9A9, 0x5AC2, 0xC9AA, 0x745F, 0xC9AB, 0x8272, 0xC9AC, 0x6DA9, 0xC9AD, 0x68EE, + 0xC9AE, 0x50E7, 0xC9AF, 0x838E, 0xC9B0, 0x7802, 0xC9B1, 0x6740, 0xC9B2, 0x5239, 0xC9B3, 0x6C99, 0xC9B4, 0x7EB1, 0xC9B5, 0x50BB, + 0xC9B6, 0x5565, 0xC9B7, 0x715E, 0xC9B8, 0x7B5B, 0xC9B9, 0x6652, 0xC9BA, 0x73CA, 0xC9BB, 0x82EB, 0xC9BC, 0x6749, 0xC9BD, 0x5C71, + 0xC9BE, 0x5220, 0xC9BF, 0x717D, 0xC9C0, 0x886B, 0xC9C1, 0x95EA, 0xC9C2, 0x9655, 0xC9C3, 0x64C5, 0xC9C4, 0x8D61, 0xC9C5, 0x81B3, + 0xC9C6, 0x5584, 0xC9C7, 0x6C55, 0xC9C8, 0x6247, 0xC9C9, 0x7F2E, 0xC9CA, 0x5892, 0xC9CB, 0x4F24, 0xC9CC, 0x5546, 0xC9CD, 0x8D4F, + 0xC9CE, 0x664C, 0xC9CF, 0x4E0A, 0xC9D0, 0x5C1A, 0xC9D1, 0x88F3, 0xC9D2, 0x68A2, 0xC9D3, 0x634E, 0xC9D4, 0x7A0D, 0xC9D5, 0x70E7, + 0xC9D6, 0x828D, 0xC9D7, 0x52FA, 0xC9D8, 0x97F6, 0xC9D9, 0x5C11, 0xC9DA, 0x54E8, 0xC9DB, 0x90B5, 0xC9DC, 0x7ECD, 0xC9DD, 0x5962, + 0xC9DE, 0x8D4A, 0xC9DF, 0x86C7, 0xC9E0, 0x820C, 0xC9E1, 0x820D, 0xC9E2, 0x8D66, 0xC9E3, 0x6444, 0xC9E4, 0x5C04, 0xC9E5, 0x6151, + 0xC9E6, 0x6D89, 0xC9E7, 0x793E, 0xC9E8, 0x8BBE, 0xC9E9, 0x7837, 0xC9EA, 0x7533, 0xC9EB, 0x547B, 0xC9EC, 0x4F38, 0xC9ED, 0x8EAB, + 0xC9EE, 0x6DF1, 0xC9EF, 0x5A20, 0xC9F0, 0x7EC5, 0xC9F1, 0x795E, 0xC9F2, 0x6C88, 0xC9F3, 0x5BA1, 0xC9F4, 0x5A76, 0xC9F5, 0x751A, + 0xC9F6, 0x80BE, 0xC9F7, 0x614E, 0xC9F8, 0x6E17, 0xC9F9, 0x58F0, 0xC9FA, 0x751F, 0xC9FB, 0x7525, 0xC9FC, 0x7272, 0xC9FD, 0x5347, + 0xC9FE, 0x7EF3, 0xCA40, 0x8503, 0xCA41, 0x8504, 0xCA42, 0x8505, 0xCA43, 0x8506, 0xCA44, 0x8507, 0xCA45, 0x8508, 0xCA46, 0x8509, + 0xCA47, 0x850A, 0xCA48, 0x850B, 0xCA49, 0x850D, 0xCA4A, 0x850E, 0xCA4B, 0x850F, 0xCA4C, 0x8510, 0xCA4D, 0x8512, 0xCA4E, 0x8514, + 0xCA4F, 0x8515, 0xCA50, 0x8516, 0xCA51, 0x8518, 0xCA52, 0x8519, 0xCA53, 0x851B, 0xCA54, 0x851C, 0xCA55, 0x851D, 0xCA56, 0x851E, + 0xCA57, 0x8520, 0xCA58, 0x8522, 0xCA59, 0x8523, 0xCA5A, 0x8524, 0xCA5B, 0x8525, 0xCA5C, 0x8526, 0xCA5D, 0x8527, 0xCA5E, 0x8528, + 0xCA5F, 0x8529, 0xCA60, 0x852A, 0xCA61, 0x852D, 0xCA62, 0x852E, 0xCA63, 0x852F, 0xCA64, 0x8530, 0xCA65, 0x8531, 0xCA66, 0x8532, + 0xCA67, 0x8533, 0xCA68, 0x8534, 0xCA69, 0x8535, 0xCA6A, 0x8536, 0xCA6B, 0x853E, 0xCA6C, 0x853F, 0xCA6D, 0x8540, 0xCA6E, 0x8541, + 0xCA6F, 0x8542, 0xCA70, 0x8544, 0xCA71, 0x8545, 0xCA72, 0x8546, 0xCA73, 0x8547, 0xCA74, 0x854B, 0xCA75, 0x854C, 0xCA76, 0x854D, + 0xCA77, 0x854E, 0xCA78, 0x854F, 0xCA79, 0x8550, 0xCA7A, 0x8551, 0xCA7B, 0x8552, 0xCA7C, 0x8553, 0xCA7D, 0x8554, 0xCA7E, 0x8555, + 0xCA80, 0x8557, 0xCA81, 0x8558, 0xCA82, 0x855A, 0xCA83, 0x855B, 0xCA84, 0x855C, 0xCA85, 0x855D, 0xCA86, 0x855F, 0xCA87, 0x8560, + 0xCA88, 0x8561, 0xCA89, 0x8562, 0xCA8A, 0x8563, 0xCA8B, 0x8565, 0xCA8C, 0x8566, 0xCA8D, 0x8567, 0xCA8E, 0x8569, 0xCA8F, 0x856A, + 0xCA90, 0x856B, 0xCA91, 0x856C, 0xCA92, 0x856D, 0xCA93, 0x856E, 0xCA94, 0x856F, 0xCA95, 0x8570, 0xCA96, 0x8571, 0xCA97, 0x8573, + 0xCA98, 0x8575, 0xCA99, 0x8576, 0xCA9A, 0x8577, 0xCA9B, 0x8578, 0xCA9C, 0x857C, 0xCA9D, 0x857D, 0xCA9E, 0x857F, 0xCA9F, 0x8580, + 0xCAA0, 0x8581, 0xCAA1, 0x7701, 0xCAA2, 0x76DB, 0xCAA3, 0x5269, 0xCAA4, 0x80DC, 0xCAA5, 0x5723, 0xCAA6, 0x5E08, 0xCAA7, 0x5931, + 0xCAA8, 0x72EE, 0xCAA9, 0x65BD, 0xCAAA, 0x6E7F, 0xCAAB, 0x8BD7, 0xCAAC, 0x5C38, 0xCAAD, 0x8671, 0xCAAE, 0x5341, 0xCAAF, 0x77F3, + 0xCAB0, 0x62FE, 0xCAB1, 0x65F6, 0xCAB2, 0x4EC0, 0xCAB3, 0x98DF, 0xCAB4, 0x8680, 0xCAB5, 0x5B9E, 0xCAB6, 0x8BC6, 0xCAB7, 0x53F2, + 0xCAB8, 0x77E2, 0xCAB9, 0x4F7F, 0xCABA, 0x5C4E, 0xCABB, 0x9A76, 0xCABC, 0x59CB, 0xCABD, 0x5F0F, 0xCABE, 0x793A, 0xCABF, 0x58EB, + 0xCAC0, 0x4E16, 0xCAC1, 0x67FF, 0xCAC2, 0x4E8B, 0xCAC3, 0x62ED, 0xCAC4, 0x8A93, 0xCAC5, 0x901D, 0xCAC6, 0x52BF, 0xCAC7, 0x662F, + 0xCAC8, 0x55DC, 0xCAC9, 0x566C, 0xCACA, 0x9002, 0xCACB, 0x4ED5, 0xCACC, 0x4F8D, 0xCACD, 0x91CA, 0xCACE, 0x9970, 0xCACF, 0x6C0F, + 0xCAD0, 0x5E02, 0xCAD1, 0x6043, 0xCAD2, 0x5BA4, 0xCAD3, 0x89C6, 0xCAD4, 0x8BD5, 0xCAD5, 0x6536, 0xCAD6, 0x624B, 0xCAD7, 0x9996, + 0xCAD8, 0x5B88, 0xCAD9, 0x5BFF, 0xCADA, 0x6388, 0xCADB, 0x552E, 0xCADC, 0x53D7, 0xCADD, 0x7626, 0xCADE, 0x517D, 0xCADF, 0x852C, + 0xCAE0, 0x67A2, 0xCAE1, 0x68B3, 0xCAE2, 0x6B8A, 0xCAE3, 0x6292, 0xCAE4, 0x8F93, 0xCAE5, 0x53D4, 0xCAE6, 0x8212, 0xCAE7, 0x6DD1, + 0xCAE8, 0x758F, 0xCAE9, 0x4E66, 0xCAEA, 0x8D4E, 0xCAEB, 0x5B70, 0xCAEC, 0x719F, 0xCAED, 0x85AF, 0xCAEE, 0x6691, 0xCAEF, 0x66D9, + 0xCAF0, 0x7F72, 0xCAF1, 0x8700, 0xCAF2, 0x9ECD, 0xCAF3, 0x9F20, 0xCAF4, 0x5C5E, 0xCAF5, 0x672F, 0xCAF6, 0x8FF0, 0xCAF7, 0x6811, + 0xCAF8, 0x675F, 0xCAF9, 0x620D, 0xCAFA, 0x7AD6, 0xCAFB, 0x5885, 0xCAFC, 0x5EB6, 0xCAFD, 0x6570, 0xCAFE, 0x6F31, 0xCB40, 0x8582, + 0xCB41, 0x8583, 0xCB42, 0x8586, 0xCB43, 0x8588, 0xCB44, 0x8589, 0xCB45, 0x858A, 0xCB46, 0x858B, 0xCB47, 0x858C, 0xCB48, 0x858D, + 0xCB49, 0x858E, 0xCB4A, 0x8590, 0xCB4B, 0x8591, 0xCB4C, 0x8592, 0xCB4D, 0x8593, 0xCB4E, 0x8594, 0xCB4F, 0x8595, 0xCB50, 0x8596, + 0xCB51, 0x8597, 0xCB52, 0x8598, 0xCB53, 0x8599, 0xCB54, 0x859A, 0xCB55, 0x859D, 0xCB56, 0x859E, 0xCB57, 0x859F, 0xCB58, 0x85A0, + 0xCB59, 0x85A1, 0xCB5A, 0x85A2, 0xCB5B, 0x85A3, 0xCB5C, 0x85A5, 0xCB5D, 0x85A6, 0xCB5E, 0x85A7, 0xCB5F, 0x85A9, 0xCB60, 0x85AB, + 0xCB61, 0x85AC, 0xCB62, 0x85AD, 0xCB63, 0x85B1, 0xCB64, 0x85B2, 0xCB65, 0x85B3, 0xCB66, 0x85B4, 0xCB67, 0x85B5, 0xCB68, 0x85B6, + 0xCB69, 0x85B8, 0xCB6A, 0x85BA, 0xCB6B, 0x85BB, 0xCB6C, 0x85BC, 0xCB6D, 0x85BD, 0xCB6E, 0x85BE, 0xCB6F, 0x85BF, 0xCB70, 0x85C0, + 0xCB71, 0x85C2, 0xCB72, 0x85C3, 0xCB73, 0x85C4, 0xCB74, 0x85C5, 0xCB75, 0x85C6, 0xCB76, 0x85C7, 0xCB77, 0x85C8, 0xCB78, 0x85CA, + 0xCB79, 0x85CB, 0xCB7A, 0x85CC, 0xCB7B, 0x85CD, 0xCB7C, 0x85CE, 0xCB7D, 0x85D1, 0xCB7E, 0x85D2, 0xCB80, 0x85D4, 0xCB81, 0x85D6, + 0xCB82, 0x85D7, 0xCB83, 0x85D8, 0xCB84, 0x85D9, 0xCB85, 0x85DA, 0xCB86, 0x85DB, 0xCB87, 0x85DD, 0xCB88, 0x85DE, 0xCB89, 0x85DF, + 0xCB8A, 0x85E0, 0xCB8B, 0x85E1, 0xCB8C, 0x85E2, 0xCB8D, 0x85E3, 0xCB8E, 0x85E5, 0xCB8F, 0x85E6, 0xCB90, 0x85E7, 0xCB91, 0x85E8, + 0xCB92, 0x85EA, 0xCB93, 0x85EB, 0xCB94, 0x85EC, 0xCB95, 0x85ED, 0xCB96, 0x85EE, 0xCB97, 0x85EF, 0xCB98, 0x85F0, 0xCB99, 0x85F1, + 0xCB9A, 0x85F2, 0xCB9B, 0x85F3, 0xCB9C, 0x85F4, 0xCB9D, 0x85F5, 0xCB9E, 0x85F6, 0xCB9F, 0x85F7, 0xCBA0, 0x85F8, 0xCBA1, 0x6055, + 0xCBA2, 0x5237, 0xCBA3, 0x800D, 0xCBA4, 0x6454, 0xCBA5, 0x8870, 0xCBA6, 0x7529, 0xCBA7, 0x5E05, 0xCBA8, 0x6813, 0xCBA9, 0x62F4, + 0xCBAA, 0x971C, 0xCBAB, 0x53CC, 0xCBAC, 0x723D, 0xCBAD, 0x8C01, 0xCBAE, 0x6C34, 0xCBAF, 0x7761, 0xCBB0, 0x7A0E, 0xCBB1, 0x542E, + 0xCBB2, 0x77AC, 0xCBB3, 0x987A, 0xCBB4, 0x821C, 0xCBB5, 0x8BF4, 0xCBB6, 0x7855, 0xCBB7, 0x6714, 0xCBB8, 0x70C1, 0xCBB9, 0x65AF, + 0xCBBA, 0x6495, 0xCBBB, 0x5636, 0xCBBC, 0x601D, 0xCBBD, 0x79C1, 0xCBBE, 0x53F8, 0xCBBF, 0x4E1D, 0xCBC0, 0x6B7B, 0xCBC1, 0x8086, + 0xCBC2, 0x5BFA, 0xCBC3, 0x55E3, 0xCBC4, 0x56DB, 0xCBC5, 0x4F3A, 0xCBC6, 0x4F3C, 0xCBC7, 0x9972, 0xCBC8, 0x5DF3, 0xCBC9, 0x677E, + 0xCBCA, 0x8038, 0xCBCB, 0x6002, 0xCBCC, 0x9882, 0xCBCD, 0x9001, 0xCBCE, 0x5B8B, 0xCBCF, 0x8BBC, 0xCBD0, 0x8BF5, 0xCBD1, 0x641C, + 0xCBD2, 0x8258, 0xCBD3, 0x64DE, 0xCBD4, 0x55FD, 0xCBD5, 0x82CF, 0xCBD6, 0x9165, 0xCBD7, 0x4FD7, 0xCBD8, 0x7D20, 0xCBD9, 0x901F, + 0xCBDA, 0x7C9F, 0xCBDB, 0x50F3, 0xCBDC, 0x5851, 0xCBDD, 0x6EAF, 0xCBDE, 0x5BBF, 0xCBDF, 0x8BC9, 0xCBE0, 0x8083, 0xCBE1, 0x9178, + 0xCBE2, 0x849C, 0xCBE3, 0x7B97, 0xCBE4, 0x867D, 0xCBE5, 0x968B, 0xCBE6, 0x968F, 0xCBE7, 0x7EE5, 0xCBE8, 0x9AD3, 0xCBE9, 0x788E, + 0xCBEA, 0x5C81, 0xCBEB, 0x7A57, 0xCBEC, 0x9042, 0xCBED, 0x96A7, 0xCBEE, 0x795F, 0xCBEF, 0x5B59, 0xCBF0, 0x635F, 0xCBF1, 0x7B0B, + 0xCBF2, 0x84D1, 0xCBF3, 0x68AD, 0xCBF4, 0x5506, 0xCBF5, 0x7F29, 0xCBF6, 0x7410, 0xCBF7, 0x7D22, 0xCBF8, 0x9501, 0xCBF9, 0x6240, + 0xCBFA, 0x584C, 0xCBFB, 0x4ED6, 0xCBFC, 0x5B83, 0xCBFD, 0x5979, 0xCBFE, 0x5854, 0xCC40, 0x85F9, 0xCC41, 0x85FA, 0xCC42, 0x85FC, + 0xCC43, 0x85FD, 0xCC44, 0x85FE, 0xCC45, 0x8600, 0xCC46, 0x8601, 0xCC47, 0x8602, 0xCC48, 0x8603, 0xCC49, 0x8604, 0xCC4A, 0x8606, + 0xCC4B, 0x8607, 0xCC4C, 0x8608, 0xCC4D, 0x8609, 0xCC4E, 0x860A, 0xCC4F, 0x860B, 0xCC50, 0x860C, 0xCC51, 0x860D, 0xCC52, 0x860E, + 0xCC53, 0x860F, 0xCC54, 0x8610, 0xCC55, 0x8612, 0xCC56, 0x8613, 0xCC57, 0x8614, 0xCC58, 0x8615, 0xCC59, 0x8617, 0xCC5A, 0x8618, + 0xCC5B, 0x8619, 0xCC5C, 0x861A, 0xCC5D, 0x861B, 0xCC5E, 0x861C, 0xCC5F, 0x861D, 0xCC60, 0x861E, 0xCC61, 0x861F, 0xCC62, 0x8620, + 0xCC63, 0x8621, 0xCC64, 0x8622, 0xCC65, 0x8623, 0xCC66, 0x8624, 0xCC67, 0x8625, 0xCC68, 0x8626, 0xCC69, 0x8628, 0xCC6A, 0x862A, + 0xCC6B, 0x862B, 0xCC6C, 0x862C, 0xCC6D, 0x862D, 0xCC6E, 0x862E, 0xCC6F, 0x862F, 0xCC70, 0x8630, 0xCC71, 0x8631, 0xCC72, 0x8632, + 0xCC73, 0x8633, 0xCC74, 0x8634, 0xCC75, 0x8635, 0xCC76, 0x8636, 0xCC77, 0x8637, 0xCC78, 0x8639, 0xCC79, 0x863A, 0xCC7A, 0x863B, + 0xCC7B, 0x863D, 0xCC7C, 0x863E, 0xCC7D, 0x863F, 0xCC7E, 0x8640, 0xCC80, 0x8641, 0xCC81, 0x8642, 0xCC82, 0x8643, 0xCC83, 0x8644, + 0xCC84, 0x8645, 0xCC85, 0x8646, 0xCC86, 0x8647, 0xCC87, 0x8648, 0xCC88, 0x8649, 0xCC89, 0x864A, 0xCC8A, 0x864B, 0xCC8B, 0x864C, + 0xCC8C, 0x8652, 0xCC8D, 0x8653, 0xCC8E, 0x8655, 0xCC8F, 0x8656, 0xCC90, 0x8657, 0xCC91, 0x8658, 0xCC92, 0x8659, 0xCC93, 0x865B, + 0xCC94, 0x865C, 0xCC95, 0x865D, 0xCC96, 0x865F, 0xCC97, 0x8660, 0xCC98, 0x8661, 0xCC99, 0x8663, 0xCC9A, 0x8664, 0xCC9B, 0x8665, + 0xCC9C, 0x8666, 0xCC9D, 0x8667, 0xCC9E, 0x8668, 0xCC9F, 0x8669, 0xCCA0, 0x866A, 0xCCA1, 0x736D, 0xCCA2, 0x631E, 0xCCA3, 0x8E4B, + 0xCCA4, 0x8E0F, 0xCCA5, 0x80CE, 0xCCA6, 0x82D4, 0xCCA7, 0x62AC, 0xCCA8, 0x53F0, 0xCCA9, 0x6CF0, 0xCCAA, 0x915E, 0xCCAB, 0x592A, + 0xCCAC, 0x6001, 0xCCAD, 0x6C70, 0xCCAE, 0x574D, 0xCCAF, 0x644A, 0xCCB0, 0x8D2A, 0xCCB1, 0x762B, 0xCCB2, 0x6EE9, 0xCCB3, 0x575B, + 0xCCB4, 0x6A80, 0xCCB5, 0x75F0, 0xCCB6, 0x6F6D, 0xCCB7, 0x8C2D, 0xCCB8, 0x8C08, 0xCCB9, 0x5766, 0xCCBA, 0x6BEF, 0xCCBB, 0x8892, + 0xCCBC, 0x78B3, 0xCCBD, 0x63A2, 0xCCBE, 0x53F9, 0xCCBF, 0x70AD, 0xCCC0, 0x6C64, 0xCCC1, 0x5858, 0xCCC2, 0x642A, 0xCCC3, 0x5802, + 0xCCC4, 0x68E0, 0xCCC5, 0x819B, 0xCCC6, 0x5510, 0xCCC7, 0x7CD6, 0xCCC8, 0x5018, 0xCCC9, 0x8EBA, 0xCCCA, 0x6DCC, 0xCCCB, 0x8D9F, + 0xCCCC, 0x70EB, 0xCCCD, 0x638F, 0xCCCE, 0x6D9B, 0xCCCF, 0x6ED4, 0xCCD0, 0x7EE6, 0xCCD1, 0x8404, 0xCCD2, 0x6843, 0xCCD3, 0x9003, + 0xCCD4, 0x6DD8, 0xCCD5, 0x9676, 0xCCD6, 0x8BA8, 0xCCD7, 0x5957, 0xCCD8, 0x7279, 0xCCD9, 0x85E4, 0xCCDA, 0x817E, 0xCCDB, 0x75BC, + 0xCCDC, 0x8A8A, 0xCCDD, 0x68AF, 0xCCDE, 0x5254, 0xCCDF, 0x8E22, 0xCCE0, 0x9511, 0xCCE1, 0x63D0, 0xCCE2, 0x9898, 0xCCE3, 0x8E44, + 0xCCE4, 0x557C, 0xCCE5, 0x4F53, 0xCCE6, 0x66FF, 0xCCE7, 0x568F, 0xCCE8, 0x60D5, 0xCCE9, 0x6D95, 0xCCEA, 0x5243, 0xCCEB, 0x5C49, + 0xCCEC, 0x5929, 0xCCED, 0x6DFB, 0xCCEE, 0x586B, 0xCCEF, 0x7530, 0xCCF0, 0x751C, 0xCCF1, 0x606C, 0xCCF2, 0x8214, 0xCCF3, 0x8146, + 0xCCF4, 0x6311, 0xCCF5, 0x6761, 0xCCF6, 0x8FE2, 0xCCF7, 0x773A, 0xCCF8, 0x8DF3, 0xCCF9, 0x8D34, 0xCCFA, 0x94C1, 0xCCFB, 0x5E16, + 0xCCFC, 0x5385, 0xCCFD, 0x542C, 0xCCFE, 0x70C3, 0xCD40, 0x866D, 0xCD41, 0x866F, 0xCD42, 0x8670, 0xCD43, 0x8672, 0xCD44, 0x8673, + 0xCD45, 0x8674, 0xCD46, 0x8675, 0xCD47, 0x8676, 0xCD48, 0x8677, 0xCD49, 0x8678, 0xCD4A, 0x8683, 0xCD4B, 0x8684, 0xCD4C, 0x8685, + 0xCD4D, 0x8686, 0xCD4E, 0x8687, 0xCD4F, 0x8688, 0xCD50, 0x8689, 0xCD51, 0x868E, 0xCD52, 0x868F, 0xCD53, 0x8690, 0xCD54, 0x8691, + 0xCD55, 0x8692, 0xCD56, 0x8694, 0xCD57, 0x8696, 0xCD58, 0x8697, 0xCD59, 0x8698, 0xCD5A, 0x8699, 0xCD5B, 0x869A, 0xCD5C, 0x869B, + 0xCD5D, 0x869E, 0xCD5E, 0x869F, 0xCD5F, 0x86A0, 0xCD60, 0x86A1, 0xCD61, 0x86A2, 0xCD62, 0x86A5, 0xCD63, 0x86A6, 0xCD64, 0x86AB, + 0xCD65, 0x86AD, 0xCD66, 0x86AE, 0xCD67, 0x86B2, 0xCD68, 0x86B3, 0xCD69, 0x86B7, 0xCD6A, 0x86B8, 0xCD6B, 0x86B9, 0xCD6C, 0x86BB, + 0xCD6D, 0x86BC, 0xCD6E, 0x86BD, 0xCD6F, 0x86BE, 0xCD70, 0x86BF, 0xCD71, 0x86C1, 0xCD72, 0x86C2, 0xCD73, 0x86C3, 0xCD74, 0x86C5, + 0xCD75, 0x86C8, 0xCD76, 0x86CC, 0xCD77, 0x86CD, 0xCD78, 0x86D2, 0xCD79, 0x86D3, 0xCD7A, 0x86D5, 0xCD7B, 0x86D6, 0xCD7C, 0x86D7, + 0xCD7D, 0x86DA, 0xCD7E, 0x86DC, 0xCD80, 0x86DD, 0xCD81, 0x86E0, 0xCD82, 0x86E1, 0xCD83, 0x86E2, 0xCD84, 0x86E3, 0xCD85, 0x86E5, + 0xCD86, 0x86E6, 0xCD87, 0x86E7, 0xCD88, 0x86E8, 0xCD89, 0x86EA, 0xCD8A, 0x86EB, 0xCD8B, 0x86EC, 0xCD8C, 0x86EF, 0xCD8D, 0x86F5, + 0xCD8E, 0x86F6, 0xCD8F, 0x86F7, 0xCD90, 0x86FA, 0xCD91, 0x86FB, 0xCD92, 0x86FC, 0xCD93, 0x86FD, 0xCD94, 0x86FF, 0xCD95, 0x8701, + 0xCD96, 0x8704, 0xCD97, 0x8705, 0xCD98, 0x8706, 0xCD99, 0x870B, 0xCD9A, 0x870C, 0xCD9B, 0x870E, 0xCD9C, 0x870F, 0xCD9D, 0x8710, + 0xCD9E, 0x8711, 0xCD9F, 0x8714, 0xCDA0, 0x8716, 0xCDA1, 0x6C40, 0xCDA2, 0x5EF7, 0xCDA3, 0x505C, 0xCDA4, 0x4EAD, 0xCDA5, 0x5EAD, + 0xCDA6, 0x633A, 0xCDA7, 0x8247, 0xCDA8, 0x901A, 0xCDA9, 0x6850, 0xCDAA, 0x916E, 0xCDAB, 0x77B3, 0xCDAC, 0x540C, 0xCDAD, 0x94DC, + 0xCDAE, 0x5F64, 0xCDAF, 0x7AE5, 0xCDB0, 0x6876, 0xCDB1, 0x6345, 0xCDB2, 0x7B52, 0xCDB3, 0x7EDF, 0xCDB4, 0x75DB, 0xCDB5, 0x5077, + 0xCDB6, 0x6295, 0xCDB7, 0x5934, 0xCDB8, 0x900F, 0xCDB9, 0x51F8, 0xCDBA, 0x79C3, 0xCDBB, 0x7A81, 0xCDBC, 0x56FE, 0xCDBD, 0x5F92, + 0xCDBE, 0x9014, 0xCDBF, 0x6D82, 0xCDC0, 0x5C60, 0xCDC1, 0x571F, 0xCDC2, 0x5410, 0xCDC3, 0x5154, 0xCDC4, 0x6E4D, 0xCDC5, 0x56E2, + 0xCDC6, 0x63A8, 0xCDC7, 0x9893, 0xCDC8, 0x817F, 0xCDC9, 0x8715, 0xCDCA, 0x892A, 0xCDCB, 0x9000, 0xCDCC, 0x541E, 0xCDCD, 0x5C6F, + 0xCDCE, 0x81C0, 0xCDCF, 0x62D6, 0xCDD0, 0x6258, 0xCDD1, 0x8131, 0xCDD2, 0x9E35, 0xCDD3, 0x9640, 0xCDD4, 0x9A6E, 0xCDD5, 0x9A7C, + 0xCDD6, 0x692D, 0xCDD7, 0x59A5, 0xCDD8, 0x62D3, 0xCDD9, 0x553E, 0xCDDA, 0x6316, 0xCDDB, 0x54C7, 0xCDDC, 0x86D9, 0xCDDD, 0x6D3C, + 0xCDDE, 0x5A03, 0xCDDF, 0x74E6, 0xCDE0, 0x889C, 0xCDE1, 0x6B6A, 0xCDE2, 0x5916, 0xCDE3, 0x8C4C, 0xCDE4, 0x5F2F, 0xCDE5, 0x6E7E, + 0xCDE6, 0x73A9, 0xCDE7, 0x987D, 0xCDE8, 0x4E38, 0xCDE9, 0x70F7, 0xCDEA, 0x5B8C, 0xCDEB, 0x7897, 0xCDEC, 0x633D, 0xCDED, 0x665A, + 0xCDEE, 0x7696, 0xCDEF, 0x60CB, 0xCDF0, 0x5B9B, 0xCDF1, 0x5A49, 0xCDF2, 0x4E07, 0xCDF3, 0x8155, 0xCDF4, 0x6C6A, 0xCDF5, 0x738B, + 0xCDF6, 0x4EA1, 0xCDF7, 0x6789, 0xCDF8, 0x7F51, 0xCDF9, 0x5F80, 0xCDFA, 0x65FA, 0xCDFB, 0x671B, 0xCDFC, 0x5FD8, 0xCDFD, 0x5984, + 0xCDFE, 0x5A01, 0xCE40, 0x8719, 0xCE41, 0x871B, 0xCE42, 0x871D, 0xCE43, 0x871F, 0xCE44, 0x8720, 0xCE45, 0x8724, 0xCE46, 0x8726, + 0xCE47, 0x8727, 0xCE48, 0x8728, 0xCE49, 0x872A, 0xCE4A, 0x872B, 0xCE4B, 0x872C, 0xCE4C, 0x872D, 0xCE4D, 0x872F, 0xCE4E, 0x8730, + 0xCE4F, 0x8732, 0xCE50, 0x8733, 0xCE51, 0x8735, 0xCE52, 0x8736, 0xCE53, 0x8738, 0xCE54, 0x8739, 0xCE55, 0x873A, 0xCE56, 0x873C, + 0xCE57, 0x873D, 0xCE58, 0x8740, 0xCE59, 0x8741, 0xCE5A, 0x8742, 0xCE5B, 0x8743, 0xCE5C, 0x8744, 0xCE5D, 0x8745, 0xCE5E, 0x8746, + 0xCE5F, 0x874A, 0xCE60, 0x874B, 0xCE61, 0x874D, 0xCE62, 0x874F, 0xCE63, 0x8750, 0xCE64, 0x8751, 0xCE65, 0x8752, 0xCE66, 0x8754, + 0xCE67, 0x8755, 0xCE68, 0x8756, 0xCE69, 0x8758, 0xCE6A, 0x875A, 0xCE6B, 0x875B, 0xCE6C, 0x875C, 0xCE6D, 0x875D, 0xCE6E, 0x875E, + 0xCE6F, 0x875F, 0xCE70, 0x8761, 0xCE71, 0x8762, 0xCE72, 0x8766, 0xCE73, 0x8767, 0xCE74, 0x8768, 0xCE75, 0x8769, 0xCE76, 0x876A, + 0xCE77, 0x876B, 0xCE78, 0x876C, 0xCE79, 0x876D, 0xCE7A, 0x876F, 0xCE7B, 0x8771, 0xCE7C, 0x8772, 0xCE7D, 0x8773, 0xCE7E, 0x8775, + 0xCE80, 0x8777, 0xCE81, 0x8778, 0xCE82, 0x8779, 0xCE83, 0x877A, 0xCE84, 0x877F, 0xCE85, 0x8780, 0xCE86, 0x8781, 0xCE87, 0x8784, + 0xCE88, 0x8786, 0xCE89, 0x8787, 0xCE8A, 0x8789, 0xCE8B, 0x878A, 0xCE8C, 0x878C, 0xCE8D, 0x878E, 0xCE8E, 0x878F, 0xCE8F, 0x8790, + 0xCE90, 0x8791, 0xCE91, 0x8792, 0xCE92, 0x8794, 0xCE93, 0x8795, 0xCE94, 0x8796, 0xCE95, 0x8798, 0xCE96, 0x8799, 0xCE97, 0x879A, + 0xCE98, 0x879B, 0xCE99, 0x879C, 0xCE9A, 0x879D, 0xCE9B, 0x879E, 0xCE9C, 0x87A0, 0xCE9D, 0x87A1, 0xCE9E, 0x87A2, 0xCE9F, 0x87A3, + 0xCEA0, 0x87A4, 0xCEA1, 0x5DCD, 0xCEA2, 0x5FAE, 0xCEA3, 0x5371, 0xCEA4, 0x97E6, 0xCEA5, 0x8FDD, 0xCEA6, 0x6845, 0xCEA7, 0x56F4, + 0xCEA8, 0x552F, 0xCEA9, 0x60DF, 0xCEAA, 0x4E3A, 0xCEAB, 0x6F4D, 0xCEAC, 0x7EF4, 0xCEAD, 0x82C7, 0xCEAE, 0x840E, 0xCEAF, 0x59D4, + 0xCEB0, 0x4F1F, 0xCEB1, 0x4F2A, 0xCEB2, 0x5C3E, 0xCEB3, 0x7EAC, 0xCEB4, 0x672A, 0xCEB5, 0x851A, 0xCEB6, 0x5473, 0xCEB7, 0x754F, + 0xCEB8, 0x80C3, 0xCEB9, 0x5582, 0xCEBA, 0x9B4F, 0xCEBB, 0x4F4D, 0xCEBC, 0x6E2D, 0xCEBD, 0x8C13, 0xCEBE, 0x5C09, 0xCEBF, 0x6170, + 0xCEC0, 0x536B, 0xCEC1, 0x761F, 0xCEC2, 0x6E29, 0xCEC3, 0x868A, 0xCEC4, 0x6587, 0xCEC5, 0x95FB, 0xCEC6, 0x7EB9, 0xCEC7, 0x543B, + 0xCEC8, 0x7A33, 0xCEC9, 0x7D0A, 0xCECA, 0x95EE, 0xCECB, 0x55E1, 0xCECC, 0x7FC1, 0xCECD, 0x74EE, 0xCECE, 0x631D, 0xCECF, 0x8717, + 0xCED0, 0x6DA1, 0xCED1, 0x7A9D, 0xCED2, 0x6211, 0xCED3, 0x65A1, 0xCED4, 0x5367, 0xCED5, 0x63E1, 0xCED6, 0x6C83, 0xCED7, 0x5DEB, + 0xCED8, 0x545C, 0xCED9, 0x94A8, 0xCEDA, 0x4E4C, 0xCEDB, 0x6C61, 0xCEDC, 0x8BEC, 0xCEDD, 0x5C4B, 0xCEDE, 0x65E0, 0xCEDF, 0x829C, + 0xCEE0, 0x68A7, 0xCEE1, 0x543E, 0xCEE2, 0x5434, 0xCEE3, 0x6BCB, 0xCEE4, 0x6B66, 0xCEE5, 0x4E94, 0xCEE6, 0x6342, 0xCEE7, 0x5348, + 0xCEE8, 0x821E, 0xCEE9, 0x4F0D, 0xCEEA, 0x4FAE, 0xCEEB, 0x575E, 0xCEEC, 0x620A, 0xCEED, 0x96FE, 0xCEEE, 0x6664, 0xCEEF, 0x7269, + 0xCEF0, 0x52FF, 0xCEF1, 0x52A1, 0xCEF2, 0x609F, 0xCEF3, 0x8BEF, 0xCEF4, 0x6614, 0xCEF5, 0x7199, 0xCEF6, 0x6790, 0xCEF7, 0x897F, + 0xCEF8, 0x7852, 0xCEF9, 0x77FD, 0xCEFA, 0x6670, 0xCEFB, 0x563B, 0xCEFC, 0x5438, 0xCEFD, 0x9521, 0xCEFE, 0x727A, 0xCF40, 0x87A5, + 0xCF41, 0x87A6, 0xCF42, 0x87A7, 0xCF43, 0x87A9, 0xCF44, 0x87AA, 0xCF45, 0x87AE, 0xCF46, 0x87B0, 0xCF47, 0x87B1, 0xCF48, 0x87B2, + 0xCF49, 0x87B4, 0xCF4A, 0x87B6, 0xCF4B, 0x87B7, 0xCF4C, 0x87B8, 0xCF4D, 0x87B9, 0xCF4E, 0x87BB, 0xCF4F, 0x87BC, 0xCF50, 0x87BE, + 0xCF51, 0x87BF, 0xCF52, 0x87C1, 0xCF53, 0x87C2, 0xCF54, 0x87C3, 0xCF55, 0x87C4, 0xCF56, 0x87C5, 0xCF57, 0x87C7, 0xCF58, 0x87C8, + 0xCF59, 0x87C9, 0xCF5A, 0x87CC, 0xCF5B, 0x87CD, 0xCF5C, 0x87CE, 0xCF5D, 0x87CF, 0xCF5E, 0x87D0, 0xCF5F, 0x87D4, 0xCF60, 0x87D5, + 0xCF61, 0x87D6, 0xCF62, 0x87D7, 0xCF63, 0x87D8, 0xCF64, 0x87D9, 0xCF65, 0x87DA, 0xCF66, 0x87DC, 0xCF67, 0x87DD, 0xCF68, 0x87DE, + 0xCF69, 0x87DF, 0xCF6A, 0x87E1, 0xCF6B, 0x87E2, 0xCF6C, 0x87E3, 0xCF6D, 0x87E4, 0xCF6E, 0x87E6, 0xCF6F, 0x87E7, 0xCF70, 0x87E8, + 0xCF71, 0x87E9, 0xCF72, 0x87EB, 0xCF73, 0x87EC, 0xCF74, 0x87ED, 0xCF75, 0x87EF, 0xCF76, 0x87F0, 0xCF77, 0x87F1, 0xCF78, 0x87F2, + 0xCF79, 0x87F3, 0xCF7A, 0x87F4, 0xCF7B, 0x87F5, 0xCF7C, 0x87F6, 0xCF7D, 0x87F7, 0xCF7E, 0x87F8, 0xCF80, 0x87FA, 0xCF81, 0x87FB, + 0xCF82, 0x87FC, 0xCF83, 0x87FD, 0xCF84, 0x87FF, 0xCF85, 0x8800, 0xCF86, 0x8801, 0xCF87, 0x8802, 0xCF88, 0x8804, 0xCF89, 0x8805, + 0xCF8A, 0x8806, 0xCF8B, 0x8807, 0xCF8C, 0x8808, 0xCF8D, 0x8809, 0xCF8E, 0x880B, 0xCF8F, 0x880C, 0xCF90, 0x880D, 0xCF91, 0x880E, + 0xCF92, 0x880F, 0xCF93, 0x8810, 0xCF94, 0x8811, 0xCF95, 0x8812, 0xCF96, 0x8814, 0xCF97, 0x8817, 0xCF98, 0x8818, 0xCF99, 0x8819, + 0xCF9A, 0x881A, 0xCF9B, 0x881C, 0xCF9C, 0x881D, 0xCF9D, 0x881E, 0xCF9E, 0x881F, 0xCF9F, 0x8820, 0xCFA0, 0x8823, 0xCFA1, 0x7A00, + 0xCFA2, 0x606F, 0xCFA3, 0x5E0C, 0xCFA4, 0x6089, 0xCFA5, 0x819D, 0xCFA6, 0x5915, 0xCFA7, 0x60DC, 0xCFA8, 0x7184, 0xCFA9, 0x70EF, + 0xCFAA, 0x6EAA, 0xCFAB, 0x6C50, 0xCFAC, 0x7280, 0xCFAD, 0x6A84, 0xCFAE, 0x88AD, 0xCFAF, 0x5E2D, 0xCFB0, 0x4E60, 0xCFB1, 0x5AB3, + 0xCFB2, 0x559C, 0xCFB3, 0x94E3, 0xCFB4, 0x6D17, 0xCFB5, 0x7CFB, 0xCFB6, 0x9699, 0xCFB7, 0x620F, 0xCFB8, 0x7EC6, 0xCFB9, 0x778E, + 0xCFBA, 0x867E, 0xCFBB, 0x5323, 0xCFBC, 0x971E, 0xCFBD, 0x8F96, 0xCFBE, 0x6687, 0xCFBF, 0x5CE1, 0xCFC0, 0x4FA0, 0xCFC1, 0x72ED, + 0xCFC2, 0x4E0B, 0xCFC3, 0x53A6, 0xCFC4, 0x590F, 0xCFC5, 0x5413, 0xCFC6, 0x6380, 0xCFC7, 0x9528, 0xCFC8, 0x5148, 0xCFC9, 0x4ED9, + 0xCFCA, 0x9C9C, 0xCFCB, 0x7EA4, 0xCFCC, 0x54B8, 0xCFCD, 0x8D24, 0xCFCE, 0x8854, 0xCFCF, 0x8237, 0xCFD0, 0x95F2, 0xCFD1, 0x6D8E, + 0xCFD2, 0x5F26, 0xCFD3, 0x5ACC, 0xCFD4, 0x663E, 0xCFD5, 0x9669, 0xCFD6, 0x73B0, 0xCFD7, 0x732E, 0xCFD8, 0x53BF, 0xCFD9, 0x817A, + 0xCFDA, 0x9985, 0xCFDB, 0x7FA1, 0xCFDC, 0x5BAA, 0xCFDD, 0x9677, 0xCFDE, 0x9650, 0xCFDF, 0x7EBF, 0xCFE0, 0x76F8, 0xCFE1, 0x53A2, + 0xCFE2, 0x9576, 0xCFE3, 0x9999, 0xCFE4, 0x7BB1, 0xCFE5, 0x8944, 0xCFE6, 0x6E58, 0xCFE7, 0x4E61, 0xCFE8, 0x7FD4, 0xCFE9, 0x7965, + 0xCFEA, 0x8BE6, 0xCFEB, 0x60F3, 0xCFEC, 0x54CD, 0xCFED, 0x4EAB, 0xCFEE, 0x9879, 0xCFEF, 0x5DF7, 0xCFF0, 0x6A61, 0xCFF1, 0x50CF, + 0xCFF2, 0x5411, 0xCFF3, 0x8C61, 0xCFF4, 0x8427, 0xCFF5, 0x785D, 0xCFF6, 0x9704, 0xCFF7, 0x524A, 0xCFF8, 0x54EE, 0xCFF9, 0x56A3, + 0xCFFA, 0x9500, 0xCFFB, 0x6D88, 0xCFFC, 0x5BB5, 0xCFFD, 0x6DC6, 0xCFFE, 0x6653, 0xD040, 0x8824, 0xD041, 0x8825, 0xD042, 0x8826, + 0xD043, 0x8827, 0xD044, 0x8828, 0xD045, 0x8829, 0xD046, 0x882A, 0xD047, 0x882B, 0xD048, 0x882C, 0xD049, 0x882D, 0xD04A, 0x882E, + 0xD04B, 0x882F, 0xD04C, 0x8830, 0xD04D, 0x8831, 0xD04E, 0x8833, 0xD04F, 0x8834, 0xD050, 0x8835, 0xD051, 0x8836, 0xD052, 0x8837, + 0xD053, 0x8838, 0xD054, 0x883A, 0xD055, 0x883B, 0xD056, 0x883D, 0xD057, 0x883E, 0xD058, 0x883F, 0xD059, 0x8841, 0xD05A, 0x8842, + 0xD05B, 0x8843, 0xD05C, 0x8846, 0xD05D, 0x8847, 0xD05E, 0x8848, 0xD05F, 0x8849, 0xD060, 0x884A, 0xD061, 0x884B, 0xD062, 0x884E, + 0xD063, 0x884F, 0xD064, 0x8850, 0xD065, 0x8851, 0xD066, 0x8852, 0xD067, 0x8853, 0xD068, 0x8855, 0xD069, 0x8856, 0xD06A, 0x8858, + 0xD06B, 0x885A, 0xD06C, 0x885B, 0xD06D, 0x885C, 0xD06E, 0x885D, 0xD06F, 0x885E, 0xD070, 0x885F, 0xD071, 0x8860, 0xD072, 0x8866, + 0xD073, 0x8867, 0xD074, 0x886A, 0xD075, 0x886D, 0xD076, 0x886F, 0xD077, 0x8871, 0xD078, 0x8873, 0xD079, 0x8874, 0xD07A, 0x8875, + 0xD07B, 0x8876, 0xD07C, 0x8878, 0xD07D, 0x8879, 0xD07E, 0x887A, 0xD080, 0x887B, 0xD081, 0x887C, 0xD082, 0x8880, 0xD083, 0x8883, + 0xD084, 0x8886, 0xD085, 0x8887, 0xD086, 0x8889, 0xD087, 0x888A, 0xD088, 0x888C, 0xD089, 0x888E, 0xD08A, 0x888F, 0xD08B, 0x8890, + 0xD08C, 0x8891, 0xD08D, 0x8893, 0xD08E, 0x8894, 0xD08F, 0x8895, 0xD090, 0x8897, 0xD091, 0x8898, 0xD092, 0x8899, 0xD093, 0x889A, + 0xD094, 0x889B, 0xD095, 0x889D, 0xD096, 0x889E, 0xD097, 0x889F, 0xD098, 0x88A0, 0xD099, 0x88A1, 0xD09A, 0x88A3, 0xD09B, 0x88A5, + 0xD09C, 0x88A6, 0xD09D, 0x88A7, 0xD09E, 0x88A8, 0xD09F, 0x88A9, 0xD0A0, 0x88AA, 0xD0A1, 0x5C0F, 0xD0A2, 0x5B5D, 0xD0A3, 0x6821, + 0xD0A4, 0x8096, 0xD0A5, 0x5578, 0xD0A6, 0x7B11, 0xD0A7, 0x6548, 0xD0A8, 0x6954, 0xD0A9, 0x4E9B, 0xD0AA, 0x6B47, 0xD0AB, 0x874E, + 0xD0AC, 0x978B, 0xD0AD, 0x534F, 0xD0AE, 0x631F, 0xD0AF, 0x643A, 0xD0B0, 0x90AA, 0xD0B1, 0x659C, 0xD0B2, 0x80C1, 0xD0B3, 0x8C10, + 0xD0B4, 0x5199, 0xD0B5, 0x68B0, 0xD0B6, 0x5378, 0xD0B7, 0x87F9, 0xD0B8, 0x61C8, 0xD0B9, 0x6CC4, 0xD0BA, 0x6CFB, 0xD0BB, 0x8C22, + 0xD0BC, 0x5C51, 0xD0BD, 0x85AA, 0xD0BE, 0x82AF, 0xD0BF, 0x950C, 0xD0C0, 0x6B23, 0xD0C1, 0x8F9B, 0xD0C2, 0x65B0, 0xD0C3, 0x5FFB, + 0xD0C4, 0x5FC3, 0xD0C5, 0x4FE1, 0xD0C6, 0x8845, 0xD0C7, 0x661F, 0xD0C8, 0x8165, 0xD0C9, 0x7329, 0xD0CA, 0x60FA, 0xD0CB, 0x5174, + 0xD0CC, 0x5211, 0xD0CD, 0x578B, 0xD0CE, 0x5F62, 0xD0CF, 0x90A2, 0xD0D0, 0x884C, 0xD0D1, 0x9192, 0xD0D2, 0x5E78, 0xD0D3, 0x674F, + 0xD0D4, 0x6027, 0xD0D5, 0x59D3, 0xD0D6, 0x5144, 0xD0D7, 0x51F6, 0xD0D8, 0x80F8, 0xD0D9, 0x5308, 0xD0DA, 0x6C79, 0xD0DB, 0x96C4, + 0xD0DC, 0x718A, 0xD0DD, 0x4F11, 0xD0DE, 0x4FEE, 0xD0DF, 0x7F9E, 0xD0E0, 0x673D, 0xD0E1, 0x55C5, 0xD0E2, 0x9508, 0xD0E3, 0x79C0, + 0xD0E4, 0x8896, 0xD0E5, 0x7EE3, 0xD0E6, 0x589F, 0xD0E7, 0x620C, 0xD0E8, 0x9700, 0xD0E9, 0x865A, 0xD0EA, 0x5618, 0xD0EB, 0x987B, + 0xD0EC, 0x5F90, 0xD0ED, 0x8BB8, 0xD0EE, 0x84C4, 0xD0EF, 0x9157, 0xD0F0, 0x53D9, 0xD0F1, 0x65ED, 0xD0F2, 0x5E8F, 0xD0F3, 0x755C, + 0xD0F4, 0x6064, 0xD0F5, 0x7D6E, 0xD0F6, 0x5A7F, 0xD0F7, 0x7EEA, 0xD0F8, 0x7EED, 0xD0F9, 0x8F69, 0xD0FA, 0x55A7, 0xD0FB, 0x5BA3, + 0xD0FC, 0x60AC, 0xD0FD, 0x65CB, 0xD0FE, 0x7384, 0xD140, 0x88AC, 0xD141, 0x88AE, 0xD142, 0x88AF, 0xD143, 0x88B0, 0xD144, 0x88B2, + 0xD145, 0x88B3, 0xD146, 0x88B4, 0xD147, 0x88B5, 0xD148, 0x88B6, 0xD149, 0x88B8, 0xD14A, 0x88B9, 0xD14B, 0x88BA, 0xD14C, 0x88BB, + 0xD14D, 0x88BD, 0xD14E, 0x88BE, 0xD14F, 0x88BF, 0xD150, 0x88C0, 0xD151, 0x88C3, 0xD152, 0x88C4, 0xD153, 0x88C7, 0xD154, 0x88C8, + 0xD155, 0x88CA, 0xD156, 0x88CB, 0xD157, 0x88CC, 0xD158, 0x88CD, 0xD159, 0x88CF, 0xD15A, 0x88D0, 0xD15B, 0x88D1, 0xD15C, 0x88D3, + 0xD15D, 0x88D6, 0xD15E, 0x88D7, 0xD15F, 0x88DA, 0xD160, 0x88DB, 0xD161, 0x88DC, 0xD162, 0x88DD, 0xD163, 0x88DE, 0xD164, 0x88E0, + 0xD165, 0x88E1, 0xD166, 0x88E6, 0xD167, 0x88E7, 0xD168, 0x88E9, 0xD169, 0x88EA, 0xD16A, 0x88EB, 0xD16B, 0x88EC, 0xD16C, 0x88ED, + 0xD16D, 0x88EE, 0xD16E, 0x88EF, 0xD16F, 0x88F2, 0xD170, 0x88F5, 0xD171, 0x88F6, 0xD172, 0x88F7, 0xD173, 0x88FA, 0xD174, 0x88FB, + 0xD175, 0x88FD, 0xD176, 0x88FF, 0xD177, 0x8900, 0xD178, 0x8901, 0xD179, 0x8903, 0xD17A, 0x8904, 0xD17B, 0x8905, 0xD17C, 0x8906, + 0xD17D, 0x8907, 0xD17E, 0x8908, 0xD180, 0x8909, 0xD181, 0x890B, 0xD182, 0x890C, 0xD183, 0x890D, 0xD184, 0x890E, 0xD185, 0x890F, + 0xD186, 0x8911, 0xD187, 0x8914, 0xD188, 0x8915, 0xD189, 0x8916, 0xD18A, 0x8917, 0xD18B, 0x8918, 0xD18C, 0x891C, 0xD18D, 0x891D, + 0xD18E, 0x891E, 0xD18F, 0x891F, 0xD190, 0x8920, 0xD191, 0x8922, 0xD192, 0x8923, 0xD193, 0x8924, 0xD194, 0x8926, 0xD195, 0x8927, + 0xD196, 0x8928, 0xD197, 0x8929, 0xD198, 0x892C, 0xD199, 0x892D, 0xD19A, 0x892E, 0xD19B, 0x892F, 0xD19C, 0x8931, 0xD19D, 0x8932, + 0xD19E, 0x8933, 0xD19F, 0x8935, 0xD1A0, 0x8937, 0xD1A1, 0x9009, 0xD1A2, 0x7663, 0xD1A3, 0x7729, 0xD1A4, 0x7EDA, 0xD1A5, 0x9774, + 0xD1A6, 0x859B, 0xD1A7, 0x5B66, 0xD1A8, 0x7A74, 0xD1A9, 0x96EA, 0xD1AA, 0x8840, 0xD1AB, 0x52CB, 0xD1AC, 0x718F, 0xD1AD, 0x5FAA, + 0xD1AE, 0x65EC, 0xD1AF, 0x8BE2, 0xD1B0, 0x5BFB, 0xD1B1, 0x9A6F, 0xD1B2, 0x5DE1, 0xD1B3, 0x6B89, 0xD1B4, 0x6C5B, 0xD1B5, 0x8BAD, + 0xD1B6, 0x8BAF, 0xD1B7, 0x900A, 0xD1B8, 0x8FC5, 0xD1B9, 0x538B, 0xD1BA, 0x62BC, 0xD1BB, 0x9E26, 0xD1BC, 0x9E2D, 0xD1BD, 0x5440, + 0xD1BE, 0x4E2B, 0xD1BF, 0x82BD, 0xD1C0, 0x7259, 0xD1C1, 0x869C, 0xD1C2, 0x5D16, 0xD1C3, 0x8859, 0xD1C4, 0x6DAF, 0xD1C5, 0x96C5, + 0xD1C6, 0x54D1, 0xD1C7, 0x4E9A, 0xD1C8, 0x8BB6, 0xD1C9, 0x7109, 0xD1CA, 0x54BD, 0xD1CB, 0x9609, 0xD1CC, 0x70DF, 0xD1CD, 0x6DF9, + 0xD1CE, 0x76D0, 0xD1CF, 0x4E25, 0xD1D0, 0x7814, 0xD1D1, 0x8712, 0xD1D2, 0x5CA9, 0xD1D3, 0x5EF6, 0xD1D4, 0x8A00, 0xD1D5, 0x989C, + 0xD1D6, 0x960E, 0xD1D7, 0x708E, 0xD1D8, 0x6CBF, 0xD1D9, 0x5944, 0xD1DA, 0x63A9, 0xD1DB, 0x773C, 0xD1DC, 0x884D, 0xD1DD, 0x6F14, + 0xD1DE, 0x8273, 0xD1DF, 0x5830, 0xD1E0, 0x71D5, 0xD1E1, 0x538C, 0xD1E2, 0x781A, 0xD1E3, 0x96C1, 0xD1E4, 0x5501, 0xD1E5, 0x5F66, + 0xD1E6, 0x7130, 0xD1E7, 0x5BB4, 0xD1E8, 0x8C1A, 0xD1E9, 0x9A8C, 0xD1EA, 0x6B83, 0xD1EB, 0x592E, 0xD1EC, 0x9E2F, 0xD1ED, 0x79E7, + 0xD1EE, 0x6768, 0xD1EF, 0x626C, 0xD1F0, 0x4F6F, 0xD1F1, 0x75A1, 0xD1F2, 0x7F8A, 0xD1F3, 0x6D0B, 0xD1F4, 0x9633, 0xD1F5, 0x6C27, + 0xD1F6, 0x4EF0, 0xD1F7, 0x75D2, 0xD1F8, 0x517B, 0xD1F9, 0x6837, 0xD1FA, 0x6F3E, 0xD1FB, 0x9080, 0xD1FC, 0x8170, 0xD1FD, 0x5996, + 0xD1FE, 0x7476, 0xD240, 0x8938, 0xD241, 0x8939, 0xD242, 0x893A, 0xD243, 0x893B, 0xD244, 0x893C, 0xD245, 0x893D, 0xD246, 0x893E, + 0xD247, 0x893F, 0xD248, 0x8940, 0xD249, 0x8942, 0xD24A, 0x8943, 0xD24B, 0x8945, 0xD24C, 0x8946, 0xD24D, 0x8947, 0xD24E, 0x8948, + 0xD24F, 0x8949, 0xD250, 0x894A, 0xD251, 0x894B, 0xD252, 0x894C, 0xD253, 0x894D, 0xD254, 0x894E, 0xD255, 0x894F, 0xD256, 0x8950, + 0xD257, 0x8951, 0xD258, 0x8952, 0xD259, 0x8953, 0xD25A, 0x8954, 0xD25B, 0x8955, 0xD25C, 0x8956, 0xD25D, 0x8957, 0xD25E, 0x8958, + 0xD25F, 0x8959, 0xD260, 0x895A, 0xD261, 0x895B, 0xD262, 0x895C, 0xD263, 0x895D, 0xD264, 0x8960, 0xD265, 0x8961, 0xD266, 0x8962, + 0xD267, 0x8963, 0xD268, 0x8964, 0xD269, 0x8965, 0xD26A, 0x8967, 0xD26B, 0x8968, 0xD26C, 0x8969, 0xD26D, 0x896A, 0xD26E, 0x896B, + 0xD26F, 0x896C, 0xD270, 0x896D, 0xD271, 0x896E, 0xD272, 0x896F, 0xD273, 0x8970, 0xD274, 0x8971, 0xD275, 0x8972, 0xD276, 0x8973, + 0xD277, 0x8974, 0xD278, 0x8975, 0xD279, 0x8976, 0xD27A, 0x8977, 0xD27B, 0x8978, 0xD27C, 0x8979, 0xD27D, 0x897A, 0xD27E, 0x897C, + 0xD280, 0x897D, 0xD281, 0x897E, 0xD282, 0x8980, 0xD283, 0x8982, 0xD284, 0x8984, 0xD285, 0x8985, 0xD286, 0x8987, 0xD287, 0x8988, + 0xD288, 0x8989, 0xD289, 0x898A, 0xD28A, 0x898B, 0xD28B, 0x898C, 0xD28C, 0x898D, 0xD28D, 0x898E, 0xD28E, 0x898F, 0xD28F, 0x8990, + 0xD290, 0x8991, 0xD291, 0x8992, 0xD292, 0x8993, 0xD293, 0x8994, 0xD294, 0x8995, 0xD295, 0x8996, 0xD296, 0x8997, 0xD297, 0x8998, + 0xD298, 0x8999, 0xD299, 0x899A, 0xD29A, 0x899B, 0xD29B, 0x899C, 0xD29C, 0x899D, 0xD29D, 0x899E, 0xD29E, 0x899F, 0xD29F, 0x89A0, + 0xD2A0, 0x89A1, 0xD2A1, 0x6447, 0xD2A2, 0x5C27, 0xD2A3, 0x9065, 0xD2A4, 0x7A91, 0xD2A5, 0x8C23, 0xD2A6, 0x59DA, 0xD2A7, 0x54AC, + 0xD2A8, 0x8200, 0xD2A9, 0x836F, 0xD2AA, 0x8981, 0xD2AB, 0x8000, 0xD2AC, 0x6930, 0xD2AD, 0x564E, 0xD2AE, 0x8036, 0xD2AF, 0x7237, + 0xD2B0, 0x91CE, 0xD2B1, 0x51B6, 0xD2B2, 0x4E5F, 0xD2B3, 0x9875, 0xD2B4, 0x6396, 0xD2B5, 0x4E1A, 0xD2B6, 0x53F6, 0xD2B7, 0x66F3, + 0xD2B8, 0x814B, 0xD2B9, 0x591C, 0xD2BA, 0x6DB2, 0xD2BB, 0x4E00, 0xD2BC, 0x58F9, 0xD2BD, 0x533B, 0xD2BE, 0x63D6, 0xD2BF, 0x94F1, + 0xD2C0, 0x4F9D, 0xD2C1, 0x4F0A, 0xD2C2, 0x8863, 0xD2C3, 0x9890, 0xD2C4, 0x5937, 0xD2C5, 0x9057, 0xD2C6, 0x79FB, 0xD2C7, 0x4EEA, + 0xD2C8, 0x80F0, 0xD2C9, 0x7591, 0xD2CA, 0x6C82, 0xD2CB, 0x5B9C, 0xD2CC, 0x59E8, 0xD2CD, 0x5F5D, 0xD2CE, 0x6905, 0xD2CF, 0x8681, + 0xD2D0, 0x501A, 0xD2D1, 0x5DF2, 0xD2D2, 0x4E59, 0xD2D3, 0x77E3, 0xD2D4, 0x4EE5, 0xD2D5, 0x827A, 0xD2D6, 0x6291, 0xD2D7, 0x6613, + 0xD2D8, 0x9091, 0xD2D9, 0x5C79, 0xD2DA, 0x4EBF, 0xD2DB, 0x5F79, 0xD2DC, 0x81C6, 0xD2DD, 0x9038, 0xD2DE, 0x8084, 0xD2DF, 0x75AB, + 0xD2E0, 0x4EA6, 0xD2E1, 0x88D4, 0xD2E2, 0x610F, 0xD2E3, 0x6BC5, 0xD2E4, 0x5FC6, 0xD2E5, 0x4E49, 0xD2E6, 0x76CA, 0xD2E7, 0x6EA2, + 0xD2E8, 0x8BE3, 0xD2E9, 0x8BAE, 0xD2EA, 0x8C0A, 0xD2EB, 0x8BD1, 0xD2EC, 0x5F02, 0xD2ED, 0x7FFC, 0xD2EE, 0x7FCC, 0xD2EF, 0x7ECE, + 0xD2F0, 0x8335, 0xD2F1, 0x836B, 0xD2F2, 0x56E0, 0xD2F3, 0x6BB7, 0xD2F4, 0x97F3, 0xD2F5, 0x9634, 0xD2F6, 0x59FB, 0xD2F7, 0x541F, + 0xD2F8, 0x94F6, 0xD2F9, 0x6DEB, 0xD2FA, 0x5BC5, 0xD2FB, 0x996E, 0xD2FC, 0x5C39, 0xD2FD, 0x5F15, 0xD2FE, 0x9690, 0xD340, 0x89A2, + 0xD341, 0x89A3, 0xD342, 0x89A4, 0xD343, 0x89A5, 0xD344, 0x89A6, 0xD345, 0x89A7, 0xD346, 0x89A8, 0xD347, 0x89A9, 0xD348, 0x89AA, + 0xD349, 0x89AB, 0xD34A, 0x89AC, 0xD34B, 0x89AD, 0xD34C, 0x89AE, 0xD34D, 0x89AF, 0xD34E, 0x89B0, 0xD34F, 0x89B1, 0xD350, 0x89B2, + 0xD351, 0x89B3, 0xD352, 0x89B4, 0xD353, 0x89B5, 0xD354, 0x89B6, 0xD355, 0x89B7, 0xD356, 0x89B8, 0xD357, 0x89B9, 0xD358, 0x89BA, + 0xD359, 0x89BB, 0xD35A, 0x89BC, 0xD35B, 0x89BD, 0xD35C, 0x89BE, 0xD35D, 0x89BF, 0xD35E, 0x89C0, 0xD35F, 0x89C3, 0xD360, 0x89CD, + 0xD361, 0x89D3, 0xD362, 0x89D4, 0xD363, 0x89D5, 0xD364, 0x89D7, 0xD365, 0x89D8, 0xD366, 0x89D9, 0xD367, 0x89DB, 0xD368, 0x89DD, + 0xD369, 0x89DF, 0xD36A, 0x89E0, 0xD36B, 0x89E1, 0xD36C, 0x89E2, 0xD36D, 0x89E4, 0xD36E, 0x89E7, 0xD36F, 0x89E8, 0xD370, 0x89E9, + 0xD371, 0x89EA, 0xD372, 0x89EC, 0xD373, 0x89ED, 0xD374, 0x89EE, 0xD375, 0x89F0, 0xD376, 0x89F1, 0xD377, 0x89F2, 0xD378, 0x89F4, + 0xD379, 0x89F5, 0xD37A, 0x89F6, 0xD37B, 0x89F7, 0xD37C, 0x89F8, 0xD37D, 0x89F9, 0xD37E, 0x89FA, 0xD380, 0x89FB, 0xD381, 0x89FC, + 0xD382, 0x89FD, 0xD383, 0x89FE, 0xD384, 0x89FF, 0xD385, 0x8A01, 0xD386, 0x8A02, 0xD387, 0x8A03, 0xD388, 0x8A04, 0xD389, 0x8A05, + 0xD38A, 0x8A06, 0xD38B, 0x8A08, 0xD38C, 0x8A09, 0xD38D, 0x8A0A, 0xD38E, 0x8A0B, 0xD38F, 0x8A0C, 0xD390, 0x8A0D, 0xD391, 0x8A0E, + 0xD392, 0x8A0F, 0xD393, 0x8A10, 0xD394, 0x8A11, 0xD395, 0x8A12, 0xD396, 0x8A13, 0xD397, 0x8A14, 0xD398, 0x8A15, 0xD399, 0x8A16, + 0xD39A, 0x8A17, 0xD39B, 0x8A18, 0xD39C, 0x8A19, 0xD39D, 0x8A1A, 0xD39E, 0x8A1B, 0xD39F, 0x8A1C, 0xD3A0, 0x8A1D, 0xD3A1, 0x5370, + 0xD3A2, 0x82F1, 0xD3A3, 0x6A31, 0xD3A4, 0x5A74, 0xD3A5, 0x9E70, 0xD3A6, 0x5E94, 0xD3A7, 0x7F28, 0xD3A8, 0x83B9, 0xD3A9, 0x8424, + 0xD3AA, 0x8425, 0xD3AB, 0x8367, 0xD3AC, 0x8747, 0xD3AD, 0x8FCE, 0xD3AE, 0x8D62, 0xD3AF, 0x76C8, 0xD3B0, 0x5F71, 0xD3B1, 0x9896, + 0xD3B2, 0x786C, 0xD3B3, 0x6620, 0xD3B4, 0x54DF, 0xD3B5, 0x62E5, 0xD3B6, 0x4F63, 0xD3B7, 0x81C3, 0xD3B8, 0x75C8, 0xD3B9, 0x5EB8, + 0xD3BA, 0x96CD, 0xD3BB, 0x8E0A, 0xD3BC, 0x86F9, 0xD3BD, 0x548F, 0xD3BE, 0x6CF3, 0xD3BF, 0x6D8C, 0xD3C0, 0x6C38, 0xD3C1, 0x607F, + 0xD3C2, 0x52C7, 0xD3C3, 0x7528, 0xD3C4, 0x5E7D, 0xD3C5, 0x4F18, 0xD3C6, 0x60A0, 0xD3C7, 0x5FE7, 0xD3C8, 0x5C24, 0xD3C9, 0x7531, + 0xD3CA, 0x90AE, 0xD3CB, 0x94C0, 0xD3CC, 0x72B9, 0xD3CD, 0x6CB9, 0xD3CE, 0x6E38, 0xD3CF, 0x9149, 0xD3D0, 0x6709, 0xD3D1, 0x53CB, + 0xD3D2, 0x53F3, 0xD3D3, 0x4F51, 0xD3D4, 0x91C9, 0xD3D5, 0x8BF1, 0xD3D6, 0x53C8, 0xD3D7, 0x5E7C, 0xD3D8, 0x8FC2, 0xD3D9, 0x6DE4, + 0xD3DA, 0x4E8E, 0xD3DB, 0x76C2, 0xD3DC, 0x6986, 0xD3DD, 0x865E, 0xD3DE, 0x611A, 0xD3DF, 0x8206, 0xD3E0, 0x4F59, 0xD3E1, 0x4FDE, + 0xD3E2, 0x903E, 0xD3E3, 0x9C7C, 0xD3E4, 0x6109, 0xD3E5, 0x6E1D, 0xD3E6, 0x6E14, 0xD3E7, 0x9685, 0xD3E8, 0x4E88, 0xD3E9, 0x5A31, + 0xD3EA, 0x96E8, 0xD3EB, 0x4E0E, 0xD3EC, 0x5C7F, 0xD3ED, 0x79B9, 0xD3EE, 0x5B87, 0xD3EF, 0x8BED, 0xD3F0, 0x7FBD, 0xD3F1, 0x7389, + 0xD3F2, 0x57DF, 0xD3F3, 0x828B, 0xD3F4, 0x90C1, 0xD3F5, 0x5401, 0xD3F6, 0x9047, 0xD3F7, 0x55BB, 0xD3F8, 0x5CEA, 0xD3F9, 0x5FA1, + 0xD3FA, 0x6108, 0xD3FB, 0x6B32, 0xD3FC, 0x72F1, 0xD3FD, 0x80B2, 0xD3FE, 0x8A89, 0xD440, 0x8A1E, 0xD441, 0x8A1F, 0xD442, 0x8A20, + 0xD443, 0x8A21, 0xD444, 0x8A22, 0xD445, 0x8A23, 0xD446, 0x8A24, 0xD447, 0x8A25, 0xD448, 0x8A26, 0xD449, 0x8A27, 0xD44A, 0x8A28, + 0xD44B, 0x8A29, 0xD44C, 0x8A2A, 0xD44D, 0x8A2B, 0xD44E, 0x8A2C, 0xD44F, 0x8A2D, 0xD450, 0x8A2E, 0xD451, 0x8A2F, 0xD452, 0x8A30, + 0xD453, 0x8A31, 0xD454, 0x8A32, 0xD455, 0x8A33, 0xD456, 0x8A34, 0xD457, 0x8A35, 0xD458, 0x8A36, 0xD459, 0x8A37, 0xD45A, 0x8A38, + 0xD45B, 0x8A39, 0xD45C, 0x8A3A, 0xD45D, 0x8A3B, 0xD45E, 0x8A3C, 0xD45F, 0x8A3D, 0xD460, 0x8A3F, 0xD461, 0x8A40, 0xD462, 0x8A41, + 0xD463, 0x8A42, 0xD464, 0x8A43, 0xD465, 0x8A44, 0xD466, 0x8A45, 0xD467, 0x8A46, 0xD468, 0x8A47, 0xD469, 0x8A49, 0xD46A, 0x8A4A, + 0xD46B, 0x8A4B, 0xD46C, 0x8A4C, 0xD46D, 0x8A4D, 0xD46E, 0x8A4E, 0xD46F, 0x8A4F, 0xD470, 0x8A50, 0xD471, 0x8A51, 0xD472, 0x8A52, + 0xD473, 0x8A53, 0xD474, 0x8A54, 0xD475, 0x8A55, 0xD476, 0x8A56, 0xD477, 0x8A57, 0xD478, 0x8A58, 0xD479, 0x8A59, 0xD47A, 0x8A5A, + 0xD47B, 0x8A5B, 0xD47C, 0x8A5C, 0xD47D, 0x8A5D, 0xD47E, 0x8A5E, 0xD480, 0x8A5F, 0xD481, 0x8A60, 0xD482, 0x8A61, 0xD483, 0x8A62, + 0xD484, 0x8A63, 0xD485, 0x8A64, 0xD486, 0x8A65, 0xD487, 0x8A66, 0xD488, 0x8A67, 0xD489, 0x8A68, 0xD48A, 0x8A69, 0xD48B, 0x8A6A, + 0xD48C, 0x8A6B, 0xD48D, 0x8A6C, 0xD48E, 0x8A6D, 0xD48F, 0x8A6E, 0xD490, 0x8A6F, 0xD491, 0x8A70, 0xD492, 0x8A71, 0xD493, 0x8A72, + 0xD494, 0x8A73, 0xD495, 0x8A74, 0xD496, 0x8A75, 0xD497, 0x8A76, 0xD498, 0x8A77, 0xD499, 0x8A78, 0xD49A, 0x8A7A, 0xD49B, 0x8A7B, + 0xD49C, 0x8A7C, 0xD49D, 0x8A7D, 0xD49E, 0x8A7E, 0xD49F, 0x8A7F, 0xD4A0, 0x8A80, 0xD4A1, 0x6D74, 0xD4A2, 0x5BD3, 0xD4A3, 0x88D5, + 0xD4A4, 0x9884, 0xD4A5, 0x8C6B, 0xD4A6, 0x9A6D, 0xD4A7, 0x9E33, 0xD4A8, 0x6E0A, 0xD4A9, 0x51A4, 0xD4AA, 0x5143, 0xD4AB, 0x57A3, + 0xD4AC, 0x8881, 0xD4AD, 0x539F, 0xD4AE, 0x63F4, 0xD4AF, 0x8F95, 0xD4B0, 0x56ED, 0xD4B1, 0x5458, 0xD4B2, 0x5706, 0xD4B3, 0x733F, + 0xD4B4, 0x6E90, 0xD4B5, 0x7F18, 0xD4B6, 0x8FDC, 0xD4B7, 0x82D1, 0xD4B8, 0x613F, 0xD4B9, 0x6028, 0xD4BA, 0x9662, 0xD4BB, 0x66F0, + 0xD4BC, 0x7EA6, 0xD4BD, 0x8D8A, 0xD4BE, 0x8DC3, 0xD4BF, 0x94A5, 0xD4C0, 0x5CB3, 0xD4C1, 0x7CA4, 0xD4C2, 0x6708, 0xD4C3, 0x60A6, + 0xD4C4, 0x9605, 0xD4C5, 0x8018, 0xD4C6, 0x4E91, 0xD4C7, 0x90E7, 0xD4C8, 0x5300, 0xD4C9, 0x9668, 0xD4CA, 0x5141, 0xD4CB, 0x8FD0, + 0xD4CC, 0x8574, 0xD4CD, 0x915D, 0xD4CE, 0x6655, 0xD4CF, 0x97F5, 0xD4D0, 0x5B55, 0xD4D1, 0x531D, 0xD4D2, 0x7838, 0xD4D3, 0x6742, + 0xD4D4, 0x683D, 0xD4D5, 0x54C9, 0xD4D6, 0x707E, 0xD4D7, 0x5BB0, 0xD4D8, 0x8F7D, 0xD4D9, 0x518D, 0xD4DA, 0x5728, 0xD4DB, 0x54B1, + 0xD4DC, 0x6512, 0xD4DD, 0x6682, 0xD4DE, 0x8D5E, 0xD4DF, 0x8D43, 0xD4E0, 0x810F, 0xD4E1, 0x846C, 0xD4E2, 0x906D, 0xD4E3, 0x7CDF, + 0xD4E4, 0x51FF, 0xD4E5, 0x85FB, 0xD4E6, 0x67A3, 0xD4E7, 0x65E9, 0xD4E8, 0x6FA1, 0xD4E9, 0x86A4, 0xD4EA, 0x8E81, 0xD4EB, 0x566A, + 0xD4EC, 0x9020, 0xD4ED, 0x7682, 0xD4EE, 0x7076, 0xD4EF, 0x71E5, 0xD4F0, 0x8D23, 0xD4F1, 0x62E9, 0xD4F2, 0x5219, 0xD4F3, 0x6CFD, + 0xD4F4, 0x8D3C, 0xD4F5, 0x600E, 0xD4F6, 0x589E, 0xD4F7, 0x618E, 0xD4F8, 0x66FE, 0xD4F9, 0x8D60, 0xD4FA, 0x624E, 0xD4FB, 0x55B3, + 0xD4FC, 0x6E23, 0xD4FD, 0x672D, 0xD4FE, 0x8F67, 0xD540, 0x8A81, 0xD541, 0x8A82, 0xD542, 0x8A83, 0xD543, 0x8A84, 0xD544, 0x8A85, + 0xD545, 0x8A86, 0xD546, 0x8A87, 0xD547, 0x8A88, 0xD548, 0x8A8B, 0xD549, 0x8A8C, 0xD54A, 0x8A8D, 0xD54B, 0x8A8E, 0xD54C, 0x8A8F, + 0xD54D, 0x8A90, 0xD54E, 0x8A91, 0xD54F, 0x8A92, 0xD550, 0x8A94, 0xD551, 0x8A95, 0xD552, 0x8A96, 0xD553, 0x8A97, 0xD554, 0x8A98, + 0xD555, 0x8A99, 0xD556, 0x8A9A, 0xD557, 0x8A9B, 0xD558, 0x8A9C, 0xD559, 0x8A9D, 0xD55A, 0x8A9E, 0xD55B, 0x8A9F, 0xD55C, 0x8AA0, + 0xD55D, 0x8AA1, 0xD55E, 0x8AA2, 0xD55F, 0x8AA3, 0xD560, 0x8AA4, 0xD561, 0x8AA5, 0xD562, 0x8AA6, 0xD563, 0x8AA7, 0xD564, 0x8AA8, + 0xD565, 0x8AA9, 0xD566, 0x8AAA, 0xD567, 0x8AAB, 0xD568, 0x8AAC, 0xD569, 0x8AAD, 0xD56A, 0x8AAE, 0xD56B, 0x8AAF, 0xD56C, 0x8AB0, + 0xD56D, 0x8AB1, 0xD56E, 0x8AB2, 0xD56F, 0x8AB3, 0xD570, 0x8AB4, 0xD571, 0x8AB5, 0xD572, 0x8AB6, 0xD573, 0x8AB7, 0xD574, 0x8AB8, + 0xD575, 0x8AB9, 0xD576, 0x8ABA, 0xD577, 0x8ABB, 0xD578, 0x8ABC, 0xD579, 0x8ABD, 0xD57A, 0x8ABE, 0xD57B, 0x8ABF, 0xD57C, 0x8AC0, + 0xD57D, 0x8AC1, 0xD57E, 0x8AC2, 0xD580, 0x8AC3, 0xD581, 0x8AC4, 0xD582, 0x8AC5, 0xD583, 0x8AC6, 0xD584, 0x8AC7, 0xD585, 0x8AC8, + 0xD586, 0x8AC9, 0xD587, 0x8ACA, 0xD588, 0x8ACB, 0xD589, 0x8ACC, 0xD58A, 0x8ACD, 0xD58B, 0x8ACE, 0xD58C, 0x8ACF, 0xD58D, 0x8AD0, + 0xD58E, 0x8AD1, 0xD58F, 0x8AD2, 0xD590, 0x8AD3, 0xD591, 0x8AD4, 0xD592, 0x8AD5, 0xD593, 0x8AD6, 0xD594, 0x8AD7, 0xD595, 0x8AD8, + 0xD596, 0x8AD9, 0xD597, 0x8ADA, 0xD598, 0x8ADB, 0xD599, 0x8ADC, 0xD59A, 0x8ADD, 0xD59B, 0x8ADE, 0xD59C, 0x8ADF, 0xD59D, 0x8AE0, + 0xD59E, 0x8AE1, 0xD59F, 0x8AE2, 0xD5A0, 0x8AE3, 0xD5A1, 0x94E1, 0xD5A2, 0x95F8, 0xD5A3, 0x7728, 0xD5A4, 0x6805, 0xD5A5, 0x69A8, + 0xD5A6, 0x548B, 0xD5A7, 0x4E4D, 0xD5A8, 0x70B8, 0xD5A9, 0x8BC8, 0xD5AA, 0x6458, 0xD5AB, 0x658B, 0xD5AC, 0x5B85, 0xD5AD, 0x7A84, + 0xD5AE, 0x503A, 0xD5AF, 0x5BE8, 0xD5B0, 0x77BB, 0xD5B1, 0x6BE1, 0xD5B2, 0x8A79, 0xD5B3, 0x7C98, 0xD5B4, 0x6CBE, 0xD5B5, 0x76CF, + 0xD5B6, 0x65A9, 0xD5B7, 0x8F97, 0xD5B8, 0x5D2D, 0xD5B9, 0x5C55, 0xD5BA, 0x8638, 0xD5BB, 0x6808, 0xD5BC, 0x5360, 0xD5BD, 0x6218, + 0xD5BE, 0x7AD9, 0xD5BF, 0x6E5B, 0xD5C0, 0x7EFD, 0xD5C1, 0x6A1F, 0xD5C2, 0x7AE0, 0xD5C3, 0x5F70, 0xD5C4, 0x6F33, 0xD5C5, 0x5F20, + 0xD5C6, 0x638C, 0xD5C7, 0x6DA8, 0xD5C8, 0x6756, 0xD5C9, 0x4E08, 0xD5CA, 0x5E10, 0xD5CB, 0x8D26, 0xD5CC, 0x4ED7, 0xD5CD, 0x80C0, + 0xD5CE, 0x7634, 0xD5CF, 0x969C, 0xD5D0, 0x62DB, 0xD5D1, 0x662D, 0xD5D2, 0x627E, 0xD5D3, 0x6CBC, 0xD5D4, 0x8D75, 0xD5D5, 0x7167, + 0xD5D6, 0x7F69, 0xD5D7, 0x5146, 0xD5D8, 0x8087, 0xD5D9, 0x53EC, 0xD5DA, 0x906E, 0xD5DB, 0x6298, 0xD5DC, 0x54F2, 0xD5DD, 0x86F0, + 0xD5DE, 0x8F99, 0xD5DF, 0x8005, 0xD5E0, 0x9517, 0xD5E1, 0x8517, 0xD5E2, 0x8FD9, 0xD5E3, 0x6D59, 0xD5E4, 0x73CD, 0xD5E5, 0x659F, + 0xD5E6, 0x771F, 0xD5E7, 0x7504, 0xD5E8, 0x7827, 0xD5E9, 0x81FB, 0xD5EA, 0x8D1E, 0xD5EB, 0x9488, 0xD5EC, 0x4FA6, 0xD5ED, 0x6795, + 0xD5EE, 0x75B9, 0xD5EF, 0x8BCA, 0xD5F0, 0x9707, 0xD5F1, 0x632F, 0xD5F2, 0x9547, 0xD5F3, 0x9635, 0xD5F4, 0x84B8, 0xD5F5, 0x6323, + 0xD5F6, 0x7741, 0xD5F7, 0x5F81, 0xD5F8, 0x72F0, 0xD5F9, 0x4E89, 0xD5FA, 0x6014, 0xD5FB, 0x6574, 0xD5FC, 0x62EF, 0xD5FD, 0x6B63, + 0xD5FE, 0x653F, 0xD640, 0x8AE4, 0xD641, 0x8AE5, 0xD642, 0x8AE6, 0xD643, 0x8AE7, 0xD644, 0x8AE8, 0xD645, 0x8AE9, 0xD646, 0x8AEA, + 0xD647, 0x8AEB, 0xD648, 0x8AEC, 0xD649, 0x8AED, 0xD64A, 0x8AEE, 0xD64B, 0x8AEF, 0xD64C, 0x8AF0, 0xD64D, 0x8AF1, 0xD64E, 0x8AF2, + 0xD64F, 0x8AF3, 0xD650, 0x8AF4, 0xD651, 0x8AF5, 0xD652, 0x8AF6, 0xD653, 0x8AF7, 0xD654, 0x8AF8, 0xD655, 0x8AF9, 0xD656, 0x8AFA, + 0xD657, 0x8AFB, 0xD658, 0x8AFC, 0xD659, 0x8AFD, 0xD65A, 0x8AFE, 0xD65B, 0x8AFF, 0xD65C, 0x8B00, 0xD65D, 0x8B01, 0xD65E, 0x8B02, + 0xD65F, 0x8B03, 0xD660, 0x8B04, 0xD661, 0x8B05, 0xD662, 0x8B06, 0xD663, 0x8B08, 0xD664, 0x8B09, 0xD665, 0x8B0A, 0xD666, 0x8B0B, + 0xD667, 0x8B0C, 0xD668, 0x8B0D, 0xD669, 0x8B0E, 0xD66A, 0x8B0F, 0xD66B, 0x8B10, 0xD66C, 0x8B11, 0xD66D, 0x8B12, 0xD66E, 0x8B13, + 0xD66F, 0x8B14, 0xD670, 0x8B15, 0xD671, 0x8B16, 0xD672, 0x8B17, 0xD673, 0x8B18, 0xD674, 0x8B19, 0xD675, 0x8B1A, 0xD676, 0x8B1B, + 0xD677, 0x8B1C, 0xD678, 0x8B1D, 0xD679, 0x8B1E, 0xD67A, 0x8B1F, 0xD67B, 0x8B20, 0xD67C, 0x8B21, 0xD67D, 0x8B22, 0xD67E, 0x8B23, + 0xD680, 0x8B24, 0xD681, 0x8B25, 0xD682, 0x8B27, 0xD683, 0x8B28, 0xD684, 0x8B29, 0xD685, 0x8B2A, 0xD686, 0x8B2B, 0xD687, 0x8B2C, + 0xD688, 0x8B2D, 0xD689, 0x8B2E, 0xD68A, 0x8B2F, 0xD68B, 0x8B30, 0xD68C, 0x8B31, 0xD68D, 0x8B32, 0xD68E, 0x8B33, 0xD68F, 0x8B34, + 0xD690, 0x8B35, 0xD691, 0x8B36, 0xD692, 0x8B37, 0xD693, 0x8B38, 0xD694, 0x8B39, 0xD695, 0x8B3A, 0xD696, 0x8B3B, 0xD697, 0x8B3C, + 0xD698, 0x8B3D, 0xD699, 0x8B3E, 0xD69A, 0x8B3F, 0xD69B, 0x8B40, 0xD69C, 0x8B41, 0xD69D, 0x8B42, 0xD69E, 0x8B43, 0xD69F, 0x8B44, + 0xD6A0, 0x8B45, 0xD6A1, 0x5E27, 0xD6A2, 0x75C7, 0xD6A3, 0x90D1, 0xD6A4, 0x8BC1, 0xD6A5, 0x829D, 0xD6A6, 0x679D, 0xD6A7, 0x652F, + 0xD6A8, 0x5431, 0xD6A9, 0x8718, 0xD6AA, 0x77E5, 0xD6AB, 0x80A2, 0xD6AC, 0x8102, 0xD6AD, 0x6C41, 0xD6AE, 0x4E4B, 0xD6AF, 0x7EC7, + 0xD6B0, 0x804C, 0xD6B1, 0x76F4, 0xD6B2, 0x690D, 0xD6B3, 0x6B96, 0xD6B4, 0x6267, 0xD6B5, 0x503C, 0xD6B6, 0x4F84, 0xD6B7, 0x5740, + 0xD6B8, 0x6307, 0xD6B9, 0x6B62, 0xD6BA, 0x8DBE, 0xD6BB, 0x53EA, 0xD6BC, 0x65E8, 0xD6BD, 0x7EB8, 0xD6BE, 0x5FD7, 0xD6BF, 0x631A, + 0xD6C0, 0x63B7, 0xD6C1, 0x81F3, 0xD6C2, 0x81F4, 0xD6C3, 0x7F6E, 0xD6C4, 0x5E1C, 0xD6C5, 0x5CD9, 0xD6C6, 0x5236, 0xD6C7, 0x667A, + 0xD6C8, 0x79E9, 0xD6C9, 0x7A1A, 0xD6CA, 0x8D28, 0xD6CB, 0x7099, 0xD6CC, 0x75D4, 0xD6CD, 0x6EDE, 0xD6CE, 0x6CBB, 0xD6CF, 0x7A92, + 0xD6D0, 0x4E2D, 0xD6D1, 0x76C5, 0xD6D2, 0x5FE0, 0xD6D3, 0x949F, 0xD6D4, 0x8877, 0xD6D5, 0x7EC8, 0xD6D6, 0x79CD, 0xD6D7, 0x80BF, + 0xD6D8, 0x91CD, 0xD6D9, 0x4EF2, 0xD6DA, 0x4F17, 0xD6DB, 0x821F, 0xD6DC, 0x5468, 0xD6DD, 0x5DDE, 0xD6DE, 0x6D32, 0xD6DF, 0x8BCC, + 0xD6E0, 0x7CA5, 0xD6E1, 0x8F74, 0xD6E2, 0x8098, 0xD6E3, 0x5E1A, 0xD6E4, 0x5492, 0xD6E5, 0x76B1, 0xD6E6, 0x5B99, 0xD6E7, 0x663C, + 0xD6E8, 0x9AA4, 0xD6E9, 0x73E0, 0xD6EA, 0x682A, 0xD6EB, 0x86DB, 0xD6EC, 0x6731, 0xD6ED, 0x732A, 0xD6EE, 0x8BF8, 0xD6EF, 0x8BDB, + 0xD6F0, 0x9010, 0xD6F1, 0x7AF9, 0xD6F2, 0x70DB, 0xD6F3, 0x716E, 0xD6F4, 0x62C4, 0xD6F5, 0x77A9, 0xD6F6, 0x5631, 0xD6F7, 0x4E3B, + 0xD6F8, 0x8457, 0xD6F9, 0x67F1, 0xD6FA, 0x52A9, 0xD6FB, 0x86C0, 0xD6FC, 0x8D2E, 0xD6FD, 0x94F8, 0xD6FE, 0x7B51, 0xD740, 0x8B46, + 0xD741, 0x8B47, 0xD742, 0x8B48, 0xD743, 0x8B49, 0xD744, 0x8B4A, 0xD745, 0x8B4B, 0xD746, 0x8B4C, 0xD747, 0x8B4D, 0xD748, 0x8B4E, + 0xD749, 0x8B4F, 0xD74A, 0x8B50, 0xD74B, 0x8B51, 0xD74C, 0x8B52, 0xD74D, 0x8B53, 0xD74E, 0x8B54, 0xD74F, 0x8B55, 0xD750, 0x8B56, + 0xD751, 0x8B57, 0xD752, 0x8B58, 0xD753, 0x8B59, 0xD754, 0x8B5A, 0xD755, 0x8B5B, 0xD756, 0x8B5C, 0xD757, 0x8B5D, 0xD758, 0x8B5E, + 0xD759, 0x8B5F, 0xD75A, 0x8B60, 0xD75B, 0x8B61, 0xD75C, 0x8B62, 0xD75D, 0x8B63, 0xD75E, 0x8B64, 0xD75F, 0x8B65, 0xD760, 0x8B67, + 0xD761, 0x8B68, 0xD762, 0x8B69, 0xD763, 0x8B6A, 0xD764, 0x8B6B, 0xD765, 0x8B6D, 0xD766, 0x8B6E, 0xD767, 0x8B6F, 0xD768, 0x8B70, + 0xD769, 0x8B71, 0xD76A, 0x8B72, 0xD76B, 0x8B73, 0xD76C, 0x8B74, 0xD76D, 0x8B75, 0xD76E, 0x8B76, 0xD76F, 0x8B77, 0xD770, 0x8B78, + 0xD771, 0x8B79, 0xD772, 0x8B7A, 0xD773, 0x8B7B, 0xD774, 0x8B7C, 0xD775, 0x8B7D, 0xD776, 0x8B7E, 0xD777, 0x8B7F, 0xD778, 0x8B80, + 0xD779, 0x8B81, 0xD77A, 0x8B82, 0xD77B, 0x8B83, 0xD77C, 0x8B84, 0xD77D, 0x8B85, 0xD77E, 0x8B86, 0xD780, 0x8B87, 0xD781, 0x8B88, + 0xD782, 0x8B89, 0xD783, 0x8B8A, 0xD784, 0x8B8B, 0xD785, 0x8B8C, 0xD786, 0x8B8D, 0xD787, 0x8B8E, 0xD788, 0x8B8F, 0xD789, 0x8B90, + 0xD78A, 0x8B91, 0xD78B, 0x8B92, 0xD78C, 0x8B93, 0xD78D, 0x8B94, 0xD78E, 0x8B95, 0xD78F, 0x8B96, 0xD790, 0x8B97, 0xD791, 0x8B98, + 0xD792, 0x8B99, 0xD793, 0x8B9A, 0xD794, 0x8B9B, 0xD795, 0x8B9C, 0xD796, 0x8B9D, 0xD797, 0x8B9E, 0xD798, 0x8B9F, 0xD799, 0x8BAC, + 0xD79A, 0x8BB1, 0xD79B, 0x8BBB, 0xD79C, 0x8BC7, 0xD79D, 0x8BD0, 0xD79E, 0x8BEA, 0xD79F, 0x8C09, 0xD7A0, 0x8C1E, 0xD7A1, 0x4F4F, + 0xD7A2, 0x6CE8, 0xD7A3, 0x795D, 0xD7A4, 0x9A7B, 0xD7A5, 0x6293, 0xD7A6, 0x722A, 0xD7A7, 0x62FD, 0xD7A8, 0x4E13, 0xD7A9, 0x7816, + 0xD7AA, 0x8F6C, 0xD7AB, 0x64B0, 0xD7AC, 0x8D5A, 0xD7AD, 0x7BC6, 0xD7AE, 0x6869, 0xD7AF, 0x5E84, 0xD7B0, 0x88C5, 0xD7B1, 0x5986, + 0xD7B2, 0x649E, 0xD7B3, 0x58EE, 0xD7B4, 0x72B6, 0xD7B5, 0x690E, 0xD7B6, 0x9525, 0xD7B7, 0x8FFD, 0xD7B8, 0x8D58, 0xD7B9, 0x5760, + 0xD7BA, 0x7F00, 0xD7BB, 0x8C06, 0xD7BC, 0x51C6, 0xD7BD, 0x6349, 0xD7BE, 0x62D9, 0xD7BF, 0x5353, 0xD7C0, 0x684C, 0xD7C1, 0x7422, + 0xD7C2, 0x8301, 0xD7C3, 0x914C, 0xD7C4, 0x5544, 0xD7C5, 0x7740, 0xD7C6, 0x707C, 0xD7C7, 0x6D4A, 0xD7C8, 0x5179, 0xD7C9, 0x54A8, + 0xD7CA, 0x8D44, 0xD7CB, 0x59FF, 0xD7CC, 0x6ECB, 0xD7CD, 0x6DC4, 0xD7CE, 0x5B5C, 0xD7CF, 0x7D2B, 0xD7D0, 0x4ED4, 0xD7D1, 0x7C7D, + 0xD7D2, 0x6ED3, 0xD7D3, 0x5B50, 0xD7D4, 0x81EA, 0xD7D5, 0x6E0D, 0xD7D6, 0x5B57, 0xD7D7, 0x9B03, 0xD7D8, 0x68D5, 0xD7D9, 0x8E2A, + 0xD7DA, 0x5B97, 0xD7DB, 0x7EFC, 0xD7DC, 0x603B, 0xD7DD, 0x7EB5, 0xD7DE, 0x90B9, 0xD7DF, 0x8D70, 0xD7E0, 0x594F, 0xD7E1, 0x63CD, + 0xD7E2, 0x79DF, 0xD7E3, 0x8DB3, 0xD7E4, 0x5352, 0xD7E5, 0x65CF, 0xD7E6, 0x7956, 0xD7E7, 0x8BC5, 0xD7E8, 0x963B, 0xD7E9, 0x7EC4, + 0xD7EA, 0x94BB, 0xD7EB, 0x7E82, 0xD7EC, 0x5634, 0xD7ED, 0x9189, 0xD7EE, 0x6700, 0xD7EF, 0x7F6A, 0xD7F0, 0x5C0A, 0xD7F1, 0x9075, + 0xD7F2, 0x6628, 0xD7F3, 0x5DE6, 0xD7F4, 0x4F50, 0xD7F5, 0x67DE, 0xD7F6, 0x505A, 0xD7F7, 0x4F5C, 0xD7F8, 0x5750, 0xD7F9, 0x5EA7, + 0xD840, 0x8C38, 0xD841, 0x8C39, 0xD842, 0x8C3A, 0xD843, 0x8C3B, 0xD844, 0x8C3C, 0xD845, 0x8C3D, 0xD846, 0x8C3E, 0xD847, 0x8C3F, + 0xD848, 0x8C40, 0xD849, 0x8C42, 0xD84A, 0x8C43, 0xD84B, 0x8C44, 0xD84C, 0x8C45, 0xD84D, 0x8C48, 0xD84E, 0x8C4A, 0xD84F, 0x8C4B, + 0xD850, 0x8C4D, 0xD851, 0x8C4E, 0xD852, 0x8C4F, 0xD853, 0x8C50, 0xD854, 0x8C51, 0xD855, 0x8C52, 0xD856, 0x8C53, 0xD857, 0x8C54, + 0xD858, 0x8C56, 0xD859, 0x8C57, 0xD85A, 0x8C58, 0xD85B, 0x8C59, 0xD85C, 0x8C5B, 0xD85D, 0x8C5C, 0xD85E, 0x8C5D, 0xD85F, 0x8C5E, + 0xD860, 0x8C5F, 0xD861, 0x8C60, 0xD862, 0x8C63, 0xD863, 0x8C64, 0xD864, 0x8C65, 0xD865, 0x8C66, 0xD866, 0x8C67, 0xD867, 0x8C68, + 0xD868, 0x8C69, 0xD869, 0x8C6C, 0xD86A, 0x8C6D, 0xD86B, 0x8C6E, 0xD86C, 0x8C6F, 0xD86D, 0x8C70, 0xD86E, 0x8C71, 0xD86F, 0x8C72, + 0xD870, 0x8C74, 0xD871, 0x8C75, 0xD872, 0x8C76, 0xD873, 0x8C77, 0xD874, 0x8C7B, 0xD875, 0x8C7C, 0xD876, 0x8C7D, 0xD877, 0x8C7E, + 0xD878, 0x8C7F, 0xD879, 0x8C80, 0xD87A, 0x8C81, 0xD87B, 0x8C83, 0xD87C, 0x8C84, 0xD87D, 0x8C86, 0xD87E, 0x8C87, 0xD880, 0x8C88, + 0xD881, 0x8C8B, 0xD882, 0x8C8D, 0xD883, 0x8C8E, 0xD884, 0x8C8F, 0xD885, 0x8C90, 0xD886, 0x8C91, 0xD887, 0x8C92, 0xD888, 0x8C93, + 0xD889, 0x8C95, 0xD88A, 0x8C96, 0xD88B, 0x8C97, 0xD88C, 0x8C99, 0xD88D, 0x8C9A, 0xD88E, 0x8C9B, 0xD88F, 0x8C9C, 0xD890, 0x8C9D, + 0xD891, 0x8C9E, 0xD892, 0x8C9F, 0xD893, 0x8CA0, 0xD894, 0x8CA1, 0xD895, 0x8CA2, 0xD896, 0x8CA3, 0xD897, 0x8CA4, 0xD898, 0x8CA5, + 0xD899, 0x8CA6, 0xD89A, 0x8CA7, 0xD89B, 0x8CA8, 0xD89C, 0x8CA9, 0xD89D, 0x8CAA, 0xD89E, 0x8CAB, 0xD89F, 0x8CAC, 0xD8A0, 0x8CAD, + 0xD8A1, 0x4E8D, 0xD8A2, 0x4E0C, 0xD8A3, 0x5140, 0xD8A4, 0x4E10, 0xD8A5, 0x5EFF, 0xD8A6, 0x5345, 0xD8A7, 0x4E15, 0xD8A8, 0x4E98, + 0xD8A9, 0x4E1E, 0xD8AA, 0x9B32, 0xD8AB, 0x5B6C, 0xD8AC, 0x5669, 0xD8AD, 0x4E28, 0xD8AE, 0x79BA, 0xD8AF, 0x4E3F, 0xD8B0, 0x5315, + 0xD8B1, 0x4E47, 0xD8B2, 0x592D, 0xD8B3, 0x723B, 0xD8B4, 0x536E, 0xD8B5, 0x6C10, 0xD8B6, 0x56DF, 0xD8B7, 0x80E4, 0xD8B8, 0x9997, + 0xD8B9, 0x6BD3, 0xD8BA, 0x777E, 0xD8BB, 0x9F17, 0xD8BC, 0x4E36, 0xD8BD, 0x4E9F, 0xD8BE, 0x9F10, 0xD8BF, 0x4E5C, 0xD8C0, 0x4E69, + 0xD8C1, 0x4E93, 0xD8C2, 0x8288, 0xD8C3, 0x5B5B, 0xD8C4, 0x556C, 0xD8C5, 0x560F, 0xD8C6, 0x4EC4, 0xD8C7, 0x538D, 0xD8C8, 0x539D, + 0xD8C9, 0x53A3, 0xD8CA, 0x53A5, 0xD8CB, 0x53AE, 0xD8CC, 0x9765, 0xD8CD, 0x8D5D, 0xD8CE, 0x531A, 0xD8CF, 0x53F5, 0xD8D0, 0x5326, + 0xD8D1, 0x532E, 0xD8D2, 0x533E, 0xD8D3, 0x8D5C, 0xD8D4, 0x5366, 0xD8D5, 0x5363, 0xD8D6, 0x5202, 0xD8D7, 0x5208, 0xD8D8, 0x520E, + 0xD8D9, 0x522D, 0xD8DA, 0x5233, 0xD8DB, 0x523F, 0xD8DC, 0x5240, 0xD8DD, 0x524C, 0xD8DE, 0x525E, 0xD8DF, 0x5261, 0xD8E0, 0x525C, + 0xD8E1, 0x84AF, 0xD8E2, 0x527D, 0xD8E3, 0x5282, 0xD8E4, 0x5281, 0xD8E5, 0x5290, 0xD8E6, 0x5293, 0xD8E7, 0x5182, 0xD8E8, 0x7F54, + 0xD8E9, 0x4EBB, 0xD8EA, 0x4EC3, 0xD8EB, 0x4EC9, 0xD8EC, 0x4EC2, 0xD8ED, 0x4EE8, 0xD8EE, 0x4EE1, 0xD8EF, 0x4EEB, 0xD8F0, 0x4EDE, + 0xD8F1, 0x4F1B, 0xD8F2, 0x4EF3, 0xD8F3, 0x4F22, 0xD8F4, 0x4F64, 0xD8F5, 0x4EF5, 0xD8F6, 0x4F25, 0xD8F7, 0x4F27, 0xD8F8, 0x4F09, + 0xD8F9, 0x4F2B, 0xD8FA, 0x4F5E, 0xD8FB, 0x4F67, 0xD8FC, 0x6538, 0xD8FD, 0x4F5A, 0xD8FE, 0x4F5D, 0xD940, 0x8CAE, 0xD941, 0x8CAF, + 0xD942, 0x8CB0, 0xD943, 0x8CB1, 0xD944, 0x8CB2, 0xD945, 0x8CB3, 0xD946, 0x8CB4, 0xD947, 0x8CB5, 0xD948, 0x8CB6, 0xD949, 0x8CB7, + 0xD94A, 0x8CB8, 0xD94B, 0x8CB9, 0xD94C, 0x8CBA, 0xD94D, 0x8CBB, 0xD94E, 0x8CBC, 0xD94F, 0x8CBD, 0xD950, 0x8CBE, 0xD951, 0x8CBF, + 0xD952, 0x8CC0, 0xD953, 0x8CC1, 0xD954, 0x8CC2, 0xD955, 0x8CC3, 0xD956, 0x8CC4, 0xD957, 0x8CC5, 0xD958, 0x8CC6, 0xD959, 0x8CC7, + 0xD95A, 0x8CC8, 0xD95B, 0x8CC9, 0xD95C, 0x8CCA, 0xD95D, 0x8CCB, 0xD95E, 0x8CCC, 0xD95F, 0x8CCD, 0xD960, 0x8CCE, 0xD961, 0x8CCF, + 0xD962, 0x8CD0, 0xD963, 0x8CD1, 0xD964, 0x8CD2, 0xD965, 0x8CD3, 0xD966, 0x8CD4, 0xD967, 0x8CD5, 0xD968, 0x8CD6, 0xD969, 0x8CD7, + 0xD96A, 0x8CD8, 0xD96B, 0x8CD9, 0xD96C, 0x8CDA, 0xD96D, 0x8CDB, 0xD96E, 0x8CDC, 0xD96F, 0x8CDD, 0xD970, 0x8CDE, 0xD971, 0x8CDF, + 0xD972, 0x8CE0, 0xD973, 0x8CE1, 0xD974, 0x8CE2, 0xD975, 0x8CE3, 0xD976, 0x8CE4, 0xD977, 0x8CE5, 0xD978, 0x8CE6, 0xD979, 0x8CE7, + 0xD97A, 0x8CE8, 0xD97B, 0x8CE9, 0xD97C, 0x8CEA, 0xD97D, 0x8CEB, 0xD97E, 0x8CEC, 0xD980, 0x8CED, 0xD981, 0x8CEE, 0xD982, 0x8CEF, + 0xD983, 0x8CF0, 0xD984, 0x8CF1, 0xD985, 0x8CF2, 0xD986, 0x8CF3, 0xD987, 0x8CF4, 0xD988, 0x8CF5, 0xD989, 0x8CF6, 0xD98A, 0x8CF7, + 0xD98B, 0x8CF8, 0xD98C, 0x8CF9, 0xD98D, 0x8CFA, 0xD98E, 0x8CFB, 0xD98F, 0x8CFC, 0xD990, 0x8CFD, 0xD991, 0x8CFE, 0xD992, 0x8CFF, + 0xD993, 0x8D00, 0xD994, 0x8D01, 0xD995, 0x8D02, 0xD996, 0x8D03, 0xD997, 0x8D04, 0xD998, 0x8D05, 0xD999, 0x8D06, 0xD99A, 0x8D07, + 0xD99B, 0x8D08, 0xD99C, 0x8D09, 0xD99D, 0x8D0A, 0xD99E, 0x8D0B, 0xD99F, 0x8D0C, 0xD9A0, 0x8D0D, 0xD9A1, 0x4F5F, 0xD9A2, 0x4F57, + 0xD9A3, 0x4F32, 0xD9A4, 0x4F3D, 0xD9A5, 0x4F76, 0xD9A6, 0x4F74, 0xD9A7, 0x4F91, 0xD9A8, 0x4F89, 0xD9A9, 0x4F83, 0xD9AA, 0x4F8F, + 0xD9AB, 0x4F7E, 0xD9AC, 0x4F7B, 0xD9AD, 0x4FAA, 0xD9AE, 0x4F7C, 0xD9AF, 0x4FAC, 0xD9B0, 0x4F94, 0xD9B1, 0x4FE6, 0xD9B2, 0x4FE8, + 0xD9B3, 0x4FEA, 0xD9B4, 0x4FC5, 0xD9B5, 0x4FDA, 0xD9B6, 0x4FE3, 0xD9B7, 0x4FDC, 0xD9B8, 0x4FD1, 0xD9B9, 0x4FDF, 0xD9BA, 0x4FF8, + 0xD9BB, 0x5029, 0xD9BC, 0x504C, 0xD9BD, 0x4FF3, 0xD9BE, 0x502C, 0xD9BF, 0x500F, 0xD9C0, 0x502E, 0xD9C1, 0x502D, 0xD9C2, 0x4FFE, + 0xD9C3, 0x501C, 0xD9C4, 0x500C, 0xD9C5, 0x5025, 0xD9C6, 0x5028, 0xD9C7, 0x507E, 0xD9C8, 0x5043, 0xD9C9, 0x5055, 0xD9CA, 0x5048, + 0xD9CB, 0x504E, 0xD9CC, 0x506C, 0xD9CD, 0x507B, 0xD9CE, 0x50A5, 0xD9CF, 0x50A7, 0xD9D0, 0x50A9, 0xD9D1, 0x50BA, 0xD9D2, 0x50D6, + 0xD9D3, 0x5106, 0xD9D4, 0x50ED, 0xD9D5, 0x50EC, 0xD9D6, 0x50E6, 0xD9D7, 0x50EE, 0xD9D8, 0x5107, 0xD9D9, 0x510B, 0xD9DA, 0x4EDD, + 0xD9DB, 0x6C3D, 0xD9DC, 0x4F58, 0xD9DD, 0x4F65, 0xD9DE, 0x4FCE, 0xD9DF, 0x9FA0, 0xD9E0, 0x6C46, 0xD9E1, 0x7C74, 0xD9E2, 0x516E, + 0xD9E3, 0x5DFD, 0xD9E4, 0x9EC9, 0xD9E5, 0x9998, 0xD9E6, 0x5181, 0xD9E7, 0x5914, 0xD9E8, 0x52F9, 0xD9E9, 0x530D, 0xD9EA, 0x8A07, + 0xD9EB, 0x5310, 0xD9EC, 0x51EB, 0xD9ED, 0x5919, 0xD9EE, 0x5155, 0xD9EF, 0x4EA0, 0xD9F0, 0x5156, 0xD9F1, 0x4EB3, 0xD9F2, 0x886E, + 0xD9F3, 0x88A4, 0xD9F4, 0x4EB5, 0xD9F5, 0x8114, 0xD9F6, 0x88D2, 0xD9F7, 0x7980, 0xD9F8, 0x5B34, 0xD9F9, 0x8803, 0xD9FA, 0x7FB8, + 0xD9FB, 0x51AB, 0xD9FC, 0x51B1, 0xD9FD, 0x51BD, 0xD9FE, 0x51BC, 0xDA40, 0x8D0E, 0xDA41, 0x8D0F, 0xDA42, 0x8D10, 0xDA43, 0x8D11, + 0xDA44, 0x8D12, 0xDA45, 0x8D13, 0xDA46, 0x8D14, 0xDA47, 0x8D15, 0xDA48, 0x8D16, 0xDA49, 0x8D17, 0xDA4A, 0x8D18, 0xDA4B, 0x8D19, + 0xDA4C, 0x8D1A, 0xDA4D, 0x8D1B, 0xDA4E, 0x8D1C, 0xDA4F, 0x8D20, 0xDA50, 0x8D51, 0xDA51, 0x8D52, 0xDA52, 0x8D57, 0xDA53, 0x8D5F, + 0xDA54, 0x8D65, 0xDA55, 0x8D68, 0xDA56, 0x8D69, 0xDA57, 0x8D6A, 0xDA58, 0x8D6C, 0xDA59, 0x8D6E, 0xDA5A, 0x8D6F, 0xDA5B, 0x8D71, + 0xDA5C, 0x8D72, 0xDA5D, 0x8D78, 0xDA5E, 0x8D79, 0xDA5F, 0x8D7A, 0xDA60, 0x8D7B, 0xDA61, 0x8D7C, 0xDA62, 0x8D7D, 0xDA63, 0x8D7E, + 0xDA64, 0x8D7F, 0xDA65, 0x8D80, 0xDA66, 0x8D82, 0xDA67, 0x8D83, 0xDA68, 0x8D86, 0xDA69, 0x8D87, 0xDA6A, 0x8D88, 0xDA6B, 0x8D89, + 0xDA6C, 0x8D8C, 0xDA6D, 0x8D8D, 0xDA6E, 0x8D8E, 0xDA6F, 0x8D8F, 0xDA70, 0x8D90, 0xDA71, 0x8D92, 0xDA72, 0x8D93, 0xDA73, 0x8D95, + 0xDA74, 0x8D96, 0xDA75, 0x8D97, 0xDA76, 0x8D98, 0xDA77, 0x8D99, 0xDA78, 0x8D9A, 0xDA79, 0x8D9B, 0xDA7A, 0x8D9C, 0xDA7B, 0x8D9D, + 0xDA7C, 0x8D9E, 0xDA7D, 0x8DA0, 0xDA7E, 0x8DA1, 0xDA80, 0x8DA2, 0xDA81, 0x8DA4, 0xDA82, 0x8DA5, 0xDA83, 0x8DA6, 0xDA84, 0x8DA7, + 0xDA85, 0x8DA8, 0xDA86, 0x8DA9, 0xDA87, 0x8DAA, 0xDA88, 0x8DAB, 0xDA89, 0x8DAC, 0xDA8A, 0x8DAD, 0xDA8B, 0x8DAE, 0xDA8C, 0x8DAF, + 0xDA8D, 0x8DB0, 0xDA8E, 0x8DB2, 0xDA8F, 0x8DB6, 0xDA90, 0x8DB7, 0xDA91, 0x8DB9, 0xDA92, 0x8DBB, 0xDA93, 0x8DBD, 0xDA94, 0x8DC0, + 0xDA95, 0x8DC1, 0xDA96, 0x8DC2, 0xDA97, 0x8DC5, 0xDA98, 0x8DC7, 0xDA99, 0x8DC8, 0xDA9A, 0x8DC9, 0xDA9B, 0x8DCA, 0xDA9C, 0x8DCD, + 0xDA9D, 0x8DD0, 0xDA9E, 0x8DD2, 0xDA9F, 0x8DD3, 0xDAA0, 0x8DD4, 0xDAA1, 0x51C7, 0xDAA2, 0x5196, 0xDAA3, 0x51A2, 0xDAA4, 0x51A5, + 0xDAA5, 0x8BA0, 0xDAA6, 0x8BA6, 0xDAA7, 0x8BA7, 0xDAA8, 0x8BAA, 0xDAA9, 0x8BB4, 0xDAAA, 0x8BB5, 0xDAAB, 0x8BB7, 0xDAAC, 0x8BC2, + 0xDAAD, 0x8BC3, 0xDAAE, 0x8BCB, 0xDAAF, 0x8BCF, 0xDAB0, 0x8BCE, 0xDAB1, 0x8BD2, 0xDAB2, 0x8BD3, 0xDAB3, 0x8BD4, 0xDAB4, 0x8BD6, + 0xDAB5, 0x8BD8, 0xDAB6, 0x8BD9, 0xDAB7, 0x8BDC, 0xDAB8, 0x8BDF, 0xDAB9, 0x8BE0, 0xDABA, 0x8BE4, 0xDABB, 0x8BE8, 0xDABC, 0x8BE9, + 0xDABD, 0x8BEE, 0xDABE, 0x8BF0, 0xDABF, 0x8BF3, 0xDAC0, 0x8BF6, 0xDAC1, 0x8BF9, 0xDAC2, 0x8BFC, 0xDAC3, 0x8BFF, 0xDAC4, 0x8C00, + 0xDAC5, 0x8C02, 0xDAC6, 0x8C04, 0xDAC7, 0x8C07, 0xDAC8, 0x8C0C, 0xDAC9, 0x8C0F, 0xDACA, 0x8C11, 0xDACB, 0x8C12, 0xDACC, 0x8C14, + 0xDACD, 0x8C15, 0xDACE, 0x8C16, 0xDACF, 0x8C19, 0xDAD0, 0x8C1B, 0xDAD1, 0x8C18, 0xDAD2, 0x8C1D, 0xDAD3, 0x8C1F, 0xDAD4, 0x8C20, + 0xDAD5, 0x8C21, 0xDAD6, 0x8C25, 0xDAD7, 0x8C27, 0xDAD8, 0x8C2A, 0xDAD9, 0x8C2B, 0xDADA, 0x8C2E, 0xDADB, 0x8C2F, 0xDADC, 0x8C32, + 0xDADD, 0x8C33, 0xDADE, 0x8C35, 0xDADF, 0x8C36, 0xDAE0, 0x5369, 0xDAE1, 0x537A, 0xDAE2, 0x961D, 0xDAE3, 0x9622, 0xDAE4, 0x9621, + 0xDAE5, 0x9631, 0xDAE6, 0x962A, 0xDAE7, 0x963D, 0xDAE8, 0x963C, 0xDAE9, 0x9642, 0xDAEA, 0x9649, 0xDAEB, 0x9654, 0xDAEC, 0x965F, + 0xDAED, 0x9667, 0xDAEE, 0x966C, 0xDAEF, 0x9672, 0xDAF0, 0x9674, 0xDAF1, 0x9688, 0xDAF2, 0x968D, 0xDAF3, 0x9697, 0xDAF4, 0x96B0, + 0xDAF5, 0x9097, 0xDAF6, 0x909B, 0xDAF7, 0x909D, 0xDAF8, 0x9099, 0xDAF9, 0x90AC, 0xDAFA, 0x90A1, 0xDAFB, 0x90B4, 0xDAFC, 0x90B3, + 0xDAFD, 0x90B6, 0xDAFE, 0x90BA, 0xDB40, 0x8DD5, 0xDB41, 0x8DD8, 0xDB42, 0x8DD9, 0xDB43, 0x8DDC, 0xDB44, 0x8DE0, 0xDB45, 0x8DE1, + 0xDB46, 0x8DE2, 0xDB47, 0x8DE5, 0xDB48, 0x8DE6, 0xDB49, 0x8DE7, 0xDB4A, 0x8DE9, 0xDB4B, 0x8DED, 0xDB4C, 0x8DEE, 0xDB4D, 0x8DF0, + 0xDB4E, 0x8DF1, 0xDB4F, 0x8DF2, 0xDB50, 0x8DF4, 0xDB51, 0x8DF6, 0xDB52, 0x8DFC, 0xDB53, 0x8DFE, 0xDB54, 0x8DFF, 0xDB55, 0x8E00, + 0xDB56, 0x8E01, 0xDB57, 0x8E02, 0xDB58, 0x8E03, 0xDB59, 0x8E04, 0xDB5A, 0x8E06, 0xDB5B, 0x8E07, 0xDB5C, 0x8E08, 0xDB5D, 0x8E0B, + 0xDB5E, 0x8E0D, 0xDB5F, 0x8E0E, 0xDB60, 0x8E10, 0xDB61, 0x8E11, 0xDB62, 0x8E12, 0xDB63, 0x8E13, 0xDB64, 0x8E15, 0xDB65, 0x8E16, + 0xDB66, 0x8E17, 0xDB67, 0x8E18, 0xDB68, 0x8E19, 0xDB69, 0x8E1A, 0xDB6A, 0x8E1B, 0xDB6B, 0x8E1C, 0xDB6C, 0x8E20, 0xDB6D, 0x8E21, + 0xDB6E, 0x8E24, 0xDB6F, 0x8E25, 0xDB70, 0x8E26, 0xDB71, 0x8E27, 0xDB72, 0x8E28, 0xDB73, 0x8E2B, 0xDB74, 0x8E2D, 0xDB75, 0x8E30, + 0xDB76, 0x8E32, 0xDB77, 0x8E33, 0xDB78, 0x8E34, 0xDB79, 0x8E36, 0xDB7A, 0x8E37, 0xDB7B, 0x8E38, 0xDB7C, 0x8E3B, 0xDB7D, 0x8E3C, + 0xDB7E, 0x8E3E, 0xDB80, 0x8E3F, 0xDB81, 0x8E43, 0xDB82, 0x8E45, 0xDB83, 0x8E46, 0xDB84, 0x8E4C, 0xDB85, 0x8E4D, 0xDB86, 0x8E4E, + 0xDB87, 0x8E4F, 0xDB88, 0x8E50, 0xDB89, 0x8E53, 0xDB8A, 0x8E54, 0xDB8B, 0x8E55, 0xDB8C, 0x8E56, 0xDB8D, 0x8E57, 0xDB8E, 0x8E58, + 0xDB8F, 0x8E5A, 0xDB90, 0x8E5B, 0xDB91, 0x8E5C, 0xDB92, 0x8E5D, 0xDB93, 0x8E5E, 0xDB94, 0x8E5F, 0xDB95, 0x8E60, 0xDB96, 0x8E61, + 0xDB97, 0x8E62, 0xDB98, 0x8E63, 0xDB99, 0x8E64, 0xDB9A, 0x8E65, 0xDB9B, 0x8E67, 0xDB9C, 0x8E68, 0xDB9D, 0x8E6A, 0xDB9E, 0x8E6B, + 0xDB9F, 0x8E6E, 0xDBA0, 0x8E71, 0xDBA1, 0x90B8, 0xDBA2, 0x90B0, 0xDBA3, 0x90CF, 0xDBA4, 0x90C5, 0xDBA5, 0x90BE, 0xDBA6, 0x90D0, + 0xDBA7, 0x90C4, 0xDBA8, 0x90C7, 0xDBA9, 0x90D3, 0xDBAA, 0x90E6, 0xDBAB, 0x90E2, 0xDBAC, 0x90DC, 0xDBAD, 0x90D7, 0xDBAE, 0x90DB, + 0xDBAF, 0x90EB, 0xDBB0, 0x90EF, 0xDBB1, 0x90FE, 0xDBB2, 0x9104, 0xDBB3, 0x9122, 0xDBB4, 0x911E, 0xDBB5, 0x9123, 0xDBB6, 0x9131, + 0xDBB7, 0x912F, 0xDBB8, 0x9139, 0xDBB9, 0x9143, 0xDBBA, 0x9146, 0xDBBB, 0x520D, 0xDBBC, 0x5942, 0xDBBD, 0x52A2, 0xDBBE, 0x52AC, + 0xDBBF, 0x52AD, 0xDBC0, 0x52BE, 0xDBC1, 0x54FF, 0xDBC2, 0x52D0, 0xDBC3, 0x52D6, 0xDBC4, 0x52F0, 0xDBC5, 0x53DF, 0xDBC6, 0x71EE, + 0xDBC7, 0x77CD, 0xDBC8, 0x5EF4, 0xDBC9, 0x51F5, 0xDBCA, 0x51FC, 0xDBCB, 0x9B2F, 0xDBCC, 0x53B6, 0xDBCD, 0x5F01, 0xDBCE, 0x755A, + 0xDBCF, 0x5DEF, 0xDBD0, 0x574C, 0xDBD1, 0x57A9, 0xDBD2, 0x57A1, 0xDBD3, 0x587E, 0xDBD4, 0x58BC, 0xDBD5, 0x58C5, 0xDBD6, 0x58D1, + 0xDBD7, 0x5729, 0xDBD8, 0x572C, 0xDBD9, 0x572A, 0xDBDA, 0x5733, 0xDBDB, 0x5739, 0xDBDC, 0x572E, 0xDBDD, 0x572F, 0xDBDE, 0x575C, + 0xDBDF, 0x573B, 0xDBE0, 0x5742, 0xDBE1, 0x5769, 0xDBE2, 0x5785, 0xDBE3, 0x576B, 0xDBE4, 0x5786, 0xDBE5, 0x577C, 0xDBE6, 0x577B, + 0xDBE7, 0x5768, 0xDBE8, 0x576D, 0xDBE9, 0x5776, 0xDBEA, 0x5773, 0xDBEB, 0x57AD, 0xDBEC, 0x57A4, 0xDBED, 0x578C, 0xDBEE, 0x57B2, + 0xDBEF, 0x57CF, 0xDBF0, 0x57A7, 0xDBF1, 0x57B4, 0xDBF2, 0x5793, 0xDBF3, 0x57A0, 0xDBF4, 0x57D5, 0xDBF5, 0x57D8, 0xDBF6, 0x57DA, + 0xDBF7, 0x57D9, 0xDBF8, 0x57D2, 0xDBF9, 0x57B8, 0xDBFA, 0x57F4, 0xDBFB, 0x57EF, 0xDBFC, 0x57F8, 0xDBFD, 0x57E4, 0xDBFE, 0x57DD, + 0xDC40, 0x8E73, 0xDC41, 0x8E75, 0xDC42, 0x8E77, 0xDC43, 0x8E78, 0xDC44, 0x8E79, 0xDC45, 0x8E7A, 0xDC46, 0x8E7B, 0xDC47, 0x8E7D, + 0xDC48, 0x8E7E, 0xDC49, 0x8E80, 0xDC4A, 0x8E82, 0xDC4B, 0x8E83, 0xDC4C, 0x8E84, 0xDC4D, 0x8E86, 0xDC4E, 0x8E88, 0xDC4F, 0x8E89, + 0xDC50, 0x8E8A, 0xDC51, 0x8E8B, 0xDC52, 0x8E8C, 0xDC53, 0x8E8D, 0xDC54, 0x8E8E, 0xDC55, 0x8E91, 0xDC56, 0x8E92, 0xDC57, 0x8E93, + 0xDC58, 0x8E95, 0xDC59, 0x8E96, 0xDC5A, 0x8E97, 0xDC5B, 0x8E98, 0xDC5C, 0x8E99, 0xDC5D, 0x8E9A, 0xDC5E, 0x8E9B, 0xDC5F, 0x8E9D, + 0xDC60, 0x8E9F, 0xDC61, 0x8EA0, 0xDC62, 0x8EA1, 0xDC63, 0x8EA2, 0xDC64, 0x8EA3, 0xDC65, 0x8EA4, 0xDC66, 0x8EA5, 0xDC67, 0x8EA6, + 0xDC68, 0x8EA7, 0xDC69, 0x8EA8, 0xDC6A, 0x8EA9, 0xDC6B, 0x8EAA, 0xDC6C, 0x8EAD, 0xDC6D, 0x8EAE, 0xDC6E, 0x8EB0, 0xDC6F, 0x8EB1, + 0xDC70, 0x8EB3, 0xDC71, 0x8EB4, 0xDC72, 0x8EB5, 0xDC73, 0x8EB6, 0xDC74, 0x8EB7, 0xDC75, 0x8EB8, 0xDC76, 0x8EB9, 0xDC77, 0x8EBB, + 0xDC78, 0x8EBC, 0xDC79, 0x8EBD, 0xDC7A, 0x8EBE, 0xDC7B, 0x8EBF, 0xDC7C, 0x8EC0, 0xDC7D, 0x8EC1, 0xDC7E, 0x8EC2, 0xDC80, 0x8EC3, + 0xDC81, 0x8EC4, 0xDC82, 0x8EC5, 0xDC83, 0x8EC6, 0xDC84, 0x8EC7, 0xDC85, 0x8EC8, 0xDC86, 0x8EC9, 0xDC87, 0x8ECA, 0xDC88, 0x8ECB, + 0xDC89, 0x8ECC, 0xDC8A, 0x8ECD, 0xDC8B, 0x8ECF, 0xDC8C, 0x8ED0, 0xDC8D, 0x8ED1, 0xDC8E, 0x8ED2, 0xDC8F, 0x8ED3, 0xDC90, 0x8ED4, + 0xDC91, 0x8ED5, 0xDC92, 0x8ED6, 0xDC93, 0x8ED7, 0xDC94, 0x8ED8, 0xDC95, 0x8ED9, 0xDC96, 0x8EDA, 0xDC97, 0x8EDB, 0xDC98, 0x8EDC, + 0xDC99, 0x8EDD, 0xDC9A, 0x8EDE, 0xDC9B, 0x8EDF, 0xDC9C, 0x8EE0, 0xDC9D, 0x8EE1, 0xDC9E, 0x8EE2, 0xDC9F, 0x8EE3, 0xDCA0, 0x8EE4, + 0xDCA1, 0x580B, 0xDCA2, 0x580D, 0xDCA3, 0x57FD, 0xDCA4, 0x57ED, 0xDCA5, 0x5800, 0xDCA6, 0x581E, 0xDCA7, 0x5819, 0xDCA8, 0x5844, + 0xDCA9, 0x5820, 0xDCAA, 0x5865, 0xDCAB, 0x586C, 0xDCAC, 0x5881, 0xDCAD, 0x5889, 0xDCAE, 0x589A, 0xDCAF, 0x5880, 0xDCB0, 0x99A8, + 0xDCB1, 0x9F19, 0xDCB2, 0x61FF, 0xDCB3, 0x8279, 0xDCB4, 0x827D, 0xDCB5, 0x827F, 0xDCB6, 0x828F, 0xDCB7, 0x828A, 0xDCB8, 0x82A8, + 0xDCB9, 0x8284, 0xDCBA, 0x828E, 0xDCBB, 0x8291, 0xDCBC, 0x8297, 0xDCBD, 0x8299, 0xDCBE, 0x82AB, 0xDCBF, 0x82B8, 0xDCC0, 0x82BE, + 0xDCC1, 0x82B0, 0xDCC2, 0x82C8, 0xDCC3, 0x82CA, 0xDCC4, 0x82E3, 0xDCC5, 0x8298, 0xDCC6, 0x82B7, 0xDCC7, 0x82AE, 0xDCC8, 0x82CB, + 0xDCC9, 0x82CC, 0xDCCA, 0x82C1, 0xDCCB, 0x82A9, 0xDCCC, 0x82B4, 0xDCCD, 0x82A1, 0xDCCE, 0x82AA, 0xDCCF, 0x829F, 0xDCD0, 0x82C4, + 0xDCD1, 0x82CE, 0xDCD2, 0x82A4, 0xDCD3, 0x82E1, 0xDCD4, 0x8309, 0xDCD5, 0x82F7, 0xDCD6, 0x82E4, 0xDCD7, 0x830F, 0xDCD8, 0x8307, + 0xDCD9, 0x82DC, 0xDCDA, 0x82F4, 0xDCDB, 0x82D2, 0xDCDC, 0x82D8, 0xDCDD, 0x830C, 0xDCDE, 0x82FB, 0xDCDF, 0x82D3, 0xDCE0, 0x8311, + 0xDCE1, 0x831A, 0xDCE2, 0x8306, 0xDCE3, 0x8314, 0xDCE4, 0x8315, 0xDCE5, 0x82E0, 0xDCE6, 0x82D5, 0xDCE7, 0x831C, 0xDCE8, 0x8351, + 0xDCE9, 0x835B, 0xDCEA, 0x835C, 0xDCEB, 0x8308, 0xDCEC, 0x8392, 0xDCED, 0x833C, 0xDCEE, 0x8334, 0xDCEF, 0x8331, 0xDCF0, 0x839B, + 0xDCF1, 0x835E, 0xDCF2, 0x832F, 0xDCF3, 0x834F, 0xDCF4, 0x8347, 0xDCF5, 0x8343, 0xDCF6, 0x835F, 0xDCF7, 0x8340, 0xDCF8, 0x8317, + 0xDCF9, 0x8360, 0xDCFA, 0x832D, 0xDCFB, 0x833A, 0xDCFC, 0x8333, 0xDCFD, 0x8366, 0xDCFE, 0x8365, 0xDD40, 0x8EE5, 0xDD41, 0x8EE6, + 0xDD42, 0x8EE7, 0xDD43, 0x8EE8, 0xDD44, 0x8EE9, 0xDD45, 0x8EEA, 0xDD46, 0x8EEB, 0xDD47, 0x8EEC, 0xDD48, 0x8EED, 0xDD49, 0x8EEE, + 0xDD4A, 0x8EEF, 0xDD4B, 0x8EF0, 0xDD4C, 0x8EF1, 0xDD4D, 0x8EF2, 0xDD4E, 0x8EF3, 0xDD4F, 0x8EF4, 0xDD50, 0x8EF5, 0xDD51, 0x8EF6, + 0xDD52, 0x8EF7, 0xDD53, 0x8EF8, 0xDD54, 0x8EF9, 0xDD55, 0x8EFA, 0xDD56, 0x8EFB, 0xDD57, 0x8EFC, 0xDD58, 0x8EFD, 0xDD59, 0x8EFE, + 0xDD5A, 0x8EFF, 0xDD5B, 0x8F00, 0xDD5C, 0x8F01, 0xDD5D, 0x8F02, 0xDD5E, 0x8F03, 0xDD5F, 0x8F04, 0xDD60, 0x8F05, 0xDD61, 0x8F06, + 0xDD62, 0x8F07, 0xDD63, 0x8F08, 0xDD64, 0x8F09, 0xDD65, 0x8F0A, 0xDD66, 0x8F0B, 0xDD67, 0x8F0C, 0xDD68, 0x8F0D, 0xDD69, 0x8F0E, + 0xDD6A, 0x8F0F, 0xDD6B, 0x8F10, 0xDD6C, 0x8F11, 0xDD6D, 0x8F12, 0xDD6E, 0x8F13, 0xDD6F, 0x8F14, 0xDD70, 0x8F15, 0xDD71, 0x8F16, + 0xDD72, 0x8F17, 0xDD73, 0x8F18, 0xDD74, 0x8F19, 0xDD75, 0x8F1A, 0xDD76, 0x8F1B, 0xDD77, 0x8F1C, 0xDD78, 0x8F1D, 0xDD79, 0x8F1E, + 0xDD7A, 0x8F1F, 0xDD7B, 0x8F20, 0xDD7C, 0x8F21, 0xDD7D, 0x8F22, 0xDD7E, 0x8F23, 0xDD80, 0x8F24, 0xDD81, 0x8F25, 0xDD82, 0x8F26, + 0xDD83, 0x8F27, 0xDD84, 0x8F28, 0xDD85, 0x8F29, 0xDD86, 0x8F2A, 0xDD87, 0x8F2B, 0xDD88, 0x8F2C, 0xDD89, 0x8F2D, 0xDD8A, 0x8F2E, + 0xDD8B, 0x8F2F, 0xDD8C, 0x8F30, 0xDD8D, 0x8F31, 0xDD8E, 0x8F32, 0xDD8F, 0x8F33, 0xDD90, 0x8F34, 0xDD91, 0x8F35, 0xDD92, 0x8F36, + 0xDD93, 0x8F37, 0xDD94, 0x8F38, 0xDD95, 0x8F39, 0xDD96, 0x8F3A, 0xDD97, 0x8F3B, 0xDD98, 0x8F3C, 0xDD99, 0x8F3D, 0xDD9A, 0x8F3E, + 0xDD9B, 0x8F3F, 0xDD9C, 0x8F40, 0xDD9D, 0x8F41, 0xDD9E, 0x8F42, 0xDD9F, 0x8F43, 0xDDA0, 0x8F44, 0xDDA1, 0x8368, 0xDDA2, 0x831B, + 0xDDA3, 0x8369, 0xDDA4, 0x836C, 0xDDA5, 0x836A, 0xDDA6, 0x836D, 0xDDA7, 0x836E, 0xDDA8, 0x83B0, 0xDDA9, 0x8378, 0xDDAA, 0x83B3, + 0xDDAB, 0x83B4, 0xDDAC, 0x83A0, 0xDDAD, 0x83AA, 0xDDAE, 0x8393, 0xDDAF, 0x839C, 0xDDB0, 0x8385, 0xDDB1, 0x837C, 0xDDB2, 0x83B6, + 0xDDB3, 0x83A9, 0xDDB4, 0x837D, 0xDDB5, 0x83B8, 0xDDB6, 0x837B, 0xDDB7, 0x8398, 0xDDB8, 0x839E, 0xDDB9, 0x83A8, 0xDDBA, 0x83BA, + 0xDDBB, 0x83BC, 0xDDBC, 0x83C1, 0xDDBD, 0x8401, 0xDDBE, 0x83E5, 0xDDBF, 0x83D8, 0xDDC0, 0x5807, 0xDDC1, 0x8418, 0xDDC2, 0x840B, + 0xDDC3, 0x83DD, 0xDDC4, 0x83FD, 0xDDC5, 0x83D6, 0xDDC6, 0x841C, 0xDDC7, 0x8438, 0xDDC8, 0x8411, 0xDDC9, 0x8406, 0xDDCA, 0x83D4, + 0xDDCB, 0x83DF, 0xDDCC, 0x840F, 0xDDCD, 0x8403, 0xDDCE, 0x83F8, 0xDDCF, 0x83F9, 0xDDD0, 0x83EA, 0xDDD1, 0x83C5, 0xDDD2, 0x83C0, + 0xDDD3, 0x8426, 0xDDD4, 0x83F0, 0xDDD5, 0x83E1, 0xDDD6, 0x845C, 0xDDD7, 0x8451, 0xDDD8, 0x845A, 0xDDD9, 0x8459, 0xDDDA, 0x8473, + 0xDDDB, 0x8487, 0xDDDC, 0x8488, 0xDDDD, 0x847A, 0xDDDE, 0x8489, 0xDDDF, 0x8478, 0xDDE0, 0x843C, 0xDDE1, 0x8446, 0xDDE2, 0x8469, + 0xDDE3, 0x8476, 0xDDE4, 0x848C, 0xDDE5, 0x848E, 0xDDE6, 0x8431, 0xDDE7, 0x846D, 0xDDE8, 0x84C1, 0xDDE9, 0x84CD, 0xDDEA, 0x84D0, + 0xDDEB, 0x84E6, 0xDDEC, 0x84BD, 0xDDED, 0x84D3, 0xDDEE, 0x84CA, 0xDDEF, 0x84BF, 0xDDF0, 0x84BA, 0xDDF1, 0x84E0, 0xDDF2, 0x84A1, + 0xDDF3, 0x84B9, 0xDDF4, 0x84B4, 0xDDF5, 0x8497, 0xDDF6, 0x84E5, 0xDDF7, 0x84E3, 0xDDF8, 0x850C, 0xDDF9, 0x750D, 0xDDFA, 0x8538, + 0xDDFB, 0x84F0, 0xDDFC, 0x8539, 0xDDFD, 0x851F, 0xDDFE, 0x853A, 0xDE40, 0x8F45, 0xDE41, 0x8F46, 0xDE42, 0x8F47, 0xDE43, 0x8F48, + 0xDE44, 0x8F49, 0xDE45, 0x8F4A, 0xDE46, 0x8F4B, 0xDE47, 0x8F4C, 0xDE48, 0x8F4D, 0xDE49, 0x8F4E, 0xDE4A, 0x8F4F, 0xDE4B, 0x8F50, + 0xDE4C, 0x8F51, 0xDE4D, 0x8F52, 0xDE4E, 0x8F53, 0xDE4F, 0x8F54, 0xDE50, 0x8F55, 0xDE51, 0x8F56, 0xDE52, 0x8F57, 0xDE53, 0x8F58, + 0xDE54, 0x8F59, 0xDE55, 0x8F5A, 0xDE56, 0x8F5B, 0xDE57, 0x8F5C, 0xDE58, 0x8F5D, 0xDE59, 0x8F5E, 0xDE5A, 0x8F5F, 0xDE5B, 0x8F60, + 0xDE5C, 0x8F61, 0xDE5D, 0x8F62, 0xDE5E, 0x8F63, 0xDE5F, 0x8F64, 0xDE60, 0x8F65, 0xDE61, 0x8F6A, 0xDE62, 0x8F80, 0xDE63, 0x8F8C, + 0xDE64, 0x8F92, 0xDE65, 0x8F9D, 0xDE66, 0x8FA0, 0xDE67, 0x8FA1, 0xDE68, 0x8FA2, 0xDE69, 0x8FA4, 0xDE6A, 0x8FA5, 0xDE6B, 0x8FA6, + 0xDE6C, 0x8FA7, 0xDE6D, 0x8FAA, 0xDE6E, 0x8FAC, 0xDE6F, 0x8FAD, 0xDE70, 0x8FAE, 0xDE71, 0x8FAF, 0xDE72, 0x8FB2, 0xDE73, 0x8FB3, + 0xDE74, 0x8FB4, 0xDE75, 0x8FB5, 0xDE76, 0x8FB7, 0xDE77, 0x8FB8, 0xDE78, 0x8FBA, 0xDE79, 0x8FBB, 0xDE7A, 0x8FBC, 0xDE7B, 0x8FBF, + 0xDE7C, 0x8FC0, 0xDE7D, 0x8FC3, 0xDE7E, 0x8FC6, 0xDE80, 0x8FC9, 0xDE81, 0x8FCA, 0xDE82, 0x8FCB, 0xDE83, 0x8FCC, 0xDE84, 0x8FCD, + 0xDE85, 0x8FCF, 0xDE86, 0x8FD2, 0xDE87, 0x8FD6, 0xDE88, 0x8FD7, 0xDE89, 0x8FDA, 0xDE8A, 0x8FE0, 0xDE8B, 0x8FE1, 0xDE8C, 0x8FE3, + 0xDE8D, 0x8FE7, 0xDE8E, 0x8FEC, 0xDE8F, 0x8FEF, 0xDE90, 0x8FF1, 0xDE91, 0x8FF2, 0xDE92, 0x8FF4, 0xDE93, 0x8FF5, 0xDE94, 0x8FF6, + 0xDE95, 0x8FFA, 0xDE96, 0x8FFB, 0xDE97, 0x8FFC, 0xDE98, 0x8FFE, 0xDE99, 0x8FFF, 0xDE9A, 0x9007, 0xDE9B, 0x9008, 0xDE9C, 0x900C, + 0xDE9D, 0x900E, 0xDE9E, 0x9013, 0xDE9F, 0x9015, 0xDEA0, 0x9018, 0xDEA1, 0x8556, 0xDEA2, 0x853B, 0xDEA3, 0x84FF, 0xDEA4, 0x84FC, + 0xDEA5, 0x8559, 0xDEA6, 0x8548, 0xDEA7, 0x8568, 0xDEA8, 0x8564, 0xDEA9, 0x855E, 0xDEAA, 0x857A, 0xDEAB, 0x77A2, 0xDEAC, 0x8543, + 0xDEAD, 0x8572, 0xDEAE, 0x857B, 0xDEAF, 0x85A4, 0xDEB0, 0x85A8, 0xDEB1, 0x8587, 0xDEB2, 0x858F, 0xDEB3, 0x8579, 0xDEB4, 0x85AE, + 0xDEB5, 0x859C, 0xDEB6, 0x8585, 0xDEB7, 0x85B9, 0xDEB8, 0x85B7, 0xDEB9, 0x85B0, 0xDEBA, 0x85D3, 0xDEBB, 0x85C1, 0xDEBC, 0x85DC, + 0xDEBD, 0x85FF, 0xDEBE, 0x8627, 0xDEBF, 0x8605, 0xDEC0, 0x8629, 0xDEC1, 0x8616, 0xDEC2, 0x863C, 0xDEC3, 0x5EFE, 0xDEC4, 0x5F08, + 0xDEC5, 0x593C, 0xDEC6, 0x5941, 0xDEC7, 0x8037, 0xDEC8, 0x5955, 0xDEC9, 0x595A, 0xDECA, 0x5958, 0xDECB, 0x530F, 0xDECC, 0x5C22, + 0xDECD, 0x5C25, 0xDECE, 0x5C2C, 0xDECF, 0x5C34, 0xDED0, 0x624C, 0xDED1, 0x626A, 0xDED2, 0x629F, 0xDED3, 0x62BB, 0xDED4, 0x62CA, + 0xDED5, 0x62DA, 0xDED6, 0x62D7, 0xDED7, 0x62EE, 0xDED8, 0x6322, 0xDED9, 0x62F6, 0xDEDA, 0x6339, 0xDEDB, 0x634B, 0xDEDC, 0x6343, + 0xDEDD, 0x63AD, 0xDEDE, 0x63F6, 0xDEDF, 0x6371, 0xDEE0, 0x637A, 0xDEE1, 0x638E, 0xDEE2, 0x63B4, 0xDEE3, 0x636D, 0xDEE4, 0x63AC, + 0xDEE5, 0x638A, 0xDEE6, 0x6369, 0xDEE7, 0x63AE, 0xDEE8, 0x63BC, 0xDEE9, 0x63F2, 0xDEEA, 0x63F8, 0xDEEB, 0x63E0, 0xDEEC, 0x63FF, + 0xDEED, 0x63C4, 0xDEEE, 0x63DE, 0xDEEF, 0x63CE, 0xDEF0, 0x6452, 0xDEF1, 0x63C6, 0xDEF2, 0x63BE, 0xDEF3, 0x6445, 0xDEF4, 0x6441, + 0xDEF5, 0x640B, 0xDEF6, 0x641B, 0xDEF7, 0x6420, 0xDEF8, 0x640C, 0xDEF9, 0x6426, 0xDEFA, 0x6421, 0xDEFB, 0x645E, 0xDEFC, 0x6484, + 0xDEFD, 0x646D, 0xDEFE, 0x6496, 0xDF40, 0x9019, 0xDF41, 0x901C, 0xDF42, 0x9023, 0xDF43, 0x9024, 0xDF44, 0x9025, 0xDF45, 0x9027, + 0xDF46, 0x9028, 0xDF47, 0x9029, 0xDF48, 0x902A, 0xDF49, 0x902B, 0xDF4A, 0x902C, 0xDF4B, 0x9030, 0xDF4C, 0x9031, 0xDF4D, 0x9032, + 0xDF4E, 0x9033, 0xDF4F, 0x9034, 0xDF50, 0x9037, 0xDF51, 0x9039, 0xDF52, 0x903A, 0xDF53, 0x903D, 0xDF54, 0x903F, 0xDF55, 0x9040, + 0xDF56, 0x9043, 0xDF57, 0x9045, 0xDF58, 0x9046, 0xDF59, 0x9048, 0xDF5A, 0x9049, 0xDF5B, 0x904A, 0xDF5C, 0x904B, 0xDF5D, 0x904C, + 0xDF5E, 0x904E, 0xDF5F, 0x9054, 0xDF60, 0x9055, 0xDF61, 0x9056, 0xDF62, 0x9059, 0xDF63, 0x905A, 0xDF64, 0x905C, 0xDF65, 0x905D, + 0xDF66, 0x905E, 0xDF67, 0x905F, 0xDF68, 0x9060, 0xDF69, 0x9061, 0xDF6A, 0x9064, 0xDF6B, 0x9066, 0xDF6C, 0x9067, 0xDF6D, 0x9069, + 0xDF6E, 0x906A, 0xDF6F, 0x906B, 0xDF70, 0x906C, 0xDF71, 0x906F, 0xDF72, 0x9070, 0xDF73, 0x9071, 0xDF74, 0x9072, 0xDF75, 0x9073, + 0xDF76, 0x9076, 0xDF77, 0x9077, 0xDF78, 0x9078, 0xDF79, 0x9079, 0xDF7A, 0x907A, 0xDF7B, 0x907B, 0xDF7C, 0x907C, 0xDF7D, 0x907E, + 0xDF7E, 0x9081, 0xDF80, 0x9084, 0xDF81, 0x9085, 0xDF82, 0x9086, 0xDF83, 0x9087, 0xDF84, 0x9089, 0xDF85, 0x908A, 0xDF86, 0x908C, + 0xDF87, 0x908D, 0xDF88, 0x908E, 0xDF89, 0x908F, 0xDF8A, 0x9090, 0xDF8B, 0x9092, 0xDF8C, 0x9094, 0xDF8D, 0x9096, 0xDF8E, 0x9098, + 0xDF8F, 0x909A, 0xDF90, 0x909C, 0xDF91, 0x909E, 0xDF92, 0x909F, 0xDF93, 0x90A0, 0xDF94, 0x90A4, 0xDF95, 0x90A5, 0xDF96, 0x90A7, + 0xDF97, 0x90A8, 0xDF98, 0x90A9, 0xDF99, 0x90AB, 0xDF9A, 0x90AD, 0xDF9B, 0x90B2, 0xDF9C, 0x90B7, 0xDF9D, 0x90BC, 0xDF9E, 0x90BD, + 0xDF9F, 0x90BF, 0xDFA0, 0x90C0, 0xDFA1, 0x647A, 0xDFA2, 0x64B7, 0xDFA3, 0x64B8, 0xDFA4, 0x6499, 0xDFA5, 0x64BA, 0xDFA6, 0x64C0, + 0xDFA7, 0x64D0, 0xDFA8, 0x64D7, 0xDFA9, 0x64E4, 0xDFAA, 0x64E2, 0xDFAB, 0x6509, 0xDFAC, 0x6525, 0xDFAD, 0x652E, 0xDFAE, 0x5F0B, + 0xDFAF, 0x5FD2, 0xDFB0, 0x7519, 0xDFB1, 0x5F11, 0xDFB2, 0x535F, 0xDFB3, 0x53F1, 0xDFB4, 0x53FD, 0xDFB5, 0x53E9, 0xDFB6, 0x53E8, + 0xDFB7, 0x53FB, 0xDFB8, 0x5412, 0xDFB9, 0x5416, 0xDFBA, 0x5406, 0xDFBB, 0x544B, 0xDFBC, 0x5452, 0xDFBD, 0x5453, 0xDFBE, 0x5454, + 0xDFBF, 0x5456, 0xDFC0, 0x5443, 0xDFC1, 0x5421, 0xDFC2, 0x5457, 0xDFC3, 0x5459, 0xDFC4, 0x5423, 0xDFC5, 0x5432, 0xDFC6, 0x5482, + 0xDFC7, 0x5494, 0xDFC8, 0x5477, 0xDFC9, 0x5471, 0xDFCA, 0x5464, 0xDFCB, 0x549A, 0xDFCC, 0x549B, 0xDFCD, 0x5484, 0xDFCE, 0x5476, + 0xDFCF, 0x5466, 0xDFD0, 0x549D, 0xDFD1, 0x54D0, 0xDFD2, 0x54AD, 0xDFD3, 0x54C2, 0xDFD4, 0x54B4, 0xDFD5, 0x54D2, 0xDFD6, 0x54A7, + 0xDFD7, 0x54A6, 0xDFD8, 0x54D3, 0xDFD9, 0x54D4, 0xDFDA, 0x5472, 0xDFDB, 0x54A3, 0xDFDC, 0x54D5, 0xDFDD, 0x54BB, 0xDFDE, 0x54BF, + 0xDFDF, 0x54CC, 0xDFE0, 0x54D9, 0xDFE1, 0x54DA, 0xDFE2, 0x54DC, 0xDFE3, 0x54A9, 0xDFE4, 0x54AA, 0xDFE5, 0x54A4, 0xDFE6, 0x54DD, + 0xDFE7, 0x54CF, 0xDFE8, 0x54DE, 0xDFE9, 0x551B, 0xDFEA, 0x54E7, 0xDFEB, 0x5520, 0xDFEC, 0x54FD, 0xDFED, 0x5514, 0xDFEE, 0x54F3, + 0xDFEF, 0x5522, 0xDFF0, 0x5523, 0xDFF1, 0x550F, 0xDFF2, 0x5511, 0xDFF3, 0x5527, 0xDFF4, 0x552A, 0xDFF5, 0x5567, 0xDFF6, 0x558F, + 0xDFF7, 0x55B5, 0xDFF8, 0x5549, 0xDFF9, 0x556D, 0xDFFA, 0x5541, 0xDFFB, 0x5555, 0xDFFC, 0x553F, 0xDFFD, 0x5550, 0xDFFE, 0x553C, + 0xE040, 0x90C2, 0xE041, 0x90C3, 0xE042, 0x90C6, 0xE043, 0x90C8, 0xE044, 0x90C9, 0xE045, 0x90CB, 0xE046, 0x90CC, 0xE047, 0x90CD, + 0xE048, 0x90D2, 0xE049, 0x90D4, 0xE04A, 0x90D5, 0xE04B, 0x90D6, 0xE04C, 0x90D8, 0xE04D, 0x90D9, 0xE04E, 0x90DA, 0xE04F, 0x90DE, + 0xE050, 0x90DF, 0xE051, 0x90E0, 0xE052, 0x90E3, 0xE053, 0x90E4, 0xE054, 0x90E5, 0xE055, 0x90E9, 0xE056, 0x90EA, 0xE057, 0x90EC, + 0xE058, 0x90EE, 0xE059, 0x90F0, 0xE05A, 0x90F1, 0xE05B, 0x90F2, 0xE05C, 0x90F3, 0xE05D, 0x90F5, 0xE05E, 0x90F6, 0xE05F, 0x90F7, + 0xE060, 0x90F9, 0xE061, 0x90FA, 0xE062, 0x90FB, 0xE063, 0x90FC, 0xE064, 0x90FF, 0xE065, 0x9100, 0xE066, 0x9101, 0xE067, 0x9103, + 0xE068, 0x9105, 0xE069, 0x9106, 0xE06A, 0x9107, 0xE06B, 0x9108, 0xE06C, 0x9109, 0xE06D, 0x910A, 0xE06E, 0x910B, 0xE06F, 0x910C, + 0xE070, 0x910D, 0xE071, 0x910E, 0xE072, 0x910F, 0xE073, 0x9110, 0xE074, 0x9111, 0xE075, 0x9112, 0xE076, 0x9113, 0xE077, 0x9114, + 0xE078, 0x9115, 0xE079, 0x9116, 0xE07A, 0x9117, 0xE07B, 0x9118, 0xE07C, 0x911A, 0xE07D, 0x911B, 0xE07E, 0x911C, 0xE080, 0x911D, + 0xE081, 0x911F, 0xE082, 0x9120, 0xE083, 0x9121, 0xE084, 0x9124, 0xE085, 0x9125, 0xE086, 0x9126, 0xE087, 0x9127, 0xE088, 0x9128, + 0xE089, 0x9129, 0xE08A, 0x912A, 0xE08B, 0x912B, 0xE08C, 0x912C, 0xE08D, 0x912D, 0xE08E, 0x912E, 0xE08F, 0x9130, 0xE090, 0x9132, + 0xE091, 0x9133, 0xE092, 0x9134, 0xE093, 0x9135, 0xE094, 0x9136, 0xE095, 0x9137, 0xE096, 0x9138, 0xE097, 0x913A, 0xE098, 0x913B, + 0xE099, 0x913C, 0xE09A, 0x913D, 0xE09B, 0x913E, 0xE09C, 0x913F, 0xE09D, 0x9140, 0xE09E, 0x9141, 0xE09F, 0x9142, 0xE0A0, 0x9144, + 0xE0A1, 0x5537, 0xE0A2, 0x5556, 0xE0A3, 0x5575, 0xE0A4, 0x5576, 0xE0A5, 0x5577, 0xE0A6, 0x5533, 0xE0A7, 0x5530, 0xE0A8, 0x555C, + 0xE0A9, 0x558B, 0xE0AA, 0x55D2, 0xE0AB, 0x5583, 0xE0AC, 0x55B1, 0xE0AD, 0x55B9, 0xE0AE, 0x5588, 0xE0AF, 0x5581, 0xE0B0, 0x559F, + 0xE0B1, 0x557E, 0xE0B2, 0x55D6, 0xE0B3, 0x5591, 0xE0B4, 0x557B, 0xE0B5, 0x55DF, 0xE0B6, 0x55BD, 0xE0B7, 0x55BE, 0xE0B8, 0x5594, + 0xE0B9, 0x5599, 0xE0BA, 0x55EA, 0xE0BB, 0x55F7, 0xE0BC, 0x55C9, 0xE0BD, 0x561F, 0xE0BE, 0x55D1, 0xE0BF, 0x55EB, 0xE0C0, 0x55EC, + 0xE0C1, 0x55D4, 0xE0C2, 0x55E6, 0xE0C3, 0x55DD, 0xE0C4, 0x55C4, 0xE0C5, 0x55EF, 0xE0C6, 0x55E5, 0xE0C7, 0x55F2, 0xE0C8, 0x55F3, + 0xE0C9, 0x55CC, 0xE0CA, 0x55CD, 0xE0CB, 0x55E8, 0xE0CC, 0x55F5, 0xE0CD, 0x55E4, 0xE0CE, 0x8F94, 0xE0CF, 0x561E, 0xE0D0, 0x5608, + 0xE0D1, 0x560C, 0xE0D2, 0x5601, 0xE0D3, 0x5624, 0xE0D4, 0x5623, 0xE0D5, 0x55FE, 0xE0D6, 0x5600, 0xE0D7, 0x5627, 0xE0D8, 0x562D, + 0xE0D9, 0x5658, 0xE0DA, 0x5639, 0xE0DB, 0x5657, 0xE0DC, 0x562C, 0xE0DD, 0x564D, 0xE0DE, 0x5662, 0xE0DF, 0x5659, 0xE0E0, 0x565C, + 0xE0E1, 0x564C, 0xE0E2, 0x5654, 0xE0E3, 0x5686, 0xE0E4, 0x5664, 0xE0E5, 0x5671, 0xE0E6, 0x566B, 0xE0E7, 0x567B, 0xE0E8, 0x567C, + 0xE0E9, 0x5685, 0xE0EA, 0x5693, 0xE0EB, 0x56AF, 0xE0EC, 0x56D4, 0xE0ED, 0x56D7, 0xE0EE, 0x56DD, 0xE0EF, 0x56E1, 0xE0F0, 0x56F5, + 0xE0F1, 0x56EB, 0xE0F2, 0x56F9, 0xE0F3, 0x56FF, 0xE0F4, 0x5704, 0xE0F5, 0x570A, 0xE0F6, 0x5709, 0xE0F7, 0x571C, 0xE0F8, 0x5E0F, + 0xE0F9, 0x5E19, 0xE0FA, 0x5E14, 0xE0FB, 0x5E11, 0xE0FC, 0x5E31, 0xE0FD, 0x5E3B, 0xE0FE, 0x5E3C, 0xE140, 0x9145, 0xE141, 0x9147, + 0xE142, 0x9148, 0xE143, 0x9151, 0xE144, 0x9153, 0xE145, 0x9154, 0xE146, 0x9155, 0xE147, 0x9156, 0xE148, 0x9158, 0xE149, 0x9159, + 0xE14A, 0x915B, 0xE14B, 0x915C, 0xE14C, 0x915F, 0xE14D, 0x9160, 0xE14E, 0x9166, 0xE14F, 0x9167, 0xE150, 0x9168, 0xE151, 0x916B, + 0xE152, 0x916D, 0xE153, 0x9173, 0xE154, 0x917A, 0xE155, 0x917B, 0xE156, 0x917C, 0xE157, 0x9180, 0xE158, 0x9181, 0xE159, 0x9182, + 0xE15A, 0x9183, 0xE15B, 0x9184, 0xE15C, 0x9186, 0xE15D, 0x9188, 0xE15E, 0x918A, 0xE15F, 0x918E, 0xE160, 0x918F, 0xE161, 0x9193, + 0xE162, 0x9194, 0xE163, 0x9195, 0xE164, 0x9196, 0xE165, 0x9197, 0xE166, 0x9198, 0xE167, 0x9199, 0xE168, 0x919C, 0xE169, 0x919D, + 0xE16A, 0x919E, 0xE16B, 0x919F, 0xE16C, 0x91A0, 0xE16D, 0x91A1, 0xE16E, 0x91A4, 0xE16F, 0x91A5, 0xE170, 0x91A6, 0xE171, 0x91A7, + 0xE172, 0x91A8, 0xE173, 0x91A9, 0xE174, 0x91AB, 0xE175, 0x91AC, 0xE176, 0x91B0, 0xE177, 0x91B1, 0xE178, 0x91B2, 0xE179, 0x91B3, + 0xE17A, 0x91B6, 0xE17B, 0x91B7, 0xE17C, 0x91B8, 0xE17D, 0x91B9, 0xE17E, 0x91BB, 0xE180, 0x91BC, 0xE181, 0x91BD, 0xE182, 0x91BE, + 0xE183, 0x91BF, 0xE184, 0x91C0, 0xE185, 0x91C1, 0xE186, 0x91C2, 0xE187, 0x91C3, 0xE188, 0x91C4, 0xE189, 0x91C5, 0xE18A, 0x91C6, + 0xE18B, 0x91C8, 0xE18C, 0x91CB, 0xE18D, 0x91D0, 0xE18E, 0x91D2, 0xE18F, 0x91D3, 0xE190, 0x91D4, 0xE191, 0x91D5, 0xE192, 0x91D6, + 0xE193, 0x91D7, 0xE194, 0x91D8, 0xE195, 0x91D9, 0xE196, 0x91DA, 0xE197, 0x91DB, 0xE198, 0x91DD, 0xE199, 0x91DE, 0xE19A, 0x91DF, + 0xE19B, 0x91E0, 0xE19C, 0x91E1, 0xE19D, 0x91E2, 0xE19E, 0x91E3, 0xE19F, 0x91E4, 0xE1A0, 0x91E5, 0xE1A1, 0x5E37, 0xE1A2, 0x5E44, + 0xE1A3, 0x5E54, 0xE1A4, 0x5E5B, 0xE1A5, 0x5E5E, 0xE1A6, 0x5E61, 0xE1A7, 0x5C8C, 0xE1A8, 0x5C7A, 0xE1A9, 0x5C8D, 0xE1AA, 0x5C90, + 0xE1AB, 0x5C96, 0xE1AC, 0x5C88, 0xE1AD, 0x5C98, 0xE1AE, 0x5C99, 0xE1AF, 0x5C91, 0xE1B0, 0x5C9A, 0xE1B1, 0x5C9C, 0xE1B2, 0x5CB5, + 0xE1B3, 0x5CA2, 0xE1B4, 0x5CBD, 0xE1B5, 0x5CAC, 0xE1B6, 0x5CAB, 0xE1B7, 0x5CB1, 0xE1B8, 0x5CA3, 0xE1B9, 0x5CC1, 0xE1BA, 0x5CB7, + 0xE1BB, 0x5CC4, 0xE1BC, 0x5CD2, 0xE1BD, 0x5CE4, 0xE1BE, 0x5CCB, 0xE1BF, 0x5CE5, 0xE1C0, 0x5D02, 0xE1C1, 0x5D03, 0xE1C2, 0x5D27, + 0xE1C3, 0x5D26, 0xE1C4, 0x5D2E, 0xE1C5, 0x5D24, 0xE1C6, 0x5D1E, 0xE1C7, 0x5D06, 0xE1C8, 0x5D1B, 0xE1C9, 0x5D58, 0xE1CA, 0x5D3E, + 0xE1CB, 0x5D34, 0xE1CC, 0x5D3D, 0xE1CD, 0x5D6C, 0xE1CE, 0x5D5B, 0xE1CF, 0x5D6F, 0xE1D0, 0x5D5D, 0xE1D1, 0x5D6B, 0xE1D2, 0x5D4B, + 0xE1D3, 0x5D4A, 0xE1D4, 0x5D69, 0xE1D5, 0x5D74, 0xE1D6, 0x5D82, 0xE1D7, 0x5D99, 0xE1D8, 0x5D9D, 0xE1D9, 0x8C73, 0xE1DA, 0x5DB7, + 0xE1DB, 0x5DC5, 0xE1DC, 0x5F73, 0xE1DD, 0x5F77, 0xE1DE, 0x5F82, 0xE1DF, 0x5F87, 0xE1E0, 0x5F89, 0xE1E1, 0x5F8C, 0xE1E2, 0x5F95, + 0xE1E3, 0x5F99, 0xE1E4, 0x5F9C, 0xE1E5, 0x5FA8, 0xE1E6, 0x5FAD, 0xE1E7, 0x5FB5, 0xE1E8, 0x5FBC, 0xE1E9, 0x8862, 0xE1EA, 0x5F61, + 0xE1EB, 0x72AD, 0xE1EC, 0x72B0, 0xE1ED, 0x72B4, 0xE1EE, 0x72B7, 0xE1EF, 0x72B8, 0xE1F0, 0x72C3, 0xE1F1, 0x72C1, 0xE1F2, 0x72CE, + 0xE1F3, 0x72CD, 0xE1F4, 0x72D2, 0xE1F5, 0x72E8, 0xE1F6, 0x72EF, 0xE1F7, 0x72E9, 0xE1F8, 0x72F2, 0xE1F9, 0x72F4, 0xE1FA, 0x72F7, + 0xE1FB, 0x7301, 0xE1FC, 0x72F3, 0xE1FD, 0x7303, 0xE1FE, 0x72FA, 0xE240, 0x91E6, 0xE241, 0x91E7, 0xE242, 0x91E8, 0xE243, 0x91E9, + 0xE244, 0x91EA, 0xE245, 0x91EB, 0xE246, 0x91EC, 0xE247, 0x91ED, 0xE248, 0x91EE, 0xE249, 0x91EF, 0xE24A, 0x91F0, 0xE24B, 0x91F1, + 0xE24C, 0x91F2, 0xE24D, 0x91F3, 0xE24E, 0x91F4, 0xE24F, 0x91F5, 0xE250, 0x91F6, 0xE251, 0x91F7, 0xE252, 0x91F8, 0xE253, 0x91F9, + 0xE254, 0x91FA, 0xE255, 0x91FB, 0xE256, 0x91FC, 0xE257, 0x91FD, 0xE258, 0x91FE, 0xE259, 0x91FF, 0xE25A, 0x9200, 0xE25B, 0x9201, + 0xE25C, 0x9202, 0xE25D, 0x9203, 0xE25E, 0x9204, 0xE25F, 0x9205, 0xE260, 0x9206, 0xE261, 0x9207, 0xE262, 0x9208, 0xE263, 0x9209, + 0xE264, 0x920A, 0xE265, 0x920B, 0xE266, 0x920C, 0xE267, 0x920D, 0xE268, 0x920E, 0xE269, 0x920F, 0xE26A, 0x9210, 0xE26B, 0x9211, + 0xE26C, 0x9212, 0xE26D, 0x9213, 0xE26E, 0x9214, 0xE26F, 0x9215, 0xE270, 0x9216, 0xE271, 0x9217, 0xE272, 0x9218, 0xE273, 0x9219, + 0xE274, 0x921A, 0xE275, 0x921B, 0xE276, 0x921C, 0xE277, 0x921D, 0xE278, 0x921E, 0xE279, 0x921F, 0xE27A, 0x9220, 0xE27B, 0x9221, + 0xE27C, 0x9222, 0xE27D, 0x9223, 0xE27E, 0x9224, 0xE280, 0x9225, 0xE281, 0x9226, 0xE282, 0x9227, 0xE283, 0x9228, 0xE284, 0x9229, + 0xE285, 0x922A, 0xE286, 0x922B, 0xE287, 0x922C, 0xE288, 0x922D, 0xE289, 0x922E, 0xE28A, 0x922F, 0xE28B, 0x9230, 0xE28C, 0x9231, + 0xE28D, 0x9232, 0xE28E, 0x9233, 0xE28F, 0x9234, 0xE290, 0x9235, 0xE291, 0x9236, 0xE292, 0x9237, 0xE293, 0x9238, 0xE294, 0x9239, + 0xE295, 0x923A, 0xE296, 0x923B, 0xE297, 0x923C, 0xE298, 0x923D, 0xE299, 0x923E, 0xE29A, 0x923F, 0xE29B, 0x9240, 0xE29C, 0x9241, + 0xE29D, 0x9242, 0xE29E, 0x9243, 0xE29F, 0x9244, 0xE2A0, 0x9245, 0xE2A1, 0x72FB, 0xE2A2, 0x7317, 0xE2A3, 0x7313, 0xE2A4, 0x7321, + 0xE2A5, 0x730A, 0xE2A6, 0x731E, 0xE2A7, 0x731D, 0xE2A8, 0x7315, 0xE2A9, 0x7322, 0xE2AA, 0x7339, 0xE2AB, 0x7325, 0xE2AC, 0x732C, + 0xE2AD, 0x7338, 0xE2AE, 0x7331, 0xE2AF, 0x7350, 0xE2B0, 0x734D, 0xE2B1, 0x7357, 0xE2B2, 0x7360, 0xE2B3, 0x736C, 0xE2B4, 0x736F, + 0xE2B5, 0x737E, 0xE2B6, 0x821B, 0xE2B7, 0x5925, 0xE2B8, 0x98E7, 0xE2B9, 0x5924, 0xE2BA, 0x5902, 0xE2BB, 0x9963, 0xE2BC, 0x9967, + 0xE2BD, 0x9968, 0xE2BE, 0x9969, 0xE2BF, 0x996A, 0xE2C0, 0x996B, 0xE2C1, 0x996C, 0xE2C2, 0x9974, 0xE2C3, 0x9977, 0xE2C4, 0x997D, + 0xE2C5, 0x9980, 0xE2C6, 0x9984, 0xE2C7, 0x9987, 0xE2C8, 0x998A, 0xE2C9, 0x998D, 0xE2CA, 0x9990, 0xE2CB, 0x9991, 0xE2CC, 0x9993, + 0xE2CD, 0x9994, 0xE2CE, 0x9995, 0xE2CF, 0x5E80, 0xE2D0, 0x5E91, 0xE2D1, 0x5E8B, 0xE2D2, 0x5E96, 0xE2D3, 0x5EA5, 0xE2D4, 0x5EA0, + 0xE2D5, 0x5EB9, 0xE2D6, 0x5EB5, 0xE2D7, 0x5EBE, 0xE2D8, 0x5EB3, 0xE2D9, 0x8D53, 0xE2DA, 0x5ED2, 0xE2DB, 0x5ED1, 0xE2DC, 0x5EDB, + 0xE2DD, 0x5EE8, 0xE2DE, 0x5EEA, 0xE2DF, 0x81BA, 0xE2E0, 0x5FC4, 0xE2E1, 0x5FC9, 0xE2E2, 0x5FD6, 0xE2E3, 0x5FCF, 0xE2E4, 0x6003, + 0xE2E5, 0x5FEE, 0xE2E6, 0x6004, 0xE2E7, 0x5FE1, 0xE2E8, 0x5FE4, 0xE2E9, 0x5FFE, 0xE2EA, 0x6005, 0xE2EB, 0x6006, 0xE2EC, 0x5FEA, + 0xE2ED, 0x5FED, 0xE2EE, 0x5FF8, 0xE2EF, 0x6019, 0xE2F0, 0x6035, 0xE2F1, 0x6026, 0xE2F2, 0x601B, 0xE2F3, 0x600F, 0xE2F4, 0x600D, + 0xE2F5, 0x6029, 0xE2F6, 0x602B, 0xE2F7, 0x600A, 0xE2F8, 0x603F, 0xE2F9, 0x6021, 0xE2FA, 0x6078, 0xE2FB, 0x6079, 0xE2FC, 0x607B, + 0xE2FD, 0x607A, 0xE2FE, 0x6042, 0xE340, 0x9246, 0xE341, 0x9247, 0xE342, 0x9248, 0xE343, 0x9249, 0xE344, 0x924A, 0xE345, 0x924B, + 0xE346, 0x924C, 0xE347, 0x924D, 0xE348, 0x924E, 0xE349, 0x924F, 0xE34A, 0x9250, 0xE34B, 0x9251, 0xE34C, 0x9252, 0xE34D, 0x9253, + 0xE34E, 0x9254, 0xE34F, 0x9255, 0xE350, 0x9256, 0xE351, 0x9257, 0xE352, 0x9258, 0xE353, 0x9259, 0xE354, 0x925A, 0xE355, 0x925B, + 0xE356, 0x925C, 0xE357, 0x925D, 0xE358, 0x925E, 0xE359, 0x925F, 0xE35A, 0x9260, 0xE35B, 0x9261, 0xE35C, 0x9262, 0xE35D, 0x9263, + 0xE35E, 0x9264, 0xE35F, 0x9265, 0xE360, 0x9266, 0xE361, 0x9267, 0xE362, 0x9268, 0xE363, 0x9269, 0xE364, 0x926A, 0xE365, 0x926B, + 0xE366, 0x926C, 0xE367, 0x926D, 0xE368, 0x926E, 0xE369, 0x926F, 0xE36A, 0x9270, 0xE36B, 0x9271, 0xE36C, 0x9272, 0xE36D, 0x9273, + 0xE36E, 0x9275, 0xE36F, 0x9276, 0xE370, 0x9277, 0xE371, 0x9278, 0xE372, 0x9279, 0xE373, 0x927A, 0xE374, 0x927B, 0xE375, 0x927C, + 0xE376, 0x927D, 0xE377, 0x927E, 0xE378, 0x927F, 0xE379, 0x9280, 0xE37A, 0x9281, 0xE37B, 0x9282, 0xE37C, 0x9283, 0xE37D, 0x9284, + 0xE37E, 0x9285, 0xE380, 0x9286, 0xE381, 0x9287, 0xE382, 0x9288, 0xE383, 0x9289, 0xE384, 0x928A, 0xE385, 0x928B, 0xE386, 0x928C, + 0xE387, 0x928D, 0xE388, 0x928F, 0xE389, 0x9290, 0xE38A, 0x9291, 0xE38B, 0x9292, 0xE38C, 0x9293, 0xE38D, 0x9294, 0xE38E, 0x9295, + 0xE38F, 0x9296, 0xE390, 0x9297, 0xE391, 0x9298, 0xE392, 0x9299, 0xE393, 0x929A, 0xE394, 0x929B, 0xE395, 0x929C, 0xE396, 0x929D, + 0xE397, 0x929E, 0xE398, 0x929F, 0xE399, 0x92A0, 0xE39A, 0x92A1, 0xE39B, 0x92A2, 0xE39C, 0x92A3, 0xE39D, 0x92A4, 0xE39E, 0x92A5, + 0xE39F, 0x92A6, 0xE3A0, 0x92A7, 0xE3A1, 0x606A, 0xE3A2, 0x607D, 0xE3A3, 0x6096, 0xE3A4, 0x609A, 0xE3A5, 0x60AD, 0xE3A6, 0x609D, + 0xE3A7, 0x6083, 0xE3A8, 0x6092, 0xE3A9, 0x608C, 0xE3AA, 0x609B, 0xE3AB, 0x60EC, 0xE3AC, 0x60BB, 0xE3AD, 0x60B1, 0xE3AE, 0x60DD, + 0xE3AF, 0x60D8, 0xE3B0, 0x60C6, 0xE3B1, 0x60DA, 0xE3B2, 0x60B4, 0xE3B3, 0x6120, 0xE3B4, 0x6126, 0xE3B5, 0x6115, 0xE3B6, 0x6123, + 0xE3B7, 0x60F4, 0xE3B8, 0x6100, 0xE3B9, 0x610E, 0xE3BA, 0x612B, 0xE3BB, 0x614A, 0xE3BC, 0x6175, 0xE3BD, 0x61AC, 0xE3BE, 0x6194, + 0xE3BF, 0x61A7, 0xE3C0, 0x61B7, 0xE3C1, 0x61D4, 0xE3C2, 0x61F5, 0xE3C3, 0x5FDD, 0xE3C4, 0x96B3, 0xE3C5, 0x95E9, 0xE3C6, 0x95EB, + 0xE3C7, 0x95F1, 0xE3C8, 0x95F3, 0xE3C9, 0x95F5, 0xE3CA, 0x95F6, 0xE3CB, 0x95FC, 0xE3CC, 0x95FE, 0xE3CD, 0x9603, 0xE3CE, 0x9604, + 0xE3CF, 0x9606, 0xE3D0, 0x9608, 0xE3D1, 0x960A, 0xE3D2, 0x960B, 0xE3D3, 0x960C, 0xE3D4, 0x960D, 0xE3D5, 0x960F, 0xE3D6, 0x9612, + 0xE3D7, 0x9615, 0xE3D8, 0x9616, 0xE3D9, 0x9617, 0xE3DA, 0x9619, 0xE3DB, 0x961A, 0xE3DC, 0x4E2C, 0xE3DD, 0x723F, 0xE3DE, 0x6215, + 0xE3DF, 0x6C35, 0xE3E0, 0x6C54, 0xE3E1, 0x6C5C, 0xE3E2, 0x6C4A, 0xE3E3, 0x6CA3, 0xE3E4, 0x6C85, 0xE3E5, 0x6C90, 0xE3E6, 0x6C94, + 0xE3E7, 0x6C8C, 0xE3E8, 0x6C68, 0xE3E9, 0x6C69, 0xE3EA, 0x6C74, 0xE3EB, 0x6C76, 0xE3EC, 0x6C86, 0xE3ED, 0x6CA9, 0xE3EE, 0x6CD0, + 0xE3EF, 0x6CD4, 0xE3F0, 0x6CAD, 0xE3F1, 0x6CF7, 0xE3F2, 0x6CF8, 0xE3F3, 0x6CF1, 0xE3F4, 0x6CD7, 0xE3F5, 0x6CB2, 0xE3F6, 0x6CE0, + 0xE3F7, 0x6CD6, 0xE3F8, 0x6CFA, 0xE3F9, 0x6CEB, 0xE3FA, 0x6CEE, 0xE3FB, 0x6CB1, 0xE3FC, 0x6CD3, 0xE3FD, 0x6CEF, 0xE3FE, 0x6CFE, + 0xE440, 0x92A8, 0xE441, 0x92A9, 0xE442, 0x92AA, 0xE443, 0x92AB, 0xE444, 0x92AC, 0xE445, 0x92AD, 0xE446, 0x92AF, 0xE447, 0x92B0, + 0xE448, 0x92B1, 0xE449, 0x92B2, 0xE44A, 0x92B3, 0xE44B, 0x92B4, 0xE44C, 0x92B5, 0xE44D, 0x92B6, 0xE44E, 0x92B7, 0xE44F, 0x92B8, + 0xE450, 0x92B9, 0xE451, 0x92BA, 0xE452, 0x92BB, 0xE453, 0x92BC, 0xE454, 0x92BD, 0xE455, 0x92BE, 0xE456, 0x92BF, 0xE457, 0x92C0, + 0xE458, 0x92C1, 0xE459, 0x92C2, 0xE45A, 0x92C3, 0xE45B, 0x92C4, 0xE45C, 0x92C5, 0xE45D, 0x92C6, 0xE45E, 0x92C7, 0xE45F, 0x92C9, + 0xE460, 0x92CA, 0xE461, 0x92CB, 0xE462, 0x92CC, 0xE463, 0x92CD, 0xE464, 0x92CE, 0xE465, 0x92CF, 0xE466, 0x92D0, 0xE467, 0x92D1, + 0xE468, 0x92D2, 0xE469, 0x92D3, 0xE46A, 0x92D4, 0xE46B, 0x92D5, 0xE46C, 0x92D6, 0xE46D, 0x92D7, 0xE46E, 0x92D8, 0xE46F, 0x92D9, + 0xE470, 0x92DA, 0xE471, 0x92DB, 0xE472, 0x92DC, 0xE473, 0x92DD, 0xE474, 0x92DE, 0xE475, 0x92DF, 0xE476, 0x92E0, 0xE477, 0x92E1, + 0xE478, 0x92E2, 0xE479, 0x92E3, 0xE47A, 0x92E4, 0xE47B, 0x92E5, 0xE47C, 0x92E6, 0xE47D, 0x92E7, 0xE47E, 0x92E8, 0xE480, 0x92E9, + 0xE481, 0x92EA, 0xE482, 0x92EB, 0xE483, 0x92EC, 0xE484, 0x92ED, 0xE485, 0x92EE, 0xE486, 0x92EF, 0xE487, 0x92F0, 0xE488, 0x92F1, + 0xE489, 0x92F2, 0xE48A, 0x92F3, 0xE48B, 0x92F4, 0xE48C, 0x92F5, 0xE48D, 0x92F6, 0xE48E, 0x92F7, 0xE48F, 0x92F8, 0xE490, 0x92F9, + 0xE491, 0x92FA, 0xE492, 0x92FB, 0xE493, 0x92FC, 0xE494, 0x92FD, 0xE495, 0x92FE, 0xE496, 0x92FF, 0xE497, 0x9300, 0xE498, 0x9301, + 0xE499, 0x9302, 0xE49A, 0x9303, 0xE49B, 0x9304, 0xE49C, 0x9305, 0xE49D, 0x9306, 0xE49E, 0x9307, 0xE49F, 0x9308, 0xE4A0, 0x9309, + 0xE4A1, 0x6D39, 0xE4A2, 0x6D27, 0xE4A3, 0x6D0C, 0xE4A4, 0x6D43, 0xE4A5, 0x6D48, 0xE4A6, 0x6D07, 0xE4A7, 0x6D04, 0xE4A8, 0x6D19, + 0xE4A9, 0x6D0E, 0xE4AA, 0x6D2B, 0xE4AB, 0x6D4D, 0xE4AC, 0x6D2E, 0xE4AD, 0x6D35, 0xE4AE, 0x6D1A, 0xE4AF, 0x6D4F, 0xE4B0, 0x6D52, + 0xE4B1, 0x6D54, 0xE4B2, 0x6D33, 0xE4B3, 0x6D91, 0xE4B4, 0x6D6F, 0xE4B5, 0x6D9E, 0xE4B6, 0x6DA0, 0xE4B7, 0x6D5E, 0xE4B8, 0x6D93, + 0xE4B9, 0x6D94, 0xE4BA, 0x6D5C, 0xE4BB, 0x6D60, 0xE4BC, 0x6D7C, 0xE4BD, 0x6D63, 0xE4BE, 0x6E1A, 0xE4BF, 0x6DC7, 0xE4C0, 0x6DC5, + 0xE4C1, 0x6DDE, 0xE4C2, 0x6E0E, 0xE4C3, 0x6DBF, 0xE4C4, 0x6DE0, 0xE4C5, 0x6E11, 0xE4C6, 0x6DE6, 0xE4C7, 0x6DDD, 0xE4C8, 0x6DD9, + 0xE4C9, 0x6E16, 0xE4CA, 0x6DAB, 0xE4CB, 0x6E0C, 0xE4CC, 0x6DAE, 0xE4CD, 0x6E2B, 0xE4CE, 0x6E6E, 0xE4CF, 0x6E4E, 0xE4D0, 0x6E6B, + 0xE4D1, 0x6EB2, 0xE4D2, 0x6E5F, 0xE4D3, 0x6E86, 0xE4D4, 0x6E53, 0xE4D5, 0x6E54, 0xE4D6, 0x6E32, 0xE4D7, 0x6E25, 0xE4D8, 0x6E44, + 0xE4D9, 0x6EDF, 0xE4DA, 0x6EB1, 0xE4DB, 0x6E98, 0xE4DC, 0x6EE0, 0xE4DD, 0x6F2D, 0xE4DE, 0x6EE2, 0xE4DF, 0x6EA5, 0xE4E0, 0x6EA7, + 0xE4E1, 0x6EBD, 0xE4E2, 0x6EBB, 0xE4E3, 0x6EB7, 0xE4E4, 0x6ED7, 0xE4E5, 0x6EB4, 0xE4E6, 0x6ECF, 0xE4E7, 0x6E8F, 0xE4E8, 0x6EC2, + 0xE4E9, 0x6E9F, 0xE4EA, 0x6F62, 0xE4EB, 0x6F46, 0xE4EC, 0x6F47, 0xE4ED, 0x6F24, 0xE4EE, 0x6F15, 0xE4EF, 0x6EF9, 0xE4F0, 0x6F2F, + 0xE4F1, 0x6F36, 0xE4F2, 0x6F4B, 0xE4F3, 0x6F74, 0xE4F4, 0x6F2A, 0xE4F5, 0x6F09, 0xE4F6, 0x6F29, 0xE4F7, 0x6F89, 0xE4F8, 0x6F8D, + 0xE4F9, 0x6F8C, 0xE4FA, 0x6F78, 0xE4FB, 0x6F72, 0xE4FC, 0x6F7C, 0xE4FD, 0x6F7A, 0xE4FE, 0x6FD1, 0xE540, 0x930A, 0xE541, 0x930B, + 0xE542, 0x930C, 0xE543, 0x930D, 0xE544, 0x930E, 0xE545, 0x930F, 0xE546, 0x9310, 0xE547, 0x9311, 0xE548, 0x9312, 0xE549, 0x9313, + 0xE54A, 0x9314, 0xE54B, 0x9315, 0xE54C, 0x9316, 0xE54D, 0x9317, 0xE54E, 0x9318, 0xE54F, 0x9319, 0xE550, 0x931A, 0xE551, 0x931B, + 0xE552, 0x931C, 0xE553, 0x931D, 0xE554, 0x931E, 0xE555, 0x931F, 0xE556, 0x9320, 0xE557, 0x9321, 0xE558, 0x9322, 0xE559, 0x9323, + 0xE55A, 0x9324, 0xE55B, 0x9325, 0xE55C, 0x9326, 0xE55D, 0x9327, 0xE55E, 0x9328, 0xE55F, 0x9329, 0xE560, 0x932A, 0xE561, 0x932B, + 0xE562, 0x932C, 0xE563, 0x932D, 0xE564, 0x932E, 0xE565, 0x932F, 0xE566, 0x9330, 0xE567, 0x9331, 0xE568, 0x9332, 0xE569, 0x9333, + 0xE56A, 0x9334, 0xE56B, 0x9335, 0xE56C, 0x9336, 0xE56D, 0x9337, 0xE56E, 0x9338, 0xE56F, 0x9339, 0xE570, 0x933A, 0xE571, 0x933B, + 0xE572, 0x933C, 0xE573, 0x933D, 0xE574, 0x933F, 0xE575, 0x9340, 0xE576, 0x9341, 0xE577, 0x9342, 0xE578, 0x9343, 0xE579, 0x9344, + 0xE57A, 0x9345, 0xE57B, 0x9346, 0xE57C, 0x9347, 0xE57D, 0x9348, 0xE57E, 0x9349, 0xE580, 0x934A, 0xE581, 0x934B, 0xE582, 0x934C, + 0xE583, 0x934D, 0xE584, 0x934E, 0xE585, 0x934F, 0xE586, 0x9350, 0xE587, 0x9351, 0xE588, 0x9352, 0xE589, 0x9353, 0xE58A, 0x9354, + 0xE58B, 0x9355, 0xE58C, 0x9356, 0xE58D, 0x9357, 0xE58E, 0x9358, 0xE58F, 0x9359, 0xE590, 0x935A, 0xE591, 0x935B, 0xE592, 0x935C, + 0xE593, 0x935D, 0xE594, 0x935E, 0xE595, 0x935F, 0xE596, 0x9360, 0xE597, 0x9361, 0xE598, 0x9362, 0xE599, 0x9363, 0xE59A, 0x9364, + 0xE59B, 0x9365, 0xE59C, 0x9366, 0xE59D, 0x9367, 0xE59E, 0x9368, 0xE59F, 0x9369, 0xE5A0, 0x936B, 0xE5A1, 0x6FC9, 0xE5A2, 0x6FA7, + 0xE5A3, 0x6FB9, 0xE5A4, 0x6FB6, 0xE5A5, 0x6FC2, 0xE5A6, 0x6FE1, 0xE5A7, 0x6FEE, 0xE5A8, 0x6FDE, 0xE5A9, 0x6FE0, 0xE5AA, 0x6FEF, + 0xE5AB, 0x701A, 0xE5AC, 0x7023, 0xE5AD, 0x701B, 0xE5AE, 0x7039, 0xE5AF, 0x7035, 0xE5B0, 0x704F, 0xE5B1, 0x705E, 0xE5B2, 0x5B80, + 0xE5B3, 0x5B84, 0xE5B4, 0x5B95, 0xE5B5, 0x5B93, 0xE5B6, 0x5BA5, 0xE5B7, 0x5BB8, 0xE5B8, 0x752F, 0xE5B9, 0x9A9E, 0xE5BA, 0x6434, + 0xE5BB, 0x5BE4, 0xE5BC, 0x5BEE, 0xE5BD, 0x8930, 0xE5BE, 0x5BF0, 0xE5BF, 0x8E47, 0xE5C0, 0x8B07, 0xE5C1, 0x8FB6, 0xE5C2, 0x8FD3, + 0xE5C3, 0x8FD5, 0xE5C4, 0x8FE5, 0xE5C5, 0x8FEE, 0xE5C6, 0x8FE4, 0xE5C7, 0x8FE9, 0xE5C8, 0x8FE6, 0xE5C9, 0x8FF3, 0xE5CA, 0x8FE8, + 0xE5CB, 0x9005, 0xE5CC, 0x9004, 0xE5CD, 0x900B, 0xE5CE, 0x9026, 0xE5CF, 0x9011, 0xE5D0, 0x900D, 0xE5D1, 0x9016, 0xE5D2, 0x9021, + 0xE5D3, 0x9035, 0xE5D4, 0x9036, 0xE5D5, 0x902D, 0xE5D6, 0x902F, 0xE5D7, 0x9044, 0xE5D8, 0x9051, 0xE5D9, 0x9052, 0xE5DA, 0x9050, + 0xE5DB, 0x9068, 0xE5DC, 0x9058, 0xE5DD, 0x9062, 0xE5DE, 0x905B, 0xE5DF, 0x66B9, 0xE5E0, 0x9074, 0xE5E1, 0x907D, 0xE5E2, 0x9082, + 0xE5E3, 0x9088, 0xE5E4, 0x9083, 0xE5E5, 0x908B, 0xE5E6, 0x5F50, 0xE5E7, 0x5F57, 0xE5E8, 0x5F56, 0xE5E9, 0x5F58, 0xE5EA, 0x5C3B, + 0xE5EB, 0x54AB, 0xE5EC, 0x5C50, 0xE5ED, 0x5C59, 0xE5EE, 0x5B71, 0xE5EF, 0x5C63, 0xE5F0, 0x5C66, 0xE5F1, 0x7FBC, 0xE5F2, 0x5F2A, + 0xE5F3, 0x5F29, 0xE5F4, 0x5F2D, 0xE5F5, 0x8274, 0xE5F6, 0x5F3C, 0xE5F7, 0x9B3B, 0xE5F8, 0x5C6E, 0xE5F9, 0x5981, 0xE5FA, 0x5983, + 0xE5FB, 0x598D, 0xE5FC, 0x59A9, 0xE5FD, 0x59AA, 0xE5FE, 0x59A3, 0xE640, 0x936C, 0xE641, 0x936D, 0xE642, 0x936E, 0xE643, 0x936F, + 0xE644, 0x9370, 0xE645, 0x9371, 0xE646, 0x9372, 0xE647, 0x9373, 0xE648, 0x9374, 0xE649, 0x9375, 0xE64A, 0x9376, 0xE64B, 0x9377, + 0xE64C, 0x9378, 0xE64D, 0x9379, 0xE64E, 0x937A, 0xE64F, 0x937B, 0xE650, 0x937C, 0xE651, 0x937D, 0xE652, 0x937E, 0xE653, 0x937F, + 0xE654, 0x9380, 0xE655, 0x9381, 0xE656, 0x9382, 0xE657, 0x9383, 0xE658, 0x9384, 0xE659, 0x9385, 0xE65A, 0x9386, 0xE65B, 0x9387, + 0xE65C, 0x9388, 0xE65D, 0x9389, 0xE65E, 0x938A, 0xE65F, 0x938B, 0xE660, 0x938C, 0xE661, 0x938D, 0xE662, 0x938E, 0xE663, 0x9390, + 0xE664, 0x9391, 0xE665, 0x9392, 0xE666, 0x9393, 0xE667, 0x9394, 0xE668, 0x9395, 0xE669, 0x9396, 0xE66A, 0x9397, 0xE66B, 0x9398, + 0xE66C, 0x9399, 0xE66D, 0x939A, 0xE66E, 0x939B, 0xE66F, 0x939C, 0xE670, 0x939D, 0xE671, 0x939E, 0xE672, 0x939F, 0xE673, 0x93A0, + 0xE674, 0x93A1, 0xE675, 0x93A2, 0xE676, 0x93A3, 0xE677, 0x93A4, 0xE678, 0x93A5, 0xE679, 0x93A6, 0xE67A, 0x93A7, 0xE67B, 0x93A8, + 0xE67C, 0x93A9, 0xE67D, 0x93AA, 0xE67E, 0x93AB, 0xE680, 0x93AC, 0xE681, 0x93AD, 0xE682, 0x93AE, 0xE683, 0x93AF, 0xE684, 0x93B0, + 0xE685, 0x93B1, 0xE686, 0x93B2, 0xE687, 0x93B3, 0xE688, 0x93B4, 0xE689, 0x93B5, 0xE68A, 0x93B6, 0xE68B, 0x93B7, 0xE68C, 0x93B8, + 0xE68D, 0x93B9, 0xE68E, 0x93BA, 0xE68F, 0x93BB, 0xE690, 0x93BC, 0xE691, 0x93BD, 0xE692, 0x93BE, 0xE693, 0x93BF, 0xE694, 0x93C0, + 0xE695, 0x93C1, 0xE696, 0x93C2, 0xE697, 0x93C3, 0xE698, 0x93C4, 0xE699, 0x93C5, 0xE69A, 0x93C6, 0xE69B, 0x93C7, 0xE69C, 0x93C8, + 0xE69D, 0x93C9, 0xE69E, 0x93CB, 0xE69F, 0x93CC, 0xE6A0, 0x93CD, 0xE6A1, 0x5997, 0xE6A2, 0x59CA, 0xE6A3, 0x59AB, 0xE6A4, 0x599E, + 0xE6A5, 0x59A4, 0xE6A6, 0x59D2, 0xE6A7, 0x59B2, 0xE6A8, 0x59AF, 0xE6A9, 0x59D7, 0xE6AA, 0x59BE, 0xE6AB, 0x5A05, 0xE6AC, 0x5A06, + 0xE6AD, 0x59DD, 0xE6AE, 0x5A08, 0xE6AF, 0x59E3, 0xE6B0, 0x59D8, 0xE6B1, 0x59F9, 0xE6B2, 0x5A0C, 0xE6B3, 0x5A09, 0xE6B4, 0x5A32, + 0xE6B5, 0x5A34, 0xE6B6, 0x5A11, 0xE6B7, 0x5A23, 0xE6B8, 0x5A13, 0xE6B9, 0x5A40, 0xE6BA, 0x5A67, 0xE6BB, 0x5A4A, 0xE6BC, 0x5A55, + 0xE6BD, 0x5A3C, 0xE6BE, 0x5A62, 0xE6BF, 0x5A75, 0xE6C0, 0x80EC, 0xE6C1, 0x5AAA, 0xE6C2, 0x5A9B, 0xE6C3, 0x5A77, 0xE6C4, 0x5A7A, + 0xE6C5, 0x5ABE, 0xE6C6, 0x5AEB, 0xE6C7, 0x5AB2, 0xE6C8, 0x5AD2, 0xE6C9, 0x5AD4, 0xE6CA, 0x5AB8, 0xE6CB, 0x5AE0, 0xE6CC, 0x5AE3, + 0xE6CD, 0x5AF1, 0xE6CE, 0x5AD6, 0xE6CF, 0x5AE6, 0xE6D0, 0x5AD8, 0xE6D1, 0x5ADC, 0xE6D2, 0x5B09, 0xE6D3, 0x5B17, 0xE6D4, 0x5B16, + 0xE6D5, 0x5B32, 0xE6D6, 0x5B37, 0xE6D7, 0x5B40, 0xE6D8, 0x5C15, 0xE6D9, 0x5C1C, 0xE6DA, 0x5B5A, 0xE6DB, 0x5B65, 0xE6DC, 0x5B73, + 0xE6DD, 0x5B51, 0xE6DE, 0x5B53, 0xE6DF, 0x5B62, 0xE6E0, 0x9A75, 0xE6E1, 0x9A77, 0xE6E2, 0x9A78, 0xE6E3, 0x9A7A, 0xE6E4, 0x9A7F, + 0xE6E5, 0x9A7D, 0xE6E6, 0x9A80, 0xE6E7, 0x9A81, 0xE6E8, 0x9A85, 0xE6E9, 0x9A88, 0xE6EA, 0x9A8A, 0xE6EB, 0x9A90, 0xE6EC, 0x9A92, + 0xE6ED, 0x9A93, 0xE6EE, 0x9A96, 0xE6EF, 0x9A98, 0xE6F0, 0x9A9B, 0xE6F1, 0x9A9C, 0xE6F2, 0x9A9D, 0xE6F3, 0x9A9F, 0xE6F4, 0x9AA0, + 0xE6F5, 0x9AA2, 0xE6F6, 0x9AA3, 0xE6F7, 0x9AA5, 0xE6F8, 0x9AA7, 0xE6F9, 0x7E9F, 0xE6FA, 0x7EA1, 0xE6FB, 0x7EA3, 0xE6FC, 0x7EA5, + 0xE6FD, 0x7EA8, 0xE6FE, 0x7EA9, 0xE740, 0x93CE, 0xE741, 0x93CF, 0xE742, 0x93D0, 0xE743, 0x93D1, 0xE744, 0x93D2, 0xE745, 0x93D3, + 0xE746, 0x93D4, 0xE747, 0x93D5, 0xE748, 0x93D7, 0xE749, 0x93D8, 0xE74A, 0x93D9, 0xE74B, 0x93DA, 0xE74C, 0x93DB, 0xE74D, 0x93DC, + 0xE74E, 0x93DD, 0xE74F, 0x93DE, 0xE750, 0x93DF, 0xE751, 0x93E0, 0xE752, 0x93E1, 0xE753, 0x93E2, 0xE754, 0x93E3, 0xE755, 0x93E4, + 0xE756, 0x93E5, 0xE757, 0x93E6, 0xE758, 0x93E7, 0xE759, 0x93E8, 0xE75A, 0x93E9, 0xE75B, 0x93EA, 0xE75C, 0x93EB, 0xE75D, 0x93EC, + 0xE75E, 0x93ED, 0xE75F, 0x93EE, 0xE760, 0x93EF, 0xE761, 0x93F0, 0xE762, 0x93F1, 0xE763, 0x93F2, 0xE764, 0x93F3, 0xE765, 0x93F4, + 0xE766, 0x93F5, 0xE767, 0x93F6, 0xE768, 0x93F7, 0xE769, 0x93F8, 0xE76A, 0x93F9, 0xE76B, 0x93FA, 0xE76C, 0x93FB, 0xE76D, 0x93FC, + 0xE76E, 0x93FD, 0xE76F, 0x93FE, 0xE770, 0x93FF, 0xE771, 0x9400, 0xE772, 0x9401, 0xE773, 0x9402, 0xE774, 0x9403, 0xE775, 0x9404, + 0xE776, 0x9405, 0xE777, 0x9406, 0xE778, 0x9407, 0xE779, 0x9408, 0xE77A, 0x9409, 0xE77B, 0x940A, 0xE77C, 0x940B, 0xE77D, 0x940C, + 0xE77E, 0x940D, 0xE780, 0x940E, 0xE781, 0x940F, 0xE782, 0x9410, 0xE783, 0x9411, 0xE784, 0x9412, 0xE785, 0x9413, 0xE786, 0x9414, + 0xE787, 0x9415, 0xE788, 0x9416, 0xE789, 0x9417, 0xE78A, 0x9418, 0xE78B, 0x9419, 0xE78C, 0x941A, 0xE78D, 0x941B, 0xE78E, 0x941C, + 0xE78F, 0x941D, 0xE790, 0x941E, 0xE791, 0x941F, 0xE792, 0x9420, 0xE793, 0x9421, 0xE794, 0x9422, 0xE795, 0x9423, 0xE796, 0x9424, + 0xE797, 0x9425, 0xE798, 0x9426, 0xE799, 0x9427, 0xE79A, 0x9428, 0xE79B, 0x9429, 0xE79C, 0x942A, 0xE79D, 0x942B, 0xE79E, 0x942C, + 0xE79F, 0x942D, 0xE7A0, 0x942E, 0xE7A1, 0x7EAD, 0xE7A2, 0x7EB0, 0xE7A3, 0x7EBE, 0xE7A4, 0x7EC0, 0xE7A5, 0x7EC1, 0xE7A6, 0x7EC2, + 0xE7A7, 0x7EC9, 0xE7A8, 0x7ECB, 0xE7A9, 0x7ECC, 0xE7AA, 0x7ED0, 0xE7AB, 0x7ED4, 0xE7AC, 0x7ED7, 0xE7AD, 0x7EDB, 0xE7AE, 0x7EE0, + 0xE7AF, 0x7EE1, 0xE7B0, 0x7EE8, 0xE7B1, 0x7EEB, 0xE7B2, 0x7EEE, 0xE7B3, 0x7EEF, 0xE7B4, 0x7EF1, 0xE7B5, 0x7EF2, 0xE7B6, 0x7F0D, + 0xE7B7, 0x7EF6, 0xE7B8, 0x7EFA, 0xE7B9, 0x7EFB, 0xE7BA, 0x7EFE, 0xE7BB, 0x7F01, 0xE7BC, 0x7F02, 0xE7BD, 0x7F03, 0xE7BE, 0x7F07, + 0xE7BF, 0x7F08, 0xE7C0, 0x7F0B, 0xE7C1, 0x7F0C, 0xE7C2, 0x7F0F, 0xE7C3, 0x7F11, 0xE7C4, 0x7F12, 0xE7C5, 0x7F17, 0xE7C6, 0x7F19, + 0xE7C7, 0x7F1C, 0xE7C8, 0x7F1B, 0xE7C9, 0x7F1F, 0xE7CA, 0x7F21, 0xE7CB, 0x7F22, 0xE7CC, 0x7F23, 0xE7CD, 0x7F24, 0xE7CE, 0x7F25, + 0xE7CF, 0x7F26, 0xE7D0, 0x7F27, 0xE7D1, 0x7F2A, 0xE7D2, 0x7F2B, 0xE7D3, 0x7F2C, 0xE7D4, 0x7F2D, 0xE7D5, 0x7F2F, 0xE7D6, 0x7F30, + 0xE7D7, 0x7F31, 0xE7D8, 0x7F32, 0xE7D9, 0x7F33, 0xE7DA, 0x7F35, 0xE7DB, 0x5E7A, 0xE7DC, 0x757F, 0xE7DD, 0x5DDB, 0xE7DE, 0x753E, + 0xE7DF, 0x9095, 0xE7E0, 0x738E, 0xE7E1, 0x7391, 0xE7E2, 0x73AE, 0xE7E3, 0x73A2, 0xE7E4, 0x739F, 0xE7E5, 0x73CF, 0xE7E6, 0x73C2, + 0xE7E7, 0x73D1, 0xE7E8, 0x73B7, 0xE7E9, 0x73B3, 0xE7EA, 0x73C0, 0xE7EB, 0x73C9, 0xE7EC, 0x73C8, 0xE7ED, 0x73E5, 0xE7EE, 0x73D9, + 0xE7EF, 0x987C, 0xE7F0, 0x740A, 0xE7F1, 0x73E9, 0xE7F2, 0x73E7, 0xE7F3, 0x73DE, 0xE7F4, 0x73BA, 0xE7F5, 0x73F2, 0xE7F6, 0x740F, + 0xE7F7, 0x742A, 0xE7F8, 0x745B, 0xE7F9, 0x7426, 0xE7FA, 0x7425, 0xE7FB, 0x7428, 0xE7FC, 0x7430, 0xE7FD, 0x742E, 0xE7FE, 0x742C, + 0xE840, 0x942F, 0xE841, 0x9430, 0xE842, 0x9431, 0xE843, 0x9432, 0xE844, 0x9433, 0xE845, 0x9434, 0xE846, 0x9435, 0xE847, 0x9436, + 0xE848, 0x9437, 0xE849, 0x9438, 0xE84A, 0x9439, 0xE84B, 0x943A, 0xE84C, 0x943B, 0xE84D, 0x943C, 0xE84E, 0x943D, 0xE84F, 0x943F, + 0xE850, 0x9440, 0xE851, 0x9441, 0xE852, 0x9442, 0xE853, 0x9443, 0xE854, 0x9444, 0xE855, 0x9445, 0xE856, 0x9446, 0xE857, 0x9447, + 0xE858, 0x9448, 0xE859, 0x9449, 0xE85A, 0x944A, 0xE85B, 0x944B, 0xE85C, 0x944C, 0xE85D, 0x944D, 0xE85E, 0x944E, 0xE85F, 0x944F, + 0xE860, 0x9450, 0xE861, 0x9451, 0xE862, 0x9452, 0xE863, 0x9453, 0xE864, 0x9454, 0xE865, 0x9455, 0xE866, 0x9456, 0xE867, 0x9457, + 0xE868, 0x9458, 0xE869, 0x9459, 0xE86A, 0x945A, 0xE86B, 0x945B, 0xE86C, 0x945C, 0xE86D, 0x945D, 0xE86E, 0x945E, 0xE86F, 0x945F, + 0xE870, 0x9460, 0xE871, 0x9461, 0xE872, 0x9462, 0xE873, 0x9463, 0xE874, 0x9464, 0xE875, 0x9465, 0xE876, 0x9466, 0xE877, 0x9467, + 0xE878, 0x9468, 0xE879, 0x9469, 0xE87A, 0x946A, 0xE87B, 0x946C, 0xE87C, 0x946D, 0xE87D, 0x946E, 0xE87E, 0x946F, 0xE880, 0x9470, + 0xE881, 0x9471, 0xE882, 0x9472, 0xE883, 0x9473, 0xE884, 0x9474, 0xE885, 0x9475, 0xE886, 0x9476, 0xE887, 0x9477, 0xE888, 0x9478, + 0xE889, 0x9479, 0xE88A, 0x947A, 0xE88B, 0x947B, 0xE88C, 0x947C, 0xE88D, 0x947D, 0xE88E, 0x947E, 0xE88F, 0x947F, 0xE890, 0x9480, + 0xE891, 0x9481, 0xE892, 0x9482, 0xE893, 0x9483, 0xE894, 0x9484, 0xE895, 0x9491, 0xE896, 0x9496, 0xE897, 0x9498, 0xE898, 0x94C7, + 0xE899, 0x94CF, 0xE89A, 0x94D3, 0xE89B, 0x94D4, 0xE89C, 0x94DA, 0xE89D, 0x94E6, 0xE89E, 0x94FB, 0xE89F, 0x951C, 0xE8A0, 0x9520, + 0xE8A1, 0x741B, 0xE8A2, 0x741A, 0xE8A3, 0x7441, 0xE8A4, 0x745C, 0xE8A5, 0x7457, 0xE8A6, 0x7455, 0xE8A7, 0x7459, 0xE8A8, 0x7477, + 0xE8A9, 0x746D, 0xE8AA, 0x747E, 0xE8AB, 0x749C, 0xE8AC, 0x748E, 0xE8AD, 0x7480, 0xE8AE, 0x7481, 0xE8AF, 0x7487, 0xE8B0, 0x748B, + 0xE8B1, 0x749E, 0xE8B2, 0x74A8, 0xE8B3, 0x74A9, 0xE8B4, 0x7490, 0xE8B5, 0x74A7, 0xE8B6, 0x74D2, 0xE8B7, 0x74BA, 0xE8B8, 0x97EA, + 0xE8B9, 0x97EB, 0xE8BA, 0x97EC, 0xE8BB, 0x674C, 0xE8BC, 0x6753, 0xE8BD, 0x675E, 0xE8BE, 0x6748, 0xE8BF, 0x6769, 0xE8C0, 0x67A5, + 0xE8C1, 0x6787, 0xE8C2, 0x676A, 0xE8C3, 0x6773, 0xE8C4, 0x6798, 0xE8C5, 0x67A7, 0xE8C6, 0x6775, 0xE8C7, 0x67A8, 0xE8C8, 0x679E, + 0xE8C9, 0x67AD, 0xE8CA, 0x678B, 0xE8CB, 0x6777, 0xE8CC, 0x677C, 0xE8CD, 0x67F0, 0xE8CE, 0x6809, 0xE8CF, 0x67D8, 0xE8D0, 0x680A, + 0xE8D1, 0x67E9, 0xE8D2, 0x67B0, 0xE8D3, 0x680C, 0xE8D4, 0x67D9, 0xE8D5, 0x67B5, 0xE8D6, 0x67DA, 0xE8D7, 0x67B3, 0xE8D8, 0x67DD, + 0xE8D9, 0x6800, 0xE8DA, 0x67C3, 0xE8DB, 0x67B8, 0xE8DC, 0x67E2, 0xE8DD, 0x680E, 0xE8DE, 0x67C1, 0xE8DF, 0x67FD, 0xE8E0, 0x6832, + 0xE8E1, 0x6833, 0xE8E2, 0x6860, 0xE8E3, 0x6861, 0xE8E4, 0x684E, 0xE8E5, 0x6862, 0xE8E6, 0x6844, 0xE8E7, 0x6864, 0xE8E8, 0x6883, + 0xE8E9, 0x681D, 0xE8EA, 0x6855, 0xE8EB, 0x6866, 0xE8EC, 0x6841, 0xE8ED, 0x6867, 0xE8EE, 0x6840, 0xE8EF, 0x683E, 0xE8F0, 0x684A, + 0xE8F1, 0x6849, 0xE8F2, 0x6829, 0xE8F3, 0x68B5, 0xE8F4, 0x688F, 0xE8F5, 0x6874, 0xE8F6, 0x6877, 0xE8F7, 0x6893, 0xE8F8, 0x686B, + 0xE8F9, 0x68C2, 0xE8FA, 0x696E, 0xE8FB, 0x68FC, 0xE8FC, 0x691F, 0xE8FD, 0x6920, 0xE8FE, 0x68F9, 0xE940, 0x9527, 0xE941, 0x9533, + 0xE942, 0x953D, 0xE943, 0x9543, 0xE944, 0x9548, 0xE945, 0x954B, 0xE946, 0x9555, 0xE947, 0x955A, 0xE948, 0x9560, 0xE949, 0x956E, + 0xE94A, 0x9574, 0xE94B, 0x9575, 0xE94C, 0x9577, 0xE94D, 0x9578, 0xE94E, 0x9579, 0xE94F, 0x957A, 0xE950, 0x957B, 0xE951, 0x957C, + 0xE952, 0x957D, 0xE953, 0x957E, 0xE954, 0x9580, 0xE955, 0x9581, 0xE956, 0x9582, 0xE957, 0x9583, 0xE958, 0x9584, 0xE959, 0x9585, + 0xE95A, 0x9586, 0xE95B, 0x9587, 0xE95C, 0x9588, 0xE95D, 0x9589, 0xE95E, 0x958A, 0xE95F, 0x958B, 0xE960, 0x958C, 0xE961, 0x958D, + 0xE962, 0x958E, 0xE963, 0x958F, 0xE964, 0x9590, 0xE965, 0x9591, 0xE966, 0x9592, 0xE967, 0x9593, 0xE968, 0x9594, 0xE969, 0x9595, + 0xE96A, 0x9596, 0xE96B, 0x9597, 0xE96C, 0x9598, 0xE96D, 0x9599, 0xE96E, 0x959A, 0xE96F, 0x959B, 0xE970, 0x959C, 0xE971, 0x959D, + 0xE972, 0x959E, 0xE973, 0x959F, 0xE974, 0x95A0, 0xE975, 0x95A1, 0xE976, 0x95A2, 0xE977, 0x95A3, 0xE978, 0x95A4, 0xE979, 0x95A5, + 0xE97A, 0x95A6, 0xE97B, 0x95A7, 0xE97C, 0x95A8, 0xE97D, 0x95A9, 0xE97E, 0x95AA, 0xE980, 0x95AB, 0xE981, 0x95AC, 0xE982, 0x95AD, + 0xE983, 0x95AE, 0xE984, 0x95AF, 0xE985, 0x95B0, 0xE986, 0x95B1, 0xE987, 0x95B2, 0xE988, 0x95B3, 0xE989, 0x95B4, 0xE98A, 0x95B5, + 0xE98B, 0x95B6, 0xE98C, 0x95B7, 0xE98D, 0x95B8, 0xE98E, 0x95B9, 0xE98F, 0x95BA, 0xE990, 0x95BB, 0xE991, 0x95BC, 0xE992, 0x95BD, + 0xE993, 0x95BE, 0xE994, 0x95BF, 0xE995, 0x95C0, 0xE996, 0x95C1, 0xE997, 0x95C2, 0xE998, 0x95C3, 0xE999, 0x95C4, 0xE99A, 0x95C5, + 0xE99B, 0x95C6, 0xE99C, 0x95C7, 0xE99D, 0x95C8, 0xE99E, 0x95C9, 0xE99F, 0x95CA, 0xE9A0, 0x95CB, 0xE9A1, 0x6924, 0xE9A2, 0x68F0, + 0xE9A3, 0x690B, 0xE9A4, 0x6901, 0xE9A5, 0x6957, 0xE9A6, 0x68E3, 0xE9A7, 0x6910, 0xE9A8, 0x6971, 0xE9A9, 0x6939, 0xE9AA, 0x6960, + 0xE9AB, 0x6942, 0xE9AC, 0x695D, 0xE9AD, 0x6984, 0xE9AE, 0x696B, 0xE9AF, 0x6980, 0xE9B0, 0x6998, 0xE9B1, 0x6978, 0xE9B2, 0x6934, + 0xE9B3, 0x69CC, 0xE9B4, 0x6987, 0xE9B5, 0x6988, 0xE9B6, 0x69CE, 0xE9B7, 0x6989, 0xE9B8, 0x6966, 0xE9B9, 0x6963, 0xE9BA, 0x6979, + 0xE9BB, 0x699B, 0xE9BC, 0x69A7, 0xE9BD, 0x69BB, 0xE9BE, 0x69AB, 0xE9BF, 0x69AD, 0xE9C0, 0x69D4, 0xE9C1, 0x69B1, 0xE9C2, 0x69C1, + 0xE9C3, 0x69CA, 0xE9C4, 0x69DF, 0xE9C5, 0x6995, 0xE9C6, 0x69E0, 0xE9C7, 0x698D, 0xE9C8, 0x69FF, 0xE9C9, 0x6A2F, 0xE9CA, 0x69ED, + 0xE9CB, 0x6A17, 0xE9CC, 0x6A18, 0xE9CD, 0x6A65, 0xE9CE, 0x69F2, 0xE9CF, 0x6A44, 0xE9D0, 0x6A3E, 0xE9D1, 0x6AA0, 0xE9D2, 0x6A50, + 0xE9D3, 0x6A5B, 0xE9D4, 0x6A35, 0xE9D5, 0x6A8E, 0xE9D6, 0x6A79, 0xE9D7, 0x6A3D, 0xE9D8, 0x6A28, 0xE9D9, 0x6A58, 0xE9DA, 0x6A7C, + 0xE9DB, 0x6A91, 0xE9DC, 0x6A90, 0xE9DD, 0x6AA9, 0xE9DE, 0x6A97, 0xE9DF, 0x6AAB, 0xE9E0, 0x7337, 0xE9E1, 0x7352, 0xE9E2, 0x6B81, + 0xE9E3, 0x6B82, 0xE9E4, 0x6B87, 0xE9E5, 0x6B84, 0xE9E6, 0x6B92, 0xE9E7, 0x6B93, 0xE9E8, 0x6B8D, 0xE9E9, 0x6B9A, 0xE9EA, 0x6B9B, + 0xE9EB, 0x6BA1, 0xE9EC, 0x6BAA, 0xE9ED, 0x8F6B, 0xE9EE, 0x8F6D, 0xE9EF, 0x8F71, 0xE9F0, 0x8F72, 0xE9F1, 0x8F73, 0xE9F2, 0x8F75, + 0xE9F3, 0x8F76, 0xE9F4, 0x8F78, 0xE9F5, 0x8F77, 0xE9F6, 0x8F79, 0xE9F7, 0x8F7A, 0xE9F8, 0x8F7C, 0xE9F9, 0x8F7E, 0xE9FA, 0x8F81, + 0xE9FB, 0x8F82, 0xE9FC, 0x8F84, 0xE9FD, 0x8F87, 0xE9FE, 0x8F8B, 0xEA40, 0x95CC, 0xEA41, 0x95CD, 0xEA42, 0x95CE, 0xEA43, 0x95CF, + 0xEA44, 0x95D0, 0xEA45, 0x95D1, 0xEA46, 0x95D2, 0xEA47, 0x95D3, 0xEA48, 0x95D4, 0xEA49, 0x95D5, 0xEA4A, 0x95D6, 0xEA4B, 0x95D7, + 0xEA4C, 0x95D8, 0xEA4D, 0x95D9, 0xEA4E, 0x95DA, 0xEA4F, 0x95DB, 0xEA50, 0x95DC, 0xEA51, 0x95DD, 0xEA52, 0x95DE, 0xEA53, 0x95DF, + 0xEA54, 0x95E0, 0xEA55, 0x95E1, 0xEA56, 0x95E2, 0xEA57, 0x95E3, 0xEA58, 0x95E4, 0xEA59, 0x95E5, 0xEA5A, 0x95E6, 0xEA5B, 0x95E7, + 0xEA5C, 0x95EC, 0xEA5D, 0x95FF, 0xEA5E, 0x9607, 0xEA5F, 0x9613, 0xEA60, 0x9618, 0xEA61, 0x961B, 0xEA62, 0x961E, 0xEA63, 0x9620, + 0xEA64, 0x9623, 0xEA65, 0x9624, 0xEA66, 0x9625, 0xEA67, 0x9626, 0xEA68, 0x9627, 0xEA69, 0x9628, 0xEA6A, 0x9629, 0xEA6B, 0x962B, + 0xEA6C, 0x962C, 0xEA6D, 0x962D, 0xEA6E, 0x962F, 0xEA6F, 0x9630, 0xEA70, 0x9637, 0xEA71, 0x9638, 0xEA72, 0x9639, 0xEA73, 0x963A, + 0xEA74, 0x963E, 0xEA75, 0x9641, 0xEA76, 0x9643, 0xEA77, 0x964A, 0xEA78, 0x964E, 0xEA79, 0x964F, 0xEA7A, 0x9651, 0xEA7B, 0x9652, + 0xEA7C, 0x9653, 0xEA7D, 0x9656, 0xEA7E, 0x9657, 0xEA80, 0x9658, 0xEA81, 0x9659, 0xEA82, 0x965A, 0xEA83, 0x965C, 0xEA84, 0x965D, + 0xEA85, 0x965E, 0xEA86, 0x9660, 0xEA87, 0x9663, 0xEA88, 0x9665, 0xEA89, 0x9666, 0xEA8A, 0x966B, 0xEA8B, 0x966D, 0xEA8C, 0x966E, + 0xEA8D, 0x966F, 0xEA8E, 0x9670, 0xEA8F, 0x9671, 0xEA90, 0x9673, 0xEA91, 0x9678, 0xEA92, 0x9679, 0xEA93, 0x967A, 0xEA94, 0x967B, + 0xEA95, 0x967C, 0xEA96, 0x967D, 0xEA97, 0x967E, 0xEA98, 0x967F, 0xEA99, 0x9680, 0xEA9A, 0x9681, 0xEA9B, 0x9682, 0xEA9C, 0x9683, + 0xEA9D, 0x9684, 0xEA9E, 0x9687, 0xEA9F, 0x9689, 0xEAA0, 0x968A, 0xEAA1, 0x8F8D, 0xEAA2, 0x8F8E, 0xEAA3, 0x8F8F, 0xEAA4, 0x8F98, + 0xEAA5, 0x8F9A, 0xEAA6, 0x8ECE, 0xEAA7, 0x620B, 0xEAA8, 0x6217, 0xEAA9, 0x621B, 0xEAAA, 0x621F, 0xEAAB, 0x6222, 0xEAAC, 0x6221, + 0xEAAD, 0x6225, 0xEAAE, 0x6224, 0xEAAF, 0x622C, 0xEAB0, 0x81E7, 0xEAB1, 0x74EF, 0xEAB2, 0x74F4, 0xEAB3, 0x74FF, 0xEAB4, 0x750F, + 0xEAB5, 0x7511, 0xEAB6, 0x7513, 0xEAB7, 0x6534, 0xEAB8, 0x65EE, 0xEAB9, 0x65EF, 0xEABA, 0x65F0, 0xEABB, 0x660A, 0xEABC, 0x6619, + 0xEABD, 0x6772, 0xEABE, 0x6603, 0xEABF, 0x6615, 0xEAC0, 0x6600, 0xEAC1, 0x7085, 0xEAC2, 0x66F7, 0xEAC3, 0x661D, 0xEAC4, 0x6634, + 0xEAC5, 0x6631, 0xEAC6, 0x6636, 0xEAC7, 0x6635, 0xEAC8, 0x8006, 0xEAC9, 0x665F, 0xEACA, 0x6654, 0xEACB, 0x6641, 0xEACC, 0x664F, + 0xEACD, 0x6656, 0xEACE, 0x6661, 0xEACF, 0x6657, 0xEAD0, 0x6677, 0xEAD1, 0x6684, 0xEAD2, 0x668C, 0xEAD3, 0x66A7, 0xEAD4, 0x669D, + 0xEAD5, 0x66BE, 0xEAD6, 0x66DB, 0xEAD7, 0x66DC, 0xEAD8, 0x66E6, 0xEAD9, 0x66E9, 0xEADA, 0x8D32, 0xEADB, 0x8D33, 0xEADC, 0x8D36, + 0xEADD, 0x8D3B, 0xEADE, 0x8D3D, 0xEADF, 0x8D40, 0xEAE0, 0x8D45, 0xEAE1, 0x8D46, 0xEAE2, 0x8D48, 0xEAE3, 0x8D49, 0xEAE4, 0x8D47, + 0xEAE5, 0x8D4D, 0xEAE6, 0x8D55, 0xEAE7, 0x8D59, 0xEAE8, 0x89C7, 0xEAE9, 0x89CA, 0xEAEA, 0x89CB, 0xEAEB, 0x89CC, 0xEAEC, 0x89CE, + 0xEAED, 0x89CF, 0xEAEE, 0x89D0, 0xEAEF, 0x89D1, 0xEAF0, 0x726E, 0xEAF1, 0x729F, 0xEAF2, 0x725D, 0xEAF3, 0x7266, 0xEAF4, 0x726F, + 0xEAF5, 0x727E, 0xEAF6, 0x727F, 0xEAF7, 0x7284, 0xEAF8, 0x728B, 0xEAF9, 0x728D, 0xEAFA, 0x728F, 0xEAFB, 0x7292, 0xEAFC, 0x6308, + 0xEAFD, 0x6332, 0xEAFE, 0x63B0, 0xEB40, 0x968C, 0xEB41, 0x968E, 0xEB42, 0x9691, 0xEB43, 0x9692, 0xEB44, 0x9693, 0xEB45, 0x9695, + 0xEB46, 0x9696, 0xEB47, 0x969A, 0xEB48, 0x969B, 0xEB49, 0x969D, 0xEB4A, 0x969E, 0xEB4B, 0x969F, 0xEB4C, 0x96A0, 0xEB4D, 0x96A1, + 0xEB4E, 0x96A2, 0xEB4F, 0x96A3, 0xEB50, 0x96A4, 0xEB51, 0x96A5, 0xEB52, 0x96A6, 0xEB53, 0x96A8, 0xEB54, 0x96A9, 0xEB55, 0x96AA, + 0xEB56, 0x96AB, 0xEB57, 0x96AC, 0xEB58, 0x96AD, 0xEB59, 0x96AE, 0xEB5A, 0x96AF, 0xEB5B, 0x96B1, 0xEB5C, 0x96B2, 0xEB5D, 0x96B4, + 0xEB5E, 0x96B5, 0xEB5F, 0x96B7, 0xEB60, 0x96B8, 0xEB61, 0x96BA, 0xEB62, 0x96BB, 0xEB63, 0x96BF, 0xEB64, 0x96C2, 0xEB65, 0x96C3, + 0xEB66, 0x96C8, 0xEB67, 0x96CA, 0xEB68, 0x96CB, 0xEB69, 0x96D0, 0xEB6A, 0x96D1, 0xEB6B, 0x96D3, 0xEB6C, 0x96D4, 0xEB6D, 0x96D6, + 0xEB6E, 0x96D7, 0xEB6F, 0x96D8, 0xEB70, 0x96D9, 0xEB71, 0x96DA, 0xEB72, 0x96DB, 0xEB73, 0x96DC, 0xEB74, 0x96DD, 0xEB75, 0x96DE, + 0xEB76, 0x96DF, 0xEB77, 0x96E1, 0xEB78, 0x96E2, 0xEB79, 0x96E3, 0xEB7A, 0x96E4, 0xEB7B, 0x96E5, 0xEB7C, 0x96E6, 0xEB7D, 0x96E7, + 0xEB7E, 0x96EB, 0xEB80, 0x96EC, 0xEB81, 0x96ED, 0xEB82, 0x96EE, 0xEB83, 0x96F0, 0xEB84, 0x96F1, 0xEB85, 0x96F2, 0xEB86, 0x96F4, + 0xEB87, 0x96F5, 0xEB88, 0x96F8, 0xEB89, 0x96FA, 0xEB8A, 0x96FB, 0xEB8B, 0x96FC, 0xEB8C, 0x96FD, 0xEB8D, 0x96FF, 0xEB8E, 0x9702, + 0xEB8F, 0x9703, 0xEB90, 0x9705, 0xEB91, 0x970A, 0xEB92, 0x970B, 0xEB93, 0x970C, 0xEB94, 0x9710, 0xEB95, 0x9711, 0xEB96, 0x9712, + 0xEB97, 0x9714, 0xEB98, 0x9715, 0xEB99, 0x9717, 0xEB9A, 0x9718, 0xEB9B, 0x9719, 0xEB9C, 0x971A, 0xEB9D, 0x971B, 0xEB9E, 0x971D, + 0xEB9F, 0x971F, 0xEBA0, 0x9720, 0xEBA1, 0x643F, 0xEBA2, 0x64D8, 0xEBA3, 0x8004, 0xEBA4, 0x6BEA, 0xEBA5, 0x6BF3, 0xEBA6, 0x6BFD, + 0xEBA7, 0x6BF5, 0xEBA8, 0x6BF9, 0xEBA9, 0x6C05, 0xEBAA, 0x6C07, 0xEBAB, 0x6C06, 0xEBAC, 0x6C0D, 0xEBAD, 0x6C15, 0xEBAE, 0x6C18, + 0xEBAF, 0x6C19, 0xEBB0, 0x6C1A, 0xEBB1, 0x6C21, 0xEBB2, 0x6C29, 0xEBB3, 0x6C24, 0xEBB4, 0x6C2A, 0xEBB5, 0x6C32, 0xEBB6, 0x6535, + 0xEBB7, 0x6555, 0xEBB8, 0x656B, 0xEBB9, 0x724D, 0xEBBA, 0x7252, 0xEBBB, 0x7256, 0xEBBC, 0x7230, 0xEBBD, 0x8662, 0xEBBE, 0x5216, + 0xEBBF, 0x809F, 0xEBC0, 0x809C, 0xEBC1, 0x8093, 0xEBC2, 0x80BC, 0xEBC3, 0x670A, 0xEBC4, 0x80BD, 0xEBC5, 0x80B1, 0xEBC6, 0x80AB, + 0xEBC7, 0x80AD, 0xEBC8, 0x80B4, 0xEBC9, 0x80B7, 0xEBCA, 0x80E7, 0xEBCB, 0x80E8, 0xEBCC, 0x80E9, 0xEBCD, 0x80EA, 0xEBCE, 0x80DB, + 0xEBCF, 0x80C2, 0xEBD0, 0x80C4, 0xEBD1, 0x80D9, 0xEBD2, 0x80CD, 0xEBD3, 0x80D7, 0xEBD4, 0x6710, 0xEBD5, 0x80DD, 0xEBD6, 0x80EB, + 0xEBD7, 0x80F1, 0xEBD8, 0x80F4, 0xEBD9, 0x80ED, 0xEBDA, 0x810D, 0xEBDB, 0x810E, 0xEBDC, 0x80F2, 0xEBDD, 0x80FC, 0xEBDE, 0x6715, + 0xEBDF, 0x8112, 0xEBE0, 0x8C5A, 0xEBE1, 0x8136, 0xEBE2, 0x811E, 0xEBE3, 0x812C, 0xEBE4, 0x8118, 0xEBE5, 0x8132, 0xEBE6, 0x8148, + 0xEBE7, 0x814C, 0xEBE8, 0x8153, 0xEBE9, 0x8174, 0xEBEA, 0x8159, 0xEBEB, 0x815A, 0xEBEC, 0x8171, 0xEBED, 0x8160, 0xEBEE, 0x8169, + 0xEBEF, 0x817C, 0xEBF0, 0x817D, 0xEBF1, 0x816D, 0xEBF2, 0x8167, 0xEBF3, 0x584D, 0xEBF4, 0x5AB5, 0xEBF5, 0x8188, 0xEBF6, 0x8182, + 0xEBF7, 0x8191, 0xEBF8, 0x6ED5, 0xEBF9, 0x81A3, 0xEBFA, 0x81AA, 0xEBFB, 0x81CC, 0xEBFC, 0x6726, 0xEBFD, 0x81CA, 0xEBFE, 0x81BB, + 0xEC40, 0x9721, 0xEC41, 0x9722, 0xEC42, 0x9723, 0xEC43, 0x9724, 0xEC44, 0x9725, 0xEC45, 0x9726, 0xEC46, 0x9727, 0xEC47, 0x9728, + 0xEC48, 0x9729, 0xEC49, 0x972B, 0xEC4A, 0x972C, 0xEC4B, 0x972E, 0xEC4C, 0x972F, 0xEC4D, 0x9731, 0xEC4E, 0x9733, 0xEC4F, 0x9734, + 0xEC50, 0x9735, 0xEC51, 0x9736, 0xEC52, 0x9737, 0xEC53, 0x973A, 0xEC54, 0x973B, 0xEC55, 0x973C, 0xEC56, 0x973D, 0xEC57, 0x973F, + 0xEC58, 0x9740, 0xEC59, 0x9741, 0xEC5A, 0x9742, 0xEC5B, 0x9743, 0xEC5C, 0x9744, 0xEC5D, 0x9745, 0xEC5E, 0x9746, 0xEC5F, 0x9747, + 0xEC60, 0x9748, 0xEC61, 0x9749, 0xEC62, 0x974A, 0xEC63, 0x974B, 0xEC64, 0x974C, 0xEC65, 0x974D, 0xEC66, 0x974E, 0xEC67, 0x974F, + 0xEC68, 0x9750, 0xEC69, 0x9751, 0xEC6A, 0x9754, 0xEC6B, 0x9755, 0xEC6C, 0x9757, 0xEC6D, 0x9758, 0xEC6E, 0x975A, 0xEC6F, 0x975C, + 0xEC70, 0x975D, 0xEC71, 0x975F, 0xEC72, 0x9763, 0xEC73, 0x9764, 0xEC74, 0x9766, 0xEC75, 0x9767, 0xEC76, 0x9768, 0xEC77, 0x976A, + 0xEC78, 0x976B, 0xEC79, 0x976C, 0xEC7A, 0x976D, 0xEC7B, 0x976E, 0xEC7C, 0x976F, 0xEC7D, 0x9770, 0xEC7E, 0x9771, 0xEC80, 0x9772, + 0xEC81, 0x9775, 0xEC82, 0x9777, 0xEC83, 0x9778, 0xEC84, 0x9779, 0xEC85, 0x977A, 0xEC86, 0x977B, 0xEC87, 0x977D, 0xEC88, 0x977E, + 0xEC89, 0x977F, 0xEC8A, 0x9780, 0xEC8B, 0x9781, 0xEC8C, 0x9782, 0xEC8D, 0x9783, 0xEC8E, 0x9784, 0xEC8F, 0x9786, 0xEC90, 0x9787, + 0xEC91, 0x9788, 0xEC92, 0x9789, 0xEC93, 0x978A, 0xEC94, 0x978C, 0xEC95, 0x978E, 0xEC96, 0x978F, 0xEC97, 0x9790, 0xEC98, 0x9793, + 0xEC99, 0x9795, 0xEC9A, 0x9796, 0xEC9B, 0x9797, 0xEC9C, 0x9799, 0xEC9D, 0x979A, 0xEC9E, 0x979B, 0xEC9F, 0x979C, 0xECA0, 0x979D, + 0xECA1, 0x81C1, 0xECA2, 0x81A6, 0xECA3, 0x6B24, 0xECA4, 0x6B37, 0xECA5, 0x6B39, 0xECA6, 0x6B43, 0xECA7, 0x6B46, 0xECA8, 0x6B59, + 0xECA9, 0x98D1, 0xECAA, 0x98D2, 0xECAB, 0x98D3, 0xECAC, 0x98D5, 0xECAD, 0x98D9, 0xECAE, 0x98DA, 0xECAF, 0x6BB3, 0xECB0, 0x5F40, + 0xECB1, 0x6BC2, 0xECB2, 0x89F3, 0xECB3, 0x6590, 0xECB4, 0x9F51, 0xECB5, 0x6593, 0xECB6, 0x65BC, 0xECB7, 0x65C6, 0xECB8, 0x65C4, + 0xECB9, 0x65C3, 0xECBA, 0x65CC, 0xECBB, 0x65CE, 0xECBC, 0x65D2, 0xECBD, 0x65D6, 0xECBE, 0x7080, 0xECBF, 0x709C, 0xECC0, 0x7096, + 0xECC1, 0x709D, 0xECC2, 0x70BB, 0xECC3, 0x70C0, 0xECC4, 0x70B7, 0xECC5, 0x70AB, 0xECC6, 0x70B1, 0xECC7, 0x70E8, 0xECC8, 0x70CA, + 0xECC9, 0x7110, 0xECCA, 0x7113, 0xECCB, 0x7116, 0xECCC, 0x712F, 0xECCD, 0x7131, 0xECCE, 0x7173, 0xECCF, 0x715C, 0xECD0, 0x7168, + 0xECD1, 0x7145, 0xECD2, 0x7172, 0xECD3, 0x714A, 0xECD4, 0x7178, 0xECD5, 0x717A, 0xECD6, 0x7198, 0xECD7, 0x71B3, 0xECD8, 0x71B5, + 0xECD9, 0x71A8, 0xECDA, 0x71A0, 0xECDB, 0x71E0, 0xECDC, 0x71D4, 0xECDD, 0x71E7, 0xECDE, 0x71F9, 0xECDF, 0x721D, 0xECE0, 0x7228, + 0xECE1, 0x706C, 0xECE2, 0x7118, 0xECE3, 0x7166, 0xECE4, 0x71B9, 0xECE5, 0x623E, 0xECE6, 0x623D, 0xECE7, 0x6243, 0xECE8, 0x6248, + 0xECE9, 0x6249, 0xECEA, 0x793B, 0xECEB, 0x7940, 0xECEC, 0x7946, 0xECED, 0x7949, 0xECEE, 0x795B, 0xECEF, 0x795C, 0xECF0, 0x7953, + 0xECF1, 0x795A, 0xECF2, 0x7962, 0xECF3, 0x7957, 0xECF4, 0x7960, 0xECF5, 0x796F, 0xECF6, 0x7967, 0xECF7, 0x797A, 0xECF8, 0x7985, + 0xECF9, 0x798A, 0xECFA, 0x799A, 0xECFB, 0x79A7, 0xECFC, 0x79B3, 0xECFD, 0x5FD1, 0xECFE, 0x5FD0, 0xED40, 0x979E, 0xED41, 0x979F, + 0xED42, 0x97A1, 0xED43, 0x97A2, 0xED44, 0x97A4, 0xED45, 0x97A5, 0xED46, 0x97A6, 0xED47, 0x97A7, 0xED48, 0x97A8, 0xED49, 0x97A9, + 0xED4A, 0x97AA, 0xED4B, 0x97AC, 0xED4C, 0x97AE, 0xED4D, 0x97B0, 0xED4E, 0x97B1, 0xED4F, 0x97B3, 0xED50, 0x97B5, 0xED51, 0x97B6, + 0xED52, 0x97B7, 0xED53, 0x97B8, 0xED54, 0x97B9, 0xED55, 0x97BA, 0xED56, 0x97BB, 0xED57, 0x97BC, 0xED58, 0x97BD, 0xED59, 0x97BE, + 0xED5A, 0x97BF, 0xED5B, 0x97C0, 0xED5C, 0x97C1, 0xED5D, 0x97C2, 0xED5E, 0x97C3, 0xED5F, 0x97C4, 0xED60, 0x97C5, 0xED61, 0x97C6, + 0xED62, 0x97C7, 0xED63, 0x97C8, 0xED64, 0x97C9, 0xED65, 0x97CA, 0xED66, 0x97CB, 0xED67, 0x97CC, 0xED68, 0x97CD, 0xED69, 0x97CE, + 0xED6A, 0x97CF, 0xED6B, 0x97D0, 0xED6C, 0x97D1, 0xED6D, 0x97D2, 0xED6E, 0x97D3, 0xED6F, 0x97D4, 0xED70, 0x97D5, 0xED71, 0x97D6, + 0xED72, 0x97D7, 0xED73, 0x97D8, 0xED74, 0x97D9, 0xED75, 0x97DA, 0xED76, 0x97DB, 0xED77, 0x97DC, 0xED78, 0x97DD, 0xED79, 0x97DE, + 0xED7A, 0x97DF, 0xED7B, 0x97E0, 0xED7C, 0x97E1, 0xED7D, 0x97E2, 0xED7E, 0x97E3, 0xED80, 0x97E4, 0xED81, 0x97E5, 0xED82, 0x97E8, + 0xED83, 0x97EE, 0xED84, 0x97EF, 0xED85, 0x97F0, 0xED86, 0x97F1, 0xED87, 0x97F2, 0xED88, 0x97F4, 0xED89, 0x97F7, 0xED8A, 0x97F8, + 0xED8B, 0x97F9, 0xED8C, 0x97FA, 0xED8D, 0x97FB, 0xED8E, 0x97FC, 0xED8F, 0x97FD, 0xED90, 0x97FE, 0xED91, 0x97FF, 0xED92, 0x9800, + 0xED93, 0x9801, 0xED94, 0x9802, 0xED95, 0x9803, 0xED96, 0x9804, 0xED97, 0x9805, 0xED98, 0x9806, 0xED99, 0x9807, 0xED9A, 0x9808, + 0xED9B, 0x9809, 0xED9C, 0x980A, 0xED9D, 0x980B, 0xED9E, 0x980C, 0xED9F, 0x980D, 0xEDA0, 0x980E, 0xEDA1, 0x603C, 0xEDA2, 0x605D, + 0xEDA3, 0x605A, 0xEDA4, 0x6067, 0xEDA5, 0x6041, 0xEDA6, 0x6059, 0xEDA7, 0x6063, 0xEDA8, 0x60AB, 0xEDA9, 0x6106, 0xEDAA, 0x610D, + 0xEDAB, 0x615D, 0xEDAC, 0x61A9, 0xEDAD, 0x619D, 0xEDAE, 0x61CB, 0xEDAF, 0x61D1, 0xEDB0, 0x6206, 0xEDB1, 0x8080, 0xEDB2, 0x807F, + 0xEDB3, 0x6C93, 0xEDB4, 0x6CF6, 0xEDB5, 0x6DFC, 0xEDB6, 0x77F6, 0xEDB7, 0x77F8, 0xEDB8, 0x7800, 0xEDB9, 0x7809, 0xEDBA, 0x7817, + 0xEDBB, 0x7818, 0xEDBC, 0x7811, 0xEDBD, 0x65AB, 0xEDBE, 0x782D, 0xEDBF, 0x781C, 0xEDC0, 0x781D, 0xEDC1, 0x7839, 0xEDC2, 0x783A, + 0xEDC3, 0x783B, 0xEDC4, 0x781F, 0xEDC5, 0x783C, 0xEDC6, 0x7825, 0xEDC7, 0x782C, 0xEDC8, 0x7823, 0xEDC9, 0x7829, 0xEDCA, 0x784E, + 0xEDCB, 0x786D, 0xEDCC, 0x7856, 0xEDCD, 0x7857, 0xEDCE, 0x7826, 0xEDCF, 0x7850, 0xEDD0, 0x7847, 0xEDD1, 0x784C, 0xEDD2, 0x786A, + 0xEDD3, 0x789B, 0xEDD4, 0x7893, 0xEDD5, 0x789A, 0xEDD6, 0x7887, 0xEDD7, 0x789C, 0xEDD8, 0x78A1, 0xEDD9, 0x78A3, 0xEDDA, 0x78B2, + 0xEDDB, 0x78B9, 0xEDDC, 0x78A5, 0xEDDD, 0x78D4, 0xEDDE, 0x78D9, 0xEDDF, 0x78C9, 0xEDE0, 0x78EC, 0xEDE1, 0x78F2, 0xEDE2, 0x7905, + 0xEDE3, 0x78F4, 0xEDE4, 0x7913, 0xEDE5, 0x7924, 0xEDE6, 0x791E, 0xEDE7, 0x7934, 0xEDE8, 0x9F9B, 0xEDE9, 0x9EF9, 0xEDEA, 0x9EFB, + 0xEDEB, 0x9EFC, 0xEDEC, 0x76F1, 0xEDED, 0x7704, 0xEDEE, 0x770D, 0xEDEF, 0x76F9, 0xEDF0, 0x7707, 0xEDF1, 0x7708, 0xEDF2, 0x771A, + 0xEDF3, 0x7722, 0xEDF4, 0x7719, 0xEDF5, 0x772D, 0xEDF6, 0x7726, 0xEDF7, 0x7735, 0xEDF8, 0x7738, 0xEDF9, 0x7750, 0xEDFA, 0x7751, + 0xEDFB, 0x7747, 0xEDFC, 0x7743, 0xEDFD, 0x775A, 0xEDFE, 0x7768, 0xEE40, 0x980F, 0xEE41, 0x9810, 0xEE42, 0x9811, 0xEE43, 0x9812, + 0xEE44, 0x9813, 0xEE45, 0x9814, 0xEE46, 0x9815, 0xEE47, 0x9816, 0xEE48, 0x9817, 0xEE49, 0x9818, 0xEE4A, 0x9819, 0xEE4B, 0x981A, + 0xEE4C, 0x981B, 0xEE4D, 0x981C, 0xEE4E, 0x981D, 0xEE4F, 0x981E, 0xEE50, 0x981F, 0xEE51, 0x9820, 0xEE52, 0x9821, 0xEE53, 0x9822, + 0xEE54, 0x9823, 0xEE55, 0x9824, 0xEE56, 0x9825, 0xEE57, 0x9826, 0xEE58, 0x9827, 0xEE59, 0x9828, 0xEE5A, 0x9829, 0xEE5B, 0x982A, + 0xEE5C, 0x982B, 0xEE5D, 0x982C, 0xEE5E, 0x982D, 0xEE5F, 0x982E, 0xEE60, 0x982F, 0xEE61, 0x9830, 0xEE62, 0x9831, 0xEE63, 0x9832, + 0xEE64, 0x9833, 0xEE65, 0x9834, 0xEE66, 0x9835, 0xEE67, 0x9836, 0xEE68, 0x9837, 0xEE69, 0x9838, 0xEE6A, 0x9839, 0xEE6B, 0x983A, + 0xEE6C, 0x983B, 0xEE6D, 0x983C, 0xEE6E, 0x983D, 0xEE6F, 0x983E, 0xEE70, 0x983F, 0xEE71, 0x9840, 0xEE72, 0x9841, 0xEE73, 0x9842, + 0xEE74, 0x9843, 0xEE75, 0x9844, 0xEE76, 0x9845, 0xEE77, 0x9846, 0xEE78, 0x9847, 0xEE79, 0x9848, 0xEE7A, 0x9849, 0xEE7B, 0x984A, + 0xEE7C, 0x984B, 0xEE7D, 0x984C, 0xEE7E, 0x984D, 0xEE80, 0x984E, 0xEE81, 0x984F, 0xEE82, 0x9850, 0xEE83, 0x9851, 0xEE84, 0x9852, + 0xEE85, 0x9853, 0xEE86, 0x9854, 0xEE87, 0x9855, 0xEE88, 0x9856, 0xEE89, 0x9857, 0xEE8A, 0x9858, 0xEE8B, 0x9859, 0xEE8C, 0x985A, + 0xEE8D, 0x985B, 0xEE8E, 0x985C, 0xEE8F, 0x985D, 0xEE90, 0x985E, 0xEE91, 0x985F, 0xEE92, 0x9860, 0xEE93, 0x9861, 0xEE94, 0x9862, + 0xEE95, 0x9863, 0xEE96, 0x9864, 0xEE97, 0x9865, 0xEE98, 0x9866, 0xEE99, 0x9867, 0xEE9A, 0x9868, 0xEE9B, 0x9869, 0xEE9C, 0x986A, + 0xEE9D, 0x986B, 0xEE9E, 0x986C, 0xEE9F, 0x986D, 0xEEA0, 0x986E, 0xEEA1, 0x7762, 0xEEA2, 0x7765, 0xEEA3, 0x777F, 0xEEA4, 0x778D, + 0xEEA5, 0x777D, 0xEEA6, 0x7780, 0xEEA7, 0x778C, 0xEEA8, 0x7791, 0xEEA9, 0x779F, 0xEEAA, 0x77A0, 0xEEAB, 0x77B0, 0xEEAC, 0x77B5, + 0xEEAD, 0x77BD, 0xEEAE, 0x753A, 0xEEAF, 0x7540, 0xEEB0, 0x754E, 0xEEB1, 0x754B, 0xEEB2, 0x7548, 0xEEB3, 0x755B, 0xEEB4, 0x7572, + 0xEEB5, 0x7579, 0xEEB6, 0x7583, 0xEEB7, 0x7F58, 0xEEB8, 0x7F61, 0xEEB9, 0x7F5F, 0xEEBA, 0x8A48, 0xEEBB, 0x7F68, 0xEEBC, 0x7F74, + 0xEEBD, 0x7F71, 0xEEBE, 0x7F79, 0xEEBF, 0x7F81, 0xEEC0, 0x7F7E, 0xEEC1, 0x76CD, 0xEEC2, 0x76E5, 0xEEC3, 0x8832, 0xEEC4, 0x9485, + 0xEEC5, 0x9486, 0xEEC6, 0x9487, 0xEEC7, 0x948B, 0xEEC8, 0x948A, 0xEEC9, 0x948C, 0xEECA, 0x948D, 0xEECB, 0x948F, 0xEECC, 0x9490, + 0xEECD, 0x9494, 0xEECE, 0x9497, 0xEECF, 0x9495, 0xEED0, 0x949A, 0xEED1, 0x949B, 0xEED2, 0x949C, 0xEED3, 0x94A3, 0xEED4, 0x94A4, + 0xEED5, 0x94AB, 0xEED6, 0x94AA, 0xEED7, 0x94AD, 0xEED8, 0x94AC, 0xEED9, 0x94AF, 0xEEDA, 0x94B0, 0xEEDB, 0x94B2, 0xEEDC, 0x94B4, + 0xEEDD, 0x94B6, 0xEEDE, 0x94B7, 0xEEDF, 0x94B8, 0xEEE0, 0x94B9, 0xEEE1, 0x94BA, 0xEEE2, 0x94BC, 0xEEE3, 0x94BD, 0xEEE4, 0x94BF, + 0xEEE5, 0x94C4, 0xEEE6, 0x94C8, 0xEEE7, 0x94C9, 0xEEE8, 0x94CA, 0xEEE9, 0x94CB, 0xEEEA, 0x94CC, 0xEEEB, 0x94CD, 0xEEEC, 0x94CE, + 0xEEED, 0x94D0, 0xEEEE, 0x94D1, 0xEEEF, 0x94D2, 0xEEF0, 0x94D5, 0xEEF1, 0x94D6, 0xEEF2, 0x94D7, 0xEEF3, 0x94D9, 0xEEF4, 0x94D8, + 0xEEF5, 0x94DB, 0xEEF6, 0x94DE, 0xEEF7, 0x94DF, 0xEEF8, 0x94E0, 0xEEF9, 0x94E2, 0xEEFA, 0x94E4, 0xEEFB, 0x94E5, 0xEEFC, 0x94E7, + 0xEEFD, 0x94E8, 0xEEFE, 0x94EA, 0xEF40, 0x986F, 0xEF41, 0x9870, 0xEF42, 0x9871, 0xEF43, 0x9872, 0xEF44, 0x9873, 0xEF45, 0x9874, + 0xEF46, 0x988B, 0xEF47, 0x988E, 0xEF48, 0x9892, 0xEF49, 0x9895, 0xEF4A, 0x9899, 0xEF4B, 0x98A3, 0xEF4C, 0x98A8, 0xEF4D, 0x98A9, + 0xEF4E, 0x98AA, 0xEF4F, 0x98AB, 0xEF50, 0x98AC, 0xEF51, 0x98AD, 0xEF52, 0x98AE, 0xEF53, 0x98AF, 0xEF54, 0x98B0, 0xEF55, 0x98B1, + 0xEF56, 0x98B2, 0xEF57, 0x98B3, 0xEF58, 0x98B4, 0xEF59, 0x98B5, 0xEF5A, 0x98B6, 0xEF5B, 0x98B7, 0xEF5C, 0x98B8, 0xEF5D, 0x98B9, + 0xEF5E, 0x98BA, 0xEF5F, 0x98BB, 0xEF60, 0x98BC, 0xEF61, 0x98BD, 0xEF62, 0x98BE, 0xEF63, 0x98BF, 0xEF64, 0x98C0, 0xEF65, 0x98C1, + 0xEF66, 0x98C2, 0xEF67, 0x98C3, 0xEF68, 0x98C4, 0xEF69, 0x98C5, 0xEF6A, 0x98C6, 0xEF6B, 0x98C7, 0xEF6C, 0x98C8, 0xEF6D, 0x98C9, + 0xEF6E, 0x98CA, 0xEF6F, 0x98CB, 0xEF70, 0x98CC, 0xEF71, 0x98CD, 0xEF72, 0x98CF, 0xEF73, 0x98D0, 0xEF74, 0x98D4, 0xEF75, 0x98D6, + 0xEF76, 0x98D7, 0xEF77, 0x98DB, 0xEF78, 0x98DC, 0xEF79, 0x98DD, 0xEF7A, 0x98E0, 0xEF7B, 0x98E1, 0xEF7C, 0x98E2, 0xEF7D, 0x98E3, + 0xEF7E, 0x98E4, 0xEF80, 0x98E5, 0xEF81, 0x98E6, 0xEF82, 0x98E9, 0xEF83, 0x98EA, 0xEF84, 0x98EB, 0xEF85, 0x98EC, 0xEF86, 0x98ED, + 0xEF87, 0x98EE, 0xEF88, 0x98EF, 0xEF89, 0x98F0, 0xEF8A, 0x98F1, 0xEF8B, 0x98F2, 0xEF8C, 0x98F3, 0xEF8D, 0x98F4, 0xEF8E, 0x98F5, + 0xEF8F, 0x98F6, 0xEF90, 0x98F7, 0xEF91, 0x98F8, 0xEF92, 0x98F9, 0xEF93, 0x98FA, 0xEF94, 0x98FB, 0xEF95, 0x98FC, 0xEF96, 0x98FD, + 0xEF97, 0x98FE, 0xEF98, 0x98FF, 0xEF99, 0x9900, 0xEF9A, 0x9901, 0xEF9B, 0x9902, 0xEF9C, 0x9903, 0xEF9D, 0x9904, 0xEF9E, 0x9905, + 0xEF9F, 0x9906, 0xEFA0, 0x9907, 0xEFA1, 0x94E9, 0xEFA2, 0x94EB, 0xEFA3, 0x94EE, 0xEFA4, 0x94EF, 0xEFA5, 0x94F3, 0xEFA6, 0x94F4, + 0xEFA7, 0x94F5, 0xEFA8, 0x94F7, 0xEFA9, 0x94F9, 0xEFAA, 0x94FC, 0xEFAB, 0x94FD, 0xEFAC, 0x94FF, 0xEFAD, 0x9503, 0xEFAE, 0x9502, + 0xEFAF, 0x9506, 0xEFB0, 0x9507, 0xEFB1, 0x9509, 0xEFB2, 0x950A, 0xEFB3, 0x950D, 0xEFB4, 0x950E, 0xEFB5, 0x950F, 0xEFB6, 0x9512, + 0xEFB7, 0x9513, 0xEFB8, 0x9514, 0xEFB9, 0x9515, 0xEFBA, 0x9516, 0xEFBB, 0x9518, 0xEFBC, 0x951B, 0xEFBD, 0x951D, 0xEFBE, 0x951E, + 0xEFBF, 0x951F, 0xEFC0, 0x9522, 0xEFC1, 0x952A, 0xEFC2, 0x952B, 0xEFC3, 0x9529, 0xEFC4, 0x952C, 0xEFC5, 0x9531, 0xEFC6, 0x9532, + 0xEFC7, 0x9534, 0xEFC8, 0x9536, 0xEFC9, 0x9537, 0xEFCA, 0x9538, 0xEFCB, 0x953C, 0xEFCC, 0x953E, 0xEFCD, 0x953F, 0xEFCE, 0x9542, + 0xEFCF, 0x9535, 0xEFD0, 0x9544, 0xEFD1, 0x9545, 0xEFD2, 0x9546, 0xEFD3, 0x9549, 0xEFD4, 0x954C, 0xEFD5, 0x954E, 0xEFD6, 0x954F, + 0xEFD7, 0x9552, 0xEFD8, 0x9553, 0xEFD9, 0x9554, 0xEFDA, 0x9556, 0xEFDB, 0x9557, 0xEFDC, 0x9558, 0xEFDD, 0x9559, 0xEFDE, 0x955B, + 0xEFDF, 0x955E, 0xEFE0, 0x955F, 0xEFE1, 0x955D, 0xEFE2, 0x9561, 0xEFE3, 0x9562, 0xEFE4, 0x9564, 0xEFE5, 0x9565, 0xEFE6, 0x9566, + 0xEFE7, 0x9567, 0xEFE8, 0x9568, 0xEFE9, 0x9569, 0xEFEA, 0x956A, 0xEFEB, 0x956B, 0xEFEC, 0x956C, 0xEFED, 0x956F, 0xEFEE, 0x9571, + 0xEFEF, 0x9572, 0xEFF0, 0x9573, 0xEFF1, 0x953A, 0xEFF2, 0x77E7, 0xEFF3, 0x77EC, 0xEFF4, 0x96C9, 0xEFF5, 0x79D5, 0xEFF6, 0x79ED, + 0xEFF7, 0x79E3, 0xEFF8, 0x79EB, 0xEFF9, 0x7A06, 0xEFFA, 0x5D47, 0xEFFB, 0x7A03, 0xEFFC, 0x7A02, 0xEFFD, 0x7A1E, 0xEFFE, 0x7A14, + 0xF040, 0x9908, 0xF041, 0x9909, 0xF042, 0x990A, 0xF043, 0x990B, 0xF044, 0x990C, 0xF045, 0x990E, 0xF046, 0x990F, 0xF047, 0x9911, + 0xF048, 0x9912, 0xF049, 0x9913, 0xF04A, 0x9914, 0xF04B, 0x9915, 0xF04C, 0x9916, 0xF04D, 0x9917, 0xF04E, 0x9918, 0xF04F, 0x9919, + 0xF050, 0x991A, 0xF051, 0x991B, 0xF052, 0x991C, 0xF053, 0x991D, 0xF054, 0x991E, 0xF055, 0x991F, 0xF056, 0x9920, 0xF057, 0x9921, + 0xF058, 0x9922, 0xF059, 0x9923, 0xF05A, 0x9924, 0xF05B, 0x9925, 0xF05C, 0x9926, 0xF05D, 0x9927, 0xF05E, 0x9928, 0xF05F, 0x9929, + 0xF060, 0x992A, 0xF061, 0x992B, 0xF062, 0x992C, 0xF063, 0x992D, 0xF064, 0x992F, 0xF065, 0x9930, 0xF066, 0x9931, 0xF067, 0x9932, + 0xF068, 0x9933, 0xF069, 0x9934, 0xF06A, 0x9935, 0xF06B, 0x9936, 0xF06C, 0x9937, 0xF06D, 0x9938, 0xF06E, 0x9939, 0xF06F, 0x993A, + 0xF070, 0x993B, 0xF071, 0x993C, 0xF072, 0x993D, 0xF073, 0x993E, 0xF074, 0x993F, 0xF075, 0x9940, 0xF076, 0x9941, 0xF077, 0x9942, + 0xF078, 0x9943, 0xF079, 0x9944, 0xF07A, 0x9945, 0xF07B, 0x9946, 0xF07C, 0x9947, 0xF07D, 0x9948, 0xF07E, 0x9949, 0xF080, 0x994A, + 0xF081, 0x994B, 0xF082, 0x994C, 0xF083, 0x994D, 0xF084, 0x994E, 0xF085, 0x994F, 0xF086, 0x9950, 0xF087, 0x9951, 0xF088, 0x9952, + 0xF089, 0x9953, 0xF08A, 0x9956, 0xF08B, 0x9957, 0xF08C, 0x9958, 0xF08D, 0x9959, 0xF08E, 0x995A, 0xF08F, 0x995B, 0xF090, 0x995C, + 0xF091, 0x995D, 0xF092, 0x995E, 0xF093, 0x995F, 0xF094, 0x9960, 0xF095, 0x9961, 0xF096, 0x9962, 0xF097, 0x9964, 0xF098, 0x9966, + 0xF099, 0x9973, 0xF09A, 0x9978, 0xF09B, 0x9979, 0xF09C, 0x997B, 0xF09D, 0x997E, 0xF09E, 0x9982, 0xF09F, 0x9983, 0xF0A0, 0x9989, + 0xF0A1, 0x7A39, 0xF0A2, 0x7A37, 0xF0A3, 0x7A51, 0xF0A4, 0x9ECF, 0xF0A5, 0x99A5, 0xF0A6, 0x7A70, 0xF0A7, 0x7688, 0xF0A8, 0x768E, + 0xF0A9, 0x7693, 0xF0AA, 0x7699, 0xF0AB, 0x76A4, 0xF0AC, 0x74DE, 0xF0AD, 0x74E0, 0xF0AE, 0x752C, 0xF0AF, 0x9E20, 0xF0B0, 0x9E22, + 0xF0B1, 0x9E28, 0xF0B2, 0x9E29, 0xF0B3, 0x9E2A, 0xF0B4, 0x9E2B, 0xF0B5, 0x9E2C, 0xF0B6, 0x9E32, 0xF0B7, 0x9E31, 0xF0B8, 0x9E36, + 0xF0B9, 0x9E38, 0xF0BA, 0x9E37, 0xF0BB, 0x9E39, 0xF0BC, 0x9E3A, 0xF0BD, 0x9E3E, 0xF0BE, 0x9E41, 0xF0BF, 0x9E42, 0xF0C0, 0x9E44, + 0xF0C1, 0x9E46, 0xF0C2, 0x9E47, 0xF0C3, 0x9E48, 0xF0C4, 0x9E49, 0xF0C5, 0x9E4B, 0xF0C6, 0x9E4C, 0xF0C7, 0x9E4E, 0xF0C8, 0x9E51, + 0xF0C9, 0x9E55, 0xF0CA, 0x9E57, 0xF0CB, 0x9E5A, 0xF0CC, 0x9E5B, 0xF0CD, 0x9E5C, 0xF0CE, 0x9E5E, 0xF0CF, 0x9E63, 0xF0D0, 0x9E66, + 0xF0D1, 0x9E67, 0xF0D2, 0x9E68, 0xF0D3, 0x9E69, 0xF0D4, 0x9E6A, 0xF0D5, 0x9E6B, 0xF0D6, 0x9E6C, 0xF0D7, 0x9E71, 0xF0D8, 0x9E6D, + 0xF0D9, 0x9E73, 0xF0DA, 0x7592, 0xF0DB, 0x7594, 0xF0DC, 0x7596, 0xF0DD, 0x75A0, 0xF0DE, 0x759D, 0xF0DF, 0x75AC, 0xF0E0, 0x75A3, + 0xF0E1, 0x75B3, 0xF0E2, 0x75B4, 0xF0E3, 0x75B8, 0xF0E4, 0x75C4, 0xF0E5, 0x75B1, 0xF0E6, 0x75B0, 0xF0E7, 0x75C3, 0xF0E8, 0x75C2, + 0xF0E9, 0x75D6, 0xF0EA, 0x75CD, 0xF0EB, 0x75E3, 0xF0EC, 0x75E8, 0xF0ED, 0x75E6, 0xF0EE, 0x75E4, 0xF0EF, 0x75EB, 0xF0F0, 0x75E7, + 0xF0F1, 0x7603, 0xF0F2, 0x75F1, 0xF0F3, 0x75FC, 0xF0F4, 0x75FF, 0xF0F5, 0x7610, 0xF0F6, 0x7600, 0xF0F7, 0x7605, 0xF0F8, 0x760C, + 0xF0F9, 0x7617, 0xF0FA, 0x760A, 0xF0FB, 0x7625, 0xF0FC, 0x7618, 0xF0FD, 0x7615, 0xF0FE, 0x7619, 0xF140, 0x998C, 0xF141, 0x998E, + 0xF142, 0x999A, 0xF143, 0x999B, 0xF144, 0x999C, 0xF145, 0x999D, 0xF146, 0x999E, 0xF147, 0x999F, 0xF148, 0x99A0, 0xF149, 0x99A1, + 0xF14A, 0x99A2, 0xF14B, 0x99A3, 0xF14C, 0x99A4, 0xF14D, 0x99A6, 0xF14E, 0x99A7, 0xF14F, 0x99A9, 0xF150, 0x99AA, 0xF151, 0x99AB, + 0xF152, 0x99AC, 0xF153, 0x99AD, 0xF154, 0x99AE, 0xF155, 0x99AF, 0xF156, 0x99B0, 0xF157, 0x99B1, 0xF158, 0x99B2, 0xF159, 0x99B3, + 0xF15A, 0x99B4, 0xF15B, 0x99B5, 0xF15C, 0x99B6, 0xF15D, 0x99B7, 0xF15E, 0x99B8, 0xF15F, 0x99B9, 0xF160, 0x99BA, 0xF161, 0x99BB, + 0xF162, 0x99BC, 0xF163, 0x99BD, 0xF164, 0x99BE, 0xF165, 0x99BF, 0xF166, 0x99C0, 0xF167, 0x99C1, 0xF168, 0x99C2, 0xF169, 0x99C3, + 0xF16A, 0x99C4, 0xF16B, 0x99C5, 0xF16C, 0x99C6, 0xF16D, 0x99C7, 0xF16E, 0x99C8, 0xF16F, 0x99C9, 0xF170, 0x99CA, 0xF171, 0x99CB, + 0xF172, 0x99CC, 0xF173, 0x99CD, 0xF174, 0x99CE, 0xF175, 0x99CF, 0xF176, 0x99D0, 0xF177, 0x99D1, 0xF178, 0x99D2, 0xF179, 0x99D3, + 0xF17A, 0x99D4, 0xF17B, 0x99D5, 0xF17C, 0x99D6, 0xF17D, 0x99D7, 0xF17E, 0x99D8, 0xF180, 0x99D9, 0xF181, 0x99DA, 0xF182, 0x99DB, + 0xF183, 0x99DC, 0xF184, 0x99DD, 0xF185, 0x99DE, 0xF186, 0x99DF, 0xF187, 0x99E0, 0xF188, 0x99E1, 0xF189, 0x99E2, 0xF18A, 0x99E3, + 0xF18B, 0x99E4, 0xF18C, 0x99E5, 0xF18D, 0x99E6, 0xF18E, 0x99E7, 0xF18F, 0x99E8, 0xF190, 0x99E9, 0xF191, 0x99EA, 0xF192, 0x99EB, + 0xF193, 0x99EC, 0xF194, 0x99ED, 0xF195, 0x99EE, 0xF196, 0x99EF, 0xF197, 0x99F0, 0xF198, 0x99F1, 0xF199, 0x99F2, 0xF19A, 0x99F3, + 0xF19B, 0x99F4, 0xF19C, 0x99F5, 0xF19D, 0x99F6, 0xF19E, 0x99F7, 0xF19F, 0x99F8, 0xF1A0, 0x99F9, 0xF1A1, 0x761B, 0xF1A2, 0x763C, + 0xF1A3, 0x7622, 0xF1A4, 0x7620, 0xF1A5, 0x7640, 0xF1A6, 0x762D, 0xF1A7, 0x7630, 0xF1A8, 0x763F, 0xF1A9, 0x7635, 0xF1AA, 0x7643, + 0xF1AB, 0x763E, 0xF1AC, 0x7633, 0xF1AD, 0x764D, 0xF1AE, 0x765E, 0xF1AF, 0x7654, 0xF1B0, 0x765C, 0xF1B1, 0x7656, 0xF1B2, 0x766B, + 0xF1B3, 0x766F, 0xF1B4, 0x7FCA, 0xF1B5, 0x7AE6, 0xF1B6, 0x7A78, 0xF1B7, 0x7A79, 0xF1B8, 0x7A80, 0xF1B9, 0x7A86, 0xF1BA, 0x7A88, + 0xF1BB, 0x7A95, 0xF1BC, 0x7AA6, 0xF1BD, 0x7AA0, 0xF1BE, 0x7AAC, 0xF1BF, 0x7AA8, 0xF1C0, 0x7AAD, 0xF1C1, 0x7AB3, 0xF1C2, 0x8864, + 0xF1C3, 0x8869, 0xF1C4, 0x8872, 0xF1C5, 0x887D, 0xF1C6, 0x887F, 0xF1C7, 0x8882, 0xF1C8, 0x88A2, 0xF1C9, 0x88C6, 0xF1CA, 0x88B7, + 0xF1CB, 0x88BC, 0xF1CC, 0x88C9, 0xF1CD, 0x88E2, 0xF1CE, 0x88CE, 0xF1CF, 0x88E3, 0xF1D0, 0x88E5, 0xF1D1, 0x88F1, 0xF1D2, 0x891A, + 0xF1D3, 0x88FC, 0xF1D4, 0x88E8, 0xF1D5, 0x88FE, 0xF1D6, 0x88F0, 0xF1D7, 0x8921, 0xF1D8, 0x8919, 0xF1D9, 0x8913, 0xF1DA, 0x891B, + 0xF1DB, 0x890A, 0xF1DC, 0x8934, 0xF1DD, 0x892B, 0xF1DE, 0x8936, 0xF1DF, 0x8941, 0xF1E0, 0x8966, 0xF1E1, 0x897B, 0xF1E2, 0x758B, + 0xF1E3, 0x80E5, 0xF1E4, 0x76B2, 0xF1E5, 0x76B4, 0xF1E6, 0x77DC, 0xF1E7, 0x8012, 0xF1E8, 0x8014, 0xF1E9, 0x8016, 0xF1EA, 0x801C, + 0xF1EB, 0x8020, 0xF1EC, 0x8022, 0xF1ED, 0x8025, 0xF1EE, 0x8026, 0xF1EF, 0x8027, 0xF1F0, 0x8029, 0xF1F1, 0x8028, 0xF1F2, 0x8031, + 0xF1F3, 0x800B, 0xF1F4, 0x8035, 0xF1F5, 0x8043, 0xF1F6, 0x8046, 0xF1F7, 0x804D, 0xF1F8, 0x8052, 0xF1F9, 0x8069, 0xF1FA, 0x8071, + 0xF1FB, 0x8983, 0xF1FC, 0x9878, 0xF1FD, 0x9880, 0xF1FE, 0x9883, 0xF240, 0x99FA, 0xF241, 0x99FB, 0xF242, 0x99FC, 0xF243, 0x99FD, + 0xF244, 0x99FE, 0xF245, 0x99FF, 0xF246, 0x9A00, 0xF247, 0x9A01, 0xF248, 0x9A02, 0xF249, 0x9A03, 0xF24A, 0x9A04, 0xF24B, 0x9A05, + 0xF24C, 0x9A06, 0xF24D, 0x9A07, 0xF24E, 0x9A08, 0xF24F, 0x9A09, 0xF250, 0x9A0A, 0xF251, 0x9A0B, 0xF252, 0x9A0C, 0xF253, 0x9A0D, + 0xF254, 0x9A0E, 0xF255, 0x9A0F, 0xF256, 0x9A10, 0xF257, 0x9A11, 0xF258, 0x9A12, 0xF259, 0x9A13, 0xF25A, 0x9A14, 0xF25B, 0x9A15, + 0xF25C, 0x9A16, 0xF25D, 0x9A17, 0xF25E, 0x9A18, 0xF25F, 0x9A19, 0xF260, 0x9A1A, 0xF261, 0x9A1B, 0xF262, 0x9A1C, 0xF263, 0x9A1D, + 0xF264, 0x9A1E, 0xF265, 0x9A1F, 0xF266, 0x9A20, 0xF267, 0x9A21, 0xF268, 0x9A22, 0xF269, 0x9A23, 0xF26A, 0x9A24, 0xF26B, 0x9A25, + 0xF26C, 0x9A26, 0xF26D, 0x9A27, 0xF26E, 0x9A28, 0xF26F, 0x9A29, 0xF270, 0x9A2A, 0xF271, 0x9A2B, 0xF272, 0x9A2C, 0xF273, 0x9A2D, + 0xF274, 0x9A2E, 0xF275, 0x9A2F, 0xF276, 0x9A30, 0xF277, 0x9A31, 0xF278, 0x9A32, 0xF279, 0x9A33, 0xF27A, 0x9A34, 0xF27B, 0x9A35, + 0xF27C, 0x9A36, 0xF27D, 0x9A37, 0xF27E, 0x9A38, 0xF280, 0x9A39, 0xF281, 0x9A3A, 0xF282, 0x9A3B, 0xF283, 0x9A3C, 0xF284, 0x9A3D, + 0xF285, 0x9A3E, 0xF286, 0x9A3F, 0xF287, 0x9A40, 0xF288, 0x9A41, 0xF289, 0x9A42, 0xF28A, 0x9A43, 0xF28B, 0x9A44, 0xF28C, 0x9A45, + 0xF28D, 0x9A46, 0xF28E, 0x9A47, 0xF28F, 0x9A48, 0xF290, 0x9A49, 0xF291, 0x9A4A, 0xF292, 0x9A4B, 0xF293, 0x9A4C, 0xF294, 0x9A4D, + 0xF295, 0x9A4E, 0xF296, 0x9A4F, 0xF297, 0x9A50, 0xF298, 0x9A51, 0xF299, 0x9A52, 0xF29A, 0x9A53, 0xF29B, 0x9A54, 0xF29C, 0x9A55, + 0xF29D, 0x9A56, 0xF29E, 0x9A57, 0xF29F, 0x9A58, 0xF2A0, 0x9A59, 0xF2A1, 0x9889, 0xF2A2, 0x988C, 0xF2A3, 0x988D, 0xF2A4, 0x988F, + 0xF2A5, 0x9894, 0xF2A6, 0x989A, 0xF2A7, 0x989B, 0xF2A8, 0x989E, 0xF2A9, 0x989F, 0xF2AA, 0x98A1, 0xF2AB, 0x98A2, 0xF2AC, 0x98A5, + 0xF2AD, 0x98A6, 0xF2AE, 0x864D, 0xF2AF, 0x8654, 0xF2B0, 0x866C, 0xF2B1, 0x866E, 0xF2B2, 0x867F, 0xF2B3, 0x867A, 0xF2B4, 0x867C, + 0xF2B5, 0x867B, 0xF2B6, 0x86A8, 0xF2B7, 0x868D, 0xF2B8, 0x868B, 0xF2B9, 0x86AC, 0xF2BA, 0x869D, 0xF2BB, 0x86A7, 0xF2BC, 0x86A3, + 0xF2BD, 0x86AA, 0xF2BE, 0x8693, 0xF2BF, 0x86A9, 0xF2C0, 0x86B6, 0xF2C1, 0x86C4, 0xF2C2, 0x86B5, 0xF2C3, 0x86CE, 0xF2C4, 0x86B0, + 0xF2C5, 0x86BA, 0xF2C6, 0x86B1, 0xF2C7, 0x86AF, 0xF2C8, 0x86C9, 0xF2C9, 0x86CF, 0xF2CA, 0x86B4, 0xF2CB, 0x86E9, 0xF2CC, 0x86F1, + 0xF2CD, 0x86F2, 0xF2CE, 0x86ED, 0xF2CF, 0x86F3, 0xF2D0, 0x86D0, 0xF2D1, 0x8713, 0xF2D2, 0x86DE, 0xF2D3, 0x86F4, 0xF2D4, 0x86DF, + 0xF2D5, 0x86D8, 0xF2D6, 0x86D1, 0xF2D7, 0x8703, 0xF2D8, 0x8707, 0xF2D9, 0x86F8, 0xF2DA, 0x8708, 0xF2DB, 0x870A, 0xF2DC, 0x870D, + 0xF2DD, 0x8709, 0xF2DE, 0x8723, 0xF2DF, 0x873B, 0xF2E0, 0x871E, 0xF2E1, 0x8725, 0xF2E2, 0x872E, 0xF2E3, 0x871A, 0xF2E4, 0x873E, + 0xF2E5, 0x8748, 0xF2E6, 0x8734, 0xF2E7, 0x8731, 0xF2E8, 0x8729, 0xF2E9, 0x8737, 0xF2EA, 0x873F, 0xF2EB, 0x8782, 0xF2EC, 0x8722, + 0xF2ED, 0x877D, 0xF2EE, 0x877E, 0xF2EF, 0x877B, 0xF2F0, 0x8760, 0xF2F1, 0x8770, 0xF2F2, 0x874C, 0xF2F3, 0x876E, 0xF2F4, 0x878B, + 0xF2F5, 0x8753, 0xF2F6, 0x8763, 0xF2F7, 0x877C, 0xF2F8, 0x8764, 0xF2F9, 0x8759, 0xF2FA, 0x8765, 0xF2FB, 0x8793, 0xF2FC, 0x87AF, + 0xF2FD, 0x87A8, 0xF2FE, 0x87D2, 0xF340, 0x9A5A, 0xF341, 0x9A5B, 0xF342, 0x9A5C, 0xF343, 0x9A5D, 0xF344, 0x9A5E, 0xF345, 0x9A5F, + 0xF346, 0x9A60, 0xF347, 0x9A61, 0xF348, 0x9A62, 0xF349, 0x9A63, 0xF34A, 0x9A64, 0xF34B, 0x9A65, 0xF34C, 0x9A66, 0xF34D, 0x9A67, + 0xF34E, 0x9A68, 0xF34F, 0x9A69, 0xF350, 0x9A6A, 0xF351, 0x9A6B, 0xF352, 0x9A72, 0xF353, 0x9A83, 0xF354, 0x9A89, 0xF355, 0x9A8D, + 0xF356, 0x9A8E, 0xF357, 0x9A94, 0xF358, 0x9A95, 0xF359, 0x9A99, 0xF35A, 0x9AA6, 0xF35B, 0x9AA9, 0xF35C, 0x9AAA, 0xF35D, 0x9AAB, + 0xF35E, 0x9AAC, 0xF35F, 0x9AAD, 0xF360, 0x9AAE, 0xF361, 0x9AAF, 0xF362, 0x9AB2, 0xF363, 0x9AB3, 0xF364, 0x9AB4, 0xF365, 0x9AB5, + 0xF366, 0x9AB9, 0xF367, 0x9ABB, 0xF368, 0x9ABD, 0xF369, 0x9ABE, 0xF36A, 0x9ABF, 0xF36B, 0x9AC3, 0xF36C, 0x9AC4, 0xF36D, 0x9AC6, + 0xF36E, 0x9AC7, 0xF36F, 0x9AC8, 0xF370, 0x9AC9, 0xF371, 0x9ACA, 0xF372, 0x9ACD, 0xF373, 0x9ACE, 0xF374, 0x9ACF, 0xF375, 0x9AD0, + 0xF376, 0x9AD2, 0xF377, 0x9AD4, 0xF378, 0x9AD5, 0xF379, 0x9AD6, 0xF37A, 0x9AD7, 0xF37B, 0x9AD9, 0xF37C, 0x9ADA, 0xF37D, 0x9ADB, + 0xF37E, 0x9ADC, 0xF380, 0x9ADD, 0xF381, 0x9ADE, 0xF382, 0x9AE0, 0xF383, 0x9AE2, 0xF384, 0x9AE3, 0xF385, 0x9AE4, 0xF386, 0x9AE5, + 0xF387, 0x9AE7, 0xF388, 0x9AE8, 0xF389, 0x9AE9, 0xF38A, 0x9AEA, 0xF38B, 0x9AEC, 0xF38C, 0x9AEE, 0xF38D, 0x9AF0, 0xF38E, 0x9AF1, + 0xF38F, 0x9AF2, 0xF390, 0x9AF3, 0xF391, 0x9AF4, 0xF392, 0x9AF5, 0xF393, 0x9AF6, 0xF394, 0x9AF7, 0xF395, 0x9AF8, 0xF396, 0x9AFA, + 0xF397, 0x9AFC, 0xF398, 0x9AFD, 0xF399, 0x9AFE, 0xF39A, 0x9AFF, 0xF39B, 0x9B00, 0xF39C, 0x9B01, 0xF39D, 0x9B02, 0xF39E, 0x9B04, + 0xF39F, 0x9B05, 0xF3A0, 0x9B06, 0xF3A1, 0x87C6, 0xF3A2, 0x8788, 0xF3A3, 0x8785, 0xF3A4, 0x87AD, 0xF3A5, 0x8797, 0xF3A6, 0x8783, + 0xF3A7, 0x87AB, 0xF3A8, 0x87E5, 0xF3A9, 0x87AC, 0xF3AA, 0x87B5, 0xF3AB, 0x87B3, 0xF3AC, 0x87CB, 0xF3AD, 0x87D3, 0xF3AE, 0x87BD, + 0xF3AF, 0x87D1, 0xF3B0, 0x87C0, 0xF3B1, 0x87CA, 0xF3B2, 0x87DB, 0xF3B3, 0x87EA, 0xF3B4, 0x87E0, 0xF3B5, 0x87EE, 0xF3B6, 0x8816, + 0xF3B7, 0x8813, 0xF3B8, 0x87FE, 0xF3B9, 0x880A, 0xF3BA, 0x881B, 0xF3BB, 0x8821, 0xF3BC, 0x8839, 0xF3BD, 0x883C, 0xF3BE, 0x7F36, + 0xF3BF, 0x7F42, 0xF3C0, 0x7F44, 0xF3C1, 0x7F45, 0xF3C2, 0x8210, 0xF3C3, 0x7AFA, 0xF3C4, 0x7AFD, 0xF3C5, 0x7B08, 0xF3C6, 0x7B03, + 0xF3C7, 0x7B04, 0xF3C8, 0x7B15, 0xF3C9, 0x7B0A, 0xF3CA, 0x7B2B, 0xF3CB, 0x7B0F, 0xF3CC, 0x7B47, 0xF3CD, 0x7B38, 0xF3CE, 0x7B2A, + 0xF3CF, 0x7B19, 0xF3D0, 0x7B2E, 0xF3D1, 0x7B31, 0xF3D2, 0x7B20, 0xF3D3, 0x7B25, 0xF3D4, 0x7B24, 0xF3D5, 0x7B33, 0xF3D6, 0x7B3E, + 0xF3D7, 0x7B1E, 0xF3D8, 0x7B58, 0xF3D9, 0x7B5A, 0xF3DA, 0x7B45, 0xF3DB, 0x7B75, 0xF3DC, 0x7B4C, 0xF3DD, 0x7B5D, 0xF3DE, 0x7B60, + 0xF3DF, 0x7B6E, 0xF3E0, 0x7B7B, 0xF3E1, 0x7B62, 0xF3E2, 0x7B72, 0xF3E3, 0x7B71, 0xF3E4, 0x7B90, 0xF3E5, 0x7BA6, 0xF3E6, 0x7BA7, + 0xF3E7, 0x7BB8, 0xF3E8, 0x7BAC, 0xF3E9, 0x7B9D, 0xF3EA, 0x7BA8, 0xF3EB, 0x7B85, 0xF3EC, 0x7BAA, 0xF3ED, 0x7B9C, 0xF3EE, 0x7BA2, + 0xF3EF, 0x7BAB, 0xF3F0, 0x7BB4, 0xF3F1, 0x7BD1, 0xF3F2, 0x7BC1, 0xF3F3, 0x7BCC, 0xF3F4, 0x7BDD, 0xF3F5, 0x7BDA, 0xF3F6, 0x7BE5, + 0xF3F7, 0x7BE6, 0xF3F8, 0x7BEA, 0xF3F9, 0x7C0C, 0xF3FA, 0x7BFE, 0xF3FB, 0x7BFC, 0xF3FC, 0x7C0F, 0xF3FD, 0x7C16, 0xF3FE, 0x7C0B, + 0xF440, 0x9B07, 0xF441, 0x9B09, 0xF442, 0x9B0A, 0xF443, 0x9B0B, 0xF444, 0x9B0C, 0xF445, 0x9B0D, 0xF446, 0x9B0E, 0xF447, 0x9B10, + 0xF448, 0x9B11, 0xF449, 0x9B12, 0xF44A, 0x9B14, 0xF44B, 0x9B15, 0xF44C, 0x9B16, 0xF44D, 0x9B17, 0xF44E, 0x9B18, 0xF44F, 0x9B19, + 0xF450, 0x9B1A, 0xF451, 0x9B1B, 0xF452, 0x9B1C, 0xF453, 0x9B1D, 0xF454, 0x9B1E, 0xF455, 0x9B20, 0xF456, 0x9B21, 0xF457, 0x9B22, + 0xF458, 0x9B24, 0xF459, 0x9B25, 0xF45A, 0x9B26, 0xF45B, 0x9B27, 0xF45C, 0x9B28, 0xF45D, 0x9B29, 0xF45E, 0x9B2A, 0xF45F, 0x9B2B, + 0xF460, 0x9B2C, 0xF461, 0x9B2D, 0xF462, 0x9B2E, 0xF463, 0x9B30, 0xF464, 0x9B31, 0xF465, 0x9B33, 0xF466, 0x9B34, 0xF467, 0x9B35, + 0xF468, 0x9B36, 0xF469, 0x9B37, 0xF46A, 0x9B38, 0xF46B, 0x9B39, 0xF46C, 0x9B3A, 0xF46D, 0x9B3D, 0xF46E, 0x9B3E, 0xF46F, 0x9B3F, + 0xF470, 0x9B40, 0xF471, 0x9B46, 0xF472, 0x9B4A, 0xF473, 0x9B4B, 0xF474, 0x9B4C, 0xF475, 0x9B4E, 0xF476, 0x9B50, 0xF477, 0x9B52, + 0xF478, 0x9B53, 0xF479, 0x9B55, 0xF47A, 0x9B56, 0xF47B, 0x9B57, 0xF47C, 0x9B58, 0xF47D, 0x9B59, 0xF47E, 0x9B5A, 0xF480, 0x9B5B, + 0xF481, 0x9B5C, 0xF482, 0x9B5D, 0xF483, 0x9B5E, 0xF484, 0x9B5F, 0xF485, 0x9B60, 0xF486, 0x9B61, 0xF487, 0x9B62, 0xF488, 0x9B63, + 0xF489, 0x9B64, 0xF48A, 0x9B65, 0xF48B, 0x9B66, 0xF48C, 0x9B67, 0xF48D, 0x9B68, 0xF48E, 0x9B69, 0xF48F, 0x9B6A, 0xF490, 0x9B6B, + 0xF491, 0x9B6C, 0xF492, 0x9B6D, 0xF493, 0x9B6E, 0xF494, 0x9B6F, 0xF495, 0x9B70, 0xF496, 0x9B71, 0xF497, 0x9B72, 0xF498, 0x9B73, + 0xF499, 0x9B74, 0xF49A, 0x9B75, 0xF49B, 0x9B76, 0xF49C, 0x9B77, 0xF49D, 0x9B78, 0xF49E, 0x9B79, 0xF49F, 0x9B7A, 0xF4A0, 0x9B7B, + 0xF4A1, 0x7C1F, 0xF4A2, 0x7C2A, 0xF4A3, 0x7C26, 0xF4A4, 0x7C38, 0xF4A5, 0x7C41, 0xF4A6, 0x7C40, 0xF4A7, 0x81FE, 0xF4A8, 0x8201, + 0xF4A9, 0x8202, 0xF4AA, 0x8204, 0xF4AB, 0x81EC, 0xF4AC, 0x8844, 0xF4AD, 0x8221, 0xF4AE, 0x8222, 0xF4AF, 0x8223, 0xF4B0, 0x822D, + 0xF4B1, 0x822F, 0xF4B2, 0x8228, 0xF4B3, 0x822B, 0xF4B4, 0x8238, 0xF4B5, 0x823B, 0xF4B6, 0x8233, 0xF4B7, 0x8234, 0xF4B8, 0x823E, + 0xF4B9, 0x8244, 0xF4BA, 0x8249, 0xF4BB, 0x824B, 0xF4BC, 0x824F, 0xF4BD, 0x825A, 0xF4BE, 0x825F, 0xF4BF, 0x8268, 0xF4C0, 0x887E, + 0xF4C1, 0x8885, 0xF4C2, 0x8888, 0xF4C3, 0x88D8, 0xF4C4, 0x88DF, 0xF4C5, 0x895E, 0xF4C6, 0x7F9D, 0xF4C7, 0x7F9F, 0xF4C8, 0x7FA7, + 0xF4C9, 0x7FAF, 0xF4CA, 0x7FB0, 0xF4CB, 0x7FB2, 0xF4CC, 0x7C7C, 0xF4CD, 0x6549, 0xF4CE, 0x7C91, 0xF4CF, 0x7C9D, 0xF4D0, 0x7C9C, + 0xF4D1, 0x7C9E, 0xF4D2, 0x7CA2, 0xF4D3, 0x7CB2, 0xF4D4, 0x7CBC, 0xF4D5, 0x7CBD, 0xF4D6, 0x7CC1, 0xF4D7, 0x7CC7, 0xF4D8, 0x7CCC, + 0xF4D9, 0x7CCD, 0xF4DA, 0x7CC8, 0xF4DB, 0x7CC5, 0xF4DC, 0x7CD7, 0xF4DD, 0x7CE8, 0xF4DE, 0x826E, 0xF4DF, 0x66A8, 0xF4E0, 0x7FBF, + 0xF4E1, 0x7FCE, 0xF4E2, 0x7FD5, 0xF4E3, 0x7FE5, 0xF4E4, 0x7FE1, 0xF4E5, 0x7FE6, 0xF4E6, 0x7FE9, 0xF4E7, 0x7FEE, 0xF4E8, 0x7FF3, + 0xF4E9, 0x7CF8, 0xF4EA, 0x7D77, 0xF4EB, 0x7DA6, 0xF4EC, 0x7DAE, 0xF4ED, 0x7E47, 0xF4EE, 0x7E9B, 0xF4EF, 0x9EB8, 0xF4F0, 0x9EB4, + 0xF4F1, 0x8D73, 0xF4F2, 0x8D84, 0xF4F3, 0x8D94, 0xF4F4, 0x8D91, 0xF4F5, 0x8DB1, 0xF4F6, 0x8D67, 0xF4F7, 0x8D6D, 0xF4F8, 0x8C47, + 0xF4F9, 0x8C49, 0xF4FA, 0x914A, 0xF4FB, 0x9150, 0xF4FC, 0x914E, 0xF4FD, 0x914F, 0xF4FE, 0x9164, 0xF540, 0x9B7C, 0xF541, 0x9B7D, + 0xF542, 0x9B7E, 0xF543, 0x9B7F, 0xF544, 0x9B80, 0xF545, 0x9B81, 0xF546, 0x9B82, 0xF547, 0x9B83, 0xF548, 0x9B84, 0xF549, 0x9B85, + 0xF54A, 0x9B86, 0xF54B, 0x9B87, 0xF54C, 0x9B88, 0xF54D, 0x9B89, 0xF54E, 0x9B8A, 0xF54F, 0x9B8B, 0xF550, 0x9B8C, 0xF551, 0x9B8D, + 0xF552, 0x9B8E, 0xF553, 0x9B8F, 0xF554, 0x9B90, 0xF555, 0x9B91, 0xF556, 0x9B92, 0xF557, 0x9B93, 0xF558, 0x9B94, 0xF559, 0x9B95, + 0xF55A, 0x9B96, 0xF55B, 0x9B97, 0xF55C, 0x9B98, 0xF55D, 0x9B99, 0xF55E, 0x9B9A, 0xF55F, 0x9B9B, 0xF560, 0x9B9C, 0xF561, 0x9B9D, + 0xF562, 0x9B9E, 0xF563, 0x9B9F, 0xF564, 0x9BA0, 0xF565, 0x9BA1, 0xF566, 0x9BA2, 0xF567, 0x9BA3, 0xF568, 0x9BA4, 0xF569, 0x9BA5, + 0xF56A, 0x9BA6, 0xF56B, 0x9BA7, 0xF56C, 0x9BA8, 0xF56D, 0x9BA9, 0xF56E, 0x9BAA, 0xF56F, 0x9BAB, 0xF570, 0x9BAC, 0xF571, 0x9BAD, + 0xF572, 0x9BAE, 0xF573, 0x9BAF, 0xF574, 0x9BB0, 0xF575, 0x9BB1, 0xF576, 0x9BB2, 0xF577, 0x9BB3, 0xF578, 0x9BB4, 0xF579, 0x9BB5, + 0xF57A, 0x9BB6, 0xF57B, 0x9BB7, 0xF57C, 0x9BB8, 0xF57D, 0x9BB9, 0xF57E, 0x9BBA, 0xF580, 0x9BBB, 0xF581, 0x9BBC, 0xF582, 0x9BBD, + 0xF583, 0x9BBE, 0xF584, 0x9BBF, 0xF585, 0x9BC0, 0xF586, 0x9BC1, 0xF587, 0x9BC2, 0xF588, 0x9BC3, 0xF589, 0x9BC4, 0xF58A, 0x9BC5, + 0xF58B, 0x9BC6, 0xF58C, 0x9BC7, 0xF58D, 0x9BC8, 0xF58E, 0x9BC9, 0xF58F, 0x9BCA, 0xF590, 0x9BCB, 0xF591, 0x9BCC, 0xF592, 0x9BCD, + 0xF593, 0x9BCE, 0xF594, 0x9BCF, 0xF595, 0x9BD0, 0xF596, 0x9BD1, 0xF597, 0x9BD2, 0xF598, 0x9BD3, 0xF599, 0x9BD4, 0xF59A, 0x9BD5, + 0xF59B, 0x9BD6, 0xF59C, 0x9BD7, 0xF59D, 0x9BD8, 0xF59E, 0x9BD9, 0xF59F, 0x9BDA, 0xF5A0, 0x9BDB, 0xF5A1, 0x9162, 0xF5A2, 0x9161, + 0xF5A3, 0x9170, 0xF5A4, 0x9169, 0xF5A5, 0x916F, 0xF5A6, 0x917D, 0xF5A7, 0x917E, 0xF5A8, 0x9172, 0xF5A9, 0x9174, 0xF5AA, 0x9179, + 0xF5AB, 0x918C, 0xF5AC, 0x9185, 0xF5AD, 0x9190, 0xF5AE, 0x918D, 0xF5AF, 0x9191, 0xF5B0, 0x91A2, 0xF5B1, 0x91A3, 0xF5B2, 0x91AA, + 0xF5B3, 0x91AD, 0xF5B4, 0x91AE, 0xF5B5, 0x91AF, 0xF5B6, 0x91B5, 0xF5B7, 0x91B4, 0xF5B8, 0x91BA, 0xF5B9, 0x8C55, 0xF5BA, 0x9E7E, + 0xF5BB, 0x8DB8, 0xF5BC, 0x8DEB, 0xF5BD, 0x8E05, 0xF5BE, 0x8E59, 0xF5BF, 0x8E69, 0xF5C0, 0x8DB5, 0xF5C1, 0x8DBF, 0xF5C2, 0x8DBC, + 0xF5C3, 0x8DBA, 0xF5C4, 0x8DC4, 0xF5C5, 0x8DD6, 0xF5C6, 0x8DD7, 0xF5C7, 0x8DDA, 0xF5C8, 0x8DDE, 0xF5C9, 0x8DCE, 0xF5CA, 0x8DCF, + 0xF5CB, 0x8DDB, 0xF5CC, 0x8DC6, 0xF5CD, 0x8DEC, 0xF5CE, 0x8DF7, 0xF5CF, 0x8DF8, 0xF5D0, 0x8DE3, 0xF5D1, 0x8DF9, 0xF5D2, 0x8DFB, + 0xF5D3, 0x8DE4, 0xF5D4, 0x8E09, 0xF5D5, 0x8DFD, 0xF5D6, 0x8E14, 0xF5D7, 0x8E1D, 0xF5D8, 0x8E1F, 0xF5D9, 0x8E2C, 0xF5DA, 0x8E2E, + 0xF5DB, 0x8E23, 0xF5DC, 0x8E2F, 0xF5DD, 0x8E3A, 0xF5DE, 0x8E40, 0xF5DF, 0x8E39, 0xF5E0, 0x8E35, 0xF5E1, 0x8E3D, 0xF5E2, 0x8E31, + 0xF5E3, 0x8E49, 0xF5E4, 0x8E41, 0xF5E5, 0x8E42, 0xF5E6, 0x8E51, 0xF5E7, 0x8E52, 0xF5E8, 0x8E4A, 0xF5E9, 0x8E70, 0xF5EA, 0x8E76, + 0xF5EB, 0x8E7C, 0xF5EC, 0x8E6F, 0xF5ED, 0x8E74, 0xF5EE, 0x8E85, 0xF5EF, 0x8E8F, 0xF5F0, 0x8E94, 0xF5F1, 0x8E90, 0xF5F2, 0x8E9C, + 0xF5F3, 0x8E9E, 0xF5F4, 0x8C78, 0xF5F5, 0x8C82, 0xF5F6, 0x8C8A, 0xF5F7, 0x8C85, 0xF5F8, 0x8C98, 0xF5F9, 0x8C94, 0xF5FA, 0x659B, + 0xF5FB, 0x89D6, 0xF5FC, 0x89DE, 0xF5FD, 0x89DA, 0xF5FE, 0x89DC, 0xF640, 0x9BDC, 0xF641, 0x9BDD, 0xF642, 0x9BDE, 0xF643, 0x9BDF, + 0xF644, 0x9BE0, 0xF645, 0x9BE1, 0xF646, 0x9BE2, 0xF647, 0x9BE3, 0xF648, 0x9BE4, 0xF649, 0x9BE5, 0xF64A, 0x9BE6, 0xF64B, 0x9BE7, + 0xF64C, 0x9BE8, 0xF64D, 0x9BE9, 0xF64E, 0x9BEA, 0xF64F, 0x9BEB, 0xF650, 0x9BEC, 0xF651, 0x9BED, 0xF652, 0x9BEE, 0xF653, 0x9BEF, + 0xF654, 0x9BF0, 0xF655, 0x9BF1, 0xF656, 0x9BF2, 0xF657, 0x9BF3, 0xF658, 0x9BF4, 0xF659, 0x9BF5, 0xF65A, 0x9BF6, 0xF65B, 0x9BF7, + 0xF65C, 0x9BF8, 0xF65D, 0x9BF9, 0xF65E, 0x9BFA, 0xF65F, 0x9BFB, 0xF660, 0x9BFC, 0xF661, 0x9BFD, 0xF662, 0x9BFE, 0xF663, 0x9BFF, + 0xF664, 0x9C00, 0xF665, 0x9C01, 0xF666, 0x9C02, 0xF667, 0x9C03, 0xF668, 0x9C04, 0xF669, 0x9C05, 0xF66A, 0x9C06, 0xF66B, 0x9C07, + 0xF66C, 0x9C08, 0xF66D, 0x9C09, 0xF66E, 0x9C0A, 0xF66F, 0x9C0B, 0xF670, 0x9C0C, 0xF671, 0x9C0D, 0xF672, 0x9C0E, 0xF673, 0x9C0F, + 0xF674, 0x9C10, 0xF675, 0x9C11, 0xF676, 0x9C12, 0xF677, 0x9C13, 0xF678, 0x9C14, 0xF679, 0x9C15, 0xF67A, 0x9C16, 0xF67B, 0x9C17, + 0xF67C, 0x9C18, 0xF67D, 0x9C19, 0xF67E, 0x9C1A, 0xF680, 0x9C1B, 0xF681, 0x9C1C, 0xF682, 0x9C1D, 0xF683, 0x9C1E, 0xF684, 0x9C1F, + 0xF685, 0x9C20, 0xF686, 0x9C21, 0xF687, 0x9C22, 0xF688, 0x9C23, 0xF689, 0x9C24, 0xF68A, 0x9C25, 0xF68B, 0x9C26, 0xF68C, 0x9C27, + 0xF68D, 0x9C28, 0xF68E, 0x9C29, 0xF68F, 0x9C2A, 0xF690, 0x9C2B, 0xF691, 0x9C2C, 0xF692, 0x9C2D, 0xF693, 0x9C2E, 0xF694, 0x9C2F, + 0xF695, 0x9C30, 0xF696, 0x9C31, 0xF697, 0x9C32, 0xF698, 0x9C33, 0xF699, 0x9C34, 0xF69A, 0x9C35, 0xF69B, 0x9C36, 0xF69C, 0x9C37, + 0xF69D, 0x9C38, 0xF69E, 0x9C39, 0xF69F, 0x9C3A, 0xF6A0, 0x9C3B, 0xF6A1, 0x89E5, 0xF6A2, 0x89EB, 0xF6A3, 0x89EF, 0xF6A4, 0x8A3E, + 0xF6A5, 0x8B26, 0xF6A6, 0x9753, 0xF6A7, 0x96E9, 0xF6A8, 0x96F3, 0xF6A9, 0x96EF, 0xF6AA, 0x9706, 0xF6AB, 0x9701, 0xF6AC, 0x9708, + 0xF6AD, 0x970F, 0xF6AE, 0x970E, 0xF6AF, 0x972A, 0xF6B0, 0x972D, 0xF6B1, 0x9730, 0xF6B2, 0x973E, 0xF6B3, 0x9F80, 0xF6B4, 0x9F83, + 0xF6B5, 0x9F85, 0xF6B6, 0x9F86, 0xF6B7, 0x9F87, 0xF6B8, 0x9F88, 0xF6B9, 0x9F89, 0xF6BA, 0x9F8A, 0xF6BB, 0x9F8C, 0xF6BC, 0x9EFE, + 0xF6BD, 0x9F0B, 0xF6BE, 0x9F0D, 0xF6BF, 0x96B9, 0xF6C0, 0x96BC, 0xF6C1, 0x96BD, 0xF6C2, 0x96CE, 0xF6C3, 0x96D2, 0xF6C4, 0x77BF, + 0xF6C5, 0x96E0, 0xF6C6, 0x928E, 0xF6C7, 0x92AE, 0xF6C8, 0x92C8, 0xF6C9, 0x933E, 0xF6CA, 0x936A, 0xF6CB, 0x93CA, 0xF6CC, 0x938F, + 0xF6CD, 0x943E, 0xF6CE, 0x946B, 0xF6CF, 0x9C7F, 0xF6D0, 0x9C82, 0xF6D1, 0x9C85, 0xF6D2, 0x9C86, 0xF6D3, 0x9C87, 0xF6D4, 0x9C88, + 0xF6D5, 0x7A23, 0xF6D6, 0x9C8B, 0xF6D7, 0x9C8E, 0xF6D8, 0x9C90, 0xF6D9, 0x9C91, 0xF6DA, 0x9C92, 0xF6DB, 0x9C94, 0xF6DC, 0x9C95, + 0xF6DD, 0x9C9A, 0xF6DE, 0x9C9B, 0xF6DF, 0x9C9E, 0xF6E0, 0x9C9F, 0xF6E1, 0x9CA0, 0xF6E2, 0x9CA1, 0xF6E3, 0x9CA2, 0xF6E4, 0x9CA3, + 0xF6E5, 0x9CA5, 0xF6E6, 0x9CA6, 0xF6E7, 0x9CA7, 0xF6E8, 0x9CA8, 0xF6E9, 0x9CA9, 0xF6EA, 0x9CAB, 0xF6EB, 0x9CAD, 0xF6EC, 0x9CAE, + 0xF6ED, 0x9CB0, 0xF6EE, 0x9CB1, 0xF6EF, 0x9CB2, 0xF6F0, 0x9CB3, 0xF6F1, 0x9CB4, 0xF6F2, 0x9CB5, 0xF6F3, 0x9CB6, 0xF6F4, 0x9CB7, + 0xF6F5, 0x9CBA, 0xF6F6, 0x9CBB, 0xF6F7, 0x9CBC, 0xF6F8, 0x9CBD, 0xF6F9, 0x9CC4, 0xF6FA, 0x9CC5, 0xF6FB, 0x9CC6, 0xF6FC, 0x9CC7, + 0xF6FD, 0x9CCA, 0xF6FE, 0x9CCB, 0xF740, 0x9C3C, 0xF741, 0x9C3D, 0xF742, 0x9C3E, 0xF743, 0x9C3F, 0xF744, 0x9C40, 0xF745, 0x9C41, + 0xF746, 0x9C42, 0xF747, 0x9C43, 0xF748, 0x9C44, 0xF749, 0x9C45, 0xF74A, 0x9C46, 0xF74B, 0x9C47, 0xF74C, 0x9C48, 0xF74D, 0x9C49, + 0xF74E, 0x9C4A, 0xF74F, 0x9C4B, 0xF750, 0x9C4C, 0xF751, 0x9C4D, 0xF752, 0x9C4E, 0xF753, 0x9C4F, 0xF754, 0x9C50, 0xF755, 0x9C51, + 0xF756, 0x9C52, 0xF757, 0x9C53, 0xF758, 0x9C54, 0xF759, 0x9C55, 0xF75A, 0x9C56, 0xF75B, 0x9C57, 0xF75C, 0x9C58, 0xF75D, 0x9C59, + 0xF75E, 0x9C5A, 0xF75F, 0x9C5B, 0xF760, 0x9C5C, 0xF761, 0x9C5D, 0xF762, 0x9C5E, 0xF763, 0x9C5F, 0xF764, 0x9C60, 0xF765, 0x9C61, + 0xF766, 0x9C62, 0xF767, 0x9C63, 0xF768, 0x9C64, 0xF769, 0x9C65, 0xF76A, 0x9C66, 0xF76B, 0x9C67, 0xF76C, 0x9C68, 0xF76D, 0x9C69, + 0xF76E, 0x9C6A, 0xF76F, 0x9C6B, 0xF770, 0x9C6C, 0xF771, 0x9C6D, 0xF772, 0x9C6E, 0xF773, 0x9C6F, 0xF774, 0x9C70, 0xF775, 0x9C71, + 0xF776, 0x9C72, 0xF777, 0x9C73, 0xF778, 0x9C74, 0xF779, 0x9C75, 0xF77A, 0x9C76, 0xF77B, 0x9C77, 0xF77C, 0x9C78, 0xF77D, 0x9C79, + 0xF77E, 0x9C7A, 0xF780, 0x9C7B, 0xF781, 0x9C7D, 0xF782, 0x9C7E, 0xF783, 0x9C80, 0xF784, 0x9C83, 0xF785, 0x9C84, 0xF786, 0x9C89, + 0xF787, 0x9C8A, 0xF788, 0x9C8C, 0xF789, 0x9C8F, 0xF78A, 0x9C93, 0xF78B, 0x9C96, 0xF78C, 0x9C97, 0xF78D, 0x9C98, 0xF78E, 0x9C99, + 0xF78F, 0x9C9D, 0xF790, 0x9CAA, 0xF791, 0x9CAC, 0xF792, 0x9CAF, 0xF793, 0x9CB9, 0xF794, 0x9CBE, 0xF795, 0x9CBF, 0xF796, 0x9CC0, + 0xF797, 0x9CC1, 0xF798, 0x9CC2, 0xF799, 0x9CC8, 0xF79A, 0x9CC9, 0xF79B, 0x9CD1, 0xF79C, 0x9CD2, 0xF79D, 0x9CDA, 0xF79E, 0x9CDB, + 0xF79F, 0x9CE0, 0xF7A0, 0x9CE1, 0xF7A1, 0x9CCC, 0xF7A2, 0x9CCD, 0xF7A3, 0x9CCE, 0xF7A4, 0x9CCF, 0xF7A5, 0x9CD0, 0xF7A6, 0x9CD3, + 0xF7A7, 0x9CD4, 0xF7A8, 0x9CD5, 0xF7A9, 0x9CD7, 0xF7AA, 0x9CD8, 0xF7AB, 0x9CD9, 0xF7AC, 0x9CDC, 0xF7AD, 0x9CDD, 0xF7AE, 0x9CDF, + 0xF7AF, 0x9CE2, 0xF7B0, 0x977C, 0xF7B1, 0x9785, 0xF7B2, 0x9791, 0xF7B3, 0x9792, 0xF7B4, 0x9794, 0xF7B5, 0x97AF, 0xF7B6, 0x97AB, + 0xF7B7, 0x97A3, 0xF7B8, 0x97B2, 0xF7B9, 0x97B4, 0xF7BA, 0x9AB1, 0xF7BB, 0x9AB0, 0xF7BC, 0x9AB7, 0xF7BD, 0x9E58, 0xF7BE, 0x9AB6, + 0xF7BF, 0x9ABA, 0xF7C0, 0x9ABC, 0xF7C1, 0x9AC1, 0xF7C2, 0x9AC0, 0xF7C3, 0x9AC5, 0xF7C4, 0x9AC2, 0xF7C5, 0x9ACB, 0xF7C6, 0x9ACC, + 0xF7C7, 0x9AD1, 0xF7C8, 0x9B45, 0xF7C9, 0x9B43, 0xF7CA, 0x9B47, 0xF7CB, 0x9B49, 0xF7CC, 0x9B48, 0xF7CD, 0x9B4D, 0xF7CE, 0x9B51, + 0xF7CF, 0x98E8, 0xF7D0, 0x990D, 0xF7D1, 0x992E, 0xF7D2, 0x9955, 0xF7D3, 0x9954, 0xF7D4, 0x9ADF, 0xF7D5, 0x9AE1, 0xF7D6, 0x9AE6, + 0xF7D7, 0x9AEF, 0xF7D8, 0x9AEB, 0xF7D9, 0x9AFB, 0xF7DA, 0x9AED, 0xF7DB, 0x9AF9, 0xF7DC, 0x9B08, 0xF7DD, 0x9B0F, 0xF7DE, 0x9B13, + 0xF7DF, 0x9B1F, 0xF7E0, 0x9B23, 0xF7E1, 0x9EBD, 0xF7E2, 0x9EBE, 0xF7E3, 0x7E3B, 0xF7E4, 0x9E82, 0xF7E5, 0x9E87, 0xF7E6, 0x9E88, + 0xF7E7, 0x9E8B, 0xF7E8, 0x9E92, 0xF7E9, 0x93D6, 0xF7EA, 0x9E9D, 0xF7EB, 0x9E9F, 0xF7EC, 0x9EDB, 0xF7ED, 0x9EDC, 0xF7EE, 0x9EDD, + 0xF7EF, 0x9EE0, 0xF7F0, 0x9EDF, 0xF7F1, 0x9EE2, 0xF7F2, 0x9EE9, 0xF7F3, 0x9EE7, 0xF7F4, 0x9EE5, 0xF7F5, 0x9EEA, 0xF7F6, 0x9EEF, + 0xF7F7, 0x9F22, 0xF7F8, 0x9F2C, 0xF7F9, 0x9F2F, 0xF7FA, 0x9F39, 0xF7FB, 0x9F37, 0xF7FC, 0x9F3D, 0xF7FD, 0x9F3E, 0xF7FE, 0x9F44, + 0xF840, 0x9CE3, 0xF841, 0x9CE4, 0xF842, 0x9CE5, 0xF843, 0x9CE6, 0xF844, 0x9CE7, 0xF845, 0x9CE8, 0xF846, 0x9CE9, 0xF847, 0x9CEA, + 0xF848, 0x9CEB, 0xF849, 0x9CEC, 0xF84A, 0x9CED, 0xF84B, 0x9CEE, 0xF84C, 0x9CEF, 0xF84D, 0x9CF0, 0xF84E, 0x9CF1, 0xF84F, 0x9CF2, + 0xF850, 0x9CF3, 0xF851, 0x9CF4, 0xF852, 0x9CF5, 0xF853, 0x9CF6, 0xF854, 0x9CF7, 0xF855, 0x9CF8, 0xF856, 0x9CF9, 0xF857, 0x9CFA, + 0xF858, 0x9CFB, 0xF859, 0x9CFC, 0xF85A, 0x9CFD, 0xF85B, 0x9CFE, 0xF85C, 0x9CFF, 0xF85D, 0x9D00, 0xF85E, 0x9D01, 0xF85F, 0x9D02, + 0xF860, 0x9D03, 0xF861, 0x9D04, 0xF862, 0x9D05, 0xF863, 0x9D06, 0xF864, 0x9D07, 0xF865, 0x9D08, 0xF866, 0x9D09, 0xF867, 0x9D0A, + 0xF868, 0x9D0B, 0xF869, 0x9D0C, 0xF86A, 0x9D0D, 0xF86B, 0x9D0E, 0xF86C, 0x9D0F, 0xF86D, 0x9D10, 0xF86E, 0x9D11, 0xF86F, 0x9D12, + 0xF870, 0x9D13, 0xF871, 0x9D14, 0xF872, 0x9D15, 0xF873, 0x9D16, 0xF874, 0x9D17, 0xF875, 0x9D18, 0xF876, 0x9D19, 0xF877, 0x9D1A, + 0xF878, 0x9D1B, 0xF879, 0x9D1C, 0xF87A, 0x9D1D, 0xF87B, 0x9D1E, 0xF87C, 0x9D1F, 0xF87D, 0x9D20, 0xF87E, 0x9D21, 0xF880, 0x9D22, + 0xF881, 0x9D23, 0xF882, 0x9D24, 0xF883, 0x9D25, 0xF884, 0x9D26, 0xF885, 0x9D27, 0xF886, 0x9D28, 0xF887, 0x9D29, 0xF888, 0x9D2A, + 0xF889, 0x9D2B, 0xF88A, 0x9D2C, 0xF88B, 0x9D2D, 0xF88C, 0x9D2E, 0xF88D, 0x9D2F, 0xF88E, 0x9D30, 0xF88F, 0x9D31, 0xF890, 0x9D32, + 0xF891, 0x9D33, 0xF892, 0x9D34, 0xF893, 0x9D35, 0xF894, 0x9D36, 0xF895, 0x9D37, 0xF896, 0x9D38, 0xF897, 0x9D39, 0xF898, 0x9D3A, + 0xF899, 0x9D3B, 0xF89A, 0x9D3C, 0xF89B, 0x9D3D, 0xF89C, 0x9D3E, 0xF89D, 0x9D3F, 0xF89E, 0x9D40, 0xF89F, 0x9D41, 0xF8A0, 0x9D42, + 0xF940, 0x9D43, 0xF941, 0x9D44, 0xF942, 0x9D45, 0xF943, 0x9D46, 0xF944, 0x9D47, 0xF945, 0x9D48, 0xF946, 0x9D49, 0xF947, 0x9D4A, + 0xF948, 0x9D4B, 0xF949, 0x9D4C, 0xF94A, 0x9D4D, 0xF94B, 0x9D4E, 0xF94C, 0x9D4F, 0xF94D, 0x9D50, 0xF94E, 0x9D51, 0xF94F, 0x9D52, + 0xF950, 0x9D53, 0xF951, 0x9D54, 0xF952, 0x9D55, 0xF953, 0x9D56, 0xF954, 0x9D57, 0xF955, 0x9D58, 0xF956, 0x9D59, 0xF957, 0x9D5A, + 0xF958, 0x9D5B, 0xF959, 0x9D5C, 0xF95A, 0x9D5D, 0xF95B, 0x9D5E, 0xF95C, 0x9D5F, 0xF95D, 0x9D60, 0xF95E, 0x9D61, 0xF95F, 0x9D62, + 0xF960, 0x9D63, 0xF961, 0x9D64, 0xF962, 0x9D65, 0xF963, 0x9D66, 0xF964, 0x9D67, 0xF965, 0x9D68, 0xF966, 0x9D69, 0xF967, 0x9D6A, + 0xF968, 0x9D6B, 0xF969, 0x9D6C, 0xF96A, 0x9D6D, 0xF96B, 0x9D6E, 0xF96C, 0x9D6F, 0xF96D, 0x9D70, 0xF96E, 0x9D71, 0xF96F, 0x9D72, + 0xF970, 0x9D73, 0xF971, 0x9D74, 0xF972, 0x9D75, 0xF973, 0x9D76, 0xF974, 0x9D77, 0xF975, 0x9D78, 0xF976, 0x9D79, 0xF977, 0x9D7A, + 0xF978, 0x9D7B, 0xF979, 0x9D7C, 0xF97A, 0x9D7D, 0xF97B, 0x9D7E, 0xF97C, 0x9D7F, 0xF97D, 0x9D80, 0xF97E, 0x9D81, 0xF980, 0x9D82, + 0xF981, 0x9D83, 0xF982, 0x9D84, 0xF983, 0x9D85, 0xF984, 0x9D86, 0xF985, 0x9D87, 0xF986, 0x9D88, 0xF987, 0x9D89, 0xF988, 0x9D8A, + 0xF989, 0x9D8B, 0xF98A, 0x9D8C, 0xF98B, 0x9D8D, 0xF98C, 0x9D8E, 0xF98D, 0x9D8F, 0xF98E, 0x9D90, 0xF98F, 0x9D91, 0xF990, 0x9D92, + 0xF991, 0x9D93, 0xF992, 0x9D94, 0xF993, 0x9D95, 0xF994, 0x9D96, 0xF995, 0x9D97, 0xF996, 0x9D98, 0xF997, 0x9D99, 0xF998, 0x9D9A, + 0xF999, 0x9D9B, 0xF99A, 0x9D9C, 0xF99B, 0x9D9D, 0xF99C, 0x9D9E, 0xF99D, 0x9D9F, 0xF99E, 0x9DA0, 0xF99F, 0x9DA1, 0xF9A0, 0x9DA2, + 0xFA40, 0x9DA3, 0xFA41, 0x9DA4, 0xFA42, 0x9DA5, 0xFA43, 0x9DA6, 0xFA44, 0x9DA7, 0xFA45, 0x9DA8, 0xFA46, 0x9DA9, 0xFA47, 0x9DAA, + 0xFA48, 0x9DAB, 0xFA49, 0x9DAC, 0xFA4A, 0x9DAD, 0xFA4B, 0x9DAE, 0xFA4C, 0x9DAF, 0xFA4D, 0x9DB0, 0xFA4E, 0x9DB1, 0xFA4F, 0x9DB2, + 0xFA50, 0x9DB3, 0xFA51, 0x9DB4, 0xFA52, 0x9DB5, 0xFA53, 0x9DB6, 0xFA54, 0x9DB7, 0xFA55, 0x9DB8, 0xFA56, 0x9DB9, 0xFA57, 0x9DBA, + 0xFA58, 0x9DBB, 0xFA59, 0x9DBC, 0xFA5A, 0x9DBD, 0xFA5B, 0x9DBE, 0xFA5C, 0x9DBF, 0xFA5D, 0x9DC0, 0xFA5E, 0x9DC1, 0xFA5F, 0x9DC2, + 0xFA60, 0x9DC3, 0xFA61, 0x9DC4, 0xFA62, 0x9DC5, 0xFA63, 0x9DC6, 0xFA64, 0x9DC7, 0xFA65, 0x9DC8, 0xFA66, 0x9DC9, 0xFA67, 0x9DCA, + 0xFA68, 0x9DCB, 0xFA69, 0x9DCC, 0xFA6A, 0x9DCD, 0xFA6B, 0x9DCE, 0xFA6C, 0x9DCF, 0xFA6D, 0x9DD0, 0xFA6E, 0x9DD1, 0xFA6F, 0x9DD2, + 0xFA70, 0x9DD3, 0xFA71, 0x9DD4, 0xFA72, 0x9DD5, 0xFA73, 0x9DD6, 0xFA74, 0x9DD7, 0xFA75, 0x9DD8, 0xFA76, 0x9DD9, 0xFA77, 0x9DDA, + 0xFA78, 0x9DDB, 0xFA79, 0x9DDC, 0xFA7A, 0x9DDD, 0xFA7B, 0x9DDE, 0xFA7C, 0x9DDF, 0xFA7D, 0x9DE0, 0xFA7E, 0x9DE1, 0xFA80, 0x9DE2, + 0xFA81, 0x9DE3, 0xFA82, 0x9DE4, 0xFA83, 0x9DE5, 0xFA84, 0x9DE6, 0xFA85, 0x9DE7, 0xFA86, 0x9DE8, 0xFA87, 0x9DE9, 0xFA88, 0x9DEA, + 0xFA89, 0x9DEB, 0xFA8A, 0x9DEC, 0xFA8B, 0x9DED, 0xFA8C, 0x9DEE, 0xFA8D, 0x9DEF, 0xFA8E, 0x9DF0, 0xFA8F, 0x9DF1, 0xFA90, 0x9DF2, + 0xFA91, 0x9DF3, 0xFA92, 0x9DF4, 0xFA93, 0x9DF5, 0xFA94, 0x9DF6, 0xFA95, 0x9DF7, 0xFA96, 0x9DF8, 0xFA97, 0x9DF9, 0xFA98, 0x9DFA, + 0xFA99, 0x9DFB, 0xFA9A, 0x9DFC, 0xFA9B, 0x9DFD, 0xFA9C, 0x9DFE, 0xFA9D, 0x9DFF, 0xFA9E, 0x9E00, 0xFA9F, 0x9E01, 0xFAA0, 0x9E02, + 0xFB40, 0x9E03, 0xFB41, 0x9E04, 0xFB42, 0x9E05, 0xFB43, 0x9E06, 0xFB44, 0x9E07, 0xFB45, 0x9E08, 0xFB46, 0x9E09, 0xFB47, 0x9E0A, + 0xFB48, 0x9E0B, 0xFB49, 0x9E0C, 0xFB4A, 0x9E0D, 0xFB4B, 0x9E0E, 0xFB4C, 0x9E0F, 0xFB4D, 0x9E10, 0xFB4E, 0x9E11, 0xFB4F, 0x9E12, + 0xFB50, 0x9E13, 0xFB51, 0x9E14, 0xFB52, 0x9E15, 0xFB53, 0x9E16, 0xFB54, 0x9E17, 0xFB55, 0x9E18, 0xFB56, 0x9E19, 0xFB57, 0x9E1A, + 0xFB58, 0x9E1B, 0xFB59, 0x9E1C, 0xFB5A, 0x9E1D, 0xFB5B, 0x9E1E, 0xFB5C, 0x9E24, 0xFB5D, 0x9E27, 0xFB5E, 0x9E2E, 0xFB5F, 0x9E30, + 0xFB60, 0x9E34, 0xFB61, 0x9E3B, 0xFB62, 0x9E3C, 0xFB63, 0x9E40, 0xFB64, 0x9E4D, 0xFB65, 0x9E50, 0xFB66, 0x9E52, 0xFB67, 0x9E53, + 0xFB68, 0x9E54, 0xFB69, 0x9E56, 0xFB6A, 0x9E59, 0xFB6B, 0x9E5D, 0xFB6C, 0x9E5F, 0xFB6D, 0x9E60, 0xFB6E, 0x9E61, 0xFB6F, 0x9E62, + 0xFB70, 0x9E65, 0xFB71, 0x9E6E, 0xFB72, 0x9E6F, 0xFB73, 0x9E72, 0xFB74, 0x9E74, 0xFB75, 0x9E75, 0xFB76, 0x9E76, 0xFB77, 0x9E77, + 0xFB78, 0x9E78, 0xFB79, 0x9E79, 0xFB7A, 0x9E7A, 0xFB7B, 0x9E7B, 0xFB7C, 0x9E7C, 0xFB7D, 0x9E7D, 0xFB7E, 0x9E80, 0xFB80, 0x9E81, + 0xFB81, 0x9E83, 0xFB82, 0x9E84, 0xFB83, 0x9E85, 0xFB84, 0x9E86, 0xFB85, 0x9E89, 0xFB86, 0x9E8A, 0xFB87, 0x9E8C, 0xFB88, 0x9E8D, + 0xFB89, 0x9E8E, 0xFB8A, 0x9E8F, 0xFB8B, 0x9E90, 0xFB8C, 0x9E91, 0xFB8D, 0x9E94, 0xFB8E, 0x9E95, 0xFB8F, 0x9E96, 0xFB90, 0x9E97, + 0xFB91, 0x9E98, 0xFB92, 0x9E99, 0xFB93, 0x9E9A, 0xFB94, 0x9E9B, 0xFB95, 0x9E9C, 0xFB96, 0x9E9E, 0xFB97, 0x9EA0, 0xFB98, 0x9EA1, + 0xFB99, 0x9EA2, 0xFB9A, 0x9EA3, 0xFB9B, 0x9EA4, 0xFB9C, 0x9EA5, 0xFB9D, 0x9EA7, 0xFB9E, 0x9EA8, 0xFB9F, 0x9EA9, 0xFBA0, 0x9EAA, + 0xFC40, 0x9EAB, 0xFC41, 0x9EAC, 0xFC42, 0x9EAD, 0xFC43, 0x9EAE, 0xFC44, 0x9EAF, 0xFC45, 0x9EB0, 0xFC46, 0x9EB1, 0xFC47, 0x9EB2, + 0xFC48, 0x9EB3, 0xFC49, 0x9EB5, 0xFC4A, 0x9EB6, 0xFC4B, 0x9EB7, 0xFC4C, 0x9EB9, 0xFC4D, 0x9EBA, 0xFC4E, 0x9EBC, 0xFC4F, 0x9EBF, + 0xFC50, 0x9EC0, 0xFC51, 0x9EC1, 0xFC52, 0x9EC2, 0xFC53, 0x9EC3, 0xFC54, 0x9EC5, 0xFC55, 0x9EC6, 0xFC56, 0x9EC7, 0xFC57, 0x9EC8, + 0xFC58, 0x9ECA, 0xFC59, 0x9ECB, 0xFC5A, 0x9ECC, 0xFC5B, 0x9ED0, 0xFC5C, 0x9ED2, 0xFC5D, 0x9ED3, 0xFC5E, 0x9ED5, 0xFC5F, 0x9ED6, + 0xFC60, 0x9ED7, 0xFC61, 0x9ED9, 0xFC62, 0x9EDA, 0xFC63, 0x9EDE, 0xFC64, 0x9EE1, 0xFC65, 0x9EE3, 0xFC66, 0x9EE4, 0xFC67, 0x9EE6, + 0xFC68, 0x9EE8, 0xFC69, 0x9EEB, 0xFC6A, 0x9EEC, 0xFC6B, 0x9EED, 0xFC6C, 0x9EEE, 0xFC6D, 0x9EF0, 0xFC6E, 0x9EF1, 0xFC6F, 0x9EF2, + 0xFC70, 0x9EF3, 0xFC71, 0x9EF4, 0xFC72, 0x9EF5, 0xFC73, 0x9EF6, 0xFC74, 0x9EF7, 0xFC75, 0x9EF8, 0xFC76, 0x9EFA, 0xFC77, 0x9EFD, + 0xFC78, 0x9EFF, 0xFC79, 0x9F00, 0xFC7A, 0x9F01, 0xFC7B, 0x9F02, 0xFC7C, 0x9F03, 0xFC7D, 0x9F04, 0xFC7E, 0x9F05, 0xFC80, 0x9F06, + 0xFC81, 0x9F07, 0xFC82, 0x9F08, 0xFC83, 0x9F09, 0xFC84, 0x9F0A, 0xFC85, 0x9F0C, 0xFC86, 0x9F0F, 0xFC87, 0x9F11, 0xFC88, 0x9F12, + 0xFC89, 0x9F14, 0xFC8A, 0x9F15, 0xFC8B, 0x9F16, 0xFC8C, 0x9F18, 0xFC8D, 0x9F1A, 0xFC8E, 0x9F1B, 0xFC8F, 0x9F1C, 0xFC90, 0x9F1D, + 0xFC91, 0x9F1E, 0xFC92, 0x9F1F, 0xFC93, 0x9F21, 0xFC94, 0x9F23, 0xFC95, 0x9F24, 0xFC96, 0x9F25, 0xFC97, 0x9F26, 0xFC98, 0x9F27, + 0xFC99, 0x9F28, 0xFC9A, 0x9F29, 0xFC9B, 0x9F2A, 0xFC9C, 0x9F2B, 0xFC9D, 0x9F2D, 0xFC9E, 0x9F2E, 0xFC9F, 0x9F30, 0xFCA0, 0x9F31, + 0xFD40, 0x9F32, 0xFD41, 0x9F33, 0xFD42, 0x9F34, 0xFD43, 0x9F35, 0xFD44, 0x9F36, 0xFD45, 0x9F38, 0xFD46, 0x9F3A, 0xFD47, 0x9F3C, + 0xFD48, 0x9F3F, 0xFD49, 0x9F40, 0xFD4A, 0x9F41, 0xFD4B, 0x9F42, 0xFD4C, 0x9F43, 0xFD4D, 0x9F45, 0xFD4E, 0x9F46, 0xFD4F, 0x9F47, + 0xFD50, 0x9F48, 0xFD51, 0x9F49, 0xFD52, 0x9F4A, 0xFD53, 0x9F4B, 0xFD54, 0x9F4C, 0xFD55, 0x9F4D, 0xFD56, 0x9F4E, 0xFD57, 0x9F4F, + 0xFD58, 0x9F52, 0xFD59, 0x9F53, 0xFD5A, 0x9F54, 0xFD5B, 0x9F55, 0xFD5C, 0x9F56, 0xFD5D, 0x9F57, 0xFD5E, 0x9F58, 0xFD5F, 0x9F59, + 0xFD60, 0x9F5A, 0xFD61, 0x9F5B, 0xFD62, 0x9F5C, 0xFD63, 0x9F5D, 0xFD64, 0x9F5E, 0xFD65, 0x9F5F, 0xFD66, 0x9F60, 0xFD67, 0x9F61, + 0xFD68, 0x9F62, 0xFD69, 0x9F63, 0xFD6A, 0x9F64, 0xFD6B, 0x9F65, 0xFD6C, 0x9F66, 0xFD6D, 0x9F67, 0xFD6E, 0x9F68, 0xFD6F, 0x9F69, + 0xFD70, 0x9F6A, 0xFD71, 0x9F6B, 0xFD72, 0x9F6C, 0xFD73, 0x9F6D, 0xFD74, 0x9F6E, 0xFD75, 0x9F6F, 0xFD76, 0x9F70, 0xFD77, 0x9F71, + 0xFD78, 0x9F72, 0xFD79, 0x9F73, 0xFD7A, 0x9F74, 0xFD7B, 0x9F75, 0xFD7C, 0x9F76, 0xFD7D, 0x9F77, 0xFD7E, 0x9F78, 0xFD80, 0x9F79, + 0xFD81, 0x9F7A, 0xFD82, 0x9F7B, 0xFD83, 0x9F7C, 0xFD84, 0x9F7D, 0xFD85, 0x9F7E, 0xFD86, 0x9F81, 0xFD87, 0x9F82, 0xFD88, 0x9F8D, + 0xFD89, 0x9F8E, 0xFD8A, 0x9F8F, 0xFD8B, 0x9F90, 0xFD8C, 0x9F91, 0xFD8D, 0x9F92, 0xFD8E, 0x9F93, 0xFD8F, 0x9F94, 0xFD90, 0x9F95, + 0xFD91, 0x9F96, 0xFD92, 0x9F97, 0xFD93, 0x9F98, 0xFD94, 0x9F9C, 0xFD95, 0x9F9D, 0xFD96, 0x9F9E, 0xFD97, 0x9FA1, 0xFD98, 0x9FA2, + 0xFD99, 0x9FA3, 0xFD9A, 0x9FA4, 0xFD9B, 0x9FA5, 0xFD9C, 0xF92C, 0xFD9D, 0xF979, 0xFD9E, 0xF995, 0xFD9F, 0xF9E7, 0xFDA0, 0xF9F1, + 0xFE40, 0xFA0C, 0xFE41, 0xFA0D, 0xFE42, 0xFA0E, 0xFE43, 0xFA0F, 0xFE44, 0xFA11, 0xFE45, 0xFA13, 0xFE46, 0xFA14, 0xFE47, 0xFA18, + 0xFE48, 0xFA1F, 0xFE49, 0xFA20, 0xFE4A, 0xFA21, 0xFE4B, 0xFA23, 0xFE4C, 0xFA24, 0xFE4D, 0xFA27, 0xFE4E, 0xFA28, 0xFE4F, 0xFA29, + 0, 0 +}; +#endif + +#if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */ +static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ + 0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6, + 0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6, + 0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF, + 0x00D8, 0xA8AA, 0x00DE, 0xA8AD, 0x00DF, 0xA9AC, 0x00E6, 0xA9A1, 0x00F0, 0xA9A3, 0x00F7, 0xA1C0, 0x00F8, 0xA9AA, 0x00FE, 0xA9AD, + 0x0111, 0xA9A2, 0x0126, 0xA8A4, 0x0127, 0xA9A4, 0x0131, 0xA9A5, 0x0132, 0xA8A6, 0x0133, 0xA9A6, 0x0138, 0xA9A7, 0x013F, 0xA8A8, + 0x0140, 0xA9A8, 0x0141, 0xA8A9, 0x0142, 0xA9A9, 0x0149, 0xA9B0, 0x014A, 0xA8AF, 0x014B, 0xA9AF, 0x0152, 0xA8AB, 0x0153, 0xA9AB, + 0x0166, 0xA8AE, 0x0167, 0xA9AE, 0x02C7, 0xA2A7, 0x02D0, 0xA2B0, 0x02D8, 0xA2A8, 0x02D9, 0xA2AB, 0x02DA, 0xA2AA, 0x02DB, 0xA2AD, + 0x02DD, 0xA2A9, 0x0391, 0xA5C1, 0x0392, 0xA5C2, 0x0393, 0xA5C3, 0x0394, 0xA5C4, 0x0395, 0xA5C5, 0x0396, 0xA5C6, 0x0397, 0xA5C7, + 0x0398, 0xA5C8, 0x0399, 0xA5C9, 0x039A, 0xA5CA, 0x039B, 0xA5CB, 0x039C, 0xA5CC, 0x039D, 0xA5CD, 0x039E, 0xA5CE, 0x039F, 0xA5CF, + 0x03A0, 0xA5D0, 0x03A1, 0xA5D1, 0x03A3, 0xA5D2, 0x03A4, 0xA5D3, 0x03A5, 0xA5D4, 0x03A6, 0xA5D5, 0x03A7, 0xA5D6, 0x03A8, 0xA5D7, + 0x03A9, 0xA5D8, 0x03B1, 0xA5E1, 0x03B2, 0xA5E2, 0x03B3, 0xA5E3, 0x03B4, 0xA5E4, 0x03B5, 0xA5E5, 0x03B6, 0xA5E6, 0x03B7, 0xA5E7, + 0x03B8, 0xA5E8, 0x03B9, 0xA5E9, 0x03BA, 0xA5EA, 0x03BB, 0xA5EB, 0x03BC, 0xA5EC, 0x03BD, 0xA5ED, 0x03BE, 0xA5EE, 0x03BF, 0xA5EF, + 0x03C0, 0xA5F0, 0x03C1, 0xA5F1, 0x03C3, 0xA5F2, 0x03C4, 0xA5F3, 0x03C5, 0xA5F4, 0x03C6, 0xA5F5, 0x03C7, 0xA5F6, 0x03C8, 0xA5F7, + 0x03C9, 0xA5F8, 0x0401, 0xACA7, 0x0410, 0xACA1, 0x0411, 0xACA2, 0x0412, 0xACA3, 0x0413, 0xACA4, 0x0414, 0xACA5, 0x0415, 0xACA6, + 0x0416, 0xACA8, 0x0417, 0xACA9, 0x0418, 0xACAA, 0x0419, 0xACAB, 0x041A, 0xACAC, 0x041B, 0xACAD, 0x041C, 0xACAE, 0x041D, 0xACAF, + 0x041E, 0xACB0, 0x041F, 0xACB1, 0x0420, 0xACB2, 0x0421, 0xACB3, 0x0422, 0xACB4, 0x0423, 0xACB5, 0x0424, 0xACB6, 0x0425, 0xACB7, + 0x0426, 0xACB8, 0x0427, 0xACB9, 0x0428, 0xACBA, 0x0429, 0xACBB, 0x042A, 0xACBC, 0x042B, 0xACBD, 0x042C, 0xACBE, 0x042D, 0xACBF, + 0x042E, 0xACC0, 0x042F, 0xACC1, 0x0430, 0xACD1, 0x0431, 0xACD2, 0x0432, 0xACD3, 0x0433, 0xACD4, 0x0434, 0xACD5, 0x0435, 0xACD6, + 0x0436, 0xACD8, 0x0437, 0xACD9, 0x0438, 0xACDA, 0x0439, 0xACDB, 0x043A, 0xACDC, 0x043B, 0xACDD, 0x043C, 0xACDE, 0x043D, 0xACDF, + 0x043E, 0xACE0, 0x043F, 0xACE1, 0x0440, 0xACE2, 0x0441, 0xACE3, 0x0442, 0xACE4, 0x0443, 0xACE5, 0x0444, 0xACE6, 0x0445, 0xACE7, + 0x0446, 0xACE8, 0x0447, 0xACE9, 0x0448, 0xACEA, 0x0449, 0xACEB, 0x044A, 0xACEC, 0x044B, 0xACED, 0x044C, 0xACEE, 0x044D, 0xACEF, + 0x044E, 0xACF0, 0x044F, 0xACF1, 0x0451, 0xACD7, 0x2015, 0xA1AA, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, + 0x2020, 0xA2D3, 0x2021, 0xA2D4, 0x2025, 0xA1A5, 0x2026, 0xA1A6, 0x2030, 0xA2B6, 0x2032, 0xA1C7, 0x2033, 0xA1C8, 0x203B, 0xA1D8, + 0x2074, 0xA9F9, 0x207F, 0xA9FA, 0x2081, 0xA9FB, 0x2082, 0xA9FC, 0x2083, 0xA9FD, 0x2084, 0xA9FE, 0x20AC, 0xA2E6, 0x2103, 0xA1C9, + 0x2109, 0xA2B5, 0x2113, 0xA7A4, 0x2116, 0xA2E0, 0x2121, 0xA2E5, 0x2122, 0xA2E2, 0x2126, 0xA7D9, 0x212B, 0xA1CA, 0x2153, 0xA8F7, + 0x2154, 0xA8F8, 0x215B, 0xA8FB, 0x215C, 0xA8FC, 0x215D, 0xA8FD, 0x215E, 0xA8FE, 0x2160, 0xA5B0, 0x2161, 0xA5B1, 0x2162, 0xA5B2, + 0x2163, 0xA5B3, 0x2164, 0xA5B4, 0x2165, 0xA5B5, 0x2166, 0xA5B6, 0x2167, 0xA5B7, 0x2168, 0xA5B8, 0x2169, 0xA5B9, 0x2170, 0xA5A1, + 0x2171, 0xA5A2, 0x2172, 0xA5A3, 0x2173, 0xA5A4, 0x2174, 0xA5A5, 0x2175, 0xA5A6, 0x2176, 0xA5A7, 0x2177, 0xA5A8, 0x2178, 0xA5A9, + 0x2179, 0xA5AA, 0x2190, 0xA1E7, 0x2191, 0xA1E8, 0x2192, 0xA1E6, 0x2193, 0xA1E9, 0x2194, 0xA1EA, 0x2195, 0xA2D5, 0x2196, 0xA2D8, + 0x2197, 0xA2D6, 0x2198, 0xA2D9, 0x2199, 0xA2D7, 0x21D2, 0xA2A1, 0x21D4, 0xA2A2, 0x2200, 0xA2A3, 0x2202, 0xA1D3, 0x2203, 0xA2A4, + 0x2207, 0xA1D4, 0x2208, 0xA1F4, 0x220B, 0xA1F5, 0x220F, 0xA2B3, 0x2211, 0xA2B2, 0x221A, 0xA1EE, 0x221D, 0xA1F0, 0x221E, 0xA1C4, + 0x2220, 0xA1D0, 0x2225, 0xA1AB, 0x2227, 0xA1FC, 0x2228, 0xA1FD, 0x2229, 0xA1FB, 0x222A, 0xA1FA, 0x222B, 0xA1F2, 0x222C, 0xA1F3, + 0x222E, 0xA2B1, 0x2234, 0xA1C5, 0x2235, 0xA1F1, 0x223C, 0xA1AD, 0x223D, 0xA1EF, 0x2252, 0xA1D6, 0x2260, 0xA1C1, 0x2261, 0xA1D5, + 0x2264, 0xA1C2, 0x2265, 0xA1C3, 0x226A, 0xA1EC, 0x226B, 0xA1ED, 0x2282, 0xA1F8, 0x2283, 0xA1F9, 0x2286, 0xA1F6, 0x2287, 0xA1F7, + 0x2299, 0xA2C1, 0x22A5, 0xA1D1, 0x2312, 0xA1D2, 0x2460, 0xA8E7, 0x2461, 0xA8E8, 0x2462, 0xA8E9, 0x2463, 0xA8EA, 0x2464, 0xA8EB, + 0x2465, 0xA8EC, 0x2466, 0xA8ED, 0x2467, 0xA8EE, 0x2468, 0xA8EF, 0x2469, 0xA8F0, 0x246A, 0xA8F1, 0x246B, 0xA8F2, 0x246C, 0xA8F3, + 0x246D, 0xA8F4, 0x246E, 0xA8F5, 0x2474, 0xA9E7, 0x2475, 0xA9E8, 0x2476, 0xA9E9, 0x2477, 0xA9EA, 0x2478, 0xA9EB, 0x2479, 0xA9EC, + 0x247A, 0xA9ED, 0x247B, 0xA9EE, 0x247C, 0xA9EF, 0x247D, 0xA9F0, 0x247E, 0xA9F1, 0x247F, 0xA9F2, 0x2480, 0xA9F3, 0x2481, 0xA9F4, + 0x2482, 0xA9F5, 0x249C, 0xA9CD, 0x249D, 0xA9CE, 0x249E, 0xA9CF, 0x249F, 0xA9D0, 0x24A0, 0xA9D1, 0x24A1, 0xA9D2, 0x24A2, 0xA9D3, + 0x24A3, 0xA9D4, 0x24A4, 0xA9D5, 0x24A5, 0xA9D6, 0x24A6, 0xA9D7, 0x24A7, 0xA9D8, 0x24A8, 0xA9D9, 0x24A9, 0xA9DA, 0x24AA, 0xA9DB, + 0x24AB, 0xA9DC, 0x24AC, 0xA9DD, 0x24AD, 0xA9DE, 0x24AE, 0xA9DF, 0x24AF, 0xA9E0, 0x24B0, 0xA9E1, 0x24B1, 0xA9E2, 0x24B2, 0xA9E3, + 0x24B3, 0xA9E4, 0x24B4, 0xA9E5, 0x24B5, 0xA9E6, 0x24D0, 0xA8CD, 0x24D1, 0xA8CE, 0x24D2, 0xA8CF, 0x24D3, 0xA8D0, 0x24D4, 0xA8D1, + 0x24D5, 0xA8D2, 0x24D6, 0xA8D3, 0x24D7, 0xA8D4, 0x24D8, 0xA8D5, 0x24D9, 0xA8D6, 0x24DA, 0xA8D7, 0x24DB, 0xA8D8, 0x24DC, 0xA8D9, + 0x24DD, 0xA8DA, 0x24DE, 0xA8DB, 0x24DF, 0xA8DC, 0x24E0, 0xA8DD, 0x24E1, 0xA8DE, 0x24E2, 0xA8DF, 0x24E3, 0xA8E0, 0x24E4, 0xA8E1, + 0x24E5, 0xA8E2, 0x24E6, 0xA8E3, 0x24E7, 0xA8E4, 0x24E8, 0xA8E5, 0x24E9, 0xA8E6, 0x2500, 0xA6A1, 0x2501, 0xA6AC, 0x2502, 0xA6A2, + 0x2503, 0xA6AD, 0x250C, 0xA6A3, 0x250D, 0xA6C8, 0x250E, 0xA6C7, 0x250F, 0xA6AE, 0x2510, 0xA6A4, 0x2511, 0xA6C2, 0x2512, 0xA6C1, + 0x2513, 0xA6AF, 0x2514, 0xA6A6, 0x2515, 0xA6C6, 0x2516, 0xA6C5, 0x2517, 0xA6B1, 0x2518, 0xA6A5, 0x2519, 0xA6C4, 0x251A, 0xA6C3, + 0x251B, 0xA6B0, 0x251C, 0xA6A7, 0x251D, 0xA6BC, 0x251E, 0xA6C9, 0x251F, 0xA6CA, 0x2520, 0xA6B7, 0x2521, 0xA6CB, 0x2522, 0xA6CC, + 0x2523, 0xA6B2, 0x2524, 0xA6A9, 0x2525, 0xA6BE, 0x2526, 0xA6CD, 0x2527, 0xA6CE, 0x2528, 0xA6B9, 0x2529, 0xA6CF, 0x252A, 0xA6D0, + 0x252B, 0xA6B4, 0x252C, 0xA6A8, 0x252D, 0xA6D1, 0x252E, 0xA6D2, 0x252F, 0xA6B8, 0x2530, 0xA6BD, 0x2531, 0xA6D3, 0x2532, 0xA6D4, + 0x2533, 0xA6B3, 0x2534, 0xA6AA, 0x2535, 0xA6D5, 0x2536, 0xA6D6, 0x2537, 0xA6BA, 0x2538, 0xA6BF, 0x2539, 0xA6D7, 0x253A, 0xA6D8, + 0x253B, 0xA6B5, 0x253C, 0xA6AB, 0x253D, 0xA6D9, 0x253E, 0xA6DA, 0x253F, 0xA6BB, 0x2540, 0xA6DB, 0x2541, 0xA6DC, 0x2542, 0xA6C0, + 0x2543, 0xA6DD, 0x2544, 0xA6DE, 0x2545, 0xA6DF, 0x2546, 0xA6E0, 0x2547, 0xA6E1, 0x2548, 0xA6E2, 0x2549, 0xA6E3, 0x254A, 0xA6E4, + 0x254B, 0xA6B6, 0x2592, 0xA2C6, 0x25A0, 0xA1E1, 0x25A1, 0xA1E0, 0x25A3, 0xA2C3, 0x25A4, 0xA2C7, 0x25A5, 0xA2C8, 0x25A6, 0xA2CB, + 0x25A7, 0xA2CA, 0x25A8, 0xA2C9, 0x25A9, 0xA2CC, 0x25B2, 0xA1E3, 0x25B3, 0xA1E2, 0x25B6, 0xA2BA, 0x25B7, 0xA2B9, 0x25BC, 0xA1E5, + 0x25BD, 0xA1E4, 0x25C0, 0xA2B8, 0x25C1, 0xA2B7, 0x25C6, 0xA1DF, 0x25C7, 0xA1DE, 0x25C8, 0xA2C2, 0x25CB, 0xA1DB, 0x25CE, 0xA1DD, + 0x25CF, 0xA1DC, 0x25D0, 0xA2C4, 0x25D1, 0xA2C5, 0x2605, 0xA1DA, 0x2606, 0xA1D9, 0x260E, 0xA2CF, 0x260F, 0xA2CE, 0x261C, 0xA2D0, + 0x261E, 0xA2D1, 0x2640, 0xA1CF, 0x2642, 0xA1CE, 0x2660, 0xA2BC, 0x2661, 0xA2BD, 0x2663, 0xA2C0, 0x2664, 0xA2BB, 0x2665, 0xA2BE, + 0x2667, 0xA2BF, 0x2668, 0xA2CD, 0x2669, 0xA2DB, 0x266A, 0xA2DC, 0x266C, 0xA2DD, 0x266D, 0xA2DA, 0x3000, 0xA1A1, 0x3001, 0xA1A2, + 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3008, 0xA1B4, 0x3009, 0xA1B5, 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, + 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BC, 0x3011, 0xA1BD, 0x3013, 0xA1EB, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3041, 0xAAA1, + 0x3042, 0xAAA2, 0x3043, 0xAAA3, 0x3044, 0xAAA4, 0x3045, 0xAAA5, 0x3046, 0xAAA6, 0x3047, 0xAAA7, 0x3048, 0xAAA8, 0x3049, 0xAAA9, + 0x304A, 0xAAAA, 0x304B, 0xAAAB, 0x304C, 0xAAAC, 0x304D, 0xAAAD, 0x304E, 0xAAAE, 0x304F, 0xAAAF, 0x3050, 0xAAB0, 0x3051, 0xAAB1, + 0x3052, 0xAAB2, 0x3053, 0xAAB3, 0x3054, 0xAAB4, 0x3055, 0xAAB5, 0x3056, 0xAAB6, 0x3057, 0xAAB7, 0x3058, 0xAAB8, 0x3059, 0xAAB9, + 0x305A, 0xAABA, 0x305B, 0xAABB, 0x305C, 0xAABC, 0x305D, 0xAABD, 0x305E, 0xAABE, 0x305F, 0xAABF, 0x3060, 0xAAC0, 0x3061, 0xAAC1, + 0x3062, 0xAAC2, 0x3063, 0xAAC3, 0x3064, 0xAAC4, 0x3065, 0xAAC5, 0x3066, 0xAAC6, 0x3067, 0xAAC7, 0x3068, 0xAAC8, 0x3069, 0xAAC9, + 0x306A, 0xAACA, 0x306B, 0xAACB, 0x306C, 0xAACC, 0x306D, 0xAACD, 0x306E, 0xAACE, 0x306F, 0xAACF, 0x3070, 0xAAD0, 0x3071, 0xAAD1, + 0x3072, 0xAAD2, 0x3073, 0xAAD3, 0x3074, 0xAAD4, 0x3075, 0xAAD5, 0x3076, 0xAAD6, 0x3077, 0xAAD7, 0x3078, 0xAAD8, 0x3079, 0xAAD9, + 0x307A, 0xAADA, 0x307B, 0xAADB, 0x307C, 0xAADC, 0x307D, 0xAADD, 0x307E, 0xAADE, 0x307F, 0xAADF, 0x3080, 0xAAE0, 0x3081, 0xAAE1, + 0x3082, 0xAAE2, 0x3083, 0xAAE3, 0x3084, 0xAAE4, 0x3085, 0xAAE5, 0x3086, 0xAAE6, 0x3087, 0xAAE7, 0x3088, 0xAAE8, 0x3089, 0xAAE9, + 0x308A, 0xAAEA, 0x308B, 0xAAEB, 0x308C, 0xAAEC, 0x308D, 0xAAED, 0x308E, 0xAAEE, 0x308F, 0xAAEF, 0x3090, 0xAAF0, 0x3091, 0xAAF1, + 0x3092, 0xAAF2, 0x3093, 0xAAF3, 0x30A1, 0xABA1, 0x30A2, 0xABA2, 0x30A3, 0xABA3, 0x30A4, 0xABA4, 0x30A5, 0xABA5, 0x30A6, 0xABA6, + 0x30A7, 0xABA7, 0x30A8, 0xABA8, 0x30A9, 0xABA9, 0x30AA, 0xABAA, 0x30AB, 0xABAB, 0x30AC, 0xABAC, 0x30AD, 0xABAD, 0x30AE, 0xABAE, + 0x30AF, 0xABAF, 0x30B0, 0xABB0, 0x30B1, 0xABB1, 0x30B2, 0xABB2, 0x30B3, 0xABB3, 0x30B4, 0xABB4, 0x30B5, 0xABB5, 0x30B6, 0xABB6, + 0x30B7, 0xABB7, 0x30B8, 0xABB8, 0x30B9, 0xABB9, 0x30BA, 0xABBA, 0x30BB, 0xABBB, 0x30BC, 0xABBC, 0x30BD, 0xABBD, 0x30BE, 0xABBE, + 0x30BF, 0xABBF, 0x30C0, 0xABC0, 0x30C1, 0xABC1, 0x30C2, 0xABC2, 0x30C3, 0xABC3, 0x30C4, 0xABC4, 0x30C5, 0xABC5, 0x30C6, 0xABC6, + 0x30C7, 0xABC7, 0x30C8, 0xABC8, 0x30C9, 0xABC9, 0x30CA, 0xABCA, 0x30CB, 0xABCB, 0x30CC, 0xABCC, 0x30CD, 0xABCD, 0x30CE, 0xABCE, + 0x30CF, 0xABCF, 0x30D0, 0xABD0, 0x30D1, 0xABD1, 0x30D2, 0xABD2, 0x30D3, 0xABD3, 0x30D4, 0xABD4, 0x30D5, 0xABD5, 0x30D6, 0xABD6, + 0x30D7, 0xABD7, 0x30D8, 0xABD8, 0x30D9, 0xABD9, 0x30DA, 0xABDA, 0x30DB, 0xABDB, 0x30DC, 0xABDC, 0x30DD, 0xABDD, 0x30DE, 0xABDE, + 0x30DF, 0xABDF, 0x30E0, 0xABE0, 0x30E1, 0xABE1, 0x30E2, 0xABE2, 0x30E3, 0xABE3, 0x30E4, 0xABE4, 0x30E5, 0xABE5, 0x30E6, 0xABE6, + 0x30E7, 0xABE7, 0x30E8, 0xABE8, 0x30E9, 0xABE9, 0x30EA, 0xABEA, 0x30EB, 0xABEB, 0x30EC, 0xABEC, 0x30ED, 0xABED, 0x30EE, 0xABEE, + 0x30EF, 0xABEF, 0x30F0, 0xABF0, 0x30F1, 0xABF1, 0x30F2, 0xABF2, 0x30F3, 0xABF3, 0x30F4, 0xABF4, 0x30F5, 0xABF5, 0x30F6, 0xABF6, + 0x3131, 0xA4A1, 0x3132, 0xA4A2, 0x3133, 0xA4A3, 0x3134, 0xA4A4, 0x3135, 0xA4A5, 0x3136, 0xA4A6, 0x3137, 0xA4A7, 0x3138, 0xA4A8, + 0x3139, 0xA4A9, 0x313A, 0xA4AA, 0x313B, 0xA4AB, 0x313C, 0xA4AC, 0x313D, 0xA4AD, 0x313E, 0xA4AE, 0x313F, 0xA4AF, 0x3140, 0xA4B0, + 0x3141, 0xA4B1, 0x3142, 0xA4B2, 0x3143, 0xA4B3, 0x3144, 0xA4B4, 0x3145, 0xA4B5, 0x3146, 0xA4B6, 0x3147, 0xA4B7, 0x3148, 0xA4B8, + 0x3149, 0xA4B9, 0x314A, 0xA4BA, 0x314B, 0xA4BB, 0x314C, 0xA4BC, 0x314D, 0xA4BD, 0x314E, 0xA4BE, 0x314F, 0xA4BF, 0x3150, 0xA4C0, + 0x3151, 0xA4C1, 0x3152, 0xA4C2, 0x3153, 0xA4C3, 0x3154, 0xA4C4, 0x3155, 0xA4C5, 0x3156, 0xA4C6, 0x3157, 0xA4C7, 0x3158, 0xA4C8, + 0x3159, 0xA4C9, 0x315A, 0xA4CA, 0x315B, 0xA4CB, 0x315C, 0xA4CC, 0x315D, 0xA4CD, 0x315E, 0xA4CE, 0x315F, 0xA4CF, 0x3160, 0xA4D0, + 0x3161, 0xA4D1, 0x3162, 0xA4D2, 0x3163, 0xA4D3, 0x3164, 0xA4D4, 0x3165, 0xA4D5, 0x3166, 0xA4D6, 0x3167, 0xA4D7, 0x3168, 0xA4D8, + 0x3169, 0xA4D9, 0x316A, 0xA4DA, 0x316B, 0xA4DB, 0x316C, 0xA4DC, 0x316D, 0xA4DD, 0x316E, 0xA4DE, 0x316F, 0xA4DF, 0x3170, 0xA4E0, + 0x3171, 0xA4E1, 0x3172, 0xA4E2, 0x3173, 0xA4E3, 0x3174, 0xA4E4, 0x3175, 0xA4E5, 0x3176, 0xA4E6, 0x3177, 0xA4E7, 0x3178, 0xA4E8, + 0x3179, 0xA4E9, 0x317A, 0xA4EA, 0x317B, 0xA4EB, 0x317C, 0xA4EC, 0x317D, 0xA4ED, 0x317E, 0xA4EE, 0x317F, 0xA4EF, 0x3180, 0xA4F0, + 0x3181, 0xA4F1, 0x3182, 0xA4F2, 0x3183, 0xA4F3, 0x3184, 0xA4F4, 0x3185, 0xA4F5, 0x3186, 0xA4F6, 0x3187, 0xA4F7, 0x3188, 0xA4F8, + 0x3189, 0xA4F9, 0x318A, 0xA4FA, 0x318B, 0xA4FB, 0x318C, 0xA4FC, 0x318D, 0xA4FD, 0x318E, 0xA4FE, 0x3200, 0xA9B1, 0x3201, 0xA9B2, + 0x3202, 0xA9B3, 0x3203, 0xA9B4, 0x3204, 0xA9B5, 0x3205, 0xA9B6, 0x3206, 0xA9B7, 0x3207, 0xA9B8, 0x3208, 0xA9B9, 0x3209, 0xA9BA, + 0x320A, 0xA9BB, 0x320B, 0xA9BC, 0x320C, 0xA9BD, 0x320D, 0xA9BE, 0x320E, 0xA9BF, 0x320F, 0xA9C0, 0x3210, 0xA9C1, 0x3211, 0xA9C2, + 0x3212, 0xA9C3, 0x3213, 0xA9C4, 0x3214, 0xA9C5, 0x3215, 0xA9C6, 0x3216, 0xA9C7, 0x3217, 0xA9C8, 0x3218, 0xA9C9, 0x3219, 0xA9CA, + 0x321A, 0xA9CB, 0x321B, 0xA9CC, 0x321C, 0xA2DF, 0x3260, 0xA8B1, 0x3261, 0xA8B2, 0x3262, 0xA8B3, 0x3263, 0xA8B4, 0x3264, 0xA8B5, + 0x3265, 0xA8B6, 0x3266, 0xA8B7, 0x3267, 0xA8B8, 0x3268, 0xA8B9, 0x3269, 0xA8BA, 0x326A, 0xA8BB, 0x326B, 0xA8BC, 0x326C, 0xA8BD, + 0x326D, 0xA8BE, 0x326E, 0xA8BF, 0x326F, 0xA8C0, 0x3270, 0xA8C1, 0x3271, 0xA8C2, 0x3272, 0xA8C3, 0x3273, 0xA8C4, 0x3274, 0xA8C5, + 0x3275, 0xA8C6, 0x3276, 0xA8C7, 0x3277, 0xA8C8, 0x3278, 0xA8C9, 0x3279, 0xA8CA, 0x327A, 0xA8CB, 0x327B, 0xA8CC, 0x327F, 0xA2DE, + 0x3380, 0xA7C9, 0x3381, 0xA7CA, 0x3382, 0xA7CB, 0x3383, 0xA7CC, 0x3384, 0xA7CD, 0x3388, 0xA7BA, 0x3389, 0xA7BB, 0x338A, 0xA7DC, + 0x338B, 0xA7DD, 0x338C, 0xA7DE, 0x338D, 0xA7B6, 0x338E, 0xA7B7, 0x338F, 0xA7B8, 0x3390, 0xA7D4, 0x3391, 0xA7D5, 0x3392, 0xA7D6, + 0x3393, 0xA7D7, 0x3394, 0xA7D8, 0x3395, 0xA7A1, 0x3396, 0xA7A2, 0x3397, 0xA7A3, 0x3398, 0xA7A5, 0x3399, 0xA7AB, 0x339A, 0xA7AC, + 0x339B, 0xA7AD, 0x339C, 0xA7AE, 0x339D, 0xA7AF, 0x339E, 0xA7B0, 0x339F, 0xA7B1, 0x33A0, 0xA7B2, 0x33A1, 0xA7B3, 0x33A2, 0xA7B4, + 0x33A3, 0xA7A7, 0x33A4, 0xA7A8, 0x33A5, 0xA7A9, 0x33A6, 0xA7AA, 0x33A7, 0xA7BD, 0x33A8, 0xA7BE, 0x33A9, 0xA7E5, 0x33AA, 0xA7E6, + 0x33AB, 0xA7E7, 0x33AC, 0xA7E8, 0x33AD, 0xA7E1, 0x33AE, 0xA7E2, 0x33AF, 0xA7E3, 0x33B0, 0xA7BF, 0x33B1, 0xA7C0, 0x33B2, 0xA7C1, + 0x33B3, 0xA7C2, 0x33B4, 0xA7C3, 0x33B5, 0xA7C4, 0x33B6, 0xA7C5, 0x33B7, 0xA7C6, 0x33B8, 0xA7C7, 0x33B9, 0xA7C8, 0x33BA, 0xA7CE, + 0x33BB, 0xA7CF, 0x33BC, 0xA7D0, 0x33BD, 0xA7D1, 0x33BE, 0xA7D2, 0x33BF, 0xA7D3, 0x33C0, 0xA7DA, 0x33C1, 0xA7DB, 0x33C2, 0xA2E3, + 0x33C3, 0xA7EC, 0x33C4, 0xA7A6, 0x33C5, 0xA7E0, 0x33C6, 0xA7EF, 0x33C7, 0xA2E1, 0x33C8, 0xA7BC, 0x33C9, 0xA7ED, 0x33CA, 0xA7B5, + 0x33CF, 0xA7B9, 0x33D0, 0xA7EA, 0x33D3, 0xA7EB, 0x33D6, 0xA7DF, 0x33D8, 0xA2E4, 0x33DB, 0xA7E4, 0x33DC, 0xA7EE, 0x33DD, 0xA7E9, + 0x4E00, 0xECE9, 0x4E01, 0xEFCB, 0x4E03, 0xF6D2, 0x4E07, 0xD8B2, 0x4E08, 0xEDDB, 0x4E09, 0xDFB2, 0x4E0A, 0xDFBE, 0x4E0B, 0xF9BB, + 0x4E0D, 0xDCF4, 0x4E11, 0xF5E4, 0x4E14, 0xF3A6, 0x4E15, 0xDDE0, 0x4E16, 0xE1A6, 0x4E18, 0xCEF8, 0x4E19, 0xDCB0, 0x4E1E, 0xE3AA, + 0x4E2D, 0xF1E9, 0x4E32, 0xCDFA, 0x4E38, 0xFCAF, 0x4E39, 0xD3A1, 0x4E3B, 0xF1AB, 0x4E42, 0xE7D1, 0x4E43, 0xD2AC, 0x4E45, 0xCEF9, + 0x4E4B, 0xF1FD, 0x4E4D, 0xDEBF, 0x4E4E, 0xFBBA, 0x4E4F, 0xF9B9, 0x4E56, 0xCED2, 0x4E58, 0xE3AB, 0x4E59, 0xEBE0, 0x4E5D, 0xCEFA, + 0x4E5E, 0xCBF7, 0x4E5F, 0xE5A5, 0x4E6B, 0xCAE1, 0x4E6D, 0xD4CC, 0x4E73, 0xEAE1, 0x4E76, 0xDCE3, 0x4E77, 0xDFAD, 0x4E7E, 0xCBEB, + 0x4E82, 0xD5AF, 0x4E86, 0xD6F5, 0x4E88, 0xE5F8, 0x4E8B, 0xDEC0, 0x4E8C, 0xECA3, 0x4E8E, 0xE9CD, 0x4E90, 0xEAA7, 0x4E91, 0xE9F6, + 0x4E92, 0xFBBB, 0x4E94, 0xE7E9, 0x4E95, 0xEFCC, 0x4E98, 0xD0E6, 0x4E9B, 0xDEC1, 0x4E9E, 0xE4AC, 0x4EA1, 0xD8CC, 0x4EA2, 0xF9F1, + 0x4EA4, 0xCEDF, 0x4EA5, 0xFAA4, 0x4EA6, 0xE6B2, 0x4EA8, 0xFAFB, 0x4EAB, 0xFABD, 0x4EAC, 0xCCC8, 0x4EAD, 0xEFCD, 0x4EAE, 0xD5D5, + 0x4EB6, 0xD3A2, 0x4EBA, 0xECD1, 0x4EC0, 0xE4A7, 0x4EC1, 0xECD2, 0x4EC4, 0xF6B1, 0x4EC7, 0xCEFB, 0x4ECA, 0xD0D1, 0x4ECB, 0xCBBF, + 0x4ECD, 0xEDA4, 0x4ED4, 0xEDA8, 0x4ED5, 0xDEC2, 0x4ED6, 0xF6E2, 0x4ED7, 0xEDDC, 0x4ED8, 0xDCF5, 0x4ED9, 0xE0B9, 0x4EDD, 0xD4CE, + 0x4EDF, 0xF4B5, 0x4EE3, 0xD3DB, 0x4EE4, 0xD6B5, 0x4EE5, 0xECA4, 0x4EF0, 0xE4E6, 0x4EF2, 0xF1EA, 0x4EF6, 0xCBEC, 0x4EF7, 0xCBC0, + 0x4EFB, 0xECF2, 0x4F01, 0xD0EA, 0x4F09, 0xF9F2, 0x4F0A, 0xECA5, 0x4F0B, 0xD0DF, 0x4F0D, 0xE7EA, 0x4F0E, 0xD0EB, 0x4F0F, 0xDCD1, + 0x4F10, 0xDBE9, 0x4F11, 0xFDCC, 0x4F2F, 0xDBD7, 0x4F34, 0xDAE1, 0x4F36, 0xD6B6, 0x4F38, 0xE3DF, 0x4F3A, 0xDEC3, 0x4F3C, 0xDEC4, + 0x4F3D, 0xCAA1, 0x4F43, 0xEEEC, 0x4F46, 0xD3A3, 0x4F47, 0xEEB7, 0x4F48, 0xF8CF, 0x4F4D, 0xEAC8, 0x4F4E, 0xEEB8, 0x4F4F, 0xF1AC, + 0x4F50, 0xF1A5, 0x4F51, 0xE9CE, 0x4F55, 0xF9BC, 0x4F59, 0xE5F9, 0x4F5A, 0xECEA, 0x4F5B, 0xDDD6, 0x4F5C, 0xEDC2, 0x4F69, 0xF8A5, + 0x4F6F, 0xE5BA, 0x4F70, 0xDBD8, 0x4F73, 0xCAA2, 0x4F76, 0xD1CD, 0x4F7A, 0xEEED, 0x4F7E, 0xECEB, 0x4F7F, 0xDEC5, 0x4F81, 0xE3E0, + 0x4F83, 0xCAC9, 0x4F84, 0xF2E9, 0x4F86, 0xD5CE, 0x4F88, 0xF6B6, 0x4F8A, 0xCEC2, 0x4F8B, 0xD6C7, 0x4F8D, 0xE3B4, 0x4F8F, 0xF1AD, + 0x4F91, 0xEAE2, 0x4F96, 0xD7C2, 0x4F98, 0xF3A7, 0x4F9B, 0xCDEA, 0x4F9D, 0xEBEE, 0x4FAE, 0xD9B2, 0x4FAF, 0xFDA5, 0x4FB5, 0xF6D5, + 0x4FB6, 0xD5E2, 0x4FBF, 0xF8B5, 0x4FC2, 0xCCF5, 0x4FC3, 0xF5B5, 0x4FC4, 0xE4AD, 0x4FC9, 0xE7EB, 0x4FCA, 0xF1D5, 0x4FCE, 0xF0BB, + 0x4FD1, 0xE9B5, 0x4FD3, 0xCCC9, 0x4FD4, 0xFAD5, 0x4FD7, 0xE1D4, 0x4FDA, 0xD7D6, 0x4FDD, 0xDCC1, 0x4FDF, 0xDEC6, 0x4FE0, 0xFAEF, + 0x4FE1, 0xE3E1, 0x4FEE, 0xE1F3, 0x4FEF, 0xDCF6, 0x4FF1, 0xCEFC, 0x4FF3, 0xDBC4, 0x4FF5, 0xF8F1, 0x4FF8, 0xDCE4, 0x4FFA, 0xE5EF, + 0x5002, 0xDCB1, 0x5006, 0xD5D6, 0x5009, 0xF3DA, 0x500B, 0xCBC1, 0x500D, 0xDBC3, 0x5011, 0xD9FA, 0x5012, 0xD3EE, 0x5016, 0xFAB8, + 0x5019, 0xFDA6, 0x501A, 0xEBEF, 0x501C, 0xF4A6, 0x501E, 0xCCCA, 0x501F, 0xF3A8, 0x5021, 0xF3DB, 0x5023, 0xDBA7, 0x5024, 0xF6B7, + 0x5026, 0xCFE6, 0x5027, 0xF0F2, 0x5028, 0xCBDA, 0x502A, 0xE7D2, 0x502B, 0xD7C3, 0x502C, 0xF6F0, 0x502D, 0xE8DE, 0x503B, 0xE5A6, + 0x5043, 0xE5E7, 0x5047, 0xCAA3, 0x5048, 0xCCA7, 0x5049, 0xEAC9, 0x504F, 0xF8B6, 0x5055, 0xFAA5, 0x505A, 0xF1AE, 0x505C, 0xEFCE, + 0x5065, 0xCBED, 0x5074, 0xF6B0, 0x5075, 0xEFCF, 0x5076, 0xE9CF, 0x5078, 0xF7DE, 0x5080, 0xCED3, 0x5085, 0xDCF7, 0x508D, 0xDBA8, + 0x5091, 0xCBF8, 0x5098, 0xDFA1, 0x5099, 0xDDE1, 0x50AC, 0xF5CA, 0x50AD, 0xE9B6, 0x50B2, 0xE7EC, 0x50B3, 0xEEEE, 0x50B5, 0xF3F0, + 0x50B7, 0xDFBF, 0x50BE, 0xCCCB, 0x50C5, 0xD0C1, 0x50C9, 0xF4D2, 0x50CA, 0xE0BA, 0x50CF, 0xDFC0, 0x50D1, 0xCEE0, 0x50D5, 0xDCD2, + 0x50D6, 0xFDEA, 0x50DA, 0xD6F6, 0x50DE, 0xEACA, 0x50E5, 0xE8E9, 0x50E7, 0xE3AC, 0x50ED, 0xF3D0, 0x50F9, 0xCAA4, 0x50FB, 0xDBF8, + 0x50FF, 0xDEC7, 0x5100, 0xEBF0, 0x5101, 0xF1D6, 0x5104, 0xE5E2, 0x5106, 0xCCCC, 0x5109, 0xCBFB, 0x5112, 0xEAE3, 0x511F, 0xDFC1, + 0x5121, 0xD6ED, 0x512A, 0xE9D0, 0x5132, 0xEEB9, 0x5137, 0xD5E3, 0x513A, 0xD1D3, 0x513C, 0xE5F0, 0x5140, 0xE8B4, 0x5141, 0xEBC3, + 0x5143, 0xEAAA, 0x5144, 0xFAFC, 0x5145, 0xF5F6, 0x5146, 0xF0BC, 0x5147, 0xFDD4, 0x5148, 0xE0BB, 0x5149, 0xCEC3, 0x514B, 0xD0BA, + 0x514C, 0xF7BA, 0x514D, 0xD8F3, 0x514E, 0xF7CD, 0x5152, 0xE4AE, 0x515C, 0xD4DF, 0x5162, 0xD0E7, 0x5165, 0xECFD, 0x5167, 0xD2AE, + 0x5168, 0xEEEF, 0x5169, 0xD5D7, 0x516A, 0xEAE4, 0x516B, 0xF8A2, 0x516C, 0xCDEB, 0x516D, 0xD7BF, 0x516E, 0xFBB1, 0x5171, 0xCDEC, + 0x5175, 0xDCB2, 0x5176, 0xD0EC, 0x5177, 0xCEFD, 0x5178, 0xEEF0, 0x517C, 0xCCC2, 0x5180, 0xD0ED, 0x5186, 0xE5F7, 0x518A, 0xF3FC, + 0x518D, 0xEEA2, 0x5192, 0xD9B3, 0x5195, 0xD8F4, 0x5197, 0xE9B7, 0x51A0, 0xCEAE, 0x51A5, 0xD9A2, 0x51AA, 0xD8F1, 0x51AC, 0xD4CF, + 0x51B6, 0xE5A7, 0x51B7, 0xD5D2, 0x51BD, 0xD6A9, 0x51C4, 0xF4A2, 0x51C6, 0xF1D7, 0x51C9, 0xD5D8, 0x51CB, 0xF0BD, 0x51CC, 0xD7D0, + 0x51CD, 0xD4D0, 0x51DC, 0xD7CF, 0x51DD, 0xEBEA, 0x51DE, 0xFDEB, 0x51E1, 0xDBED, 0x51F0, 0xFCC5, 0x51F1, 0xCBC2, 0x51F6, 0xFDD5, + 0x51F8, 0xF4C8, 0x51F9, 0xE8EA, 0x51FA, 0xF5F3, 0x51FD, 0xF9DE, 0x5200, 0xD3EF, 0x5203, 0xECD3, 0x5206, 0xDDC2, 0x5207, 0xEFB7, + 0x5208, 0xE7D4, 0x520A, 0xCACA, 0x520E, 0xD9FB, 0x5211, 0xFAFD, 0x5217, 0xD6AA, 0x521D, 0xF4F8, 0x5224, 0xF7F7, 0x5225, 0xDCAC, + 0x5229, 0xD7D7, 0x522A, 0xDFA2, 0x522E, 0xCEBE, 0x5230, 0xD3F0, 0x5236, 0xF0A4, 0x5237, 0xE1EC, 0x5238, 0xCFE7, 0x5239, 0xF3CB, + 0x523A, 0xEDA9, 0x523B, 0xCABE, 0x5243, 0xF4EF, 0x5247, 0xF6CE, 0x524A, 0xDEFB, 0x524B, 0xD0BB, 0x524C, 0xD5B7, 0x524D, 0xEEF1, + 0x5254, 0xF4A8, 0x5256, 0xDCF8, 0x525B, 0xCBA7, 0x525D, 0xDACE, 0x5261, 0xE0E6, 0x5269, 0xEDA5, 0x526A, 0xEEF2, 0x526F, 0xDCF9, + 0x5272, 0xF9DC, 0x5275, 0xF3DC, 0x527D, 0xF8F2, 0x527F, 0xF4F9, 0x5283, 0xFCF1, 0x5287, 0xD0BC, 0x5288, 0xDBF9, 0x5289, 0xD7B1, + 0x528D, 0xCBFC, 0x5291, 0xF0A5, 0x5292, 0xCBFD, 0x529B, 0xD5F4, 0x529F, 0xCDED, 0x52A0, 0xCAA5, 0x52A3, 0xD6AB, 0x52A4, 0xD0C2, + 0x52A9, 0xF0BE, 0x52AA, 0xD2BD, 0x52AB, 0xCCA4, 0x52BE, 0xFAB6, 0x52C1, 0xCCCD, 0x52C3, 0xDAFA, 0x52C5, 0xF6CF, 0x52C7, 0xE9B8, + 0x52C9, 0xD8F5, 0x52CD, 0xCCCE, 0x52D2, 0xD7CD, 0x52D5, 0xD4D1, 0x52D6, 0xE9ED, 0x52D8, 0xCAEB, 0x52D9, 0xD9E2, 0x52DB, 0xFDB2, + 0x52DD, 0xE3AD, 0x52DE, 0xD6CC, 0x52DF, 0xD9B4, 0x52E2, 0xE1A7, 0x52E3, 0xEED3, 0x52E4, 0xD0C3, 0x52F3, 0xFDB3, 0x52F5, 0xD5E4, + 0x52F8, 0xCFE8, 0x52FA, 0xEDC3, 0x52FB, 0xD0B2, 0x52FE, 0xCEFE, 0x52FF, 0xDAA8, 0x5305, 0xF8D0, 0x5308, 0xFDD6, 0x530D, 0xF8D1, + 0x530F, 0xF8D2, 0x5310, 0xDCD3, 0x5315, 0xDDE2, 0x5316, 0xFBF9, 0x5317, 0xDDC1, 0x5319, 0xE3B5, 0x5320, 0xEDDD, 0x5321, 0xCEC4, + 0x5323, 0xCBA1, 0x532A, 0xDDE3, 0x532F, 0xFCDD, 0x5339, 0xF9AF, 0x533F, 0xD2FB, 0x5340, 0xCFA1, 0x5341, 0xE4A8, 0x5343, 0xF4B6, + 0x5344, 0xECFE, 0x5347, 0xE3AE, 0x5348, 0xE7ED, 0x5349, 0xFDC1, 0x534A, 0xDAE2, 0x534D, 0xD8B3, 0x5351, 0xDDE4, 0x5352, 0xF0EF, + 0x5353, 0xF6F1, 0x5354, 0xFAF0, 0x5357, 0xD1F5, 0x535A, 0xDACF, 0x535C, 0xDCD4, 0x535E, 0xDCA6, 0x5360, 0xEFBF, 0x5366, 0xCECF, + 0x5368, 0xE0D9, 0x536F, 0xD9D6, 0x5370, 0xECD4, 0x5371, 0xEACB, 0x5374, 0xCABF, 0x5375, 0xD5B0, 0x5377, 0xCFE9, 0x537D, 0xF1ED, + 0x537F, 0xCCCF, 0x5384, 0xE4F8, 0x5393, 0xE4ED, 0x5398, 0xD7D8, 0x539A, 0xFDA7, 0x539F, 0xEAAB, 0x53A0, 0xF6B2, 0x53A5, 0xCFF0, + 0x53A6, 0xF9BD, 0x53AD, 0xE6F4, 0x53BB, 0xCBDB, 0x53C3, 0xF3D1, 0x53C8, 0xE9D1, 0x53C9, 0xF3A9, 0x53CA, 0xD0E0, 0x53CB, 0xE9D2, + 0x53CD, 0xDAE3, 0x53D4, 0xE2D2, 0x53D6, 0xF6A2, 0x53D7, 0xE1F4, 0x53DB, 0xDAE4, 0x53E1, 0xE7D5, 0x53E2, 0xF5BF, 0x53E3, 0xCFA2, + 0x53E4, 0xCDAF, 0x53E5, 0xCFA3, 0x53E9, 0xCDB0, 0x53EA, 0xF1FE, 0x53EB, 0xD0A3, 0x53EC, 0xE1AF, 0x53ED, 0xF8A3, 0x53EF, 0xCAA6, + 0x53F0, 0xF7BB, 0x53F1, 0xF2EA, 0x53F2, 0xDEC8, 0x53F3, 0xE9D3, 0x53F8, 0xDEC9, 0x5403, 0xFDDE, 0x5404, 0xCAC0, 0x5408, 0xF9EA, + 0x5409, 0xD1CE, 0x540A, 0xEED4, 0x540C, 0xD4D2, 0x540D, 0xD9A3, 0x540E, 0xFDA8, 0x540F, 0xD7D9, 0x5410, 0xF7CE, 0x5411, 0xFABE, + 0x541B, 0xCFD6, 0x541D, 0xD7F0, 0x541F, 0xEBE1, 0x5420, 0xF8C5, 0x5426, 0xDCFA, 0x5429, 0xDDC3, 0x542B, 0xF9DF, 0x5433, 0xE7EF, + 0x5438, 0xFDE5, 0x5439, 0xF6A3, 0x543B, 0xD9FC, 0x543C, 0xFDA9, 0x543E, 0xE7EE, 0x5442, 0xD5E5, 0x5448, 0xEFD0, 0x544A, 0xCDB1, + 0x5451, 0xF7A2, 0x5468, 0xF1B2, 0x546A, 0xF1B1, 0x5471, 0xCDB2, 0x5473, 0xDAAB, 0x5475, 0xCAA7, 0x547B, 0xE3E2, 0x547C, 0xFBBC, + 0x547D, 0xD9A4, 0x5480, 0xEEBA, 0x5486, 0xF8D3, 0x548C, 0xFBFA, 0x548E, 0xCFA4, 0x5490, 0xDCFB, 0x54A4, 0xF6E3, 0x54A8, 0xEDAA, + 0x54AB, 0xF2A1, 0x54AC, 0xCEE1, 0x54B3, 0xFAA6, 0x54B8, 0xF9E0, 0x54BD, 0xECD6, 0x54C0, 0xE4EE, 0x54C1, 0xF9A1, 0x54C4, 0xFBEF, + 0x54C8, 0xF9EB, 0x54C9, 0xEEA3, 0x54E1, 0xEAAC, 0x54E5, 0xCAA8, 0x54E8, 0xF4FA, 0x54ED, 0xCDD6, 0x54EE, 0xFCF6, 0x54F2, 0xF4C9, + 0x54FA, 0xF8D4, 0x5504, 0xF8A6, 0x5506, 0xDECA, 0x5507, 0xF2C6, 0x550E, 0xD7DA, 0x5510, 0xD3D0, 0x551C, 0xD8C5, 0x552F, 0xEAE6, + 0x5531, 0xF3DD, 0x5535, 0xE4DA, 0x553E, 0xF6E4, 0x5544, 0xF6F2, 0x5546, 0xDFC2, 0x554F, 0xD9FD, 0x5553, 0xCCF6, 0x5556, 0xD3BA, + 0x555E, 0xE4AF, 0x5563, 0xF9E1, 0x557C, 0xF0A6, 0x5580, 0xCBD3, 0x5584, 0xE0BC, 0x5586, 0xF4CA, 0x5587, 0xD4FA, 0x5589, 0xFDAA, + 0x558A, 0xF9E2, 0x5598, 0xF4B7, 0x5599, 0xFDC2, 0x559A, 0xFCB0, 0x559C, 0xFDEC, 0x559D, 0xCAE2, 0x55A7, 0xFDBD, 0x55A9, 0xEAE7, + 0x55AA, 0xDFC3, 0x55AB, 0xD1D2, 0x55AC, 0xCEE2, 0x55AE, 0xD3A4, 0x55C5, 0xFDAB, 0x55C7, 0xDFE0, 0x55D4, 0xF2C7, 0x55DA, 0xE7F0, + 0x55DC, 0xD0EE, 0x55DF, 0xF3AA, 0x55E3, 0xDECB, 0x55E4, 0xF6B8, 0x55FD, 0xE1F5, 0x55FE, 0xF1B3, 0x5606, 0xF7A3, 0x5609, 0xCAA9, + 0x5614, 0xCFA5, 0x5617, 0xDFC4, 0x562F, 0xE1B0, 0x5632, 0xF0BF, 0x5634, 0xF6A4, 0x5636, 0xE3B6, 0x5653, 0xFAC6, 0x5668, 0xD0EF, + 0x566B, 0xFDED, 0x5674, 0xDDC4, 0x5686, 0xFCF7, 0x56A5, 0xE6BF, 0x56AC, 0xDEAD, 0x56AE, 0xFABF, 0x56B4, 0xE5F1, 0x56BC, 0xEDC4, + 0x56CA, 0xD2A5, 0x56CD, 0xFDEE, 0x56D1, 0xF5B6, 0x56DA, 0xE1F6, 0x56DB, 0xDECC, 0x56DE, 0xFCDE, 0x56E0, 0xECD7, 0x56F0, 0xCDDD, + 0x56F9, 0xD6B7, 0x56FA, 0xCDB3, 0x5703, 0xF8D5, 0x5704, 0xE5D8, 0x5708, 0xCFEA, 0x570B, 0xCFD0, 0x570D, 0xEACC, 0x5712, 0xEAAE, + 0x5713, 0xEAAD, 0x5716, 0xD3F1, 0x5718, 0xD3A5, 0x571F, 0xF7CF, 0x5728, 0xEEA4, 0x572D, 0xD0A4, 0x5730, 0xF2A2, 0x573B, 0xD0F0, + 0x5740, 0xF2A3, 0x5742, 0xF7F8, 0x5747, 0xD0B3, 0x574A, 0xDBA9, 0x574D, 0xD3BB, 0x574E, 0xCAEC, 0x5750, 0xF1A6, 0x5751, 0xCBD5, + 0x5761, 0xF7E7, 0x5764, 0xCDDE, 0x5766, 0xF7A4, 0x576A, 0xF8C0, 0x576E, 0xD3DD, 0x5770, 0xCCD0, 0x5775, 0xCFA6, 0x577C, 0xF6F3, + 0x5782, 0xE1F7, 0x5788, 0xD3DC, 0x578B, 0xFAFE, 0x5793, 0xFAA7, 0x57A0, 0xEBD9, 0x57A2, 0xCFA7, 0x57A3, 0xEAAF, 0x57C3, 0xE4EF, + 0x57C7, 0xE9B9, 0x57C8, 0xF1D8, 0x57CB, 0xD8D8, 0x57CE, 0xE0F2, 0x57DF, 0xE6B4, 0x57E0, 0xDCFC, 0x57F0, 0xF3F1, 0x57F4, 0xE3D0, + 0x57F7, 0xF2FB, 0x57F9, 0xDBC6, 0x57FA, 0xD0F1, 0x57FC, 0xD0F2, 0x5800, 0xCFDC, 0x5802, 0xD3D1, 0x5805, 0xCCB1, 0x5806, 0xF7D8, + 0x5808, 0xCBA8, 0x5809, 0xEBBC, 0x580A, 0xE4BE, 0x581E, 0xF4DC, 0x5821, 0xDCC2, 0x5824, 0xF0A7, 0x5827, 0xE6C0, 0x582A, 0xCAED, + 0x582F, 0xE8EB, 0x5830, 0xE5E8, 0x5831, 0xDCC3, 0x5834, 0xEDDE, 0x5835, 0xD3F2, 0x583A, 0xCCF7, 0x584A, 0xCED4, 0x584B, 0xE7AB, + 0x584F, 0xCBC3, 0x5851, 0xE1B1, 0x5854, 0xF7B2, 0x5857, 0xD3F3, 0x5858, 0xD3D2, 0x585A, 0xF5C0, 0x585E, 0xDFDD, 0x5861, 0xEEF3, + 0x5862, 0xE7F1, 0x5864, 0xFDB4, 0x5875, 0xF2C8, 0x5879, 0xF3D2, 0x587C, 0xEEF4, 0x587E, 0xE2D3, 0x5883, 0xCCD1, 0x5885, 0xDFEA, + 0x5889, 0xE9BA, 0x5893, 0xD9D7, 0x589C, 0xF5CD, 0x589E, 0xF1F2, 0x589F, 0xFAC7, 0x58A8, 0xD9F8, 0x58A9, 0xD4C2, 0x58AE, 0xF6E5, + 0x58B3, 0xDDC5, 0x58BA, 0xE7F2, 0x58BB, 0xEDDF, 0x58BE, 0xCACB, 0x58C1, 0xDBFA, 0x58C5, 0xE8B5, 0x58C7, 0xD3A6, 0x58CE, 0xFDB5, + 0x58D1, 0xF9C9, 0x58D3, 0xE4E2, 0x58D5, 0xFBBD, 0x58D8, 0xD7A4, 0x58D9, 0xCEC5, 0x58DE, 0xCED5, 0x58DF, 0xD6E6, 0x58E4, 0xE5BD, + 0x58EB, 0xDECD, 0x58EC, 0xECF3, 0x58EF, 0xEDE0, 0x58F9, 0xECEC, 0x58FA, 0xFBBE, 0x58FB, 0xDFEB, 0x58FD, 0xE1F8, 0x590F, 0xF9BE, + 0x5914, 0xD0F3, 0x5915, 0xE0AA, 0x5916, 0xE8E2, 0x5919, 0xE2D4, 0x591A, 0xD2FD, 0x591C, 0xE5A8, 0x5922, 0xD9D3, 0x5927, 0xD3DE, + 0x5929, 0xF4B8, 0x592A, 0xF7BC, 0x592B, 0xDCFD, 0x592D, 0xE8EC, 0x592E, 0xE4E7, 0x5931, 0xE3F7, 0x5937, 0xECA8, 0x593E, 0xFAF1, + 0x5944, 0xE5F2, 0x5947, 0xD0F4, 0x5948, 0xD2AF, 0x5949, 0xDCE5, 0x594E, 0xD0A5, 0x594F, 0xF1B4, 0x5950, 0xFCB1, 0x5951, 0xCCF8, + 0x5954, 0xDDC6, 0x5955, 0xFAD1, 0x5957, 0xF7DF, 0x595A, 0xFAA8, 0x5960, 0xEEF5, 0x5962, 0xDECE, 0x5967, 0xE7F3, 0x596A, 0xF7AC, + 0x596B, 0xEBC4, 0x596C, 0xEDE1, 0x596D, 0xE0AB, 0x596E, 0xDDC7, 0x5973, 0xD2B3, 0x5974, 0xD2BF, 0x5978, 0xCACC, 0x597D, 0xFBBF, + 0x5982, 0xE5FD, 0x5983, 0xDDE5, 0x5984, 0xD8CD, 0x598A, 0xECF4, 0x5993, 0xD0F5, 0x5996, 0xE8ED, 0x5997, 0xD0D2, 0x5999, 0xD9D8, + 0x59A5, 0xF6E6, 0x59A8, 0xDBAA, 0x59AC, 0xF7E0, 0x59B9, 0xD8D9, 0x59BB, 0xF4A3, 0x59BE, 0xF4DD, 0x59C3, 0xEFD1, 0x59C6, 0xD9B5, + 0x59C9, 0xEDAB, 0x59CB, 0xE3B7, 0x59D0, 0xEEBB, 0x59D1, 0xCDB4, 0x59D3, 0xE0F3, 0x59D4, 0xEACD, 0x59D9, 0xECF5, 0x59DA, 0xE8EE, + 0x59DC, 0xCBA9, 0x59DD, 0xF1AF, 0x59E6, 0xCACD, 0x59E8, 0xECA9, 0x59EA, 0xF2EB, 0x59EC, 0xFDEF, 0x59EE, 0xF9F3, 0x59F8, 0xE6C1, + 0x59FB, 0xECD8, 0x59FF, 0xEDAC, 0x5A01, 0xEACE, 0x5A03, 0xE8DF, 0x5A11, 0xDECF, 0x5A18, 0xD2A6, 0x5A1B, 0xE7F4, 0x5A1C, 0xD1D6, + 0x5A1F, 0xE6C2, 0x5A20, 0xE3E3, 0x5A25, 0xE4B0, 0x5A29, 0xD8B4, 0x5A36, 0xF6A5, 0x5A3C, 0xF3DE, 0x5A41, 0xD7A5, 0x5A46, 0xF7E8, + 0x5A49, 0xE8C6, 0x5A5A, 0xFBE6, 0x5A62, 0xDDE6, 0x5A66, 0xDCFE, 0x5A92, 0xD8DA, 0x5A9A, 0xDAAC, 0x5A9B, 0xEAB0, 0x5AA4, 0xE3B8, + 0x5AC1, 0xCAAA, 0x5AC2, 0xE1F9, 0x5AC4, 0xEAB1, 0x5AC9, 0xF2EC, 0x5ACC, 0xFAEE, 0x5AE1, 0xEED5, 0x5AE6, 0xF9F4, 0x5AE9, 0xD2EC, + 0x5B05, 0xFBFB, 0x5B09, 0xFDF0, 0x5B0B, 0xE0BD, 0x5B0C, 0xCEE3, 0x5B16, 0xF8C6, 0x5B2A, 0xDEAE, 0x5B40, 0xDFC5, 0x5B43, 0xE5BE, + 0x5B50, 0xEDAD, 0x5B51, 0xFAEA, 0x5B54, 0xCDEE, 0x5B55, 0xEDA6, 0x5B57, 0xEDAE, 0x5B58, 0xF0ED, 0x5B5A, 0xDDA1, 0x5B5C, 0xEDAF, + 0x5B5D, 0xFCF8, 0x5B5F, 0xD8EB, 0x5B63, 0xCCF9, 0x5B64, 0xCDB5, 0x5B69, 0xFAA9, 0x5B6B, 0xE1DD, 0x5B70, 0xE2D5, 0x5B71, 0xEDCF, + 0x5B75, 0xDDA2, 0x5B78, 0xF9CA, 0x5B7A, 0xEAE8, 0x5B7C, 0xE5ED, 0x5B85, 0xD3EB, 0x5B87, 0xE9D4, 0x5B88, 0xE1FA, 0x5B89, 0xE4CC, + 0x5B8B, 0xE1E4, 0x5B8C, 0xE8C7, 0x5B8F, 0xCEDB, 0x5B93, 0xDCD5, 0x5B95, 0xF7B5, 0x5B96, 0xFCF3, 0x5B97, 0xF0F3, 0x5B98, 0xCEAF, + 0x5B99, 0xF1B5, 0x5B9A, 0xEFD2, 0x5B9B, 0xE8C8, 0x5B9C, 0xEBF1, 0x5BA2, 0xCBD4, 0x5BA3, 0xE0BE, 0x5BA4, 0xE3F8, 0x5BA5, 0xEAE9, + 0x5BA6, 0xFCB2, 0x5BAC, 0xE0F4, 0x5BAE, 0xCFE0, 0x5BB0, 0xEEA5, 0x5BB3, 0xFAAA, 0x5BB4, 0xE6C3, 0x5BB5, 0xE1B2, 0x5BB6, 0xCAAB, + 0x5BB8, 0xE3E4, 0x5BB9, 0xE9BB, 0x5BBF, 0xE2D6, 0x5BC0, 0xF3F2, 0x5BC2, 0xEED6, 0x5BC3, 0xEAB2, 0x5BC4, 0xD0F6, 0x5BC5, 0xECD9, + 0x5BC6, 0xDACB, 0x5BC7, 0xCFA8, 0x5BCC, 0xDDA3, 0x5BD0, 0xD8DB, 0x5BD2, 0xF9CE, 0x5BD3, 0xE9D5, 0x5BD4, 0xE3D1, 0x5BD7, 0xD2BC, + 0x5BDE, 0xD8AC, 0x5BDF, 0xF3CC, 0x5BE1, 0xCDFB, 0x5BE2, 0xF6D6, 0x5BE4, 0xE7F5, 0x5BE5, 0xE8EF, 0x5BE6, 0xE3F9, 0x5BE7, 0xD2BB, + 0x5BE8, 0xF3F3, 0x5BE9, 0xE3FB, 0x5BEB, 0xDED0, 0x5BEC, 0xCEB0, 0x5BEE, 0xD6F7, 0x5BEF, 0xF1D9, 0x5BF5, 0xF5C1, 0x5BF6, 0xDCC4, + 0x5BF8, 0xF5BB, 0x5BFA, 0xDED1, 0x5C01, 0xDCE6, 0x5C04, 0xDED2, 0x5C07, 0xEDE2, 0x5C08, 0xEEF6, 0x5C09, 0xEACF, 0x5C0A, 0xF0EE, + 0x5C0B, 0xE3FC, 0x5C0D, 0xD3DF, 0x5C0E, 0xD3F4, 0x5C0F, 0xE1B3, 0x5C11, 0xE1B4, 0x5C16, 0xF4D3, 0x5C19, 0xDFC6, 0x5C24, 0xE9D6, + 0x5C28, 0xDBAB, 0x5C31, 0xF6A6, 0x5C38, 0xE3B9, 0x5C39, 0xEBC5, 0x5C3A, 0xF4A9, 0x5C3B, 0xCDB6, 0x5C3C, 0xD2F9, 0x5C3E, 0xDAAD, + 0x5C3F, 0xD2E3, 0x5C40, 0xCFD1, 0x5C45, 0xCBDC, 0x5C46, 0xCCFA, 0x5C48, 0xCFDD, 0x5C4B, 0xE8A9, 0x5C4D, 0xE3BB, 0x5C4E, 0xE3BA, + 0x5C51, 0xE0DA, 0x5C55, 0xEEF7, 0x5C5B, 0xDCB3, 0x5C60, 0xD3F5, 0x5C62, 0xD7A6, 0x5C64, 0xF6B5, 0x5C65, 0xD7DB, 0x5C6C, 0xE1D5, + 0x5C6F, 0xD4EA, 0x5C71, 0xDFA3, 0x5C79, 0xFDDF, 0x5C90, 0xD0F7, 0x5C91, 0xEDD4, 0x5CA1, 0xCBAA, 0x5CA9, 0xE4DB, 0x5CAB, 0xE1FB, + 0x5CAC, 0xCBA2, 0x5CB1, 0xD3E0, 0x5CB3, 0xE4BF, 0x5CB5, 0xFBC0, 0x5CB7, 0xDABE, 0x5CB8, 0xE4CD, 0x5CBA, 0xD6B9, 0x5CBE, 0xEFC0, + 0x5CC0, 0xE1FC, 0x5CD9, 0xF6B9, 0x5CE0, 0xDFC7, 0x5CE8, 0xE4B1, 0x5CEF, 0xDCE7, 0x5CF0, 0xDCE8, 0x5CF4, 0xFAD6, 0x5CF6, 0xD3F6, + 0x5CFB, 0xF1DA, 0x5CFD, 0xFAF2, 0x5D07, 0xE2FD, 0x5D0D, 0xD5CF, 0x5D0E, 0xD0F8, 0x5D11, 0xCDDF, 0x5D14, 0xF5CB, 0x5D16, 0xE4F0, + 0x5D17, 0xCBAB, 0x5D19, 0xD7C4, 0x5D27, 0xE2FE, 0x5D29, 0xDDDA, 0x5D4B, 0xDAAE, 0x5D4C, 0xCAEE, 0x5D50, 0xD5B9, 0x5D69, 0xE3A1, + 0x5D6C, 0xE8E3, 0x5D6F, 0xF3AB, 0x5D87, 0xCFA9, 0x5D8B, 0xD3F7, 0x5D9D, 0xD4F1, 0x5DA0, 0xCEE4, 0x5DA2, 0xE8F2, 0x5DAA, 0xE5F5, + 0x5DB8, 0xE7AE, 0x5DBA, 0xD6BA, 0x5DBC, 0xDFEC, 0x5DBD, 0xE4C0, 0x5DCD, 0xE8E4, 0x5DD2, 0xD8B5, 0x5DD6, 0xE4DC, 0x5DDD, 0xF4B9, + 0x5DDE, 0xF1B6, 0x5DE1, 0xE2DE, 0x5DE2, 0xE1B5, 0x5DE5, 0xCDEF, 0x5DE6, 0xF1A7, 0x5DE7, 0xCEE5, 0x5DE8, 0xCBDD, 0x5DEB, 0xD9E3, + 0x5DEE, 0xF3AC, 0x5DF1, 0xD0F9, 0x5DF2, 0xECAB, 0x5DF3, 0xDED3, 0x5DF4, 0xF7E9, 0x5DF7, 0xF9F5, 0x5DFD, 0xE1DE, 0x5DFE, 0xCBEE, + 0x5E02, 0xE3BC, 0x5E03, 0xF8D6, 0x5E06, 0xDBEE, 0x5E0C, 0xFDF1, 0x5E11, 0xF7B6, 0x5E16, 0xF4DE, 0x5E19, 0xF2ED, 0x5E1B, 0xDBD9, + 0x5E1D, 0xF0A8, 0x5E25, 0xE1FD, 0x5E2B, 0xDED4, 0x5E2D, 0xE0AC, 0x5E33, 0xEDE3, 0x5E36, 0xD3E1, 0x5E38, 0xDFC8, 0x5E3D, 0xD9B6, + 0x5E3F, 0xFDAC, 0x5E40, 0xEFD3, 0x5E44, 0xE4C1, 0x5E45, 0xF8EB, 0x5E47, 0xDBAC, 0x5E4C, 0xFCC6, 0x5E55, 0xD8AD, 0x5E5F, 0xF6BA, + 0x5E61, 0xDBDF, 0x5E62, 0xD3D3, 0x5E63, 0xF8C7, 0x5E72, 0xCACE, 0x5E73, 0xF8C1, 0x5E74, 0xD2B4, 0x5E77, 0xDCB4, 0x5E78, 0xFAB9, + 0x5E79, 0xCACF, 0x5E7B, 0xFCB3, 0x5E7C, 0xEAEA, 0x5E7D, 0xEAEB, 0x5E7E, 0xD0FA, 0x5E84, 0xEDE4, 0x5E87, 0xDDE7, 0x5E8A, 0xDFC9, + 0x5E8F, 0xDFED, 0x5E95, 0xEEBC, 0x5E97, 0xEFC1, 0x5E9A, 0xCCD2, 0x5E9C, 0xDDA4, 0x5EA0, 0xDFCA, 0x5EA6, 0xD3F8, 0x5EA7, 0xF1A8, + 0x5EAB, 0xCDB7, 0x5EAD, 0xEFD4, 0x5EB5, 0xE4DD, 0x5EB6, 0xDFEE, 0x5EB7, 0xCBAC, 0x5EB8, 0xE9BC, 0x5EBE, 0xEAEC, 0x5EC2, 0xDFCB, + 0x5EC8, 0xF9BF, 0x5EC9, 0xD6AF, 0x5ECA, 0xD5C6, 0x5ED0, 0xCFAA, 0x5ED3, 0xCEA9, 0x5ED6, 0xD6F8, 0x5EDA, 0xF1B7, 0x5EDB, 0xEEF8, + 0x5EDF, 0xD9D9, 0x5EE0, 0xF3DF, 0x5EE2, 0xF8C8, 0x5EE3, 0xCEC6, 0x5EEC, 0xD5E6, 0x5EF3, 0xF4E6, 0x5EF6, 0xE6C5, 0x5EF7, 0xEFD5, + 0x5EFA, 0xCBEF, 0x5EFB, 0xFCDF, 0x5F01, 0xDCA7, 0x5F04, 0xD6E7, 0x5F0A, 0xF8C9, 0x5F0F, 0xE3D2, 0x5F11, 0xE3BD, 0x5F13, 0xCFE1, + 0x5F14, 0xF0C0, 0x5F15, 0xECDA, 0x5F17, 0xDDD7, 0x5F18, 0xFBF0, 0x5F1B, 0xECAC, 0x5F1F, 0xF0A9, 0x5F26, 0xFAD7, 0x5F27, 0xFBC1, + 0x5F29, 0xD2C0, 0x5F31, 0xE5B0, 0x5F35, 0xEDE5, 0x5F3A, 0xCBAD, 0x5F3C, 0xF9B0, 0x5F48, 0xF7A5, 0x5F4A, 0xCBAE, 0x5F4C, 0xDAAF, + 0x5F4E, 0xD8B6, 0x5F56, 0xD3A7, 0x5F57, 0xFBB2, 0x5F59, 0xFDC4, 0x5F5B, 0xECAD, 0x5F62, 0xFBA1, 0x5F66, 0xE5E9, 0x5F67, 0xE9EE, + 0x5F69, 0xF3F4, 0x5F6A, 0xF8F3, 0x5F6B, 0xF0C1, 0x5F6C, 0xDEAF, 0x5F6D, 0xF8B0, 0x5F70, 0xF3E0, 0x5F71, 0xE7AF, 0x5F77, 0xDBAD, + 0x5F79, 0xE6B5, 0x5F7C, 0xF9A8, 0x5F7F, 0xDDD8, 0x5F80, 0xE8D9, 0x5F81, 0xEFD6, 0x5F85, 0xD3E2, 0x5F87, 0xE2DF, 0x5F8A, 0xFCE0, + 0x5F8B, 0xD7C8, 0x5F8C, 0xFDAD, 0x5F90, 0xDFEF, 0x5F91, 0xCCD3, 0x5F92, 0xD3F9, 0x5F97, 0xD4F0, 0x5F98, 0xDBC7, 0x5F99, 0xDED5, + 0x5F9E, 0xF0F4, 0x5FA0, 0xD5D0, 0x5FA1, 0xE5D9, 0x5FA8, 0xFCC7, 0x5FA9, 0xDCD6, 0x5FAA, 0xE2E0, 0x5FAE, 0xDAB0, 0x5FB5, 0xF3A3, + 0x5FB7, 0xD3EC, 0x5FB9, 0xF4CB, 0x5FBD, 0xFDC5, 0x5FC3, 0xE3FD, 0x5FC5, 0xF9B1, 0x5FCC, 0xD0FB, 0x5FCD, 0xECDB, 0x5FD6, 0xF5BC, + 0x5FD7, 0xF2A4, 0x5FD8, 0xD8CE, 0x5FD9, 0xD8CF, 0x5FE0, 0xF5F7, 0x5FEB, 0xF6E1, 0x5FF5, 0xD2B7, 0x5FFD, 0xFBEC, 0x5FFF, 0xDDC8, + 0x600F, 0xE4E8, 0x6012, 0xD2C1, 0x6016, 0xF8D7, 0x601C, 0xD6BB, 0x601D, 0xDED6, 0x6020, 0xF7BD, 0x6021, 0xECAE, 0x6025, 0xD0E1, + 0x6027, 0xE0F5, 0x6028, 0xEAB3, 0x602A, 0xCED6, 0x602F, 0xCCA5, 0x6041, 0xECF6, 0x6042, 0xE2E1, 0x6043, 0xE3BE, 0x604D, 0xFCC8, + 0x6050, 0xCDF0, 0x6052, 0xF9F6, 0x6055, 0xDFF0, 0x6059, 0xE5BF, 0x605D, 0xCEBF, 0x6062, 0xFCE1, 0x6063, 0xEDB0, 0x6064, 0xFDD1, + 0x6065, 0xF6BB, 0x6068, 0xF9CF, 0x6069, 0xEBDA, 0x606A, 0xCAC1, 0x606C, 0xD2B8, 0x606D, 0xCDF1, 0x606F, 0xE3D3, 0x6070, 0xFDE6, + 0x6085, 0xE6ED, 0x6089, 0xE3FA, 0x608C, 0xF0AA, 0x608D, 0xF9D0, 0x6094, 0xFCE2, 0x6096, 0xF8A7, 0x609A, 0xE1E5, 0x609B, 0xEEF9, + 0x609F, 0xE7F6, 0x60A0, 0xEAED, 0x60A3, 0xFCB4, 0x60A4, 0xF5C2, 0x60A7, 0xD7DC, 0x60B0, 0xF0F5, 0x60B2, 0xDDE8, 0x60B3, 0xD3ED, + 0x60B4, 0xF5FC, 0x60B6, 0xDABF, 0x60B8, 0xCCFB, 0x60BC, 0xD3FA, 0x60BD, 0xF4A4, 0x60C5, 0xEFD7, 0x60C7, 0xD4C3, 0x60D1, 0xFBE3, + 0x60DA, 0xFBED, 0x60DC, 0xE0AD, 0x60DF, 0xEAEE, 0x60E0, 0xFBB3, 0x60E1, 0xE4C2, 0x60F0, 0xF6E7, 0x60F1, 0xD2DD, 0x60F3, 0xDFCC, + 0x60F6, 0xFCC9, 0x60F9, 0xE5A9, 0x60FA, 0xE0F6, 0x60FB, 0xF6B3, 0x6101, 0xE1FE, 0x6106, 0xCBF0, 0x6108, 0xEAEF, 0x6109, 0xEAF0, + 0x610D, 0xDAC0, 0x610E, 0xF8B4, 0x610F, 0xEBF2, 0x6115, 0xE4C3, 0x611A, 0xE9D7, 0x611B, 0xE4F1, 0x611F, 0xCAEF, 0x6127, 0xCED7, + 0x6130, 0xFCCA, 0x6134, 0xF3E1, 0x6137, 0xCBC4, 0x613C, 0xE3E5, 0x613E, 0xCBC5, 0x613F, 0xEAB4, 0x6142, 0xE9BD, 0x6144, 0xD7C9, + 0x6147, 0xEBDB, 0x6148, 0xEDB1, 0x614A, 0xCCC3, 0x614B, 0xF7BE, 0x614C, 0xFCCB, 0x6153, 0xF8F4, 0x6155, 0xD9B7, 0x6158, 0xF3D3, + 0x6159, 0xF3D4, 0x615D, 0xF7E4, 0x615F, 0xF7D1, 0x6162, 0xD8B7, 0x6163, 0xCEB1, 0x6164, 0xCAC2, 0x6167, 0xFBB4, 0x6168, 0xCBC6, + 0x616B, 0xF0F6, 0x616E, 0xD5E7, 0x6170, 0xEAD0, 0x6176, 0xCCD4, 0x6177, 0xCBAF, 0x617D, 0xF4AA, 0x617E, 0xE9AF, 0x6181, 0xF5C3, + 0x6182, 0xE9D8, 0x618A, 0xDDE9, 0x618E, 0xF1F3, 0x6190, 0xD5FB, 0x6191, 0xDEBB, 0x6194, 0xF4FB, 0x6198, 0xFDF3, 0x6199, 0xFDF2, + 0x619A, 0xF7A6, 0x61A4, 0xDDC9, 0x61A7, 0xD4D3, 0x61A9, 0xCCA8, 0x61AB, 0xDAC1, 0x61AC, 0xCCD5, 0x61AE, 0xD9E4, 0x61B2, 0xFACA, + 0x61B6, 0xE5E3, 0x61BA, 0xD3BC, 0x61BE, 0xCAF0, 0x61C3, 0xD0C4, 0x61C7, 0xCAD0, 0x61C8, 0xFAAB, 0x61C9, 0xEBEB, 0x61CA, 0xE7F8, + 0x61CB, 0xD9E5, 0x61E6, 0xD1D7, 0x61F2, 0xF3A4, 0x61F6, 0xD4FB, 0x61F7, 0xFCE3, 0x61F8, 0xFAD8, 0x61FA, 0xF3D5, 0x61FC, 0xCFAB, + 0x61FF, 0xEBF3, 0x6200, 0xD5FC, 0x6207, 0xD3D4, 0x6208, 0xCDFC, 0x620A, 0xD9E6, 0x620C, 0xE2F9, 0x620D, 0xE2A1, 0x620E, 0xEBD4, + 0x6210, 0xE0F7, 0x6211, 0xE4B2, 0x6212, 0xCCFC, 0x6216, 0xFBE4, 0x621A, 0xF4AB, 0x621F, 0xD0BD, 0x6221, 0xCAF1, 0x622A, 0xEFB8, + 0x622E, 0xD7C0, 0x6230, 0xEEFA, 0x6231, 0xFDF4, 0x6234, 0xD3E3, 0x6236, 0xFBC2, 0x623E, 0xD5E8, 0x623F, 0xDBAE, 0x6240, 0xE1B6, + 0x6241, 0xF8B7, 0x6247, 0xE0BF, 0x6248, 0xFBC3, 0x6249, 0xDDEA, 0x624B, 0xE2A2, 0x624D, 0xEEA6, 0x6253, 0xF6E8, 0x6258, 0xF6F5, + 0x626E, 0xDDCA, 0x6271, 0xD0E2, 0x6276, 0xDDA6, 0x6279, 0xDDEB, 0x627C, 0xE4F9, 0x627F, 0xE3AF, 0x6280, 0xD0FC, 0x6284, 0xF4FC, + 0x6289, 0xCCBC, 0x628A, 0xF7EA, 0x6291, 0xE5E4, 0x6292, 0xDFF1, 0x6295, 0xF7E1, 0x6297, 0xF9F7, 0x6298, 0xEFB9, 0x629B, 0xF8D8, + 0x62AB, 0xF9A9, 0x62B1, 0xF8D9, 0x62B5, 0xEEBD, 0x62B9, 0xD8C6, 0x62BC, 0xE4E3, 0x62BD, 0xF5CE, 0x62C2, 0xDDD9, 0x62C7, 0xD9E7, + 0x62C8, 0xD2B9, 0x62C9, 0xD5C3, 0x62CC, 0xDAE5, 0x62CD, 0xDAD0, 0x62CF, 0xD1D9, 0x62D0, 0xCED8, 0x62D2, 0xCBDE, 0x62D3, 0xF4AC, + 0x62D4, 0xDAFB, 0x62D6, 0xF6E9, 0x62D7, 0xE8F3, 0x62D8, 0xCFAC, 0x62D9, 0xF0F0, 0x62DB, 0xF4FD, 0x62DC, 0xDBC8, 0x62EC, 0xCEC0, + 0x62ED, 0xE3D4, 0x62EE, 0xD1CF, 0x62EF, 0xF1F5, 0x62F1, 0xCDF2, 0x62F3, 0xCFEB, 0x62F7, 0xCDB8, 0x62FE, 0xE3A6, 0x62FF, 0xD1DA, + 0x6301, 0xF2A5, 0x6307, 0xF2A6, 0x6309, 0xE4CE, 0x6311, 0xD3FB, 0x632B, 0xF1A9, 0x632F, 0xF2C9, 0x633A, 0xEFD8, 0x633B, 0xE6C9, + 0x633D, 0xD8B8, 0x633E, 0xFAF3, 0x6349, 0xF3B5, 0x634C, 0xF8A4, 0x634F, 0xD1F3, 0x6350, 0xE6C8, 0x6355, 0xF8DA, 0x6367, 0xDCE9, + 0x6368, 0xDED7, 0x636E, 0xCBDF, 0x6372, 0xCFEC, 0x6377, 0xF4DF, 0x637A, 0xD1F4, 0x637B, 0xD2BA, 0x637F, 0xDFF2, 0x6383, 0xE1B7, + 0x6388, 0xE2A3, 0x6389, 0xD3FC, 0x638C, 0xEDE6, 0x6392, 0xDBC9, 0x6396, 0xE4FA, 0x6398, 0xCFDE, 0x639B, 0xCED0, 0x63A0, 0xD5D3, + 0x63A1, 0xF3F5, 0x63A2, 0xF7AE, 0x63A5, 0xEFC8, 0x63A7, 0xCDF3, 0x63A8, 0xF5CF, 0x63A9, 0xE5F3, 0x63AA, 0xF0C2, 0x63C0, 0xCAD1, + 0x63C4, 0xEAF1, 0x63C6, 0xD0A6, 0x63CF, 0xD9DA, 0x63D0, 0xF0AB, 0x63D6, 0xEBE7, 0x63DA, 0xE5C0, 0x63DB, 0xFCB5, 0x63E1, 0xE4C4, + 0x63ED, 0xCCA9, 0x63EE, 0xFDC6, 0x63F4, 0xEAB5, 0x63F6, 0xE5AA, 0x63F7, 0xDFBA, 0x640D, 0xE1DF, 0x640F, 0xDAD1, 0x6414, 0xE1B8, + 0x6416, 0xE8F4, 0x6417, 0xD3FD, 0x641C, 0xE2A4, 0x6422, 0xF2CA, 0x642C, 0xDAE6, 0x642D, 0xF7B3, 0x643A, 0xFDCD, 0x643E, 0xF3B6, + 0x6458, 0xEED7, 0x6460, 0xF5C4, 0x6469, 0xD8A4, 0x646F, 0xF2A7, 0x6478, 0xD9B8, 0x6479, 0xD9B9, 0x647A, 0xEFC9, 0x6488, 0xD6CE, + 0x6491, 0xF7CB, 0x6492, 0xDFAE, 0x6493, 0xE8F5, 0x649A, 0xD2B5, 0x649E, 0xD3D5, 0x64A4, 0xF4CC, 0x64A5, 0xDAFC, 0x64AB, 0xD9E8, + 0x64AD, 0xF7EB, 0x64AE, 0xF5C9, 0x64B0, 0xF3BC, 0x64B2, 0xDAD2, 0x64BB, 0xD3B5, 0x64C1, 0xE8B6, 0x64C4, 0xD6CF, 0x64C5, 0xF4BA, + 0x64C7, 0xF7C9, 0x64CA, 0xCCAA, 0x64CD, 0xF0C3, 0x64CE, 0xCCD6, 0x64D2, 0xD0D3, 0x64D4, 0xD3BD, 0x64D8, 0xDBFB, 0x64DA, 0xCBE0, + 0x64E1, 0xD3E4, 0x64E2, 0xF6F7, 0x64E5, 0xD5BA, 0x64E6, 0xF3CD, 0x64E7, 0xCBE1, 0x64EC, 0xEBF4, 0x64F2, 0xF4AD, 0x64F4, 0xFCAA, + 0x64FA, 0xF7EC, 0x64FE, 0xE8F6, 0x6500, 0xDAE7, 0x6504, 0xF7CC, 0x6518, 0xE5C1, 0x651D, 0xE0EE, 0x6523, 0xD5FD, 0x652A, 0xCEE6, + 0x652B, 0xFCAB, 0x652C, 0xD5BB, 0x652F, 0xF2A8, 0x6536, 0xE2A5, 0x6537, 0xCDB9, 0x6538, 0xEAF2, 0x6539, 0xCBC7, 0x653B, 0xCDF4, + 0x653E, 0xDBAF, 0x653F, 0xEFD9, 0x6545, 0xCDBA, 0x6548, 0xFCF9, 0x654D, 0xDFF3, 0x654E, 0xCEE7, 0x654F, 0xDAC2, 0x6551, 0xCFAD, + 0x6556, 0xE7F9, 0x6557, 0xF8A8, 0x655E, 0xF3E2, 0x6562, 0xCAF2, 0x6563, 0xDFA4, 0x6566, 0xD4C4, 0x656C, 0xCCD7, 0x656D, 0xE5C2, + 0x6572, 0xCDBB, 0x6574, 0xEFDA, 0x6575, 0xEED8, 0x6577, 0xDDA7, 0x6578, 0xE2A6, 0x657E, 0xE0C0, 0x6582, 0xD6B0, 0x6583, 0xF8CA, + 0x6585, 0xFCFA, 0x6587, 0xD9FE, 0x658C, 0xDEB0, 0x6590, 0xDDEC, 0x6591, 0xDAE8, 0x6597, 0xD4E0, 0x6599, 0xD6F9, 0x659B, 0xCDD7, + 0x659C, 0xDED8, 0x659F, 0xF2F8, 0x65A1, 0xE4D6, 0x65A4, 0xD0C5, 0x65A5, 0xF4AE, 0x65A7, 0xDDA8, 0x65AB, 0xEDC5, 0x65AC, 0xF3D6, + 0x65AF, 0xDED9, 0x65B0, 0xE3E6, 0x65B7, 0xD3A8, 0x65B9, 0xDBB0, 0x65BC, 0xE5DA, 0x65BD, 0xE3BF, 0x65C1, 0xDBB1, 0x65C5, 0xD5E9, + 0x65CB, 0xE0C1, 0x65CC, 0xEFDB, 0x65CF, 0xF0E9, 0x65D2, 0xD7B2, 0x65D7, 0xD0FD, 0x65E0, 0xD9E9, 0x65E3, 0xD0FE, 0x65E5, 0xECED, + 0x65E6, 0xD3A9, 0x65E8, 0xF2A9, 0x65E9, 0xF0C4, 0x65EC, 0xE2E2, 0x65ED, 0xE9EF, 0x65F1, 0xF9D1, 0x65F4, 0xE9D9, 0x65FA, 0xE8DA, + 0x65FB, 0xDAC3, 0x65FC, 0xDAC4, 0x65FD, 0xD4C5, 0x65FF, 0xE7FA, 0x6606, 0xCDE0, 0x6607, 0xE3B0, 0x6609, 0xDBB2, 0x660A, 0xFBC4, + 0x660C, 0xF3E3, 0x660E, 0xD9A5, 0x660F, 0xFBE7, 0x6610, 0xDDCB, 0x6611, 0xD0D4, 0x6613, 0xE6B6, 0x6614, 0xE0AE, 0x6615, 0xFDDA, + 0x661E, 0xDCB5, 0x661F, 0xE0F8, 0x6620, 0xE7B1, 0x6625, 0xF5F0, 0x6627, 0xD8DC, 0x6628, 0xEDC6, 0x662D, 0xE1B9, 0x662F, 0xE3C0, + 0x6630, 0xF9C0, 0x6631, 0xE9F0, 0x6634, 0xD9DB, 0x6636, 0xF3E4, 0x663A, 0xDCB6, 0x663B, 0xE4E9, 0x6641, 0xF0C5, 0x6642, 0xE3C1, + 0x6643, 0xFCCC, 0x6644, 0xFCCD, 0x6649, 0xF2CB, 0x664B, 0xF2CC, 0x664F, 0xE4CF, 0x6659, 0xF1DB, 0x665B, 0xFAD9, 0x665D, 0xF1B8, + 0x665E, 0xFDF5, 0x665F, 0xE0F9, 0x6664, 0xE7FB, 0x6665, 0xFCB7, 0x6666, 0xFCE4, 0x6667, 0xFBC5, 0x6668, 0xE3E7, 0x6669, 0xD8B9, + 0x666B, 0xF6F8, 0x666E, 0xDCC5, 0x666F, 0xCCD8, 0x6673, 0xE0AF, 0x6674, 0xF4E7, 0x6676, 0xEFDC, 0x6677, 0xCFFC, 0x6678, 0xEFDD, + 0x667A, 0xF2AA, 0x6684, 0xFDBE, 0x6687, 0xCAAC, 0x6688, 0xFDBB, 0x6689, 0xFDC7, 0x668E, 0xE7B2, 0x6690, 0xEAD1, 0x6691, 0xDFF4, + 0x6696, 0xD1EC, 0x6697, 0xE4DE, 0x6698, 0xE5C3, 0x669D, 0xD9A6, 0x66A0, 0xCDBC, 0x66A2, 0xF3E5, 0x66AB, 0xEDD5, 0x66AE, 0xD9BA, + 0x66B2, 0xEDE7, 0x66B3, 0xFBB5, 0x66B4, 0xF8EC, 0x66B9, 0xE0E7, 0x66BB, 0xCCD9, 0x66BE, 0xD4C6, 0x66C4, 0xE7A5, 0x66C6, 0xD5F5, + 0x66C7, 0xD3BE, 0x66C9, 0xFCFB, 0x66D6, 0xE4F2, 0x66D9, 0xDFF5, 0x66DC, 0xE8F8, 0x66DD, 0xF8ED, 0x66E0, 0xCEC7, 0x66E6, 0xFDF6, + 0x66F0, 0xE8D8, 0x66F2, 0xCDD8, 0x66F3, 0xE7D6, 0x66F4, 0xCCDA, 0x66F7, 0xCAE3, 0x66F8, 0xDFF6, 0x66F9, 0xF0C7, 0x66FA, 0xF0C6, + 0x66FC, 0xD8BA, 0x66FE, 0xF1F4, 0x66FF, 0xF4F0, 0x6700, 0xF5CC, 0x6703, 0xFCE5, 0x6708, 0xEAC5, 0x6709, 0xEAF3, 0x670B, 0xDDDB, + 0x670D, 0xDCD7, 0x6714, 0xDEFD, 0x6715, 0xF2F9, 0x6717, 0xD5C7, 0x671B, 0xD8D0, 0x671D, 0xF0C8, 0x671E, 0xD1A1, 0x671F, 0xD1A2, + 0x6726, 0xD9D4, 0x6727, 0xD6E8, 0x6728, 0xD9CA, 0x672A, 0xDAB1, 0x672B, 0xD8C7, 0x672C, 0xDCE2, 0x672D, 0xF3CE, 0x672E, 0xF5F4, + 0x6731, 0xF1B9, 0x6734, 0xDAD3, 0x6736, 0xF6EA, 0x673A, 0xCFF5, 0x673D, 0xFDAE, 0x6746, 0xCAD2, 0x6749, 0xDFB4, 0x674E, 0xD7DD, + 0x674F, 0xFABA, 0x6750, 0xEEA7, 0x6751, 0xF5BD, 0x6753, 0xF8F5, 0x6756, 0xEDE8, 0x675C, 0xD4E1, 0x675E, 0xD1A3, 0x675F, 0xE1D6, + 0x676D, 0xF9F8, 0x676F, 0xDBCA, 0x6770, 0xCBF9, 0x6771, 0xD4D4, 0x6773, 0xD9DC, 0x6775, 0xEEBE, 0x6777, 0xF7ED, 0x677B, 0xD2EE, + 0x677E, 0xE1E6, 0x677F, 0xF7F9, 0x6787, 0xDDED, 0x6789, 0xE8DB, 0x678B, 0xDBB3, 0x678F, 0xD1F7, 0x6790, 0xE0B0, 0x6793, 0xD4E2, + 0x6795, 0xF6D7, 0x6797, 0xD7F9, 0x679A, 0xD8DD, 0x679C, 0xCDFD, 0x679D, 0xF2AB, 0x67AF, 0xCDBD, 0x67B0, 0xF8C2, 0x67B3, 0xF2AC, + 0x67B6, 0xCAAD, 0x67B7, 0xCAAE, 0x67B8, 0xCFAE, 0x67BE, 0xE3C2, 0x67C4, 0xDCB7, 0x67CF, 0xDBDA, 0x67D0, 0xD9BB, 0x67D1, 0xCAF3, + 0x67D2, 0xF6D3, 0x67D3, 0xE6F8, 0x67D4, 0xEAF5, 0x67DA, 0xEAF6, 0x67DD, 0xF6F9, 0x67E9, 0xCFAF, 0x67EC, 0xCAD3, 0x67EF, 0xCAAF, + 0x67F0, 0xD2B0, 0x67F1, 0xF1BA, 0x67F3, 0xD7B3, 0x67F4, 0xE3C3, 0x67F5, 0xF3FD, 0x67F6, 0xDEDA, 0x67FB, 0xDEDB, 0x67FE, 0xEFDE, + 0x6812, 0xE2E3, 0x6813, 0xEEFB, 0x6816, 0xDFF7, 0x6817, 0xD7CA, 0x6821, 0xCEE8, 0x6822, 0xDBDB, 0x682A, 0xF1BB, 0x682F, 0xE9F1, + 0x6838, 0xFAB7, 0x6839, 0xD0C6, 0x683C, 0xCCAB, 0x683D, 0xEEA8, 0x6840, 0xCBFA, 0x6841, 0xF9F9, 0x6842, 0xCCFD, 0x6843, 0xD3FE, + 0x6848, 0xE4D0, 0x684E, 0xF2EE, 0x6850, 0xD4D5, 0x6851, 0xDFCD, 0x6853, 0xFCB8, 0x6854, 0xD1D0, 0x686D, 0xF2CD, 0x6876, 0xF7D2, + 0x687F, 0xCAD4, 0x6881, 0xD5D9, 0x6885, 0xD8DE, 0x688F, 0xCDD9, 0x6893, 0xEEA9, 0x6894, 0xF6BC, 0x6897, 0xCCDB, 0x689D, 0xF0C9, + 0x689F, 0xFCFC, 0x68A1, 0xE8C9, 0x68A2, 0xF4FE, 0x68A7, 0xE7FC, 0x68A8, 0xD7DE, 0x68AD, 0xDEDC, 0x68AF, 0xF0AC, 0x68B0, 0xCCFE, + 0x68B1, 0xCDE1, 0x68B3, 0xE1BA, 0x68B5, 0xDBEF, 0x68B6, 0xDAB2, 0x68C4, 0xD1A5, 0x68C5, 0xDCB8, 0x68C9, 0xD8F6, 0x68CB, 0xD1A4, + 0x68CD, 0xCDE2, 0x68D2, 0xDCEA, 0x68D5, 0xF0F7, 0x68D7, 0xF0CA, 0x68D8, 0xD0BE, 0x68DA, 0xDDDC, 0x68DF, 0xD4D6, 0x68E0, 0xD3D6, + 0x68E7, 0xEDD0, 0x68E8, 0xCDA1, 0x68EE, 0xDFB5, 0x68F2, 0xDFF8, 0x68F9, 0xD4A1, 0x68FA, 0xCEB2, 0x6900, 0xE8CA, 0x6905, 0xEBF5, + 0x690D, 0xE3D5, 0x690E, 0xF5D0, 0x6912, 0xF5A1, 0x6927, 0xD9A7, 0x6930, 0xE5AB, 0x693D, 0xE6CB, 0x693F, 0xF5F1, 0x694A, 0xE5C5, + 0x6953, 0xF9A3, 0x6954, 0xE0DB, 0x6955, 0xF6EB, 0x6957, 0xCBF1, 0x6959, 0xD9EA, 0x695A, 0xF5A2, 0x695E, 0xD7D1, 0x6960, 0xD1F8, + 0x6961, 0xEAF8, 0x6962, 0xEAF9, 0x6963, 0xDAB3, 0x6968, 0xEFDF, 0x696B, 0xF1EF, 0x696D, 0xE5F6, 0x696E, 0xEEBF, 0x696F, 0xE2E4, + 0x6975, 0xD0BF, 0x6977, 0xFAAC, 0x6978, 0xF5D1, 0x6979, 0xE7B3, 0x6995, 0xE9BE, 0x699B, 0xF2CE, 0x699C, 0xDBB4, 0x69A5, 0xFCCE, + 0x69A7, 0xDDEE, 0x69AE, 0xE7B4, 0x69B4, 0xD7B4, 0x69BB, 0xF7B4, 0x69C1, 0xCDBE, 0x69C3, 0xDAE9, 0x69CB, 0xCFB0, 0x69CC, 0xF7D9, + 0x69CD, 0xF3E6, 0x69D0, 0xCED9, 0x69E8, 0xCEAA, 0x69EA, 0xCBC8, 0x69FB, 0xD0A7, 0x69FD, 0xF0CB, 0x69FF, 0xD0C7, 0x6A02, 0xE4C5, + 0x6A0A, 0xDBE0, 0x6A11, 0xD5DA, 0x6A13, 0xD7A7, 0x6A17, 0xEEC0, 0x6A19, 0xF8F6, 0x6A1E, 0xF5D2, 0x6A1F, 0xEDE9, 0x6A21, 0xD9BC, + 0x6A23, 0xE5C6, 0x6A35, 0xF5A3, 0x6A38, 0xDAD4, 0x6A39, 0xE2A7, 0x6A3A, 0xFBFC, 0x6A3D, 0xF1DC, 0x6A44, 0xCAF4, 0x6A48, 0xE8FA, + 0x6A4B, 0xCEE9, 0x6A52, 0xE9F8, 0x6A53, 0xE2E5, 0x6A58, 0xD0B9, 0x6A59, 0xD4F2, 0x6A5F, 0xD1A6, 0x6A61, 0xDFCE, 0x6A6B, 0xFCF4, + 0x6A80, 0xD3AA, 0x6A84, 0xCCAC, 0x6A89, 0xEFE0, 0x6A8D, 0xE5E5, 0x6A8E, 0xD0D5, 0x6A97, 0xDBFC, 0x6A9C, 0xFCE6, 0x6AA2, 0xCBFE, + 0x6AA3, 0xEDEA, 0x6AB3, 0xDEB1, 0x6ABB, 0xF9E3, 0x6AC2, 0xD4A2, 0x6AC3, 0xCFF6, 0x6AD3, 0xD6D0, 0x6ADA, 0xD5EA, 0x6ADB, 0xF1EE, + 0x6AF6, 0xFACB, 0x6AFB, 0xE5A1, 0x6B04, 0xD5B1, 0x6B0A, 0xCFED, 0x6B0C, 0xEDEB, 0x6B12, 0xD5B2, 0x6B16, 0xD5BC, 0x6B20, 0xFDE2, + 0x6B21, 0xF3AD, 0x6B23, 0xFDDB, 0x6B32, 0xE9B0, 0x6B3A, 0xD1A7, 0x6B3D, 0xFDE3, 0x6B3E, 0xCEB3, 0x6B46, 0xFDE4, 0x6B47, 0xFACE, + 0x6B4C, 0xCAB0, 0x6B4E, 0xF7A7, 0x6B50, 0xCFB1, 0x6B5F, 0xE6A2, 0x6B61, 0xFCB6, 0x6B62, 0xF2AD, 0x6B63, 0xEFE1, 0x6B64, 0xF3AE, + 0x6B65, 0xDCC6, 0x6B66, 0xD9EB, 0x6B6A, 0xE8E0, 0x6B72, 0xE1A8, 0x6B77, 0xD5F6, 0x6B78, 0xCFFD, 0x6B7B, 0xDEDD, 0x6B7F, 0xD9D1, + 0x6B83, 0xE4EA, 0x6B84, 0xF2CF, 0x6B86, 0xF7BF, 0x6B89, 0xE2E6, 0x6B8A, 0xE2A8, 0x6B96, 0xE3D6, 0x6B98, 0xEDD1, 0x6B9E, 0xE9F9, + 0x6BAE, 0xD6B1, 0x6BAF, 0xDEB2, 0x6BB2, 0xE0E8, 0x6BB5, 0xD3AB, 0x6BB7, 0xEBDC, 0x6BBA, 0xDFAF, 0x6BBC, 0xCAC3, 0x6BBF, 0xEEFC, + 0x6BC1, 0xFDC3, 0x6BC5, 0xEBF6, 0x6BC6, 0xCFB2, 0x6BCB, 0xD9EC, 0x6BCD, 0xD9BD, 0x6BCF, 0xD8DF, 0x6BD2, 0xD4B8, 0x6BD3, 0xEBBE, + 0x6BD4, 0xDDEF, 0x6BD6, 0xDDF0, 0x6BD7, 0xDDF1, 0x6BD8, 0xDDF2, 0x6BDB, 0xD9BE, 0x6BEB, 0xFBC6, 0x6BEC, 0xCFB3, 0x6C08, 0xEEFD, + 0x6C0F, 0xE4AB, 0x6C11, 0xDAC5, 0x6C13, 0xD8EC, 0x6C23, 0xD1A8, 0x6C34, 0xE2A9, 0x6C37, 0xDEBC, 0x6C38, 0xE7B5, 0x6C3E, 0xDBF0, + 0x6C40, 0xEFE2, 0x6C41, 0xF1F0, 0x6C42, 0xCFB4, 0x6C4E, 0xDBF1, 0x6C50, 0xE0B1, 0x6C55, 0xDFA5, 0x6C57, 0xF9D2, 0x6C5A, 0xE7FD, + 0x6C5D, 0xE6A3, 0x6C5E, 0xFBF1, 0x6C5F, 0xCBB0, 0x6C60, 0xF2AE, 0x6C68, 0xCDE7, 0x6C6A, 0xE8DC, 0x6C6D, 0xE7D7, 0x6C70, 0xF7C0, + 0x6C72, 0xD0E3, 0x6C76, 0xDAA1, 0x6C7A, 0xCCBD, 0x6C7D, 0xD1A9, 0x6C7E, 0xDDCC, 0x6C81, 0xE3FE, 0x6C82, 0xD1AA, 0x6C83, 0xE8AA, + 0x6C85, 0xEAB6, 0x6C86, 0xF9FA, 0x6C87, 0xE6CC, 0x6C88, 0xF6D8, 0x6C8C, 0xD4C7, 0x6C90, 0xD9CB, 0x6C92, 0xD9D2, 0x6C93, 0xD3CB, + 0x6C94, 0xD8F7, 0x6C95, 0xDAA9, 0x6C96, 0xF5F8, 0x6C99, 0xDEDE, 0x6C9A, 0xF2AF, 0x6C9B, 0xF8A9, 0x6CAB, 0xD8C8, 0x6CAE, 0xEEC1, + 0x6CB3, 0xF9C1, 0x6CB8, 0xDDF3, 0x6CB9, 0xEAFA, 0x6CBB, 0xF6BD, 0x6CBC, 0xE1BB, 0x6CBD, 0xCDBF, 0x6CBE, 0xF4D4, 0x6CBF, 0xE6CD, + 0x6CC1, 0xFCCF, 0x6CC2, 0xFBA2, 0x6CC4, 0xE0DC, 0x6CC9, 0xF4BB, 0x6CCA, 0xDAD5, 0x6CCC, 0xF9B2, 0x6CD3, 0xFBF2, 0x6CD5, 0xDBF6, + 0x6CD7, 0xDEDF, 0x6CDB, 0xDBF2, 0x6CE1, 0xF8DC, 0x6CE2, 0xF7EE, 0x6CE3, 0xEBE8, 0x6CE5, 0xD2FA, 0x6CE8, 0xF1BC, 0x6CEB, 0xFADA, + 0x6CEE, 0xDAEA, 0x6CEF, 0xDAC6, 0x6CF0, 0xF7C1, 0x6CF3, 0xE7B6, 0x6D0B, 0xE5C7, 0x6D0C, 0xD6AC, 0x6D11, 0xDCC7, 0x6D17, 0xE1A9, + 0x6D19, 0xE2AA, 0x6D1B, 0xD5A6, 0x6D1E, 0xD4D7, 0x6D25, 0xF2D0, 0x6D27, 0xEAFB, 0x6D29, 0xE0DD, 0x6D2A, 0xFBF3, 0x6D32, 0xF1BD, + 0x6D35, 0xE2E7, 0x6D36, 0xFDD7, 0x6D38, 0xCEC8, 0x6D39, 0xEAB7, 0x6D3B, 0xFCC0, 0x6D3D, 0xFDE7, 0x6D3E, 0xF7EF, 0x6D41, 0xD7B5, + 0x6D59, 0xEFBA, 0x6D5A, 0xF1DD, 0x6D5C, 0xDEB3, 0x6D63, 0xE8CB, 0x6D66, 0xF8DD, 0x6D69, 0xFBC7, 0x6D6A, 0xD5C8, 0x6D6C, 0xD7DF, + 0x6D6E, 0xDDA9, 0x6D74, 0xE9B1, 0x6D77, 0xFAAD, 0x6D78, 0xF6D9, 0x6D79, 0xFAF4, 0x6D7F, 0xF8AA, 0x6D85, 0xE6EE, 0x6D87, 0xCCDC, + 0x6D88, 0xE1BC, 0x6D89, 0xE0EF, 0x6D8C, 0xE9BF, 0x6D8D, 0xFCFD, 0x6D8E, 0xE6CE, 0x6D91, 0xE1D7, 0x6D93, 0xE6CF, 0x6D95, 0xF4F1, + 0x6DAF, 0xE4F3, 0x6DB2, 0xE4FB, 0x6DB5, 0xF9E4, 0x6DC0, 0xEFE3, 0x6DC3, 0xCFEE, 0x6DC4, 0xF6BE, 0x6DC5, 0xE0B2, 0x6DC6, 0xFCFE, + 0x6DC7, 0xD1AB, 0x6DCB, 0xD7FA, 0x6DCF, 0xFBC8, 0x6DD1, 0xE2D7, 0x6DD8, 0xD4A3, 0x6DD9, 0xF0F8, 0x6DDA, 0xD7A8, 0x6DDE, 0xE1E7, + 0x6DE1, 0xD3BF, 0x6DE8, 0xEFE4, 0x6DEA, 0xD7C5, 0x6DEB, 0xEBE2, 0x6DEE, 0xFCE7, 0x6DF1, 0xE4A2, 0x6DF3, 0xE2E8, 0x6DF5, 0xE6D0, + 0x6DF7, 0xFBE8, 0x6DF8, 0xF4E8, 0x6DF9, 0xE5F4, 0x6DFA, 0xF4BC, 0x6DFB, 0xF4D5, 0x6E17, 0xDFB6, 0x6E19, 0xFCB9, 0x6E1A, 0xEEC2, + 0x6E1B, 0xCAF5, 0x6E1F, 0xEFE5, 0x6E20, 0xCBE2, 0x6E21, 0xD4A4, 0x6E23, 0xDEE0, 0x6E24, 0xDAFD, 0x6E25, 0xE4C6, 0x6E26, 0xE8BE, + 0x6E2B, 0xE0DE, 0x6E2C, 0xF6B4, 0x6E2D, 0xEAD2, 0x6E2F, 0xF9FB, 0x6E32, 0xE0C2, 0x6E34, 0xCAE4, 0x6E36, 0xE7B7, 0x6E38, 0xEAFD, + 0x6E3A, 0xD9DD, 0x6E3C, 0xDAB4, 0x6E3D, 0xEEAA, 0x6E3E, 0xFBE9, 0x6E43, 0xDBCB, 0x6E44, 0xDAB5, 0x6E4A, 0xF1BE, 0x6E4D, 0xD3AC, + 0x6E56, 0xFBC9, 0x6E58, 0xDFCF, 0x6E5B, 0xD3C0, 0x6E5C, 0xE3D7, 0x6E5E, 0xEFE6, 0x6E5F, 0xFCD0, 0x6E67, 0xE9C0, 0x6E6B, 0xF5D3, + 0x6E6E, 0xECDC, 0x6E6F, 0xF7B7, 0x6E72, 0xEAB8, 0x6E73, 0xD1F9, 0x6E7A, 0xDCC8, 0x6E90, 0xEAB9, 0x6E96, 0xF1DE, 0x6E9C, 0xD7B6, + 0x6E9D, 0xCFB5, 0x6E9F, 0xD9A8, 0x6EA2, 0xECEE, 0x6EA5, 0xDDAA, 0x6EAA, 0xCDA2, 0x6EAB, 0xE8AE, 0x6EAF, 0xE1BD, 0x6EB1, 0xF2D1, + 0x6EB6, 0xE9C1, 0x6EBA, 0xD2FC, 0x6EC2, 0xDBB5, 0x6EC4, 0xF3E7, 0x6EC5, 0xD8FE, 0x6EC9, 0xFCD1, 0x6ECB, 0xEDB2, 0x6ECC, 0xF4AF, + 0x6ECE, 0xFBA3, 0x6ED1, 0xFCC1, 0x6ED3, 0xEEAB, 0x6ED4, 0xD4A5, 0x6EEF, 0xF4F2, 0x6EF4, 0xEED9, 0x6EF8, 0xFBCA, 0x6EFE, 0xCDE3, + 0x6EFF, 0xD8BB, 0x6F01, 0xE5DB, 0x6F02, 0xF8F7, 0x6F06, 0xF6D4, 0x6F0F, 0xD7A9, 0x6F11, 0xCBC9, 0x6F14, 0xE6D1, 0x6F15, 0xF0CC, + 0x6F20, 0xD8AE, 0x6F22, 0xF9D3, 0x6F23, 0xD5FE, 0x6F2B, 0xD8BC, 0x6F2C, 0xF2B0, 0x6F31, 0xE2AB, 0x6F32, 0xF3E8, 0x6F38, 0xEFC2, + 0x6F3F, 0xEDEC, 0x6F41, 0xE7B8, 0x6F51, 0xDAFE, 0x6F54, 0xCCBE, 0x6F57, 0xF2FC, 0x6F58, 0xDAEB, 0x6F5A, 0xE2D8, 0x6F5B, 0xEDD6, + 0x6F5E, 0xD6D1, 0x6F5F, 0xE0B3, 0x6F62, 0xFCD2, 0x6F64, 0xEBC8, 0x6F6D, 0xD3C1, 0x6F6E, 0xF0CD, 0x6F70, 0xCFF7, 0x6F7A, 0xEDD2, + 0x6F7C, 0xD4D8, 0x6F7D, 0xDCC9, 0x6F7E, 0xD7F1, 0x6F81, 0xDFBB, 0x6F84, 0xF3A5, 0x6F88, 0xF4CD, 0x6F8D, 0xF1BF, 0x6F8E, 0xF8B1, + 0x6F90, 0xE9FA, 0x6F94, 0xFBCB, 0x6F97, 0xCAD5, 0x6FA3, 0xF9D4, 0x6FA4, 0xF7CA, 0x6FA7, 0xD6C8, 0x6FAE, 0xFCE8, 0x6FAF, 0xF3BD, + 0x6FB1, 0xEEFE, 0x6FB3, 0xE7FE, 0x6FB9, 0xD3C2, 0x6FBE, 0xD3B6, 0x6FC0, 0xCCAD, 0x6FC1, 0xF6FA, 0x6FC2, 0xD6B2, 0x6FC3, 0xD2D8, + 0x6FCA, 0xE7D8, 0x6FD5, 0xE3A5, 0x6FDA, 0xE7B9, 0x6FDF, 0xF0AD, 0x6FE0, 0xFBCC, 0x6FE1, 0xEBA1, 0x6FE4, 0xD4A6, 0x6FE9, 0xFBCD, + 0x6FEB, 0xD5BD, 0x6FEC, 0xF1DF, 0x6FEF, 0xF6FB, 0x6FF1, 0xDEB4, 0x6FFE, 0xD5EB, 0x7001, 0xE5C8, 0x7005, 0xFBA4, 0x7006, 0xD4B9, + 0x7009, 0xDEE1, 0x700B, 0xE4A3, 0x700F, 0xD7B7, 0x7011, 0xF8EE, 0x7015, 0xDEB5, 0x7018, 0xD6D2, 0x701A, 0xF9D5, 0x701B, 0xE7BA, + 0x701C, 0xEBD5, 0x701D, 0xD5F7, 0x701E, 0xEFE7, 0x701F, 0xE1BE, 0x7023, 0xFAAE, 0x7027, 0xD6E9, 0x7028, 0xD6EE, 0x702F, 0xE7BB, + 0x7037, 0xECCB, 0x703E, 0xD5B3, 0x704C, 0xCEB4, 0x7050, 0xFBA5, 0x7051, 0xE1EE, 0x7058, 0xF7A8, 0x705D, 0xFBCE, 0x7063, 0xD8BD, + 0x706B, 0xFBFD, 0x7070, 0xFCE9, 0x7078, 0xCFB6, 0x707C, 0xEDC7, 0x707D, 0xEEAC, 0x7085, 0xCCDD, 0x708A, 0xF6A7, 0x708E, 0xE6FA, + 0x7092, 0xF5A4, 0x7098, 0xFDDC, 0x7099, 0xEDB3, 0x709A, 0xCEC9, 0x70A1, 0xEFE8, 0x70A4, 0xE1BF, 0x70AB, 0xFADB, 0x70AC, 0xCBE3, + 0x70AD, 0xF7A9, 0x70AF, 0xFBA6, 0x70B3, 0xDCB9, 0x70B7, 0xF1C0, 0x70B8, 0xEDC8, 0x70B9, 0xEFC3, 0x70C8, 0xD6AD, 0x70CB, 0xFDCE, + 0x70CF, 0xE8A1, 0x70D8, 0xFBF4, 0x70D9, 0xD5A7, 0x70DD, 0xF1F6, 0x70DF, 0xE6D3, 0x70F1, 0xCCDE, 0x70F9, 0xF8B2, 0x70FD, 0xDCEB, + 0x7104, 0xFDB6, 0x7109, 0xE5EA, 0x710C, 0xF1E0, 0x7119, 0xDBCC, 0x711A, 0xDDCD, 0x711E, 0xD4C8, 0x7121, 0xD9ED, 0x7126, 0xF5A5, + 0x7130, 0xE6FB, 0x7136, 0xE6D4, 0x7147, 0xFDC8, 0x7149, 0xD6A1, 0x714A, 0xFDBF, 0x714C, 0xFCD3, 0x714E, 0xEFA1, 0x7150, 0xE7BC, + 0x7156, 0xD1EE, 0x7159, 0xE6D5, 0x715C, 0xE9F2, 0x715E, 0xDFB0, 0x7164, 0xD8E0, 0x7165, 0xFCBA, 0x7166, 0xFDAF, 0x7167, 0xF0CE, + 0x7169, 0xDBE1, 0x716C, 0xE5C9, 0x716E, 0xEDB4, 0x717D, 0xE0C3, 0x7184, 0xE3D8, 0x7189, 0xE9FB, 0x718A, 0xEAA8, 0x718F, 0xFDB7, + 0x7192, 0xFBA7, 0x7194, 0xE9C2, 0x7199, 0xFDF7, 0x719F, 0xE2D9, 0x71A2, 0xDCEC, 0x71AC, 0xE8A2, 0x71B1, 0xE6F0, 0x71B9, 0xFDF8, + 0x71BA, 0xFDF9, 0x71BE, 0xF6BF, 0x71C1, 0xE7A7, 0x71C3, 0xE6D7, 0x71C8, 0xD4F3, 0x71C9, 0xD4C9, 0x71CE, 0xD6FA, 0x71D0, 0xD7F2, + 0x71D2, 0xE1C0, 0x71D4, 0xDBE2, 0x71D5, 0xE6D8, 0x71DF, 0xE7BD, 0x71E5, 0xF0CF, 0x71E6, 0xF3BE, 0x71E7, 0xE2AC, 0x71ED, 0xF5B7, + 0x71EE, 0xE0F0, 0x71FB, 0xFDB8, 0x71FC, 0xE3E8, 0x71FE, 0xD4A7, 0x71FF, 0xE8FC, 0x7200, 0xFAD2, 0x7206, 0xF8EF, 0x7210, 0xD6D3, + 0x721B, 0xD5B4, 0x722A, 0xF0D0, 0x722C, 0xF7F0, 0x722D, 0xEEB3, 0x7230, 0xEABA, 0x7232, 0xEAD3, 0x7235, 0xEDC9, 0x7236, 0xDDAB, + 0x723A, 0xE5AC, 0x723B, 0xFDA1, 0x723D, 0xDFD0, 0x723E, 0xECB3, 0x7240, 0xDFD1, 0x7246, 0xEDED, 0x7247, 0xF8B8, 0x7248, 0xF7FA, + 0x724C, 0xF8AB, 0x7252, 0xF4E0, 0x7258, 0xD4BA, 0x7259, 0xE4B3, 0x725B, 0xE9DA, 0x725D, 0xDEB6, 0x725F, 0xD9BF, 0x7261, 0xD9C0, + 0x7262, 0xD6EF, 0x7267, 0xD9CC, 0x7269, 0xDAAA, 0x7272, 0xDFE5, 0x7279, 0xF7E5, 0x727D, 0xCCB2, 0x7280, 0xDFF9, 0x7281, 0xD7E0, + 0x72A2, 0xD4BB, 0x72A7, 0xFDFA, 0x72AC, 0xCCB3, 0x72AF, 0xDBF3, 0x72C0, 0xDFD2, 0x72C2, 0xCECA, 0x72C4, 0xEEDA, 0x72CE, 0xE4E4, + 0x72D0, 0xFBCF, 0x72D7, 0xCFB7, 0x72D9, 0xEEC3, 0x72E1, 0xCEEA, 0x72E9, 0xE2AD, 0x72F8, 0xD7E1, 0x72F9, 0xFAF5, 0x72FC, 0xD5C9, + 0x72FD, 0xF8AC, 0x730A, 0xE7D9, 0x7316, 0xF3E9, 0x731B, 0xD8ED, 0x731C, 0xE3C4, 0x731D, 0xF0F1, 0x7325, 0xE8E5, 0x7329, 0xE0FA, + 0x732A, 0xEEC4, 0x732B, 0xD9DE, 0x7336, 0xEBA2, 0x7337, 0xEBA3, 0x733E, 0xFCC2, 0x733F, 0xEABB, 0x7344, 0xE8AB, 0x7345, 0xDEE2, + 0x7350, 0xEDEF, 0x7352, 0xE8A3, 0x7357, 0xCFF1, 0x7368, 0xD4BC, 0x736A, 0xFCEA, 0x7370, 0xE7BE, 0x7372, 0xFCF2, 0x7375, 0xD6B4, + 0x7378, 0xE2AE, 0x737A, 0xD3B7, 0x737B, 0xFACC, 0x7384, 0xFADC, 0x7386, 0xEDB5, 0x7387, 0xE1E3, 0x7389, 0xE8AC, 0x738B, 0xE8DD, + 0x738E, 0xEFE9, 0x7394, 0xF4BD, 0x7396, 0xCFB8, 0x7397, 0xE9DB, 0x7398, 0xD1AC, 0x739F, 0xDAC7, 0x73A7, 0xEBC9, 0x73A9, 0xE8CC, + 0x73AD, 0xDEB7, 0x73B2, 0xD6BC, 0x73B3, 0xD3E5, 0x73B9, 0xFADD, 0x73C0, 0xDAD6, 0x73C2, 0xCAB1, 0x73C9, 0xDAC8, 0x73CA, 0xDFA6, + 0x73CC, 0xF9B3, 0x73CD, 0xF2D2, 0x73CF, 0xCAC4, 0x73D6, 0xCECB, 0x73D9, 0xCDF5, 0x73DD, 0xFDB0, 0x73DE, 0xD5A8, 0x73E0, 0xF1C1, + 0x73E3, 0xE2E9, 0x73E4, 0xDCCA, 0x73E5, 0xECB4, 0x73E6, 0xFAC0, 0x73E9, 0xFBA8, 0x73EA, 0xD0A8, 0x73ED, 0xDAEC, 0x73F7, 0xD9EE, + 0x73F9, 0xE0FB, 0x73FD, 0xEFEA, 0x73FE, 0xFADE, 0x7401, 0xE0C4, 0x7403, 0xCFB9, 0x7405, 0xD5CA, 0x7406, 0xD7E2, 0x7407, 0xE2AF, + 0x7409, 0xD7B8, 0x7413, 0xE8CD, 0x741B, 0xF6DA, 0x7420, 0xEFA2, 0x7421, 0xE2DA, 0x7422, 0xF6FC, 0x7425, 0xFBD0, 0x7426, 0xD1AD, + 0x7428, 0xCDE4, 0x742A, 0xD1AE, 0x742B, 0xDCED, 0x742C, 0xE8CE, 0x742E, 0xF0F9, 0x742F, 0xCEB5, 0x7430, 0xE6FC, 0x7433, 0xD7FB, + 0x7434, 0xD0D6, 0x7435, 0xDDF5, 0x7436, 0xF7F1, 0x7438, 0xF6FD, 0x743A, 0xDBF7, 0x743F, 0xFBEA, 0x7440, 0xE9DC, 0x7441, 0xD9C1, + 0x7443, 0xF5F2, 0x7444, 0xE0C5, 0x744B, 0xEAD4, 0x7455, 0xF9C2, 0x7457, 0xEABC, 0x7459, 0xD2C5, 0x745A, 0xFBD1, 0x745B, 0xE7C0, + 0x745C, 0xEBA5, 0x745E, 0xDFFA, 0x745F, 0xE3A2, 0x7460, 0xD7B9, 0x7462, 0xE9C3, 0x7464, 0xE8FD, 0x7465, 0xE8AF, 0x7468, 0xF2D3, + 0x7469, 0xFBA9, 0x746A, 0xD8A5, 0x746F, 0xD5CB, 0x747E, 0xD0C8, 0x7482, 0xD1AF, 0x7483, 0xD7E3, 0x7487, 0xE0C6, 0x7489, 0xD6A2, + 0x748B, 0xEDF0, 0x7498, 0xD7F3, 0x749C, 0xFCD4, 0x749E, 0xDAD7, 0x749F, 0xCCDF, 0x74A1, 0xF2D4, 0x74A3, 0xD1B0, 0x74A5, 0xCCE0, + 0x74A7, 0xDBFD, 0x74A8, 0xF3BF, 0x74AA, 0xF0D1, 0x74B0, 0xFCBB, 0x74B2, 0xE2B0, 0x74B5, 0xE6A5, 0x74B9, 0xE2DB, 0x74BD, 0xDFDE, + 0x74BF, 0xE0C7, 0x74C6, 0xF2EF, 0x74CA, 0xCCE1, 0x74CF, 0xD6EA, 0x74D4, 0xE7C2, 0x74D8, 0xCEB6, 0x74DA, 0xF3C0, 0x74DC, 0xCDFE, + 0x74E0, 0xFBD2, 0x74E2, 0xF8F8, 0x74E3, 0xF7FB, 0x74E6, 0xE8BF, 0x74EE, 0xE8B7, 0x74F7, 0xEDB6, 0x7501, 0xDCBA, 0x7504, 0xCCB4, + 0x7511, 0xF1F7, 0x7515, 0xE8B8, 0x7518, 0xCAF6, 0x751A, 0xE4A4, 0x751B, 0xF4D6, 0x751F, 0xDFE6, 0x7523, 0xDFA7, 0x7525, 0xDFE7, + 0x7526, 0xE1C1, 0x7528, 0xE9C4, 0x752B, 0xDCCB, 0x752C, 0xE9C5, 0x7530, 0xEFA3, 0x7531, 0xEBA6, 0x7532, 0xCBA3, 0x7533, 0xE3E9, + 0x7537, 0xD1FB, 0x7538, 0xEFA4, 0x753A, 0xEFEB, 0x7547, 0xD0B4, 0x754C, 0xCDA3, 0x754F, 0xE8E6, 0x7551, 0xEFA5, 0x7553, 0xD3CC, + 0x7554, 0xDAED, 0x7559, 0xD7BA, 0x755B, 0xF2D5, 0x755C, 0xF5E5, 0x755D, 0xD9EF, 0x7562, 0xF9B4, 0x7565, 0xD5D4, 0x7566, 0xFDCF, + 0x756A, 0xDBE3, 0x756F, 0xF1E1, 0x7570, 0xECB6, 0x7575, 0xFBFE, 0x7576, 0xD3D7, 0x7578, 0xD1B1, 0x757A, 0xCBB1, 0x757F, 0xD1B2, + 0x7586, 0xCBB2, 0x7587, 0xF1C2, 0x758A, 0xF4E1, 0x758B, 0xF9B5, 0x758E, 0xE1C3, 0x758F, 0xE1C2, 0x7591, 0xEBF7, 0x759D, 0xDFA8, + 0x75A5, 0xCBCA, 0x75AB, 0xE6B9, 0x75B1, 0xF8DE, 0x75B2, 0xF9AA, 0x75B3, 0xCAF7, 0x75B5, 0xEDB7, 0x75B8, 0xD3B8, 0x75B9, 0xF2D6, + 0x75BC, 0xD4D9, 0x75BD, 0xEEC5, 0x75BE, 0xF2F0, 0x75C2, 0xCAB2, 0x75C5, 0xDCBB, 0x75C7, 0xF1F8, 0x75CD, 0xECB7, 0x75D2, 0xE5CA, + 0x75D4, 0xF6C0, 0x75D5, 0xFDDD, 0x75D8, 0xD4E3, 0x75D9, 0xCCE2, 0x75DB, 0xF7D4, 0x75E2, 0xD7E5, 0x75F0, 0xD3C3, 0x75F2, 0xD8A6, + 0x75F4, 0xF6C1, 0x75FA, 0xDDF6, 0x75FC, 0xCDC0, 0x7600, 0xE5DC, 0x760D, 0xE5CB, 0x7619, 0xE1C4, 0x761F, 0xE8B0, 0x7620, 0xF4B0, + 0x7621, 0xF3EA, 0x7622, 0xDAEE, 0x7624, 0xD7BB, 0x7626, 0xE2B1, 0x763B, 0xD7AA, 0x7642, 0xD6FB, 0x764C, 0xE4DF, 0x764E, 0xCAD6, + 0x7652, 0xEBA8, 0x7656, 0xDBFE, 0x7661, 0xF6C2, 0x7664, 0xEFBB, 0x7669, 0xD4FD, 0x766C, 0xE0C8, 0x7670, 0xE8B9, 0x7672, 0xEFA6, + 0x7678, 0xCDA4, 0x767B, 0xD4F4, 0x767C, 0xDBA1, 0x767D, 0xDBDC, 0x767E, 0xDBDD, 0x7684, 0xEEDC, 0x7686, 0xCBCB, 0x7687, 0xFCD5, + 0x768E, 0xCEEB, 0x7690, 0xCDC1, 0x7693, 0xFBD3, 0x76AE, 0xF9AB, 0x76BA, 0xF5D4, 0x76BF, 0xD9A9, 0x76C2, 0xE9DD, 0x76C3, 0xDBCD, + 0x76C6, 0xDDCE, 0x76C8, 0xE7C3, 0x76CA, 0xECCC, 0x76D2, 0xF9EC, 0x76D6, 0xCBCC, 0x76DB, 0xE0FC, 0x76DC, 0xD4A8, 0x76DE, 0xEDD3, + 0x76DF, 0xD8EF, 0x76E1, 0xF2D7, 0x76E3, 0xCAF8, 0x76E4, 0xDAEF, 0x76E7, 0xD6D4, 0x76EE, 0xD9CD, 0x76F2, 0xD8EE, 0x76F4, 0xF2C1, + 0x76F8, 0xDFD3, 0x76FC, 0xDAF0, 0x76FE, 0xE2EA, 0x7701, 0xE0FD, 0x7704, 0xD8F8, 0x7708, 0xF7AF, 0x7709, 0xDAB6, 0x770B, 0xCAD7, + 0x771E, 0xF2D8, 0x7720, 0xD8F9, 0x7729, 0xFADF, 0x7737, 0xCFEF, 0x7738, 0xD9C2, 0x773A, 0xF0D2, 0x773C, 0xE4D1, 0x7740, 0xF3B7, + 0x774D, 0xFAE0, 0x775B, 0xEFEC, 0x7761, 0xE2B2, 0x7763, 0xD4BD, 0x7766, 0xD9CE, 0x776B, 0xF4E2, 0x7779, 0xD4A9, 0x777E, 0xCDC2, + 0x777F, 0xE7DA, 0x778B, 0xF2D9, 0x7791, 0xD9AA, 0x779E, 0xD8BE, 0x77A5, 0xDCAD, 0x77AC, 0xE2EB, 0x77AD, 0xD6FC, 0x77B0, 0xCAF9, + 0x77B3, 0xD4DA, 0x77BB, 0xF4D7, 0x77BC, 0xCCA1, 0x77BF, 0xCFBA, 0x77D7, 0xF5B8, 0x77DB, 0xD9C3, 0x77DC, 0xD0E8, 0x77E2, 0xE3C5, + 0x77E3, 0xEBF8, 0x77E5, 0xF2B1, 0x77E9, 0xCFBB, 0x77ED, 0xD3AD, 0x77EE, 0xE8E1, 0x77EF, 0xCEEC, 0x77F3, 0xE0B4, 0x7802, 0xDEE3, + 0x7812, 0xDDF7, 0x7825, 0xF2B2, 0x7826, 0xF3F6, 0x7827, 0xF6DB, 0x782C, 0xD7FE, 0x7832, 0xF8DF, 0x7834, 0xF7F2, 0x7845, 0xD0A9, + 0x784F, 0xE6DA, 0x785D, 0xF5A6, 0x786B, 0xD7BC, 0x786C, 0xCCE3, 0x786F, 0xE6DB, 0x787C, 0xDDDD, 0x7881, 0xD1B3, 0x7887, 0xEFED, + 0x788C, 0xD6DE, 0x788D, 0xE4F4, 0x788E, 0xE1EF, 0x7891, 0xDDF8, 0x7897, 0xE8CF, 0x78A3, 0xCAE5, 0x78A7, 0xDCA1, 0x78A9, 0xE0B5, + 0x78BA, 0xFCAC, 0x78BB, 0xFCAD, 0x78BC, 0xD8A7, 0x78C1, 0xEDB8, 0x78C5, 0xDBB6, 0x78CA, 0xD6F0, 0x78CB, 0xF3AF, 0x78CE, 0xCDA5, + 0x78D0, 0xDAF1, 0x78E8, 0xD8A8, 0x78EC, 0xCCE4, 0x78EF, 0xD1B4, 0x78F5, 0xCAD8, 0x78FB, 0xDAF2, 0x7901, 0xF5A7, 0x790E, 0xF5A8, + 0x7916, 0xE6A6, 0x792A, 0xD5EC, 0x792B, 0xD5F8, 0x792C, 0xDAF3, 0x793A, 0xE3C6, 0x793E, 0xDEE4, 0x7940, 0xDEE5, 0x7941, 0xD1B5, + 0x7947, 0xD1B6, 0x7948, 0xD1B7, 0x7949, 0xF2B3, 0x7950, 0xE9DE, 0x7956, 0xF0D3, 0x7957, 0xF2B4, 0x795A, 0xF0D4, 0x795B, 0xCBE4, + 0x795C, 0xFBD4, 0x795D, 0xF5E6, 0x795E, 0xE3EA, 0x7960, 0xDEE6, 0x7965, 0xDFD4, 0x7968, 0xF8F9, 0x796D, 0xF0AE, 0x797A, 0xD1B8, + 0x797F, 0xD6DF, 0x7981, 0xD0D7, 0x798D, 0xFCA1, 0x798E, 0xEFEE, 0x798F, 0xDCD8, 0x7991, 0xE9DF, 0x79A6, 0xE5DD, 0x79A7, 0xFDFB, + 0x79AA, 0xE0C9, 0x79AE, 0xD6C9, 0x79B1, 0xD4AA, 0x79B3, 0xE5CC, 0x79B9, 0xE9E0, 0x79BD, 0xD0D8, 0x79BE, 0xFCA2, 0x79BF, 0xD4BE, + 0x79C0, 0xE2B3, 0x79C1, 0xDEE7, 0x79C9, 0xDCBC, 0x79CA, 0xD2B6, 0x79CB, 0xF5D5, 0x79D1, 0xCEA1, 0x79D2, 0xF5A9, 0x79D5, 0xDDF9, + 0x79D8, 0xDDFA, 0x79DF, 0xF0D5, 0x79E4, 0xF6DF, 0x79E6, 0xF2DA, 0x79E7, 0xE4EB, 0x79E9, 0xF2F1, 0x79FB, 0xECB9, 0x7A00, 0xFDFC, + 0x7A05, 0xE1AA, 0x7A08, 0xCAD9, 0x7A0B, 0xEFEF, 0x7A0D, 0xF5AA, 0x7A14, 0xECF9, 0x7A17, 0xF8AD, 0x7A19, 0xF2C2, 0x7A1A, 0xF6C3, + 0x7A1C, 0xD7D2, 0x7A1F, 0xF9A2, 0x7A20, 0xF0D6, 0x7A2E, 0xF0FA, 0x7A31, 0xF6E0, 0x7A36, 0xE9F3, 0x7A37, 0xF2C3, 0x7A3B, 0xD4AB, + 0x7A3C, 0xCAB3, 0x7A3D, 0xCDA6, 0x7A3F, 0xCDC3, 0x7A40, 0xCDDA, 0x7A46, 0xD9CF, 0x7A49, 0xF6C4, 0x7A4D, 0xEEDD, 0x7A4E, 0xE7C4, + 0x7A57, 0xE2B4, 0x7A61, 0xDFE2, 0x7A62, 0xE7DB, 0x7A69, 0xE8B1, 0x7A6B, 0xFCAE, 0x7A70, 0xE5CD, 0x7A74, 0xFAEB, 0x7A76, 0xCFBC, + 0x7A79, 0xCFE2, 0x7A7A, 0xCDF6, 0x7A7D, 0xEFF0, 0x7A7F, 0xF4BE, 0x7A81, 0xD4CD, 0x7A84, 0xF3B8, 0x7A88, 0xE9A1, 0x7A92, 0xF2F2, + 0x7A93, 0xF3EB, 0x7A95, 0xF0D7, 0x7A98, 0xCFD7, 0x7A9F, 0xCFDF, 0x7AA9, 0xE8C0, 0x7AAA, 0xE8C1, 0x7AAE, 0xCFE3, 0x7AAF, 0xE9A2, + 0x7ABA, 0xD0AA, 0x7AC4, 0xF3C1, 0x7AC5, 0xD0AB, 0x7AC7, 0xD4E4, 0x7ACA, 0xEFBC, 0x7ACB, 0xD8A1, 0x7AD7, 0xD9DF, 0x7AD9, 0xF3D7, + 0x7ADD, 0xDCBD, 0x7ADF, 0xCCE5, 0x7AE0, 0xEDF1, 0x7AE3, 0xF1E2, 0x7AE5, 0xD4DB, 0x7AEA, 0xE2B5, 0x7AED, 0xCAE6, 0x7AEF, 0xD3AE, + 0x7AF6, 0xCCE6, 0x7AF9, 0xF1D3, 0x7AFA, 0xF5E7, 0x7AFF, 0xCADA, 0x7B0F, 0xFBEE, 0x7B11, 0xE1C5, 0x7B19, 0xDFE9, 0x7B1B, 0xEEDE, + 0x7B1E, 0xF7C2, 0x7B20, 0xD8A2, 0x7B26, 0xDDAC, 0x7B2C, 0xF0AF, 0x7B2D, 0xD6BD, 0x7B39, 0xE1AB, 0x7B46, 0xF9B6, 0x7B49, 0xD4F5, + 0x7B4B, 0xD0C9, 0x7B4C, 0xEFA7, 0x7B4D, 0xE2EC, 0x7B4F, 0xDBEA, 0x7B50, 0xCECC, 0x7B51, 0xF5E8, 0x7B52, 0xF7D5, 0x7B54, 0xD3CD, + 0x7B56, 0xF3FE, 0x7B60, 0xD0B5, 0x7B6C, 0xE0FE, 0x7B6E, 0xDFFB, 0x7B75, 0xE6DD, 0x7B7D, 0xE8A4, 0x7B87, 0xCBCD, 0x7B8B, 0xEFA8, + 0x7B8F, 0xEEB4, 0x7B94, 0xDAD8, 0x7B95, 0xD1B9, 0x7B97, 0xDFA9, 0x7B9A, 0xF3B0, 0x7B9D, 0xCCC4, 0x7BA1, 0xCEB7, 0x7BAD, 0xEFA9, + 0x7BB1, 0xDFD5, 0x7BB4, 0xEDD7, 0x7BB8, 0xEEC6, 0x7BC0, 0xEFBD, 0x7BC1, 0xFCD6, 0x7BC4, 0xDBF4, 0x7BC6, 0xEFAA, 0x7BC7, 0xF8B9, + 0x7BC9, 0xF5E9, 0x7BD2, 0xE3D9, 0x7BE0, 0xE1C6, 0x7BE4, 0xD4BF, 0x7BE9, 0xDEE8, 0x7C07, 0xF0EA, 0x7C12, 0xF3C2, 0x7C1E, 0xD3AF, + 0x7C21, 0xCADB, 0x7C27, 0xFCD7, 0x7C2A, 0xEDD8, 0x7C2B, 0xE1C7, 0x7C3D, 0xF4D8, 0x7C3E, 0xD6B3, 0x7C3F, 0xDDAD, 0x7C43, 0xD5BE, + 0x7C4C, 0xF1C3, 0x7C4D, 0xEEDF, 0x7C60, 0xD6EB, 0x7C64, 0xF4D9, 0x7C6C, 0xD7E6, 0x7C73, 0xDAB7, 0x7C83, 0xDDFB, 0x7C89, 0xDDCF, + 0x7C92, 0xD8A3, 0x7C95, 0xDAD9, 0x7C97, 0xF0D8, 0x7C98, 0xEFC4, 0x7C9F, 0xE1D8, 0x7CA5, 0xF1D4, 0x7CA7, 0xEDF2, 0x7CAE, 0xD5DB, + 0x7CB1, 0xD5DC, 0x7CB2, 0xF3C4, 0x7CB3, 0xCBD7, 0x7CB9, 0xE2B6, 0x7CBE, 0xEFF1, 0x7CCA, 0xFBD5, 0x7CD6, 0xD3D8, 0x7CDE, 0xDDD0, + 0x7CDF, 0xF0D9, 0x7CE0, 0xCBB3, 0x7CE7, 0xD5DD, 0x7CFB, 0xCDA7, 0x7CFE, 0xD0AC, 0x7D00, 0xD1BA, 0x7D02, 0xF1C4, 0x7D04, 0xE5B3, + 0x7D05, 0xFBF5, 0x7D06, 0xE9E1, 0x7D07, 0xFDE0, 0x7D08, 0xFCBC, 0x7D0A, 0xDAA2, 0x7D0B, 0xDAA3, 0x7D0D, 0xD2A1, 0x7D10, 0xD2EF, + 0x7D14, 0xE2ED, 0x7D17, 0xDEE9, 0x7D18, 0xCEDC, 0x7D19, 0xF2B5, 0x7D1A, 0xD0E4, 0x7D1B, 0xDDD1, 0x7D20, 0xE1C8, 0x7D21, 0xDBB7, + 0x7D22, 0xDFE3, 0x7D2B, 0xEDB9, 0x7D2C, 0xF1C5, 0x7D2E, 0xF3CF, 0x7D2F, 0xD7AB, 0x7D30, 0xE1AC, 0x7D33, 0xE3EB, 0x7D35, 0xEEC7, + 0x7D39, 0xE1C9, 0x7D3A, 0xCAFA, 0x7D42, 0xF0FB, 0x7D43, 0xFAE1, 0x7D44, 0xF0DA, 0x7D45, 0xCCE7, 0x7D46, 0xDAF4, 0x7D50, 0xCCBF, + 0x7D5E, 0xCEED, 0x7D61, 0xD5A9, 0x7D62, 0xFAE2, 0x7D66, 0xD0E5, 0x7D68, 0xEBD6, 0x7D6A, 0xECDF, 0x7D6E, 0xDFFC, 0x7D71, 0xF7D6, + 0x7D72, 0xDEEA, 0x7D73, 0xCBB4, 0x7D76, 0xEFBE, 0x7D79, 0xCCB5, 0x7D7F, 0xCFBD, 0x7D8E, 0xEFF2, 0x7D8F, 0xE2B7, 0x7D93, 0xCCE8, + 0x7D9C, 0xF0FC, 0x7DA0, 0xD6E0, 0x7DA2, 0xF1C6, 0x7DAC, 0xE2B8, 0x7DAD, 0xEBAB, 0x7DB1, 0xCBB5, 0x7DB2, 0xD8D1, 0x7DB4, 0xF4CE, + 0x7DB5, 0xF3F7, 0x7DB8, 0xD7C6, 0x7DBA, 0xD1BB, 0x7DBB, 0xF7AA, 0x7DBD, 0xEDCA, 0x7DBE, 0xD7D3, 0x7DBF, 0xD8FA, 0x7DC7, 0xF6C5, + 0x7DCA, 0xD1CC, 0x7DCB, 0xDDFC, 0x7DD6, 0xDFFD, 0x7DD8, 0xF9E5, 0x7DDA, 0xE0CA, 0x7DDD, 0xF2FD, 0x7DDE, 0xD3B0, 0x7DE0, 0xF4F3, + 0x7DE1, 0xDAC9, 0x7DE3, 0xE6DE, 0x7DE8, 0xF8BA, 0x7DE9, 0xE8D0, 0x7DEC, 0xD8FB, 0x7DEF, 0xEAD5, 0x7DF4, 0xD6A3, 0x7DFB, 0xF6C6, + 0x7E09, 0xF2DB, 0x7E0A, 0xE4FC, 0x7E15, 0xE8B2, 0x7E1B, 0xDADA, 0x7E1D, 0xF2DC, 0x7E1E, 0xFBD6, 0x7E1F, 0xE9B2, 0x7E21, 0xEEAD, + 0x7E23, 0xFAE3, 0x7E2B, 0xDCEE, 0x7E2E, 0xF5EA, 0x7E2F, 0xE6E0, 0x7E31, 0xF0FD, 0x7E37, 0xD7AC, 0x7E3D, 0xF5C5, 0x7E3E, 0xEEE0, + 0x7E41, 0xDBE5, 0x7E43, 0xDDDE, 0x7E46, 0xD9F0, 0x7E47, 0xE9A3, 0x7E52, 0xF1F9, 0x7E54, 0xF2C4, 0x7E55, 0xE0CB, 0x7E5E, 0xE9A4, + 0x7E61, 0xE2B9, 0x7E69, 0xE3B1, 0x7E6A, 0xFCEB, 0x7E6B, 0xCDA8, 0x7E6D, 0xCCB6, 0x7E70, 0xF0DB, 0x7E79, 0xE6BA, 0x7E7C, 0xCDA9, + 0x7E82, 0xF3C3, 0x7E8C, 0xE1D9, 0x7E8F, 0xEFAB, 0x7E93, 0xE7C5, 0x7E96, 0xE0E9, 0x7E98, 0xF3C5, 0x7E9B, 0xD4C0, 0x7E9C, 0xD5BF, + 0x7F36, 0xDDAE, 0x7F38, 0xF9FC, 0x7F3A, 0xCCC0, 0x7F4C, 0xE5A2, 0x7F50, 0xCEB8, 0x7F54, 0xD8D2, 0x7F55, 0xF9D6, 0x7F6A, 0xF1AA, + 0x7F6B, 0xCED1, 0x7F6E, 0xF6C7, 0x7F70, 0xDBEB, 0x7F72, 0xDFFE, 0x7F75, 0xD8E1, 0x7F77, 0xF7F3, 0x7F79, 0xD7E7, 0x7F85, 0xD4FE, + 0x7F88, 0xD1BC, 0x7F8A, 0xE5CF, 0x7F8C, 0xCBB6, 0x7F8E, 0xDAB8, 0x7F94, 0xCDC4, 0x7F9A, 0xD6BE, 0x7F9E, 0xE2BA, 0x7FA4, 0xCFD8, + 0x7FA8, 0xE0CC, 0x7FA9, 0xEBF9, 0x7FB2, 0xFDFD, 0x7FB8, 0xD7E8, 0x7FB9, 0xCBD8, 0x7FBD, 0xE9E2, 0x7FC1, 0xE8BA, 0x7FC5, 0xE3C7, + 0x7FCA, 0xECCD, 0x7FCC, 0xECCE, 0x7FCE, 0xD6BF, 0x7FD2, 0xE3A7, 0x7FD4, 0xDFD6, 0x7FD5, 0xFDE8, 0x7FDF, 0xEEE1, 0x7FE0, 0xF6A8, + 0x7FE1, 0xDDFD, 0x7FE9, 0xF8BB, 0x7FEB, 0xE8D1, 0x7FF0, 0xF9D7, 0x7FF9, 0xCEEE, 0x7FFC, 0xECCF, 0x8000, 0xE9A5, 0x8001, 0xD6D5, + 0x8003, 0xCDC5, 0x8005, 0xEDBA, 0x8006, 0xD1BD, 0x8009, 0xCFBE, 0x800C, 0xECBB, 0x8010, 0xD2B1, 0x8015, 0xCCE9, 0x8017, 0xD9C4, + 0x8018, 0xE9FC, 0x802D, 0xD1BE, 0x8033, 0xECBC, 0x8036, 0xE5AD, 0x803D, 0xF7B0, 0x803F, 0xCCEA, 0x8043, 0xD3C4, 0x8046, 0xD6C0, + 0x804A, 0xD6FD, 0x8056, 0xE1A1, 0x8058, 0xDEBD, 0x805A, 0xF6A9, 0x805E, 0xDAA4, 0x806F, 0xD6A4, 0x8070, 0xF5C6, 0x8072, 0xE1A2, + 0x8073, 0xE9C6, 0x8077, 0xF2C5, 0x807D, 0xF4E9, 0x807E, 0xD6EC, 0x807F, 0xEBD3, 0x8084, 0xECBD, 0x8085, 0xE2DC, 0x8086, 0xDEEB, + 0x8087, 0xF0DC, 0x8089, 0xEBBF, 0x808B, 0xD7CE, 0x808C, 0xD1BF, 0x8096, 0xF5AB, 0x809B, 0xF9FD, 0x809D, 0xCADC, 0x80A1, 0xCDC6, + 0x80A2, 0xF2B6, 0x80A5, 0xDDFE, 0x80A9, 0xCCB7, 0x80AA, 0xDBB8, 0x80AF, 0xD0E9, 0x80B1, 0xCEDD, 0x80B2, 0xEBC0, 0x80B4, 0xFDA2, + 0x80BA, 0xF8CB, 0x80C3, 0xEAD6, 0x80C4, 0xF1B0, 0x80CC, 0xDBCE, 0x80CE, 0xF7C3, 0x80DA, 0xDBCF, 0x80DB, 0xCBA4, 0x80DE, 0xF8E0, + 0x80E1, 0xFBD7, 0x80E4, 0xEBCA, 0x80E5, 0xE0A1, 0x80F1, 0xCECD, 0x80F4, 0xD4DC, 0x80F8, 0xFDD8, 0x80FD, 0xD2F6, 0x8102, 0xF2B7, + 0x8105, 0xFAF6, 0x8106, 0xF6AA, 0x8107, 0xFAF7, 0x8108, 0xD8E6, 0x810A, 0xF4B1, 0x8118, 0xE8D2, 0x811A, 0xCAC5, 0x811B, 0xCCEB, + 0x8123, 0xE2EE, 0x8129, 0xE2BB, 0x812B, 0xF7AD, 0x812F, 0xF8E1, 0x8139, 0xF3EC, 0x813E, 0xDEA1, 0x814B, 0xE4FD, 0x814E, 0xE3EC, + 0x8150, 0xDDAF, 0x8151, 0xDDB0, 0x8154, 0xCBB7, 0x8155, 0xE8D3, 0x8165, 0xE1A3, 0x8166, 0xD2E0, 0x816B, 0xF0FE, 0x8170, 0xE9A6, + 0x8171, 0xCBF2, 0x8178, 0xEDF3, 0x8179, 0xDCD9, 0x817A, 0xE0CD, 0x817F, 0xF7DA, 0x8180, 0xDBB9, 0x8188, 0xCCAE, 0x818A, 0xDADB, + 0x818F, 0xCDC7, 0x819A, 0xDDB1, 0x819C, 0xD8AF, 0x819D, 0xE3A3, 0x81A0, 0xCEEF, 0x81A3, 0xF2F3, 0x81A8, 0xF8B3, 0x81B3, 0xE0CE, + 0x81B5, 0xF5FD, 0x81BA, 0xEBEC, 0x81BD, 0xD3C5, 0x81BE, 0xFCEC, 0x81BF, 0xD2DB, 0x81C0, 0xD4EB, 0x81C2, 0xDEA2, 0x81C6, 0xE5E6, + 0x81CD, 0xF0B0, 0x81D8, 0xD5C4, 0x81DF, 0xEDF4, 0x81E3, 0xE3ED, 0x81E5, 0xE8C2, 0x81E7, 0xEDF5, 0x81E8, 0xD7FC, 0x81EA, 0xEDBB, + 0x81ED, 0xF6AB, 0x81F3, 0xF2B8, 0x81F4, 0xF6C8, 0x81FA, 0xD3E6, 0x81FB, 0xF2DD, 0x81FC, 0xCFBF, 0x81FE, 0xEBAC, 0x8205, 0xCFC0, + 0x8207, 0xE6A8, 0x8208, 0xFDE9, 0x820A, 0xCFC1, 0x820C, 0xE0DF, 0x820D, 0xDEEC, 0x8212, 0xE0A2, 0x821B, 0xF4BF, 0x821C, 0xE2EF, + 0x821E, 0xD9F1, 0x821F, 0xF1C7, 0x8221, 0xCBB8, 0x822A, 0xF9FE, 0x822B, 0xDBBA, 0x822C, 0xDAF5, 0x8235, 0xF6EC, 0x8236, 0xDADC, + 0x8237, 0xFAE4, 0x8239, 0xE0CF, 0x8240, 0xDDB2, 0x8245, 0xE6A9, 0x8247, 0xEFF3, 0x8259, 0xF3ED, 0x8264, 0xEBFA, 0x8266, 0xF9E6, + 0x826E, 0xCADD, 0x826F, 0xD5DE, 0x8271, 0xCADE, 0x8272, 0xDFE4, 0x8276, 0xE6FD, 0x8278, 0xF5AC, 0x827E, 0xE4F5, 0x828B, 0xE9E3, + 0x828D, 0xEDCB, 0x828E, 0xCFE4, 0x8292, 0xD8D3, 0x8299, 0xDDB3, 0x829A, 0xD4EC, 0x829D, 0xF2B9, 0x829F, 0xDFB7, 0x82A5, 0xCBCE, + 0x82A6, 0xFBD8, 0x82A9, 0xD0D9, 0x82AC, 0xDDD2, 0x82AD, 0xF7F4, 0x82AE, 0xE7DC, 0x82AF, 0xE4A5, 0x82B1, 0xFCA3, 0x82B3, 0xDBBB, + 0x82B7, 0xF2BA, 0x82B8, 0xE9FD, 0x82B9, 0xD0CA, 0x82BB, 0xF5D6, 0x82BC, 0xD9C5, 0x82BD, 0xE4B4, 0x82BF, 0xEDA7, 0x82D1, 0xEABD, + 0x82D2, 0xE6FE, 0x82D4, 0xF7C4, 0x82D5, 0xF5AD, 0x82D7, 0xD9E0, 0x82DB, 0xCAB4, 0x82DE, 0xF8E2, 0x82DF, 0xCFC2, 0x82E1, 0xECBE, + 0x82E5, 0xE5B4, 0x82E6, 0xCDC8, 0x82E7, 0xEEC8, 0x82F1, 0xE7C8, 0x82FD, 0xCDC9, 0x82FE, 0xF9B7, 0x8301, 0xF1E8, 0x8302, 0xD9F2, + 0x8303, 0xDBF5, 0x8304, 0xCAB5, 0x8305, 0xD9C6, 0x8309, 0xD8C9, 0x8317, 0xD9AB, 0x8328, 0xEDBC, 0x832B, 0xD8D4, 0x832F, 0xDCDA, + 0x8331, 0xE2BC, 0x8334, 0xFCED, 0x8335, 0xECE0, 0x8336, 0xD2FE, 0x8338, 0xE9C7, 0x8339, 0xE6AA, 0x8340, 0xE2F0, 0x8347, 0xFABB, + 0x8349, 0xF5AE, 0x834A, 0xFBAA, 0x834F, 0xECFB, 0x8351, 0xECBF, 0x8352, 0xFCD8, 0x8373, 0xD4E5, 0x8377, 0xF9C3, 0x837B, 0xEEE2, + 0x8389, 0xD7E9, 0x838A, 0xEDF6, 0x838E, 0xDEED, 0x8396, 0xCCEC, 0x8398, 0xE3EE, 0x839E, 0xE8D4, 0x83A2, 0xFAF8, 0x83A9, 0xDDB4, + 0x83AA, 0xE4B5, 0x83AB, 0xD8B0, 0x83BD, 0xD8D5, 0x83C1, 0xF4EA, 0x83C5, 0xCEB9, 0x83C9, 0xD6E1, 0x83CA, 0xCFD2, 0x83CC, 0xD0B6, + 0x83D3, 0xCEA2, 0x83D6, 0xF3EE, 0x83DC, 0xF3F8, 0x83E9, 0xDCCC, 0x83EB, 0xD0CB, 0x83EF, 0xFCA4, 0x83F0, 0xCDCA, 0x83F1, 0xD7D4, + 0x83F2, 0xDEA3, 0x83F4, 0xE4E0, 0x83F9, 0xEEC9, 0x83FD, 0xE2DD, 0x8403, 0xF5FE, 0x8404, 0xD4AC, 0x840A, 0xD5D1, 0x840C, 0xD8F0, + 0x840D, 0xF8C3, 0x840E, 0xEAD7, 0x8429, 0xF5D7, 0x842C, 0xD8BF, 0x8431, 0xFDC0, 0x8438, 0xEBAD, 0x843D, 0xD5AA, 0x8449, 0xE7A8, + 0x8457, 0xEECA, 0x845B, 0xCAE7, 0x8461, 0xF8E3, 0x8463, 0xD4DD, 0x8466, 0xEAD8, 0x846B, 0xFBD9, 0x846C, 0xEDF7, 0x846F, 0xE5B5, + 0x8475, 0xD0AD, 0x847A, 0xF1F1, 0x8490, 0xE2BD, 0x8494, 0xE3C8, 0x8499, 0xD9D5, 0x849C, 0xDFAA, 0x84A1, 0xDBBC, 0x84B2, 0xF8E4, + 0x84B8, 0xF1FA, 0x84BB, 0xE5B6, 0x84BC, 0xF3EF, 0x84BF, 0xFBDA, 0x84C0, 0xE1E0, 0x84C2, 0xD9AC, 0x84C4, 0xF5EB, 0x84C6, 0xE0B6, + 0x84C9, 0xE9C8, 0x84CB, 0xCBCF, 0x84CD, 0xE3C9, 0x84D1, 0xDEEE, 0x84DA, 0xE2BE, 0x84EC, 0xDCEF, 0x84EE, 0xD6A5, 0x84F4, 0xE2F1, + 0x84FC, 0xD6FE, 0x8511, 0xD9A1, 0x8513, 0xD8C0, 0x8514, 0xDCDB, 0x8517, 0xEDBD, 0x8518, 0xDFB8, 0x851A, 0xEAA5, 0x851E, 0xD7AD, + 0x8521, 0xF3F9, 0x8523, 0xEDF8, 0x8525, 0xF5C7, 0x852C, 0xE1CA, 0x852D, 0xEBE3, 0x852F, 0xF2DE, 0x853D, 0xF8CC, 0x853F, 0xEAD9, + 0x8541, 0xD3C6, 0x8543, 0xDBE6, 0x8549, 0xF5AF, 0x854E, 0xCEF0, 0x8553, 0xE9FE, 0x8559, 0xFBB6, 0x8563, 0xE2F2, 0x8568, 0xCFF2, + 0x8569, 0xF7B9, 0x856A, 0xD9F3, 0x856D, 0xE1CB, 0x8584, 0xDADD, 0x8587, 0xDAB9, 0x858F, 0xEBFB, 0x8591, 0xCBB9, 0x8594, 0xEDF9, + 0x859B, 0xE0E0, 0x85A6, 0xF4C0, 0x85A8, 0xFDBC, 0x85A9, 0xDFB1, 0x85AA, 0xE3EF, 0x85AF, 0xE0A3, 0x85B0, 0xFDB9, 0x85BA, 0xF0B1, + 0x85C1, 0xCDCB, 0x85C9, 0xEDBE, 0x85CD, 0xD5C0, 0x85CE, 0xE3F0, 0x85CF, 0xEDFA, 0x85D5, 0xE9E4, 0x85DC, 0xD5ED, 0x85DD, 0xE7DD, + 0x85E4, 0xD4F6, 0x85E5, 0xE5B7, 0x85E9, 0xDBE7, 0x85EA, 0xE2BF, 0x85F7, 0xEECB, 0x85FA, 0xD7F4, 0x85FB, 0xF0DD, 0x85FF, 0xCEAB, + 0x8602, 0xE7DE, 0x8606, 0xD6D6, 0x8607, 0xE1CC, 0x860A, 0xE8B3, 0x8616, 0xE5EE, 0x8617, 0xDCA2, 0x861A, 0xE0D0, 0x862D, 0xD5B5, + 0x863F, 0xD5A1, 0x864E, 0xFBDB, 0x8650, 0xF9CB, 0x8654, 0xCBF3, 0x8655, 0xF4A5, 0x865B, 0xFAC8, 0x865C, 0xD6D7, 0x865E, 0xE9E5, + 0x865F, 0xFBDC, 0x8667, 0xFDD0, 0x8679, 0xFBF6, 0x868A, 0xDAA5, 0x868C, 0xDBBD, 0x8693, 0xECE2, 0x86A3, 0xCDF7, 0x86A4, 0xF0DE, + 0x86A9, 0xF6C9, 0x86C7, 0xDEEF, 0x86CB, 0xD3B1, 0x86D4, 0xFCEE, 0x86D9, 0xE8C3, 0x86DB, 0xF1C8, 0x86DF, 0xCEF1, 0x86E4, 0xF9ED, + 0x86ED, 0xF2F4, 0x86FE, 0xE4B6, 0x8700, 0xF5B9, 0x8702, 0xDCF0, 0x8703, 0xE3F1, 0x8708, 0xE8A5, 0x8718, 0xF2BB, 0x871A, 0xDEA4, + 0x871C, 0xDACC, 0x874E, 0xCAE9, 0x8755, 0xE3DA, 0x8757, 0xFCD9, 0x875F, 0xEADA, 0x8766, 0xF9C4, 0x8768, 0xE3A4, 0x8774, 0xFBDD, + 0x8776, 0xEFCA, 0x8778, 0xE8C4, 0x8782, 0xD5CC, 0x878D, 0xEBD7, 0x879F, 0xD9AD, 0x87A2, 0xFBAB, 0x87B3, 0xD3D9, 0x87BA, 0xD5A2, + 0x87C4, 0xF6DE, 0x87E0, 0xDAF6, 0x87EC, 0xE0D1, 0x87EF, 0xE9A8, 0x87F2, 0xF5F9, 0x87F9, 0xFAAF, 0x87FB, 0xEBFC, 0x87FE, 0xE0EA, + 0x8805, 0xE3B2, 0x881F, 0xD5C5, 0x8822, 0xF1E3, 0x8823, 0xD5EE, 0x8831, 0xCDCC, 0x8836, 0xEDD9, 0x883B, 0xD8C1, 0x8840, 0xFAEC, + 0x8846, 0xF1EB, 0x884C, 0xFABC, 0x884D, 0xE6E2, 0x8852, 0xFAE5, 0x8853, 0xE2FA, 0x8857, 0xCAB6, 0x8859, 0xE4B7, 0x885B, 0xEADB, + 0x885D, 0xF5FA, 0x8861, 0xFBAC, 0x8862, 0xCFC3, 0x8863, 0xEBFD, 0x8868, 0xF8FA, 0x886B, 0xDFB9, 0x8870, 0xE1F1, 0x8872, 0xD2A4, + 0x8877, 0xF5FB, 0x887E, 0xD0DA, 0x887F, 0xD0DB, 0x8881, 0xEABE, 0x8882, 0xD9B1, 0x8888, 0xCAB7, 0x888B, 0xD3E7, 0x888D, 0xF8E5, + 0x8892, 0xD3B2, 0x8896, 0xE2C0, 0x8897, 0xF2DF, 0x889E, 0xCDE5, 0x88AB, 0xF9AC, 0x88B4, 0xCDCD, 0x88C1, 0xEEAE, 0x88C2, 0xD6AE, + 0x88CF, 0xD7EA, 0x88D4, 0xE7E0, 0x88D5, 0xEBAE, 0x88D9, 0xCFD9, 0x88DC, 0xDCCD, 0x88DD, 0xEDFB, 0x88DF, 0xDEF0, 0x88E1, 0xD7EB, + 0x88E8, 0xDEA5, 0x88F3, 0xDFD7, 0x88F4, 0xDBD0, 0x88F5, 0xDBD1, 0x88F8, 0xD5A3, 0x88FD, 0xF0B2, 0x8907, 0xDCDC, 0x8910, 0xCAE8, + 0x8912, 0xF8E6, 0x8913, 0xDCCE, 0x8918, 0xEADC, 0x8919, 0xDBD2, 0x8925, 0xE9B3, 0x892A, 0xF7DB, 0x8936, 0xE3A8, 0x8938, 0xD7AE, + 0x893B, 0xE0E1, 0x8941, 0xCBBA, 0x8944, 0xE5D1, 0x895F, 0xD0DC, 0x8964, 0xD5C1, 0x896A, 0xD8CA, 0x8972, 0xE3A9, 0x897F, 0xE0A4, + 0x8981, 0xE9A9, 0x8983, 0xD3C7, 0x8986, 0xDCDD, 0x8987, 0xF8AE, 0x898B, 0xCCB8, 0x898F, 0xD0AE, 0x8993, 0xD8F2, 0x8996, 0xE3CA, + 0x89A1, 0xCCAF, 0x89A9, 0xD4AD, 0x89AA, 0xF6D1, 0x89B2, 0xD0CC, 0x89BA, 0xCAC6, 0x89BD, 0xD5C2, 0x89C0, 0xCEBA, 0x89D2, 0xCAC7, + 0x89E3, 0xFAB0, 0x89F4, 0xDFD8, 0x89F8, 0xF5BA, 0x8A00, 0xE5EB, 0x8A02, 0xEFF4, 0x8A03, 0xDDB5, 0x8A08, 0xCDAA, 0x8A0A, 0xE3F2, + 0x8A0C, 0xFBF7, 0x8A0E, 0xF7D0, 0x8A13, 0xFDBA, 0x8A16, 0xFDE1, 0x8A17, 0xF6FE, 0x8A18, 0xD1C0, 0x8A1B, 0xE8C5, 0x8A1D, 0xE4B8, + 0x8A1F, 0xE1E8, 0x8A23, 0xCCC1, 0x8A25, 0xD2ED, 0x8A2A, 0xDBBE, 0x8A2D, 0xE0E2, 0x8A31, 0xFAC9, 0x8A34, 0xE1CD, 0x8A36, 0xCAB8, + 0x8A3A, 0xF2E0, 0x8A3B, 0xF1C9, 0x8A50, 0xDEF1, 0x8A54, 0xF0DF, 0x8A55, 0xF8C4, 0x8A5B, 0xEECC, 0x8A5E, 0xDEF2, 0x8A60, 0xE7C9, + 0x8A62, 0xE2F3, 0x8A63, 0xE7E1, 0x8A66, 0xE3CB, 0x8A69, 0xE3CC, 0x8A6D, 0xCFF8, 0x8A6E, 0xEFAC, 0x8A70, 0xFDFE, 0x8A71, 0xFCA5, + 0x8A72, 0xFAB1, 0x8A73, 0xDFD9, 0x8A75, 0xE0D2, 0x8A79, 0xF4DA, 0x8A85, 0xF1CA, 0x8A87, 0xCEA3, 0x8A8C, 0xF2BC, 0x8A8D, 0xECE3, + 0x8A93, 0xE0A5, 0x8A95, 0xF7AB, 0x8A98, 0xEBAF, 0x8A9E, 0xE5DE, 0x8AA0, 0xE1A4, 0x8AA1, 0xCDAB, 0x8AA3, 0xD9F4, 0x8AA4, 0xE8A6, + 0x8AA5, 0xCDCE, 0x8AA6, 0xE1E9, 0x8AA8, 0xFCEF, 0x8AAA, 0xE0E3, 0x8AB0, 0xE2C1, 0x8AB2, 0xCEA4, 0x8AB9, 0xDEA6, 0x8ABC, 0xEBFE, + 0x8ABE, 0xEBDD, 0x8ABF, 0xF0E0, 0x8AC2, 0xF4DB, 0x8AC4, 0xE2F4, 0x8AC7, 0xD3C8, 0x8ACB, 0xF4EB, 0x8ACD, 0xEEB5, 0x8ACF, 0xF5D8, + 0x8AD2, 0xD5DF, 0x8AD6, 0xD6E5, 0x8ADB, 0xEBB0, 0x8ADC, 0xF4E3, 0x8AE1, 0xE3CD, 0x8AE6, 0xF4F4, 0x8AE7, 0xFAB2, 0x8AEA, 0xEFF5, + 0x8AEB, 0xCADF, 0x8AED, 0xEBB1, 0x8AEE, 0xEDBF, 0x8AF1, 0xFDC9, 0x8AF6, 0xE4A6, 0x8AF7, 0xF9A4, 0x8AF8, 0xF0B3, 0x8AFA, 0xE5EC, + 0x8AFE, 0xD1E7, 0x8B00, 0xD9C7, 0x8B01, 0xE4D7, 0x8B02, 0xEADD, 0x8B04, 0xD4F7, 0x8B0E, 0xDABA, 0x8B10, 0xDACD, 0x8B14, 0xF9CC, + 0x8B16, 0xE1DA, 0x8B17, 0xDBBF, 0x8B19, 0xCCC5, 0x8B1A, 0xECD0, 0x8B1B, 0xCBBB, 0x8B1D, 0xDEF3, 0x8B20, 0xE9AA, 0x8B28, 0xD9C8, + 0x8B2B, 0xEEE3, 0x8B2C, 0xD7BD, 0x8B33, 0xCFC4, 0x8B39, 0xD0CD, 0x8B41, 0xFCA6, 0x8B49, 0xF1FB, 0x8B4E, 0xFDD2, 0x8B4F, 0xD1C1, + 0x8B58, 0xE3DB, 0x8B5A, 0xD3C9, 0x8B5C, 0xDCCF, 0x8B66, 0xCCED, 0x8B6C, 0xDEA7, 0x8B6F, 0xE6BB, 0x8B70, 0xECA1, 0x8B74, 0xCCB9, + 0x8B77, 0xFBDE, 0x8B7D, 0xE7E2, 0x8B80, 0xD4C1, 0x8B8A, 0xDCA8, 0x8B90, 0xE2C2, 0x8B92, 0xF3D8, 0x8B93, 0xE5D3, 0x8B96, 0xF3D9, + 0x8B9A, 0xF3C6, 0x8C37, 0xCDDB, 0x8C3F, 0xCDAC, 0x8C41, 0xFCC3, 0x8C46, 0xD4E7, 0x8C48, 0xD1C2, 0x8C4A, 0xF9A5, 0x8C4C, 0xE8D5, + 0x8C55, 0xE3CE, 0x8C5A, 0xD4CA, 0x8C61, 0xDFDA, 0x8C6A, 0xFBDF, 0x8C6B, 0xE7E3, 0x8C79, 0xF8FB, 0x8C7A, 0xE3CF, 0x8C82, 0xF5B0, + 0x8C8A, 0xD8E7, 0x8C8C, 0xD9C9, 0x8C9D, 0xF8AF, 0x8C9E, 0xEFF6, 0x8CA0, 0xDDB6, 0x8CA1, 0xEEAF, 0x8CA2, 0xCDF8, 0x8CA7, 0xDEB8, + 0x8CA8, 0xFCA7, 0x8CA9, 0xF7FC, 0x8CAA, 0xF7B1, 0x8CAB, 0xCEBB, 0x8CAC, 0xF4A1, 0x8CAF, 0xEECD, 0x8CB0, 0xE1AE, 0x8CB3, 0xECC3, + 0x8CB4, 0xCFFE, 0x8CB6, 0xF8BF, 0x8CB7, 0xD8E2, 0x8CB8, 0xD3E8, 0x8CBB, 0xDEA8, 0x8CBC, 0xF4E4, 0x8CBD, 0xECC2, 0x8CBF, 0xD9F5, + 0x8CC0, 0xF9C5, 0x8CC1, 0xDDD3, 0x8CC2, 0xD6F1, 0x8CC3, 0xECFC, 0x8CC4, 0xFCF0, 0x8CC7, 0xEDC0, 0x8CC8, 0xCAB9, 0x8CCA, 0xEEE4, + 0x8CD1, 0xF2E1, 0x8CD3, 0xDEB9, 0x8CDA, 0xD6F2, 0x8CDC, 0xDEF4, 0x8CDE, 0xDFDB, 0x8CE0, 0xDBD3, 0x8CE2, 0xFAE7, 0x8CE3, 0xD8E3, + 0x8CE4, 0xF4C1, 0x8CE6, 0xDDB7, 0x8CEA, 0xF2F5, 0x8CED, 0xD4AE, 0x8CF4, 0xD6F3, 0x8CFB, 0xDDB8, 0x8CFC, 0xCFC5, 0x8CFD, 0xDFDF, + 0x8D04, 0xF2BE, 0x8D05, 0xF6A1, 0x8D07, 0xEBCB, 0x8D08, 0xF1FC, 0x8D0A, 0xF3C7, 0x8D0D, 0xE0EB, 0x8D13, 0xEDFC, 0x8D16, 0xE1DB, + 0x8D64, 0xEEE5, 0x8D66, 0xDEF5, 0x8D6B, 0xFAD3, 0x8D70, 0xF1CB, 0x8D73, 0xD0AF, 0x8D74, 0xDDB9, 0x8D77, 0xD1C3, 0x8D85, 0xF5B1, + 0x8D8A, 0xEAC6, 0x8D99, 0xF0E1, 0x8DA3, 0xF6AC, 0x8DA8, 0xF5D9, 0x8DB3, 0xF0EB, 0x8DBA, 0xDDBA, 0x8DBE, 0xF2BF, 0x8DC6, 0xF7C5, + 0x8DCB, 0xDBA2, 0x8DCC, 0xF2F6, 0x8DCF, 0xCABA, 0x8DDB, 0xF7F5, 0x8DDD, 0xCBE5, 0x8DE1, 0xEEE6, 0x8DE3, 0xE0D3, 0x8DE8, 0xCEA5, + 0x8DEF, 0xD6D8, 0x8DF3, 0xD4AF, 0x8E0A, 0xE9C9, 0x8E0F, 0xD3CE, 0x8E10, 0xF4C2, 0x8E1E, 0xCBE6, 0x8E2A, 0xF1A1, 0x8E30, 0xEBB2, + 0x8E35, 0xF1A2, 0x8E42, 0xEBB3, 0x8E44, 0xF0B4, 0x8E47, 0xCBF4, 0x8E48, 0xD4B0, 0x8E49, 0xF3B2, 0x8E4A, 0xFBB7, 0x8E59, 0xF5EC, + 0x8E5F, 0xEEE7, 0x8E60, 0xF4B2, 0x8E74, 0xF5ED, 0x8E76, 0xCFF3, 0x8E81, 0xF0E2, 0x8E87, 0xEECE, 0x8E8A, 0xF1CC, 0x8E8D, 0xE5B8, + 0x8EAA, 0xD7F5, 0x8EAB, 0xE3F3, 0x8EAC, 0xCFE5, 0x8EC0, 0xCFC6, 0x8ECA, 0xF3B3, 0x8ECB, 0xE4D8, 0x8ECC, 0xCFF9, 0x8ECD, 0xCFDA, + 0x8ED2, 0xFACD, 0x8EDF, 0xE6E3, 0x8EEB, 0xF2E2, 0x8EF8, 0xF5EE, 0x8EFB, 0xCABB, 0x8EFE, 0xE3DC, 0x8F03, 0xCEF2, 0x8F05, 0xD6D9, + 0x8F09, 0xEEB0, 0x8F12, 0xF4E5, 0x8F13, 0xD8C2, 0x8F14, 0xDCD0, 0x8F15, 0xCCEE, 0x8F1B, 0xD5E0, 0x8F1C, 0xF6CA, 0x8F1D, 0xFDCA, + 0x8F1E, 0xD8D6, 0x8F1F, 0xF4CF, 0x8F26, 0xD6A6, 0x8F27, 0xDCBE, 0x8F29, 0xDBD4, 0x8F2A, 0xD7C7, 0x8F2F, 0xF2FE, 0x8F33, 0xF1CD, + 0x8F38, 0xE2C3, 0x8F39, 0xDCDE, 0x8F3B, 0xDCDF, 0x8F3E, 0xEFAD, 0x8F3F, 0xE6AB, 0x8F44, 0xF9DD, 0x8F45, 0xEABF, 0x8F49, 0xEFAE, + 0x8F4D, 0xF4D0, 0x8F4E, 0xCEF3, 0x8F5D, 0xE6AC, 0x8F5F, 0xCEDE, 0x8F62, 0xD5F9, 0x8F9B, 0xE3F4, 0x8F9C, 0xCDD0, 0x8FA3, 0xD5B8, + 0x8FA6, 0xF7FD, 0x8FA8, 0xDCA9, 0x8FAD, 0xDEF6, 0x8FAF, 0xDCAA, 0x8FB0, 0xF2E3, 0x8FB1, 0xE9B4, 0x8FB2, 0xD2DC, 0x8FC2, 0xE9E6, + 0x8FC5, 0xE3F6, 0x8FCE, 0xE7CA, 0x8FD1, 0xD0CE, 0x8FD4, 0xDAF7, 0x8FE6, 0xCABC, 0x8FEA, 0xEEE8, 0x8FEB, 0xDADE, 0x8FED, 0xF2F7, + 0x8FF0, 0xE2FB, 0x8FF2, 0xCCA6, 0x8FF7, 0xDABB, 0x8FF9, 0xEEE9, 0x8FFD, 0xF5DA, 0x9000, 0xF7DC, 0x9001, 0xE1EA, 0x9002, 0xCEC1, + 0x9003, 0xD4B1, 0x9005, 0xFDB1, 0x9006, 0xE6BD, 0x9008, 0xFBAD, 0x900B, 0xF8E7, 0x900D, 0xE1CE, 0x900F, 0xF7E2, 0x9010, 0xF5EF, + 0x9011, 0xCFC7, 0x9014, 0xD4B2, 0x9015, 0xCCEF, 0x9017, 0xD4E8, 0x9019, 0xEECF, 0x901A, 0xF7D7, 0x901D, 0xE0A6, 0x901E, 0xD6C1, + 0x901F, 0xE1DC, 0x9020, 0xF0E3, 0x9021, 0xF1E4, 0x9022, 0xDCF1, 0x9023, 0xD6A7, 0x902E, 0xF4F5, 0x9031, 0xF1CE, 0x9032, 0xF2E4, + 0x9035, 0xD0B0, 0x9038, 0xECEF, 0x903C, 0xF9BA, 0x903E, 0xEBB5, 0x9041, 0xD4ED, 0x9042, 0xE2C4, 0x9047, 0xE9E7, 0x904A, 0xEBB4, + 0x904B, 0xEAA1, 0x904D, 0xF8BC, 0x904E, 0xCEA6, 0x9050, 0xF9C6, 0x9051, 0xFCDA, 0x9053, 0xD4B3, 0x9054, 0xD3B9, 0x9055, 0xEADE, + 0x9059, 0xE9AB, 0x905C, 0xE1E1, 0x905D, 0xD3CF, 0x905E, 0xF4F6, 0x9060, 0xEAC0, 0x9061, 0xE1CF, 0x9063, 0xCCBA, 0x9069, 0xEEEA, + 0x906D, 0xF0E4, 0x906E, 0xF3B4, 0x906F, 0xD4EE, 0x9072, 0xF2C0, 0x9075, 0xF1E5, 0x9077, 0xF4C3, 0x9078, 0xE0D4, 0x907A, 0xEBB6, + 0x907C, 0xD7A1, 0x907D, 0xCBE8, 0x907F, 0xF9AD, 0x9080, 0xE9AD, 0x9081, 0xD8E4, 0x9082, 0xFAB3, 0x9083, 0xE2C5, 0x9084, 0xFCBD, + 0x9087, 0xECC4, 0x9088, 0xD8B1, 0x908A, 0xDCAB, 0x908F, 0xD5A4, 0x9091, 0xEBE9, 0x9095, 0xE8BB, 0x9099, 0xD8D7, 0x90A2, 0xFBAE, + 0x90A3, 0xD1E1, 0x90A6, 0xDBC0, 0x90A8, 0xF5BE, 0x90AA, 0xDEF7, 0x90AF, 0xCAFB, 0x90B0, 0xF7C6, 0x90B1, 0xCFC8, 0x90B5, 0xE1D0, + 0x90B8, 0xEED0, 0x90C1, 0xE9F4, 0x90CA, 0xCEF4, 0x90DE, 0xD5CD, 0x90E1, 0xCFDB, 0x90E8, 0xDDBB, 0x90ED, 0xCEAC, 0x90F5, 0xE9E8, + 0x90FD, 0xD4B4, 0x9102, 0xE4C7, 0x9112, 0xF5DB, 0x9115, 0xFAC1, 0x9119, 0xDEA9, 0x9127, 0xD4F8, 0x912D, 0xEFF7, 0x9132, 0xD3B3, + 0x9149, 0xEBB7, 0x914A, 0xEFF8, 0x914B, 0xF5DC, 0x914C, 0xEDCC, 0x914D, 0xDBD5, 0x914E, 0xF1CF, 0x9152, 0xF1D0, 0x9162, 0xF5B2, + 0x9169, 0xD9AE, 0x916A, 0xD5AC, 0x916C, 0xE2C6, 0x9175, 0xFDA3, 0x9177, 0xFBE5, 0x9178, 0xDFAB, 0x9187, 0xE2F5, 0x9189, 0xF6AD, + 0x918B, 0xF5B3, 0x918D, 0xF0B5, 0x9192, 0xE1A5, 0x919C, 0xF5DD, 0x91AB, 0xECA2, 0x91AC, 0xEDFD, 0x91AE, 0xF5B4, 0x91AF, 0xFBB8, + 0x91B1, 0xDBA3, 0x91B4, 0xD6CA, 0x91B5, 0xCBD9, 0x91C0, 0xE5D4, 0x91C7, 0xF3FA, 0x91C9, 0xEBB8, 0x91CB, 0xE0B7, 0x91CC, 0xD7EC, + 0x91CD, 0xF1EC, 0x91CE, 0xE5AF, 0x91CF, 0xD5E1, 0x91D0, 0xD7ED, 0x91D1, 0xD1D1, 0x91D7, 0xE1F2, 0x91D8, 0xEFF9, 0x91DC, 0xDDBC, + 0x91DD, 0xF6DC, 0x91E3, 0xF0E5, 0x91E7, 0xF4C4, 0x91EA, 0xE9E9, 0x91F5, 0xF3FB, 0x920D, 0xD4EF, 0x9210, 0xCCA2, 0x9211, 0xF7FE, + 0x9212, 0xDFBC, 0x9217, 0xEBCD, 0x921E, 0xD0B7, 0x9234, 0xD6C2, 0x923A, 0xE8AD, 0x923F, 0xEFAF, 0x9240, 0xCBA5, 0x9245, 0xCBE9, + 0x9249, 0xFAE8, 0x9257, 0xCCC6, 0x925B, 0xE6E7, 0x925E, 0xEAC7, 0x9262, 0xDBA4, 0x9264, 0xCFC9, 0x9265, 0xE2FC, 0x9266, 0xEFFA, + 0x9280, 0xEBDE, 0x9283, 0xF5C8, 0x9285, 0xD4DE, 0x9291, 0xE0D5, 0x9293, 0xEFB0, 0x9296, 0xE2C7, 0x9298, 0xD9AF, 0x929C, 0xF9E7, + 0x92B3, 0xE7E5, 0x92B6, 0xCFCA, 0x92B7, 0xE1D1, 0x92B9, 0xE2C8, 0x92CC, 0xEFFB, 0x92CF, 0xFAF9, 0x92D2, 0xDCF2, 0x92E4, 0xE0A7, + 0x92EA, 0xF8E8, 0x92F8, 0xCBEA, 0x92FC, 0xCBBC, 0x9304, 0xD6E2, 0x9310, 0xF5DE, 0x9318, 0xF5DF, 0x931A, 0xEEB6, 0x931E, 0xE2F6, + 0x931F, 0xD3CA, 0x9320, 0xEFFC, 0x9321, 0xD1C4, 0x9322, 0xEFB1, 0x9324, 0xD1C5, 0x9326, 0xD0DE, 0x9328, 0xD9E1, 0x932B, 0xE0B8, + 0x932E, 0xCDD1, 0x932F, 0xF3B9, 0x9348, 0xE7CC, 0x934A, 0xD6A8, 0x934B, 0xCEA7, 0x934D, 0xD4B5, 0x9354, 0xE4C8, 0x935B, 0xD3B4, + 0x936E, 0xEBB9, 0x9375, 0xCBF5, 0x937C, 0xF6DD, 0x937E, 0xF1A3, 0x938C, 0xCCC7, 0x9394, 0xE9CA, 0x9396, 0xE1F0, 0x939A, 0xF5E0, + 0x93A3, 0xFBAF, 0x93A7, 0xCBD1, 0x93AC, 0xFBE0, 0x93AD, 0xF2E5, 0x93B0, 0xECF0, 0x93C3, 0xF0EC, 0x93D1, 0xEEEB, 0x93DE, 0xE9CB, + 0x93E1, 0xCCF0, 0x93E4, 0xD7AF, 0x93F6, 0xF3A1, 0x9404, 0xFCF5, 0x9418, 0xF1A4, 0x9425, 0xE0D6, 0x942B, 0xEFB2, 0x9435, 0xF4D1, + 0x9438, 0xF7A1, 0x9444, 0xF1D1, 0x9451, 0xCAFC, 0x9452, 0xCAFD, 0x945B, 0xCECE, 0x947D, 0xF3C8, 0x947F, 0xF3BA, 0x9577, 0xEDFE, + 0x9580, 0xDAA6, 0x9583, 0xE0EC, 0x9589, 0xF8CD, 0x958B, 0xCBD2, 0x958F, 0xEBCE, 0x9591, 0xF9D8, 0x9592, 0xF9D9, 0x9593, 0xCAE0, + 0x9594, 0xDACA, 0x9598, 0xCBA6, 0x95A3, 0xCAC8, 0x95A4, 0xF9EE, 0x95A5, 0xDBEC, 0x95A8, 0xD0B1, 0x95AD, 0xD5EF, 0x95B1, 0xE6F3, + 0x95BB, 0xE7A2, 0x95BC, 0xE4D9, 0x95C7, 0xE4E1, 0x95CA, 0xFCC4, 0x95D4, 0xF9EF, 0x95D5, 0xCFF4, 0x95D6, 0xF7E6, 0x95DC, 0xCEBC, + 0x95E1, 0xF4C5, 0x95E2, 0xDCA3, 0x961C, 0xDDBD, 0x9621, 0xF4C6, 0x962A, 0xF8A1, 0x962E, 0xE8D6, 0x9632, 0xDBC1, 0x963B, 0xF0E6, + 0x963F, 0xE4B9, 0x9640, 0xF6ED, 0x9642, 0xF9AE, 0x9644, 0xDDBE, 0x964B, 0xD7B0, 0x964C, 0xD8E8, 0x964D, 0xCBBD, 0x9650, 0xF9DA, + 0x965B, 0xF8CE, 0x965C, 0xF9F0, 0x965D, 0xE0ED, 0x965E, 0xE3B3, 0x965F, 0xF4B3, 0x9662, 0xEAC2, 0x9663, 0xF2E6, 0x9664, 0xF0B6, + 0x966A, 0xDBD6, 0x9670, 0xEBE4, 0x9673, 0xF2E7, 0x9675, 0xD7D5, 0x9676, 0xD4B6, 0x9677, 0xF9E8, 0x9678, 0xD7C1, 0x967D, 0xE5D5, + 0x9685, 0xE9EA, 0x9686, 0xD7CC, 0x968A, 0xD3E9, 0x968B, 0xE2C9, 0x968D, 0xFCDB, 0x968E, 0xCDAD, 0x9694, 0xCCB0, 0x9695, 0xEAA2, + 0x9698, 0xE4F6, 0x9699, 0xD0C0, 0x969B, 0xF0B7, 0x969C, 0xEEA1, 0x96A3, 0xD7F6, 0x96A7, 0xE2CA, 0x96A8, 0xE2CB, 0x96AA, 0xFACF, + 0x96B1, 0xEBDF, 0x96B7, 0xD6CB, 0x96BB, 0xF4B4, 0x96C0, 0xEDCD, 0x96C1, 0xE4D2, 0x96C4, 0xEAA9, 0x96C5, 0xE4BA, 0x96C6, 0xF3A2, + 0x96C7, 0xCDD2, 0x96C9, 0xF6CB, 0x96CB, 0xF1E6, 0x96CC, 0xEDC1, 0x96CD, 0xE8BC, 0x96CE, 0xEED1, 0x96D5, 0xF0E7, 0x96D6, 0xE2CC, + 0x96D9, 0xE4AA, 0x96DB, 0xF5E1, 0x96DC, 0xEDDA, 0x96E2, 0xD7EE, 0x96E3, 0xD1F1, 0x96E8, 0xE9EB, 0x96E9, 0xE9EC, 0x96EA, 0xE0E4, + 0x96EF, 0xDAA7, 0x96F0, 0xDDD4, 0x96F2, 0xEAA3, 0x96F6, 0xD6C3, 0x96F7, 0xD6F4, 0x96F9, 0xDADF, 0x96FB, 0xEFB3, 0x9700, 0xE2CD, + 0x9706, 0xEFFD, 0x9707, 0xF2E8, 0x9711, 0xEFC5, 0x9713, 0xE7E7, 0x9716, 0xD7FD, 0x9719, 0xE7CE, 0x971C, 0xDFDC, 0x971E, 0xF9C7, + 0x9727, 0xD9F6, 0x9730, 0xDFAC, 0x9732, 0xD6DA, 0x9739, 0xDCA4, 0x973D, 0xF0B8, 0x9742, 0xD5FA, 0x9744, 0xE4F7, 0x9748, 0xD6C4, + 0x9751, 0xF4EC, 0x9756, 0xEFFE, 0x975C, 0xF0A1, 0x975E, 0xDEAA, 0x9761, 0xDABC, 0x9762, 0xD8FC, 0x9769, 0xFAD4, 0x976D, 0xECE5, + 0x9774, 0xFCA8, 0x9777, 0xECE6, 0x977A, 0xD8CB, 0x978B, 0xFBB9, 0x978D, 0xE4D3, 0x978F, 0xCDF9, 0x97A0, 0xCFD3, 0x97A8, 0xCAEA, + 0x97AB, 0xCFD4, 0x97AD, 0xF8BD, 0x97C6, 0xF4C7, 0x97CB, 0xEADF, 0x97D3, 0xF9DB, 0x97DC, 0xD4B7, 0x97F3, 0xEBE5, 0x97F6, 0xE1D2, + 0x97FB, 0xEAA4, 0x97FF, 0xFAC2, 0x9800, 0xFBE1, 0x9801, 0xFAED, 0x9802, 0xF0A2, 0x9803, 0xCCF1, 0x9805, 0xFAA3, 0x9806, 0xE2F7, + 0x9808, 0xE2CE, 0x980A, 0xE9F5, 0x980C, 0xE1EB, 0x9810, 0xE7E8, 0x9811, 0xE8D7, 0x9812, 0xDAF8, 0x9813, 0xD4CB, 0x9817, 0xF7F6, + 0x9818, 0xD6C5, 0x982D, 0xD4E9, 0x9830, 0xFAFA, 0x9838, 0xCCF2, 0x9839, 0xF7DD, 0x983B, 0xDEBA, 0x9846, 0xCEA8, 0x984C, 0xF0B9, + 0x984D, 0xE4FE, 0x984E, 0xE4C9, 0x9854, 0xE4D4, 0x9858, 0xEAC3, 0x985A, 0xEFB4, 0x985E, 0xD7BE, 0x9865, 0xFBE2, 0x9867, 0xCDD3, + 0x986B, 0xEFB5, 0x986F, 0xFAE9, 0x98A8, 0xF9A6, 0x98AF, 0xDFBD, 0x98B1, 0xF7C7, 0x98C4, 0xF8FD, 0x98C7, 0xF8FC, 0x98DB, 0xDEAB, + 0x98DC, 0xDBE8, 0x98DF, 0xE3DD, 0x98E1, 0xE1E2, 0x98E2, 0xD1C6, 0x98ED, 0xF6D0, 0x98EE, 0xEBE6, 0x98EF, 0xDAF9, 0x98F4, 0xECC7, + 0x98FC, 0xDEF8, 0x98FD, 0xF8E9, 0x98FE, 0xE3DE, 0x9903, 0xCEF5, 0x9909, 0xFAC3, 0x990A, 0xE5D7, 0x990C, 0xECC8, 0x9910, 0xF3C9, + 0x9913, 0xE4BB, 0x9918, 0xE6AE, 0x991E, 0xEFB6, 0x9920, 0xDCBF, 0x9928, 0xCEBD, 0x9945, 0xD8C3, 0x9949, 0xD0CF, 0x994B, 0xCFFA, + 0x994C, 0xF3CA, 0x994D, 0xE0D7, 0x9951, 0xD1C7, 0x9952, 0xE9AE, 0x9954, 0xE8BD, 0x9957, 0xFAC4, 0x9996, 0xE2CF, 0x9999, 0xFAC5, + 0x999D, 0xF9B8, 0x99A5, 0xDCE0, 0x99A8, 0xFBB0, 0x99AC, 0xD8A9, 0x99AD, 0xE5DF, 0x99AE, 0xF9A7, 0x99B1, 0xF6EE, 0x99B3, 0xF6CC, + 0x99B4, 0xE2F8, 0x99B9, 0xECF1, 0x99C1, 0xDAE0, 0x99D0, 0xF1D2, 0x99D1, 0xD2CC, 0x99D2, 0xCFCB, 0x99D5, 0xCABD, 0x99D9, 0xDDBF, + 0x99DD, 0xF6EF, 0x99DF, 0xDEF9, 0x99ED, 0xFAB4, 0x99F1, 0xD5AD, 0x99FF, 0xF1E7, 0x9A01, 0xDEBE, 0x9A08, 0xDCC0, 0x9A0E, 0xD1C8, + 0x9A0F, 0xD1C9, 0x9A19, 0xF8BE, 0x9A2B, 0xCBF6, 0x9A30, 0xD4F9, 0x9A36, 0xF5E2, 0x9A37, 0xE1D3, 0x9A40, 0xD8E9, 0x9A43, 0xF8FE, + 0x9A45, 0xCFCC, 0x9A4D, 0xFDA4, 0x9A55, 0xCEF6, 0x9A57, 0xFAD0, 0x9A5A, 0xCCF3, 0x9A5B, 0xE6BE, 0x9A5F, 0xF6AE, 0x9A62, 0xD5F0, + 0x9A65, 0xD1CA, 0x9A69, 0xFCBE, 0x9A6A, 0xD5F1, 0x9AA8, 0xCDE9, 0x9AB8, 0xFAB5, 0x9AD3, 0xE2D0, 0x9AD4, 0xF4F7, 0x9AD8, 0xCDD4, + 0x9AE5, 0xE7A3, 0x9AEE, 0xDBA5, 0x9B1A, 0xE2D1, 0x9B27, 0xD7A2, 0x9B2A, 0xF7E3, 0x9B31, 0xEAA6, 0x9B3C, 0xD0A1, 0x9B41, 0xCEDA, + 0x9B42, 0xFBEB, 0x9B43, 0xDBA6, 0x9B44, 0xDBDE, 0x9B45, 0xD8E5, 0x9B4F, 0xEAE0, 0x9B54, 0xD8AA, 0x9B5A, 0xE5E0, 0x9B6F, 0xD6DB, + 0x9B8E, 0xEFC6, 0x9B91, 0xF8EA, 0x9B9F, 0xE4D5, 0x9BAB, 0xCEF7, 0x9BAE, 0xE0D8, 0x9BC9, 0xD7EF, 0x9BD6, 0xF4ED, 0x9BE4, 0xCDE6, + 0x9BE8, 0xCCF4, 0x9C0D, 0xF5E3, 0x9C10, 0xE4CA, 0x9C12, 0xDCE1, 0x9C15, 0xF9C8, 0x9C25, 0xFCBF, 0x9C32, 0xE8A7, 0x9C3B, 0xD8C4, + 0x9C47, 0xCBBE, 0x9C49, 0xDCAE, 0x9C57, 0xD7F7, 0x9CE5, 0xF0E8, 0x9CE7, 0xDDC0, 0x9CE9, 0xCFCD, 0x9CF3, 0xDCF3, 0x9CF4, 0xD9B0, + 0x9CF6, 0xE6E9, 0x9D09, 0xE4BC, 0x9D1B, 0xEAC4, 0x9D26, 0xE4EC, 0x9D28, 0xE4E5, 0x9D3B, 0xFBF8, 0x9D51, 0xCCBB, 0x9D5D, 0xE4BD, + 0x9D60, 0xCDDC, 0x9D61, 0xD9F7, 0x9D6C, 0xDDDF, 0x9D72, 0xEDCE, 0x9DA9, 0xD9D0, 0x9DAF, 0xE5A3, 0x9DB4, 0xF9CD, 0x9DC4, 0xCDAE, + 0x9DD7, 0xCFCE, 0x9DF2, 0xF6AF, 0x9DF8, 0xFDD3, 0x9DF9, 0xEBED, 0x9DFA, 0xD6DC, 0x9E1A, 0xE5A4, 0x9E1E, 0xD5B6, 0x9E75, 0xD6DD, + 0x9E79, 0xF9E9, 0x9E7D, 0xE7A4, 0x9E7F, 0xD6E3, 0x9E92, 0xD1CB, 0x9E93, 0xD6E4, 0x9E97, 0xD5F2, 0x9E9D, 0xDEFA, 0x9E9F, 0xD7F8, + 0x9EA5, 0xD8EA, 0x9EB4, 0xCFD5, 0x9EB5, 0xD8FD, 0x9EBB, 0xD8AB, 0x9EBE, 0xFDCB, 0x9EC3, 0xFCDC, 0x9ECD, 0xE0A8, 0x9ECE, 0xD5F3, + 0x9ED1, 0xFDD9, 0x9ED4, 0xCCA3, 0x9ED8, 0xD9F9, 0x9EDB, 0xD3EA, 0x9EDC, 0xF5F5, 0x9EDE, 0xEFC7, 0x9EE8, 0xD3DA, 0x9EF4, 0xDABD, + 0x9F07, 0xE8A8, 0x9F08, 0xDCAF, 0x9F0E, 0xF0A3, 0x9F13, 0xCDD5, 0x9F20, 0xE0A9, 0x9F3B, 0xDEAC, 0x9F4A, 0xF0BA, 0x9F4B, 0xEEB1, + 0x9F4E, 0xEEB2, 0x9F52, 0xF6CD, 0x9F5F, 0xEED2, 0x9F61, 0xD6C6, 0x9F67, 0xE0E5, 0x9F6A, 0xF3BB, 0x9F6C, 0xE5E1, 0x9F77, 0xE4CB, + 0x9F8D, 0xD7A3, 0x9F90, 0xDBC2, 0x9F95, 0xCAFE, 0x9F9C, 0xCFCF, 0xAC00, 0xB0A1, 0xAC01, 0xB0A2, 0xAC02, 0x8141, 0xAC03, 0x8142, + 0xAC04, 0xB0A3, 0xAC05, 0x8143, 0xAC06, 0x8144, 0xAC07, 0xB0A4, 0xAC08, 0xB0A5, 0xAC09, 0xB0A6, 0xAC0A, 0xB0A7, 0xAC0B, 0x8145, + 0xAC0C, 0x8146, 0xAC0D, 0x8147, 0xAC0E, 0x8148, 0xAC0F, 0x8149, 0xAC10, 0xB0A8, 0xAC11, 0xB0A9, 0xAC12, 0xB0AA, 0xAC13, 0xB0AB, + 0xAC14, 0xB0AC, 0xAC15, 0xB0AD, 0xAC16, 0xB0AE, 0xAC17, 0xB0AF, 0xAC18, 0x814A, 0xAC19, 0xB0B0, 0xAC1A, 0xB0B1, 0xAC1B, 0xB0B2, + 0xAC1C, 0xB0B3, 0xAC1D, 0xB0B4, 0xAC1E, 0x814B, 0xAC1F, 0x814C, 0xAC20, 0xB0B5, 0xAC21, 0x814D, 0xAC22, 0x814E, 0xAC23, 0x814F, + 0xAC24, 0xB0B6, 0xAC25, 0x8150, 0xAC26, 0x8151, 0xAC27, 0x8152, 0xAC28, 0x8153, 0xAC29, 0x8154, 0xAC2A, 0x8155, 0xAC2B, 0x8156, + 0xAC2C, 0xB0B7, 0xAC2D, 0xB0B8, 0xAC2E, 0x8157, 0xAC2F, 0xB0B9, 0xAC30, 0xB0BA, 0xAC31, 0xB0BB, 0xAC32, 0x8158, 0xAC33, 0x8159, + 0xAC34, 0x815A, 0xAC35, 0x8161, 0xAC36, 0x8162, 0xAC37, 0x8163, 0xAC38, 0xB0BC, 0xAC39, 0xB0BD, 0xAC3A, 0x8164, 0xAC3B, 0x8165, + 0xAC3C, 0xB0BE, 0xAC3D, 0x8166, 0xAC3E, 0x8167, 0xAC3F, 0x8168, 0xAC40, 0xB0BF, 0xAC41, 0x8169, 0xAC42, 0x816A, 0xAC43, 0x816B, + 0xAC44, 0x816C, 0xAC45, 0x816D, 0xAC46, 0x816E, 0xAC47, 0x816F, 0xAC48, 0x8170, 0xAC49, 0x8171, 0xAC4A, 0x8172, 0xAC4B, 0xB0C0, + 0xAC4C, 0x8173, 0xAC4D, 0xB0C1, 0xAC4E, 0x8174, 0xAC4F, 0x8175, 0xAC50, 0x8176, 0xAC51, 0x8177, 0xAC52, 0x8178, 0xAC53, 0x8179, + 0xAC54, 0xB0C2, 0xAC55, 0x817A, 0xAC56, 0x8181, 0xAC57, 0x8182, 0xAC58, 0xB0C3, 0xAC59, 0x8183, 0xAC5A, 0x8184, 0xAC5B, 0x8185, + 0xAC5C, 0xB0C4, 0xAC5D, 0x8186, 0xAC5E, 0x8187, 0xAC5F, 0x8188, 0xAC60, 0x8189, 0xAC61, 0x818A, 0xAC62, 0x818B, 0xAC63, 0x818C, + 0xAC64, 0x818D, 0xAC65, 0x818E, 0xAC66, 0x818F, 0xAC67, 0x8190, 0xAC68, 0x8191, 0xAC69, 0x8192, 0xAC6A, 0x8193, 0xAC6B, 0x8194, + 0xAC6C, 0x8195, 0xAC6D, 0x8196, 0xAC6E, 0x8197, 0xAC6F, 0x8198, 0xAC70, 0xB0C5, 0xAC71, 0xB0C6, 0xAC72, 0x8199, 0xAC73, 0x819A, + 0xAC74, 0xB0C7, 0xAC75, 0x819B, 0xAC76, 0x819C, 0xAC77, 0xB0C8, 0xAC78, 0xB0C9, 0xAC79, 0x819D, 0xAC7A, 0xB0CA, 0xAC7B, 0x819E, + 0xAC7C, 0x819F, 0xAC7D, 0x81A0, 0xAC7E, 0x81A1, 0xAC7F, 0x81A2, 0xAC80, 0xB0CB, 0xAC81, 0xB0CC, 0xAC82, 0x81A3, 0xAC83, 0xB0CD, + 0xAC84, 0xB0CE, 0xAC85, 0xB0CF, 0xAC86, 0xB0D0, 0xAC87, 0x81A4, 0xAC88, 0x81A5, 0xAC89, 0xB0D1, 0xAC8A, 0xB0D2, 0xAC8B, 0xB0D3, + 0xAC8C, 0xB0D4, 0xAC8D, 0x81A6, 0xAC8E, 0x81A7, 0xAC8F, 0x81A8, 0xAC90, 0xB0D5, 0xAC91, 0x81A9, 0xAC92, 0x81AA, 0xAC93, 0x81AB, + 0xAC94, 0xB0D6, 0xAC95, 0x81AC, 0xAC96, 0x81AD, 0xAC97, 0x81AE, 0xAC98, 0x81AF, 0xAC99, 0x81B0, 0xAC9A, 0x81B1, 0xAC9B, 0x81B2, + 0xAC9C, 0xB0D7, 0xAC9D, 0xB0D8, 0xAC9E, 0x81B3, 0xAC9F, 0xB0D9, 0xACA0, 0xB0DA, 0xACA1, 0xB0DB, 0xACA2, 0x81B4, 0xACA3, 0x81B5, + 0xACA4, 0x81B6, 0xACA5, 0x81B7, 0xACA6, 0x81B8, 0xACA7, 0x81B9, 0xACA8, 0xB0DC, 0xACA9, 0xB0DD, 0xACAA, 0xB0DE, 0xACAB, 0x81BA, + 0xACAC, 0xB0DF, 0xACAD, 0x81BB, 0xACAE, 0x81BC, 0xACAF, 0xB0E0, 0xACB0, 0xB0E1, 0xACB1, 0x81BD, 0xACB2, 0x81BE, 0xACB3, 0x81BF, + 0xACB4, 0x81C0, 0xACB5, 0x81C1, 0xACB6, 0x81C2, 0xACB7, 0x81C3, 0xACB8, 0xB0E2, 0xACB9, 0xB0E3, 0xACBA, 0x81C4, 0xACBB, 0xB0E4, + 0xACBC, 0xB0E5, 0xACBD, 0xB0E6, 0xACBE, 0x81C5, 0xACBF, 0x81C6, 0xACC0, 0x81C7, 0xACC1, 0xB0E7, 0xACC2, 0x81C8, 0xACC3, 0x81C9, + 0xACC4, 0xB0E8, 0xACC5, 0x81CA, 0xACC6, 0x81CB, 0xACC7, 0x81CC, 0xACC8, 0xB0E9, 0xACC9, 0x81CD, 0xACCA, 0x81CE, 0xACCB, 0x81CF, + 0xACCC, 0xB0EA, 0xACCD, 0x81D0, 0xACCE, 0x81D1, 0xACCF, 0x81D2, 0xACD0, 0x81D3, 0xACD1, 0x81D4, 0xACD2, 0x81D5, 0xACD3, 0x81D6, + 0xACD4, 0x81D7, 0xACD5, 0xB0EB, 0xACD6, 0x81D8, 0xACD7, 0xB0EC, 0xACD8, 0x81D9, 0xACD9, 0x81DA, 0xACDA, 0x81DB, 0xACDB, 0x81DC, + 0xACDC, 0x81DD, 0xACDD, 0x81DE, 0xACDE, 0x81DF, 0xACDF, 0x81E0, 0xACE0, 0xB0ED, 0xACE1, 0xB0EE, 0xACE2, 0x81E1, 0xACE3, 0x81E2, + 0xACE4, 0xB0EF, 0xACE5, 0x81E3, 0xACE6, 0x81E4, 0xACE7, 0xB0F0, 0xACE8, 0xB0F1, 0xACE9, 0x81E5, 0xACEA, 0xB0F2, 0xACEB, 0x81E6, + 0xACEC, 0xB0F3, 0xACED, 0x81E7, 0xACEE, 0x81E8, 0xACEF, 0xB0F4, 0xACF0, 0xB0F5, 0xACF1, 0xB0F6, 0xACF2, 0x81E9, 0xACF3, 0xB0F7, + 0xACF4, 0x81EA, 0xACF5, 0xB0F8, 0xACF6, 0xB0F9, 0xACF7, 0x81EB, 0xACF8, 0x81EC, 0xACF9, 0x81ED, 0xACFA, 0x81EE, 0xACFB, 0x81EF, + 0xACFC, 0xB0FA, 0xACFD, 0xB0FB, 0xACFE, 0x81F0, 0xACFF, 0x81F1, 0xAD00, 0xB0FC, 0xAD01, 0x81F2, 0xAD02, 0x81F3, 0xAD03, 0x81F4, + 0xAD04, 0xB0FD, 0xAD05, 0x81F5, 0xAD06, 0xB0FE, 0xAD07, 0x81F6, 0xAD08, 0x81F7, 0xAD09, 0x81F8, 0xAD0A, 0x81F9, 0xAD0B, 0x81FA, + 0xAD0C, 0xB1A1, 0xAD0D, 0xB1A2, 0xAD0E, 0x81FB, 0xAD0F, 0xB1A3, 0xAD10, 0x81FC, 0xAD11, 0xB1A4, 0xAD12, 0x81FD, 0xAD13, 0x81FE, + 0xAD14, 0x8241, 0xAD15, 0x8242, 0xAD16, 0x8243, 0xAD17, 0x8244, 0xAD18, 0xB1A5, 0xAD19, 0x8245, 0xAD1A, 0x8246, 0xAD1B, 0x8247, + 0xAD1C, 0xB1A6, 0xAD1D, 0x8248, 0xAD1E, 0x8249, 0xAD1F, 0x824A, 0xAD20, 0xB1A7, 0xAD21, 0x824B, 0xAD22, 0x824C, 0xAD23, 0x824D, + 0xAD24, 0x824E, 0xAD25, 0x824F, 0xAD26, 0x8250, 0xAD27, 0x8251, 0xAD28, 0x8252, 0xAD29, 0xB1A8, 0xAD2A, 0x8253, 0xAD2B, 0x8254, + 0xAD2C, 0xB1A9, 0xAD2D, 0xB1AA, 0xAD2E, 0x8255, 0xAD2F, 0x8256, 0xAD30, 0x8257, 0xAD31, 0x8258, 0xAD32, 0x8259, 0xAD33, 0x825A, + 0xAD34, 0xB1AB, 0xAD35, 0xB1AC, 0xAD36, 0x8261, 0xAD37, 0x8262, 0xAD38, 0xB1AD, 0xAD39, 0x8263, 0xAD3A, 0x8264, 0xAD3B, 0x8265, + 0xAD3C, 0xB1AE, 0xAD3D, 0x8266, 0xAD3E, 0x8267, 0xAD3F, 0x8268, 0xAD40, 0x8269, 0xAD41, 0x826A, 0xAD42, 0x826B, 0xAD43, 0x826C, + 0xAD44, 0xB1AF, 0xAD45, 0xB1B0, 0xAD46, 0x826D, 0xAD47, 0xB1B1, 0xAD48, 0x826E, 0xAD49, 0xB1B2, 0xAD4A, 0x826F, 0xAD4B, 0x8270, + 0xAD4C, 0x8271, 0xAD4D, 0x8272, 0xAD4E, 0x8273, 0xAD4F, 0x8274, 0xAD50, 0xB1B3, 0xAD51, 0x8275, 0xAD52, 0x8276, 0xAD53, 0x8277, + 0xAD54, 0xB1B4, 0xAD55, 0x8278, 0xAD56, 0x8279, 0xAD57, 0x827A, 0xAD58, 0xB1B5, 0xAD59, 0x8281, 0xAD5A, 0x8282, 0xAD5B, 0x8283, + 0xAD5C, 0x8284, 0xAD5D, 0x8285, 0xAD5E, 0x8286, 0xAD5F, 0x8287, 0xAD60, 0x8288, 0xAD61, 0xB1B6, 0xAD62, 0x8289, 0xAD63, 0xB1B7, + 0xAD64, 0x828A, 0xAD65, 0x828B, 0xAD66, 0x828C, 0xAD67, 0x828D, 0xAD68, 0x828E, 0xAD69, 0x828F, 0xAD6A, 0x8290, 0xAD6B, 0x8291, + 0xAD6C, 0xB1B8, 0xAD6D, 0xB1B9, 0xAD6E, 0x8292, 0xAD6F, 0x8293, 0xAD70, 0xB1BA, 0xAD71, 0x8294, 0xAD72, 0x8295, 0xAD73, 0xB1BB, + 0xAD74, 0xB1BC, 0xAD75, 0xB1BD, 0xAD76, 0xB1BE, 0xAD77, 0x8296, 0xAD78, 0x8297, 0xAD79, 0x8298, 0xAD7A, 0x8299, 0xAD7B, 0xB1BF, + 0xAD7C, 0xB1C0, 0xAD7D, 0xB1C1, 0xAD7E, 0x829A, 0xAD7F, 0xB1C2, 0xAD80, 0x829B, 0xAD81, 0xB1C3, 0xAD82, 0xB1C4, 0xAD83, 0x829C, + 0xAD84, 0x829D, 0xAD85, 0x829E, 0xAD86, 0x829F, 0xAD87, 0x82A0, 0xAD88, 0xB1C5, 0xAD89, 0xB1C6, 0xAD8A, 0x82A1, 0xAD8B, 0x82A2, + 0xAD8C, 0xB1C7, 0xAD8D, 0x82A3, 0xAD8E, 0x82A4, 0xAD8F, 0x82A5, 0xAD90, 0xB1C8, 0xAD91, 0x82A6, 0xAD92, 0x82A7, 0xAD93, 0x82A8, + 0xAD94, 0x82A9, 0xAD95, 0x82AA, 0xAD96, 0x82AB, 0xAD97, 0x82AC, 0xAD98, 0x82AD, 0xAD99, 0x82AE, 0xAD9A, 0x82AF, 0xAD9B, 0x82B0, + 0xAD9C, 0xB1C9, 0xAD9D, 0xB1CA, 0xAD9E, 0x82B1, 0xAD9F, 0x82B2, 0xADA0, 0x82B3, 0xADA1, 0x82B4, 0xADA2, 0x82B5, 0xADA3, 0x82B6, + 0xADA4, 0xB1CB, 0xADA5, 0x82B7, 0xADA6, 0x82B8, 0xADA7, 0x82B9, 0xADA8, 0x82BA, 0xADA9, 0x82BB, 0xADAA, 0x82BC, 0xADAB, 0x82BD, + 0xADAC, 0x82BE, 0xADAD, 0x82BF, 0xADAE, 0x82C0, 0xADAF, 0x82C1, 0xADB0, 0x82C2, 0xADB1, 0x82C3, 0xADB2, 0x82C4, 0xADB3, 0x82C5, + 0xADB4, 0x82C6, 0xADB5, 0x82C7, 0xADB6, 0x82C8, 0xADB7, 0xB1CC, 0xADB8, 0x82C9, 0xADB9, 0x82CA, 0xADBA, 0x82CB, 0xADBB, 0x82CC, + 0xADBC, 0x82CD, 0xADBD, 0x82CE, 0xADBE, 0x82CF, 0xADBF, 0x82D0, 0xADC0, 0xB1CD, 0xADC1, 0xB1CE, 0xADC2, 0x82D1, 0xADC3, 0x82D2, + 0xADC4, 0xB1CF, 0xADC5, 0x82D3, 0xADC6, 0x82D4, 0xADC7, 0x82D5, 0xADC8, 0xB1D0, 0xADC9, 0x82D6, 0xADCA, 0x82D7, 0xADCB, 0x82D8, + 0xADCC, 0x82D9, 0xADCD, 0x82DA, 0xADCE, 0x82DB, 0xADCF, 0x82DC, 0xADD0, 0xB1D1, 0xADD1, 0xB1D2, 0xADD2, 0x82DD, 0xADD3, 0xB1D3, + 0xADD4, 0x82DE, 0xADD5, 0x82DF, 0xADD6, 0x82E0, 0xADD7, 0x82E1, 0xADD8, 0x82E2, 0xADD9, 0x82E3, 0xADDA, 0x82E4, 0xADDB, 0x82E5, + 0xADDC, 0xB1D4, 0xADDD, 0x82E6, 0xADDE, 0x82E7, 0xADDF, 0x82E8, 0xADE0, 0xB1D5, 0xADE1, 0x82E9, 0xADE2, 0x82EA, 0xADE3, 0x82EB, + 0xADE4, 0xB1D6, 0xADE5, 0x82EC, 0xADE6, 0x82ED, 0xADE7, 0x82EE, 0xADE8, 0x82EF, 0xADE9, 0x82F0, 0xADEA, 0x82F1, 0xADEB, 0x82F2, + 0xADEC, 0x82F3, 0xADED, 0x82F4, 0xADEE, 0x82F5, 0xADEF, 0x82F6, 0xADF0, 0x82F7, 0xADF1, 0x82F8, 0xADF2, 0x82F9, 0xADF3, 0x82FA, + 0xADF4, 0x82FB, 0xADF5, 0x82FC, 0xADF6, 0x82FD, 0xADF7, 0x82FE, 0xADF8, 0xB1D7, 0xADF9, 0xB1D8, 0xADFA, 0x8341, 0xADFB, 0x8342, + 0xADFC, 0xB1D9, 0xADFD, 0x8343, 0xADFE, 0x8344, 0xADFF, 0xB1DA, 0xAE00, 0xB1DB, 0xAE01, 0xB1DC, 0xAE02, 0x8345, 0xAE03, 0x8346, + 0xAE04, 0x8347, 0xAE05, 0x8348, 0xAE06, 0x8349, 0xAE07, 0x834A, 0xAE08, 0xB1DD, 0xAE09, 0xB1DE, 0xAE0A, 0x834B, 0xAE0B, 0xB1DF, + 0xAE0C, 0x834C, 0xAE0D, 0xB1E0, 0xAE0E, 0x834D, 0xAE0F, 0x834E, 0xAE10, 0x834F, 0xAE11, 0x8350, 0xAE12, 0x8351, 0xAE13, 0x8352, + 0xAE14, 0xB1E1, 0xAE15, 0x8353, 0xAE16, 0x8354, 0xAE17, 0x8355, 0xAE18, 0x8356, 0xAE19, 0x8357, 0xAE1A, 0x8358, 0xAE1B, 0x8359, + 0xAE1C, 0x835A, 0xAE1D, 0x8361, 0xAE1E, 0x8362, 0xAE1F, 0x8363, 0xAE20, 0x8364, 0xAE21, 0x8365, 0xAE22, 0x8366, 0xAE23, 0x8367, + 0xAE24, 0x8368, 0xAE25, 0x8369, 0xAE26, 0x836A, 0xAE27, 0x836B, 0xAE28, 0x836C, 0xAE29, 0x836D, 0xAE2A, 0x836E, 0xAE2B, 0x836F, + 0xAE2C, 0x8370, 0xAE2D, 0x8371, 0xAE2E, 0x8372, 0xAE2F, 0x8373, 0xAE30, 0xB1E2, 0xAE31, 0xB1E3, 0xAE32, 0x8374, 0xAE33, 0x8375, + 0xAE34, 0xB1E4, 0xAE35, 0x8376, 0xAE36, 0x8377, 0xAE37, 0xB1E5, 0xAE38, 0xB1E6, 0xAE39, 0x8378, 0xAE3A, 0xB1E7, 0xAE3B, 0x8379, + 0xAE3C, 0x837A, 0xAE3D, 0x8381, 0xAE3E, 0x8382, 0xAE3F, 0x8383, 0xAE40, 0xB1E8, 0xAE41, 0xB1E9, 0xAE42, 0x8384, 0xAE43, 0xB1EA, + 0xAE44, 0x8385, 0xAE45, 0xB1EB, 0xAE46, 0xB1EC, 0xAE47, 0x8386, 0xAE48, 0x8387, 0xAE49, 0x8388, 0xAE4A, 0xB1ED, 0xAE4B, 0x8389, + 0xAE4C, 0xB1EE, 0xAE4D, 0xB1EF, 0xAE4E, 0xB1F0, 0xAE4F, 0x838A, 0xAE50, 0xB1F1, 0xAE51, 0x838B, 0xAE52, 0x838C, 0xAE53, 0x838D, + 0xAE54, 0xB1F2, 0xAE55, 0x838E, 0xAE56, 0xB1F3, 0xAE57, 0x838F, 0xAE58, 0x8390, 0xAE59, 0x8391, 0xAE5A, 0x8392, 0xAE5B, 0x8393, + 0xAE5C, 0xB1F4, 0xAE5D, 0xB1F5, 0xAE5E, 0x8394, 0xAE5F, 0xB1F6, 0xAE60, 0xB1F7, 0xAE61, 0xB1F8, 0xAE62, 0x8395, 0xAE63, 0x8396, + 0xAE64, 0x8397, 0xAE65, 0xB1F9, 0xAE66, 0x8398, 0xAE67, 0x8399, 0xAE68, 0xB1FA, 0xAE69, 0xB1FB, 0xAE6A, 0x839A, 0xAE6B, 0x839B, + 0xAE6C, 0xB1FC, 0xAE6D, 0x839C, 0xAE6E, 0x839D, 0xAE6F, 0x839E, 0xAE70, 0xB1FD, 0xAE71, 0x839F, 0xAE72, 0x83A0, 0xAE73, 0x83A1, + 0xAE74, 0x83A2, 0xAE75, 0x83A3, 0xAE76, 0x83A4, 0xAE77, 0x83A5, 0xAE78, 0xB1FE, 0xAE79, 0xB2A1, 0xAE7A, 0x83A6, 0xAE7B, 0xB2A2, + 0xAE7C, 0xB2A3, 0xAE7D, 0xB2A4, 0xAE7E, 0x83A7, 0xAE7F, 0x83A8, 0xAE80, 0x83A9, 0xAE81, 0x83AA, 0xAE82, 0x83AB, 0xAE83, 0x83AC, + 0xAE84, 0xB2A5, 0xAE85, 0xB2A6, 0xAE86, 0x83AD, 0xAE87, 0x83AE, 0xAE88, 0x83AF, 0xAE89, 0x83B0, 0xAE8A, 0x83B1, 0xAE8B, 0x83B2, + 0xAE8C, 0xB2A7, 0xAE8D, 0x83B3, 0xAE8E, 0x83B4, 0xAE8F, 0x83B5, 0xAE90, 0x83B6, 0xAE91, 0x83B7, 0xAE92, 0x83B8, 0xAE93, 0x83B9, + 0xAE94, 0x83BA, 0xAE95, 0x83BB, 0xAE96, 0x83BC, 0xAE97, 0x83BD, 0xAE98, 0x83BE, 0xAE99, 0x83BF, 0xAE9A, 0x83C0, 0xAE9B, 0x83C1, + 0xAE9C, 0x83C2, 0xAE9D, 0x83C3, 0xAE9E, 0x83C4, 0xAE9F, 0x83C5, 0xAEA0, 0x83C6, 0xAEA1, 0x83C7, 0xAEA2, 0x83C8, 0xAEA3, 0x83C9, + 0xAEA4, 0x83CA, 0xAEA5, 0x83CB, 0xAEA6, 0x83CC, 0xAEA7, 0x83CD, 0xAEA8, 0x83CE, 0xAEA9, 0x83CF, 0xAEAA, 0x83D0, 0xAEAB, 0x83D1, + 0xAEAC, 0x83D2, 0xAEAD, 0x83D3, 0xAEAE, 0x83D4, 0xAEAF, 0x83D5, 0xAEB0, 0x83D6, 0xAEB1, 0x83D7, 0xAEB2, 0x83D8, 0xAEB3, 0x83D9, + 0xAEB4, 0x83DA, 0xAEB5, 0x83DB, 0xAEB6, 0x83DC, 0xAEB7, 0x83DD, 0xAEB8, 0x83DE, 0xAEB9, 0x83DF, 0xAEBA, 0x83E0, 0xAEBB, 0x83E1, + 0xAEBC, 0xB2A8, 0xAEBD, 0xB2A9, 0xAEBE, 0xB2AA, 0xAEBF, 0x83E2, 0xAEC0, 0xB2AB, 0xAEC1, 0x83E3, 0xAEC2, 0x83E4, 0xAEC3, 0x83E5, + 0xAEC4, 0xB2AC, 0xAEC5, 0x83E6, 0xAEC6, 0x83E7, 0xAEC7, 0x83E8, 0xAEC8, 0x83E9, 0xAEC9, 0x83EA, 0xAECA, 0x83EB, 0xAECB, 0x83EC, + 0xAECC, 0xB2AD, 0xAECD, 0xB2AE, 0xAECE, 0x83ED, 0xAECF, 0xB2AF, 0xAED0, 0xB2B0, 0xAED1, 0xB2B1, 0xAED2, 0x83EE, 0xAED3, 0x83EF, + 0xAED4, 0x83F0, 0xAED5, 0x83F1, 0xAED6, 0x83F2, 0xAED7, 0x83F3, 0xAED8, 0xB2B2, 0xAED9, 0xB2B3, 0xAEDA, 0x83F4, 0xAEDB, 0x83F5, + 0xAEDC, 0xB2B4, 0xAEDD, 0x83F6, 0xAEDE, 0x83F7, 0xAEDF, 0x83F8, 0xAEE0, 0x83F9, 0xAEE1, 0x83FA, 0xAEE2, 0x83FB, 0xAEE3, 0x83FC, + 0xAEE4, 0x83FD, 0xAEE5, 0x83FE, 0xAEE6, 0x8441, 0xAEE7, 0x8442, 0xAEE8, 0xB2B5, 0xAEE9, 0x8443, 0xAEEA, 0x8444, 0xAEEB, 0xB2B6, + 0xAEEC, 0x8445, 0xAEED, 0xB2B7, 0xAEEE, 0x8446, 0xAEEF, 0x8447, 0xAEF0, 0x8448, 0xAEF1, 0x8449, 0xAEF2, 0x844A, 0xAEF3, 0x844B, + 0xAEF4, 0xB2B8, 0xAEF5, 0x844C, 0xAEF6, 0x844D, 0xAEF7, 0x844E, 0xAEF8, 0xB2B9, 0xAEF9, 0x844F, 0xAEFA, 0x8450, 0xAEFB, 0x8451, + 0xAEFC, 0xB2BA, 0xAEFD, 0x8452, 0xAEFE, 0x8453, 0xAEFF, 0x8454, 0xAF00, 0x8455, 0xAF01, 0x8456, 0xAF02, 0x8457, 0xAF03, 0x8458, + 0xAF04, 0x8459, 0xAF05, 0x845A, 0xAF06, 0x8461, 0xAF07, 0xB2BB, 0xAF08, 0xB2BC, 0xAF09, 0x8462, 0xAF0A, 0x8463, 0xAF0B, 0x8464, + 0xAF0C, 0x8465, 0xAF0D, 0xB2BD, 0xAF0E, 0x8466, 0xAF0F, 0x8467, 0xAF10, 0xB2BE, 0xAF11, 0x8468, 0xAF12, 0x8469, 0xAF13, 0x846A, + 0xAF14, 0x846B, 0xAF15, 0x846C, 0xAF16, 0x846D, 0xAF17, 0x846E, 0xAF18, 0x846F, 0xAF19, 0x8470, 0xAF1A, 0x8471, 0xAF1B, 0x8472, + 0xAF1C, 0x8473, 0xAF1D, 0x8474, 0xAF1E, 0x8475, 0xAF1F, 0x8476, 0xAF20, 0x8477, 0xAF21, 0x8478, 0xAF22, 0x8479, 0xAF23, 0x847A, + 0xAF24, 0x8481, 0xAF25, 0x8482, 0xAF26, 0x8483, 0xAF27, 0x8484, 0xAF28, 0x8485, 0xAF29, 0x8486, 0xAF2A, 0x8487, 0xAF2B, 0x8488, + 0xAF2C, 0xB2BF, 0xAF2D, 0xB2C0, 0xAF2E, 0x8489, 0xAF2F, 0x848A, 0xAF30, 0xB2C1, 0xAF31, 0x848B, 0xAF32, 0xB2C2, 0xAF33, 0x848C, + 0xAF34, 0xB2C3, 0xAF35, 0x848D, 0xAF36, 0x848E, 0xAF37, 0x848F, 0xAF38, 0x8490, 0xAF39, 0x8491, 0xAF3A, 0x8492, 0xAF3B, 0x8493, + 0xAF3C, 0xB2C4, 0xAF3D, 0xB2C5, 0xAF3E, 0x8494, 0xAF3F, 0xB2C6, 0xAF40, 0x8495, 0xAF41, 0xB2C7, 0xAF42, 0xB2C8, 0xAF43, 0xB2C9, + 0xAF44, 0x8496, 0xAF45, 0x8497, 0xAF46, 0x8498, 0xAF47, 0x8499, 0xAF48, 0xB2CA, 0xAF49, 0xB2CB, 0xAF4A, 0x849A, 0xAF4B, 0x849B, + 0xAF4C, 0x849C, 0xAF4D, 0x849D, 0xAF4E, 0x849E, 0xAF4F, 0x849F, 0xAF50, 0xB2CC, 0xAF51, 0x84A0, 0xAF52, 0x84A1, 0xAF53, 0x84A2, + 0xAF54, 0x84A3, 0xAF55, 0x84A4, 0xAF56, 0x84A5, 0xAF57, 0x84A6, 0xAF58, 0x84A7, 0xAF59, 0x84A8, 0xAF5A, 0x84A9, 0xAF5B, 0x84AA, + 0xAF5C, 0xB2CD, 0xAF5D, 0xB2CE, 0xAF5E, 0x84AB, 0xAF5F, 0x84AC, 0xAF60, 0x84AD, 0xAF61, 0x84AE, 0xAF62, 0x84AF, 0xAF63, 0x84B0, + 0xAF64, 0xB2CF, 0xAF65, 0xB2D0, 0xAF66, 0x84B1, 0xAF67, 0x84B2, 0xAF68, 0x84B3, 0xAF69, 0x84B4, 0xAF6A, 0x84B5, 0xAF6B, 0x84B6, + 0xAF6C, 0x84B7, 0xAF6D, 0x84B8, 0xAF6E, 0x84B9, 0xAF6F, 0x84BA, 0xAF70, 0x84BB, 0xAF71, 0x84BC, 0xAF72, 0x84BD, 0xAF73, 0x84BE, + 0xAF74, 0x84BF, 0xAF75, 0x84C0, 0xAF76, 0x84C1, 0xAF77, 0x84C2, 0xAF78, 0x84C3, 0xAF79, 0xB2D1, 0xAF7A, 0x84C4, 0xAF7B, 0x84C5, + 0xAF7C, 0x84C6, 0xAF7D, 0x84C7, 0xAF7E, 0x84C8, 0xAF7F, 0x84C9, 0xAF80, 0xB2D2, 0xAF81, 0x84CA, 0xAF82, 0x84CB, 0xAF83, 0x84CC, + 0xAF84, 0xB2D3, 0xAF85, 0x84CD, 0xAF86, 0x84CE, 0xAF87, 0x84CF, 0xAF88, 0xB2D4, 0xAF89, 0x84D0, 0xAF8A, 0x84D1, 0xAF8B, 0x84D2, + 0xAF8C, 0x84D3, 0xAF8D, 0x84D4, 0xAF8E, 0x84D5, 0xAF8F, 0x84D6, 0xAF90, 0xB2D5, 0xAF91, 0xB2D6, 0xAF92, 0x84D7, 0xAF93, 0x84D8, + 0xAF94, 0x84D9, 0xAF95, 0xB2D7, 0xAF96, 0x84DA, 0xAF97, 0x84DB, 0xAF98, 0x84DC, 0xAF99, 0x84DD, 0xAF9A, 0x84DE, 0xAF9B, 0x84DF, + 0xAF9C, 0xB2D8, 0xAF9D, 0x84E0, 0xAF9E, 0x84E1, 0xAF9F, 0x84E2, 0xAFA0, 0x84E3, 0xAFA1, 0x84E4, 0xAFA2, 0x84E5, 0xAFA3, 0x84E6, + 0xAFA4, 0x84E7, 0xAFA5, 0x84E8, 0xAFA6, 0x84E9, 0xAFA7, 0x84EA, 0xAFA8, 0x84EB, 0xAFA9, 0x84EC, 0xAFAA, 0x84ED, 0xAFAB, 0x84EE, + 0xAFAC, 0x84EF, 0xAFAD, 0x84F0, 0xAFAE, 0x84F1, 0xAFAF, 0x84F2, 0xAFB0, 0x84F3, 0xAFB1, 0x84F4, 0xAFB2, 0x84F5, 0xAFB3, 0x84F6, + 0xAFB4, 0x84F7, 0xAFB5, 0x84F8, 0xAFB6, 0x84F9, 0xAFB7, 0x84FA, 0xAFB8, 0xB2D9, 0xAFB9, 0xB2DA, 0xAFBA, 0x84FB, 0xAFBB, 0x84FC, + 0xAFBC, 0xB2DB, 0xAFBD, 0x84FD, 0xAFBE, 0x84FE, 0xAFBF, 0x8541, 0xAFC0, 0xB2DC, 0xAFC1, 0x8542, 0xAFC2, 0x8543, 0xAFC3, 0x8544, + 0xAFC4, 0x8545, 0xAFC5, 0x8546, 0xAFC6, 0x8547, 0xAFC7, 0xB2DD, 0xAFC8, 0xB2DE, 0xAFC9, 0xB2DF, 0xAFCA, 0x8548, 0xAFCB, 0xB2E0, + 0xAFCC, 0x8549, 0xAFCD, 0xB2E1, 0xAFCE, 0xB2E2, 0xAFCF, 0x854A, 0xAFD0, 0x854B, 0xAFD1, 0x854C, 0xAFD2, 0x854D, 0xAFD3, 0x854E, + 0xAFD4, 0xB2E3, 0xAFD5, 0x854F, 0xAFD6, 0x8550, 0xAFD7, 0x8551, 0xAFD8, 0x8552, 0xAFD9, 0x8553, 0xAFDA, 0x8554, 0xAFDB, 0x8555, + 0xAFDC, 0xB2E4, 0xAFDD, 0x8556, 0xAFDE, 0x8557, 0xAFDF, 0x8558, 0xAFE0, 0x8559, 0xAFE1, 0x855A, 0xAFE2, 0x8561, 0xAFE3, 0x8562, + 0xAFE4, 0x8563, 0xAFE5, 0x8564, 0xAFE6, 0x8565, 0xAFE7, 0x8566, 0xAFE8, 0xB2E5, 0xAFE9, 0xB2E6, 0xAFEA, 0x8567, 0xAFEB, 0x8568, + 0xAFEC, 0x8569, 0xAFED, 0x856A, 0xAFEE, 0x856B, 0xAFEF, 0x856C, 0xAFF0, 0xB2E7, 0xAFF1, 0xB2E8, 0xAFF2, 0x856D, 0xAFF3, 0x856E, + 0xAFF4, 0xB2E9, 0xAFF5, 0x856F, 0xAFF6, 0x8570, 0xAFF7, 0x8571, 0xAFF8, 0xB2EA, 0xAFF9, 0x8572, 0xAFFA, 0x8573, 0xAFFB, 0x8574, + 0xAFFC, 0x8575, 0xAFFD, 0x8576, 0xAFFE, 0x8577, 0xAFFF, 0x8578, 0xB000, 0xB2EB, 0xB001, 0xB2EC, 0xB002, 0x8579, 0xB003, 0x857A, + 0xB004, 0xB2ED, 0xB005, 0x8581, 0xB006, 0x8582, 0xB007, 0x8583, 0xB008, 0x8584, 0xB009, 0x8585, 0xB00A, 0x8586, 0xB00B, 0x8587, + 0xB00C, 0xB2EE, 0xB00D, 0x8588, 0xB00E, 0x8589, 0xB00F, 0x858A, 0xB010, 0xB2EF, 0xB011, 0x858B, 0xB012, 0x858C, 0xB013, 0x858D, + 0xB014, 0xB2F0, 0xB015, 0x858E, 0xB016, 0x858F, 0xB017, 0x8590, 0xB018, 0x8591, 0xB019, 0x8592, 0xB01A, 0x8593, 0xB01B, 0x8594, + 0xB01C, 0xB2F1, 0xB01D, 0xB2F2, 0xB01E, 0x8595, 0xB01F, 0x8596, 0xB020, 0x8597, 0xB021, 0x8598, 0xB022, 0x8599, 0xB023, 0x859A, + 0xB024, 0x859B, 0xB025, 0x859C, 0xB026, 0x859D, 0xB027, 0x859E, 0xB028, 0xB2F3, 0xB029, 0x859F, 0xB02A, 0x85A0, 0xB02B, 0x85A1, + 0xB02C, 0x85A2, 0xB02D, 0x85A3, 0xB02E, 0x85A4, 0xB02F, 0x85A5, 0xB030, 0x85A6, 0xB031, 0x85A7, 0xB032, 0x85A8, 0xB033, 0x85A9, + 0xB034, 0x85AA, 0xB035, 0x85AB, 0xB036, 0x85AC, 0xB037, 0x85AD, 0xB038, 0x85AE, 0xB039, 0x85AF, 0xB03A, 0x85B0, 0xB03B, 0x85B1, + 0xB03C, 0x85B2, 0xB03D, 0x85B3, 0xB03E, 0x85B4, 0xB03F, 0x85B5, 0xB040, 0x85B6, 0xB041, 0x85B7, 0xB042, 0x85B8, 0xB043, 0x85B9, + 0xB044, 0xB2F4, 0xB045, 0xB2F5, 0xB046, 0x85BA, 0xB047, 0x85BB, 0xB048, 0xB2F6, 0xB049, 0x85BC, 0xB04A, 0xB2F7, 0xB04B, 0x85BD, + 0xB04C, 0xB2F8, 0xB04D, 0x85BE, 0xB04E, 0xB2F9, 0xB04F, 0x85BF, 0xB050, 0x85C0, 0xB051, 0x85C1, 0xB052, 0x85C2, 0xB053, 0xB2FA, + 0xB054, 0xB2FB, 0xB055, 0xB2FC, 0xB056, 0x85C3, 0xB057, 0xB2FD, 0xB058, 0x85C4, 0xB059, 0xB2FE, 0xB05A, 0x85C5, 0xB05B, 0x85C6, + 0xB05C, 0x85C7, 0xB05D, 0xB3A1, 0xB05E, 0x85C8, 0xB05F, 0x85C9, 0xB060, 0x85CA, 0xB061, 0x85CB, 0xB062, 0x85CC, 0xB063, 0x85CD, + 0xB064, 0x85CE, 0xB065, 0x85CF, 0xB066, 0x85D0, 0xB067, 0x85D1, 0xB068, 0x85D2, 0xB069, 0x85D3, 0xB06A, 0x85D4, 0xB06B, 0x85D5, + 0xB06C, 0x85D6, 0xB06D, 0x85D7, 0xB06E, 0x85D8, 0xB06F, 0x85D9, 0xB070, 0x85DA, 0xB071, 0x85DB, 0xB072, 0x85DC, 0xB073, 0x85DD, + 0xB074, 0x85DE, 0xB075, 0x85DF, 0xB076, 0x85E0, 0xB077, 0x85E1, 0xB078, 0x85E2, 0xB079, 0x85E3, 0xB07A, 0x85E4, 0xB07B, 0x85E5, + 0xB07C, 0xB3A2, 0xB07D, 0xB3A3, 0xB07E, 0x85E6, 0xB07F, 0x85E7, 0xB080, 0xB3A4, 0xB081, 0x85E8, 0xB082, 0x85E9, 0xB083, 0x85EA, + 0xB084, 0xB3A5, 0xB085, 0x85EB, 0xB086, 0x85EC, 0xB087, 0x85ED, 0xB088, 0x85EE, 0xB089, 0x85EF, 0xB08A, 0x85F0, 0xB08B, 0x85F1, + 0xB08C, 0xB3A6, 0xB08D, 0xB3A7, 0xB08E, 0x85F2, 0xB08F, 0xB3A8, 0xB090, 0x85F3, 0xB091, 0xB3A9, 0xB092, 0x85F4, 0xB093, 0x85F5, + 0xB094, 0x85F6, 0xB095, 0x85F7, 0xB096, 0x85F8, 0xB097, 0x85F9, 0xB098, 0xB3AA, 0xB099, 0xB3AB, 0xB09A, 0xB3AC, 0xB09B, 0x85FA, + 0xB09C, 0xB3AD, 0xB09D, 0x85FB, 0xB09E, 0x85FC, 0xB09F, 0xB3AE, 0xB0A0, 0xB3AF, 0xB0A1, 0xB3B0, 0xB0A2, 0xB3B1, 0xB0A3, 0x85FD, + 0xB0A4, 0x85FE, 0xB0A5, 0x8641, 0xB0A6, 0x8642, 0xB0A7, 0x8643, 0xB0A8, 0xB3B2, 0xB0A9, 0xB3B3, 0xB0AA, 0x8644, 0xB0AB, 0xB3B4, + 0xB0AC, 0xB3B5, 0xB0AD, 0xB3B6, 0xB0AE, 0xB3B7, 0xB0AF, 0xB3B8, 0xB0B0, 0x8645, 0xB0B1, 0xB3B9, 0xB0B2, 0x8646, 0xB0B3, 0xB3BA, + 0xB0B4, 0xB3BB, 0xB0B5, 0xB3BC, 0xB0B6, 0x8647, 0xB0B7, 0x8648, 0xB0B8, 0xB3BD, 0xB0B9, 0x8649, 0xB0BA, 0x864A, 0xB0BB, 0x864B, + 0xB0BC, 0xB3BE, 0xB0BD, 0x864C, 0xB0BE, 0x864D, 0xB0BF, 0x864E, 0xB0C0, 0x864F, 0xB0C1, 0x8650, 0xB0C2, 0x8651, 0xB0C3, 0x8652, + 0xB0C4, 0xB3BF, 0xB0C5, 0xB3C0, 0xB0C6, 0x8653, 0xB0C7, 0xB3C1, 0xB0C8, 0xB3C2, 0xB0C9, 0xB3C3, 0xB0CA, 0x8654, 0xB0CB, 0x8655, + 0xB0CC, 0x8656, 0xB0CD, 0x8657, 0xB0CE, 0x8658, 0xB0CF, 0x8659, 0xB0D0, 0xB3C4, 0xB0D1, 0xB3C5, 0xB0D2, 0x865A, 0xB0D3, 0x8661, + 0xB0D4, 0xB3C6, 0xB0D5, 0x8662, 0xB0D6, 0x8663, 0xB0D7, 0x8664, 0xB0D8, 0xB3C7, 0xB0D9, 0x8665, 0xB0DA, 0x8666, 0xB0DB, 0x8667, + 0xB0DC, 0x8668, 0xB0DD, 0x8669, 0xB0DE, 0x866A, 0xB0DF, 0x866B, 0xB0E0, 0xB3C8, 0xB0E1, 0x866C, 0xB0E2, 0x866D, 0xB0E3, 0x866E, + 0xB0E4, 0x866F, 0xB0E5, 0xB3C9, 0xB0E6, 0x8670, 0xB0E7, 0x8671, 0xB0E8, 0x8672, 0xB0E9, 0x8673, 0xB0EA, 0x8674, 0xB0EB, 0x8675, + 0xB0EC, 0x8676, 0xB0ED, 0x8677, 0xB0EE, 0x8678, 0xB0EF, 0x8679, 0xB0F0, 0x867A, 0xB0F1, 0x8681, 0xB0F2, 0x8682, 0xB0F3, 0x8683, + 0xB0F4, 0x8684, 0xB0F5, 0x8685, 0xB0F6, 0x8686, 0xB0F7, 0x8687, 0xB0F8, 0x8688, 0xB0F9, 0x8689, 0xB0FA, 0x868A, 0xB0FB, 0x868B, + 0xB0FC, 0x868C, 0xB0FD, 0x868D, 0xB0FE, 0x868E, 0xB0FF, 0x868F, 0xB100, 0x8690, 0xB101, 0x8691, 0xB102, 0x8692, 0xB103, 0x8693, + 0xB104, 0x8694, 0xB105, 0x8695, 0xB106, 0x8696, 0xB107, 0x8697, 0xB108, 0xB3CA, 0xB109, 0xB3CB, 0xB10A, 0x8698, 0xB10B, 0xB3CC, + 0xB10C, 0xB3CD, 0xB10D, 0x8699, 0xB10E, 0x869A, 0xB10F, 0x869B, 0xB110, 0xB3CE, 0xB111, 0x869C, 0xB112, 0xB3CF, 0xB113, 0xB3D0, + 0xB114, 0x869D, 0xB115, 0x869E, 0xB116, 0x869F, 0xB117, 0x86A0, 0xB118, 0xB3D1, 0xB119, 0xB3D2, 0xB11A, 0x86A1, 0xB11B, 0xB3D3, + 0xB11C, 0xB3D4, 0xB11D, 0xB3D5, 0xB11E, 0x86A2, 0xB11F, 0x86A3, 0xB120, 0x86A4, 0xB121, 0x86A5, 0xB122, 0x86A6, 0xB123, 0xB3D6, + 0xB124, 0xB3D7, 0xB125, 0xB3D8, 0xB126, 0x86A7, 0xB127, 0x86A8, 0xB128, 0xB3D9, 0xB129, 0x86A9, 0xB12A, 0x86AA, 0xB12B, 0x86AB, + 0xB12C, 0xB3DA, 0xB12D, 0x86AC, 0xB12E, 0x86AD, 0xB12F, 0x86AE, 0xB130, 0x86AF, 0xB131, 0x86B0, 0xB132, 0x86B1, 0xB133, 0x86B2, + 0xB134, 0xB3DB, 0xB135, 0xB3DC, 0xB136, 0x86B3, 0xB137, 0xB3DD, 0xB138, 0xB3DE, 0xB139, 0xB3DF, 0xB13A, 0x86B4, 0xB13B, 0x86B5, + 0xB13C, 0x86B6, 0xB13D, 0x86B7, 0xB13E, 0x86B8, 0xB13F, 0x86B9, 0xB140, 0xB3E0, 0xB141, 0xB3E1, 0xB142, 0x86BA, 0xB143, 0x86BB, + 0xB144, 0xB3E2, 0xB145, 0x86BC, 0xB146, 0x86BD, 0xB147, 0x86BE, 0xB148, 0xB3E3, 0xB149, 0x86BF, 0xB14A, 0x86C0, 0xB14B, 0x86C1, + 0xB14C, 0x86C2, 0xB14D, 0x86C3, 0xB14E, 0x86C4, 0xB14F, 0x86C5, 0xB150, 0xB3E4, 0xB151, 0xB3E5, 0xB152, 0x86C6, 0xB153, 0x86C7, + 0xB154, 0xB3E6, 0xB155, 0xB3E7, 0xB156, 0x86C8, 0xB157, 0x86C9, 0xB158, 0xB3E8, 0xB159, 0x86CA, 0xB15A, 0x86CB, 0xB15B, 0x86CC, + 0xB15C, 0xB3E9, 0xB15D, 0x86CD, 0xB15E, 0x86CE, 0xB15F, 0x86CF, 0xB160, 0xB3EA, 0xB161, 0x86D0, 0xB162, 0x86D1, 0xB163, 0x86D2, + 0xB164, 0x86D3, 0xB165, 0x86D4, 0xB166, 0x86D5, 0xB167, 0x86D6, 0xB168, 0x86D7, 0xB169, 0x86D8, 0xB16A, 0x86D9, 0xB16B, 0x86DA, + 0xB16C, 0x86DB, 0xB16D, 0x86DC, 0xB16E, 0x86DD, 0xB16F, 0x86DE, 0xB170, 0x86DF, 0xB171, 0x86E0, 0xB172, 0x86E1, 0xB173, 0x86E2, + 0xB174, 0x86E3, 0xB175, 0x86E4, 0xB176, 0x86E5, 0xB177, 0x86E6, 0xB178, 0xB3EB, 0xB179, 0xB3EC, 0xB17A, 0x86E7, 0xB17B, 0x86E8, + 0xB17C, 0xB3ED, 0xB17D, 0x86E9, 0xB17E, 0x86EA, 0xB17F, 0x86EB, 0xB180, 0xB3EE, 0xB181, 0x86EC, 0xB182, 0xB3EF, 0xB183, 0x86ED, + 0xB184, 0x86EE, 0xB185, 0x86EF, 0xB186, 0x86F0, 0xB187, 0x86F1, 0xB188, 0xB3F0, 0xB189, 0xB3F1, 0xB18A, 0x86F2, 0xB18B, 0xB3F2, + 0xB18C, 0x86F3, 0xB18D, 0xB3F3, 0xB18E, 0x86F4, 0xB18F, 0x86F5, 0xB190, 0x86F6, 0xB191, 0x86F7, 0xB192, 0xB3F4, 0xB193, 0xB3F5, + 0xB194, 0xB3F6, 0xB195, 0x86F8, 0xB196, 0x86F9, 0xB197, 0x86FA, 0xB198, 0xB3F7, 0xB199, 0x86FB, 0xB19A, 0x86FC, 0xB19B, 0x86FD, + 0xB19C, 0xB3F8, 0xB19D, 0x86FE, 0xB19E, 0x8741, 0xB19F, 0x8742, 0xB1A0, 0x8743, 0xB1A1, 0x8744, 0xB1A2, 0x8745, 0xB1A3, 0x8746, + 0xB1A4, 0x8747, 0xB1A5, 0x8748, 0xB1A6, 0x8749, 0xB1A7, 0x874A, 0xB1A8, 0xB3F9, 0xB1A9, 0x874B, 0xB1AA, 0x874C, 0xB1AB, 0x874D, + 0xB1AC, 0x874E, 0xB1AD, 0x874F, 0xB1AE, 0x8750, 0xB1AF, 0x8751, 0xB1B0, 0x8752, 0xB1B1, 0x8753, 0xB1B2, 0x8754, 0xB1B3, 0x8755, + 0xB1B4, 0x8756, 0xB1B5, 0x8757, 0xB1B6, 0x8758, 0xB1B7, 0x8759, 0xB1B8, 0x875A, 0xB1B9, 0x8761, 0xB1BA, 0x8762, 0xB1BB, 0x8763, + 0xB1BC, 0x8764, 0xB1BD, 0x8765, 0xB1BE, 0x8766, 0xB1BF, 0x8767, 0xB1C0, 0x8768, 0xB1C1, 0x8769, 0xB1C2, 0x876A, 0xB1C3, 0x876B, + 0xB1C4, 0x876C, 0xB1C5, 0x876D, 0xB1C6, 0x876E, 0xB1C7, 0x876F, 0xB1C8, 0x8770, 0xB1C9, 0x8771, 0xB1CA, 0x8772, 0xB1CB, 0x8773, + 0xB1CC, 0xB3FA, 0xB1CD, 0x8774, 0xB1CE, 0x8775, 0xB1CF, 0x8776, 0xB1D0, 0xB3FB, 0xB1D1, 0x8777, 0xB1D2, 0x8778, 0xB1D3, 0x8779, + 0xB1D4, 0xB3FC, 0xB1D5, 0x877A, 0xB1D6, 0x8781, 0xB1D7, 0x8782, 0xB1D8, 0x8783, 0xB1D9, 0x8784, 0xB1DA, 0x8785, 0xB1DB, 0x8786, + 0xB1DC, 0xB3FD, 0xB1DD, 0xB3FE, 0xB1DE, 0x8787, 0xB1DF, 0xB4A1, 0xB1E0, 0x8788, 0xB1E1, 0x8789, 0xB1E2, 0x878A, 0xB1E3, 0x878B, + 0xB1E4, 0x878C, 0xB1E5, 0x878D, 0xB1E6, 0x878E, 0xB1E7, 0x878F, 0xB1E8, 0xB4A2, 0xB1E9, 0xB4A3, 0xB1EA, 0x8790, 0xB1EB, 0x8791, + 0xB1EC, 0xB4A4, 0xB1ED, 0x8792, 0xB1EE, 0x8793, 0xB1EF, 0x8794, 0xB1F0, 0xB4A5, 0xB1F1, 0x8795, 0xB1F2, 0x8796, 0xB1F3, 0x8797, + 0xB1F4, 0x8798, 0xB1F5, 0x8799, 0xB1F6, 0x879A, 0xB1F7, 0x879B, 0xB1F8, 0x879C, 0xB1F9, 0xB4A6, 0xB1FA, 0x879D, 0xB1FB, 0xB4A7, + 0xB1FC, 0x879E, 0xB1FD, 0xB4A8, 0xB1FE, 0x879F, 0xB1FF, 0x87A0, 0xB200, 0x87A1, 0xB201, 0x87A2, 0xB202, 0x87A3, 0xB203, 0x87A4, + 0xB204, 0xB4A9, 0xB205, 0xB4AA, 0xB206, 0x87A5, 0xB207, 0x87A6, 0xB208, 0xB4AB, 0xB209, 0x87A7, 0xB20A, 0x87A8, 0xB20B, 0xB4AC, + 0xB20C, 0xB4AD, 0xB20D, 0x87A9, 0xB20E, 0x87AA, 0xB20F, 0x87AB, 0xB210, 0x87AC, 0xB211, 0x87AD, 0xB212, 0x87AE, 0xB213, 0x87AF, + 0xB214, 0xB4AE, 0xB215, 0xB4AF, 0xB216, 0x87B0, 0xB217, 0xB4B0, 0xB218, 0x87B1, 0xB219, 0xB4B1, 0xB21A, 0x87B2, 0xB21B, 0x87B3, + 0xB21C, 0x87B4, 0xB21D, 0x87B5, 0xB21E, 0x87B6, 0xB21F, 0x87B7, 0xB220, 0xB4B2, 0xB221, 0x87B8, 0xB222, 0x87B9, 0xB223, 0x87BA, + 0xB224, 0x87BB, 0xB225, 0x87BC, 0xB226, 0x87BD, 0xB227, 0x87BE, 0xB228, 0x87BF, 0xB229, 0x87C0, 0xB22A, 0x87C1, 0xB22B, 0x87C2, + 0xB22C, 0x87C3, 0xB22D, 0x87C4, 0xB22E, 0x87C5, 0xB22F, 0x87C6, 0xB230, 0x87C7, 0xB231, 0x87C8, 0xB232, 0x87C9, 0xB233, 0x87CA, + 0xB234, 0xB4B3, 0xB235, 0x87CB, 0xB236, 0x87CC, 0xB237, 0x87CD, 0xB238, 0x87CE, 0xB239, 0x87CF, 0xB23A, 0x87D0, 0xB23B, 0x87D1, + 0xB23C, 0xB4B4, 0xB23D, 0x87D2, 0xB23E, 0x87D3, 0xB23F, 0x87D4, 0xB240, 0x87D5, 0xB241, 0x87D6, 0xB242, 0x87D7, 0xB243, 0x87D8, + 0xB244, 0x87D9, 0xB245, 0x87DA, 0xB246, 0x87DB, 0xB247, 0x87DC, 0xB248, 0x87DD, 0xB249, 0x87DE, 0xB24A, 0x87DF, 0xB24B, 0x87E0, + 0xB24C, 0x87E1, 0xB24D, 0x87E2, 0xB24E, 0x87E3, 0xB24F, 0x87E4, 0xB250, 0x87E5, 0xB251, 0x87E6, 0xB252, 0x87E7, 0xB253, 0x87E8, + 0xB254, 0x87E9, 0xB255, 0x87EA, 0xB256, 0x87EB, 0xB257, 0x87EC, 0xB258, 0xB4B5, 0xB259, 0x87ED, 0xB25A, 0x87EE, 0xB25B, 0x87EF, + 0xB25C, 0xB4B6, 0xB25D, 0x87F0, 0xB25E, 0x87F1, 0xB25F, 0x87F2, 0xB260, 0xB4B7, 0xB261, 0x87F3, 0xB262, 0x87F4, 0xB263, 0x87F5, + 0xB264, 0x87F6, 0xB265, 0x87F7, 0xB266, 0x87F8, 0xB267, 0x87F9, 0xB268, 0xB4B8, 0xB269, 0xB4B9, 0xB26A, 0x87FA, 0xB26B, 0x87FB, + 0xB26C, 0x87FC, 0xB26D, 0x87FD, 0xB26E, 0x87FE, 0xB26F, 0x8841, 0xB270, 0x8842, 0xB271, 0x8843, 0xB272, 0x8844, 0xB273, 0x8845, + 0xB274, 0xB4BA, 0xB275, 0xB4BB, 0xB276, 0x8846, 0xB277, 0x8847, 0xB278, 0x8848, 0xB279, 0x8849, 0xB27A, 0x884A, 0xB27B, 0x884B, + 0xB27C, 0xB4BC, 0xB27D, 0x884C, 0xB27E, 0x884D, 0xB27F, 0x884E, 0xB280, 0x884F, 0xB281, 0x8850, 0xB282, 0x8851, 0xB283, 0x8852, + 0xB284, 0xB4BD, 0xB285, 0xB4BE, 0xB286, 0x8853, 0xB287, 0x8854, 0xB288, 0x8855, 0xB289, 0xB4BF, 0xB28A, 0x8856, 0xB28B, 0x8857, + 0xB28C, 0x8858, 0xB28D, 0x8859, 0xB28E, 0x885A, 0xB28F, 0x8861, 0xB290, 0xB4C0, 0xB291, 0xB4C1, 0xB292, 0x8862, 0xB293, 0x8863, + 0xB294, 0xB4C2, 0xB295, 0x8864, 0xB296, 0x8865, 0xB297, 0x8866, 0xB298, 0xB4C3, 0xB299, 0xB4C4, 0xB29A, 0xB4C5, 0xB29B, 0x8867, + 0xB29C, 0x8868, 0xB29D, 0x8869, 0xB29E, 0x886A, 0xB29F, 0x886B, 0xB2A0, 0xB4C6, 0xB2A1, 0xB4C7, 0xB2A2, 0x886C, 0xB2A3, 0xB4C8, + 0xB2A4, 0x886D, 0xB2A5, 0xB4C9, 0xB2A6, 0xB4CA, 0xB2A7, 0x886E, 0xB2A8, 0x886F, 0xB2A9, 0x8870, 0xB2AA, 0xB4CB, 0xB2AB, 0x8871, + 0xB2AC, 0xB4CC, 0xB2AD, 0x8872, 0xB2AE, 0x8873, 0xB2AF, 0x8874, 0xB2B0, 0xB4CD, 0xB2B1, 0x8875, 0xB2B2, 0x8876, 0xB2B3, 0x8877, + 0xB2B4, 0xB4CE, 0xB2B5, 0x8878, 0xB2B6, 0x8879, 0xB2B7, 0x887A, 0xB2B8, 0x8881, 0xB2B9, 0x8882, 0xB2BA, 0x8883, 0xB2BB, 0x8884, + 0xB2BC, 0x8885, 0xB2BD, 0x8886, 0xB2BE, 0x8887, 0xB2BF, 0x8888, 0xB2C0, 0x8889, 0xB2C1, 0x888A, 0xB2C2, 0x888B, 0xB2C3, 0x888C, + 0xB2C4, 0x888D, 0xB2C5, 0x888E, 0xB2C6, 0x888F, 0xB2C7, 0x8890, 0xB2C8, 0xB4CF, 0xB2C9, 0xB4D0, 0xB2CA, 0x8891, 0xB2CB, 0x8892, + 0xB2CC, 0xB4D1, 0xB2CD, 0x8893, 0xB2CE, 0x8894, 0xB2CF, 0x8895, 0xB2D0, 0xB4D2, 0xB2D1, 0x8896, 0xB2D2, 0xB4D3, 0xB2D3, 0x8897, + 0xB2D4, 0x8898, 0xB2D5, 0x8899, 0xB2D6, 0x889A, 0xB2D7, 0x889B, 0xB2D8, 0xB4D4, 0xB2D9, 0xB4D5, 0xB2DA, 0x889C, 0xB2DB, 0xB4D6, + 0xB2DC, 0x889D, 0xB2DD, 0xB4D7, 0xB2DE, 0x889E, 0xB2DF, 0x889F, 0xB2E0, 0x88A0, 0xB2E1, 0x88A1, 0xB2E2, 0xB4D8, 0xB2E3, 0x88A2, + 0xB2E4, 0xB4D9, 0xB2E5, 0xB4DA, 0xB2E6, 0xB4DB, 0xB2E7, 0x88A3, 0xB2E8, 0xB4DC, 0xB2E9, 0x88A4, 0xB2EA, 0x88A5, 0xB2EB, 0xB4DD, + 0xB2EC, 0xB4DE, 0xB2ED, 0xB4DF, 0xB2EE, 0xB4E0, 0xB2EF, 0xB4E1, 0xB2F0, 0x88A6, 0xB2F1, 0x88A7, 0xB2F2, 0x88A8, 0xB2F3, 0xB4E2, + 0xB2F4, 0xB4E3, 0xB2F5, 0xB4E4, 0xB2F6, 0x88A9, 0xB2F7, 0xB4E5, 0xB2F8, 0xB4E6, 0xB2F9, 0xB4E7, 0xB2FA, 0xB4E8, 0xB2FB, 0xB4E9, + 0xB2FC, 0x88AA, 0xB2FD, 0x88AB, 0xB2FE, 0x88AC, 0xB2FF, 0xB4EA, 0xB300, 0xB4EB, 0xB301, 0xB4EC, 0xB302, 0x88AD, 0xB303, 0x88AE, + 0xB304, 0xB4ED, 0xB305, 0x88AF, 0xB306, 0x88B0, 0xB307, 0x88B1, 0xB308, 0xB4EE, 0xB309, 0x88B2, 0xB30A, 0x88B3, 0xB30B, 0x88B4, + 0xB30C, 0x88B5, 0xB30D, 0x88B6, 0xB30E, 0x88B7, 0xB30F, 0x88B8, 0xB310, 0xB4EF, 0xB311, 0xB4F0, 0xB312, 0x88B9, 0xB313, 0xB4F1, + 0xB314, 0xB4F2, 0xB315, 0xB4F3, 0xB316, 0x88BA, 0xB317, 0x88BB, 0xB318, 0x88BC, 0xB319, 0x88BD, 0xB31A, 0x88BE, 0xB31B, 0x88BF, + 0xB31C, 0xB4F4, 0xB31D, 0x88C0, 0xB31E, 0x88C1, 0xB31F, 0x88C2, 0xB320, 0x88C3, 0xB321, 0x88C4, 0xB322, 0x88C5, 0xB323, 0x88C6, + 0xB324, 0x88C7, 0xB325, 0x88C8, 0xB326, 0x88C9, 0xB327, 0x88CA, 0xB328, 0x88CB, 0xB329, 0x88CC, 0xB32A, 0x88CD, 0xB32B, 0x88CE, + 0xB32C, 0x88CF, 0xB32D, 0x88D0, 0xB32E, 0x88D1, 0xB32F, 0x88D2, 0xB330, 0x88D3, 0xB331, 0x88D4, 0xB332, 0x88D5, 0xB333, 0x88D6, + 0xB334, 0x88D7, 0xB335, 0x88D8, 0xB336, 0x88D9, 0xB337, 0x88DA, 0xB338, 0x88DB, 0xB339, 0x88DC, 0xB33A, 0x88DD, 0xB33B, 0x88DE, + 0xB33C, 0x88DF, 0xB33D, 0x88E0, 0xB33E, 0x88E1, 0xB33F, 0x88E2, 0xB340, 0x88E3, 0xB341, 0x88E4, 0xB342, 0x88E5, 0xB343, 0x88E6, + 0xB344, 0x88E7, 0xB345, 0x88E8, 0xB346, 0x88E9, 0xB347, 0x88EA, 0xB348, 0x88EB, 0xB349, 0x88EC, 0xB34A, 0x88ED, 0xB34B, 0x88EE, + 0xB34C, 0x88EF, 0xB34D, 0x88F0, 0xB34E, 0x88F1, 0xB34F, 0x88F2, 0xB350, 0x88F3, 0xB351, 0x88F4, 0xB352, 0x88F5, 0xB353, 0x88F6, + 0xB354, 0xB4F5, 0xB355, 0xB4F6, 0xB356, 0xB4F7, 0xB357, 0x88F7, 0xB358, 0xB4F8, 0xB359, 0x88F8, 0xB35A, 0x88F9, 0xB35B, 0xB4F9, + 0xB35C, 0xB4FA, 0xB35D, 0x88FA, 0xB35E, 0xB4FB, 0xB35F, 0xB4FC, 0xB360, 0x88FB, 0xB361, 0x88FC, 0xB362, 0x88FD, 0xB363, 0x88FE, + 0xB364, 0xB4FD, 0xB365, 0xB4FE, 0xB366, 0x8941, 0xB367, 0xB5A1, 0xB368, 0x8942, 0xB369, 0xB5A2, 0xB36A, 0x8943, 0xB36B, 0xB5A3, + 0xB36C, 0x8944, 0xB36D, 0x8945, 0xB36E, 0xB5A4, 0xB36F, 0x8946, 0xB370, 0xB5A5, 0xB371, 0xB5A6, 0xB372, 0x8947, 0xB373, 0x8948, + 0xB374, 0xB5A7, 0xB375, 0x8949, 0xB376, 0x894A, 0xB377, 0x894B, 0xB378, 0xB5A8, 0xB379, 0x894C, 0xB37A, 0x894D, 0xB37B, 0x894E, + 0xB37C, 0x894F, 0xB37D, 0x8950, 0xB37E, 0x8951, 0xB37F, 0x8952, 0xB380, 0xB5A9, 0xB381, 0xB5AA, 0xB382, 0x8953, 0xB383, 0xB5AB, + 0xB384, 0xB5AC, 0xB385, 0xB5AD, 0xB386, 0x8954, 0xB387, 0x8955, 0xB388, 0x8956, 0xB389, 0x8957, 0xB38A, 0x8958, 0xB38B, 0x8959, + 0xB38C, 0xB5AE, 0xB38D, 0x895A, 0xB38E, 0x8961, 0xB38F, 0x8962, 0xB390, 0xB5AF, 0xB391, 0x8963, 0xB392, 0x8964, 0xB393, 0x8965, + 0xB394, 0xB5B0, 0xB395, 0x8966, 0xB396, 0x8967, 0xB397, 0x8968, 0xB398, 0x8969, 0xB399, 0x896A, 0xB39A, 0x896B, 0xB39B, 0x896C, + 0xB39C, 0x896D, 0xB39D, 0x896E, 0xB39E, 0x896F, 0xB39F, 0x8970, 0xB3A0, 0xB5B1, 0xB3A1, 0xB5B2, 0xB3A2, 0x8971, 0xB3A3, 0x8972, + 0xB3A4, 0x8973, 0xB3A5, 0x8974, 0xB3A6, 0x8975, 0xB3A7, 0x8976, 0xB3A8, 0xB5B3, 0xB3A9, 0x8977, 0xB3AA, 0x8978, 0xB3AB, 0x8979, + 0xB3AC, 0xB5B4, 0xB3AD, 0x897A, 0xB3AE, 0x8981, 0xB3AF, 0x8982, 0xB3B0, 0x8983, 0xB3B1, 0x8984, 0xB3B2, 0x8985, 0xB3B3, 0x8986, + 0xB3B4, 0x8987, 0xB3B5, 0x8988, 0xB3B6, 0x8989, 0xB3B7, 0x898A, 0xB3B8, 0x898B, 0xB3B9, 0x898C, 0xB3BA, 0x898D, 0xB3BB, 0x898E, + 0xB3BC, 0x898F, 0xB3BD, 0x8990, 0xB3BE, 0x8991, 0xB3BF, 0x8992, 0xB3C0, 0x8993, 0xB3C1, 0x8994, 0xB3C2, 0x8995, 0xB3C3, 0x8996, + 0xB3C4, 0xB5B5, 0xB3C5, 0xB5B6, 0xB3C6, 0x8997, 0xB3C7, 0x8998, 0xB3C8, 0xB5B7, 0xB3C9, 0x8999, 0xB3CA, 0x899A, 0xB3CB, 0xB5B8, + 0xB3CC, 0xB5B9, 0xB3CD, 0x899B, 0xB3CE, 0xB5BA, 0xB3CF, 0x899C, 0xB3D0, 0xB5BB, 0xB3D1, 0x899D, 0xB3D2, 0x899E, 0xB3D3, 0x899F, + 0xB3D4, 0xB5BC, 0xB3D5, 0xB5BD, 0xB3D6, 0x89A0, 0xB3D7, 0xB5BE, 0xB3D8, 0x89A1, 0xB3D9, 0xB5BF, 0xB3DA, 0x89A2, 0xB3DB, 0xB5C0, + 0xB3DC, 0x89A3, 0xB3DD, 0xB5C1, 0xB3DE, 0x89A4, 0xB3DF, 0x89A5, 0xB3E0, 0xB5C2, 0xB3E1, 0x89A6, 0xB3E2, 0x89A7, 0xB3E3, 0x89A8, + 0xB3E4, 0xB5C3, 0xB3E5, 0x89A9, 0xB3E6, 0x89AA, 0xB3E7, 0x89AB, 0xB3E8, 0xB5C4, 0xB3E9, 0x89AC, 0xB3EA, 0x89AD, 0xB3EB, 0x89AE, + 0xB3EC, 0x89AF, 0xB3ED, 0x89B0, 0xB3EE, 0x89B1, 0xB3EF, 0x89B2, 0xB3F0, 0x89B3, 0xB3F1, 0x89B4, 0xB3F2, 0x89B5, 0xB3F3, 0x89B6, + 0xB3F4, 0x89B7, 0xB3F5, 0x89B8, 0xB3F6, 0x89B9, 0xB3F7, 0x89BA, 0xB3F8, 0x89BB, 0xB3F9, 0x89BC, 0xB3FA, 0x89BD, 0xB3FB, 0x89BE, + 0xB3FC, 0xB5C5, 0xB3FD, 0x89BF, 0xB3FE, 0x89C0, 0xB3FF, 0x89C1, 0xB400, 0x89C2, 0xB401, 0x89C3, 0xB402, 0x89C4, 0xB403, 0x89C5, + 0xB404, 0x89C6, 0xB405, 0x89C7, 0xB406, 0x89C8, 0xB407, 0x89C9, 0xB408, 0x89CA, 0xB409, 0x89CB, 0xB40A, 0x89CC, 0xB40B, 0x89CD, + 0xB40C, 0x89CE, 0xB40D, 0x89CF, 0xB40E, 0x89D0, 0xB40F, 0x89D1, 0xB410, 0xB5C6, 0xB411, 0x89D2, 0xB412, 0x89D3, 0xB413, 0x89D4, + 0xB414, 0x89D5, 0xB415, 0x89D6, 0xB416, 0x89D7, 0xB417, 0x89D8, 0xB418, 0xB5C7, 0xB419, 0x89D9, 0xB41A, 0x89DA, 0xB41B, 0x89DB, + 0xB41C, 0xB5C8, 0xB41D, 0x89DC, 0xB41E, 0x89DD, 0xB41F, 0x89DE, 0xB420, 0xB5C9, 0xB421, 0x89DF, 0xB422, 0x89E0, 0xB423, 0x89E1, + 0xB424, 0x89E2, 0xB425, 0x89E3, 0xB426, 0x89E4, 0xB427, 0x89E5, 0xB428, 0xB5CA, 0xB429, 0xB5CB, 0xB42A, 0x89E6, 0xB42B, 0xB5CC, + 0xB42C, 0x89E7, 0xB42D, 0x89E8, 0xB42E, 0x89E9, 0xB42F, 0x89EA, 0xB430, 0x89EB, 0xB431, 0x89EC, 0xB432, 0x89ED, 0xB433, 0x89EE, + 0xB434, 0xB5CD, 0xB435, 0x89EF, 0xB436, 0x89F0, 0xB437, 0x89F1, 0xB438, 0x89F2, 0xB439, 0x89F3, 0xB43A, 0x89F4, 0xB43B, 0x89F5, + 0xB43C, 0x89F6, 0xB43D, 0x89F7, 0xB43E, 0x89F8, 0xB43F, 0x89F9, 0xB440, 0x89FA, 0xB441, 0x89FB, 0xB442, 0x89FC, 0xB443, 0x89FD, + 0xB444, 0x89FE, 0xB445, 0x8A41, 0xB446, 0x8A42, 0xB447, 0x8A43, 0xB448, 0x8A44, 0xB449, 0x8A45, 0xB44A, 0x8A46, 0xB44B, 0x8A47, + 0xB44C, 0x8A48, 0xB44D, 0x8A49, 0xB44E, 0x8A4A, 0xB44F, 0x8A4B, 0xB450, 0xB5CE, 0xB451, 0xB5CF, 0xB452, 0x8A4C, 0xB453, 0x8A4D, + 0xB454, 0xB5D0, 0xB455, 0x8A4E, 0xB456, 0x8A4F, 0xB457, 0x8A50, 0xB458, 0xB5D1, 0xB459, 0x8A51, 0xB45A, 0x8A52, 0xB45B, 0x8A53, + 0xB45C, 0x8A54, 0xB45D, 0x8A55, 0xB45E, 0x8A56, 0xB45F, 0x8A57, 0xB460, 0xB5D2, 0xB461, 0xB5D3, 0xB462, 0x8A58, 0xB463, 0xB5D4, + 0xB464, 0x8A59, 0xB465, 0xB5D5, 0xB466, 0x8A5A, 0xB467, 0x8A61, 0xB468, 0x8A62, 0xB469, 0x8A63, 0xB46A, 0x8A64, 0xB46B, 0x8A65, + 0xB46C, 0xB5D6, 0xB46D, 0x8A66, 0xB46E, 0x8A67, 0xB46F, 0x8A68, 0xB470, 0x8A69, 0xB471, 0x8A6A, 0xB472, 0x8A6B, 0xB473, 0x8A6C, + 0xB474, 0x8A6D, 0xB475, 0x8A6E, 0xB476, 0x8A6F, 0xB477, 0x8A70, 0xB478, 0x8A71, 0xB479, 0x8A72, 0xB47A, 0x8A73, 0xB47B, 0x8A74, + 0xB47C, 0x8A75, 0xB47D, 0x8A76, 0xB47E, 0x8A77, 0xB47F, 0x8A78, 0xB480, 0xB5D7, 0xB481, 0x8A79, 0xB482, 0x8A7A, 0xB483, 0x8A81, + 0xB484, 0x8A82, 0xB485, 0x8A83, 0xB486, 0x8A84, 0xB487, 0x8A85, 0xB488, 0xB5D8, 0xB489, 0x8A86, 0xB48A, 0x8A87, 0xB48B, 0x8A88, + 0xB48C, 0x8A89, 0xB48D, 0x8A8A, 0xB48E, 0x8A8B, 0xB48F, 0x8A8C, 0xB490, 0x8A8D, 0xB491, 0x8A8E, 0xB492, 0x8A8F, 0xB493, 0x8A90, + 0xB494, 0x8A91, 0xB495, 0x8A92, 0xB496, 0x8A93, 0xB497, 0x8A94, 0xB498, 0x8A95, 0xB499, 0x8A96, 0xB49A, 0x8A97, 0xB49B, 0x8A98, + 0xB49C, 0x8A99, 0xB49D, 0xB5D9, 0xB49E, 0x8A9A, 0xB49F, 0x8A9B, 0xB4A0, 0x8A9C, 0xB4A1, 0x8A9D, 0xB4A2, 0x8A9E, 0xB4A3, 0x8A9F, + 0xB4A4, 0xB5DA, 0xB4A5, 0x8AA0, 0xB4A6, 0x8AA1, 0xB4A7, 0x8AA2, 0xB4A8, 0xB5DB, 0xB4A9, 0x8AA3, 0xB4AA, 0x8AA4, 0xB4AB, 0x8AA5, + 0xB4AC, 0xB5DC, 0xB4AD, 0x8AA6, 0xB4AE, 0x8AA7, 0xB4AF, 0x8AA8, 0xB4B0, 0x8AA9, 0xB4B1, 0x8AAA, 0xB4B2, 0x8AAB, 0xB4B3, 0x8AAC, + 0xB4B4, 0x8AAD, 0xB4B5, 0xB5DD, 0xB4B6, 0x8AAE, 0xB4B7, 0xB5DE, 0xB4B8, 0x8AAF, 0xB4B9, 0xB5DF, 0xB4BA, 0x8AB0, 0xB4BB, 0x8AB1, + 0xB4BC, 0x8AB2, 0xB4BD, 0x8AB3, 0xB4BE, 0x8AB4, 0xB4BF, 0x8AB5, 0xB4C0, 0xB5E0, 0xB4C1, 0x8AB6, 0xB4C2, 0x8AB7, 0xB4C3, 0x8AB8, + 0xB4C4, 0xB5E1, 0xB4C5, 0x8AB9, 0xB4C6, 0x8ABA, 0xB4C7, 0x8ABB, 0xB4C8, 0xB5E2, 0xB4C9, 0x8ABC, 0xB4CA, 0x8ABD, 0xB4CB, 0x8ABE, + 0xB4CC, 0x8ABF, 0xB4CD, 0x8AC0, 0xB4CE, 0x8AC1, 0xB4CF, 0x8AC2, 0xB4D0, 0xB5E3, 0xB4D1, 0x8AC3, 0xB4D2, 0x8AC4, 0xB4D3, 0x8AC5, + 0xB4D4, 0x8AC6, 0xB4D5, 0xB5E4, 0xB4D6, 0x8AC7, 0xB4D7, 0x8AC8, 0xB4D8, 0x8AC9, 0xB4D9, 0x8ACA, 0xB4DA, 0x8ACB, 0xB4DB, 0x8ACC, + 0xB4DC, 0xB5E5, 0xB4DD, 0xB5E6, 0xB4DE, 0x8ACD, 0xB4DF, 0x8ACE, 0xB4E0, 0xB5E7, 0xB4E1, 0x8ACF, 0xB4E2, 0x8AD0, 0xB4E3, 0xB5E8, + 0xB4E4, 0xB5E9, 0xB4E5, 0x8AD1, 0xB4E6, 0xB5EA, 0xB4E7, 0x8AD2, 0xB4E8, 0x8AD3, 0xB4E9, 0x8AD4, 0xB4EA, 0x8AD5, 0xB4EB, 0x8AD6, + 0xB4EC, 0xB5EB, 0xB4ED, 0xB5EC, 0xB4EE, 0x8AD7, 0xB4EF, 0xB5ED, 0xB4F0, 0x8AD8, 0xB4F1, 0xB5EE, 0xB4F2, 0x8AD9, 0xB4F3, 0x8ADA, + 0xB4F4, 0x8ADB, 0xB4F5, 0x8ADC, 0xB4F6, 0x8ADD, 0xB4F7, 0x8ADE, 0xB4F8, 0xB5EF, 0xB4F9, 0x8ADF, 0xB4FA, 0x8AE0, 0xB4FB, 0x8AE1, + 0xB4FC, 0x8AE2, 0xB4FD, 0x8AE3, 0xB4FE, 0x8AE4, 0xB4FF, 0x8AE5, 0xB500, 0x8AE6, 0xB501, 0x8AE7, 0xB502, 0x8AE8, 0xB503, 0x8AE9, + 0xB504, 0x8AEA, 0xB505, 0x8AEB, 0xB506, 0x8AEC, 0xB507, 0x8AED, 0xB508, 0x8AEE, 0xB509, 0x8AEF, 0xB50A, 0x8AF0, 0xB50B, 0x8AF1, + 0xB50C, 0x8AF2, 0xB50D, 0x8AF3, 0xB50E, 0x8AF4, 0xB50F, 0x8AF5, 0xB510, 0x8AF6, 0xB511, 0x8AF7, 0xB512, 0x8AF8, 0xB513, 0x8AF9, + 0xB514, 0xB5F0, 0xB515, 0xB5F1, 0xB516, 0x8AFA, 0xB517, 0x8AFB, 0xB518, 0xB5F2, 0xB519, 0x8AFC, 0xB51A, 0x8AFD, 0xB51B, 0xB5F3, + 0xB51C, 0xB5F4, 0xB51D, 0x8AFE, 0xB51E, 0x8B41, 0xB51F, 0x8B42, 0xB520, 0x8B43, 0xB521, 0x8B44, 0xB522, 0x8B45, 0xB523, 0x8B46, + 0xB524, 0xB5F5, 0xB525, 0xB5F6, 0xB526, 0x8B47, 0xB527, 0xB5F7, 0xB528, 0xB5F8, 0xB529, 0xB5F9, 0xB52A, 0xB5FA, 0xB52B, 0x8B48, + 0xB52C, 0x8B49, 0xB52D, 0x8B4A, 0xB52E, 0x8B4B, 0xB52F, 0x8B4C, 0xB530, 0xB5FB, 0xB531, 0xB5FC, 0xB532, 0x8B4D, 0xB533, 0x8B4E, + 0xB534, 0xB5FD, 0xB535, 0x8B4F, 0xB536, 0x8B50, 0xB537, 0x8B51, 0xB538, 0xB5FE, 0xB539, 0x8B52, 0xB53A, 0x8B53, 0xB53B, 0x8B54, + 0xB53C, 0x8B55, 0xB53D, 0x8B56, 0xB53E, 0x8B57, 0xB53F, 0x8B58, 0xB540, 0xB6A1, 0xB541, 0xB6A2, 0xB542, 0x8B59, 0xB543, 0xB6A3, + 0xB544, 0xB6A4, 0xB545, 0xB6A5, 0xB546, 0x8B5A, 0xB547, 0x8B61, 0xB548, 0x8B62, 0xB549, 0x8B63, 0xB54A, 0x8B64, 0xB54B, 0xB6A6, + 0xB54C, 0xB6A7, 0xB54D, 0xB6A8, 0xB54E, 0x8B65, 0xB54F, 0x8B66, 0xB550, 0xB6A9, 0xB551, 0x8B67, 0xB552, 0x8B68, 0xB553, 0x8B69, + 0xB554, 0xB6AA, 0xB555, 0x8B6A, 0xB556, 0x8B6B, 0xB557, 0x8B6C, 0xB558, 0x8B6D, 0xB559, 0x8B6E, 0xB55A, 0x8B6F, 0xB55B, 0x8B70, + 0xB55C, 0xB6AB, 0xB55D, 0xB6AC, 0xB55E, 0x8B71, 0xB55F, 0xB6AD, 0xB560, 0xB6AE, 0xB561, 0xB6AF, 0xB562, 0x8B72, 0xB563, 0x8B73, + 0xB564, 0x8B74, 0xB565, 0x8B75, 0xB566, 0x8B76, 0xB567, 0x8B77, 0xB568, 0x8B78, 0xB569, 0x8B79, 0xB56A, 0x8B7A, 0xB56B, 0x8B81, + 0xB56C, 0x8B82, 0xB56D, 0x8B83, 0xB56E, 0x8B84, 0xB56F, 0x8B85, 0xB570, 0x8B86, 0xB571, 0x8B87, 0xB572, 0x8B88, 0xB573, 0x8B89, + 0xB574, 0x8B8A, 0xB575, 0x8B8B, 0xB576, 0x8B8C, 0xB577, 0x8B8D, 0xB578, 0x8B8E, 0xB579, 0x8B8F, 0xB57A, 0x8B90, 0xB57B, 0x8B91, + 0xB57C, 0x8B92, 0xB57D, 0x8B93, 0xB57E, 0x8B94, 0xB57F, 0x8B95, 0xB580, 0x8B96, 0xB581, 0x8B97, 0xB582, 0x8B98, 0xB583, 0x8B99, + 0xB584, 0x8B9A, 0xB585, 0x8B9B, 0xB586, 0x8B9C, 0xB587, 0x8B9D, 0xB588, 0x8B9E, 0xB589, 0x8B9F, 0xB58A, 0x8BA0, 0xB58B, 0x8BA1, + 0xB58C, 0x8BA2, 0xB58D, 0x8BA3, 0xB58E, 0x8BA4, 0xB58F, 0x8BA5, 0xB590, 0x8BA6, 0xB591, 0x8BA7, 0xB592, 0x8BA8, 0xB593, 0x8BA9, + 0xB594, 0x8BAA, 0xB595, 0x8BAB, 0xB596, 0x8BAC, 0xB597, 0x8BAD, 0xB598, 0x8BAE, 0xB599, 0x8BAF, 0xB59A, 0x8BB0, 0xB59B, 0x8BB1, + 0xB59C, 0x8BB2, 0xB59D, 0x8BB3, 0xB59E, 0x8BB4, 0xB59F, 0x8BB5, 0xB5A0, 0xB6B0, 0xB5A1, 0xB6B1, 0xB5A2, 0x8BB6, 0xB5A3, 0x8BB7, + 0xB5A4, 0xB6B2, 0xB5A5, 0x8BB8, 0xB5A6, 0x8BB9, 0xB5A7, 0x8BBA, 0xB5A8, 0xB6B3, 0xB5A9, 0x8BBB, 0xB5AA, 0xB6B4, 0xB5AB, 0xB6B5, + 0xB5AC, 0x8BBC, 0xB5AD, 0x8BBD, 0xB5AE, 0x8BBE, 0xB5AF, 0x8BBF, 0xB5B0, 0xB6B6, 0xB5B1, 0xB6B7, 0xB5B2, 0x8BC0, 0xB5B3, 0xB6B8, + 0xB5B4, 0xB6B9, 0xB5B5, 0xB6BA, 0xB5B6, 0x8BC1, 0xB5B7, 0x8BC2, 0xB5B8, 0x8BC3, 0xB5B9, 0x8BC4, 0xB5BA, 0x8BC5, 0xB5BB, 0xB6BB, + 0xB5BC, 0xB6BC, 0xB5BD, 0xB6BD, 0xB5BE, 0x8BC6, 0xB5BF, 0x8BC7, 0xB5C0, 0xB6BE, 0xB5C1, 0x8BC8, 0xB5C2, 0x8BC9, 0xB5C3, 0x8BCA, + 0xB5C4, 0xB6BF, 0xB5C5, 0x8BCB, 0xB5C6, 0x8BCC, 0xB5C7, 0x8BCD, 0xB5C8, 0x8BCE, 0xB5C9, 0x8BCF, 0xB5CA, 0x8BD0, 0xB5CB, 0x8BD1, + 0xB5CC, 0xB6C0, 0xB5CD, 0xB6C1, 0xB5CE, 0x8BD2, 0xB5CF, 0xB6C2, 0xB5D0, 0xB6C3, 0xB5D1, 0xB6C4, 0xB5D2, 0x8BD3, 0xB5D3, 0x8BD4, + 0xB5D4, 0x8BD5, 0xB5D5, 0x8BD6, 0xB5D6, 0x8BD7, 0xB5D7, 0x8BD8, 0xB5D8, 0xB6C5, 0xB5D9, 0x8BD9, 0xB5DA, 0x8BDA, 0xB5DB, 0x8BDB, + 0xB5DC, 0x8BDC, 0xB5DD, 0x8BDD, 0xB5DE, 0x8BDE, 0xB5DF, 0x8BDF, 0xB5E0, 0x8BE0, 0xB5E1, 0x8BE1, 0xB5E2, 0x8BE2, 0xB5E3, 0x8BE3, + 0xB5E4, 0x8BE4, 0xB5E5, 0x8BE5, 0xB5E6, 0x8BE6, 0xB5E7, 0x8BE7, 0xB5E8, 0x8BE8, 0xB5E9, 0x8BE9, 0xB5EA, 0x8BEA, 0xB5EB, 0x8BEB, + 0xB5EC, 0xB6C6, 0xB5ED, 0x8BEC, 0xB5EE, 0x8BED, 0xB5EF, 0x8BEE, 0xB5F0, 0x8BEF, 0xB5F1, 0x8BF0, 0xB5F2, 0x8BF1, 0xB5F3, 0x8BF2, + 0xB5F4, 0x8BF3, 0xB5F5, 0x8BF4, 0xB5F6, 0x8BF5, 0xB5F7, 0x8BF6, 0xB5F8, 0x8BF7, 0xB5F9, 0x8BF8, 0xB5FA, 0x8BF9, 0xB5FB, 0x8BFA, + 0xB5FC, 0x8BFB, 0xB5FD, 0x8BFC, 0xB5FE, 0x8BFD, 0xB5FF, 0x8BFE, 0xB600, 0x8C41, 0xB601, 0x8C42, 0xB602, 0x8C43, 0xB603, 0x8C44, + 0xB604, 0x8C45, 0xB605, 0x8C46, 0xB606, 0x8C47, 0xB607, 0x8C48, 0xB608, 0x8C49, 0xB609, 0x8C4A, 0xB60A, 0x8C4B, 0xB60B, 0x8C4C, + 0xB60C, 0x8C4D, 0xB60D, 0x8C4E, 0xB60E, 0x8C4F, 0xB60F, 0x8C50, 0xB610, 0xB6C7, 0xB611, 0xB6C8, 0xB612, 0x8C51, 0xB613, 0x8C52, + 0xB614, 0xB6C9, 0xB615, 0x8C53, 0xB616, 0x8C54, 0xB617, 0x8C55, 0xB618, 0xB6CA, 0xB619, 0x8C56, 0xB61A, 0x8C57, 0xB61B, 0x8C58, + 0xB61C, 0x8C59, 0xB61D, 0x8C5A, 0xB61E, 0x8C61, 0xB61F, 0x8C62, 0xB620, 0x8C63, 0xB621, 0x8C64, 0xB622, 0x8C65, 0xB623, 0x8C66, + 0xB624, 0x8C67, 0xB625, 0xB6CB, 0xB626, 0x8C68, 0xB627, 0x8C69, 0xB628, 0x8C6A, 0xB629, 0x8C6B, 0xB62A, 0x8C6C, 0xB62B, 0x8C6D, + 0xB62C, 0xB6CC, 0xB62D, 0x8C6E, 0xB62E, 0x8C6F, 0xB62F, 0x8C70, 0xB630, 0x8C71, 0xB631, 0x8C72, 0xB632, 0x8C73, 0xB633, 0x8C74, + 0xB634, 0xB6CD, 0xB635, 0x8C75, 0xB636, 0x8C76, 0xB637, 0x8C77, 0xB638, 0x8C78, 0xB639, 0x8C79, 0xB63A, 0x8C7A, 0xB63B, 0x8C81, + 0xB63C, 0x8C82, 0xB63D, 0x8C83, 0xB63E, 0x8C84, 0xB63F, 0x8C85, 0xB640, 0x8C86, 0xB641, 0x8C87, 0xB642, 0x8C88, 0xB643, 0x8C89, + 0xB644, 0x8C8A, 0xB645, 0x8C8B, 0xB646, 0x8C8C, 0xB647, 0x8C8D, 0xB648, 0xB6CE, 0xB649, 0x8C8E, 0xB64A, 0x8C8F, 0xB64B, 0x8C90, + 0xB64C, 0x8C91, 0xB64D, 0x8C92, 0xB64E, 0x8C93, 0xB64F, 0x8C94, 0xB650, 0x8C95, 0xB651, 0x8C96, 0xB652, 0x8C97, 0xB653, 0x8C98, + 0xB654, 0x8C99, 0xB655, 0x8C9A, 0xB656, 0x8C9B, 0xB657, 0x8C9C, 0xB658, 0x8C9D, 0xB659, 0x8C9E, 0xB65A, 0x8C9F, 0xB65B, 0x8CA0, + 0xB65C, 0x8CA1, 0xB65D, 0x8CA2, 0xB65E, 0x8CA3, 0xB65F, 0x8CA4, 0xB660, 0x8CA5, 0xB661, 0x8CA6, 0xB662, 0x8CA7, 0xB663, 0x8CA8, + 0xB664, 0xB6CF, 0xB665, 0x8CA9, 0xB666, 0x8CAA, 0xB667, 0x8CAB, 0xB668, 0xB6D0, 0xB669, 0x8CAC, 0xB66A, 0x8CAD, 0xB66B, 0x8CAE, + 0xB66C, 0x8CAF, 0xB66D, 0x8CB0, 0xB66E, 0x8CB1, 0xB66F, 0x8CB2, 0xB670, 0x8CB3, 0xB671, 0x8CB4, 0xB672, 0x8CB5, 0xB673, 0x8CB6, + 0xB674, 0x8CB7, 0xB675, 0x8CB8, 0xB676, 0x8CB9, 0xB677, 0x8CBA, 0xB678, 0x8CBB, 0xB679, 0x8CBC, 0xB67A, 0x8CBD, 0xB67B, 0x8CBE, + 0xB67C, 0x8CBF, 0xB67D, 0x8CC0, 0xB67E, 0x8CC1, 0xB67F, 0x8CC2, 0xB680, 0x8CC3, 0xB681, 0x8CC4, 0xB682, 0x8CC5, 0xB683, 0x8CC6, + 0xB684, 0x8CC7, 0xB685, 0x8CC8, 0xB686, 0x8CC9, 0xB687, 0x8CCA, 0xB688, 0x8CCB, 0xB689, 0x8CCC, 0xB68A, 0x8CCD, 0xB68B, 0x8CCE, + 0xB68C, 0x8CCF, 0xB68D, 0x8CD0, 0xB68E, 0x8CD1, 0xB68F, 0x8CD2, 0xB690, 0x8CD3, 0xB691, 0x8CD4, 0xB692, 0x8CD5, 0xB693, 0x8CD6, + 0xB694, 0x8CD7, 0xB695, 0x8CD8, 0xB696, 0x8CD9, 0xB697, 0x8CDA, 0xB698, 0x8CDB, 0xB699, 0x8CDC, 0xB69A, 0x8CDD, 0xB69B, 0x8CDE, + 0xB69C, 0xB6D1, 0xB69D, 0xB6D2, 0xB69E, 0x8CDF, 0xB69F, 0x8CE0, 0xB6A0, 0xB6D3, 0xB6A1, 0x8CE1, 0xB6A2, 0x8CE2, 0xB6A3, 0x8CE3, + 0xB6A4, 0xB6D4, 0xB6A5, 0x8CE4, 0xB6A6, 0x8CE5, 0xB6A7, 0x8CE6, 0xB6A8, 0x8CE7, 0xB6A9, 0x8CE8, 0xB6AA, 0x8CE9, 0xB6AB, 0xB6D5, + 0xB6AC, 0xB6D6, 0xB6AD, 0x8CEA, 0xB6AE, 0x8CEB, 0xB6AF, 0x8CEC, 0xB6B0, 0x8CED, 0xB6B1, 0xB6D7, 0xB6B2, 0x8CEE, 0xB6B3, 0x8CEF, + 0xB6B4, 0x8CF0, 0xB6B5, 0x8CF1, 0xB6B6, 0x8CF2, 0xB6B7, 0x8CF3, 0xB6B8, 0x8CF4, 0xB6B9, 0x8CF5, 0xB6BA, 0x8CF6, 0xB6BB, 0x8CF7, + 0xB6BC, 0x8CF8, 0xB6BD, 0x8CF9, 0xB6BE, 0x8CFA, 0xB6BF, 0x8CFB, 0xB6C0, 0x8CFC, 0xB6C1, 0x8CFD, 0xB6C2, 0x8CFE, 0xB6C3, 0x8D41, + 0xB6C4, 0x8D42, 0xB6C5, 0x8D43, 0xB6C6, 0x8D44, 0xB6C7, 0x8D45, 0xB6C8, 0x8D46, 0xB6C9, 0x8D47, 0xB6CA, 0x8D48, 0xB6CB, 0x8D49, + 0xB6CC, 0x8D4A, 0xB6CD, 0x8D4B, 0xB6CE, 0x8D4C, 0xB6CF, 0x8D4D, 0xB6D0, 0x8D4E, 0xB6D1, 0x8D4F, 0xB6D2, 0x8D50, 0xB6D3, 0x8D51, + 0xB6D4, 0xB6D8, 0xB6D5, 0x8D52, 0xB6D6, 0x8D53, 0xB6D7, 0x8D54, 0xB6D8, 0x8D55, 0xB6D9, 0x8D56, 0xB6DA, 0x8D57, 0xB6DB, 0x8D58, + 0xB6DC, 0x8D59, 0xB6DD, 0x8D5A, 0xB6DE, 0x8D61, 0xB6DF, 0x8D62, 0xB6E0, 0x8D63, 0xB6E1, 0x8D64, 0xB6E2, 0x8D65, 0xB6E3, 0x8D66, + 0xB6E4, 0x8D67, 0xB6E5, 0x8D68, 0xB6E6, 0x8D69, 0xB6E7, 0x8D6A, 0xB6E8, 0x8D6B, 0xB6E9, 0x8D6C, 0xB6EA, 0x8D6D, 0xB6EB, 0x8D6E, + 0xB6EC, 0x8D6F, 0xB6ED, 0x8D70, 0xB6EE, 0x8D71, 0xB6EF, 0x8D72, 0xB6F0, 0xB6D9, 0xB6F1, 0x8D73, 0xB6F2, 0x8D74, 0xB6F3, 0x8D75, + 0xB6F4, 0xB6DA, 0xB6F5, 0x8D76, 0xB6F6, 0x8D77, 0xB6F7, 0x8D78, 0xB6F8, 0xB6DB, 0xB6F9, 0x8D79, 0xB6FA, 0x8D7A, 0xB6FB, 0x8D81, + 0xB6FC, 0x8D82, 0xB6FD, 0x8D83, 0xB6FE, 0x8D84, 0xB6FF, 0x8D85, 0xB700, 0xB6DC, 0xB701, 0xB6DD, 0xB702, 0x8D86, 0xB703, 0x8D87, + 0xB704, 0x8D88, 0xB705, 0xB6DE, 0xB706, 0x8D89, 0xB707, 0x8D8A, 0xB708, 0x8D8B, 0xB709, 0x8D8C, 0xB70A, 0x8D8D, 0xB70B, 0x8D8E, + 0xB70C, 0x8D8F, 0xB70D, 0x8D90, 0xB70E, 0x8D91, 0xB70F, 0x8D92, 0xB710, 0x8D93, 0xB711, 0x8D94, 0xB712, 0x8D95, 0xB713, 0x8D96, + 0xB714, 0x8D97, 0xB715, 0x8D98, 0xB716, 0x8D99, 0xB717, 0x8D9A, 0xB718, 0x8D9B, 0xB719, 0x8D9C, 0xB71A, 0x8D9D, 0xB71B, 0x8D9E, + 0xB71C, 0x8D9F, 0xB71D, 0x8DA0, 0xB71E, 0x8DA1, 0xB71F, 0x8DA2, 0xB720, 0x8DA3, 0xB721, 0x8DA4, 0xB722, 0x8DA5, 0xB723, 0x8DA6, + 0xB724, 0x8DA7, 0xB725, 0x8DA8, 0xB726, 0x8DA9, 0xB727, 0x8DAA, 0xB728, 0xB6DF, 0xB729, 0xB6E0, 0xB72A, 0x8DAB, 0xB72B, 0x8DAC, + 0xB72C, 0xB6E1, 0xB72D, 0x8DAD, 0xB72E, 0x8DAE, 0xB72F, 0xB6E2, 0xB730, 0xB6E3, 0xB731, 0x8DAF, 0xB732, 0x8DB0, 0xB733, 0x8DB1, + 0xB734, 0x8DB2, 0xB735, 0x8DB3, 0xB736, 0x8DB4, 0xB737, 0x8DB5, 0xB738, 0xB6E4, 0xB739, 0xB6E5, 0xB73A, 0x8DB6, 0xB73B, 0xB6E6, + 0xB73C, 0x8DB7, 0xB73D, 0x8DB8, 0xB73E, 0x8DB9, 0xB73F, 0x8DBA, 0xB740, 0x8DBB, 0xB741, 0x8DBC, 0xB742, 0x8DBD, 0xB743, 0x8DBE, + 0xB744, 0xB6E7, 0xB745, 0x8DBF, 0xB746, 0x8DC0, 0xB747, 0x8DC1, 0xB748, 0xB6E8, 0xB749, 0x8DC2, 0xB74A, 0x8DC3, 0xB74B, 0x8DC4, + 0xB74C, 0xB6E9, 0xB74D, 0x8DC5, 0xB74E, 0x8DC6, 0xB74F, 0x8DC7, 0xB750, 0x8DC8, 0xB751, 0x8DC9, 0xB752, 0x8DCA, 0xB753, 0x8DCB, + 0xB754, 0xB6EA, 0xB755, 0xB6EB, 0xB756, 0x8DCC, 0xB757, 0x8DCD, 0xB758, 0x8DCE, 0xB759, 0x8DCF, 0xB75A, 0x8DD0, 0xB75B, 0x8DD1, + 0xB75C, 0x8DD2, 0xB75D, 0x8DD3, 0xB75E, 0x8DD4, 0xB75F, 0x8DD5, 0xB760, 0xB6EC, 0xB761, 0x8DD6, 0xB762, 0x8DD7, 0xB763, 0x8DD8, + 0xB764, 0xB6ED, 0xB765, 0x8DD9, 0xB766, 0x8DDA, 0xB767, 0x8DDB, 0xB768, 0xB6EE, 0xB769, 0x8DDC, 0xB76A, 0x8DDD, 0xB76B, 0x8DDE, + 0xB76C, 0x8DDF, 0xB76D, 0x8DE0, 0xB76E, 0x8DE1, 0xB76F, 0x8DE2, 0xB770, 0xB6EF, 0xB771, 0xB6F0, 0xB772, 0x8DE3, 0xB773, 0xB6F1, + 0xB774, 0x8DE4, 0xB775, 0xB6F2, 0xB776, 0x8DE5, 0xB777, 0x8DE6, 0xB778, 0x8DE7, 0xB779, 0x8DE8, 0xB77A, 0x8DE9, 0xB77B, 0x8DEA, + 0xB77C, 0xB6F3, 0xB77D, 0xB6F4, 0xB77E, 0x8DEB, 0xB77F, 0x8DEC, 0xB780, 0xB6F5, 0xB781, 0x8DED, 0xB782, 0x8DEE, 0xB783, 0x8DEF, + 0xB784, 0xB6F6, 0xB785, 0x8DF0, 0xB786, 0x8DF1, 0xB787, 0x8DF2, 0xB788, 0x8DF3, 0xB789, 0x8DF4, 0xB78A, 0x8DF5, 0xB78B, 0x8DF6, + 0xB78C, 0xB6F7, 0xB78D, 0xB6F8, 0xB78E, 0x8DF7, 0xB78F, 0xB6F9, 0xB790, 0xB6FA, 0xB791, 0xB6FB, 0xB792, 0xB6FC, 0xB793, 0x8DF8, + 0xB794, 0x8DF9, 0xB795, 0x8DFA, 0xB796, 0xB6FD, 0xB797, 0xB6FE, 0xB798, 0xB7A1, 0xB799, 0xB7A2, 0xB79A, 0x8DFB, 0xB79B, 0x8DFC, + 0xB79C, 0xB7A3, 0xB79D, 0x8DFD, 0xB79E, 0x8DFE, 0xB79F, 0x8E41, 0xB7A0, 0xB7A4, 0xB7A1, 0x8E42, 0xB7A2, 0x8E43, 0xB7A3, 0x8E44, + 0xB7A4, 0x8E45, 0xB7A5, 0x8E46, 0xB7A6, 0x8E47, 0xB7A7, 0x8E48, 0xB7A8, 0xB7A5, 0xB7A9, 0xB7A6, 0xB7AA, 0x8E49, 0xB7AB, 0xB7A7, + 0xB7AC, 0xB7A8, 0xB7AD, 0xB7A9, 0xB7AE, 0x8E4A, 0xB7AF, 0x8E4B, 0xB7B0, 0x8E4C, 0xB7B1, 0x8E4D, 0xB7B2, 0x8E4E, 0xB7B3, 0x8E4F, + 0xB7B4, 0xB7AA, 0xB7B5, 0xB7AB, 0xB7B6, 0x8E50, 0xB7B7, 0x8E51, 0xB7B8, 0xB7AC, 0xB7B9, 0x8E52, 0xB7BA, 0x8E53, 0xB7BB, 0x8E54, + 0xB7BC, 0x8E55, 0xB7BD, 0x8E56, 0xB7BE, 0x8E57, 0xB7BF, 0x8E58, 0xB7C0, 0x8E59, 0xB7C1, 0x8E5A, 0xB7C2, 0x8E61, 0xB7C3, 0x8E62, + 0xB7C4, 0x8E63, 0xB7C5, 0x8E64, 0xB7C6, 0x8E65, 0xB7C7, 0xB7AD, 0xB7C8, 0x8E66, 0xB7C9, 0xB7AE, 0xB7CA, 0x8E67, 0xB7CB, 0x8E68, + 0xB7CC, 0x8E69, 0xB7CD, 0x8E6A, 0xB7CE, 0x8E6B, 0xB7CF, 0x8E6C, 0xB7D0, 0x8E6D, 0xB7D1, 0x8E6E, 0xB7D2, 0x8E6F, 0xB7D3, 0x8E70, + 0xB7D4, 0x8E71, 0xB7D5, 0x8E72, 0xB7D6, 0x8E73, 0xB7D7, 0x8E74, 0xB7D8, 0x8E75, 0xB7D9, 0x8E76, 0xB7DA, 0x8E77, 0xB7DB, 0x8E78, + 0xB7DC, 0x8E79, 0xB7DD, 0x8E7A, 0xB7DE, 0x8E81, 0xB7DF, 0x8E82, 0xB7E0, 0x8E83, 0xB7E1, 0x8E84, 0xB7E2, 0x8E85, 0xB7E3, 0x8E86, + 0xB7E4, 0x8E87, 0xB7E5, 0x8E88, 0xB7E6, 0x8E89, 0xB7E7, 0x8E8A, 0xB7E8, 0x8E8B, 0xB7E9, 0x8E8C, 0xB7EA, 0x8E8D, 0xB7EB, 0x8E8E, + 0xB7EC, 0xB7AF, 0xB7ED, 0xB7B0, 0xB7EE, 0x8E8F, 0xB7EF, 0x8E90, 0xB7F0, 0xB7B1, 0xB7F1, 0x8E91, 0xB7F2, 0x8E92, 0xB7F3, 0x8E93, + 0xB7F4, 0xB7B2, 0xB7F5, 0x8E94, 0xB7F6, 0x8E95, 0xB7F7, 0x8E96, 0xB7F8, 0x8E97, 0xB7F9, 0x8E98, 0xB7FA, 0x8E99, 0xB7FB, 0x8E9A, + 0xB7FC, 0xB7B3, 0xB7FD, 0xB7B4, 0xB7FE, 0x8E9B, 0xB7FF, 0xB7B5, 0xB800, 0xB7B6, 0xB801, 0xB7B7, 0xB802, 0x8E9C, 0xB803, 0x8E9D, + 0xB804, 0x8E9E, 0xB805, 0x8E9F, 0xB806, 0x8EA0, 0xB807, 0xB7B8, 0xB808, 0xB7B9, 0xB809, 0xB7BA, 0xB80A, 0x8EA1, 0xB80B, 0x8EA2, + 0xB80C, 0xB7BB, 0xB80D, 0x8EA3, 0xB80E, 0x8EA4, 0xB80F, 0x8EA5, 0xB810, 0xB7BC, 0xB811, 0x8EA6, 0xB812, 0x8EA7, 0xB813, 0x8EA8, + 0xB814, 0x8EA9, 0xB815, 0x8EAA, 0xB816, 0x8EAB, 0xB817, 0x8EAC, 0xB818, 0xB7BD, 0xB819, 0xB7BE, 0xB81A, 0x8EAD, 0xB81B, 0xB7BF, + 0xB81C, 0x8EAE, 0xB81D, 0xB7C0, 0xB81E, 0x8EAF, 0xB81F, 0x8EB0, 0xB820, 0x8EB1, 0xB821, 0x8EB2, 0xB822, 0x8EB3, 0xB823, 0x8EB4, + 0xB824, 0xB7C1, 0xB825, 0xB7C2, 0xB826, 0x8EB5, 0xB827, 0x8EB6, 0xB828, 0xB7C3, 0xB829, 0x8EB7, 0xB82A, 0x8EB8, 0xB82B, 0x8EB9, + 0xB82C, 0xB7C4, 0xB82D, 0x8EBA, 0xB82E, 0x8EBB, 0xB82F, 0x8EBC, 0xB830, 0x8EBD, 0xB831, 0x8EBE, 0xB832, 0x8EBF, 0xB833, 0x8EC0, + 0xB834, 0xB7C5, 0xB835, 0xB7C6, 0xB836, 0x8EC1, 0xB837, 0xB7C7, 0xB838, 0xB7C8, 0xB839, 0xB7C9, 0xB83A, 0x8EC2, 0xB83B, 0x8EC3, + 0xB83C, 0x8EC4, 0xB83D, 0x8EC5, 0xB83E, 0x8EC6, 0xB83F, 0x8EC7, 0xB840, 0xB7CA, 0xB841, 0x8EC8, 0xB842, 0x8EC9, 0xB843, 0x8ECA, + 0xB844, 0xB7CB, 0xB845, 0x8ECB, 0xB846, 0x8ECC, 0xB847, 0x8ECD, 0xB848, 0x8ECE, 0xB849, 0x8ECF, 0xB84A, 0x8ED0, 0xB84B, 0x8ED1, + 0xB84C, 0x8ED2, 0xB84D, 0x8ED3, 0xB84E, 0x8ED4, 0xB84F, 0x8ED5, 0xB850, 0x8ED6, 0xB851, 0xB7CC, 0xB852, 0x8ED7, 0xB853, 0xB7CD, + 0xB854, 0x8ED8, 0xB855, 0x8ED9, 0xB856, 0x8EDA, 0xB857, 0x8EDB, 0xB858, 0x8EDC, 0xB859, 0x8EDD, 0xB85A, 0x8EDE, 0xB85B, 0x8EDF, + 0xB85C, 0xB7CE, 0xB85D, 0xB7CF, 0xB85E, 0x8EE0, 0xB85F, 0x8EE1, 0xB860, 0xB7D0, 0xB861, 0x8EE2, 0xB862, 0x8EE3, 0xB863, 0x8EE4, + 0xB864, 0xB7D1, 0xB865, 0x8EE5, 0xB866, 0x8EE6, 0xB867, 0x8EE7, 0xB868, 0x8EE8, 0xB869, 0x8EE9, 0xB86A, 0x8EEA, 0xB86B, 0x8EEB, + 0xB86C, 0xB7D2, 0xB86D, 0xB7D3, 0xB86E, 0x8EEC, 0xB86F, 0xB7D4, 0xB870, 0x8EED, 0xB871, 0xB7D5, 0xB872, 0x8EEE, 0xB873, 0x8EEF, + 0xB874, 0x8EF0, 0xB875, 0x8EF1, 0xB876, 0x8EF2, 0xB877, 0x8EF3, 0xB878, 0xB7D6, 0xB879, 0x8EF4, 0xB87A, 0x8EF5, 0xB87B, 0x8EF6, + 0xB87C, 0xB7D7, 0xB87D, 0x8EF7, 0xB87E, 0x8EF8, 0xB87F, 0x8EF9, 0xB880, 0x8EFA, 0xB881, 0x8EFB, 0xB882, 0x8EFC, 0xB883, 0x8EFD, + 0xB884, 0x8EFE, 0xB885, 0x8F41, 0xB886, 0x8F42, 0xB887, 0x8F43, 0xB888, 0x8F44, 0xB889, 0x8F45, 0xB88A, 0x8F46, 0xB88B, 0x8F47, + 0xB88C, 0x8F48, 0xB88D, 0xB7D8, 0xB88E, 0x8F49, 0xB88F, 0x8F4A, 0xB890, 0x8F4B, 0xB891, 0x8F4C, 0xB892, 0x8F4D, 0xB893, 0x8F4E, + 0xB894, 0x8F4F, 0xB895, 0x8F50, 0xB896, 0x8F51, 0xB897, 0x8F52, 0xB898, 0x8F53, 0xB899, 0x8F54, 0xB89A, 0x8F55, 0xB89B, 0x8F56, + 0xB89C, 0x8F57, 0xB89D, 0x8F58, 0xB89E, 0x8F59, 0xB89F, 0x8F5A, 0xB8A0, 0x8F61, 0xB8A1, 0x8F62, 0xB8A2, 0x8F63, 0xB8A3, 0x8F64, + 0xB8A4, 0x8F65, 0xB8A5, 0x8F66, 0xB8A6, 0x8F67, 0xB8A7, 0x8F68, 0xB8A8, 0xB7D9, 0xB8A9, 0x8F69, 0xB8AA, 0x8F6A, 0xB8AB, 0x8F6B, + 0xB8AC, 0x8F6C, 0xB8AD, 0x8F6D, 0xB8AE, 0x8F6E, 0xB8AF, 0x8F6F, 0xB8B0, 0xB7DA, 0xB8B1, 0x8F70, 0xB8B2, 0x8F71, 0xB8B3, 0x8F72, + 0xB8B4, 0xB7DB, 0xB8B5, 0x8F73, 0xB8B6, 0x8F74, 0xB8B7, 0x8F75, 0xB8B8, 0xB7DC, 0xB8B9, 0x8F76, 0xB8BA, 0x8F77, 0xB8BB, 0x8F78, + 0xB8BC, 0x8F79, 0xB8BD, 0x8F7A, 0xB8BE, 0x8F81, 0xB8BF, 0x8F82, 0xB8C0, 0xB7DD, 0xB8C1, 0xB7DE, 0xB8C2, 0x8F83, 0xB8C3, 0xB7DF, + 0xB8C4, 0x8F84, 0xB8C5, 0xB7E0, 0xB8C6, 0x8F85, 0xB8C7, 0x8F86, 0xB8C8, 0x8F87, 0xB8C9, 0x8F88, 0xB8CA, 0x8F89, 0xB8CB, 0x8F8A, + 0xB8CC, 0xB7E1, 0xB8CD, 0x8F8B, 0xB8CE, 0x8F8C, 0xB8CF, 0x8F8D, 0xB8D0, 0xB7E2, 0xB8D1, 0x8F8E, 0xB8D2, 0x8F8F, 0xB8D3, 0x8F90, + 0xB8D4, 0xB7E3, 0xB8D5, 0x8F91, 0xB8D6, 0x8F92, 0xB8D7, 0x8F93, 0xB8D8, 0x8F94, 0xB8D9, 0x8F95, 0xB8DA, 0x8F96, 0xB8DB, 0x8F97, + 0xB8DC, 0x8F98, 0xB8DD, 0xB7E4, 0xB8DE, 0x8F99, 0xB8DF, 0xB7E5, 0xB8E0, 0x8F9A, 0xB8E1, 0xB7E6, 0xB8E2, 0x8F9B, 0xB8E3, 0x8F9C, + 0xB8E4, 0x8F9D, 0xB8E5, 0x8F9E, 0xB8E6, 0x8F9F, 0xB8E7, 0x8FA0, 0xB8E8, 0xB7E7, 0xB8E9, 0xB7E8, 0xB8EA, 0x8FA1, 0xB8EB, 0x8FA2, + 0xB8EC, 0xB7E9, 0xB8ED, 0x8FA3, 0xB8EE, 0x8FA4, 0xB8EF, 0x8FA5, 0xB8F0, 0xB7EA, 0xB8F1, 0x8FA6, 0xB8F2, 0x8FA7, 0xB8F3, 0x8FA8, + 0xB8F4, 0x8FA9, 0xB8F5, 0x8FAA, 0xB8F6, 0x8FAB, 0xB8F7, 0x8FAC, 0xB8F8, 0xB7EB, 0xB8F9, 0xB7EC, 0xB8FA, 0x8FAD, 0xB8FB, 0xB7ED, + 0xB8FC, 0x8FAE, 0xB8FD, 0xB7EE, 0xB8FE, 0x8FAF, 0xB8FF, 0x8FB0, 0xB900, 0x8FB1, 0xB901, 0x8FB2, 0xB902, 0x8FB3, 0xB903, 0x8FB4, + 0xB904, 0xB7EF, 0xB905, 0x8FB5, 0xB906, 0x8FB6, 0xB907, 0x8FB7, 0xB908, 0x8FB8, 0xB909, 0x8FB9, 0xB90A, 0x8FBA, 0xB90B, 0x8FBB, + 0xB90C, 0x8FBC, 0xB90D, 0x8FBD, 0xB90E, 0x8FBE, 0xB90F, 0x8FBF, 0xB910, 0x8FC0, 0xB911, 0x8FC1, 0xB912, 0x8FC2, 0xB913, 0x8FC3, + 0xB914, 0x8FC4, 0xB915, 0x8FC5, 0xB916, 0x8FC6, 0xB917, 0x8FC7, 0xB918, 0xB7F0, 0xB919, 0x8FC8, 0xB91A, 0x8FC9, 0xB91B, 0x8FCA, + 0xB91C, 0x8FCB, 0xB91D, 0x8FCC, 0xB91E, 0x8FCD, 0xB91F, 0x8FCE, 0xB920, 0xB7F1, 0xB921, 0x8FCF, 0xB922, 0x8FD0, 0xB923, 0x8FD1, + 0xB924, 0x8FD2, 0xB925, 0x8FD3, 0xB926, 0x8FD4, 0xB927, 0x8FD5, 0xB928, 0x8FD6, 0xB929, 0x8FD7, 0xB92A, 0x8FD8, 0xB92B, 0x8FD9, + 0xB92C, 0x8FDA, 0xB92D, 0x8FDB, 0xB92E, 0x8FDC, 0xB92F, 0x8FDD, 0xB930, 0x8FDE, 0xB931, 0x8FDF, 0xB932, 0x8FE0, 0xB933, 0x8FE1, + 0xB934, 0x8FE2, 0xB935, 0x8FE3, 0xB936, 0x8FE4, 0xB937, 0x8FE5, 0xB938, 0x8FE6, 0xB939, 0x8FE7, 0xB93A, 0x8FE8, 0xB93B, 0x8FE9, + 0xB93C, 0xB7F2, 0xB93D, 0xB7F3, 0xB93E, 0x8FEA, 0xB93F, 0x8FEB, 0xB940, 0xB7F4, 0xB941, 0x8FEC, 0xB942, 0x8FED, 0xB943, 0x8FEE, + 0xB944, 0xB7F5, 0xB945, 0x8FEF, 0xB946, 0x8FF0, 0xB947, 0x8FF1, 0xB948, 0x8FF2, 0xB949, 0x8FF3, 0xB94A, 0x8FF4, 0xB94B, 0x8FF5, + 0xB94C, 0xB7F6, 0xB94D, 0x8FF6, 0xB94E, 0x8FF7, 0xB94F, 0xB7F7, 0xB950, 0x8FF8, 0xB951, 0xB7F8, 0xB952, 0x8FF9, 0xB953, 0x8FFA, + 0xB954, 0x8FFB, 0xB955, 0x8FFC, 0xB956, 0x8FFD, 0xB957, 0x8FFE, 0xB958, 0xB7F9, 0xB959, 0xB7FA, 0xB95A, 0x9041, 0xB95B, 0x9042, + 0xB95C, 0xB7FB, 0xB95D, 0x9043, 0xB95E, 0x9044, 0xB95F, 0x9045, 0xB960, 0xB7FC, 0xB961, 0x9046, 0xB962, 0x9047, 0xB963, 0x9048, + 0xB964, 0x9049, 0xB965, 0x904A, 0xB966, 0x904B, 0xB967, 0x904C, 0xB968, 0xB7FD, 0xB969, 0xB7FE, 0xB96A, 0x904D, 0xB96B, 0xB8A1, + 0xB96C, 0x904E, 0xB96D, 0xB8A2, 0xB96E, 0x904F, 0xB96F, 0x9050, 0xB970, 0x9051, 0xB971, 0x9052, 0xB972, 0x9053, 0xB973, 0x9054, + 0xB974, 0xB8A3, 0xB975, 0xB8A4, 0xB976, 0x9055, 0xB977, 0x9056, 0xB978, 0xB8A5, 0xB979, 0x9057, 0xB97A, 0x9058, 0xB97B, 0x9059, + 0xB97C, 0xB8A6, 0xB97D, 0x905A, 0xB97E, 0x9061, 0xB97F, 0x9062, 0xB980, 0x9063, 0xB981, 0x9064, 0xB982, 0x9065, 0xB983, 0x9066, + 0xB984, 0xB8A7, 0xB985, 0xB8A8, 0xB986, 0x9067, 0xB987, 0xB8A9, 0xB988, 0x9068, 0xB989, 0xB8AA, 0xB98A, 0xB8AB, 0xB98B, 0x9069, + 0xB98C, 0x906A, 0xB98D, 0xB8AC, 0xB98E, 0xB8AD, 0xB98F, 0x906B, 0xB990, 0x906C, 0xB991, 0x906D, 0xB992, 0x906E, 0xB993, 0x906F, + 0xB994, 0x9070, 0xB995, 0x9071, 0xB996, 0x9072, 0xB997, 0x9073, 0xB998, 0x9074, 0xB999, 0x9075, 0xB99A, 0x9076, 0xB99B, 0x9077, + 0xB99C, 0x9078, 0xB99D, 0x9079, 0xB99E, 0x907A, 0xB99F, 0x9081, 0xB9A0, 0x9082, 0xB9A1, 0x9083, 0xB9A2, 0x9084, 0xB9A3, 0x9085, + 0xB9A4, 0x9086, 0xB9A5, 0x9087, 0xB9A6, 0x9088, 0xB9A7, 0x9089, 0xB9A8, 0x908A, 0xB9A9, 0x908B, 0xB9AA, 0x908C, 0xB9AB, 0x908D, + 0xB9AC, 0xB8AE, 0xB9AD, 0xB8AF, 0xB9AE, 0x908E, 0xB9AF, 0x908F, 0xB9B0, 0xB8B0, 0xB9B1, 0x9090, 0xB9B2, 0x9091, 0xB9B3, 0x9092, + 0xB9B4, 0xB8B1, 0xB9B5, 0x9093, 0xB9B6, 0x9094, 0xB9B7, 0x9095, 0xB9B8, 0x9096, 0xB9B9, 0x9097, 0xB9BA, 0x9098, 0xB9BB, 0x9099, + 0xB9BC, 0xB8B2, 0xB9BD, 0xB8B3, 0xB9BE, 0x909A, 0xB9BF, 0xB8B4, 0xB9C0, 0x909B, 0xB9C1, 0xB8B5, 0xB9C2, 0x909C, 0xB9C3, 0x909D, + 0xB9C4, 0x909E, 0xB9C5, 0x909F, 0xB9C6, 0x90A0, 0xB9C7, 0x90A1, 0xB9C8, 0xB8B6, 0xB9C9, 0xB8B7, 0xB9CA, 0x90A2, 0xB9CB, 0x90A3, + 0xB9CC, 0xB8B8, 0xB9CD, 0x90A4, 0xB9CE, 0xB8B9, 0xB9CF, 0xB8BA, 0xB9D0, 0xB8BB, 0xB9D1, 0xB8BC, 0xB9D2, 0xB8BD, 0xB9D3, 0x90A5, + 0xB9D4, 0x90A6, 0xB9D5, 0x90A7, 0xB9D6, 0x90A8, 0xB9D7, 0x90A9, 0xB9D8, 0xB8BE, 0xB9D9, 0xB8BF, 0xB9DA, 0x90AA, 0xB9DB, 0xB8C0, + 0xB9DC, 0x90AB, 0xB9DD, 0xB8C1, 0xB9DE, 0xB8C2, 0xB9DF, 0x90AC, 0xB9E0, 0x90AD, 0xB9E1, 0xB8C3, 0xB9E2, 0x90AE, 0xB9E3, 0xB8C4, + 0xB9E4, 0xB8C5, 0xB9E5, 0xB8C6, 0xB9E6, 0x90AF, 0xB9E7, 0x90B0, 0xB9E8, 0xB8C7, 0xB9E9, 0x90B1, 0xB9EA, 0x90B2, 0xB9EB, 0x90B3, + 0xB9EC, 0xB8C8, 0xB9ED, 0x90B4, 0xB9EE, 0x90B5, 0xB9EF, 0x90B6, 0xB9F0, 0x90B7, 0xB9F1, 0x90B8, 0xB9F2, 0x90B9, 0xB9F3, 0x90BA, + 0xB9F4, 0xB8C9, 0xB9F5, 0xB8CA, 0xB9F6, 0x90BB, 0xB9F7, 0xB8CB, 0xB9F8, 0xB8CC, 0xB9F9, 0xB8CD, 0xB9FA, 0xB8CE, 0xB9FB, 0x90BC, + 0xB9FC, 0x90BD, 0xB9FD, 0x90BE, 0xB9FE, 0x90BF, 0xB9FF, 0x90C0, 0xBA00, 0xB8CF, 0xBA01, 0xB8D0, 0xBA02, 0x90C1, 0xBA03, 0x90C2, + 0xBA04, 0x90C3, 0xBA05, 0x90C4, 0xBA06, 0x90C5, 0xBA07, 0x90C6, 0xBA08, 0xB8D1, 0xBA09, 0x90C7, 0xBA0A, 0x90C8, 0xBA0B, 0x90C9, + 0xBA0C, 0x90CA, 0xBA0D, 0x90CB, 0xBA0E, 0x90CC, 0xBA0F, 0x90CD, 0xBA10, 0x90CE, 0xBA11, 0x90CF, 0xBA12, 0x90D0, 0xBA13, 0x90D1, + 0xBA14, 0x90D2, 0xBA15, 0xB8D2, 0xBA16, 0x90D3, 0xBA17, 0x90D4, 0xBA18, 0x90D5, 0xBA19, 0x90D6, 0xBA1A, 0x90D7, 0xBA1B, 0x90D8, + 0xBA1C, 0x90D9, 0xBA1D, 0x90DA, 0xBA1E, 0x90DB, 0xBA1F, 0x90DC, 0xBA20, 0x90DD, 0xBA21, 0x90DE, 0xBA22, 0x90DF, 0xBA23, 0x90E0, + 0xBA24, 0x90E1, 0xBA25, 0x90E2, 0xBA26, 0x90E3, 0xBA27, 0x90E4, 0xBA28, 0x90E5, 0xBA29, 0x90E6, 0xBA2A, 0x90E7, 0xBA2B, 0x90E8, + 0xBA2C, 0x90E9, 0xBA2D, 0x90EA, 0xBA2E, 0x90EB, 0xBA2F, 0x90EC, 0xBA30, 0x90ED, 0xBA31, 0x90EE, 0xBA32, 0x90EF, 0xBA33, 0x90F0, + 0xBA34, 0x90F1, 0xBA35, 0x90F2, 0xBA36, 0x90F3, 0xBA37, 0x90F4, 0xBA38, 0xB8D3, 0xBA39, 0xB8D4, 0xBA3A, 0x90F5, 0xBA3B, 0x90F6, + 0xBA3C, 0xB8D5, 0xBA3D, 0x90F7, 0xBA3E, 0x90F8, 0xBA3F, 0x90F9, 0xBA40, 0xB8D6, 0xBA41, 0x90FA, 0xBA42, 0xB8D7, 0xBA43, 0x90FB, + 0xBA44, 0x90FC, 0xBA45, 0x90FD, 0xBA46, 0x90FE, 0xBA47, 0x9141, 0xBA48, 0xB8D8, 0xBA49, 0xB8D9, 0xBA4A, 0x9142, 0xBA4B, 0xB8DA, + 0xBA4C, 0x9143, 0xBA4D, 0xB8DB, 0xBA4E, 0xB8DC, 0xBA4F, 0x9144, 0xBA50, 0x9145, 0xBA51, 0x9146, 0xBA52, 0x9147, 0xBA53, 0xB8DD, + 0xBA54, 0xB8DE, 0xBA55, 0xB8DF, 0xBA56, 0x9148, 0xBA57, 0x9149, 0xBA58, 0xB8E0, 0xBA59, 0x914A, 0xBA5A, 0x914B, 0xBA5B, 0x914C, + 0xBA5C, 0xB8E1, 0xBA5D, 0x914D, 0xBA5E, 0x914E, 0xBA5F, 0x914F, 0xBA60, 0x9150, 0xBA61, 0x9151, 0xBA62, 0x9152, 0xBA63, 0x9153, + 0xBA64, 0xB8E2, 0xBA65, 0xB8E3, 0xBA66, 0x9154, 0xBA67, 0xB8E4, 0xBA68, 0xB8E5, 0xBA69, 0xB8E6, 0xBA6A, 0x9155, 0xBA6B, 0x9156, + 0xBA6C, 0x9157, 0xBA6D, 0x9158, 0xBA6E, 0x9159, 0xBA6F, 0x915A, 0xBA70, 0xB8E7, 0xBA71, 0xB8E8, 0xBA72, 0x9161, 0xBA73, 0x9162, + 0xBA74, 0xB8E9, 0xBA75, 0x9163, 0xBA76, 0x9164, 0xBA77, 0x9165, 0xBA78, 0xB8EA, 0xBA79, 0x9166, 0xBA7A, 0x9167, 0xBA7B, 0x9168, + 0xBA7C, 0x9169, 0xBA7D, 0x916A, 0xBA7E, 0x916B, 0xBA7F, 0x916C, 0xBA80, 0x916D, 0xBA81, 0x916E, 0xBA82, 0x916F, 0xBA83, 0xB8EB, + 0xBA84, 0xB8EC, 0xBA85, 0xB8ED, 0xBA86, 0x9170, 0xBA87, 0xB8EE, 0xBA88, 0x9171, 0xBA89, 0x9172, 0xBA8A, 0x9173, 0xBA8B, 0x9174, + 0xBA8C, 0xB8EF, 0xBA8D, 0x9175, 0xBA8E, 0x9176, 0xBA8F, 0x9177, 0xBA90, 0x9178, 0xBA91, 0x9179, 0xBA92, 0x917A, 0xBA93, 0x9181, + 0xBA94, 0x9182, 0xBA95, 0x9183, 0xBA96, 0x9184, 0xBA97, 0x9185, 0xBA98, 0x9186, 0xBA99, 0x9187, 0xBA9A, 0x9188, 0xBA9B, 0x9189, + 0xBA9C, 0x918A, 0xBA9D, 0x918B, 0xBA9E, 0x918C, 0xBA9F, 0x918D, 0xBAA0, 0x918E, 0xBAA1, 0x918F, 0xBAA2, 0x9190, 0xBAA3, 0x9191, + 0xBAA4, 0x9192, 0xBAA5, 0x9193, 0xBAA6, 0x9194, 0xBAA7, 0x9195, 0xBAA8, 0xB8F0, 0xBAA9, 0xB8F1, 0xBAAA, 0x9196, 0xBAAB, 0xB8F2, + 0xBAAC, 0xB8F3, 0xBAAD, 0x9197, 0xBAAE, 0x9198, 0xBAAF, 0x9199, 0xBAB0, 0xB8F4, 0xBAB1, 0x919A, 0xBAB2, 0xB8F5, 0xBAB3, 0x919B, + 0xBAB4, 0x919C, 0xBAB5, 0x919D, 0xBAB6, 0x919E, 0xBAB7, 0x919F, 0xBAB8, 0xB8F6, 0xBAB9, 0xB8F7, 0xBABA, 0x91A0, 0xBABB, 0xB8F8, + 0xBABC, 0x91A1, 0xBABD, 0xB8F9, 0xBABE, 0x91A2, 0xBABF, 0x91A3, 0xBAC0, 0x91A4, 0xBAC1, 0x91A5, 0xBAC2, 0x91A6, 0xBAC3, 0x91A7, + 0xBAC4, 0xB8FA, 0xBAC5, 0x91A8, 0xBAC6, 0x91A9, 0xBAC7, 0x91AA, 0xBAC8, 0xB8FB, 0xBAC9, 0x91AB, 0xBACA, 0x91AC, 0xBACB, 0x91AD, + 0xBACC, 0x91AE, 0xBACD, 0x91AF, 0xBACE, 0x91B0, 0xBACF, 0x91B1, 0xBAD0, 0x91B2, 0xBAD1, 0x91B3, 0xBAD2, 0x91B4, 0xBAD3, 0x91B5, + 0xBAD4, 0x91B6, 0xBAD5, 0x91B7, 0xBAD6, 0x91B8, 0xBAD7, 0x91B9, 0xBAD8, 0xB8FC, 0xBAD9, 0xB8FD, 0xBADA, 0x91BA, 0xBADB, 0x91BB, + 0xBADC, 0x91BC, 0xBADD, 0x91BD, 0xBADE, 0x91BE, 0xBADF, 0x91BF, 0xBAE0, 0x91C0, 0xBAE1, 0x91C1, 0xBAE2, 0x91C2, 0xBAE3, 0x91C3, + 0xBAE4, 0x91C4, 0xBAE5, 0x91C5, 0xBAE6, 0x91C6, 0xBAE7, 0x91C7, 0xBAE8, 0x91C8, 0xBAE9, 0x91C9, 0xBAEA, 0x91CA, 0xBAEB, 0x91CB, + 0xBAEC, 0x91CC, 0xBAED, 0x91CD, 0xBAEE, 0x91CE, 0xBAEF, 0x91CF, 0xBAF0, 0x91D0, 0xBAF1, 0x91D1, 0xBAF2, 0x91D2, 0xBAF3, 0x91D3, + 0xBAF4, 0x91D4, 0xBAF5, 0x91D5, 0xBAF6, 0x91D6, 0xBAF7, 0x91D7, 0xBAF8, 0x91D8, 0xBAF9, 0x91D9, 0xBAFA, 0x91DA, 0xBAFB, 0x91DB, + 0xBAFC, 0xB8FE, 0xBAFD, 0x91DC, 0xBAFE, 0x91DD, 0xBAFF, 0x91DE, 0xBB00, 0xB9A1, 0xBB01, 0x91DF, 0xBB02, 0x91E0, 0xBB03, 0x91E1, + 0xBB04, 0xB9A2, 0xBB05, 0x91E2, 0xBB06, 0x91E3, 0xBB07, 0x91E4, 0xBB08, 0x91E5, 0xBB09, 0x91E6, 0xBB0A, 0x91E7, 0xBB0B, 0x91E8, + 0xBB0C, 0x91E9, 0xBB0D, 0xB9A3, 0xBB0E, 0x91EA, 0xBB0F, 0xB9A4, 0xBB10, 0x91EB, 0xBB11, 0xB9A5, 0xBB12, 0x91EC, 0xBB13, 0x91ED, + 0xBB14, 0x91EE, 0xBB15, 0x91EF, 0xBB16, 0x91F0, 0xBB17, 0x91F1, 0xBB18, 0xB9A6, 0xBB19, 0x91F2, 0xBB1A, 0x91F3, 0xBB1B, 0x91F4, + 0xBB1C, 0xB9A7, 0xBB1D, 0x91F5, 0xBB1E, 0x91F6, 0xBB1F, 0x91F7, 0xBB20, 0xB9A8, 0xBB21, 0x91F8, 0xBB22, 0x91F9, 0xBB23, 0x91FA, + 0xBB24, 0x91FB, 0xBB25, 0x91FC, 0xBB26, 0x91FD, 0xBB27, 0x91FE, 0xBB28, 0x9241, 0xBB29, 0xB9A9, 0xBB2A, 0x9242, 0xBB2B, 0xB9AA, + 0xBB2C, 0x9243, 0xBB2D, 0x9244, 0xBB2E, 0x9245, 0xBB2F, 0x9246, 0xBB30, 0x9247, 0xBB31, 0x9248, 0xBB32, 0x9249, 0xBB33, 0x924A, + 0xBB34, 0xB9AB, 0xBB35, 0xB9AC, 0xBB36, 0xB9AD, 0xBB37, 0x924B, 0xBB38, 0xB9AE, 0xBB39, 0x924C, 0xBB3A, 0x924D, 0xBB3B, 0xB9AF, + 0xBB3C, 0xB9B0, 0xBB3D, 0xB9B1, 0xBB3E, 0xB9B2, 0xBB3F, 0x924E, 0xBB40, 0x924F, 0xBB41, 0x9250, 0xBB42, 0x9251, 0xBB43, 0x9252, + 0xBB44, 0xB9B3, 0xBB45, 0xB9B4, 0xBB46, 0x9253, 0xBB47, 0xB9B5, 0xBB48, 0x9254, 0xBB49, 0xB9B6, 0xBB4A, 0x9255, 0xBB4B, 0x9256, + 0xBB4C, 0x9257, 0xBB4D, 0xB9B7, 0xBB4E, 0x9258, 0xBB4F, 0xB9B8, 0xBB50, 0xB9B9, 0xBB51, 0x9259, 0xBB52, 0x925A, 0xBB53, 0x9261, + 0xBB54, 0xB9BA, 0xBB55, 0x9262, 0xBB56, 0x9263, 0xBB57, 0x9264, 0xBB58, 0xB9BB, 0xBB59, 0x9265, 0xBB5A, 0x9266, 0xBB5B, 0x9267, + 0xBB5C, 0x9268, 0xBB5D, 0x9269, 0xBB5E, 0x926A, 0xBB5F, 0x926B, 0xBB60, 0x926C, 0xBB61, 0xB9BC, 0xBB62, 0x926D, 0xBB63, 0xB9BD, + 0xBB64, 0x926E, 0xBB65, 0x926F, 0xBB66, 0x9270, 0xBB67, 0x9271, 0xBB68, 0x9272, 0xBB69, 0x9273, 0xBB6A, 0x9274, 0xBB6B, 0x9275, + 0xBB6C, 0xB9BE, 0xBB6D, 0x9276, 0xBB6E, 0x9277, 0xBB6F, 0x9278, 0xBB70, 0x9279, 0xBB71, 0x927A, 0xBB72, 0x9281, 0xBB73, 0x9282, + 0xBB74, 0x9283, 0xBB75, 0x9284, 0xBB76, 0x9285, 0xBB77, 0x9286, 0xBB78, 0x9287, 0xBB79, 0x9288, 0xBB7A, 0x9289, 0xBB7B, 0x928A, + 0xBB7C, 0x928B, 0xBB7D, 0x928C, 0xBB7E, 0x928D, 0xBB7F, 0x928E, 0xBB80, 0x928F, 0xBB81, 0x9290, 0xBB82, 0x9291, 0xBB83, 0x9292, + 0xBB84, 0x9293, 0xBB85, 0x9294, 0xBB86, 0x9295, 0xBB87, 0x9296, 0xBB88, 0xB9BF, 0xBB89, 0x9297, 0xBB8A, 0x9298, 0xBB8B, 0x9299, + 0xBB8C, 0xB9C0, 0xBB8D, 0x929A, 0xBB8E, 0x929B, 0xBB8F, 0x929C, 0xBB90, 0xB9C1, 0xBB91, 0x929D, 0xBB92, 0x929E, 0xBB93, 0x929F, + 0xBB94, 0x92A0, 0xBB95, 0x92A1, 0xBB96, 0x92A2, 0xBB97, 0x92A3, 0xBB98, 0x92A4, 0xBB99, 0x92A5, 0xBB9A, 0x92A6, 0xBB9B, 0x92A7, + 0xBB9C, 0x92A8, 0xBB9D, 0x92A9, 0xBB9E, 0x92AA, 0xBB9F, 0x92AB, 0xBBA0, 0x92AC, 0xBBA1, 0x92AD, 0xBBA2, 0x92AE, 0xBBA3, 0x92AF, + 0xBBA4, 0xB9C2, 0xBBA5, 0x92B0, 0xBBA6, 0x92B1, 0xBBA7, 0x92B2, 0xBBA8, 0xB9C3, 0xBBA9, 0x92B3, 0xBBAA, 0x92B4, 0xBBAB, 0x92B5, + 0xBBAC, 0xB9C4, 0xBBAD, 0x92B6, 0xBBAE, 0x92B7, 0xBBAF, 0x92B8, 0xBBB0, 0x92B9, 0xBBB1, 0x92BA, 0xBBB2, 0x92BB, 0xBBB3, 0x92BC, + 0xBBB4, 0xB9C5, 0xBBB5, 0x92BD, 0xBBB6, 0x92BE, 0xBBB7, 0xB9C6, 0xBBB8, 0x92BF, 0xBBB9, 0x92C0, 0xBBBA, 0x92C1, 0xBBBB, 0x92C2, + 0xBBBC, 0x92C3, 0xBBBD, 0x92C4, 0xBBBE, 0x92C5, 0xBBBF, 0x92C6, 0xBBC0, 0xB9C7, 0xBBC1, 0x92C7, 0xBBC2, 0x92C8, 0xBBC3, 0x92C9, + 0xBBC4, 0xB9C8, 0xBBC5, 0x92CA, 0xBBC6, 0x92CB, 0xBBC7, 0x92CC, 0xBBC8, 0xB9C9, 0xBBC9, 0x92CD, 0xBBCA, 0x92CE, 0xBBCB, 0x92CF, + 0xBBCC, 0x92D0, 0xBBCD, 0x92D1, 0xBBCE, 0x92D2, 0xBBCF, 0x92D3, 0xBBD0, 0xB9CA, 0xBBD1, 0x92D4, 0xBBD2, 0x92D5, 0xBBD3, 0xB9CB, + 0xBBD4, 0x92D6, 0xBBD5, 0x92D7, 0xBBD6, 0x92D8, 0xBBD7, 0x92D9, 0xBBD8, 0x92DA, 0xBBD9, 0x92DB, 0xBBDA, 0x92DC, 0xBBDB, 0x92DD, + 0xBBDC, 0x92DE, 0xBBDD, 0x92DF, 0xBBDE, 0x92E0, 0xBBDF, 0x92E1, 0xBBE0, 0x92E2, 0xBBE1, 0x92E3, 0xBBE2, 0x92E4, 0xBBE3, 0x92E5, + 0xBBE4, 0x92E6, 0xBBE5, 0x92E7, 0xBBE6, 0x92E8, 0xBBE7, 0x92E9, 0xBBE8, 0x92EA, 0xBBE9, 0x92EB, 0xBBEA, 0x92EC, 0xBBEB, 0x92ED, + 0xBBEC, 0x92EE, 0xBBED, 0x92EF, 0xBBEE, 0x92F0, 0xBBEF, 0x92F1, 0xBBF0, 0x92F2, 0xBBF1, 0x92F3, 0xBBF2, 0x92F4, 0xBBF3, 0x92F5, + 0xBBF4, 0x92F6, 0xBBF5, 0x92F7, 0xBBF6, 0x92F8, 0xBBF7, 0x92F9, 0xBBF8, 0xB9CC, 0xBBF9, 0xB9CD, 0xBBFA, 0x92FA, 0xBBFB, 0x92FB, + 0xBBFC, 0xB9CE, 0xBBFD, 0x92FC, 0xBBFE, 0x92FD, 0xBBFF, 0xB9CF, 0xBC00, 0xB9D0, 0xBC01, 0x92FE, 0xBC02, 0xB9D1, 0xBC03, 0x9341, + 0xBC04, 0x9342, 0xBC05, 0x9343, 0xBC06, 0x9344, 0xBC07, 0x9345, 0xBC08, 0xB9D2, 0xBC09, 0xB9D3, 0xBC0A, 0x9346, 0xBC0B, 0xB9D4, + 0xBC0C, 0xB9D5, 0xBC0D, 0xB9D6, 0xBC0E, 0x9347, 0xBC0F, 0xB9D7, 0xBC10, 0x9348, 0xBC11, 0xB9D8, 0xBC12, 0x9349, 0xBC13, 0x934A, + 0xBC14, 0xB9D9, 0xBC15, 0xB9DA, 0xBC16, 0xB9DB, 0xBC17, 0xB9DC, 0xBC18, 0xB9DD, 0xBC19, 0x934B, 0xBC1A, 0x934C, 0xBC1B, 0xB9DE, + 0xBC1C, 0xB9DF, 0xBC1D, 0xB9E0, 0xBC1E, 0xB9E1, 0xBC1F, 0xB9E2, 0xBC20, 0x934D, 0xBC21, 0x934E, 0xBC22, 0x934F, 0xBC23, 0x9350, + 0xBC24, 0xB9E3, 0xBC25, 0xB9E4, 0xBC26, 0x9351, 0xBC27, 0xB9E5, 0xBC28, 0x9352, 0xBC29, 0xB9E6, 0xBC2A, 0x9353, 0xBC2B, 0x9354, + 0xBC2C, 0x9355, 0xBC2D, 0xB9E7, 0xBC2E, 0x9356, 0xBC2F, 0x9357, 0xBC30, 0xB9E8, 0xBC31, 0xB9E9, 0xBC32, 0x9358, 0xBC33, 0x9359, + 0xBC34, 0xB9EA, 0xBC35, 0x935A, 0xBC36, 0x9361, 0xBC37, 0x9362, 0xBC38, 0xB9EB, 0xBC39, 0x9363, 0xBC3A, 0x9364, 0xBC3B, 0x9365, + 0xBC3C, 0x9366, 0xBC3D, 0x9367, 0xBC3E, 0x9368, 0xBC3F, 0x9369, 0xBC40, 0xB9EC, 0xBC41, 0xB9ED, 0xBC42, 0x936A, 0xBC43, 0xB9EE, + 0xBC44, 0xB9EF, 0xBC45, 0xB9F0, 0xBC46, 0x936B, 0xBC47, 0x936C, 0xBC48, 0x936D, 0xBC49, 0xB9F1, 0xBC4A, 0x936E, 0xBC4B, 0x936F, + 0xBC4C, 0xB9F2, 0xBC4D, 0xB9F3, 0xBC4E, 0x9370, 0xBC4F, 0x9371, 0xBC50, 0xB9F4, 0xBC51, 0x9372, 0xBC52, 0x9373, 0xBC53, 0x9374, + 0xBC54, 0x9375, 0xBC55, 0x9376, 0xBC56, 0x9377, 0xBC57, 0x9378, 0xBC58, 0x9379, 0xBC59, 0x937A, 0xBC5A, 0x9381, 0xBC5B, 0x9382, + 0xBC5C, 0x9383, 0xBC5D, 0xB9F5, 0xBC5E, 0x9384, 0xBC5F, 0x9385, 0xBC60, 0x9386, 0xBC61, 0x9387, 0xBC62, 0x9388, 0xBC63, 0x9389, + 0xBC64, 0x938A, 0xBC65, 0x938B, 0xBC66, 0x938C, 0xBC67, 0x938D, 0xBC68, 0x938E, 0xBC69, 0x938F, 0xBC6A, 0x9390, 0xBC6B, 0x9391, + 0xBC6C, 0x9392, 0xBC6D, 0x9393, 0xBC6E, 0x9394, 0xBC6F, 0x9395, 0xBC70, 0x9396, 0xBC71, 0x9397, 0xBC72, 0x9398, 0xBC73, 0x9399, + 0xBC74, 0x939A, 0xBC75, 0x939B, 0xBC76, 0x939C, 0xBC77, 0x939D, 0xBC78, 0x939E, 0xBC79, 0x939F, 0xBC7A, 0x93A0, 0xBC7B, 0x93A1, + 0xBC7C, 0x93A2, 0xBC7D, 0x93A3, 0xBC7E, 0x93A4, 0xBC7F, 0x93A5, 0xBC80, 0x93A6, 0xBC81, 0x93A7, 0xBC82, 0x93A8, 0xBC83, 0x93A9, + 0xBC84, 0xB9F6, 0xBC85, 0xB9F7, 0xBC86, 0x93AA, 0xBC87, 0x93AB, 0xBC88, 0xB9F8, 0xBC89, 0x93AC, 0xBC8A, 0x93AD, 0xBC8B, 0xB9F9, + 0xBC8C, 0xB9FA, 0xBC8D, 0x93AE, 0xBC8E, 0xB9FB, 0xBC8F, 0x93AF, 0xBC90, 0x93B0, 0xBC91, 0x93B1, 0xBC92, 0x93B2, 0xBC93, 0x93B3, + 0xBC94, 0xB9FC, 0xBC95, 0xB9FD, 0xBC96, 0x93B4, 0xBC97, 0xB9FE, 0xBC98, 0x93B5, 0xBC99, 0xBAA1, 0xBC9A, 0xBAA2, 0xBC9B, 0x93B6, + 0xBC9C, 0x93B7, 0xBC9D, 0x93B8, 0xBC9E, 0x93B9, 0xBC9F, 0x93BA, 0xBCA0, 0xBAA3, 0xBCA1, 0xBAA4, 0xBCA2, 0x93BB, 0xBCA3, 0x93BC, + 0xBCA4, 0xBAA5, 0xBCA5, 0x93BD, 0xBCA6, 0x93BE, 0xBCA7, 0xBAA6, 0xBCA8, 0xBAA7, 0xBCA9, 0x93BF, 0xBCAA, 0x93C0, 0xBCAB, 0x93C1, + 0xBCAC, 0x93C2, 0xBCAD, 0x93C3, 0xBCAE, 0x93C4, 0xBCAF, 0x93C5, 0xBCB0, 0xBAA8, 0xBCB1, 0xBAA9, 0xBCB2, 0x93C6, 0xBCB3, 0xBAAA, + 0xBCB4, 0xBAAB, 0xBCB5, 0xBAAC, 0xBCB6, 0x93C7, 0xBCB7, 0x93C8, 0xBCB8, 0x93C9, 0xBCB9, 0x93CA, 0xBCBA, 0x93CB, 0xBCBB, 0x93CC, + 0xBCBC, 0xBAAD, 0xBCBD, 0xBAAE, 0xBCBE, 0x93CD, 0xBCBF, 0x93CE, 0xBCC0, 0xBAAF, 0xBCC1, 0x93CF, 0xBCC2, 0x93D0, 0xBCC3, 0x93D1, + 0xBCC4, 0xBAB0, 0xBCC5, 0x93D2, 0xBCC6, 0x93D3, 0xBCC7, 0x93D4, 0xBCC8, 0x93D5, 0xBCC9, 0x93D6, 0xBCCA, 0x93D7, 0xBCCB, 0x93D8, + 0xBCCC, 0x93D9, 0xBCCD, 0xBAB1, 0xBCCE, 0x93DA, 0xBCCF, 0xBAB2, 0xBCD0, 0xBAB3, 0xBCD1, 0xBAB4, 0xBCD2, 0x93DB, 0xBCD3, 0x93DC, + 0xBCD4, 0x93DD, 0xBCD5, 0xBAB5, 0xBCD6, 0x93DE, 0xBCD7, 0x93DF, 0xBCD8, 0xBAB6, 0xBCD9, 0x93E0, 0xBCDA, 0x93E1, 0xBCDB, 0x93E2, + 0xBCDC, 0xBAB7, 0xBCDD, 0x93E3, 0xBCDE, 0x93E4, 0xBCDF, 0x93E5, 0xBCE0, 0x93E6, 0xBCE1, 0x93E7, 0xBCE2, 0x93E8, 0xBCE3, 0x93E9, + 0xBCE4, 0x93EA, 0xBCE5, 0x93EB, 0xBCE6, 0x93EC, 0xBCE7, 0x93ED, 0xBCE8, 0x93EE, 0xBCE9, 0x93EF, 0xBCEA, 0x93F0, 0xBCEB, 0x93F1, + 0xBCEC, 0x93F2, 0xBCED, 0x93F3, 0xBCEE, 0x93F4, 0xBCEF, 0x93F5, 0xBCF0, 0x93F6, 0xBCF1, 0x93F7, 0xBCF2, 0x93F8, 0xBCF3, 0x93F9, + 0xBCF4, 0xBAB8, 0xBCF5, 0xBAB9, 0xBCF6, 0xBABA, 0xBCF7, 0x93FA, 0xBCF8, 0xBABB, 0xBCF9, 0x93FB, 0xBCFA, 0x93FC, 0xBCFB, 0x93FD, + 0xBCFC, 0xBABC, 0xBCFD, 0x93FE, 0xBCFE, 0x9441, 0xBCFF, 0x9442, 0xBD00, 0x9443, 0xBD01, 0x9444, 0xBD02, 0x9445, 0xBD03, 0x9446, + 0xBD04, 0xBABD, 0xBD05, 0xBABE, 0xBD06, 0x9447, 0xBD07, 0xBABF, 0xBD08, 0x9448, 0xBD09, 0xBAC0, 0xBD0A, 0x9449, 0xBD0B, 0x944A, + 0xBD0C, 0x944B, 0xBD0D, 0x944C, 0xBD0E, 0x944D, 0xBD0F, 0x944E, 0xBD10, 0xBAC1, 0xBD11, 0x944F, 0xBD12, 0x9450, 0xBD13, 0x9451, + 0xBD14, 0xBAC2, 0xBD15, 0x9452, 0xBD16, 0x9453, 0xBD17, 0x9454, 0xBD18, 0x9455, 0xBD19, 0x9456, 0xBD1A, 0x9457, 0xBD1B, 0x9458, + 0xBD1C, 0x9459, 0xBD1D, 0x945A, 0xBD1E, 0x9461, 0xBD1F, 0x9462, 0xBD20, 0x9463, 0xBD21, 0x9464, 0xBD22, 0x9465, 0xBD23, 0x9466, + 0xBD24, 0xBAC3, 0xBD25, 0x9467, 0xBD26, 0x9468, 0xBD27, 0x9469, 0xBD28, 0x946A, 0xBD29, 0x946B, 0xBD2A, 0x946C, 0xBD2B, 0x946D, + 0xBD2C, 0xBAC4, 0xBD2D, 0x946E, 0xBD2E, 0x946F, 0xBD2F, 0x9470, 0xBD30, 0x9471, 0xBD31, 0x9472, 0xBD32, 0x9473, 0xBD33, 0x9474, + 0xBD34, 0x9475, 0xBD35, 0x9476, 0xBD36, 0x9477, 0xBD37, 0x9478, 0xBD38, 0x9479, 0xBD39, 0x947A, 0xBD3A, 0x9481, 0xBD3B, 0x9482, + 0xBD3C, 0x9483, 0xBD3D, 0x9484, 0xBD3E, 0x9485, 0xBD3F, 0x9486, 0xBD40, 0xBAC5, 0xBD41, 0x9487, 0xBD42, 0x9488, 0xBD43, 0x9489, + 0xBD44, 0x948A, 0xBD45, 0x948B, 0xBD46, 0x948C, 0xBD47, 0x948D, 0xBD48, 0xBAC6, 0xBD49, 0xBAC7, 0xBD4A, 0x948E, 0xBD4B, 0x948F, + 0xBD4C, 0xBAC8, 0xBD4D, 0x9490, 0xBD4E, 0x9491, 0xBD4F, 0x9492, 0xBD50, 0xBAC9, 0xBD51, 0x9493, 0xBD52, 0x9494, 0xBD53, 0x9495, + 0xBD54, 0x9496, 0xBD55, 0x9497, 0xBD56, 0x9498, 0xBD57, 0x9499, 0xBD58, 0xBACA, 0xBD59, 0xBACB, 0xBD5A, 0x949A, 0xBD5B, 0x949B, + 0xBD5C, 0x949C, 0xBD5D, 0x949D, 0xBD5E, 0x949E, 0xBD5F, 0x949F, 0xBD60, 0x94A0, 0xBD61, 0x94A1, 0xBD62, 0x94A2, 0xBD63, 0x94A3, + 0xBD64, 0xBACC, 0xBD65, 0x94A4, 0xBD66, 0x94A5, 0xBD67, 0x94A6, 0xBD68, 0xBACD, 0xBD69, 0x94A7, 0xBD6A, 0x94A8, 0xBD6B, 0x94A9, + 0xBD6C, 0x94AA, 0xBD6D, 0x94AB, 0xBD6E, 0x94AC, 0xBD6F, 0x94AD, 0xBD70, 0x94AE, 0xBD71, 0x94AF, 0xBD72, 0x94B0, 0xBD73, 0x94B1, + 0xBD74, 0x94B2, 0xBD75, 0x94B3, 0xBD76, 0x94B4, 0xBD77, 0x94B5, 0xBD78, 0x94B6, 0xBD79, 0x94B7, 0xBD7A, 0x94B8, 0xBD7B, 0x94B9, + 0xBD7C, 0x94BA, 0xBD7D, 0x94BB, 0xBD7E, 0x94BC, 0xBD7F, 0x94BD, 0xBD80, 0xBACE, 0xBD81, 0xBACF, 0xBD82, 0x94BE, 0xBD83, 0x94BF, + 0xBD84, 0xBAD0, 0xBD85, 0x94C0, 0xBD86, 0x94C1, 0xBD87, 0xBAD1, 0xBD88, 0xBAD2, 0xBD89, 0xBAD3, 0xBD8A, 0xBAD4, 0xBD8B, 0x94C2, + 0xBD8C, 0x94C3, 0xBD8D, 0x94C4, 0xBD8E, 0x94C5, 0xBD8F, 0x94C6, 0xBD90, 0xBAD5, 0xBD91, 0xBAD6, 0xBD92, 0x94C7, 0xBD93, 0xBAD7, + 0xBD94, 0x94C8, 0xBD95, 0xBAD8, 0xBD96, 0x94C9, 0xBD97, 0x94CA, 0xBD98, 0x94CB, 0xBD99, 0xBAD9, 0xBD9A, 0xBADA, 0xBD9B, 0x94CC, + 0xBD9C, 0xBADB, 0xBD9D, 0x94CD, 0xBD9E, 0x94CE, 0xBD9F, 0x94CF, 0xBDA0, 0x94D0, 0xBDA1, 0x94D1, 0xBDA2, 0x94D2, 0xBDA3, 0x94D3, + 0xBDA4, 0xBADC, 0xBDA5, 0x94D4, 0xBDA6, 0x94D5, 0xBDA7, 0x94D6, 0xBDA8, 0x94D7, 0xBDA9, 0x94D8, 0xBDAA, 0x94D9, 0xBDAB, 0x94DA, + 0xBDAC, 0x94DB, 0xBDAD, 0x94DC, 0xBDAE, 0x94DD, 0xBDAF, 0x94DE, 0xBDB0, 0xBADD, 0xBDB1, 0x94DF, 0xBDB2, 0x94E0, 0xBDB3, 0x94E1, + 0xBDB4, 0x94E2, 0xBDB5, 0x94E3, 0xBDB6, 0x94E4, 0xBDB7, 0x94E5, 0xBDB8, 0xBADE, 0xBDB9, 0x94E6, 0xBDBA, 0x94E7, 0xBDBB, 0x94E8, + 0xBDBC, 0x94E9, 0xBDBD, 0x94EA, 0xBDBE, 0x94EB, 0xBDBF, 0x94EC, 0xBDC0, 0x94ED, 0xBDC1, 0x94EE, 0xBDC2, 0x94EF, 0xBDC3, 0x94F0, + 0xBDC4, 0x94F1, 0xBDC5, 0x94F2, 0xBDC6, 0x94F3, 0xBDC7, 0x94F4, 0xBDC8, 0x94F5, 0xBDC9, 0x94F6, 0xBDCA, 0x94F7, 0xBDCB, 0x94F8, + 0xBDCC, 0x94F9, 0xBDCD, 0x94FA, 0xBDCE, 0x94FB, 0xBDCF, 0x94FC, 0xBDD0, 0x94FD, 0xBDD1, 0x94FE, 0xBDD2, 0x9541, 0xBDD3, 0x9542, + 0xBDD4, 0xBADF, 0xBDD5, 0xBAE0, 0xBDD6, 0x9543, 0xBDD7, 0x9544, 0xBDD8, 0xBAE1, 0xBDD9, 0x9545, 0xBDDA, 0x9546, 0xBDDB, 0x9547, + 0xBDDC, 0xBAE2, 0xBDDD, 0x9548, 0xBDDE, 0x9549, 0xBDDF, 0x954A, 0xBDE0, 0x954B, 0xBDE1, 0x954C, 0xBDE2, 0x954D, 0xBDE3, 0x954E, + 0xBDE4, 0x954F, 0xBDE5, 0x9550, 0xBDE6, 0x9551, 0xBDE7, 0x9552, 0xBDE8, 0x9553, 0xBDE9, 0xBAE3, 0xBDEA, 0x9554, 0xBDEB, 0x9555, + 0xBDEC, 0x9556, 0xBDED, 0x9557, 0xBDEE, 0x9558, 0xBDEF, 0x9559, 0xBDF0, 0xBAE4, 0xBDF1, 0x955A, 0xBDF2, 0x9561, 0xBDF3, 0x9562, + 0xBDF4, 0xBAE5, 0xBDF5, 0x9563, 0xBDF6, 0x9564, 0xBDF7, 0x9565, 0xBDF8, 0xBAE6, 0xBDF9, 0x9566, 0xBDFA, 0x9567, 0xBDFB, 0x9568, + 0xBDFC, 0x9569, 0xBDFD, 0x956A, 0xBDFE, 0x956B, 0xBDFF, 0x956C, 0xBE00, 0xBAE7, 0xBE01, 0x956D, 0xBE02, 0x956E, 0xBE03, 0xBAE8, + 0xBE04, 0x956F, 0xBE05, 0xBAE9, 0xBE06, 0x9570, 0xBE07, 0x9571, 0xBE08, 0x9572, 0xBE09, 0x9573, 0xBE0A, 0x9574, 0xBE0B, 0x9575, + 0xBE0C, 0xBAEA, 0xBE0D, 0xBAEB, 0xBE0E, 0x9576, 0xBE0F, 0x9577, 0xBE10, 0xBAEC, 0xBE11, 0x9578, 0xBE12, 0x9579, 0xBE13, 0x957A, + 0xBE14, 0xBAED, 0xBE15, 0x9581, 0xBE16, 0x9582, 0xBE17, 0x9583, 0xBE18, 0x9584, 0xBE19, 0x9585, 0xBE1A, 0x9586, 0xBE1B, 0x9587, + 0xBE1C, 0xBAEE, 0xBE1D, 0xBAEF, 0xBE1E, 0x9588, 0xBE1F, 0xBAF0, 0xBE20, 0x9589, 0xBE21, 0x958A, 0xBE22, 0x958B, 0xBE23, 0x958C, + 0xBE24, 0x958D, 0xBE25, 0x958E, 0xBE26, 0x958F, 0xBE27, 0x9590, 0xBE28, 0x9591, 0xBE29, 0x9592, 0xBE2A, 0x9593, 0xBE2B, 0x9594, + 0xBE2C, 0x9595, 0xBE2D, 0x9596, 0xBE2E, 0x9597, 0xBE2F, 0x9598, 0xBE30, 0x9599, 0xBE31, 0x959A, 0xBE32, 0x959B, 0xBE33, 0x959C, + 0xBE34, 0x959D, 0xBE35, 0x959E, 0xBE36, 0x959F, 0xBE37, 0x95A0, 0xBE38, 0x95A1, 0xBE39, 0x95A2, 0xBE3A, 0x95A3, 0xBE3B, 0x95A4, + 0xBE3C, 0x95A5, 0xBE3D, 0x95A6, 0xBE3E, 0x95A7, 0xBE3F, 0x95A8, 0xBE40, 0x95A9, 0xBE41, 0x95AA, 0xBE42, 0x95AB, 0xBE43, 0x95AC, + 0xBE44, 0xBAF1, 0xBE45, 0xBAF2, 0xBE46, 0x95AD, 0xBE47, 0x95AE, 0xBE48, 0xBAF3, 0xBE49, 0x95AF, 0xBE4A, 0x95B0, 0xBE4B, 0x95B1, + 0xBE4C, 0xBAF4, 0xBE4D, 0x95B2, 0xBE4E, 0xBAF5, 0xBE4F, 0x95B3, 0xBE50, 0x95B4, 0xBE51, 0x95B5, 0xBE52, 0x95B6, 0xBE53, 0x95B7, + 0xBE54, 0xBAF6, 0xBE55, 0xBAF7, 0xBE56, 0x95B8, 0xBE57, 0xBAF8, 0xBE58, 0x95B9, 0xBE59, 0xBAF9, 0xBE5A, 0xBAFA, 0xBE5B, 0xBAFB, + 0xBE5C, 0x95BA, 0xBE5D, 0x95BB, 0xBE5E, 0x95BC, 0xBE5F, 0x95BD, 0xBE60, 0xBAFC, 0xBE61, 0xBAFD, 0xBE62, 0x95BE, 0xBE63, 0x95BF, + 0xBE64, 0xBAFE, 0xBE65, 0x95C0, 0xBE66, 0x95C1, 0xBE67, 0x95C2, 0xBE68, 0xBBA1, 0xBE69, 0x95C3, 0xBE6A, 0xBBA2, 0xBE6B, 0x95C4, + 0xBE6C, 0x95C5, 0xBE6D, 0x95C6, 0xBE6E, 0x95C7, 0xBE6F, 0x95C8, 0xBE70, 0xBBA3, 0xBE71, 0xBBA4, 0xBE72, 0x95C9, 0xBE73, 0xBBA5, + 0xBE74, 0xBBA6, 0xBE75, 0xBBA7, 0xBE76, 0x95CA, 0xBE77, 0x95CB, 0xBE78, 0x95CC, 0xBE79, 0x95CD, 0xBE7A, 0x95CE, 0xBE7B, 0xBBA8, + 0xBE7C, 0xBBA9, 0xBE7D, 0xBBAA, 0xBE7E, 0x95CF, 0xBE7F, 0x95D0, 0xBE80, 0xBBAB, 0xBE81, 0x95D1, 0xBE82, 0x95D2, 0xBE83, 0x95D3, + 0xBE84, 0xBBAC, 0xBE85, 0x95D4, 0xBE86, 0x95D5, 0xBE87, 0x95D6, 0xBE88, 0x95D7, 0xBE89, 0x95D8, 0xBE8A, 0x95D9, 0xBE8B, 0x95DA, + 0xBE8C, 0xBBAD, 0xBE8D, 0xBBAE, 0xBE8E, 0x95DB, 0xBE8F, 0xBBAF, 0xBE90, 0xBBB0, 0xBE91, 0xBBB1, 0xBE92, 0x95DC, 0xBE93, 0x95DD, + 0xBE94, 0x95DE, 0xBE95, 0x95DF, 0xBE96, 0x95E0, 0xBE97, 0x95E1, 0xBE98, 0xBBB2, 0xBE99, 0xBBB3, 0xBE9A, 0x95E2, 0xBE9B, 0x95E3, + 0xBE9C, 0x95E4, 0xBE9D, 0x95E5, 0xBE9E, 0x95E6, 0xBE9F, 0x95E7, 0xBEA0, 0x95E8, 0xBEA1, 0x95E9, 0xBEA2, 0x95EA, 0xBEA3, 0x95EB, + 0xBEA4, 0x95EC, 0xBEA5, 0x95ED, 0xBEA6, 0x95EE, 0xBEA7, 0x95EF, 0xBEA8, 0xBBB4, 0xBEA9, 0x95F0, 0xBEAA, 0x95F1, 0xBEAB, 0x95F2, + 0xBEAC, 0x95F3, 0xBEAD, 0x95F4, 0xBEAE, 0x95F5, 0xBEAF, 0x95F6, 0xBEB0, 0x95F7, 0xBEB1, 0x95F8, 0xBEB2, 0x95F9, 0xBEB3, 0x95FA, + 0xBEB4, 0x95FB, 0xBEB5, 0x95FC, 0xBEB6, 0x95FD, 0xBEB7, 0x95FE, 0xBEB8, 0x9641, 0xBEB9, 0x9642, 0xBEBA, 0x9643, 0xBEBB, 0x9644, + 0xBEBC, 0x9645, 0xBEBD, 0x9646, 0xBEBE, 0x9647, 0xBEBF, 0x9648, 0xBEC0, 0x9649, 0xBEC1, 0x964A, 0xBEC2, 0x964B, 0xBEC3, 0x964C, + 0xBEC4, 0x964D, 0xBEC5, 0x964E, 0xBEC6, 0x964F, 0xBEC7, 0x9650, 0xBEC8, 0x9651, 0xBEC9, 0x9652, 0xBECA, 0x9653, 0xBECB, 0x9654, + 0xBECC, 0x9655, 0xBECD, 0x9656, 0xBECE, 0x9657, 0xBECF, 0x9658, 0xBED0, 0xBBB5, 0xBED1, 0xBBB6, 0xBED2, 0x9659, 0xBED3, 0x965A, + 0xBED4, 0xBBB7, 0xBED5, 0x9661, 0xBED6, 0x9662, 0xBED7, 0xBBB8, 0xBED8, 0xBBB9, 0xBED9, 0x9663, 0xBEDA, 0x9664, 0xBEDB, 0x9665, + 0xBEDC, 0x9666, 0xBEDD, 0x9667, 0xBEDE, 0x9668, 0xBEDF, 0x9669, 0xBEE0, 0xBBBA, 0xBEE1, 0x966A, 0xBEE2, 0x966B, 0xBEE3, 0xBBBB, + 0xBEE4, 0xBBBC, 0xBEE5, 0xBBBD, 0xBEE6, 0x966C, 0xBEE7, 0x966D, 0xBEE8, 0x966E, 0xBEE9, 0x966F, 0xBEEA, 0x9670, 0xBEEB, 0x9671, + 0xBEEC, 0xBBBE, 0xBEED, 0x9672, 0xBEEE, 0x9673, 0xBEEF, 0x9674, 0xBEF0, 0x9675, 0xBEF1, 0x9676, 0xBEF2, 0x9677, 0xBEF3, 0x9678, + 0xBEF4, 0x9679, 0xBEF5, 0x967A, 0xBEF6, 0x9681, 0xBEF7, 0x9682, 0xBEF8, 0x9683, 0xBEF9, 0x9684, 0xBEFA, 0x9685, 0xBEFB, 0x9686, + 0xBEFC, 0x9687, 0xBEFD, 0x9688, 0xBEFE, 0x9689, 0xBEFF, 0x968A, 0xBF00, 0x968B, 0xBF01, 0xBBBF, 0xBF02, 0x968C, 0xBF03, 0x968D, + 0xBF04, 0x968E, 0xBF05, 0x968F, 0xBF06, 0x9690, 0xBF07, 0x9691, 0xBF08, 0xBBC0, 0xBF09, 0xBBC1, 0xBF0A, 0x9692, 0xBF0B, 0x9693, + 0xBF0C, 0x9694, 0xBF0D, 0x9695, 0xBF0E, 0x9696, 0xBF0F, 0x9697, 0xBF10, 0x9698, 0xBF11, 0x9699, 0xBF12, 0x969A, 0xBF13, 0x969B, + 0xBF14, 0x969C, 0xBF15, 0x969D, 0xBF16, 0x969E, 0xBF17, 0x969F, 0xBF18, 0xBBC2, 0xBF19, 0xBBC3, 0xBF1A, 0x96A0, 0xBF1B, 0xBBC4, + 0xBF1C, 0xBBC5, 0xBF1D, 0xBBC6, 0xBF1E, 0x96A1, 0xBF1F, 0x96A2, 0xBF20, 0x96A3, 0xBF21, 0x96A4, 0xBF22, 0x96A5, 0xBF23, 0x96A6, + 0xBF24, 0x96A7, 0xBF25, 0x96A8, 0xBF26, 0x96A9, 0xBF27, 0x96AA, 0xBF28, 0x96AB, 0xBF29, 0x96AC, 0xBF2A, 0x96AD, 0xBF2B, 0x96AE, + 0xBF2C, 0x96AF, 0xBF2D, 0x96B0, 0xBF2E, 0x96B1, 0xBF2F, 0x96B2, 0xBF30, 0x96B3, 0xBF31, 0x96B4, 0xBF32, 0x96B5, 0xBF33, 0x96B6, + 0xBF34, 0x96B7, 0xBF35, 0x96B8, 0xBF36, 0x96B9, 0xBF37, 0x96BA, 0xBF38, 0x96BB, 0xBF39, 0x96BC, 0xBF3A, 0x96BD, 0xBF3B, 0x96BE, + 0xBF3C, 0x96BF, 0xBF3D, 0x96C0, 0xBF3E, 0x96C1, 0xBF3F, 0x96C2, 0xBF40, 0xBBC7, 0xBF41, 0xBBC8, 0xBF42, 0x96C3, 0xBF43, 0x96C4, + 0xBF44, 0xBBC9, 0xBF45, 0x96C5, 0xBF46, 0x96C6, 0xBF47, 0x96C7, 0xBF48, 0xBBCA, 0xBF49, 0x96C8, 0xBF4A, 0x96C9, 0xBF4B, 0x96CA, + 0xBF4C, 0x96CB, 0xBF4D, 0x96CC, 0xBF4E, 0x96CD, 0xBF4F, 0x96CE, 0xBF50, 0xBBCB, 0xBF51, 0xBBCC, 0xBF52, 0x96CF, 0xBF53, 0x96D0, + 0xBF54, 0x96D1, 0xBF55, 0xBBCD, 0xBF56, 0x96D2, 0xBF57, 0x96D3, 0xBF58, 0x96D4, 0xBF59, 0x96D5, 0xBF5A, 0x96D6, 0xBF5B, 0x96D7, + 0xBF5C, 0x96D8, 0xBF5D, 0x96D9, 0xBF5E, 0x96DA, 0xBF5F, 0x96DB, 0xBF60, 0x96DC, 0xBF61, 0x96DD, 0xBF62, 0x96DE, 0xBF63, 0x96DF, + 0xBF64, 0x96E0, 0xBF65, 0x96E1, 0xBF66, 0x96E2, 0xBF67, 0x96E3, 0xBF68, 0x96E4, 0xBF69, 0x96E5, 0xBF6A, 0x96E6, 0xBF6B, 0x96E7, + 0xBF6C, 0x96E8, 0xBF6D, 0x96E9, 0xBF6E, 0x96EA, 0xBF6F, 0x96EB, 0xBF70, 0x96EC, 0xBF71, 0x96ED, 0xBF72, 0x96EE, 0xBF73, 0x96EF, + 0xBF74, 0x96F0, 0xBF75, 0x96F1, 0xBF76, 0x96F2, 0xBF77, 0x96F3, 0xBF78, 0x96F4, 0xBF79, 0x96F5, 0xBF7A, 0x96F6, 0xBF7B, 0x96F7, + 0xBF7C, 0x96F8, 0xBF7D, 0x96F9, 0xBF7E, 0x96FA, 0xBF7F, 0x96FB, 0xBF80, 0x96FC, 0xBF81, 0x96FD, 0xBF82, 0x96FE, 0xBF83, 0x9741, + 0xBF84, 0x9742, 0xBF85, 0x9743, 0xBF86, 0x9744, 0xBF87, 0x9745, 0xBF88, 0x9746, 0xBF89, 0x9747, 0xBF8A, 0x9748, 0xBF8B, 0x9749, + 0xBF8C, 0x974A, 0xBF8D, 0x974B, 0xBF8E, 0x974C, 0xBF8F, 0x974D, 0xBF90, 0x974E, 0xBF91, 0x974F, 0xBF92, 0x9750, 0xBF93, 0x9751, + 0xBF94, 0xBBCE, 0xBF95, 0x9752, 0xBF96, 0x9753, 0xBF97, 0x9754, 0xBF98, 0x9755, 0xBF99, 0x9756, 0xBF9A, 0x9757, 0xBF9B, 0x9758, + 0xBF9C, 0x9759, 0xBF9D, 0x975A, 0xBF9E, 0x9761, 0xBF9F, 0x9762, 0xBFA0, 0x9763, 0xBFA1, 0x9764, 0xBFA2, 0x9765, 0xBFA3, 0x9766, + 0xBFA4, 0x9767, 0xBFA5, 0x9768, 0xBFA6, 0x9769, 0xBFA7, 0x976A, 0xBFA8, 0x976B, 0xBFA9, 0x976C, 0xBFAA, 0x976D, 0xBFAB, 0x976E, + 0xBFAC, 0x976F, 0xBFAD, 0x9770, 0xBFAE, 0x9771, 0xBFAF, 0x9772, 0xBFB0, 0xBBCF, 0xBFB1, 0x9773, 0xBFB2, 0x9774, 0xBFB3, 0x9775, + 0xBFB4, 0x9776, 0xBFB5, 0x9777, 0xBFB6, 0x9778, 0xBFB7, 0x9779, 0xBFB8, 0x977A, 0xBFB9, 0x9781, 0xBFBA, 0x9782, 0xBFBB, 0x9783, + 0xBFBC, 0x9784, 0xBFBD, 0x9785, 0xBFBE, 0x9786, 0xBFBF, 0x9787, 0xBFC0, 0x9788, 0xBFC1, 0x9789, 0xBFC2, 0x978A, 0xBFC3, 0x978B, + 0xBFC4, 0x978C, 0xBFC5, 0xBBD0, 0xBFC6, 0x978D, 0xBFC7, 0x978E, 0xBFC8, 0x978F, 0xBFC9, 0x9790, 0xBFCA, 0x9791, 0xBFCB, 0x9792, + 0xBFCC, 0xBBD1, 0xBFCD, 0xBBD2, 0xBFCE, 0x9793, 0xBFCF, 0x9794, 0xBFD0, 0xBBD3, 0xBFD1, 0x9795, 0xBFD2, 0x9796, 0xBFD3, 0x9797, + 0xBFD4, 0xBBD4, 0xBFD5, 0x9798, 0xBFD6, 0x9799, 0xBFD7, 0x979A, 0xBFD8, 0x979B, 0xBFD9, 0x979C, 0xBFDA, 0x979D, 0xBFDB, 0x979E, + 0xBFDC, 0xBBD5, 0xBFDD, 0x979F, 0xBFDE, 0x97A0, 0xBFDF, 0xBBD6, 0xBFE0, 0x97A1, 0xBFE1, 0xBBD7, 0xBFE2, 0x97A2, 0xBFE3, 0x97A3, + 0xBFE4, 0x97A4, 0xBFE5, 0x97A5, 0xBFE6, 0x97A6, 0xBFE7, 0x97A7, 0xBFE8, 0x97A8, 0xBFE9, 0x97A9, 0xBFEA, 0x97AA, 0xBFEB, 0x97AB, + 0xBFEC, 0x97AC, 0xBFED, 0x97AD, 0xBFEE, 0x97AE, 0xBFEF, 0x97AF, 0xBFF0, 0x97B0, 0xBFF1, 0x97B1, 0xBFF2, 0x97B2, 0xBFF3, 0x97B3, + 0xBFF4, 0x97B4, 0xBFF5, 0x97B5, 0xBFF6, 0x97B6, 0xBFF7, 0x97B7, 0xBFF8, 0x97B8, 0xBFF9, 0x97B9, 0xBFFA, 0x97BA, 0xBFFB, 0x97BB, + 0xBFFC, 0x97BC, 0xBFFD, 0x97BD, 0xBFFE, 0x97BE, 0xBFFF, 0x97BF, 0xC000, 0x97C0, 0xC001, 0x97C1, 0xC002, 0x97C2, 0xC003, 0x97C3, + 0xC004, 0x97C4, 0xC005, 0x97C5, 0xC006, 0x97C6, 0xC007, 0x97C7, 0xC008, 0x97C8, 0xC009, 0x97C9, 0xC00A, 0x97CA, 0xC00B, 0x97CB, + 0xC00C, 0x97CC, 0xC00D, 0x97CD, 0xC00E, 0x97CE, 0xC00F, 0x97CF, 0xC010, 0x97D0, 0xC011, 0x97D1, 0xC012, 0x97D2, 0xC013, 0x97D3, + 0xC014, 0x97D4, 0xC015, 0x97D5, 0xC016, 0x97D6, 0xC017, 0x97D7, 0xC018, 0x97D8, 0xC019, 0x97D9, 0xC01A, 0x97DA, 0xC01B, 0x97DB, + 0xC01C, 0x97DC, 0xC01D, 0x97DD, 0xC01E, 0x97DE, 0xC01F, 0x97DF, 0xC020, 0x97E0, 0xC021, 0x97E1, 0xC022, 0x97E2, 0xC023, 0x97E3, + 0xC024, 0x97E4, 0xC025, 0x97E5, 0xC026, 0x97E6, 0xC027, 0x97E7, 0xC028, 0x97E8, 0xC029, 0x97E9, 0xC02A, 0x97EA, 0xC02B, 0x97EB, + 0xC02C, 0x97EC, 0xC02D, 0x97ED, 0xC02E, 0x97EE, 0xC02F, 0x97EF, 0xC030, 0x97F0, 0xC031, 0x97F1, 0xC032, 0x97F2, 0xC033, 0x97F3, + 0xC034, 0x97F4, 0xC035, 0x97F5, 0xC036, 0x97F6, 0xC037, 0x97F7, 0xC038, 0x97F8, 0xC039, 0x97F9, 0xC03A, 0x97FA, 0xC03B, 0x97FB, + 0xC03C, 0xBBD8, 0xC03D, 0x97FC, 0xC03E, 0x97FD, 0xC03F, 0x97FE, 0xC040, 0x9841, 0xC041, 0x9842, 0xC042, 0x9843, 0xC043, 0x9844, + 0xC044, 0x9845, 0xC045, 0x9846, 0xC046, 0x9847, 0xC047, 0x9848, 0xC048, 0x9849, 0xC049, 0x984A, 0xC04A, 0x984B, 0xC04B, 0x984C, + 0xC04C, 0x984D, 0xC04D, 0x984E, 0xC04E, 0x984F, 0xC04F, 0x9850, 0xC050, 0x9851, 0xC051, 0xBBD9, 0xC052, 0x9852, 0xC053, 0x9853, + 0xC054, 0x9854, 0xC055, 0x9855, 0xC056, 0x9856, 0xC057, 0x9857, 0xC058, 0xBBDA, 0xC059, 0x9858, 0xC05A, 0x9859, 0xC05B, 0x985A, + 0xC05C, 0xBBDB, 0xC05D, 0x9861, 0xC05E, 0x9862, 0xC05F, 0x9863, 0xC060, 0xBBDC, 0xC061, 0x9864, 0xC062, 0x9865, 0xC063, 0x9866, + 0xC064, 0x9867, 0xC065, 0x9868, 0xC066, 0x9869, 0xC067, 0x986A, 0xC068, 0xBBDD, 0xC069, 0xBBDE, 0xC06A, 0x986B, 0xC06B, 0x986C, + 0xC06C, 0x986D, 0xC06D, 0x986E, 0xC06E, 0x986F, 0xC06F, 0x9870, 0xC070, 0x9871, 0xC071, 0x9872, 0xC072, 0x9873, 0xC073, 0x9874, + 0xC074, 0x9875, 0xC075, 0x9876, 0xC076, 0x9877, 0xC077, 0x9878, 0xC078, 0x9879, 0xC079, 0x987A, 0xC07A, 0x9881, 0xC07B, 0x9882, + 0xC07C, 0x9883, 0xC07D, 0x9884, 0xC07E, 0x9885, 0xC07F, 0x9886, 0xC080, 0x9887, 0xC081, 0x9888, 0xC082, 0x9889, 0xC083, 0x988A, + 0xC084, 0x988B, 0xC085, 0x988C, 0xC086, 0x988D, 0xC087, 0x988E, 0xC088, 0x988F, 0xC089, 0x9890, 0xC08A, 0x9891, 0xC08B, 0x9892, + 0xC08C, 0x9893, 0xC08D, 0x9894, 0xC08E, 0x9895, 0xC08F, 0x9896, 0xC090, 0xBBDF, 0xC091, 0xBBE0, 0xC092, 0x9897, 0xC093, 0x9898, + 0xC094, 0xBBE1, 0xC095, 0x9899, 0xC096, 0x989A, 0xC097, 0x989B, 0xC098, 0xBBE2, 0xC099, 0x989C, 0xC09A, 0x989D, 0xC09B, 0x989E, + 0xC09C, 0x989F, 0xC09D, 0x98A0, 0xC09E, 0x98A1, 0xC09F, 0x98A2, 0xC0A0, 0xBBE3, 0xC0A1, 0xBBE4, 0xC0A2, 0x98A3, 0xC0A3, 0xBBE5, + 0xC0A4, 0x98A4, 0xC0A5, 0xBBE6, 0xC0A6, 0x98A5, 0xC0A7, 0x98A6, 0xC0A8, 0x98A7, 0xC0A9, 0x98A8, 0xC0AA, 0x98A9, 0xC0AB, 0x98AA, + 0xC0AC, 0xBBE7, 0xC0AD, 0xBBE8, 0xC0AE, 0x98AB, 0xC0AF, 0xBBE9, 0xC0B0, 0xBBEA, 0xC0B1, 0x98AC, 0xC0B2, 0x98AD, 0xC0B3, 0xBBEB, + 0xC0B4, 0xBBEC, 0xC0B5, 0xBBED, 0xC0B6, 0xBBEE, 0xC0B7, 0x98AE, 0xC0B8, 0x98AF, 0xC0B9, 0x98B0, 0xC0BA, 0x98B1, 0xC0BB, 0x98B2, + 0xC0BC, 0xBBEF, 0xC0BD, 0xBBF0, 0xC0BE, 0x98B3, 0xC0BF, 0xBBF1, 0xC0C0, 0xBBF2, 0xC0C1, 0xBBF3, 0xC0C2, 0x98B4, 0xC0C3, 0x98B5, + 0xC0C4, 0x98B6, 0xC0C5, 0xBBF4, 0xC0C6, 0x98B7, 0xC0C7, 0x98B8, 0xC0C8, 0xBBF5, 0xC0C9, 0xBBF6, 0xC0CA, 0x98B9, 0xC0CB, 0x98BA, + 0xC0CC, 0xBBF7, 0xC0CD, 0x98BB, 0xC0CE, 0x98BC, 0xC0CF, 0x98BD, 0xC0D0, 0xBBF8, 0xC0D1, 0x98BE, 0xC0D2, 0x98BF, 0xC0D3, 0x98C0, + 0xC0D4, 0x98C1, 0xC0D5, 0x98C2, 0xC0D6, 0x98C3, 0xC0D7, 0x98C4, 0xC0D8, 0xBBF9, 0xC0D9, 0xBBFA, 0xC0DA, 0x98C5, 0xC0DB, 0xBBFB, + 0xC0DC, 0xBBFC, 0xC0DD, 0xBBFD, 0xC0DE, 0x98C6, 0xC0DF, 0x98C7, 0xC0E0, 0x98C8, 0xC0E1, 0x98C9, 0xC0E2, 0x98CA, 0xC0E3, 0x98CB, + 0xC0E4, 0xBBFE, 0xC0E5, 0xBCA1, 0xC0E6, 0x98CC, 0xC0E7, 0x98CD, 0xC0E8, 0xBCA2, 0xC0E9, 0x98CE, 0xC0EA, 0x98CF, 0xC0EB, 0x98D0, + 0xC0EC, 0xBCA3, 0xC0ED, 0x98D1, 0xC0EE, 0x98D2, 0xC0EF, 0x98D3, 0xC0F0, 0x98D4, 0xC0F1, 0x98D5, 0xC0F2, 0x98D6, 0xC0F3, 0x98D7, + 0xC0F4, 0xBCA4, 0xC0F5, 0xBCA5, 0xC0F6, 0x98D8, 0xC0F7, 0xBCA6, 0xC0F8, 0x98D9, 0xC0F9, 0xBCA7, 0xC0FA, 0x98DA, 0xC0FB, 0x98DB, + 0xC0FC, 0x98DC, 0xC0FD, 0x98DD, 0xC0FE, 0x98DE, 0xC0FF, 0x98DF, 0xC100, 0xBCA8, 0xC101, 0x98E0, 0xC102, 0x98E1, 0xC103, 0x98E2, + 0xC104, 0xBCA9, 0xC105, 0x98E3, 0xC106, 0x98E4, 0xC107, 0x98E5, 0xC108, 0xBCAA, 0xC109, 0x98E6, 0xC10A, 0x98E7, 0xC10B, 0x98E8, + 0xC10C, 0x98E9, 0xC10D, 0x98EA, 0xC10E, 0x98EB, 0xC10F, 0x98EC, 0xC110, 0xBCAB, 0xC111, 0x98ED, 0xC112, 0x98EE, 0xC113, 0x98EF, + 0xC114, 0x98F0, 0xC115, 0xBCAC, 0xC116, 0x98F1, 0xC117, 0x98F2, 0xC118, 0x98F3, 0xC119, 0x98F4, 0xC11A, 0x98F5, 0xC11B, 0x98F6, + 0xC11C, 0xBCAD, 0xC11D, 0xBCAE, 0xC11E, 0xBCAF, 0xC11F, 0xBCB0, 0xC120, 0xBCB1, 0xC121, 0x98F7, 0xC122, 0x98F8, 0xC123, 0xBCB2, + 0xC124, 0xBCB3, 0xC125, 0x98F9, 0xC126, 0xBCB4, 0xC127, 0xBCB5, 0xC128, 0x98FA, 0xC129, 0x98FB, 0xC12A, 0x98FC, 0xC12B, 0x98FD, + 0xC12C, 0xBCB6, 0xC12D, 0xBCB7, 0xC12E, 0x98FE, 0xC12F, 0xBCB8, 0xC130, 0xBCB9, 0xC131, 0xBCBA, 0xC132, 0x9941, 0xC133, 0x9942, + 0xC134, 0x9943, 0xC135, 0x9944, 0xC136, 0xBCBB, 0xC137, 0x9945, 0xC138, 0xBCBC, 0xC139, 0xBCBD, 0xC13A, 0x9946, 0xC13B, 0x9947, + 0xC13C, 0xBCBE, 0xC13D, 0x9948, 0xC13E, 0x9949, 0xC13F, 0x994A, 0xC140, 0xBCBF, 0xC141, 0x994B, 0xC142, 0x994C, 0xC143, 0x994D, + 0xC144, 0x994E, 0xC145, 0x994F, 0xC146, 0x9950, 0xC147, 0x9951, 0xC148, 0xBCC0, 0xC149, 0xBCC1, 0xC14A, 0x9952, 0xC14B, 0xBCC2, + 0xC14C, 0xBCC3, 0xC14D, 0xBCC4, 0xC14E, 0x9953, 0xC14F, 0x9954, 0xC150, 0x9955, 0xC151, 0x9956, 0xC152, 0x9957, 0xC153, 0x9958, + 0xC154, 0xBCC5, 0xC155, 0xBCC6, 0xC156, 0x9959, 0xC157, 0x995A, 0xC158, 0xBCC7, 0xC159, 0x9961, 0xC15A, 0x9962, 0xC15B, 0x9963, + 0xC15C, 0xBCC8, 0xC15D, 0x9964, 0xC15E, 0x9965, 0xC15F, 0x9966, 0xC160, 0x9967, 0xC161, 0x9968, 0xC162, 0x9969, 0xC163, 0x996A, + 0xC164, 0xBCC9, 0xC165, 0xBCCA, 0xC166, 0x996B, 0xC167, 0xBCCB, 0xC168, 0xBCCC, 0xC169, 0xBCCD, 0xC16A, 0x996C, 0xC16B, 0x996D, + 0xC16C, 0x996E, 0xC16D, 0x996F, 0xC16E, 0x9970, 0xC16F, 0x9971, 0xC170, 0xBCCE, 0xC171, 0x9972, 0xC172, 0x9973, 0xC173, 0x9974, + 0xC174, 0xBCCF, 0xC175, 0x9975, 0xC176, 0x9976, 0xC177, 0x9977, 0xC178, 0xBCD0, 0xC179, 0x9978, 0xC17A, 0x9979, 0xC17B, 0x997A, + 0xC17C, 0x9981, 0xC17D, 0x9982, 0xC17E, 0x9983, 0xC17F, 0x9984, 0xC180, 0x9985, 0xC181, 0x9986, 0xC182, 0x9987, 0xC183, 0x9988, + 0xC184, 0x9989, 0xC185, 0xBCD1, 0xC186, 0x998A, 0xC187, 0x998B, 0xC188, 0x998C, 0xC189, 0x998D, 0xC18A, 0x998E, 0xC18B, 0x998F, + 0xC18C, 0xBCD2, 0xC18D, 0xBCD3, 0xC18E, 0xBCD4, 0xC18F, 0x9990, 0xC190, 0xBCD5, 0xC191, 0x9991, 0xC192, 0x9992, 0xC193, 0x9993, + 0xC194, 0xBCD6, 0xC195, 0x9994, 0xC196, 0xBCD7, 0xC197, 0x9995, 0xC198, 0x9996, 0xC199, 0x9997, 0xC19A, 0x9998, 0xC19B, 0x9999, + 0xC19C, 0xBCD8, 0xC19D, 0xBCD9, 0xC19E, 0x999A, 0xC19F, 0xBCDA, 0xC1A0, 0x999B, 0xC1A1, 0xBCDB, 0xC1A2, 0x999C, 0xC1A3, 0x999D, + 0xC1A4, 0x999E, 0xC1A5, 0xBCDC, 0xC1A6, 0x999F, 0xC1A7, 0x99A0, 0xC1A8, 0xBCDD, 0xC1A9, 0xBCDE, 0xC1AA, 0x99A1, 0xC1AB, 0x99A2, + 0xC1AC, 0xBCDF, 0xC1AD, 0x99A3, 0xC1AE, 0x99A4, 0xC1AF, 0x99A5, 0xC1B0, 0xBCE0, 0xC1B1, 0x99A6, 0xC1B2, 0x99A7, 0xC1B3, 0x99A8, + 0xC1B4, 0x99A9, 0xC1B5, 0x99AA, 0xC1B6, 0x99AB, 0xC1B7, 0x99AC, 0xC1B8, 0x99AD, 0xC1B9, 0x99AE, 0xC1BA, 0x99AF, 0xC1BB, 0x99B0, + 0xC1BC, 0x99B1, 0xC1BD, 0xBCE1, 0xC1BE, 0x99B2, 0xC1BF, 0x99B3, 0xC1C0, 0x99B4, 0xC1C1, 0x99B5, 0xC1C2, 0x99B6, 0xC1C3, 0x99B7, + 0xC1C4, 0xBCE2, 0xC1C5, 0x99B8, 0xC1C6, 0x99B9, 0xC1C7, 0x99BA, 0xC1C8, 0xBCE3, 0xC1C9, 0x99BB, 0xC1CA, 0x99BC, 0xC1CB, 0x99BD, + 0xC1CC, 0xBCE4, 0xC1CD, 0x99BE, 0xC1CE, 0x99BF, 0xC1CF, 0x99C0, 0xC1D0, 0x99C1, 0xC1D1, 0x99C2, 0xC1D2, 0x99C3, 0xC1D3, 0x99C4, + 0xC1D4, 0xBCE5, 0xC1D5, 0x99C5, 0xC1D6, 0x99C6, 0xC1D7, 0xBCE6, 0xC1D8, 0xBCE7, 0xC1D9, 0x99C7, 0xC1DA, 0x99C8, 0xC1DB, 0x99C9, + 0xC1DC, 0x99CA, 0xC1DD, 0x99CB, 0xC1DE, 0x99CC, 0xC1DF, 0x99CD, 0xC1E0, 0xBCE8, 0xC1E1, 0x99CE, 0xC1E2, 0x99CF, 0xC1E3, 0x99D0, + 0xC1E4, 0xBCE9, 0xC1E5, 0x99D1, 0xC1E6, 0x99D2, 0xC1E7, 0x99D3, 0xC1E8, 0xBCEA, 0xC1E9, 0x99D4, 0xC1EA, 0x99D5, 0xC1EB, 0x99D6, + 0xC1EC, 0x99D7, 0xC1ED, 0x99D8, 0xC1EE, 0x99D9, 0xC1EF, 0x99DA, 0xC1F0, 0xBCEB, 0xC1F1, 0xBCEC, 0xC1F2, 0x99DB, 0xC1F3, 0xBCED, + 0xC1F4, 0x99DC, 0xC1F5, 0x99DD, 0xC1F6, 0x99DE, 0xC1F7, 0x99DF, 0xC1F8, 0x99E0, 0xC1F9, 0x99E1, 0xC1FA, 0x99E2, 0xC1FB, 0x99E3, + 0xC1FC, 0xBCEE, 0xC1FD, 0xBCEF, 0xC1FE, 0x99E4, 0xC1FF, 0x99E5, 0xC200, 0xBCF0, 0xC201, 0x99E6, 0xC202, 0x99E7, 0xC203, 0x99E8, + 0xC204, 0xBCF1, 0xC205, 0x99E9, 0xC206, 0x99EA, 0xC207, 0x99EB, 0xC208, 0x99EC, 0xC209, 0x99ED, 0xC20A, 0x99EE, 0xC20B, 0x99EF, + 0xC20C, 0xBCF2, 0xC20D, 0xBCF3, 0xC20E, 0x99F0, 0xC20F, 0xBCF4, 0xC210, 0x99F1, 0xC211, 0xBCF5, 0xC212, 0x99F2, 0xC213, 0x99F3, + 0xC214, 0x99F4, 0xC215, 0x99F5, 0xC216, 0x99F6, 0xC217, 0x99F7, 0xC218, 0xBCF6, 0xC219, 0xBCF7, 0xC21A, 0x99F8, 0xC21B, 0x99F9, + 0xC21C, 0xBCF8, 0xC21D, 0x99FA, 0xC21E, 0x99FB, 0xC21F, 0xBCF9, 0xC220, 0xBCFA, 0xC221, 0x99FC, 0xC222, 0x99FD, 0xC223, 0x99FE, + 0xC224, 0x9A41, 0xC225, 0x9A42, 0xC226, 0x9A43, 0xC227, 0x9A44, 0xC228, 0xBCFB, 0xC229, 0xBCFC, 0xC22A, 0x9A45, 0xC22B, 0xBCFD, + 0xC22C, 0x9A46, 0xC22D, 0xBCFE, 0xC22E, 0x9A47, 0xC22F, 0xBDA1, 0xC230, 0x9A48, 0xC231, 0xBDA2, 0xC232, 0xBDA3, 0xC233, 0x9A49, + 0xC234, 0xBDA4, 0xC235, 0x9A4A, 0xC236, 0x9A4B, 0xC237, 0x9A4C, 0xC238, 0x9A4D, 0xC239, 0x9A4E, 0xC23A, 0x9A4F, 0xC23B, 0x9A50, + 0xC23C, 0x9A51, 0xC23D, 0x9A52, 0xC23E, 0x9A53, 0xC23F, 0x9A54, 0xC240, 0x9A55, 0xC241, 0x9A56, 0xC242, 0x9A57, 0xC243, 0x9A58, + 0xC244, 0x9A59, 0xC245, 0x9A5A, 0xC246, 0x9A61, 0xC247, 0x9A62, 0xC248, 0xBDA5, 0xC249, 0x9A63, 0xC24A, 0x9A64, 0xC24B, 0x9A65, + 0xC24C, 0x9A66, 0xC24D, 0x9A67, 0xC24E, 0x9A68, 0xC24F, 0x9A69, 0xC250, 0xBDA6, 0xC251, 0xBDA7, 0xC252, 0x9A6A, 0xC253, 0x9A6B, + 0xC254, 0xBDA8, 0xC255, 0x9A6C, 0xC256, 0x9A6D, 0xC257, 0x9A6E, 0xC258, 0xBDA9, 0xC259, 0x9A6F, 0xC25A, 0x9A70, 0xC25B, 0x9A71, + 0xC25C, 0x9A72, 0xC25D, 0x9A73, 0xC25E, 0x9A74, 0xC25F, 0x9A75, 0xC260, 0xBDAA, 0xC261, 0x9A76, 0xC262, 0x9A77, 0xC263, 0x9A78, + 0xC264, 0x9A79, 0xC265, 0xBDAB, 0xC266, 0x9A7A, 0xC267, 0x9A81, 0xC268, 0x9A82, 0xC269, 0x9A83, 0xC26A, 0x9A84, 0xC26B, 0x9A85, + 0xC26C, 0xBDAC, 0xC26D, 0xBDAD, 0xC26E, 0x9A86, 0xC26F, 0x9A87, 0xC270, 0xBDAE, 0xC271, 0x9A88, 0xC272, 0x9A89, 0xC273, 0x9A8A, + 0xC274, 0xBDAF, 0xC275, 0x9A8B, 0xC276, 0x9A8C, 0xC277, 0x9A8D, 0xC278, 0x9A8E, 0xC279, 0x9A8F, 0xC27A, 0x9A90, 0xC27B, 0x9A91, + 0xC27C, 0xBDB0, 0xC27D, 0xBDB1, 0xC27E, 0x9A92, 0xC27F, 0xBDB2, 0xC280, 0x9A93, 0xC281, 0xBDB3, 0xC282, 0x9A94, 0xC283, 0x9A95, + 0xC284, 0x9A96, 0xC285, 0x9A97, 0xC286, 0x9A98, 0xC287, 0x9A99, 0xC288, 0xBDB4, 0xC289, 0xBDB5, 0xC28A, 0x9A9A, 0xC28B, 0x9A9B, + 0xC28C, 0x9A9C, 0xC28D, 0x9A9D, 0xC28E, 0x9A9E, 0xC28F, 0x9A9F, 0xC290, 0xBDB6, 0xC291, 0x9AA0, 0xC292, 0x9AA1, 0xC293, 0x9AA2, + 0xC294, 0x9AA3, 0xC295, 0x9AA4, 0xC296, 0x9AA5, 0xC297, 0x9AA6, 0xC298, 0xBDB7, 0xC299, 0x9AA7, 0xC29A, 0x9AA8, 0xC29B, 0xBDB8, + 0xC29C, 0x9AA9, 0xC29D, 0xBDB9, 0xC29E, 0x9AAA, 0xC29F, 0x9AAB, 0xC2A0, 0x9AAC, 0xC2A1, 0x9AAD, 0xC2A2, 0x9AAE, 0xC2A3, 0x9AAF, + 0xC2A4, 0xBDBA, 0xC2A5, 0xBDBB, 0xC2A6, 0x9AB0, 0xC2A7, 0x9AB1, 0xC2A8, 0xBDBC, 0xC2A9, 0x9AB2, 0xC2AA, 0x9AB3, 0xC2AB, 0x9AB4, + 0xC2AC, 0xBDBD, 0xC2AD, 0xBDBE, 0xC2AE, 0x9AB5, 0xC2AF, 0x9AB6, 0xC2B0, 0x9AB7, 0xC2B1, 0x9AB8, 0xC2B2, 0x9AB9, 0xC2B3, 0x9ABA, + 0xC2B4, 0xBDBF, 0xC2B5, 0xBDC0, 0xC2B6, 0x9ABB, 0xC2B7, 0xBDC1, 0xC2B8, 0x9ABC, 0xC2B9, 0xBDC2, 0xC2BA, 0x9ABD, 0xC2BB, 0x9ABE, + 0xC2BC, 0x9ABF, 0xC2BD, 0x9AC0, 0xC2BE, 0x9AC1, 0xC2BF, 0x9AC2, 0xC2C0, 0x9AC3, 0xC2C1, 0x9AC4, 0xC2C2, 0x9AC5, 0xC2C3, 0x9AC6, + 0xC2C4, 0x9AC7, 0xC2C5, 0x9AC8, 0xC2C6, 0x9AC9, 0xC2C7, 0x9ACA, 0xC2C8, 0x9ACB, 0xC2C9, 0x9ACC, 0xC2CA, 0x9ACD, 0xC2CB, 0x9ACE, + 0xC2CC, 0x9ACF, 0xC2CD, 0x9AD0, 0xC2CE, 0x9AD1, 0xC2CF, 0x9AD2, 0xC2D0, 0x9AD3, 0xC2D1, 0x9AD4, 0xC2D2, 0x9AD5, 0xC2D3, 0x9AD6, + 0xC2D4, 0x9AD7, 0xC2D5, 0x9AD8, 0xC2D6, 0x9AD9, 0xC2D7, 0x9ADA, 0xC2D8, 0x9ADB, 0xC2D9, 0x9ADC, 0xC2DA, 0x9ADD, 0xC2DB, 0x9ADE, + 0xC2DC, 0xBDC3, 0xC2DD, 0xBDC4, 0xC2DE, 0x9ADF, 0xC2DF, 0x9AE0, 0xC2E0, 0xBDC5, 0xC2E1, 0x9AE1, 0xC2E2, 0x9AE2, 0xC2E3, 0xBDC6, + 0xC2E4, 0xBDC7, 0xC2E5, 0x9AE3, 0xC2E6, 0x9AE4, 0xC2E7, 0x9AE5, 0xC2E8, 0x9AE6, 0xC2E9, 0x9AE7, 0xC2EA, 0x9AE8, 0xC2EB, 0xBDC8, + 0xC2EC, 0xBDC9, 0xC2ED, 0xBDCA, 0xC2EE, 0x9AE9, 0xC2EF, 0xBDCB, 0xC2F0, 0x9AEA, 0xC2F1, 0xBDCC, 0xC2F2, 0x9AEB, 0xC2F3, 0x9AEC, + 0xC2F4, 0x9AED, 0xC2F5, 0x9AEE, 0xC2F6, 0xBDCD, 0xC2F7, 0x9AEF, 0xC2F8, 0xBDCE, 0xC2F9, 0xBDCF, 0xC2FA, 0x9AF0, 0xC2FB, 0xBDD0, + 0xC2FC, 0xBDD1, 0xC2FD, 0x9AF1, 0xC2FE, 0x9AF2, 0xC2FF, 0x9AF3, 0xC300, 0xBDD2, 0xC301, 0x9AF4, 0xC302, 0x9AF5, 0xC303, 0x9AF6, + 0xC304, 0x9AF7, 0xC305, 0x9AF8, 0xC306, 0x9AF9, 0xC307, 0x9AFA, 0xC308, 0xBDD3, 0xC309, 0xBDD4, 0xC30A, 0x9AFB, 0xC30B, 0x9AFC, + 0xC30C, 0xBDD5, 0xC30D, 0xBDD6, 0xC30E, 0x9AFD, 0xC30F, 0x9AFE, 0xC310, 0x9B41, 0xC311, 0x9B42, 0xC312, 0x9B43, 0xC313, 0xBDD7, + 0xC314, 0xBDD8, 0xC315, 0xBDD9, 0xC316, 0x9B44, 0xC317, 0x9B45, 0xC318, 0xBDDA, 0xC319, 0x9B46, 0xC31A, 0x9B47, 0xC31B, 0x9B48, + 0xC31C, 0xBDDB, 0xC31D, 0x9B49, 0xC31E, 0x9B4A, 0xC31F, 0x9B4B, 0xC320, 0x9B4C, 0xC321, 0x9B4D, 0xC322, 0x9B4E, 0xC323, 0x9B4F, + 0xC324, 0xBDDC, 0xC325, 0xBDDD, 0xC326, 0x9B50, 0xC327, 0x9B51, 0xC328, 0xBDDE, 0xC329, 0xBDDF, 0xC32A, 0x9B52, 0xC32B, 0x9B53, + 0xC32C, 0x9B54, 0xC32D, 0x9B55, 0xC32E, 0x9B56, 0xC32F, 0x9B57, 0xC330, 0x9B58, 0xC331, 0x9B59, 0xC332, 0x9B5A, 0xC333, 0x9B61, + 0xC334, 0x9B62, 0xC335, 0x9B63, 0xC336, 0x9B64, 0xC337, 0x9B65, 0xC338, 0x9B66, 0xC339, 0x9B67, 0xC33A, 0x9B68, 0xC33B, 0x9B69, + 0xC33C, 0x9B6A, 0xC33D, 0x9B6B, 0xC33E, 0x9B6C, 0xC33F, 0x9B6D, 0xC340, 0x9B6E, 0xC341, 0x9B6F, 0xC342, 0x9B70, 0xC343, 0x9B71, + 0xC344, 0x9B72, 0xC345, 0xBDE0, 0xC346, 0x9B73, 0xC347, 0x9B74, 0xC348, 0x9B75, 0xC349, 0x9B76, 0xC34A, 0x9B77, 0xC34B, 0x9B78, + 0xC34C, 0x9B79, 0xC34D, 0x9B7A, 0xC34E, 0x9B81, 0xC34F, 0x9B82, 0xC350, 0x9B83, 0xC351, 0x9B84, 0xC352, 0x9B85, 0xC353, 0x9B86, + 0xC354, 0x9B87, 0xC355, 0x9B88, 0xC356, 0x9B89, 0xC357, 0x9B8A, 0xC358, 0x9B8B, 0xC359, 0x9B8C, 0xC35A, 0x9B8D, 0xC35B, 0x9B8E, + 0xC35C, 0x9B8F, 0xC35D, 0x9B90, 0xC35E, 0x9B91, 0xC35F, 0x9B92, 0xC360, 0x9B93, 0xC361, 0x9B94, 0xC362, 0x9B95, 0xC363, 0x9B96, + 0xC364, 0x9B97, 0xC365, 0x9B98, 0xC366, 0x9B99, 0xC367, 0x9B9A, 0xC368, 0xBDE1, 0xC369, 0xBDE2, 0xC36A, 0x9B9B, 0xC36B, 0x9B9C, + 0xC36C, 0xBDE3, 0xC36D, 0x9B9D, 0xC36E, 0x9B9E, 0xC36F, 0x9B9F, 0xC370, 0xBDE4, 0xC371, 0x9BA0, 0xC372, 0xBDE5, 0xC373, 0x9BA1, + 0xC374, 0x9BA2, 0xC375, 0x9BA3, 0xC376, 0x9BA4, 0xC377, 0x9BA5, 0xC378, 0xBDE6, 0xC379, 0xBDE7, 0xC37A, 0x9BA6, 0xC37B, 0x9BA7, + 0xC37C, 0xBDE8, 0xC37D, 0xBDE9, 0xC37E, 0x9BA8, 0xC37F, 0x9BA9, 0xC380, 0x9BAA, 0xC381, 0x9BAB, 0xC382, 0x9BAC, 0xC383, 0x9BAD, + 0xC384, 0xBDEA, 0xC385, 0x9BAE, 0xC386, 0x9BAF, 0xC387, 0x9BB0, 0xC388, 0xBDEB, 0xC389, 0x9BB1, 0xC38A, 0x9BB2, 0xC38B, 0x9BB3, + 0xC38C, 0xBDEC, 0xC38D, 0x9BB4, 0xC38E, 0x9BB5, 0xC38F, 0x9BB6, 0xC390, 0x9BB7, 0xC391, 0x9BB8, 0xC392, 0x9BB9, 0xC393, 0x9BBA, + 0xC394, 0x9BBB, 0xC395, 0x9BBC, 0xC396, 0x9BBD, 0xC397, 0x9BBE, 0xC398, 0x9BBF, 0xC399, 0x9BC0, 0xC39A, 0x9BC1, 0xC39B, 0x9BC2, + 0xC39C, 0x9BC3, 0xC39D, 0x9BC4, 0xC39E, 0x9BC5, 0xC39F, 0x9BC6, 0xC3A0, 0x9BC7, 0xC3A1, 0x9BC8, 0xC3A2, 0x9BC9, 0xC3A3, 0x9BCA, + 0xC3A4, 0x9BCB, 0xC3A5, 0x9BCC, 0xC3A6, 0x9BCD, 0xC3A7, 0x9BCE, 0xC3A8, 0x9BCF, 0xC3A9, 0x9BD0, 0xC3AA, 0x9BD1, 0xC3AB, 0x9BD2, + 0xC3AC, 0x9BD3, 0xC3AD, 0x9BD4, 0xC3AE, 0x9BD5, 0xC3AF, 0x9BD6, 0xC3B0, 0x9BD7, 0xC3B1, 0x9BD8, 0xC3B2, 0x9BD9, 0xC3B3, 0x9BDA, + 0xC3B4, 0x9BDB, 0xC3B5, 0x9BDC, 0xC3B6, 0x9BDD, 0xC3B7, 0x9BDE, 0xC3B8, 0x9BDF, 0xC3B9, 0x9BE0, 0xC3BA, 0x9BE1, 0xC3BB, 0x9BE2, + 0xC3BC, 0x9BE3, 0xC3BD, 0x9BE4, 0xC3BE, 0x9BE5, 0xC3BF, 0x9BE6, 0xC3C0, 0xBDED, 0xC3C1, 0x9BE7, 0xC3C2, 0x9BE8, 0xC3C3, 0x9BE9, + 0xC3C4, 0x9BEA, 0xC3C5, 0x9BEB, 0xC3C6, 0x9BEC, 0xC3C7, 0x9BED, 0xC3C8, 0x9BEE, 0xC3C9, 0x9BEF, 0xC3CA, 0x9BF0, 0xC3CB, 0x9BF1, + 0xC3CC, 0x9BF2, 0xC3CD, 0x9BF3, 0xC3CE, 0x9BF4, 0xC3CF, 0x9BF5, 0xC3D0, 0x9BF6, 0xC3D1, 0x9BF7, 0xC3D2, 0x9BF8, 0xC3D3, 0x9BF9, + 0xC3D4, 0x9BFA, 0xC3D5, 0x9BFB, 0xC3D6, 0x9BFC, 0xC3D7, 0x9BFD, 0xC3D8, 0xBDEE, 0xC3D9, 0xBDEF, 0xC3DA, 0x9BFE, 0xC3DB, 0x9C41, + 0xC3DC, 0xBDF0, 0xC3DD, 0x9C42, 0xC3DE, 0x9C43, 0xC3DF, 0xBDF1, 0xC3E0, 0xBDF2, 0xC3E1, 0x9C44, 0xC3E2, 0xBDF3, 0xC3E3, 0x9C45, + 0xC3E4, 0x9C46, 0xC3E5, 0x9C47, 0xC3E6, 0x9C48, 0xC3E7, 0x9C49, 0xC3E8, 0xBDF4, 0xC3E9, 0xBDF5, 0xC3EA, 0x9C4A, 0xC3EB, 0x9C4B, + 0xC3EC, 0x9C4C, 0xC3ED, 0xBDF6, 0xC3EE, 0x9C4D, 0xC3EF, 0x9C4E, 0xC3F0, 0x9C4F, 0xC3F1, 0x9C50, 0xC3F2, 0x9C51, 0xC3F3, 0x9C52, + 0xC3F4, 0xBDF7, 0xC3F5, 0xBDF8, 0xC3F6, 0x9C53, 0xC3F7, 0x9C54, 0xC3F8, 0xBDF9, 0xC3F9, 0x9C55, 0xC3FA, 0x9C56, 0xC3FB, 0x9C57, + 0xC3FC, 0x9C58, 0xC3FD, 0x9C59, 0xC3FE, 0x9C5A, 0xC3FF, 0x9C61, 0xC400, 0x9C62, 0xC401, 0x9C63, 0xC402, 0x9C64, 0xC403, 0x9C65, + 0xC404, 0x9C66, 0xC405, 0x9C67, 0xC406, 0x9C68, 0xC407, 0x9C69, 0xC408, 0xBDFA, 0xC409, 0x9C6A, 0xC40A, 0x9C6B, 0xC40B, 0x9C6C, + 0xC40C, 0x9C6D, 0xC40D, 0x9C6E, 0xC40E, 0x9C6F, 0xC40F, 0x9C70, 0xC410, 0xBDFB, 0xC411, 0x9C71, 0xC412, 0x9C72, 0xC413, 0x9C73, + 0xC414, 0x9C74, 0xC415, 0x9C75, 0xC416, 0x9C76, 0xC417, 0x9C77, 0xC418, 0x9C78, 0xC419, 0x9C79, 0xC41A, 0x9C7A, 0xC41B, 0x9C81, + 0xC41C, 0x9C82, 0xC41D, 0x9C83, 0xC41E, 0x9C84, 0xC41F, 0x9C85, 0xC420, 0x9C86, 0xC421, 0x9C87, 0xC422, 0x9C88, 0xC423, 0x9C89, + 0xC424, 0xBDFC, 0xC425, 0x9C8A, 0xC426, 0x9C8B, 0xC427, 0x9C8C, 0xC428, 0x9C8D, 0xC429, 0x9C8E, 0xC42A, 0x9C8F, 0xC42B, 0x9C90, + 0xC42C, 0xBDFD, 0xC42D, 0x9C91, 0xC42E, 0x9C92, 0xC42F, 0x9C93, 0xC430, 0xBDFE, 0xC431, 0x9C94, 0xC432, 0x9C95, 0xC433, 0x9C96, + 0xC434, 0xBEA1, 0xC435, 0x9C97, 0xC436, 0x9C98, 0xC437, 0x9C99, 0xC438, 0x9C9A, 0xC439, 0x9C9B, 0xC43A, 0x9C9C, 0xC43B, 0x9C9D, + 0xC43C, 0xBEA2, 0xC43D, 0xBEA3, 0xC43E, 0x9C9E, 0xC43F, 0x9C9F, 0xC440, 0x9CA0, 0xC441, 0x9CA1, 0xC442, 0x9CA2, 0xC443, 0x9CA3, + 0xC444, 0x9CA4, 0xC445, 0x9CA5, 0xC446, 0x9CA6, 0xC447, 0x9CA7, 0xC448, 0xBEA4, 0xC449, 0x9CA8, 0xC44A, 0x9CA9, 0xC44B, 0x9CAA, + 0xC44C, 0x9CAB, 0xC44D, 0x9CAC, 0xC44E, 0x9CAD, 0xC44F, 0x9CAE, 0xC450, 0x9CAF, 0xC451, 0x9CB0, 0xC452, 0x9CB1, 0xC453, 0x9CB2, + 0xC454, 0x9CB3, 0xC455, 0x9CB4, 0xC456, 0x9CB5, 0xC457, 0x9CB6, 0xC458, 0x9CB7, 0xC459, 0x9CB8, 0xC45A, 0x9CB9, 0xC45B, 0x9CBA, + 0xC45C, 0x9CBB, 0xC45D, 0x9CBC, 0xC45E, 0x9CBD, 0xC45F, 0x9CBE, 0xC460, 0x9CBF, 0xC461, 0x9CC0, 0xC462, 0x9CC1, 0xC463, 0x9CC2, + 0xC464, 0xBEA5, 0xC465, 0xBEA6, 0xC466, 0x9CC3, 0xC467, 0x9CC4, 0xC468, 0xBEA7, 0xC469, 0x9CC5, 0xC46A, 0x9CC6, 0xC46B, 0x9CC7, + 0xC46C, 0xBEA8, 0xC46D, 0x9CC8, 0xC46E, 0x9CC9, 0xC46F, 0x9CCA, 0xC470, 0x9CCB, 0xC471, 0x9CCC, 0xC472, 0x9CCD, 0xC473, 0x9CCE, + 0xC474, 0xBEA9, 0xC475, 0xBEAA, 0xC476, 0x9CCF, 0xC477, 0x9CD0, 0xC478, 0x9CD1, 0xC479, 0xBEAB, 0xC47A, 0x9CD2, 0xC47B, 0x9CD3, + 0xC47C, 0x9CD4, 0xC47D, 0x9CD5, 0xC47E, 0x9CD6, 0xC47F, 0x9CD7, 0xC480, 0xBEAC, 0xC481, 0x9CD8, 0xC482, 0x9CD9, 0xC483, 0x9CDA, + 0xC484, 0x9CDB, 0xC485, 0x9CDC, 0xC486, 0x9CDD, 0xC487, 0x9CDE, 0xC488, 0x9CDF, 0xC489, 0x9CE0, 0xC48A, 0x9CE1, 0xC48B, 0x9CE2, + 0xC48C, 0x9CE3, 0xC48D, 0x9CE4, 0xC48E, 0x9CE5, 0xC48F, 0x9CE6, 0xC490, 0x9CE7, 0xC491, 0x9CE8, 0xC492, 0x9CE9, 0xC493, 0x9CEA, + 0xC494, 0xBEAD, 0xC495, 0x9CEB, 0xC496, 0x9CEC, 0xC497, 0x9CED, 0xC498, 0x9CEE, 0xC499, 0x9CEF, 0xC49A, 0x9CF0, 0xC49B, 0x9CF1, + 0xC49C, 0xBEAE, 0xC49D, 0x9CF2, 0xC49E, 0x9CF3, 0xC49F, 0x9CF4, 0xC4A0, 0x9CF5, 0xC4A1, 0x9CF6, 0xC4A2, 0x9CF7, 0xC4A3, 0x9CF8, + 0xC4A4, 0x9CF9, 0xC4A5, 0x9CFA, 0xC4A6, 0x9CFB, 0xC4A7, 0x9CFC, 0xC4A8, 0x9CFD, 0xC4A9, 0x9CFE, 0xC4AA, 0x9D41, 0xC4AB, 0x9D42, + 0xC4AC, 0x9D43, 0xC4AD, 0x9D44, 0xC4AE, 0x9D45, 0xC4AF, 0x9D46, 0xC4B0, 0x9D47, 0xC4B1, 0x9D48, 0xC4B2, 0x9D49, 0xC4B3, 0x9D4A, + 0xC4B4, 0x9D4B, 0xC4B5, 0x9D4C, 0xC4B6, 0x9D4D, 0xC4B7, 0x9D4E, 0xC4B8, 0xBEAF, 0xC4B9, 0x9D4F, 0xC4BA, 0x9D50, 0xC4BB, 0x9D51, + 0xC4BC, 0xBEB0, 0xC4BD, 0x9D52, 0xC4BE, 0x9D53, 0xC4BF, 0x9D54, 0xC4C0, 0x9D55, 0xC4C1, 0x9D56, 0xC4C2, 0x9D57, 0xC4C3, 0x9D58, + 0xC4C4, 0x9D59, 0xC4C5, 0x9D5A, 0xC4C6, 0x9D61, 0xC4C7, 0x9D62, 0xC4C8, 0x9D63, 0xC4C9, 0x9D64, 0xC4CA, 0x9D65, 0xC4CB, 0x9D66, + 0xC4CC, 0x9D67, 0xC4CD, 0x9D68, 0xC4CE, 0x9D69, 0xC4CF, 0x9D6A, 0xC4D0, 0x9D6B, 0xC4D1, 0x9D6C, 0xC4D2, 0x9D6D, 0xC4D3, 0x9D6E, + 0xC4D4, 0x9D6F, 0xC4D5, 0x9D70, 0xC4D6, 0x9D71, 0xC4D7, 0x9D72, 0xC4D8, 0x9D73, 0xC4D9, 0x9D74, 0xC4DA, 0x9D75, 0xC4DB, 0x9D76, + 0xC4DC, 0x9D77, 0xC4DD, 0x9D78, 0xC4DE, 0x9D79, 0xC4DF, 0x9D7A, 0xC4E0, 0x9D81, 0xC4E1, 0x9D82, 0xC4E2, 0x9D83, 0xC4E3, 0x9D84, + 0xC4E4, 0x9D85, 0xC4E5, 0x9D86, 0xC4E6, 0x9D87, 0xC4E7, 0x9D88, 0xC4E8, 0x9D89, 0xC4E9, 0xBEB1, 0xC4EA, 0x9D8A, 0xC4EB, 0x9D8B, + 0xC4EC, 0x9D8C, 0xC4ED, 0x9D8D, 0xC4EE, 0x9D8E, 0xC4EF, 0x9D8F, 0xC4F0, 0xBEB2, 0xC4F1, 0xBEB3, 0xC4F2, 0x9D90, 0xC4F3, 0x9D91, + 0xC4F4, 0xBEB4, 0xC4F5, 0x9D92, 0xC4F6, 0x9D93, 0xC4F7, 0x9D94, 0xC4F8, 0xBEB5, 0xC4F9, 0x9D95, 0xC4FA, 0xBEB6, 0xC4FB, 0x9D96, + 0xC4FC, 0x9D97, 0xC4FD, 0x9D98, 0xC4FE, 0x9D99, 0xC4FF, 0xBEB7, 0xC500, 0xBEB8, 0xC501, 0xBEB9, 0xC502, 0x9D9A, 0xC503, 0x9D9B, + 0xC504, 0x9D9C, 0xC505, 0x9D9D, 0xC506, 0x9D9E, 0xC507, 0x9D9F, 0xC508, 0x9DA0, 0xC509, 0x9DA1, 0xC50A, 0x9DA2, 0xC50B, 0x9DA3, + 0xC50C, 0xBEBA, 0xC50D, 0x9DA4, 0xC50E, 0x9DA5, 0xC50F, 0x9DA6, 0xC510, 0xBEBB, 0xC511, 0x9DA7, 0xC512, 0x9DA8, 0xC513, 0x9DA9, + 0xC514, 0xBEBC, 0xC515, 0x9DAA, 0xC516, 0x9DAB, 0xC517, 0x9DAC, 0xC518, 0x9DAD, 0xC519, 0x9DAE, 0xC51A, 0x9DAF, 0xC51B, 0x9DB0, + 0xC51C, 0xBEBD, 0xC51D, 0x9DB1, 0xC51E, 0x9DB2, 0xC51F, 0x9DB3, 0xC520, 0x9DB4, 0xC521, 0x9DB5, 0xC522, 0x9DB6, 0xC523, 0x9DB7, + 0xC524, 0x9DB8, 0xC525, 0x9DB9, 0xC526, 0x9DBA, 0xC527, 0x9DBB, 0xC528, 0xBEBE, 0xC529, 0xBEBF, 0xC52A, 0x9DBC, 0xC52B, 0x9DBD, + 0xC52C, 0xBEC0, 0xC52D, 0x9DBE, 0xC52E, 0x9DBF, 0xC52F, 0x9DC0, 0xC530, 0xBEC1, 0xC531, 0x9DC1, 0xC532, 0x9DC2, 0xC533, 0x9DC3, + 0xC534, 0x9DC4, 0xC535, 0x9DC5, 0xC536, 0x9DC6, 0xC537, 0x9DC7, 0xC538, 0xBEC2, 0xC539, 0xBEC3, 0xC53A, 0x9DC8, 0xC53B, 0xBEC4, + 0xC53C, 0x9DC9, 0xC53D, 0xBEC5, 0xC53E, 0x9DCA, 0xC53F, 0x9DCB, 0xC540, 0x9DCC, 0xC541, 0x9DCD, 0xC542, 0x9DCE, 0xC543, 0x9DCF, + 0xC544, 0xBEC6, 0xC545, 0xBEC7, 0xC546, 0x9DD0, 0xC547, 0x9DD1, 0xC548, 0xBEC8, 0xC549, 0xBEC9, 0xC54A, 0xBECA, 0xC54B, 0x9DD2, + 0xC54C, 0xBECB, 0xC54D, 0xBECC, 0xC54E, 0xBECD, 0xC54F, 0x9DD3, 0xC550, 0x9DD4, 0xC551, 0x9DD5, 0xC552, 0x9DD6, 0xC553, 0xBECE, + 0xC554, 0xBECF, 0xC555, 0xBED0, 0xC556, 0x9DD7, 0xC557, 0xBED1, 0xC558, 0xBED2, 0xC559, 0xBED3, 0xC55A, 0x9DD8, 0xC55B, 0x9DD9, + 0xC55C, 0x9DDA, 0xC55D, 0xBED4, 0xC55E, 0xBED5, 0xC55F, 0x9DDB, 0xC560, 0xBED6, 0xC561, 0xBED7, 0xC562, 0x9DDC, 0xC563, 0x9DDD, + 0xC564, 0xBED8, 0xC565, 0x9DDE, 0xC566, 0x9DDF, 0xC567, 0x9DE0, 0xC568, 0xBED9, 0xC569, 0x9DE1, 0xC56A, 0x9DE2, 0xC56B, 0x9DE3, + 0xC56C, 0x9DE4, 0xC56D, 0x9DE5, 0xC56E, 0x9DE6, 0xC56F, 0x9DE7, 0xC570, 0xBEDA, 0xC571, 0xBEDB, 0xC572, 0x9DE8, 0xC573, 0xBEDC, + 0xC574, 0xBEDD, 0xC575, 0xBEDE, 0xC576, 0x9DE9, 0xC577, 0x9DEA, 0xC578, 0x9DEB, 0xC579, 0x9DEC, 0xC57A, 0x9DED, 0xC57B, 0x9DEE, + 0xC57C, 0xBEDF, 0xC57D, 0xBEE0, 0xC57E, 0x9DEF, 0xC57F, 0x9DF0, 0xC580, 0xBEE1, 0xC581, 0x9DF1, 0xC582, 0x9DF2, 0xC583, 0x9DF3, + 0xC584, 0xBEE2, 0xC585, 0x9DF4, 0xC586, 0x9DF5, 0xC587, 0xBEE3, 0xC588, 0x9DF6, 0xC589, 0x9DF7, 0xC58A, 0x9DF8, 0xC58B, 0x9DF9, + 0xC58C, 0xBEE4, 0xC58D, 0xBEE5, 0xC58E, 0x9DFA, 0xC58F, 0xBEE6, 0xC590, 0x9DFB, 0xC591, 0xBEE7, 0xC592, 0x9DFC, 0xC593, 0x9DFD, + 0xC594, 0x9DFE, 0xC595, 0xBEE8, 0xC596, 0x9E41, 0xC597, 0xBEE9, 0xC598, 0xBEEA, 0xC599, 0x9E42, 0xC59A, 0x9E43, 0xC59B, 0x9E44, + 0xC59C, 0xBEEB, 0xC59D, 0x9E45, 0xC59E, 0x9E46, 0xC59F, 0x9E47, 0xC5A0, 0xBEEC, 0xC5A1, 0x9E48, 0xC5A2, 0x9E49, 0xC5A3, 0x9E4A, + 0xC5A4, 0x9E4B, 0xC5A5, 0x9E4C, 0xC5A6, 0x9E4D, 0xC5A7, 0x9E4E, 0xC5A8, 0x9E4F, 0xC5A9, 0xBEED, 0xC5AA, 0x9E50, 0xC5AB, 0x9E51, + 0xC5AC, 0x9E52, 0xC5AD, 0x9E53, 0xC5AE, 0x9E54, 0xC5AF, 0x9E55, 0xC5B0, 0x9E56, 0xC5B1, 0x9E57, 0xC5B2, 0x9E58, 0xC5B3, 0x9E59, + 0xC5B4, 0xBEEE, 0xC5B5, 0xBEEF, 0xC5B6, 0x9E5A, 0xC5B7, 0x9E61, 0xC5B8, 0xBEF0, 0xC5B9, 0xBEF1, 0xC5BA, 0x9E62, 0xC5BB, 0xBEF2, + 0xC5BC, 0xBEF3, 0xC5BD, 0xBEF4, 0xC5BE, 0xBEF5, 0xC5BF, 0x9E63, 0xC5C0, 0x9E64, 0xC5C1, 0x9E65, 0xC5C2, 0x9E66, 0xC5C3, 0x9E67, + 0xC5C4, 0xBEF6, 0xC5C5, 0xBEF7, 0xC5C6, 0xBEF8, 0xC5C7, 0xBEF9, 0xC5C8, 0xBEFA, 0xC5C9, 0xBEFB, 0xC5CA, 0xBEFC, 0xC5CB, 0x9E68, + 0xC5CC, 0xBEFD, 0xC5CD, 0x9E69, 0xC5CE, 0xBEFE, 0xC5CF, 0x9E6A, 0xC5D0, 0xBFA1, 0xC5D1, 0xBFA2, 0xC5D2, 0x9E6B, 0xC5D3, 0x9E6C, + 0xC5D4, 0xBFA3, 0xC5D5, 0x9E6D, 0xC5D6, 0x9E6E, 0xC5D7, 0x9E6F, 0xC5D8, 0xBFA4, 0xC5D9, 0x9E70, 0xC5DA, 0x9E71, 0xC5DB, 0x9E72, + 0xC5DC, 0x9E73, 0xC5DD, 0x9E74, 0xC5DE, 0x9E75, 0xC5DF, 0x9E76, 0xC5E0, 0xBFA5, 0xC5E1, 0xBFA6, 0xC5E2, 0x9E77, 0xC5E3, 0xBFA7, + 0xC5E4, 0x9E78, 0xC5E5, 0xBFA8, 0xC5E6, 0x9E79, 0xC5E7, 0x9E7A, 0xC5E8, 0x9E81, 0xC5E9, 0x9E82, 0xC5EA, 0x9E83, 0xC5EB, 0x9E84, + 0xC5EC, 0xBFA9, 0xC5ED, 0xBFAA, 0xC5EE, 0xBFAB, 0xC5EF, 0x9E85, 0xC5F0, 0xBFAC, 0xC5F1, 0x9E86, 0xC5F2, 0x9E87, 0xC5F3, 0x9E88, + 0xC5F4, 0xBFAD, 0xC5F5, 0x9E89, 0xC5F6, 0xBFAE, 0xC5F7, 0xBFAF, 0xC5F8, 0x9E8A, 0xC5F9, 0x9E8B, 0xC5FA, 0x9E8C, 0xC5FB, 0x9E8D, + 0xC5FC, 0xBFB0, 0xC5FD, 0xBFB1, 0xC5FE, 0xBFB2, 0xC5FF, 0xBFB3, 0xC600, 0xBFB4, 0xC601, 0xBFB5, 0xC602, 0x9E8E, 0xC603, 0x9E8F, + 0xC604, 0x9E90, 0xC605, 0xBFB6, 0xC606, 0xBFB7, 0xC607, 0xBFB8, 0xC608, 0xBFB9, 0xC609, 0x9E91, 0xC60A, 0x9E92, 0xC60B, 0x9E93, + 0xC60C, 0xBFBA, 0xC60D, 0x9E94, 0xC60E, 0x9E95, 0xC60F, 0x9E96, 0xC610, 0xBFBB, 0xC611, 0x9E97, 0xC612, 0x9E98, 0xC613, 0x9E99, + 0xC614, 0x9E9A, 0xC615, 0x9E9B, 0xC616, 0x9E9C, 0xC617, 0x9E9D, 0xC618, 0xBFBC, 0xC619, 0xBFBD, 0xC61A, 0x9E9E, 0xC61B, 0xBFBE, + 0xC61C, 0xBFBF, 0xC61D, 0x9E9F, 0xC61E, 0x9EA0, 0xC61F, 0x9EA1, 0xC620, 0x9EA2, 0xC621, 0x9EA3, 0xC622, 0x9EA4, 0xC623, 0x9EA5, + 0xC624, 0xBFC0, 0xC625, 0xBFC1, 0xC626, 0x9EA6, 0xC627, 0x9EA7, 0xC628, 0xBFC2, 0xC629, 0x9EA8, 0xC62A, 0x9EA9, 0xC62B, 0x9EAA, + 0xC62C, 0xBFC3, 0xC62D, 0xBFC4, 0xC62E, 0xBFC5, 0xC62F, 0x9EAB, 0xC630, 0xBFC6, 0xC631, 0x9EAC, 0xC632, 0x9EAD, 0xC633, 0xBFC7, + 0xC634, 0xBFC8, 0xC635, 0xBFC9, 0xC636, 0x9EAE, 0xC637, 0xBFCA, 0xC638, 0x9EAF, 0xC639, 0xBFCB, 0xC63A, 0x9EB0, 0xC63B, 0xBFCC, + 0xC63C, 0x9EB1, 0xC63D, 0x9EB2, 0xC63E, 0x9EB3, 0xC63F, 0x9EB4, 0xC640, 0xBFCD, 0xC641, 0xBFCE, 0xC642, 0x9EB5, 0xC643, 0x9EB6, + 0xC644, 0xBFCF, 0xC645, 0x9EB7, 0xC646, 0x9EB8, 0xC647, 0x9EB9, 0xC648, 0xBFD0, 0xC649, 0x9EBA, 0xC64A, 0x9EBB, 0xC64B, 0x9EBC, + 0xC64C, 0x9EBD, 0xC64D, 0x9EBE, 0xC64E, 0x9EBF, 0xC64F, 0x9EC0, 0xC650, 0xBFD1, 0xC651, 0xBFD2, 0xC652, 0x9EC1, 0xC653, 0xBFD3, + 0xC654, 0xBFD4, 0xC655, 0xBFD5, 0xC656, 0x9EC2, 0xC657, 0x9EC3, 0xC658, 0x9EC4, 0xC659, 0x9EC5, 0xC65A, 0x9EC6, 0xC65B, 0x9EC7, + 0xC65C, 0xBFD6, 0xC65D, 0xBFD7, 0xC65E, 0x9EC8, 0xC65F, 0x9EC9, 0xC660, 0xBFD8, 0xC661, 0x9ECA, 0xC662, 0x9ECB, 0xC663, 0x9ECC, + 0xC664, 0x9ECD, 0xC665, 0x9ECE, 0xC666, 0x9ECF, 0xC667, 0x9ED0, 0xC668, 0x9ED1, 0xC669, 0x9ED2, 0xC66A, 0x9ED3, 0xC66B, 0x9ED4, + 0xC66C, 0xBFD9, 0xC66D, 0x9ED5, 0xC66E, 0x9ED6, 0xC66F, 0xBFDA, 0xC670, 0x9ED7, 0xC671, 0xBFDB, 0xC672, 0x9ED8, 0xC673, 0x9ED9, + 0xC674, 0x9EDA, 0xC675, 0x9EDB, 0xC676, 0x9EDC, 0xC677, 0x9EDD, 0xC678, 0xBFDC, 0xC679, 0xBFDD, 0xC67A, 0x9EDE, 0xC67B, 0x9EDF, + 0xC67C, 0xBFDE, 0xC67D, 0x9EE0, 0xC67E, 0x9EE1, 0xC67F, 0x9EE2, 0xC680, 0xBFDF, 0xC681, 0x9EE3, 0xC682, 0x9EE4, 0xC683, 0x9EE5, + 0xC684, 0x9EE6, 0xC685, 0x9EE7, 0xC686, 0x9EE8, 0xC687, 0x9EE9, 0xC688, 0xBFE0, 0xC689, 0xBFE1, 0xC68A, 0x9EEA, 0xC68B, 0xBFE2, + 0xC68C, 0x9EEB, 0xC68D, 0xBFE3, 0xC68E, 0x9EEC, 0xC68F, 0x9EED, 0xC690, 0x9EEE, 0xC691, 0x9EEF, 0xC692, 0x9EF0, 0xC693, 0x9EF1, + 0xC694, 0xBFE4, 0xC695, 0xBFE5, 0xC696, 0x9EF2, 0xC697, 0x9EF3, 0xC698, 0xBFE6, 0xC699, 0x9EF4, 0xC69A, 0x9EF5, 0xC69B, 0x9EF6, + 0xC69C, 0xBFE7, 0xC69D, 0x9EF7, 0xC69E, 0x9EF8, 0xC69F, 0x9EF9, 0xC6A0, 0x9EFA, 0xC6A1, 0x9EFB, 0xC6A2, 0x9EFC, 0xC6A3, 0x9EFD, + 0xC6A4, 0xBFE8, 0xC6A5, 0xBFE9, 0xC6A6, 0x9EFE, 0xC6A7, 0xBFEA, 0xC6A8, 0x9F41, 0xC6A9, 0xBFEB, 0xC6AA, 0x9F42, 0xC6AB, 0x9F43, + 0xC6AC, 0x9F44, 0xC6AD, 0x9F45, 0xC6AE, 0x9F46, 0xC6AF, 0x9F47, 0xC6B0, 0xBFEC, 0xC6B1, 0xBFED, 0xC6B2, 0x9F48, 0xC6B3, 0x9F49, + 0xC6B4, 0xBFEE, 0xC6B5, 0x9F4A, 0xC6B6, 0x9F4B, 0xC6B7, 0x9F4C, 0xC6B8, 0xBFEF, 0xC6B9, 0xBFF0, 0xC6BA, 0xBFF1, 0xC6BB, 0x9F4D, + 0xC6BC, 0x9F4E, 0xC6BD, 0x9F4F, 0xC6BE, 0x9F50, 0xC6BF, 0x9F51, 0xC6C0, 0xBFF2, 0xC6C1, 0xBFF3, 0xC6C2, 0x9F52, 0xC6C3, 0xBFF4, + 0xC6C4, 0x9F53, 0xC6C5, 0xBFF5, 0xC6C6, 0x9F54, 0xC6C7, 0x9F55, 0xC6C8, 0x9F56, 0xC6C9, 0x9F57, 0xC6CA, 0x9F58, 0xC6CB, 0x9F59, + 0xC6CC, 0xBFF6, 0xC6CD, 0xBFF7, 0xC6CE, 0x9F5A, 0xC6CF, 0x9F61, 0xC6D0, 0xBFF8, 0xC6D1, 0x9F62, 0xC6D2, 0x9F63, 0xC6D3, 0x9F64, + 0xC6D4, 0xBFF9, 0xC6D5, 0x9F65, 0xC6D6, 0x9F66, 0xC6D7, 0x9F67, 0xC6D8, 0x9F68, 0xC6D9, 0x9F69, 0xC6DA, 0x9F6A, 0xC6DB, 0x9F6B, + 0xC6DC, 0xBFFA, 0xC6DD, 0xBFFB, 0xC6DE, 0x9F6C, 0xC6DF, 0x9F6D, 0xC6E0, 0xBFFC, 0xC6E1, 0xBFFD, 0xC6E2, 0x9F6E, 0xC6E3, 0x9F6F, + 0xC6E4, 0x9F70, 0xC6E5, 0x9F71, 0xC6E6, 0x9F72, 0xC6E7, 0x9F73, 0xC6E8, 0xBFFE, 0xC6E9, 0xC0A1, 0xC6EA, 0x9F74, 0xC6EB, 0x9F75, + 0xC6EC, 0xC0A2, 0xC6ED, 0x9F76, 0xC6EE, 0x9F77, 0xC6EF, 0x9F78, 0xC6F0, 0xC0A3, 0xC6F1, 0x9F79, 0xC6F2, 0x9F7A, 0xC6F3, 0x9F81, + 0xC6F4, 0x9F82, 0xC6F5, 0x9F83, 0xC6F6, 0x9F84, 0xC6F7, 0x9F85, 0xC6F8, 0xC0A4, 0xC6F9, 0xC0A5, 0xC6FA, 0x9F86, 0xC6FB, 0x9F87, + 0xC6FC, 0x9F88, 0xC6FD, 0xC0A6, 0xC6FE, 0x9F89, 0xC6FF, 0x9F8A, 0xC700, 0x9F8B, 0xC701, 0x9F8C, 0xC702, 0x9F8D, 0xC703, 0x9F8E, + 0xC704, 0xC0A7, 0xC705, 0xC0A8, 0xC706, 0x9F8F, 0xC707, 0x9F90, 0xC708, 0xC0A9, 0xC709, 0x9F91, 0xC70A, 0x9F92, 0xC70B, 0x9F93, + 0xC70C, 0xC0AA, 0xC70D, 0x9F94, 0xC70E, 0x9F95, 0xC70F, 0x9F96, 0xC710, 0x9F97, 0xC711, 0x9F98, 0xC712, 0x9F99, 0xC713, 0x9F9A, + 0xC714, 0xC0AB, 0xC715, 0xC0AC, 0xC716, 0x9F9B, 0xC717, 0xC0AD, 0xC718, 0x9F9C, 0xC719, 0xC0AE, 0xC71A, 0x9F9D, 0xC71B, 0x9F9E, + 0xC71C, 0x9F9F, 0xC71D, 0x9FA0, 0xC71E, 0x9FA1, 0xC71F, 0x9FA2, 0xC720, 0xC0AF, 0xC721, 0xC0B0, 0xC722, 0x9FA3, 0xC723, 0x9FA4, + 0xC724, 0xC0B1, 0xC725, 0x9FA5, 0xC726, 0x9FA6, 0xC727, 0x9FA7, 0xC728, 0xC0B2, 0xC729, 0x9FA8, 0xC72A, 0x9FA9, 0xC72B, 0x9FAA, + 0xC72C, 0x9FAB, 0xC72D, 0x9FAC, 0xC72E, 0x9FAD, 0xC72F, 0x9FAE, 0xC730, 0xC0B3, 0xC731, 0xC0B4, 0xC732, 0x9FAF, 0xC733, 0xC0B5, + 0xC734, 0x9FB0, 0xC735, 0xC0B6, 0xC736, 0x9FB1, 0xC737, 0xC0B7, 0xC738, 0x9FB2, 0xC739, 0x9FB3, 0xC73A, 0x9FB4, 0xC73B, 0x9FB5, + 0xC73C, 0xC0B8, 0xC73D, 0xC0B9, 0xC73E, 0x9FB6, 0xC73F, 0x9FB7, 0xC740, 0xC0BA, 0xC741, 0x9FB8, 0xC742, 0x9FB9, 0xC743, 0x9FBA, + 0xC744, 0xC0BB, 0xC745, 0x9FBB, 0xC746, 0x9FBC, 0xC747, 0x9FBD, 0xC748, 0x9FBE, 0xC749, 0x9FBF, 0xC74A, 0xC0BC, 0xC74B, 0x9FC0, + 0xC74C, 0xC0BD, 0xC74D, 0xC0BE, 0xC74E, 0x9FC1, 0xC74F, 0xC0BF, 0xC750, 0x9FC2, 0xC751, 0xC0C0, 0xC752, 0xC0C1, 0xC753, 0xC0C2, + 0xC754, 0xC0C3, 0xC755, 0xC0C4, 0xC756, 0xC0C5, 0xC757, 0xC0C6, 0xC758, 0xC0C7, 0xC759, 0x9FC3, 0xC75A, 0x9FC4, 0xC75B, 0x9FC5, + 0xC75C, 0xC0C8, 0xC75D, 0x9FC6, 0xC75E, 0x9FC7, 0xC75F, 0x9FC8, 0xC760, 0xC0C9, 0xC761, 0x9FC9, 0xC762, 0x9FCA, 0xC763, 0x9FCB, + 0xC764, 0x9FCC, 0xC765, 0x9FCD, 0xC766, 0x9FCE, 0xC767, 0x9FCF, 0xC768, 0xC0CA, 0xC769, 0x9FD0, 0xC76A, 0x9FD1, 0xC76B, 0xC0CB, + 0xC76C, 0x9FD2, 0xC76D, 0x9FD3, 0xC76E, 0x9FD4, 0xC76F, 0x9FD5, 0xC770, 0x9FD6, 0xC771, 0x9FD7, 0xC772, 0x9FD8, 0xC773, 0x9FD9, + 0xC774, 0xC0CC, 0xC775, 0xC0CD, 0xC776, 0x9FDA, 0xC777, 0x9FDB, 0xC778, 0xC0CE, 0xC779, 0x9FDC, 0xC77A, 0x9FDD, 0xC77B, 0x9FDE, + 0xC77C, 0xC0CF, 0xC77D, 0xC0D0, 0xC77E, 0xC0D1, 0xC77F, 0x9FDF, 0xC780, 0x9FE0, 0xC781, 0x9FE1, 0xC782, 0x9FE2, 0xC783, 0xC0D2, + 0xC784, 0xC0D3, 0xC785, 0xC0D4, 0xC786, 0x9FE3, 0xC787, 0xC0D5, 0xC788, 0xC0D6, 0xC789, 0xC0D7, 0xC78A, 0xC0D8, 0xC78B, 0x9FE4, + 0xC78C, 0x9FE5, 0xC78D, 0x9FE6, 0xC78E, 0xC0D9, 0xC78F, 0x9FE7, 0xC790, 0xC0DA, 0xC791, 0xC0DB, 0xC792, 0x9FE8, 0xC793, 0x9FE9, + 0xC794, 0xC0DC, 0xC795, 0x9FEA, 0xC796, 0xC0DD, 0xC797, 0xC0DE, 0xC798, 0xC0DF, 0xC799, 0x9FEB, 0xC79A, 0xC0E0, 0xC79B, 0x9FEC, + 0xC79C, 0x9FED, 0xC79D, 0x9FEE, 0xC79E, 0x9FEF, 0xC79F, 0x9FF0, 0xC7A0, 0xC0E1, 0xC7A1, 0xC0E2, 0xC7A2, 0x9FF1, 0xC7A3, 0xC0E3, + 0xC7A4, 0xC0E4, 0xC7A5, 0xC0E5, 0xC7A6, 0xC0E6, 0xC7A7, 0x9FF2, 0xC7A8, 0x9FF3, 0xC7A9, 0x9FF4, 0xC7AA, 0x9FF5, 0xC7AB, 0x9FF6, + 0xC7AC, 0xC0E7, 0xC7AD, 0xC0E8, 0xC7AE, 0x9FF7, 0xC7AF, 0x9FF8, 0xC7B0, 0xC0E9, 0xC7B1, 0x9FF9, 0xC7B2, 0x9FFA, 0xC7B3, 0x9FFB, + 0xC7B4, 0xC0EA, 0xC7B5, 0x9FFC, 0xC7B6, 0x9FFD, 0xC7B7, 0x9FFE, 0xC7B8, 0xA041, 0xC7B9, 0xA042, 0xC7BA, 0xA043, 0xC7BB, 0xA044, + 0xC7BC, 0xC0EB, 0xC7BD, 0xC0EC, 0xC7BE, 0xA045, 0xC7BF, 0xC0ED, 0xC7C0, 0xC0EE, 0xC7C1, 0xC0EF, 0xC7C2, 0xA046, 0xC7C3, 0xA047, + 0xC7C4, 0xA048, 0xC7C5, 0xA049, 0xC7C6, 0xA04A, 0xC7C7, 0xA04B, 0xC7C8, 0xC0F0, 0xC7C9, 0xC0F1, 0xC7CA, 0xA04C, 0xC7CB, 0xA04D, + 0xC7CC, 0xC0F2, 0xC7CD, 0xA04E, 0xC7CE, 0xC0F3, 0xC7CF, 0xA04F, 0xC7D0, 0xC0F4, 0xC7D1, 0xA050, 0xC7D2, 0xA051, 0xC7D3, 0xA052, + 0xC7D4, 0xA053, 0xC7D5, 0xA054, 0xC7D6, 0xA055, 0xC7D7, 0xA056, 0xC7D8, 0xC0F5, 0xC7D9, 0xA057, 0xC7DA, 0xA058, 0xC7DB, 0xA059, + 0xC7DC, 0xA05A, 0xC7DD, 0xC0F6, 0xC7DE, 0xA061, 0xC7DF, 0xA062, 0xC7E0, 0xA063, 0xC7E1, 0xA064, 0xC7E2, 0xA065, 0xC7E3, 0xA066, + 0xC7E4, 0xC0F7, 0xC7E5, 0xA067, 0xC7E6, 0xA068, 0xC7E7, 0xA069, 0xC7E8, 0xC0F8, 0xC7E9, 0xA06A, 0xC7EA, 0xA06B, 0xC7EB, 0xA06C, + 0xC7EC, 0xC0F9, 0xC7ED, 0xA06D, 0xC7EE, 0xA06E, 0xC7EF, 0xA06F, 0xC7F0, 0xA070, 0xC7F1, 0xA071, 0xC7F2, 0xA072, 0xC7F3, 0xA073, + 0xC7F4, 0xA074, 0xC7F5, 0xA075, 0xC7F6, 0xA076, 0xC7F7, 0xA077, 0xC7F8, 0xA078, 0xC7F9, 0xA079, 0xC7FA, 0xA07A, 0xC7FB, 0xA081, + 0xC7FC, 0xA082, 0xC7FD, 0xA083, 0xC7FE, 0xA084, 0xC7FF, 0xA085, 0xC800, 0xC0FA, 0xC801, 0xC0FB, 0xC802, 0xA086, 0xC803, 0xA087, + 0xC804, 0xC0FC, 0xC805, 0xA088, 0xC806, 0xA089, 0xC807, 0xA08A, 0xC808, 0xC0FD, 0xC809, 0xA08B, 0xC80A, 0xC0FE, 0xC80B, 0xA08C, + 0xC80C, 0xA08D, 0xC80D, 0xA08E, 0xC80E, 0xA08F, 0xC80F, 0xA090, 0xC810, 0xC1A1, 0xC811, 0xC1A2, 0xC812, 0xA091, 0xC813, 0xC1A3, + 0xC814, 0xA092, 0xC815, 0xC1A4, 0xC816, 0xC1A5, 0xC817, 0xA093, 0xC818, 0xA094, 0xC819, 0xA095, 0xC81A, 0xA096, 0xC81B, 0xA097, + 0xC81C, 0xC1A6, 0xC81D, 0xC1A7, 0xC81E, 0xA098, 0xC81F, 0xA099, 0xC820, 0xC1A8, 0xC821, 0xA09A, 0xC822, 0xA09B, 0xC823, 0xA09C, + 0xC824, 0xC1A9, 0xC825, 0xA09D, 0xC826, 0xA09E, 0xC827, 0xA09F, 0xC828, 0xA0A0, 0xC829, 0xA0A1, 0xC82A, 0xA0A2, 0xC82B, 0xA0A3, + 0xC82C, 0xC1AA, 0xC82D, 0xC1AB, 0xC82E, 0xA0A4, 0xC82F, 0xC1AC, 0xC830, 0xA0A5, 0xC831, 0xC1AD, 0xC832, 0xA0A6, 0xC833, 0xA0A7, + 0xC834, 0xA0A8, 0xC835, 0xA0A9, 0xC836, 0xA0AA, 0xC837, 0xA0AB, 0xC838, 0xC1AE, 0xC839, 0xA0AC, 0xC83A, 0xA0AD, 0xC83B, 0xA0AE, + 0xC83C, 0xC1AF, 0xC83D, 0xA0AF, 0xC83E, 0xA0B0, 0xC83F, 0xA0B1, 0xC840, 0xC1B0, 0xC841, 0xA0B2, 0xC842, 0xA0B3, 0xC843, 0xA0B4, + 0xC844, 0xA0B5, 0xC845, 0xA0B6, 0xC846, 0xA0B7, 0xC847, 0xA0B8, 0xC848, 0xC1B1, 0xC849, 0xC1B2, 0xC84A, 0xA0B9, 0xC84B, 0xA0BA, + 0xC84C, 0xC1B3, 0xC84D, 0xC1B4, 0xC84E, 0xA0BB, 0xC84F, 0xA0BC, 0xC850, 0xA0BD, 0xC851, 0xA0BE, 0xC852, 0xA0BF, 0xC853, 0xA0C0, + 0xC854, 0xC1B5, 0xC855, 0xA0C1, 0xC856, 0xA0C2, 0xC857, 0xA0C3, 0xC858, 0xA0C4, 0xC859, 0xA0C5, 0xC85A, 0xA0C6, 0xC85B, 0xA0C7, + 0xC85C, 0xA0C8, 0xC85D, 0xA0C9, 0xC85E, 0xA0CA, 0xC85F, 0xA0CB, 0xC860, 0xA0CC, 0xC861, 0xA0CD, 0xC862, 0xA0CE, 0xC863, 0xA0CF, + 0xC864, 0xA0D0, 0xC865, 0xA0D1, 0xC866, 0xA0D2, 0xC867, 0xA0D3, 0xC868, 0xA0D4, 0xC869, 0xA0D5, 0xC86A, 0xA0D6, 0xC86B, 0xA0D7, + 0xC86C, 0xA0D8, 0xC86D, 0xA0D9, 0xC86E, 0xA0DA, 0xC86F, 0xA0DB, 0xC870, 0xC1B6, 0xC871, 0xC1B7, 0xC872, 0xA0DC, 0xC873, 0xA0DD, + 0xC874, 0xC1B8, 0xC875, 0xA0DE, 0xC876, 0xA0DF, 0xC877, 0xA0E0, 0xC878, 0xC1B9, 0xC879, 0xA0E1, 0xC87A, 0xC1BA, 0xC87B, 0xA0E2, + 0xC87C, 0xA0E3, 0xC87D, 0xA0E4, 0xC87E, 0xA0E5, 0xC87F, 0xA0E6, 0xC880, 0xC1BB, 0xC881, 0xC1BC, 0xC882, 0xA0E7, 0xC883, 0xC1BD, + 0xC884, 0xA0E8, 0xC885, 0xC1BE, 0xC886, 0xC1BF, 0xC887, 0xC1C0, 0xC888, 0xA0E9, 0xC889, 0xA0EA, 0xC88A, 0xA0EB, 0xC88B, 0xC1C1, + 0xC88C, 0xC1C2, 0xC88D, 0xC1C3, 0xC88E, 0xA0EC, 0xC88F, 0xA0ED, 0xC890, 0xA0EE, 0xC891, 0xA0EF, 0xC892, 0xA0F0, 0xC893, 0xA0F1, + 0xC894, 0xC1C4, 0xC895, 0xA0F2, 0xC896, 0xA0F3, 0xC897, 0xA0F4, 0xC898, 0xA0F5, 0xC899, 0xA0F6, 0xC89A, 0xA0F7, 0xC89B, 0xA0F8, + 0xC89C, 0xA0F9, 0xC89D, 0xC1C5, 0xC89E, 0xA0FA, 0xC89F, 0xC1C6, 0xC8A0, 0xA0FB, 0xC8A1, 0xC1C7, 0xC8A2, 0xA0FC, 0xC8A3, 0xA0FD, + 0xC8A4, 0xA0FE, 0xC8A5, 0xA141, 0xC8A6, 0xA142, 0xC8A7, 0xA143, 0xC8A8, 0xC1C8, 0xC8A9, 0xA144, 0xC8AA, 0xA145, 0xC8AB, 0xA146, + 0xC8AC, 0xA147, 0xC8AD, 0xA148, 0xC8AE, 0xA149, 0xC8AF, 0xA14A, 0xC8B0, 0xA14B, 0xC8B1, 0xA14C, 0xC8B2, 0xA14D, 0xC8B3, 0xA14E, + 0xC8B4, 0xA14F, 0xC8B5, 0xA150, 0xC8B6, 0xA151, 0xC8B7, 0xA152, 0xC8B8, 0xA153, 0xC8B9, 0xA154, 0xC8BA, 0xA155, 0xC8BB, 0xA156, + 0xC8BC, 0xC1C9, 0xC8BD, 0xC1CA, 0xC8BE, 0xA157, 0xC8BF, 0xA158, 0xC8C0, 0xA159, 0xC8C1, 0xA15A, 0xC8C2, 0xA161, 0xC8C3, 0xA162, + 0xC8C4, 0xC1CB, 0xC8C5, 0xA163, 0xC8C6, 0xA164, 0xC8C7, 0xA165, 0xC8C8, 0xC1CC, 0xC8C9, 0xA166, 0xC8CA, 0xA167, 0xC8CB, 0xA168, + 0xC8CC, 0xC1CD, 0xC8CD, 0xA169, 0xC8CE, 0xA16A, 0xC8CF, 0xA16B, 0xC8D0, 0xA16C, 0xC8D1, 0xA16D, 0xC8D2, 0xA16E, 0xC8D3, 0xA16F, + 0xC8D4, 0xC1CE, 0xC8D5, 0xC1CF, 0xC8D6, 0xA170, 0xC8D7, 0xC1D0, 0xC8D8, 0xA171, 0xC8D9, 0xC1D1, 0xC8DA, 0xA172, 0xC8DB, 0xA173, + 0xC8DC, 0xA174, 0xC8DD, 0xA175, 0xC8DE, 0xA176, 0xC8DF, 0xA177, 0xC8E0, 0xC1D2, 0xC8E1, 0xC1D3, 0xC8E2, 0xA178, 0xC8E3, 0xA179, + 0xC8E4, 0xC1D4, 0xC8E5, 0xA17A, 0xC8E6, 0xA181, 0xC8E7, 0xA182, 0xC8E8, 0xA183, 0xC8E9, 0xA184, 0xC8EA, 0xA185, 0xC8EB, 0xA186, + 0xC8EC, 0xA187, 0xC8ED, 0xA188, 0xC8EE, 0xA189, 0xC8EF, 0xA18A, 0xC8F0, 0xA18B, 0xC8F1, 0xA18C, 0xC8F2, 0xA18D, 0xC8F3, 0xA18E, + 0xC8F4, 0xA18F, 0xC8F5, 0xC1D5, 0xC8F6, 0xA190, 0xC8F7, 0xA191, 0xC8F8, 0xA192, 0xC8F9, 0xA193, 0xC8FA, 0xA194, 0xC8FB, 0xA195, + 0xC8FC, 0xC1D6, 0xC8FD, 0xC1D7, 0xC8FE, 0xA196, 0xC8FF, 0xA197, 0xC900, 0xC1D8, 0xC901, 0xA198, 0xC902, 0xA199, 0xC903, 0xA19A, + 0xC904, 0xC1D9, 0xC905, 0xC1DA, 0xC906, 0xC1DB, 0xC907, 0xA19B, 0xC908, 0xA19C, 0xC909, 0xA19D, 0xC90A, 0xA19E, 0xC90B, 0xA19F, + 0xC90C, 0xC1DC, 0xC90D, 0xC1DD, 0xC90E, 0xA1A0, 0xC90F, 0xC1DE, 0xC910, 0xA241, 0xC911, 0xC1DF, 0xC912, 0xA242, 0xC913, 0xA243, + 0xC914, 0xA244, 0xC915, 0xA245, 0xC916, 0xA246, 0xC917, 0xA247, 0xC918, 0xC1E0, 0xC919, 0xA248, 0xC91A, 0xA249, 0xC91B, 0xA24A, + 0xC91C, 0xA24B, 0xC91D, 0xA24C, 0xC91E, 0xA24D, 0xC91F, 0xA24E, 0xC920, 0xA24F, 0xC921, 0xA250, 0xC922, 0xA251, 0xC923, 0xA252, + 0xC924, 0xA253, 0xC925, 0xA254, 0xC926, 0xA255, 0xC927, 0xA256, 0xC928, 0xA257, 0xC929, 0xA258, 0xC92A, 0xA259, 0xC92B, 0xA25A, + 0xC92C, 0xC1E1, 0xC92D, 0xA261, 0xC92E, 0xA262, 0xC92F, 0xA263, 0xC930, 0xA264, 0xC931, 0xA265, 0xC932, 0xA266, 0xC933, 0xA267, + 0xC934, 0xC1E2, 0xC935, 0xA268, 0xC936, 0xA269, 0xC937, 0xA26A, 0xC938, 0xA26B, 0xC939, 0xA26C, 0xC93A, 0xA26D, 0xC93B, 0xA26E, + 0xC93C, 0xA26F, 0xC93D, 0xA270, 0xC93E, 0xA271, 0xC93F, 0xA272, 0xC940, 0xA273, 0xC941, 0xA274, 0xC942, 0xA275, 0xC943, 0xA276, + 0xC944, 0xA277, 0xC945, 0xA278, 0xC946, 0xA279, 0xC947, 0xA27A, 0xC948, 0xA281, 0xC949, 0xA282, 0xC94A, 0xA283, 0xC94B, 0xA284, + 0xC94C, 0xA285, 0xC94D, 0xA286, 0xC94E, 0xA287, 0xC94F, 0xA288, 0xC950, 0xC1E3, 0xC951, 0xC1E4, 0xC952, 0xA289, 0xC953, 0xA28A, + 0xC954, 0xC1E5, 0xC955, 0xA28B, 0xC956, 0xA28C, 0xC957, 0xA28D, 0xC958, 0xC1E6, 0xC959, 0xA28E, 0xC95A, 0xA28F, 0xC95B, 0xA290, + 0xC95C, 0xA291, 0xC95D, 0xA292, 0xC95E, 0xA293, 0xC95F, 0xA294, 0xC960, 0xC1E7, 0xC961, 0xC1E8, 0xC962, 0xA295, 0xC963, 0xC1E9, + 0xC964, 0xA296, 0xC965, 0xA297, 0xC966, 0xA298, 0xC967, 0xA299, 0xC968, 0xA29A, 0xC969, 0xA29B, 0xC96A, 0xA29C, 0xC96B, 0xA29D, + 0xC96C, 0xC1EA, 0xC96D, 0xA29E, 0xC96E, 0xA29F, 0xC96F, 0xA2A0, 0xC970, 0xC1EB, 0xC971, 0xA341, 0xC972, 0xA342, 0xC973, 0xA343, + 0xC974, 0xC1EC, 0xC975, 0xA344, 0xC976, 0xA345, 0xC977, 0xA346, 0xC978, 0xA347, 0xC979, 0xA348, 0xC97A, 0xA349, 0xC97B, 0xA34A, + 0xC97C, 0xC1ED, 0xC97D, 0xA34B, 0xC97E, 0xA34C, 0xC97F, 0xA34D, 0xC980, 0xA34E, 0xC981, 0xA34F, 0xC982, 0xA350, 0xC983, 0xA351, + 0xC984, 0xA352, 0xC985, 0xA353, 0xC986, 0xA354, 0xC987, 0xA355, 0xC988, 0xC1EE, 0xC989, 0xC1EF, 0xC98A, 0xA356, 0xC98B, 0xA357, + 0xC98C, 0xC1F0, 0xC98D, 0xA358, 0xC98E, 0xA359, 0xC98F, 0xA35A, 0xC990, 0xC1F1, 0xC991, 0xA361, 0xC992, 0xA362, 0xC993, 0xA363, + 0xC994, 0xA364, 0xC995, 0xA365, 0xC996, 0xA366, 0xC997, 0xA367, 0xC998, 0xC1F2, 0xC999, 0xC1F3, 0xC99A, 0xA368, 0xC99B, 0xC1F4, + 0xC99C, 0xA369, 0xC99D, 0xC1F5, 0xC99E, 0xA36A, 0xC99F, 0xA36B, 0xC9A0, 0xA36C, 0xC9A1, 0xA36D, 0xC9A2, 0xA36E, 0xC9A3, 0xA36F, + 0xC9A4, 0xA370, 0xC9A5, 0xA371, 0xC9A6, 0xA372, 0xC9A7, 0xA373, 0xC9A8, 0xA374, 0xC9A9, 0xA375, 0xC9AA, 0xA376, 0xC9AB, 0xA377, + 0xC9AC, 0xA378, 0xC9AD, 0xA379, 0xC9AE, 0xA37A, 0xC9AF, 0xA381, 0xC9B0, 0xA382, 0xC9B1, 0xA383, 0xC9B2, 0xA384, 0xC9B3, 0xA385, + 0xC9B4, 0xA386, 0xC9B5, 0xA387, 0xC9B6, 0xA388, 0xC9B7, 0xA389, 0xC9B8, 0xA38A, 0xC9B9, 0xA38B, 0xC9BA, 0xA38C, 0xC9BB, 0xA38D, + 0xC9BC, 0xA38E, 0xC9BD, 0xA38F, 0xC9BE, 0xA390, 0xC9BF, 0xA391, 0xC9C0, 0xC1F6, 0xC9C1, 0xC1F7, 0xC9C2, 0xA392, 0xC9C3, 0xA393, + 0xC9C4, 0xC1F8, 0xC9C5, 0xA394, 0xC9C6, 0xA395, 0xC9C7, 0xC1F9, 0xC9C8, 0xC1FA, 0xC9C9, 0xA396, 0xC9CA, 0xC1FB, 0xC9CB, 0xA397, + 0xC9CC, 0xA398, 0xC9CD, 0xA399, 0xC9CE, 0xA39A, 0xC9CF, 0xA39B, 0xC9D0, 0xC1FC, 0xC9D1, 0xC1FD, 0xC9D2, 0xA39C, 0xC9D3, 0xC1FE, + 0xC9D4, 0xA39D, 0xC9D5, 0xC2A1, 0xC9D6, 0xC2A2, 0xC9D7, 0xA39E, 0xC9D8, 0xA39F, 0xC9D9, 0xC2A3, 0xC9DA, 0xC2A4, 0xC9DB, 0xA3A0, + 0xC9DC, 0xC2A5, 0xC9DD, 0xC2A6, 0xC9DE, 0xA441, 0xC9DF, 0xA442, 0xC9E0, 0xC2A7, 0xC9E1, 0xA443, 0xC9E2, 0xC2A8, 0xC9E3, 0xA444, + 0xC9E4, 0xC2A9, 0xC9E5, 0xA445, 0xC9E6, 0xA446, 0xC9E7, 0xC2AA, 0xC9E8, 0xA447, 0xC9E9, 0xA448, 0xC9EA, 0xA449, 0xC9EB, 0xA44A, + 0xC9EC, 0xC2AB, 0xC9ED, 0xC2AC, 0xC9EE, 0xA44B, 0xC9EF, 0xC2AD, 0xC9F0, 0xC2AE, 0xC9F1, 0xC2AF, 0xC9F2, 0xA44C, 0xC9F3, 0xA44D, + 0xC9F4, 0xA44E, 0xC9F5, 0xA44F, 0xC9F6, 0xA450, 0xC9F7, 0xA451, 0xC9F8, 0xC2B0, 0xC9F9, 0xC2B1, 0xC9FA, 0xA452, 0xC9FB, 0xA453, + 0xC9FC, 0xC2B2, 0xC9FD, 0xA454, 0xC9FE, 0xA455, 0xC9FF, 0xA456, 0xCA00, 0xC2B3, 0xCA01, 0xA457, 0xCA02, 0xA458, 0xCA03, 0xA459, + 0xCA04, 0xA45A, 0xCA05, 0xA461, 0xCA06, 0xA462, 0xCA07, 0xA463, 0xCA08, 0xC2B4, 0xCA09, 0xC2B5, 0xCA0A, 0xA464, 0xCA0B, 0xC2B6, + 0xCA0C, 0xC2B7, 0xCA0D, 0xC2B8, 0xCA0E, 0xA465, 0xCA0F, 0xA466, 0xCA10, 0xA467, 0xCA11, 0xA468, 0xCA12, 0xA469, 0xCA13, 0xA46A, + 0xCA14, 0xC2B9, 0xCA15, 0xA46B, 0xCA16, 0xA46C, 0xCA17, 0xA46D, 0xCA18, 0xC2BA, 0xCA19, 0xA46E, 0xCA1A, 0xA46F, 0xCA1B, 0xA470, + 0xCA1C, 0xA471, 0xCA1D, 0xA472, 0xCA1E, 0xA473, 0xCA1F, 0xA474, 0xCA20, 0xA475, 0xCA21, 0xA476, 0xCA22, 0xA477, 0xCA23, 0xA478, + 0xCA24, 0xA479, 0xCA25, 0xA47A, 0xCA26, 0xA481, 0xCA27, 0xA482, 0xCA28, 0xA483, 0xCA29, 0xC2BB, 0xCA2A, 0xA484, 0xCA2B, 0xA485, + 0xCA2C, 0xA486, 0xCA2D, 0xA487, 0xCA2E, 0xA488, 0xCA2F, 0xA489, 0xCA30, 0xA48A, 0xCA31, 0xA48B, 0xCA32, 0xA48C, 0xCA33, 0xA48D, + 0xCA34, 0xA48E, 0xCA35, 0xA48F, 0xCA36, 0xA490, 0xCA37, 0xA491, 0xCA38, 0xA492, 0xCA39, 0xA493, 0xCA3A, 0xA494, 0xCA3B, 0xA495, + 0xCA3C, 0xA496, 0xCA3D, 0xA497, 0xCA3E, 0xA498, 0xCA3F, 0xA499, 0xCA40, 0xA49A, 0xCA41, 0xA49B, 0xCA42, 0xA49C, 0xCA43, 0xA49D, + 0xCA44, 0xA49E, 0xCA45, 0xA49F, 0xCA46, 0xA4A0, 0xCA47, 0xA541, 0xCA48, 0xA542, 0xCA49, 0xA543, 0xCA4A, 0xA544, 0xCA4B, 0xA545, + 0xCA4C, 0xC2BC, 0xCA4D, 0xC2BD, 0xCA4E, 0xA546, 0xCA4F, 0xA547, 0xCA50, 0xC2BE, 0xCA51, 0xA548, 0xCA52, 0xA549, 0xCA53, 0xA54A, + 0xCA54, 0xC2BF, 0xCA55, 0xA54B, 0xCA56, 0xA54C, 0xCA57, 0xA54D, 0xCA58, 0xA54E, 0xCA59, 0xA54F, 0xCA5A, 0xA550, 0xCA5B, 0xA551, + 0xCA5C, 0xC2C0, 0xCA5D, 0xC2C1, 0xCA5E, 0xA552, 0xCA5F, 0xC2C2, 0xCA60, 0xC2C3, 0xCA61, 0xC2C4, 0xCA62, 0xA553, 0xCA63, 0xA554, + 0xCA64, 0xA555, 0xCA65, 0xA556, 0xCA66, 0xA557, 0xCA67, 0xA558, 0xCA68, 0xC2C5, 0xCA69, 0xA559, 0xCA6A, 0xA55A, 0xCA6B, 0xA561, + 0xCA6C, 0xA562, 0xCA6D, 0xA563, 0xCA6E, 0xA564, 0xCA6F, 0xA565, 0xCA70, 0xA566, 0xCA71, 0xA567, 0xCA72, 0xA568, 0xCA73, 0xA569, + 0xCA74, 0xA56A, 0xCA75, 0xA56B, 0xCA76, 0xA56C, 0xCA77, 0xA56D, 0xCA78, 0xA56E, 0xCA79, 0xA56F, 0xCA7A, 0xA570, 0xCA7B, 0xA571, + 0xCA7C, 0xA572, 0xCA7D, 0xC2C6, 0xCA7E, 0xA573, 0xCA7F, 0xA574, 0xCA80, 0xA575, 0xCA81, 0xA576, 0xCA82, 0xA577, 0xCA83, 0xA578, + 0xCA84, 0xC2C7, 0xCA85, 0xA579, 0xCA86, 0xA57A, 0xCA87, 0xA581, 0xCA88, 0xA582, 0xCA89, 0xA583, 0xCA8A, 0xA584, 0xCA8B, 0xA585, + 0xCA8C, 0xA586, 0xCA8D, 0xA587, 0xCA8E, 0xA588, 0xCA8F, 0xA589, 0xCA90, 0xA58A, 0xCA91, 0xA58B, 0xCA92, 0xA58C, 0xCA93, 0xA58D, + 0xCA94, 0xA58E, 0xCA95, 0xA58F, 0xCA96, 0xA590, 0xCA97, 0xA591, 0xCA98, 0xC2C8, 0xCA99, 0xA592, 0xCA9A, 0xA593, 0xCA9B, 0xA594, + 0xCA9C, 0xA595, 0xCA9D, 0xA596, 0xCA9E, 0xA597, 0xCA9F, 0xA598, 0xCAA0, 0xA599, 0xCAA1, 0xA59A, 0xCAA2, 0xA59B, 0xCAA3, 0xA59C, + 0xCAA4, 0xA59D, 0xCAA5, 0xA59E, 0xCAA6, 0xA59F, 0xCAA7, 0xA5A0, 0xCAA8, 0xA641, 0xCAA9, 0xA642, 0xCAAA, 0xA643, 0xCAAB, 0xA644, + 0xCAAC, 0xA645, 0xCAAD, 0xA646, 0xCAAE, 0xA647, 0xCAAF, 0xA648, 0xCAB0, 0xA649, 0xCAB1, 0xA64A, 0xCAB2, 0xA64B, 0xCAB3, 0xA64C, + 0xCAB4, 0xA64D, 0xCAB5, 0xA64E, 0xCAB6, 0xA64F, 0xCAB7, 0xA650, 0xCAB8, 0xA651, 0xCAB9, 0xA652, 0xCABA, 0xA653, 0xCABB, 0xA654, + 0xCABC, 0xC2C9, 0xCABD, 0xC2CA, 0xCABE, 0xA655, 0xCABF, 0xA656, 0xCAC0, 0xC2CB, 0xCAC1, 0xA657, 0xCAC2, 0xA658, 0xCAC3, 0xA659, + 0xCAC4, 0xC2CC, 0xCAC5, 0xA65A, 0xCAC6, 0xA661, 0xCAC7, 0xA662, 0xCAC8, 0xA663, 0xCAC9, 0xA664, 0xCACA, 0xA665, 0xCACB, 0xA666, + 0xCACC, 0xC2CD, 0xCACD, 0xC2CE, 0xCACE, 0xA667, 0xCACF, 0xC2CF, 0xCAD0, 0xA668, 0xCAD1, 0xC2D0, 0xCAD2, 0xA669, 0xCAD3, 0xC2D1, + 0xCAD4, 0xA66A, 0xCAD5, 0xA66B, 0xCAD6, 0xA66C, 0xCAD7, 0xA66D, 0xCAD8, 0xC2D2, 0xCAD9, 0xC2D3, 0xCADA, 0xA66E, 0xCADB, 0xA66F, + 0xCADC, 0xA670, 0xCADD, 0xA671, 0xCADE, 0xA672, 0xCADF, 0xA673, 0xCAE0, 0xC2D4, 0xCAE1, 0xA674, 0xCAE2, 0xA675, 0xCAE3, 0xA676, + 0xCAE4, 0xA677, 0xCAE5, 0xA678, 0xCAE6, 0xA679, 0xCAE7, 0xA67A, 0xCAE8, 0xA681, 0xCAE9, 0xA682, 0xCAEA, 0xA683, 0xCAEB, 0xA684, + 0xCAEC, 0xC2D5, 0xCAED, 0xA685, 0xCAEE, 0xA686, 0xCAEF, 0xA687, 0xCAF0, 0xA688, 0xCAF1, 0xA689, 0xCAF2, 0xA68A, 0xCAF3, 0xA68B, + 0xCAF4, 0xC2D6, 0xCAF5, 0xA68C, 0xCAF6, 0xA68D, 0xCAF7, 0xA68E, 0xCAF8, 0xA68F, 0xCAF9, 0xA690, 0xCAFA, 0xA691, 0xCAFB, 0xA692, + 0xCAFC, 0xA693, 0xCAFD, 0xA694, 0xCAFE, 0xA695, 0xCAFF, 0xA696, 0xCB00, 0xA697, 0xCB01, 0xA698, 0xCB02, 0xA699, 0xCB03, 0xA69A, + 0xCB04, 0xA69B, 0xCB05, 0xA69C, 0xCB06, 0xA69D, 0xCB07, 0xA69E, 0xCB08, 0xC2D7, 0xCB09, 0xA69F, 0xCB0A, 0xA6A0, 0xCB0B, 0xA741, + 0xCB0C, 0xA742, 0xCB0D, 0xA743, 0xCB0E, 0xA744, 0xCB0F, 0xA745, 0xCB10, 0xC2D8, 0xCB11, 0xA746, 0xCB12, 0xA747, 0xCB13, 0xA748, + 0xCB14, 0xC2D9, 0xCB15, 0xA749, 0xCB16, 0xA74A, 0xCB17, 0xA74B, 0xCB18, 0xC2DA, 0xCB19, 0xA74C, 0xCB1A, 0xA74D, 0xCB1B, 0xA74E, + 0xCB1C, 0xA74F, 0xCB1D, 0xA750, 0xCB1E, 0xA751, 0xCB1F, 0xA752, 0xCB20, 0xC2DB, 0xCB21, 0xC2DC, 0xCB22, 0xA753, 0xCB23, 0xA754, + 0xCB24, 0xA755, 0xCB25, 0xA756, 0xCB26, 0xA757, 0xCB27, 0xA758, 0xCB28, 0xA759, 0xCB29, 0xA75A, 0xCB2A, 0xA761, 0xCB2B, 0xA762, + 0xCB2C, 0xA763, 0xCB2D, 0xA764, 0xCB2E, 0xA765, 0xCB2F, 0xA766, 0xCB30, 0xA767, 0xCB31, 0xA768, 0xCB32, 0xA769, 0xCB33, 0xA76A, + 0xCB34, 0xA76B, 0xCB35, 0xA76C, 0xCB36, 0xA76D, 0xCB37, 0xA76E, 0xCB38, 0xA76F, 0xCB39, 0xA770, 0xCB3A, 0xA771, 0xCB3B, 0xA772, + 0xCB3C, 0xA773, 0xCB3D, 0xA774, 0xCB3E, 0xA775, 0xCB3F, 0xA776, 0xCB40, 0xA777, 0xCB41, 0xC2DD, 0xCB42, 0xA778, 0xCB43, 0xA779, + 0xCB44, 0xA77A, 0xCB45, 0xA781, 0xCB46, 0xA782, 0xCB47, 0xA783, 0xCB48, 0xC2DE, 0xCB49, 0xC2DF, 0xCB4A, 0xA784, 0xCB4B, 0xA785, + 0xCB4C, 0xC2E0, 0xCB4D, 0xA786, 0xCB4E, 0xA787, 0xCB4F, 0xA788, 0xCB50, 0xC2E1, 0xCB51, 0xA789, 0xCB52, 0xA78A, 0xCB53, 0xA78B, + 0xCB54, 0xA78C, 0xCB55, 0xA78D, 0xCB56, 0xA78E, 0xCB57, 0xA78F, 0xCB58, 0xC2E2, 0xCB59, 0xC2E3, 0xCB5A, 0xA790, 0xCB5B, 0xA791, + 0xCB5C, 0xA792, 0xCB5D, 0xC2E4, 0xCB5E, 0xA793, 0xCB5F, 0xA794, 0xCB60, 0xA795, 0xCB61, 0xA796, 0xCB62, 0xA797, 0xCB63, 0xA798, + 0xCB64, 0xC2E5, 0xCB65, 0xA799, 0xCB66, 0xA79A, 0xCB67, 0xA79B, 0xCB68, 0xA79C, 0xCB69, 0xA79D, 0xCB6A, 0xA79E, 0xCB6B, 0xA79F, + 0xCB6C, 0xA7A0, 0xCB6D, 0xA841, 0xCB6E, 0xA842, 0xCB6F, 0xA843, 0xCB70, 0xA844, 0xCB71, 0xA845, 0xCB72, 0xA846, 0xCB73, 0xA847, + 0xCB74, 0xA848, 0xCB75, 0xA849, 0xCB76, 0xA84A, 0xCB77, 0xA84B, 0xCB78, 0xC2E6, 0xCB79, 0xC2E7, 0xCB7A, 0xA84C, 0xCB7B, 0xA84D, + 0xCB7C, 0xA84E, 0xCB7D, 0xA84F, 0xCB7E, 0xA850, 0xCB7F, 0xA851, 0xCB80, 0xA852, 0xCB81, 0xA853, 0xCB82, 0xA854, 0xCB83, 0xA855, + 0xCB84, 0xA856, 0xCB85, 0xA857, 0xCB86, 0xA858, 0xCB87, 0xA859, 0xCB88, 0xA85A, 0xCB89, 0xA861, 0xCB8A, 0xA862, 0xCB8B, 0xA863, + 0xCB8C, 0xA864, 0xCB8D, 0xA865, 0xCB8E, 0xA866, 0xCB8F, 0xA867, 0xCB90, 0xA868, 0xCB91, 0xA869, 0xCB92, 0xA86A, 0xCB93, 0xA86B, + 0xCB94, 0xA86C, 0xCB95, 0xA86D, 0xCB96, 0xA86E, 0xCB97, 0xA86F, 0xCB98, 0xA870, 0xCB99, 0xA871, 0xCB9A, 0xA872, 0xCB9B, 0xA873, + 0xCB9C, 0xC2E8, 0xCB9D, 0xA874, 0xCB9E, 0xA875, 0xCB9F, 0xA876, 0xCBA0, 0xA877, 0xCBA1, 0xA878, 0xCBA2, 0xA879, 0xCBA3, 0xA87A, + 0xCBA4, 0xA881, 0xCBA5, 0xA882, 0xCBA6, 0xA883, 0xCBA7, 0xA884, 0xCBA8, 0xA885, 0xCBA9, 0xA886, 0xCBAA, 0xA887, 0xCBAB, 0xA888, + 0xCBAC, 0xA889, 0xCBAD, 0xA88A, 0xCBAE, 0xA88B, 0xCBAF, 0xA88C, 0xCBB0, 0xA88D, 0xCBB1, 0xA88E, 0xCBB2, 0xA88F, 0xCBB3, 0xA890, + 0xCBB4, 0xA891, 0xCBB5, 0xA892, 0xCBB6, 0xA893, 0xCBB7, 0xA894, 0xCBB8, 0xC2E9, 0xCBB9, 0xA895, 0xCBBA, 0xA896, 0xCBBB, 0xA897, + 0xCBBC, 0xA898, 0xCBBD, 0xA899, 0xCBBE, 0xA89A, 0xCBBF, 0xA89B, 0xCBC0, 0xA89C, 0xCBC1, 0xA89D, 0xCBC2, 0xA89E, 0xCBC3, 0xA89F, + 0xCBC4, 0xA8A0, 0xCBC5, 0xA941, 0xCBC6, 0xA942, 0xCBC7, 0xA943, 0xCBC8, 0xA944, 0xCBC9, 0xA945, 0xCBCA, 0xA946, 0xCBCB, 0xA947, + 0xCBCC, 0xA948, 0xCBCD, 0xA949, 0xCBCE, 0xA94A, 0xCBCF, 0xA94B, 0xCBD0, 0xA94C, 0xCBD1, 0xA94D, 0xCBD2, 0xA94E, 0xCBD3, 0xA94F, + 0xCBD4, 0xC2EA, 0xCBD5, 0xA950, 0xCBD6, 0xA951, 0xCBD7, 0xA952, 0xCBD8, 0xA953, 0xCBD9, 0xA954, 0xCBDA, 0xA955, 0xCBDB, 0xA956, + 0xCBDC, 0xA957, 0xCBDD, 0xA958, 0xCBDE, 0xA959, 0xCBDF, 0xA95A, 0xCBE0, 0xA961, 0xCBE1, 0xA962, 0xCBE2, 0xA963, 0xCBE3, 0xA964, + 0xCBE4, 0xC2EB, 0xCBE5, 0xA965, 0xCBE6, 0xA966, 0xCBE7, 0xC2EC, 0xCBE8, 0xA967, 0xCBE9, 0xC2ED, 0xCBEA, 0xA968, 0xCBEB, 0xA969, + 0xCBEC, 0xA96A, 0xCBED, 0xA96B, 0xCBEE, 0xA96C, 0xCBEF, 0xA96D, 0xCBF0, 0xA96E, 0xCBF1, 0xA96F, 0xCBF2, 0xA970, 0xCBF3, 0xA971, + 0xCBF4, 0xA972, 0xCBF5, 0xA973, 0xCBF6, 0xA974, 0xCBF7, 0xA975, 0xCBF8, 0xA976, 0xCBF9, 0xA977, 0xCBFA, 0xA978, 0xCBFB, 0xA979, + 0xCBFC, 0xA97A, 0xCBFD, 0xA981, 0xCBFE, 0xA982, 0xCBFF, 0xA983, 0xCC00, 0xA984, 0xCC01, 0xA985, 0xCC02, 0xA986, 0xCC03, 0xA987, + 0xCC04, 0xA988, 0xCC05, 0xA989, 0xCC06, 0xA98A, 0xCC07, 0xA98B, 0xCC08, 0xA98C, 0xCC09, 0xA98D, 0xCC0A, 0xA98E, 0xCC0B, 0xA98F, + 0xCC0C, 0xC2EE, 0xCC0D, 0xC2EF, 0xCC0E, 0xA990, 0xCC0F, 0xA991, 0xCC10, 0xC2F0, 0xCC11, 0xA992, 0xCC12, 0xA993, 0xCC13, 0xA994, + 0xCC14, 0xC2F1, 0xCC15, 0xA995, 0xCC16, 0xA996, 0xCC17, 0xA997, 0xCC18, 0xA998, 0xCC19, 0xA999, 0xCC1A, 0xA99A, 0xCC1B, 0xA99B, + 0xCC1C, 0xC2F2, 0xCC1D, 0xC2F3, 0xCC1E, 0xA99C, 0xCC1F, 0xA99D, 0xCC20, 0xA99E, 0xCC21, 0xC2F4, 0xCC22, 0xC2F5, 0xCC23, 0xA99F, + 0xCC24, 0xA9A0, 0xCC25, 0xAA41, 0xCC26, 0xAA42, 0xCC27, 0xC2F6, 0xCC28, 0xC2F7, 0xCC29, 0xC2F8, 0xCC2A, 0xAA43, 0xCC2B, 0xAA44, + 0xCC2C, 0xC2F9, 0xCC2D, 0xAA45, 0xCC2E, 0xC2FA, 0xCC2F, 0xAA46, 0xCC30, 0xC2FB, 0xCC31, 0xAA47, 0xCC32, 0xAA48, 0xCC33, 0xAA49, + 0xCC34, 0xAA4A, 0xCC35, 0xAA4B, 0xCC36, 0xAA4C, 0xCC37, 0xAA4D, 0xCC38, 0xC2FC, 0xCC39, 0xC2FD, 0xCC3A, 0xAA4E, 0xCC3B, 0xC2FE, + 0xCC3C, 0xC3A1, 0xCC3D, 0xC3A2, 0xCC3E, 0xC3A3, 0xCC3F, 0xAA4F, 0xCC40, 0xAA50, 0xCC41, 0xAA51, 0xCC42, 0xAA52, 0xCC43, 0xAA53, + 0xCC44, 0xC3A4, 0xCC45, 0xC3A5, 0xCC46, 0xAA54, 0xCC47, 0xAA55, 0xCC48, 0xC3A6, 0xCC49, 0xAA56, 0xCC4A, 0xAA57, 0xCC4B, 0xAA58, + 0xCC4C, 0xC3A7, 0xCC4D, 0xAA59, 0xCC4E, 0xAA5A, 0xCC4F, 0xAA61, 0xCC50, 0xAA62, 0xCC51, 0xAA63, 0xCC52, 0xAA64, 0xCC53, 0xAA65, + 0xCC54, 0xC3A8, 0xCC55, 0xC3A9, 0xCC56, 0xAA66, 0xCC57, 0xC3AA, 0xCC58, 0xC3AB, 0xCC59, 0xC3AC, 0xCC5A, 0xAA67, 0xCC5B, 0xAA68, + 0xCC5C, 0xAA69, 0xCC5D, 0xAA6A, 0xCC5E, 0xAA6B, 0xCC5F, 0xAA6C, 0xCC60, 0xC3AD, 0xCC61, 0xAA6D, 0xCC62, 0xAA6E, 0xCC63, 0xAA6F, + 0xCC64, 0xC3AE, 0xCC65, 0xAA70, 0xCC66, 0xC3AF, 0xCC67, 0xAA71, 0xCC68, 0xC3B0, 0xCC69, 0xAA72, 0xCC6A, 0xAA73, 0xCC6B, 0xAA74, + 0xCC6C, 0xAA75, 0xCC6D, 0xAA76, 0xCC6E, 0xAA77, 0xCC6F, 0xAA78, 0xCC70, 0xC3B1, 0xCC71, 0xAA79, 0xCC72, 0xAA7A, 0xCC73, 0xAA81, + 0xCC74, 0xAA82, 0xCC75, 0xC3B2, 0xCC76, 0xAA83, 0xCC77, 0xAA84, 0xCC78, 0xAA85, 0xCC79, 0xAA86, 0xCC7A, 0xAA87, 0xCC7B, 0xAA88, + 0xCC7C, 0xAA89, 0xCC7D, 0xAA8A, 0xCC7E, 0xAA8B, 0xCC7F, 0xAA8C, 0xCC80, 0xAA8D, 0xCC81, 0xAA8E, 0xCC82, 0xAA8F, 0xCC83, 0xAA90, + 0xCC84, 0xAA91, 0xCC85, 0xAA92, 0xCC86, 0xAA93, 0xCC87, 0xAA94, 0xCC88, 0xAA95, 0xCC89, 0xAA96, 0xCC8A, 0xAA97, 0xCC8B, 0xAA98, + 0xCC8C, 0xAA99, 0xCC8D, 0xAA9A, 0xCC8E, 0xAA9B, 0xCC8F, 0xAA9C, 0xCC90, 0xAA9D, 0xCC91, 0xAA9E, 0xCC92, 0xAA9F, 0xCC93, 0xAAA0, + 0xCC94, 0xAB41, 0xCC95, 0xAB42, 0xCC96, 0xAB43, 0xCC97, 0xAB44, 0xCC98, 0xC3B3, 0xCC99, 0xC3B4, 0xCC9A, 0xAB45, 0xCC9B, 0xAB46, + 0xCC9C, 0xC3B5, 0xCC9D, 0xAB47, 0xCC9E, 0xAB48, 0xCC9F, 0xAB49, 0xCCA0, 0xC3B6, 0xCCA1, 0xAB4A, 0xCCA2, 0xAB4B, 0xCCA3, 0xAB4C, + 0xCCA4, 0xAB4D, 0xCCA5, 0xAB4E, 0xCCA6, 0xAB4F, 0xCCA7, 0xAB50, 0xCCA8, 0xC3B7, 0xCCA9, 0xC3B8, 0xCCAA, 0xAB51, 0xCCAB, 0xC3B9, + 0xCCAC, 0xC3BA, 0xCCAD, 0xC3BB, 0xCCAE, 0xAB52, 0xCCAF, 0xAB53, 0xCCB0, 0xAB54, 0xCCB1, 0xAB55, 0xCCB2, 0xAB56, 0xCCB3, 0xAB57, + 0xCCB4, 0xC3BC, 0xCCB5, 0xC3BD, 0xCCB6, 0xAB58, 0xCCB7, 0xAB59, 0xCCB8, 0xC3BE, 0xCCB9, 0xAB5A, 0xCCBA, 0xAB61, 0xCCBB, 0xAB62, + 0xCCBC, 0xC3BF, 0xCCBD, 0xAB63, 0xCCBE, 0xAB64, 0xCCBF, 0xAB65, 0xCCC0, 0xAB66, 0xCCC1, 0xAB67, 0xCCC2, 0xAB68, 0xCCC3, 0xAB69, + 0xCCC4, 0xC3C0, 0xCCC5, 0xC3C1, 0xCCC6, 0xAB6A, 0xCCC7, 0xC3C2, 0xCCC8, 0xAB6B, 0xCCC9, 0xC3C3, 0xCCCA, 0xAB6C, 0xCCCB, 0xAB6D, + 0xCCCC, 0xAB6E, 0xCCCD, 0xAB6F, 0xCCCE, 0xAB70, 0xCCCF, 0xAB71, 0xCCD0, 0xC3C4, 0xCCD1, 0xAB72, 0xCCD2, 0xAB73, 0xCCD3, 0xAB74, + 0xCCD4, 0xC3C5, 0xCCD5, 0xAB75, 0xCCD6, 0xAB76, 0xCCD7, 0xAB77, 0xCCD8, 0xAB78, 0xCCD9, 0xAB79, 0xCCDA, 0xAB7A, 0xCCDB, 0xAB81, + 0xCCDC, 0xAB82, 0xCCDD, 0xAB83, 0xCCDE, 0xAB84, 0xCCDF, 0xAB85, 0xCCE0, 0xAB86, 0xCCE1, 0xAB87, 0xCCE2, 0xAB88, 0xCCE3, 0xAB89, + 0xCCE4, 0xC3C6, 0xCCE5, 0xAB8A, 0xCCE6, 0xAB8B, 0xCCE7, 0xAB8C, 0xCCE8, 0xAB8D, 0xCCE9, 0xAB8E, 0xCCEA, 0xAB8F, 0xCCEB, 0xAB90, + 0xCCEC, 0xC3C7, 0xCCED, 0xAB91, 0xCCEE, 0xAB92, 0xCCEF, 0xAB93, 0xCCF0, 0xC3C8, 0xCCF1, 0xAB94, 0xCCF2, 0xAB95, 0xCCF3, 0xAB96, + 0xCCF4, 0xAB97, 0xCCF5, 0xAB98, 0xCCF6, 0xAB99, 0xCCF7, 0xAB9A, 0xCCF8, 0xAB9B, 0xCCF9, 0xAB9C, 0xCCFA, 0xAB9D, 0xCCFB, 0xAB9E, + 0xCCFC, 0xAB9F, 0xCCFD, 0xABA0, 0xCCFE, 0xAC41, 0xCCFF, 0xAC42, 0xCD00, 0xAC43, 0xCD01, 0xC3C9, 0xCD02, 0xAC44, 0xCD03, 0xAC45, + 0xCD04, 0xAC46, 0xCD05, 0xAC47, 0xCD06, 0xAC48, 0xCD07, 0xAC49, 0xCD08, 0xC3CA, 0xCD09, 0xC3CB, 0xCD0A, 0xAC4A, 0xCD0B, 0xAC4B, + 0xCD0C, 0xC3CC, 0xCD0D, 0xAC4C, 0xCD0E, 0xAC4D, 0xCD0F, 0xAC4E, 0xCD10, 0xC3CD, 0xCD11, 0xAC4F, 0xCD12, 0xAC50, 0xCD13, 0xAC51, + 0xCD14, 0xAC52, 0xCD15, 0xAC53, 0xCD16, 0xAC54, 0xCD17, 0xAC55, 0xCD18, 0xC3CE, 0xCD19, 0xC3CF, 0xCD1A, 0xAC56, 0xCD1B, 0xC3D0, + 0xCD1C, 0xAC57, 0xCD1D, 0xC3D1, 0xCD1E, 0xAC58, 0xCD1F, 0xAC59, 0xCD20, 0xAC5A, 0xCD21, 0xAC61, 0xCD22, 0xAC62, 0xCD23, 0xAC63, + 0xCD24, 0xC3D2, 0xCD25, 0xAC64, 0xCD26, 0xAC65, 0xCD27, 0xAC66, 0xCD28, 0xC3D3, 0xCD29, 0xAC67, 0xCD2A, 0xAC68, 0xCD2B, 0xAC69, + 0xCD2C, 0xC3D4, 0xCD2D, 0xAC6A, 0xCD2E, 0xAC6B, 0xCD2F, 0xAC6C, 0xCD30, 0xAC6D, 0xCD31, 0xAC6E, 0xCD32, 0xAC6F, 0xCD33, 0xAC70, + 0xCD34, 0xAC71, 0xCD35, 0xAC72, 0xCD36, 0xAC73, 0xCD37, 0xAC74, 0xCD38, 0xAC75, 0xCD39, 0xC3D5, 0xCD3A, 0xAC76, 0xCD3B, 0xAC77, + 0xCD3C, 0xAC78, 0xCD3D, 0xAC79, 0xCD3E, 0xAC7A, 0xCD3F, 0xAC81, 0xCD40, 0xAC82, 0xCD41, 0xAC83, 0xCD42, 0xAC84, 0xCD43, 0xAC85, + 0xCD44, 0xAC86, 0xCD45, 0xAC87, 0xCD46, 0xAC88, 0xCD47, 0xAC89, 0xCD48, 0xAC8A, 0xCD49, 0xAC8B, 0xCD4A, 0xAC8C, 0xCD4B, 0xAC8D, + 0xCD4C, 0xAC8E, 0xCD4D, 0xAC8F, 0xCD4E, 0xAC90, 0xCD4F, 0xAC91, 0xCD50, 0xAC92, 0xCD51, 0xAC93, 0xCD52, 0xAC94, 0xCD53, 0xAC95, + 0xCD54, 0xAC96, 0xCD55, 0xAC97, 0xCD56, 0xAC98, 0xCD57, 0xAC99, 0xCD58, 0xAC9A, 0xCD59, 0xAC9B, 0xCD5A, 0xAC9C, 0xCD5B, 0xAC9D, + 0xCD5C, 0xC3D6, 0xCD5D, 0xAC9E, 0xCD5E, 0xAC9F, 0xCD5F, 0xACA0, 0xCD60, 0xC3D7, 0xCD61, 0xAD41, 0xCD62, 0xAD42, 0xCD63, 0xAD43, + 0xCD64, 0xC3D8, 0xCD65, 0xAD44, 0xCD66, 0xAD45, 0xCD67, 0xAD46, 0xCD68, 0xAD47, 0xCD69, 0xAD48, 0xCD6A, 0xAD49, 0xCD6B, 0xAD4A, + 0xCD6C, 0xC3D9, 0xCD6D, 0xC3DA, 0xCD6E, 0xAD4B, 0xCD6F, 0xC3DB, 0xCD70, 0xAD4C, 0xCD71, 0xC3DC, 0xCD72, 0xAD4D, 0xCD73, 0xAD4E, + 0xCD74, 0xAD4F, 0xCD75, 0xAD50, 0xCD76, 0xAD51, 0xCD77, 0xAD52, 0xCD78, 0xC3DD, 0xCD79, 0xAD53, 0xCD7A, 0xAD54, 0xCD7B, 0xAD55, + 0xCD7C, 0xAD56, 0xCD7D, 0xAD57, 0xCD7E, 0xAD58, 0xCD7F, 0xAD59, 0xCD80, 0xAD5A, 0xCD81, 0xAD61, 0xCD82, 0xAD62, 0xCD83, 0xAD63, + 0xCD84, 0xAD64, 0xCD85, 0xAD65, 0xCD86, 0xAD66, 0xCD87, 0xAD67, 0xCD88, 0xC3DE, 0xCD89, 0xAD68, 0xCD8A, 0xAD69, 0xCD8B, 0xAD6A, + 0xCD8C, 0xAD6B, 0xCD8D, 0xAD6C, 0xCD8E, 0xAD6D, 0xCD8F, 0xAD6E, 0xCD90, 0xAD6F, 0xCD91, 0xAD70, 0xCD92, 0xAD71, 0xCD93, 0xAD72, + 0xCD94, 0xC3DF, 0xCD95, 0xC3E0, 0xCD96, 0xAD73, 0xCD97, 0xAD74, 0xCD98, 0xC3E1, 0xCD99, 0xAD75, 0xCD9A, 0xAD76, 0xCD9B, 0xAD77, + 0xCD9C, 0xC3E2, 0xCD9D, 0xAD78, 0xCD9E, 0xAD79, 0xCD9F, 0xAD7A, 0xCDA0, 0xAD81, 0xCDA1, 0xAD82, 0xCDA2, 0xAD83, 0xCDA3, 0xAD84, + 0xCDA4, 0xC3E3, 0xCDA5, 0xC3E4, 0xCDA6, 0xAD85, 0xCDA7, 0xC3E5, 0xCDA8, 0xAD86, 0xCDA9, 0xC3E6, 0xCDAA, 0xAD87, 0xCDAB, 0xAD88, + 0xCDAC, 0xAD89, 0xCDAD, 0xAD8A, 0xCDAE, 0xAD8B, 0xCDAF, 0xAD8C, 0xCDB0, 0xC3E7, 0xCDB1, 0xAD8D, 0xCDB2, 0xAD8E, 0xCDB3, 0xAD8F, + 0xCDB4, 0xAD90, 0xCDB5, 0xAD91, 0xCDB6, 0xAD92, 0xCDB7, 0xAD93, 0xCDB8, 0xAD94, 0xCDB9, 0xAD95, 0xCDBA, 0xAD96, 0xCDBB, 0xAD97, + 0xCDBC, 0xAD98, 0xCDBD, 0xAD99, 0xCDBE, 0xAD9A, 0xCDBF, 0xAD9B, 0xCDC0, 0xAD9C, 0xCDC1, 0xAD9D, 0xCDC2, 0xAD9E, 0xCDC3, 0xAD9F, + 0xCDC4, 0xC3E8, 0xCDC5, 0xADA0, 0xCDC6, 0xAE41, 0xCDC7, 0xAE42, 0xCDC8, 0xAE43, 0xCDC9, 0xAE44, 0xCDCA, 0xAE45, 0xCDCB, 0xAE46, + 0xCDCC, 0xC3E9, 0xCDCD, 0xAE47, 0xCDCE, 0xAE48, 0xCDCF, 0xAE49, 0xCDD0, 0xC3EA, 0xCDD1, 0xAE4A, 0xCDD2, 0xAE4B, 0xCDD3, 0xAE4C, + 0xCDD4, 0xAE4D, 0xCDD5, 0xAE4E, 0xCDD6, 0xAE4F, 0xCDD7, 0xAE50, 0xCDD8, 0xAE51, 0xCDD9, 0xAE52, 0xCDDA, 0xAE53, 0xCDDB, 0xAE54, + 0xCDDC, 0xAE55, 0xCDDD, 0xAE56, 0xCDDE, 0xAE57, 0xCDDF, 0xAE58, 0xCDE0, 0xAE59, 0xCDE1, 0xAE5A, 0xCDE2, 0xAE61, 0xCDE3, 0xAE62, + 0xCDE4, 0xAE63, 0xCDE5, 0xAE64, 0xCDE6, 0xAE65, 0xCDE7, 0xAE66, 0xCDE8, 0xC3EB, 0xCDE9, 0xAE67, 0xCDEA, 0xAE68, 0xCDEB, 0xAE69, + 0xCDEC, 0xC3EC, 0xCDED, 0xAE6A, 0xCDEE, 0xAE6B, 0xCDEF, 0xAE6C, 0xCDF0, 0xC3ED, 0xCDF1, 0xAE6D, 0xCDF2, 0xAE6E, 0xCDF3, 0xAE6F, + 0xCDF4, 0xAE70, 0xCDF5, 0xAE71, 0xCDF6, 0xAE72, 0xCDF7, 0xAE73, 0xCDF8, 0xC3EE, 0xCDF9, 0xC3EF, 0xCDFA, 0xAE74, 0xCDFB, 0xC3F0, + 0xCDFC, 0xAE75, 0xCDFD, 0xC3F1, 0xCDFE, 0xAE76, 0xCDFF, 0xAE77, 0xCE00, 0xAE78, 0xCE01, 0xAE79, 0xCE02, 0xAE7A, 0xCE03, 0xAE81, + 0xCE04, 0xC3F2, 0xCE05, 0xAE82, 0xCE06, 0xAE83, 0xCE07, 0xAE84, 0xCE08, 0xC3F3, 0xCE09, 0xAE85, 0xCE0A, 0xAE86, 0xCE0B, 0xAE87, + 0xCE0C, 0xC3F4, 0xCE0D, 0xAE88, 0xCE0E, 0xAE89, 0xCE0F, 0xAE8A, 0xCE10, 0xAE8B, 0xCE11, 0xAE8C, 0xCE12, 0xAE8D, 0xCE13, 0xAE8E, + 0xCE14, 0xC3F5, 0xCE15, 0xAE8F, 0xCE16, 0xAE90, 0xCE17, 0xAE91, 0xCE18, 0xAE92, 0xCE19, 0xC3F6, 0xCE1A, 0xAE93, 0xCE1B, 0xAE94, + 0xCE1C, 0xAE95, 0xCE1D, 0xAE96, 0xCE1E, 0xAE97, 0xCE1F, 0xAE98, 0xCE20, 0xC3F7, 0xCE21, 0xC3F8, 0xCE22, 0xAE99, 0xCE23, 0xAE9A, + 0xCE24, 0xC3F9, 0xCE25, 0xAE9B, 0xCE26, 0xAE9C, 0xCE27, 0xAE9D, 0xCE28, 0xC3FA, 0xCE29, 0xAE9E, 0xCE2A, 0xAE9F, 0xCE2B, 0xAEA0, + 0xCE2C, 0xAF41, 0xCE2D, 0xAF42, 0xCE2E, 0xAF43, 0xCE2F, 0xAF44, 0xCE30, 0xC3FB, 0xCE31, 0xC3FC, 0xCE32, 0xAF45, 0xCE33, 0xC3FD, + 0xCE34, 0xAF46, 0xCE35, 0xC3FE, 0xCE36, 0xAF47, 0xCE37, 0xAF48, 0xCE38, 0xAF49, 0xCE39, 0xAF4A, 0xCE3A, 0xAF4B, 0xCE3B, 0xAF4C, + 0xCE3C, 0xAF4D, 0xCE3D, 0xAF4E, 0xCE3E, 0xAF4F, 0xCE3F, 0xAF50, 0xCE40, 0xAF51, 0xCE41, 0xAF52, 0xCE42, 0xAF53, 0xCE43, 0xAF54, + 0xCE44, 0xAF55, 0xCE45, 0xAF56, 0xCE46, 0xAF57, 0xCE47, 0xAF58, 0xCE48, 0xAF59, 0xCE49, 0xAF5A, 0xCE4A, 0xAF61, 0xCE4B, 0xAF62, + 0xCE4C, 0xAF63, 0xCE4D, 0xAF64, 0xCE4E, 0xAF65, 0xCE4F, 0xAF66, 0xCE50, 0xAF67, 0xCE51, 0xAF68, 0xCE52, 0xAF69, 0xCE53, 0xAF6A, + 0xCE54, 0xAF6B, 0xCE55, 0xAF6C, 0xCE56, 0xAF6D, 0xCE57, 0xAF6E, 0xCE58, 0xC4A1, 0xCE59, 0xC4A2, 0xCE5A, 0xAF6F, 0xCE5B, 0xAF70, + 0xCE5C, 0xC4A3, 0xCE5D, 0xAF71, 0xCE5E, 0xAF72, 0xCE5F, 0xC4A4, 0xCE60, 0xC4A5, 0xCE61, 0xC4A6, 0xCE62, 0xAF73, 0xCE63, 0xAF74, + 0xCE64, 0xAF75, 0xCE65, 0xAF76, 0xCE66, 0xAF77, 0xCE67, 0xAF78, 0xCE68, 0xC4A7, 0xCE69, 0xC4A8, 0xCE6A, 0xAF79, 0xCE6B, 0xC4A9, + 0xCE6C, 0xAF7A, 0xCE6D, 0xC4AA, 0xCE6E, 0xAF81, 0xCE6F, 0xAF82, 0xCE70, 0xAF83, 0xCE71, 0xAF84, 0xCE72, 0xAF85, 0xCE73, 0xAF86, + 0xCE74, 0xC4AB, 0xCE75, 0xC4AC, 0xCE76, 0xAF87, 0xCE77, 0xAF88, 0xCE78, 0xC4AD, 0xCE79, 0xAF89, 0xCE7A, 0xAF8A, 0xCE7B, 0xAF8B, + 0xCE7C, 0xC4AE, 0xCE7D, 0xAF8C, 0xCE7E, 0xAF8D, 0xCE7F, 0xAF8E, 0xCE80, 0xAF8F, 0xCE81, 0xAF90, 0xCE82, 0xAF91, 0xCE83, 0xAF92, + 0xCE84, 0xC4AF, 0xCE85, 0xC4B0, 0xCE86, 0xAF93, 0xCE87, 0xC4B1, 0xCE88, 0xAF94, 0xCE89, 0xC4B2, 0xCE8A, 0xAF95, 0xCE8B, 0xAF96, + 0xCE8C, 0xAF97, 0xCE8D, 0xAF98, 0xCE8E, 0xAF99, 0xCE8F, 0xAF9A, 0xCE90, 0xC4B3, 0xCE91, 0xC4B4, 0xCE92, 0xAF9B, 0xCE93, 0xAF9C, + 0xCE94, 0xC4B5, 0xCE95, 0xAF9D, 0xCE96, 0xAF9E, 0xCE97, 0xAF9F, 0xCE98, 0xC4B6, 0xCE99, 0xAFA0, 0xCE9A, 0xB041, 0xCE9B, 0xB042, + 0xCE9C, 0xB043, 0xCE9D, 0xB044, 0xCE9E, 0xB045, 0xCE9F, 0xB046, 0xCEA0, 0xC4B7, 0xCEA1, 0xC4B8, 0xCEA2, 0xB047, 0xCEA3, 0xC4B9, + 0xCEA4, 0xC4BA, 0xCEA5, 0xC4BB, 0xCEA6, 0xB048, 0xCEA7, 0xB049, 0xCEA8, 0xB04A, 0xCEA9, 0xB04B, 0xCEAA, 0xB04C, 0xCEAB, 0xB04D, + 0xCEAC, 0xC4BC, 0xCEAD, 0xC4BD, 0xCEAE, 0xB04E, 0xCEAF, 0xB04F, 0xCEB0, 0xB050, 0xCEB1, 0xB051, 0xCEB2, 0xB052, 0xCEB3, 0xB053, + 0xCEB4, 0xB054, 0xCEB5, 0xB055, 0xCEB6, 0xB056, 0xCEB7, 0xB057, 0xCEB8, 0xB058, 0xCEB9, 0xB059, 0xCEBA, 0xB05A, 0xCEBB, 0xB061, + 0xCEBC, 0xB062, 0xCEBD, 0xB063, 0xCEBE, 0xB064, 0xCEBF, 0xB065, 0xCEC0, 0xB066, 0xCEC1, 0xC4BE, 0xCEC2, 0xB067, 0xCEC3, 0xB068, + 0xCEC4, 0xB069, 0xCEC5, 0xB06A, 0xCEC6, 0xB06B, 0xCEC7, 0xB06C, 0xCEC8, 0xB06D, 0xCEC9, 0xB06E, 0xCECA, 0xB06F, 0xCECB, 0xB070, + 0xCECC, 0xB071, 0xCECD, 0xB072, 0xCECE, 0xB073, 0xCECF, 0xB074, 0xCED0, 0xB075, 0xCED1, 0xB076, 0xCED2, 0xB077, 0xCED3, 0xB078, + 0xCED4, 0xB079, 0xCED5, 0xB07A, 0xCED6, 0xB081, 0xCED7, 0xB082, 0xCED8, 0xB083, 0xCED9, 0xB084, 0xCEDA, 0xB085, 0xCEDB, 0xB086, + 0xCEDC, 0xB087, 0xCEDD, 0xB088, 0xCEDE, 0xB089, 0xCEDF, 0xB08A, 0xCEE0, 0xB08B, 0xCEE1, 0xB08C, 0xCEE2, 0xB08D, 0xCEE3, 0xB08E, + 0xCEE4, 0xC4BF, 0xCEE5, 0xC4C0, 0xCEE6, 0xB08F, 0xCEE7, 0xB090, 0xCEE8, 0xC4C1, 0xCEE9, 0xB091, 0xCEEA, 0xB092, 0xCEEB, 0xC4C2, + 0xCEEC, 0xC4C3, 0xCEED, 0xB093, 0xCEEE, 0xB094, 0xCEEF, 0xB095, 0xCEF0, 0xB096, 0xCEF1, 0xB097, 0xCEF2, 0xB098, 0xCEF3, 0xB099, + 0xCEF4, 0xC4C4, 0xCEF5, 0xC4C5, 0xCEF6, 0xB09A, 0xCEF7, 0xC4C6, 0xCEF8, 0xC4C7, 0xCEF9, 0xC4C8, 0xCEFA, 0xB09B, 0xCEFB, 0xB09C, + 0xCEFC, 0xB09D, 0xCEFD, 0xB09E, 0xCEFE, 0xB09F, 0xCEFF, 0xB0A0, 0xCF00, 0xC4C9, 0xCF01, 0xC4CA, 0xCF02, 0xB141, 0xCF03, 0xB142, + 0xCF04, 0xC4CB, 0xCF05, 0xB143, 0xCF06, 0xB144, 0xCF07, 0xB145, 0xCF08, 0xC4CC, 0xCF09, 0xB146, 0xCF0A, 0xB147, 0xCF0B, 0xB148, + 0xCF0C, 0xB149, 0xCF0D, 0xB14A, 0xCF0E, 0xB14B, 0xCF0F, 0xB14C, 0xCF10, 0xC4CD, 0xCF11, 0xC4CE, 0xCF12, 0xB14D, 0xCF13, 0xC4CF, + 0xCF14, 0xB14E, 0xCF15, 0xC4D0, 0xCF16, 0xB14F, 0xCF17, 0xB150, 0xCF18, 0xB151, 0xCF19, 0xB152, 0xCF1A, 0xB153, 0xCF1B, 0xB154, + 0xCF1C, 0xC4D1, 0xCF1D, 0xB155, 0xCF1E, 0xB156, 0xCF1F, 0xB157, 0xCF20, 0xC4D2, 0xCF21, 0xB158, 0xCF22, 0xB159, 0xCF23, 0xB15A, + 0xCF24, 0xC4D3, 0xCF25, 0xB161, 0xCF26, 0xB162, 0xCF27, 0xB163, 0xCF28, 0xB164, 0xCF29, 0xB165, 0xCF2A, 0xB166, 0xCF2B, 0xB167, + 0xCF2C, 0xC4D4, 0xCF2D, 0xC4D5, 0xCF2E, 0xB168, 0xCF2F, 0xC4D6, 0xCF30, 0xC4D7, 0xCF31, 0xC4D8, 0xCF32, 0xB169, 0xCF33, 0xB16A, + 0xCF34, 0xB16B, 0xCF35, 0xB16C, 0xCF36, 0xB16D, 0xCF37, 0xB16E, 0xCF38, 0xC4D9, 0xCF39, 0xB16F, 0xCF3A, 0xB170, 0xCF3B, 0xB171, + 0xCF3C, 0xB172, 0xCF3D, 0xB173, 0xCF3E, 0xB174, 0xCF3F, 0xB175, 0xCF40, 0xB176, 0xCF41, 0xB177, 0xCF42, 0xB178, 0xCF43, 0xB179, + 0xCF44, 0xB17A, 0xCF45, 0xB181, 0xCF46, 0xB182, 0xCF47, 0xB183, 0xCF48, 0xB184, 0xCF49, 0xB185, 0xCF4A, 0xB186, 0xCF4B, 0xB187, + 0xCF4C, 0xB188, 0xCF4D, 0xB189, 0xCF4E, 0xB18A, 0xCF4F, 0xB18B, 0xCF50, 0xB18C, 0xCF51, 0xB18D, 0xCF52, 0xB18E, 0xCF53, 0xB18F, + 0xCF54, 0xC4DA, 0xCF55, 0xC4DB, 0xCF56, 0xB190, 0xCF57, 0xB191, 0xCF58, 0xC4DC, 0xCF59, 0xB192, 0xCF5A, 0xB193, 0xCF5B, 0xB194, + 0xCF5C, 0xC4DD, 0xCF5D, 0xB195, 0xCF5E, 0xB196, 0xCF5F, 0xB197, 0xCF60, 0xB198, 0xCF61, 0xB199, 0xCF62, 0xB19A, 0xCF63, 0xB19B, + 0xCF64, 0xC4DE, 0xCF65, 0xC4DF, 0xCF66, 0xB19C, 0xCF67, 0xC4E0, 0xCF68, 0xB19D, 0xCF69, 0xC4E1, 0xCF6A, 0xB19E, 0xCF6B, 0xB19F, + 0xCF6C, 0xB1A0, 0xCF6D, 0xB241, 0xCF6E, 0xB242, 0xCF6F, 0xB243, 0xCF70, 0xC4E2, 0xCF71, 0xC4E3, 0xCF72, 0xB244, 0xCF73, 0xB245, + 0xCF74, 0xC4E4, 0xCF75, 0xB246, 0xCF76, 0xB247, 0xCF77, 0xB248, 0xCF78, 0xC4E5, 0xCF79, 0xB249, 0xCF7A, 0xB24A, 0xCF7B, 0xB24B, + 0xCF7C, 0xB24C, 0xCF7D, 0xB24D, 0xCF7E, 0xB24E, 0xCF7F, 0xB24F, 0xCF80, 0xC4E6, 0xCF81, 0xB250, 0xCF82, 0xB251, 0xCF83, 0xB252, + 0xCF84, 0xB253, 0xCF85, 0xC4E7, 0xCF86, 0xB254, 0xCF87, 0xB255, 0xCF88, 0xB256, 0xCF89, 0xB257, 0xCF8A, 0xB258, 0xCF8B, 0xB259, + 0xCF8C, 0xC4E8, 0xCF8D, 0xB25A, 0xCF8E, 0xB261, 0xCF8F, 0xB262, 0xCF90, 0xB263, 0xCF91, 0xB264, 0xCF92, 0xB265, 0xCF93, 0xB266, + 0xCF94, 0xB267, 0xCF95, 0xB268, 0xCF96, 0xB269, 0xCF97, 0xB26A, 0xCF98, 0xB26B, 0xCF99, 0xB26C, 0xCF9A, 0xB26D, 0xCF9B, 0xB26E, + 0xCF9C, 0xB26F, 0xCF9D, 0xB270, 0xCF9E, 0xB271, 0xCF9F, 0xB272, 0xCFA0, 0xB273, 0xCFA1, 0xC4E9, 0xCFA2, 0xB274, 0xCFA3, 0xB275, + 0xCFA4, 0xB276, 0xCFA5, 0xB277, 0xCFA6, 0xB278, 0xCFA7, 0xB279, 0xCFA8, 0xC4EA, 0xCFA9, 0xB27A, 0xCFAA, 0xB281, 0xCFAB, 0xB282, + 0xCFAC, 0xB283, 0xCFAD, 0xB284, 0xCFAE, 0xB285, 0xCFAF, 0xB286, 0xCFB0, 0xC4EB, 0xCFB1, 0xB287, 0xCFB2, 0xB288, 0xCFB3, 0xB289, + 0xCFB4, 0xB28A, 0xCFB5, 0xB28B, 0xCFB6, 0xB28C, 0xCFB7, 0xB28D, 0xCFB8, 0xB28E, 0xCFB9, 0xB28F, 0xCFBA, 0xB290, 0xCFBB, 0xB291, + 0xCFBC, 0xB292, 0xCFBD, 0xB293, 0xCFBE, 0xB294, 0xCFBF, 0xB295, 0xCFC0, 0xB296, 0xCFC1, 0xB297, 0xCFC2, 0xB298, 0xCFC3, 0xB299, + 0xCFC4, 0xC4EC, 0xCFC5, 0xB29A, 0xCFC6, 0xB29B, 0xCFC7, 0xB29C, 0xCFC8, 0xB29D, 0xCFC9, 0xB29E, 0xCFCA, 0xB29F, 0xCFCB, 0xB2A0, + 0xCFCC, 0xB341, 0xCFCD, 0xB342, 0xCFCE, 0xB343, 0xCFCF, 0xB344, 0xCFD0, 0xB345, 0xCFD1, 0xB346, 0xCFD2, 0xB347, 0xCFD3, 0xB348, + 0xCFD4, 0xB349, 0xCFD5, 0xB34A, 0xCFD6, 0xB34B, 0xCFD7, 0xB34C, 0xCFD8, 0xB34D, 0xCFD9, 0xB34E, 0xCFDA, 0xB34F, 0xCFDB, 0xB350, + 0xCFDC, 0xB351, 0xCFDD, 0xB352, 0xCFDE, 0xB353, 0xCFDF, 0xB354, 0xCFE0, 0xC4ED, 0xCFE1, 0xC4EE, 0xCFE2, 0xB355, 0xCFE3, 0xB356, + 0xCFE4, 0xC4EF, 0xCFE5, 0xB357, 0xCFE6, 0xB358, 0xCFE7, 0xB359, 0xCFE8, 0xC4F0, 0xCFE9, 0xB35A, 0xCFEA, 0xB361, 0xCFEB, 0xB362, + 0xCFEC, 0xB363, 0xCFED, 0xB364, 0xCFEE, 0xB365, 0xCFEF, 0xB366, 0xCFF0, 0xC4F1, 0xCFF1, 0xC4F2, 0xCFF2, 0xB367, 0xCFF3, 0xC4F3, + 0xCFF4, 0xB368, 0xCFF5, 0xC4F4, 0xCFF6, 0xB369, 0xCFF7, 0xB36A, 0xCFF8, 0xB36B, 0xCFF9, 0xB36C, 0xCFFA, 0xB36D, 0xCFFB, 0xB36E, + 0xCFFC, 0xC4F5, 0xCFFD, 0xB36F, 0xCFFE, 0xB370, 0xCFFF, 0xB371, 0xD000, 0xC4F6, 0xD001, 0xB372, 0xD002, 0xB373, 0xD003, 0xB374, + 0xD004, 0xC4F7, 0xD005, 0xB375, 0xD006, 0xB376, 0xD007, 0xB377, 0xD008, 0xB378, 0xD009, 0xB379, 0xD00A, 0xB37A, 0xD00B, 0xB381, + 0xD00C, 0xB382, 0xD00D, 0xB383, 0xD00E, 0xB384, 0xD00F, 0xB385, 0xD010, 0xB386, 0xD011, 0xC4F8, 0xD012, 0xB387, 0xD013, 0xB388, + 0xD014, 0xB389, 0xD015, 0xB38A, 0xD016, 0xB38B, 0xD017, 0xB38C, 0xD018, 0xC4F9, 0xD019, 0xB38D, 0xD01A, 0xB38E, 0xD01B, 0xB38F, + 0xD01C, 0xB390, 0xD01D, 0xB391, 0xD01E, 0xB392, 0xD01F, 0xB393, 0xD020, 0xB394, 0xD021, 0xB395, 0xD022, 0xB396, 0xD023, 0xB397, + 0xD024, 0xB398, 0xD025, 0xB399, 0xD026, 0xB39A, 0xD027, 0xB39B, 0xD028, 0xB39C, 0xD029, 0xB39D, 0xD02A, 0xB39E, 0xD02B, 0xB39F, + 0xD02C, 0xB3A0, 0xD02D, 0xC4FA, 0xD02E, 0xB441, 0xD02F, 0xB442, 0xD030, 0xB443, 0xD031, 0xB444, 0xD032, 0xB445, 0xD033, 0xB446, + 0xD034, 0xC4FB, 0xD035, 0xC4FC, 0xD036, 0xB447, 0xD037, 0xB448, 0xD038, 0xC4FD, 0xD039, 0xB449, 0xD03A, 0xB44A, 0xD03B, 0xB44B, + 0xD03C, 0xC4FE, 0xD03D, 0xB44C, 0xD03E, 0xB44D, 0xD03F, 0xB44E, 0xD040, 0xB44F, 0xD041, 0xB450, 0xD042, 0xB451, 0xD043, 0xB452, + 0xD044, 0xC5A1, 0xD045, 0xC5A2, 0xD046, 0xB453, 0xD047, 0xC5A3, 0xD048, 0xB454, 0xD049, 0xC5A4, 0xD04A, 0xB455, 0xD04B, 0xB456, + 0xD04C, 0xB457, 0xD04D, 0xB458, 0xD04E, 0xB459, 0xD04F, 0xB45A, 0xD050, 0xC5A5, 0xD051, 0xB461, 0xD052, 0xB462, 0xD053, 0xB463, + 0xD054, 0xC5A6, 0xD055, 0xB464, 0xD056, 0xB465, 0xD057, 0xB466, 0xD058, 0xC5A7, 0xD059, 0xB467, 0xD05A, 0xB468, 0xD05B, 0xB469, + 0xD05C, 0xB46A, 0xD05D, 0xB46B, 0xD05E, 0xB46C, 0xD05F, 0xB46D, 0xD060, 0xC5A8, 0xD061, 0xB46E, 0xD062, 0xB46F, 0xD063, 0xB470, + 0xD064, 0xB471, 0xD065, 0xB472, 0xD066, 0xB473, 0xD067, 0xB474, 0xD068, 0xB475, 0xD069, 0xB476, 0xD06A, 0xB477, 0xD06B, 0xB478, + 0xD06C, 0xC5A9, 0xD06D, 0xC5AA, 0xD06E, 0xB479, 0xD06F, 0xB47A, 0xD070, 0xC5AB, 0xD071, 0xB481, 0xD072, 0xB482, 0xD073, 0xB483, + 0xD074, 0xC5AC, 0xD075, 0xB484, 0xD076, 0xB485, 0xD077, 0xB486, 0xD078, 0xB487, 0xD079, 0xB488, 0xD07A, 0xB489, 0xD07B, 0xB48A, + 0xD07C, 0xC5AD, 0xD07D, 0xC5AE, 0xD07E, 0xB48B, 0xD07F, 0xB48C, 0xD080, 0xB48D, 0xD081, 0xC5AF, 0xD082, 0xB48E, 0xD083, 0xB48F, + 0xD084, 0xB490, 0xD085, 0xB491, 0xD086, 0xB492, 0xD087, 0xB493, 0xD088, 0xB494, 0xD089, 0xB495, 0xD08A, 0xB496, 0xD08B, 0xB497, + 0xD08C, 0xB498, 0xD08D, 0xB499, 0xD08E, 0xB49A, 0xD08F, 0xB49B, 0xD090, 0xB49C, 0xD091, 0xB49D, 0xD092, 0xB49E, 0xD093, 0xB49F, + 0xD094, 0xB4A0, 0xD095, 0xB541, 0xD096, 0xB542, 0xD097, 0xB543, 0xD098, 0xB544, 0xD099, 0xB545, 0xD09A, 0xB546, 0xD09B, 0xB547, + 0xD09C, 0xB548, 0xD09D, 0xB549, 0xD09E, 0xB54A, 0xD09F, 0xB54B, 0xD0A0, 0xB54C, 0xD0A1, 0xB54D, 0xD0A2, 0xB54E, 0xD0A3, 0xB54F, + 0xD0A4, 0xC5B0, 0xD0A5, 0xC5B1, 0xD0A6, 0xB550, 0xD0A7, 0xB551, 0xD0A8, 0xC5B2, 0xD0A9, 0xB552, 0xD0AA, 0xB553, 0xD0AB, 0xB554, + 0xD0AC, 0xC5B3, 0xD0AD, 0xB555, 0xD0AE, 0xB556, 0xD0AF, 0xB557, 0xD0B0, 0xB558, 0xD0B1, 0xB559, 0xD0B2, 0xB55A, 0xD0B3, 0xB561, + 0xD0B4, 0xC5B4, 0xD0B5, 0xC5B5, 0xD0B6, 0xB562, 0xD0B7, 0xC5B6, 0xD0B8, 0xB563, 0xD0B9, 0xC5B7, 0xD0BA, 0xB564, 0xD0BB, 0xB565, + 0xD0BC, 0xB566, 0xD0BD, 0xB567, 0xD0BE, 0xB568, 0xD0BF, 0xB569, 0xD0C0, 0xC5B8, 0xD0C1, 0xC5B9, 0xD0C2, 0xB56A, 0xD0C3, 0xB56B, + 0xD0C4, 0xC5BA, 0xD0C5, 0xB56C, 0xD0C6, 0xB56D, 0xD0C7, 0xB56E, 0xD0C8, 0xC5BB, 0xD0C9, 0xC5BC, 0xD0CA, 0xB56F, 0xD0CB, 0xB570, + 0xD0CC, 0xB571, 0xD0CD, 0xB572, 0xD0CE, 0xB573, 0xD0CF, 0xB574, 0xD0D0, 0xC5BD, 0xD0D1, 0xC5BE, 0xD0D2, 0xB575, 0xD0D3, 0xC5BF, + 0xD0D4, 0xC5C0, 0xD0D5, 0xC5C1, 0xD0D6, 0xB576, 0xD0D7, 0xB577, 0xD0D8, 0xB578, 0xD0D9, 0xB579, 0xD0DA, 0xB57A, 0xD0DB, 0xB581, + 0xD0DC, 0xC5C2, 0xD0DD, 0xC5C3, 0xD0DE, 0xB582, 0xD0DF, 0xB583, 0xD0E0, 0xC5C4, 0xD0E1, 0xB584, 0xD0E2, 0xB585, 0xD0E3, 0xB586, + 0xD0E4, 0xC5C5, 0xD0E5, 0xB587, 0xD0E6, 0xB588, 0xD0E7, 0xB589, 0xD0E8, 0xB58A, 0xD0E9, 0xB58B, 0xD0EA, 0xB58C, 0xD0EB, 0xB58D, + 0xD0EC, 0xC5C6, 0xD0ED, 0xC5C7, 0xD0EE, 0xB58E, 0xD0EF, 0xC5C8, 0xD0F0, 0xC5C9, 0xD0F1, 0xC5CA, 0xD0F2, 0xB58F, 0xD0F3, 0xB590, + 0xD0F4, 0xB591, 0xD0F5, 0xB592, 0xD0F6, 0xB593, 0xD0F7, 0xB594, 0xD0F8, 0xC5CB, 0xD0F9, 0xB595, 0xD0FA, 0xB596, 0xD0FB, 0xB597, + 0xD0FC, 0xB598, 0xD0FD, 0xB599, 0xD0FE, 0xB59A, 0xD0FF, 0xB59B, 0xD100, 0xB59C, 0xD101, 0xB59D, 0xD102, 0xB59E, 0xD103, 0xB59F, + 0xD104, 0xB5A0, 0xD105, 0xB641, 0xD106, 0xB642, 0xD107, 0xB643, 0xD108, 0xB644, 0xD109, 0xB645, 0xD10A, 0xB646, 0xD10B, 0xB647, + 0xD10C, 0xB648, 0xD10D, 0xC5CC, 0xD10E, 0xB649, 0xD10F, 0xB64A, 0xD110, 0xB64B, 0xD111, 0xB64C, 0xD112, 0xB64D, 0xD113, 0xB64E, + 0xD114, 0xB64F, 0xD115, 0xB650, 0xD116, 0xB651, 0xD117, 0xB652, 0xD118, 0xB653, 0xD119, 0xB654, 0xD11A, 0xB655, 0xD11B, 0xB656, + 0xD11C, 0xB657, 0xD11D, 0xB658, 0xD11E, 0xB659, 0xD11F, 0xB65A, 0xD120, 0xB661, 0xD121, 0xB662, 0xD122, 0xB663, 0xD123, 0xB664, + 0xD124, 0xB665, 0xD125, 0xB666, 0xD126, 0xB667, 0xD127, 0xB668, 0xD128, 0xB669, 0xD129, 0xB66A, 0xD12A, 0xB66B, 0xD12B, 0xB66C, + 0xD12C, 0xB66D, 0xD12D, 0xB66E, 0xD12E, 0xB66F, 0xD12F, 0xB670, 0xD130, 0xC5CD, 0xD131, 0xC5CE, 0xD132, 0xB671, 0xD133, 0xB672, + 0xD134, 0xC5CF, 0xD135, 0xB673, 0xD136, 0xB674, 0xD137, 0xB675, 0xD138, 0xC5D0, 0xD139, 0xB676, 0xD13A, 0xC5D1, 0xD13B, 0xB677, + 0xD13C, 0xB678, 0xD13D, 0xB679, 0xD13E, 0xB67A, 0xD13F, 0xB681, 0xD140, 0xC5D2, 0xD141, 0xC5D3, 0xD142, 0xB682, 0xD143, 0xC5D4, + 0xD144, 0xC5D5, 0xD145, 0xC5D6, 0xD146, 0xB683, 0xD147, 0xB684, 0xD148, 0xB685, 0xD149, 0xB686, 0xD14A, 0xB687, 0xD14B, 0xB688, + 0xD14C, 0xC5D7, 0xD14D, 0xC5D8, 0xD14E, 0xB689, 0xD14F, 0xB68A, 0xD150, 0xC5D9, 0xD151, 0xB68B, 0xD152, 0xB68C, 0xD153, 0xB68D, + 0xD154, 0xC5DA, 0xD155, 0xB68E, 0xD156, 0xB68F, 0xD157, 0xB690, 0xD158, 0xB691, 0xD159, 0xB692, 0xD15A, 0xB693, 0xD15B, 0xB694, + 0xD15C, 0xC5DB, 0xD15D, 0xC5DC, 0xD15E, 0xB695, 0xD15F, 0xC5DD, 0xD160, 0xB696, 0xD161, 0xC5DE, 0xD162, 0xB697, 0xD163, 0xB698, + 0xD164, 0xB699, 0xD165, 0xB69A, 0xD166, 0xB69B, 0xD167, 0xB69C, 0xD168, 0xC5DF, 0xD169, 0xB69D, 0xD16A, 0xB69E, 0xD16B, 0xB69F, + 0xD16C, 0xC5E0, 0xD16D, 0xB6A0, 0xD16E, 0xB741, 0xD16F, 0xB742, 0xD170, 0xB743, 0xD171, 0xB744, 0xD172, 0xB745, 0xD173, 0xB746, + 0xD174, 0xB747, 0xD175, 0xB748, 0xD176, 0xB749, 0xD177, 0xB74A, 0xD178, 0xB74B, 0xD179, 0xB74C, 0xD17A, 0xB74D, 0xD17B, 0xB74E, + 0xD17C, 0xC5E1, 0xD17D, 0xB74F, 0xD17E, 0xB750, 0xD17F, 0xB751, 0xD180, 0xB752, 0xD181, 0xB753, 0xD182, 0xB754, 0xD183, 0xB755, + 0xD184, 0xC5E2, 0xD185, 0xB756, 0xD186, 0xB757, 0xD187, 0xB758, 0xD188, 0xC5E3, 0xD189, 0xB759, 0xD18A, 0xB75A, 0xD18B, 0xB761, + 0xD18C, 0xB762, 0xD18D, 0xB763, 0xD18E, 0xB764, 0xD18F, 0xB765, 0xD190, 0xB766, 0xD191, 0xB767, 0xD192, 0xB768, 0xD193, 0xB769, + 0xD194, 0xB76A, 0xD195, 0xB76B, 0xD196, 0xB76C, 0xD197, 0xB76D, 0xD198, 0xB76E, 0xD199, 0xB76F, 0xD19A, 0xB770, 0xD19B, 0xB771, + 0xD19C, 0xB772, 0xD19D, 0xB773, 0xD19E, 0xB774, 0xD19F, 0xB775, 0xD1A0, 0xC5E4, 0xD1A1, 0xC5E5, 0xD1A2, 0xB776, 0xD1A3, 0xB777, + 0xD1A4, 0xC5E6, 0xD1A5, 0xB778, 0xD1A6, 0xB779, 0xD1A7, 0xB77A, 0xD1A8, 0xC5E7, 0xD1A9, 0xB781, 0xD1AA, 0xB782, 0xD1AB, 0xB783, + 0xD1AC, 0xB784, 0xD1AD, 0xB785, 0xD1AE, 0xB786, 0xD1AF, 0xB787, 0xD1B0, 0xC5E8, 0xD1B1, 0xC5E9, 0xD1B2, 0xB788, 0xD1B3, 0xC5EA, + 0xD1B4, 0xB789, 0xD1B5, 0xC5EB, 0xD1B6, 0xB78A, 0xD1B7, 0xB78B, 0xD1B8, 0xB78C, 0xD1B9, 0xB78D, 0xD1BA, 0xC5EC, 0xD1BB, 0xB78E, + 0xD1BC, 0xC5ED, 0xD1BD, 0xB78F, 0xD1BE, 0xB790, 0xD1BF, 0xB791, 0xD1C0, 0xC5EE, 0xD1C1, 0xB792, 0xD1C2, 0xB793, 0xD1C3, 0xB794, + 0xD1C4, 0xB795, 0xD1C5, 0xB796, 0xD1C6, 0xB797, 0xD1C7, 0xB798, 0xD1C8, 0xB799, 0xD1C9, 0xB79A, 0xD1CA, 0xB79B, 0xD1CB, 0xB79C, + 0xD1CC, 0xB79D, 0xD1CD, 0xB79E, 0xD1CE, 0xB79F, 0xD1CF, 0xB7A0, 0xD1D0, 0xB841, 0xD1D1, 0xB842, 0xD1D2, 0xB843, 0xD1D3, 0xB844, + 0xD1D4, 0xB845, 0xD1D5, 0xB846, 0xD1D6, 0xB847, 0xD1D7, 0xB848, 0xD1D8, 0xC5EF, 0xD1D9, 0xB849, 0xD1DA, 0xB84A, 0xD1DB, 0xB84B, + 0xD1DC, 0xB84C, 0xD1DD, 0xB84D, 0xD1DE, 0xB84E, 0xD1DF, 0xB84F, 0xD1E0, 0xB850, 0xD1E1, 0xB851, 0xD1E2, 0xB852, 0xD1E3, 0xB853, + 0xD1E4, 0xB854, 0xD1E5, 0xB855, 0xD1E6, 0xB856, 0xD1E7, 0xB857, 0xD1E8, 0xB858, 0xD1E9, 0xB859, 0xD1EA, 0xB85A, 0xD1EB, 0xB861, + 0xD1EC, 0xB862, 0xD1ED, 0xB863, 0xD1EE, 0xB864, 0xD1EF, 0xB865, 0xD1F0, 0xB866, 0xD1F1, 0xB867, 0xD1F2, 0xB868, 0xD1F3, 0xB869, + 0xD1F4, 0xC5F0, 0xD1F5, 0xB86A, 0xD1F6, 0xB86B, 0xD1F7, 0xB86C, 0xD1F8, 0xC5F1, 0xD1F9, 0xB86D, 0xD1FA, 0xB86E, 0xD1FB, 0xB86F, + 0xD1FC, 0xB870, 0xD1FD, 0xB871, 0xD1FE, 0xB872, 0xD1FF, 0xB873, 0xD200, 0xB874, 0xD201, 0xB875, 0xD202, 0xB876, 0xD203, 0xB877, + 0xD204, 0xB878, 0xD205, 0xB879, 0xD206, 0xB87A, 0xD207, 0xC5F2, 0xD208, 0xB881, 0xD209, 0xC5F3, 0xD20A, 0xB882, 0xD20B, 0xB883, + 0xD20C, 0xB884, 0xD20D, 0xB885, 0xD20E, 0xB886, 0xD20F, 0xB887, 0xD210, 0xC5F4, 0xD211, 0xB888, 0xD212, 0xB889, 0xD213, 0xB88A, + 0xD214, 0xB88B, 0xD215, 0xB88C, 0xD216, 0xB88D, 0xD217, 0xB88E, 0xD218, 0xB88F, 0xD219, 0xB890, 0xD21A, 0xB891, 0xD21B, 0xB892, + 0xD21C, 0xB893, 0xD21D, 0xB894, 0xD21E, 0xB895, 0xD21F, 0xB896, 0xD220, 0xB897, 0xD221, 0xB898, 0xD222, 0xB899, 0xD223, 0xB89A, + 0xD224, 0xB89B, 0xD225, 0xB89C, 0xD226, 0xB89D, 0xD227, 0xB89E, 0xD228, 0xB89F, 0xD229, 0xB8A0, 0xD22A, 0xB941, 0xD22B, 0xB942, + 0xD22C, 0xC5F5, 0xD22D, 0xC5F6, 0xD22E, 0xB943, 0xD22F, 0xB944, 0xD230, 0xC5F7, 0xD231, 0xB945, 0xD232, 0xB946, 0xD233, 0xB947, + 0xD234, 0xC5F8, 0xD235, 0xB948, 0xD236, 0xB949, 0xD237, 0xB94A, 0xD238, 0xB94B, 0xD239, 0xB94C, 0xD23A, 0xB94D, 0xD23B, 0xB94E, + 0xD23C, 0xC5F9, 0xD23D, 0xC5FA, 0xD23E, 0xB94F, 0xD23F, 0xC5FB, 0xD240, 0xB950, 0xD241, 0xC5FC, 0xD242, 0xB951, 0xD243, 0xB952, + 0xD244, 0xB953, 0xD245, 0xB954, 0xD246, 0xB955, 0xD247, 0xB956, 0xD248, 0xC5FD, 0xD249, 0xB957, 0xD24A, 0xB958, 0xD24B, 0xB959, + 0xD24C, 0xB95A, 0xD24D, 0xB961, 0xD24E, 0xB962, 0xD24F, 0xB963, 0xD250, 0xB964, 0xD251, 0xB965, 0xD252, 0xB966, 0xD253, 0xB967, + 0xD254, 0xB968, 0xD255, 0xB969, 0xD256, 0xB96A, 0xD257, 0xB96B, 0xD258, 0xB96C, 0xD259, 0xB96D, 0xD25A, 0xB96E, 0xD25B, 0xB96F, + 0xD25C, 0xC5FE, 0xD25D, 0xB970, 0xD25E, 0xB971, 0xD25F, 0xB972, 0xD260, 0xB973, 0xD261, 0xB974, 0xD262, 0xB975, 0xD263, 0xB976, + 0xD264, 0xC6A1, 0xD265, 0xB977, 0xD266, 0xB978, 0xD267, 0xB979, 0xD268, 0xB97A, 0xD269, 0xB981, 0xD26A, 0xB982, 0xD26B, 0xB983, + 0xD26C, 0xB984, 0xD26D, 0xB985, 0xD26E, 0xB986, 0xD26F, 0xB987, 0xD270, 0xB988, 0xD271, 0xB989, 0xD272, 0xB98A, 0xD273, 0xB98B, + 0xD274, 0xB98C, 0xD275, 0xB98D, 0xD276, 0xB98E, 0xD277, 0xB98F, 0xD278, 0xB990, 0xD279, 0xB991, 0xD27A, 0xB992, 0xD27B, 0xB993, + 0xD27C, 0xB994, 0xD27D, 0xB995, 0xD27E, 0xB996, 0xD27F, 0xB997, 0xD280, 0xC6A2, 0xD281, 0xC6A3, 0xD282, 0xB998, 0xD283, 0xB999, + 0xD284, 0xC6A4, 0xD285, 0xB99A, 0xD286, 0xB99B, 0xD287, 0xB99C, 0xD288, 0xC6A5, 0xD289, 0xB99D, 0xD28A, 0xB99E, 0xD28B, 0xB99F, + 0xD28C, 0xB9A0, 0xD28D, 0xBA41, 0xD28E, 0xBA42, 0xD28F, 0xBA43, 0xD290, 0xC6A6, 0xD291, 0xC6A7, 0xD292, 0xBA44, 0xD293, 0xBA45, + 0xD294, 0xBA46, 0xD295, 0xC6A8, 0xD296, 0xBA47, 0xD297, 0xBA48, 0xD298, 0xBA49, 0xD299, 0xBA4A, 0xD29A, 0xBA4B, 0xD29B, 0xBA4C, + 0xD29C, 0xC6A9, 0xD29D, 0xBA4D, 0xD29E, 0xBA4E, 0xD29F, 0xBA4F, 0xD2A0, 0xC6AA, 0xD2A1, 0xBA50, 0xD2A2, 0xBA51, 0xD2A3, 0xBA52, + 0xD2A4, 0xC6AB, 0xD2A5, 0xBA53, 0xD2A6, 0xBA54, 0xD2A7, 0xBA55, 0xD2A8, 0xBA56, 0xD2A9, 0xBA57, 0xD2AA, 0xBA58, 0xD2AB, 0xBA59, + 0xD2AC, 0xC6AC, 0xD2AD, 0xBA5A, 0xD2AE, 0xBA61, 0xD2AF, 0xBA62, 0xD2B0, 0xBA63, 0xD2B1, 0xC6AD, 0xD2B2, 0xBA64, 0xD2B3, 0xBA65, + 0xD2B4, 0xBA66, 0xD2B5, 0xBA67, 0xD2B6, 0xBA68, 0xD2B7, 0xBA69, 0xD2B8, 0xC6AE, 0xD2B9, 0xC6AF, 0xD2BA, 0xBA6A, 0xD2BB, 0xBA6B, + 0xD2BC, 0xC6B0, 0xD2BD, 0xBA6C, 0xD2BE, 0xBA6D, 0xD2BF, 0xC6B1, 0xD2C0, 0xC6B2, 0xD2C1, 0xBA6E, 0xD2C2, 0xC6B3, 0xD2C3, 0xBA6F, + 0xD2C4, 0xBA70, 0xD2C5, 0xBA71, 0xD2C6, 0xBA72, 0xD2C7, 0xBA73, 0xD2C8, 0xC6B4, 0xD2C9, 0xC6B5, 0xD2CA, 0xBA74, 0xD2CB, 0xC6B6, + 0xD2CC, 0xBA75, 0xD2CD, 0xBA76, 0xD2CE, 0xBA77, 0xD2CF, 0xBA78, 0xD2D0, 0xBA79, 0xD2D1, 0xBA7A, 0xD2D2, 0xBA81, 0xD2D3, 0xBA82, + 0xD2D4, 0xC6B7, 0xD2D5, 0xBA83, 0xD2D6, 0xBA84, 0xD2D7, 0xBA85, 0xD2D8, 0xC6B8, 0xD2D9, 0xBA86, 0xD2DA, 0xBA87, 0xD2DB, 0xBA88, + 0xD2DC, 0xC6B9, 0xD2DD, 0xBA89, 0xD2DE, 0xBA8A, 0xD2DF, 0xBA8B, 0xD2E0, 0xBA8C, 0xD2E1, 0xBA8D, 0xD2E2, 0xBA8E, 0xD2E3, 0xBA8F, + 0xD2E4, 0xC6BA, 0xD2E5, 0xC6BB, 0xD2E6, 0xBA90, 0xD2E7, 0xBA91, 0xD2E8, 0xBA92, 0xD2E9, 0xBA93, 0xD2EA, 0xBA94, 0xD2EB, 0xBA95, + 0xD2EC, 0xBA96, 0xD2ED, 0xBA97, 0xD2EE, 0xBA98, 0xD2EF, 0xBA99, 0xD2F0, 0xC6BC, 0xD2F1, 0xC6BD, 0xD2F2, 0xBA9A, 0xD2F3, 0xBA9B, + 0xD2F4, 0xC6BE, 0xD2F5, 0xBA9C, 0xD2F6, 0xBA9D, 0xD2F7, 0xBA9E, 0xD2F8, 0xC6BF, 0xD2F9, 0xBA9F, 0xD2FA, 0xBAA0, 0xD2FB, 0xBB41, + 0xD2FC, 0xBB42, 0xD2FD, 0xBB43, 0xD2FE, 0xBB44, 0xD2FF, 0xBB45, 0xD300, 0xC6C0, 0xD301, 0xC6C1, 0xD302, 0xBB46, 0xD303, 0xC6C2, + 0xD304, 0xBB47, 0xD305, 0xC6C3, 0xD306, 0xBB48, 0xD307, 0xBB49, 0xD308, 0xBB4A, 0xD309, 0xBB4B, 0xD30A, 0xBB4C, 0xD30B, 0xBB4D, + 0xD30C, 0xC6C4, 0xD30D, 0xC6C5, 0xD30E, 0xC6C6, 0xD30F, 0xBB4E, 0xD310, 0xC6C7, 0xD311, 0xBB4F, 0xD312, 0xBB50, 0xD313, 0xBB51, + 0xD314, 0xC6C8, 0xD315, 0xBB52, 0xD316, 0xC6C9, 0xD317, 0xBB53, 0xD318, 0xBB54, 0xD319, 0xBB55, 0xD31A, 0xBB56, 0xD31B, 0xBB57, + 0xD31C, 0xC6CA, 0xD31D, 0xC6CB, 0xD31E, 0xBB58, 0xD31F, 0xC6CC, 0xD320, 0xC6CD, 0xD321, 0xC6CE, 0xD322, 0xBB59, 0xD323, 0xBB5A, + 0xD324, 0xBB61, 0xD325, 0xC6CF, 0xD326, 0xBB62, 0xD327, 0xBB63, 0xD328, 0xC6D0, 0xD329, 0xC6D1, 0xD32A, 0xBB64, 0xD32B, 0xBB65, + 0xD32C, 0xC6D2, 0xD32D, 0xBB66, 0xD32E, 0xBB67, 0xD32F, 0xBB68, 0xD330, 0xC6D3, 0xD331, 0xBB69, 0xD332, 0xBB6A, 0xD333, 0xBB6B, + 0xD334, 0xBB6C, 0xD335, 0xBB6D, 0xD336, 0xBB6E, 0xD337, 0xBB6F, 0xD338, 0xC6D4, 0xD339, 0xC6D5, 0xD33A, 0xBB70, 0xD33B, 0xC6D6, + 0xD33C, 0xC6D7, 0xD33D, 0xC6D8, 0xD33E, 0xBB71, 0xD33F, 0xBB72, 0xD340, 0xBB73, 0xD341, 0xBB74, 0xD342, 0xBB75, 0xD343, 0xBB76, + 0xD344, 0xC6D9, 0xD345, 0xC6DA, 0xD346, 0xBB77, 0xD347, 0xBB78, 0xD348, 0xBB79, 0xD349, 0xBB7A, 0xD34A, 0xBB81, 0xD34B, 0xBB82, + 0xD34C, 0xBB83, 0xD34D, 0xBB84, 0xD34E, 0xBB85, 0xD34F, 0xBB86, 0xD350, 0xBB87, 0xD351, 0xBB88, 0xD352, 0xBB89, 0xD353, 0xBB8A, + 0xD354, 0xBB8B, 0xD355, 0xBB8C, 0xD356, 0xBB8D, 0xD357, 0xBB8E, 0xD358, 0xBB8F, 0xD359, 0xBB90, 0xD35A, 0xBB91, 0xD35B, 0xBB92, + 0xD35C, 0xBB93, 0xD35D, 0xBB94, 0xD35E, 0xBB95, 0xD35F, 0xBB96, 0xD360, 0xBB97, 0xD361, 0xBB98, 0xD362, 0xBB99, 0xD363, 0xBB9A, + 0xD364, 0xBB9B, 0xD365, 0xBB9C, 0xD366, 0xBB9D, 0xD367, 0xBB9E, 0xD368, 0xBB9F, 0xD369, 0xBBA0, 0xD36A, 0xBC41, 0xD36B, 0xBC42, + 0xD36C, 0xBC43, 0xD36D, 0xBC44, 0xD36E, 0xBC45, 0xD36F, 0xBC46, 0xD370, 0xBC47, 0xD371, 0xBC48, 0xD372, 0xBC49, 0xD373, 0xBC4A, + 0xD374, 0xBC4B, 0xD375, 0xBC4C, 0xD376, 0xBC4D, 0xD377, 0xBC4E, 0xD378, 0xBC4F, 0xD379, 0xBC50, 0xD37A, 0xBC51, 0xD37B, 0xBC52, + 0xD37C, 0xC6DB, 0xD37D, 0xC6DC, 0xD37E, 0xBC53, 0xD37F, 0xBC54, 0xD380, 0xC6DD, 0xD381, 0xBC55, 0xD382, 0xBC56, 0xD383, 0xBC57, + 0xD384, 0xC6DE, 0xD385, 0xBC58, 0xD386, 0xBC59, 0xD387, 0xBC5A, 0xD388, 0xBC61, 0xD389, 0xBC62, 0xD38A, 0xBC63, 0xD38B, 0xBC64, + 0xD38C, 0xC6DF, 0xD38D, 0xC6E0, 0xD38E, 0xBC65, 0xD38F, 0xC6E1, 0xD390, 0xC6E2, 0xD391, 0xC6E3, 0xD392, 0xBC66, 0xD393, 0xBC67, + 0xD394, 0xBC68, 0xD395, 0xBC69, 0xD396, 0xBC6A, 0xD397, 0xBC6B, 0xD398, 0xC6E4, 0xD399, 0xC6E5, 0xD39A, 0xBC6C, 0xD39B, 0xBC6D, + 0xD39C, 0xC6E6, 0xD39D, 0xBC6E, 0xD39E, 0xBC6F, 0xD39F, 0xBC70, 0xD3A0, 0xC6E7, 0xD3A1, 0xBC71, 0xD3A2, 0xBC72, 0xD3A3, 0xBC73, + 0xD3A4, 0xBC74, 0xD3A5, 0xBC75, 0xD3A6, 0xBC76, 0xD3A7, 0xBC77, 0xD3A8, 0xC6E8, 0xD3A9, 0xC6E9, 0xD3AA, 0xBC78, 0xD3AB, 0xC6EA, + 0xD3AC, 0xBC79, 0xD3AD, 0xC6EB, 0xD3AE, 0xBC7A, 0xD3AF, 0xBC81, 0xD3B0, 0xBC82, 0xD3B1, 0xBC83, 0xD3B2, 0xBC84, 0xD3B3, 0xBC85, + 0xD3B4, 0xC6EC, 0xD3B5, 0xBC86, 0xD3B6, 0xBC87, 0xD3B7, 0xBC88, 0xD3B8, 0xC6ED, 0xD3B9, 0xBC89, 0xD3BA, 0xBC8A, 0xD3BB, 0xBC8B, + 0xD3BC, 0xC6EE, 0xD3BD, 0xBC8C, 0xD3BE, 0xBC8D, 0xD3BF, 0xBC8E, 0xD3C0, 0xBC8F, 0xD3C1, 0xBC90, 0xD3C2, 0xBC91, 0xD3C3, 0xBC92, + 0xD3C4, 0xC6EF, 0xD3C5, 0xC6F0, 0xD3C6, 0xBC93, 0xD3C7, 0xBC94, 0xD3C8, 0xC6F1, 0xD3C9, 0xC6F2, 0xD3CA, 0xBC95, 0xD3CB, 0xBC96, + 0xD3CC, 0xBC97, 0xD3CD, 0xBC98, 0xD3CE, 0xBC99, 0xD3CF, 0xBC9A, 0xD3D0, 0xC6F3, 0xD3D1, 0xBC9B, 0xD3D2, 0xBC9C, 0xD3D3, 0xBC9D, + 0xD3D4, 0xBC9E, 0xD3D5, 0xBC9F, 0xD3D6, 0xBCA0, 0xD3D7, 0xBD41, 0xD3D8, 0xC6F4, 0xD3D9, 0xBD42, 0xD3DA, 0xBD43, 0xD3DB, 0xBD44, + 0xD3DC, 0xBD45, 0xD3DD, 0xBD46, 0xD3DE, 0xBD47, 0xD3DF, 0xBD48, 0xD3E0, 0xBD49, 0xD3E1, 0xC6F5, 0xD3E2, 0xBD4A, 0xD3E3, 0xC6F6, + 0xD3E4, 0xBD4B, 0xD3E5, 0xBD4C, 0xD3E6, 0xBD4D, 0xD3E7, 0xBD4E, 0xD3E8, 0xBD4F, 0xD3E9, 0xBD50, 0xD3EA, 0xBD51, 0xD3EB, 0xBD52, + 0xD3EC, 0xC6F7, 0xD3ED, 0xC6F8, 0xD3EE, 0xBD53, 0xD3EF, 0xBD54, 0xD3F0, 0xC6F9, 0xD3F1, 0xBD55, 0xD3F2, 0xBD56, 0xD3F3, 0xBD57, + 0xD3F4, 0xC6FA, 0xD3F5, 0xBD58, 0xD3F6, 0xBD59, 0xD3F7, 0xBD5A, 0xD3F8, 0xBD61, 0xD3F9, 0xBD62, 0xD3FA, 0xBD63, 0xD3FB, 0xBD64, + 0xD3FC, 0xC6FB, 0xD3FD, 0xC6FC, 0xD3FE, 0xBD65, 0xD3FF, 0xC6FD, 0xD400, 0xBD66, 0xD401, 0xC6FE, 0xD402, 0xBD67, 0xD403, 0xBD68, + 0xD404, 0xBD69, 0xD405, 0xBD6A, 0xD406, 0xBD6B, 0xD407, 0xBD6C, 0xD408, 0xC7A1, 0xD409, 0xBD6D, 0xD40A, 0xBD6E, 0xD40B, 0xBD6F, + 0xD40C, 0xBD70, 0xD40D, 0xBD71, 0xD40E, 0xBD72, 0xD40F, 0xBD73, 0xD410, 0xBD74, 0xD411, 0xBD75, 0xD412, 0xBD76, 0xD413, 0xBD77, + 0xD414, 0xBD78, 0xD415, 0xBD79, 0xD416, 0xBD7A, 0xD417, 0xBD81, 0xD418, 0xBD82, 0xD419, 0xBD83, 0xD41A, 0xBD84, 0xD41B, 0xBD85, + 0xD41C, 0xBD86, 0xD41D, 0xC7A2, 0xD41E, 0xBD87, 0xD41F, 0xBD88, 0xD420, 0xBD89, 0xD421, 0xBD8A, 0xD422, 0xBD8B, 0xD423, 0xBD8C, + 0xD424, 0xBD8D, 0xD425, 0xBD8E, 0xD426, 0xBD8F, 0xD427, 0xBD90, 0xD428, 0xBD91, 0xD429, 0xBD92, 0xD42A, 0xBD93, 0xD42B, 0xBD94, + 0xD42C, 0xBD95, 0xD42D, 0xBD96, 0xD42E, 0xBD97, 0xD42F, 0xBD98, 0xD430, 0xBD99, 0xD431, 0xBD9A, 0xD432, 0xBD9B, 0xD433, 0xBD9C, + 0xD434, 0xBD9D, 0xD435, 0xBD9E, 0xD436, 0xBD9F, 0xD437, 0xBDA0, 0xD438, 0xBE41, 0xD439, 0xBE42, 0xD43A, 0xBE43, 0xD43B, 0xBE44, + 0xD43C, 0xBE45, 0xD43D, 0xBE46, 0xD43E, 0xBE47, 0xD43F, 0xBE48, 0xD440, 0xC7A3, 0xD441, 0xBE49, 0xD442, 0xBE4A, 0xD443, 0xBE4B, + 0xD444, 0xC7A4, 0xD445, 0xBE4C, 0xD446, 0xBE4D, 0xD447, 0xBE4E, 0xD448, 0xBE4F, 0xD449, 0xBE50, 0xD44A, 0xBE51, 0xD44B, 0xBE52, + 0xD44C, 0xBE53, 0xD44D, 0xBE54, 0xD44E, 0xBE55, 0xD44F, 0xBE56, 0xD450, 0xBE57, 0xD451, 0xBE58, 0xD452, 0xBE59, 0xD453, 0xBE5A, + 0xD454, 0xBE61, 0xD455, 0xBE62, 0xD456, 0xBE63, 0xD457, 0xBE64, 0xD458, 0xBE65, 0xD459, 0xBE66, 0xD45A, 0xBE67, 0xD45B, 0xBE68, + 0xD45C, 0xC7A5, 0xD45D, 0xBE69, 0xD45E, 0xBE6A, 0xD45F, 0xBE6B, 0xD460, 0xC7A6, 0xD461, 0xBE6C, 0xD462, 0xBE6D, 0xD463, 0xBE6E, + 0xD464, 0xC7A7, 0xD465, 0xBE6F, 0xD466, 0xBE70, 0xD467, 0xBE71, 0xD468, 0xBE72, 0xD469, 0xBE73, 0xD46A, 0xBE74, 0xD46B, 0xBE75, + 0xD46C, 0xBE76, 0xD46D, 0xC7A8, 0xD46E, 0xBE77, 0xD46F, 0xC7A9, 0xD470, 0xBE78, 0xD471, 0xBE79, 0xD472, 0xBE7A, 0xD473, 0xBE81, + 0xD474, 0xBE82, 0xD475, 0xBE83, 0xD476, 0xBE84, 0xD477, 0xBE85, 0xD478, 0xC7AA, 0xD479, 0xC7AB, 0xD47A, 0xBE86, 0xD47B, 0xBE87, + 0xD47C, 0xC7AC, 0xD47D, 0xBE88, 0xD47E, 0xBE89, 0xD47F, 0xC7AD, 0xD480, 0xC7AE, 0xD481, 0xBE8A, 0xD482, 0xC7AF, 0xD483, 0xBE8B, + 0xD484, 0xBE8C, 0xD485, 0xBE8D, 0xD486, 0xBE8E, 0xD487, 0xBE8F, 0xD488, 0xC7B0, 0xD489, 0xC7B1, 0xD48A, 0xBE90, 0xD48B, 0xC7B2, + 0xD48C, 0xBE91, 0xD48D, 0xC7B3, 0xD48E, 0xBE92, 0xD48F, 0xBE93, 0xD490, 0xBE94, 0xD491, 0xBE95, 0xD492, 0xBE96, 0xD493, 0xBE97, + 0xD494, 0xC7B4, 0xD495, 0xBE98, 0xD496, 0xBE99, 0xD497, 0xBE9A, 0xD498, 0xBE9B, 0xD499, 0xBE9C, 0xD49A, 0xBE9D, 0xD49B, 0xBE9E, + 0xD49C, 0xBE9F, 0xD49D, 0xBEA0, 0xD49E, 0xBF41, 0xD49F, 0xBF42, 0xD4A0, 0xBF43, 0xD4A1, 0xBF44, 0xD4A2, 0xBF45, 0xD4A3, 0xBF46, + 0xD4A4, 0xBF47, 0xD4A5, 0xBF48, 0xD4A6, 0xBF49, 0xD4A7, 0xBF4A, 0xD4A8, 0xBF4B, 0xD4A9, 0xC7B5, 0xD4AA, 0xBF4C, 0xD4AB, 0xBF4D, + 0xD4AC, 0xBF4E, 0xD4AD, 0xBF4F, 0xD4AE, 0xBF50, 0xD4AF, 0xBF51, 0xD4B0, 0xBF52, 0xD4B1, 0xBF53, 0xD4B2, 0xBF54, 0xD4B3, 0xBF55, + 0xD4B4, 0xBF56, 0xD4B5, 0xBF57, 0xD4B6, 0xBF58, 0xD4B7, 0xBF59, 0xD4B8, 0xBF5A, 0xD4B9, 0xBF61, 0xD4BA, 0xBF62, 0xD4BB, 0xBF63, + 0xD4BC, 0xBF64, 0xD4BD, 0xBF65, 0xD4BE, 0xBF66, 0xD4BF, 0xBF67, 0xD4C0, 0xBF68, 0xD4C1, 0xBF69, 0xD4C2, 0xBF6A, 0xD4C3, 0xBF6B, + 0xD4C4, 0xBF6C, 0xD4C5, 0xBF6D, 0xD4C6, 0xBF6E, 0xD4C7, 0xBF6F, 0xD4C8, 0xBF70, 0xD4C9, 0xBF71, 0xD4CA, 0xBF72, 0xD4CB, 0xBF73, + 0xD4CC, 0xC7B6, 0xD4CD, 0xBF74, 0xD4CE, 0xBF75, 0xD4CF, 0xBF76, 0xD4D0, 0xC7B7, 0xD4D1, 0xBF77, 0xD4D2, 0xBF78, 0xD4D3, 0xBF79, + 0xD4D4, 0xC7B8, 0xD4D5, 0xBF7A, 0xD4D6, 0xBF81, 0xD4D7, 0xBF82, 0xD4D8, 0xBF83, 0xD4D9, 0xBF84, 0xD4DA, 0xBF85, 0xD4DB, 0xBF86, + 0xD4DC, 0xC7B9, 0xD4DD, 0xBF87, 0xD4DE, 0xBF88, 0xD4DF, 0xC7BA, 0xD4E0, 0xBF89, 0xD4E1, 0xBF8A, 0xD4E2, 0xBF8B, 0xD4E3, 0xBF8C, + 0xD4E4, 0xBF8D, 0xD4E5, 0xBF8E, 0xD4E6, 0xBF8F, 0xD4E7, 0xBF90, 0xD4E8, 0xC7BB, 0xD4E9, 0xBF91, 0xD4EA, 0xBF92, 0xD4EB, 0xBF93, + 0xD4EC, 0xC7BC, 0xD4ED, 0xBF94, 0xD4EE, 0xBF95, 0xD4EF, 0xBF96, 0xD4F0, 0xC7BD, 0xD4F1, 0xBF97, 0xD4F2, 0xBF98, 0xD4F3, 0xBF99, + 0xD4F4, 0xBF9A, 0xD4F5, 0xBF9B, 0xD4F6, 0xBF9C, 0xD4F7, 0xBF9D, 0xD4F8, 0xC7BE, 0xD4F9, 0xBF9E, 0xD4FA, 0xBF9F, 0xD4FB, 0xC7BF, + 0xD4FC, 0xBFA0, 0xD4FD, 0xC7C0, 0xD4FE, 0xC041, 0xD4FF, 0xC042, 0xD500, 0xC043, 0xD501, 0xC044, 0xD502, 0xC045, 0xD503, 0xC046, + 0xD504, 0xC7C1, 0xD505, 0xC047, 0xD506, 0xC048, 0xD507, 0xC049, 0xD508, 0xC7C2, 0xD509, 0xC04A, 0xD50A, 0xC04B, 0xD50B, 0xC04C, + 0xD50C, 0xC7C3, 0xD50D, 0xC04D, 0xD50E, 0xC04E, 0xD50F, 0xC04F, 0xD510, 0xC050, 0xD511, 0xC051, 0xD512, 0xC052, 0xD513, 0xC053, + 0xD514, 0xC7C4, 0xD515, 0xC7C5, 0xD516, 0xC054, 0xD517, 0xC7C6, 0xD518, 0xC055, 0xD519, 0xC056, 0xD51A, 0xC057, 0xD51B, 0xC058, + 0xD51C, 0xC059, 0xD51D, 0xC05A, 0xD51E, 0xC061, 0xD51F, 0xC062, 0xD520, 0xC063, 0xD521, 0xC064, 0xD522, 0xC065, 0xD523, 0xC066, + 0xD524, 0xC067, 0xD525, 0xC068, 0xD526, 0xC069, 0xD527, 0xC06A, 0xD528, 0xC06B, 0xD529, 0xC06C, 0xD52A, 0xC06D, 0xD52B, 0xC06E, + 0xD52C, 0xC06F, 0xD52D, 0xC070, 0xD52E, 0xC071, 0xD52F, 0xC072, 0xD530, 0xC073, 0xD531, 0xC074, 0xD532, 0xC075, 0xD533, 0xC076, + 0xD534, 0xC077, 0xD535, 0xC078, 0xD536, 0xC079, 0xD537, 0xC07A, 0xD538, 0xC081, 0xD539, 0xC082, 0xD53A, 0xC083, 0xD53B, 0xC084, + 0xD53C, 0xC7C7, 0xD53D, 0xC7C8, 0xD53E, 0xC085, 0xD53F, 0xC086, 0xD540, 0xC7C9, 0xD541, 0xC087, 0xD542, 0xC088, 0xD543, 0xC089, + 0xD544, 0xC7CA, 0xD545, 0xC08A, 0xD546, 0xC08B, 0xD547, 0xC08C, 0xD548, 0xC08D, 0xD549, 0xC08E, 0xD54A, 0xC08F, 0xD54B, 0xC090, + 0xD54C, 0xC7CB, 0xD54D, 0xC7CC, 0xD54E, 0xC091, 0xD54F, 0xC7CD, 0xD550, 0xC092, 0xD551, 0xC7CE, 0xD552, 0xC093, 0xD553, 0xC094, + 0xD554, 0xC095, 0xD555, 0xC096, 0xD556, 0xC097, 0xD557, 0xC098, 0xD558, 0xC7CF, 0xD559, 0xC7D0, 0xD55A, 0xC099, 0xD55B, 0xC09A, + 0xD55C, 0xC7D1, 0xD55D, 0xC09B, 0xD55E, 0xC09C, 0xD55F, 0xC09D, 0xD560, 0xC7D2, 0xD561, 0xC09E, 0xD562, 0xC09F, 0xD563, 0xC0A0, + 0xD564, 0xC141, 0xD565, 0xC7D3, 0xD566, 0xC142, 0xD567, 0xC143, 0xD568, 0xC7D4, 0xD569, 0xC7D5, 0xD56A, 0xC144, 0xD56B, 0xC7D6, + 0xD56C, 0xC145, 0xD56D, 0xC7D7, 0xD56E, 0xC146, 0xD56F, 0xC147, 0xD570, 0xC148, 0xD571, 0xC149, 0xD572, 0xC14A, 0xD573, 0xC14B, + 0xD574, 0xC7D8, 0xD575, 0xC7D9, 0xD576, 0xC14C, 0xD577, 0xC14D, 0xD578, 0xC7DA, 0xD579, 0xC14E, 0xD57A, 0xC14F, 0xD57B, 0xC150, + 0xD57C, 0xC7DB, 0xD57D, 0xC151, 0xD57E, 0xC152, 0xD57F, 0xC153, 0xD580, 0xC154, 0xD581, 0xC155, 0xD582, 0xC156, 0xD583, 0xC157, + 0xD584, 0xC7DC, 0xD585, 0xC7DD, 0xD586, 0xC158, 0xD587, 0xC7DE, 0xD588, 0xC7DF, 0xD589, 0xC7E0, 0xD58A, 0xC159, 0xD58B, 0xC15A, + 0xD58C, 0xC161, 0xD58D, 0xC162, 0xD58E, 0xC163, 0xD58F, 0xC164, 0xD590, 0xC7E1, 0xD591, 0xC165, 0xD592, 0xC166, 0xD593, 0xC167, + 0xD594, 0xC168, 0xD595, 0xC169, 0xD596, 0xC16A, 0xD597, 0xC16B, 0xD598, 0xC16C, 0xD599, 0xC16D, 0xD59A, 0xC16E, 0xD59B, 0xC16F, + 0xD59C, 0xC170, 0xD59D, 0xC171, 0xD59E, 0xC172, 0xD59F, 0xC173, 0xD5A0, 0xC174, 0xD5A1, 0xC175, 0xD5A2, 0xC176, 0xD5A3, 0xC177, + 0xD5A4, 0xC178, 0xD5A5, 0xC7E2, 0xD5A6, 0xC179, 0xD5A7, 0xC17A, 0xD5A8, 0xC181, 0xD5A9, 0xC182, 0xD5AA, 0xC183, 0xD5AB, 0xC184, + 0xD5AC, 0xC185, 0xD5AD, 0xC186, 0xD5AE, 0xC187, 0xD5AF, 0xC188, 0xD5B0, 0xC189, 0xD5B1, 0xC18A, 0xD5B2, 0xC18B, 0xD5B3, 0xC18C, + 0xD5B4, 0xC18D, 0xD5B5, 0xC18E, 0xD5B6, 0xC18F, 0xD5B7, 0xC190, 0xD5B8, 0xC191, 0xD5B9, 0xC192, 0xD5BA, 0xC193, 0xD5BB, 0xC194, + 0xD5BC, 0xC195, 0xD5BD, 0xC196, 0xD5BE, 0xC197, 0xD5BF, 0xC198, 0xD5C0, 0xC199, 0xD5C1, 0xC19A, 0xD5C2, 0xC19B, 0xD5C3, 0xC19C, + 0xD5C4, 0xC19D, 0xD5C5, 0xC19E, 0xD5C6, 0xC19F, 0xD5C7, 0xC1A0, 0xD5C8, 0xC7E3, 0xD5C9, 0xC7E4, 0xD5CA, 0xC241, 0xD5CB, 0xC242, + 0xD5CC, 0xC7E5, 0xD5CD, 0xC243, 0xD5CE, 0xC244, 0xD5CF, 0xC245, 0xD5D0, 0xC7E6, 0xD5D1, 0xC246, 0xD5D2, 0xC7E7, 0xD5D3, 0xC247, + 0xD5D4, 0xC248, 0xD5D5, 0xC249, 0xD5D6, 0xC24A, 0xD5D7, 0xC24B, 0xD5D8, 0xC7E8, 0xD5D9, 0xC7E9, 0xD5DA, 0xC24C, 0xD5DB, 0xC7EA, + 0xD5DC, 0xC24D, 0xD5DD, 0xC7EB, 0xD5DE, 0xC24E, 0xD5DF, 0xC24F, 0xD5E0, 0xC250, 0xD5E1, 0xC251, 0xD5E2, 0xC252, 0xD5E3, 0xC253, + 0xD5E4, 0xC7EC, 0xD5E5, 0xC7ED, 0xD5E6, 0xC254, 0xD5E7, 0xC255, 0xD5E8, 0xC7EE, 0xD5E9, 0xC256, 0xD5EA, 0xC257, 0xD5EB, 0xC258, + 0xD5EC, 0xC7EF, 0xD5ED, 0xC259, 0xD5EE, 0xC25A, 0xD5EF, 0xC261, 0xD5F0, 0xC262, 0xD5F1, 0xC263, 0xD5F2, 0xC264, 0xD5F3, 0xC265, + 0xD5F4, 0xC7F0, 0xD5F5, 0xC7F1, 0xD5F6, 0xC266, 0xD5F7, 0xC7F2, 0xD5F8, 0xC267, 0xD5F9, 0xC7F3, 0xD5FA, 0xC268, 0xD5FB, 0xC269, + 0xD5FC, 0xC26A, 0xD5FD, 0xC26B, 0xD5FE, 0xC26C, 0xD5FF, 0xC26D, 0xD600, 0xC7F4, 0xD601, 0xC7F5, 0xD602, 0xC26E, 0xD603, 0xC26F, + 0xD604, 0xC7F6, 0xD605, 0xC270, 0xD606, 0xC271, 0xD607, 0xC272, 0xD608, 0xC7F7, 0xD609, 0xC273, 0xD60A, 0xC274, 0xD60B, 0xC275, + 0xD60C, 0xC276, 0xD60D, 0xC277, 0xD60E, 0xC278, 0xD60F, 0xC279, 0xD610, 0xC7F8, 0xD611, 0xC7F9, 0xD612, 0xC27A, 0xD613, 0xC7FA, + 0xD614, 0xC7FB, 0xD615, 0xC7FC, 0xD616, 0xC281, 0xD617, 0xC282, 0xD618, 0xC283, 0xD619, 0xC284, 0xD61A, 0xC285, 0xD61B, 0xC286, + 0xD61C, 0xC7FD, 0xD61D, 0xC287, 0xD61E, 0xC288, 0xD61F, 0xC289, 0xD620, 0xC7FE, 0xD621, 0xC28A, 0xD622, 0xC28B, 0xD623, 0xC28C, + 0xD624, 0xC8A1, 0xD625, 0xC28D, 0xD626, 0xC28E, 0xD627, 0xC28F, 0xD628, 0xC290, 0xD629, 0xC291, 0xD62A, 0xC292, 0xD62B, 0xC293, + 0xD62C, 0xC294, 0xD62D, 0xC8A2, 0xD62E, 0xC295, 0xD62F, 0xC296, 0xD630, 0xC297, 0xD631, 0xC298, 0xD632, 0xC299, 0xD633, 0xC29A, + 0xD634, 0xC29B, 0xD635, 0xC29C, 0xD636, 0xC29D, 0xD637, 0xC29E, 0xD638, 0xC8A3, 0xD639, 0xC8A4, 0xD63A, 0xC29F, 0xD63B, 0xC2A0, + 0xD63C, 0xC8A5, 0xD63D, 0xC341, 0xD63E, 0xC342, 0xD63F, 0xC343, 0xD640, 0xC8A6, 0xD641, 0xC344, 0xD642, 0xC345, 0xD643, 0xC346, + 0xD644, 0xC347, 0xD645, 0xC8A7, 0xD646, 0xC348, 0xD647, 0xC349, 0xD648, 0xC8A8, 0xD649, 0xC8A9, 0xD64A, 0xC34A, 0xD64B, 0xC8AA, + 0xD64C, 0xC34B, 0xD64D, 0xC8AB, 0xD64E, 0xC34C, 0xD64F, 0xC34D, 0xD650, 0xC34E, 0xD651, 0xC8AC, 0xD652, 0xC34F, 0xD653, 0xC350, + 0xD654, 0xC8AD, 0xD655, 0xC8AE, 0xD656, 0xC351, 0xD657, 0xC352, 0xD658, 0xC8AF, 0xD659, 0xC353, 0xD65A, 0xC354, 0xD65B, 0xC355, + 0xD65C, 0xC8B0, 0xD65D, 0xC356, 0xD65E, 0xC357, 0xD65F, 0xC358, 0xD660, 0xC359, 0xD661, 0xC35A, 0xD662, 0xC361, 0xD663, 0xC362, + 0xD664, 0xC363, 0xD665, 0xC364, 0xD666, 0xC365, 0xD667, 0xC8B1, 0xD668, 0xC366, 0xD669, 0xC8B2, 0xD66A, 0xC367, 0xD66B, 0xC368, + 0xD66C, 0xC369, 0xD66D, 0xC36A, 0xD66E, 0xC36B, 0xD66F, 0xC36C, 0xD670, 0xC8B3, 0xD671, 0xC8B4, 0xD672, 0xC36D, 0xD673, 0xC36E, + 0xD674, 0xC8B5, 0xD675, 0xC36F, 0xD676, 0xC370, 0xD677, 0xC371, 0xD678, 0xC372, 0xD679, 0xC373, 0xD67A, 0xC374, 0xD67B, 0xC375, + 0xD67C, 0xC376, 0xD67D, 0xC377, 0xD67E, 0xC378, 0xD67F, 0xC379, 0xD680, 0xC37A, 0xD681, 0xC381, 0xD682, 0xC382, 0xD683, 0xC8B6, + 0xD684, 0xC383, 0xD685, 0xC8B7, 0xD686, 0xC384, 0xD687, 0xC385, 0xD688, 0xC386, 0xD689, 0xC387, 0xD68A, 0xC388, 0xD68B, 0xC389, + 0xD68C, 0xC8B8, 0xD68D, 0xC8B9, 0xD68E, 0xC38A, 0xD68F, 0xC38B, 0xD690, 0xC8BA, 0xD691, 0xC38C, 0xD692, 0xC38D, 0xD693, 0xC38E, + 0xD694, 0xC8BB, 0xD695, 0xC38F, 0xD696, 0xC390, 0xD697, 0xC391, 0xD698, 0xC392, 0xD699, 0xC393, 0xD69A, 0xC394, 0xD69B, 0xC395, + 0xD69C, 0xC396, 0xD69D, 0xC8BC, 0xD69E, 0xC397, 0xD69F, 0xC8BD, 0xD6A0, 0xC398, 0xD6A1, 0xC8BE, 0xD6A2, 0xC399, 0xD6A3, 0xC39A, + 0xD6A4, 0xC39B, 0xD6A5, 0xC39C, 0xD6A6, 0xC39D, 0xD6A7, 0xC39E, 0xD6A8, 0xC8BF, 0xD6A9, 0xC39F, 0xD6AA, 0xC3A0, 0xD6AB, 0xC441, + 0xD6AC, 0xC8C0, 0xD6AD, 0xC442, 0xD6AE, 0xC443, 0xD6AF, 0xC444, 0xD6B0, 0xC8C1, 0xD6B1, 0xC445, 0xD6B2, 0xC446, 0xD6B3, 0xC447, + 0xD6B4, 0xC448, 0xD6B5, 0xC449, 0xD6B6, 0xC44A, 0xD6B7, 0xC44B, 0xD6B8, 0xC44C, 0xD6B9, 0xC8C2, 0xD6BA, 0xC44D, 0xD6BB, 0xC8C3, + 0xD6BC, 0xC44E, 0xD6BD, 0xC44F, 0xD6BE, 0xC450, 0xD6BF, 0xC451, 0xD6C0, 0xC452, 0xD6C1, 0xC453, 0xD6C2, 0xC454, 0xD6C3, 0xC455, + 0xD6C4, 0xC8C4, 0xD6C5, 0xC8C5, 0xD6C6, 0xC456, 0xD6C7, 0xC457, 0xD6C8, 0xC8C6, 0xD6C9, 0xC458, 0xD6CA, 0xC459, 0xD6CB, 0xC45A, + 0xD6CC, 0xC8C7, 0xD6CD, 0xC461, 0xD6CE, 0xC462, 0xD6CF, 0xC463, 0xD6D0, 0xC464, 0xD6D1, 0xC8C8, 0xD6D2, 0xC465, 0xD6D3, 0xC466, + 0xD6D4, 0xC8C9, 0xD6D5, 0xC467, 0xD6D6, 0xC468, 0xD6D7, 0xC8CA, 0xD6D8, 0xC469, 0xD6D9, 0xC8CB, 0xD6DA, 0xC46A, 0xD6DB, 0xC46B, + 0xD6DC, 0xC46C, 0xD6DD, 0xC46D, 0xD6DE, 0xC46E, 0xD6DF, 0xC46F, 0xD6E0, 0xC8CC, 0xD6E1, 0xC470, 0xD6E2, 0xC471, 0xD6E3, 0xC472, + 0xD6E4, 0xC8CD, 0xD6E5, 0xC473, 0xD6E6, 0xC474, 0xD6E7, 0xC475, 0xD6E8, 0xC8CE, 0xD6E9, 0xC476, 0xD6EA, 0xC477, 0xD6EB, 0xC478, + 0xD6EC, 0xC479, 0xD6ED, 0xC47A, 0xD6EE, 0xC481, 0xD6EF, 0xC482, 0xD6F0, 0xC8CF, 0xD6F1, 0xC483, 0xD6F2, 0xC484, 0xD6F3, 0xC485, + 0xD6F4, 0xC486, 0xD6F5, 0xC8D0, 0xD6F6, 0xC487, 0xD6F7, 0xC488, 0xD6F8, 0xC489, 0xD6F9, 0xC48A, 0xD6FA, 0xC48B, 0xD6FB, 0xC48C, + 0xD6FC, 0xC8D1, 0xD6FD, 0xC8D2, 0xD6FE, 0xC48D, 0xD6FF, 0xC48E, 0xD700, 0xC8D3, 0xD701, 0xC48F, 0xD702, 0xC490, 0xD703, 0xC491, + 0xD704, 0xC8D4, 0xD705, 0xC492, 0xD706, 0xC493, 0xD707, 0xC494, 0xD708, 0xC495, 0xD709, 0xC496, 0xD70A, 0xC497, 0xD70B, 0xC498, + 0xD70C, 0xC499, 0xD70D, 0xC49A, 0xD70E, 0xC49B, 0xD70F, 0xC49C, 0xD710, 0xC49D, 0xD711, 0xC8D5, 0xD712, 0xC49E, 0xD713, 0xC49F, + 0xD714, 0xC4A0, 0xD715, 0xC541, 0xD716, 0xC542, 0xD717, 0xC543, 0xD718, 0xC8D6, 0xD719, 0xC8D7, 0xD71A, 0xC544, 0xD71B, 0xC545, + 0xD71C, 0xC8D8, 0xD71D, 0xC546, 0xD71E, 0xC547, 0xD71F, 0xC548, 0xD720, 0xC8D9, 0xD721, 0xC549, 0xD722, 0xC54A, 0xD723, 0xC54B, + 0xD724, 0xC54C, 0xD725, 0xC54D, 0xD726, 0xC54E, 0xD727, 0xC54F, 0xD728, 0xC8DA, 0xD729, 0xC8DB, 0xD72A, 0xC550, 0xD72B, 0xC8DC, + 0xD72C, 0xC551, 0xD72D, 0xC8DD, 0xD72E, 0xC552, 0xD72F, 0xC553, 0xD730, 0xC554, 0xD731, 0xC555, 0xD732, 0xC556, 0xD733, 0xC557, + 0xD734, 0xC8DE, 0xD735, 0xC8DF, 0xD736, 0xC558, 0xD737, 0xC559, 0xD738, 0xC8E0, 0xD739, 0xC55A, 0xD73A, 0xC561, 0xD73B, 0xC562, + 0xD73C, 0xC8E1, 0xD73D, 0xC563, 0xD73E, 0xC564, 0xD73F, 0xC565, 0xD740, 0xC566, 0xD741, 0xC567, 0xD742, 0xC568, 0xD743, 0xC569, + 0xD744, 0xC8E2, 0xD745, 0xC56A, 0xD746, 0xC56B, 0xD747, 0xC8E3, 0xD748, 0xC56C, 0xD749, 0xC8E4, 0xD74A, 0xC56D, 0xD74B, 0xC56E, + 0xD74C, 0xC56F, 0xD74D, 0xC570, 0xD74E, 0xC571, 0xD74F, 0xC572, 0xD750, 0xC8E5, 0xD751, 0xC8E6, 0xD752, 0xC573, 0xD753, 0xC574, + 0xD754, 0xC8E7, 0xD755, 0xC575, 0xD756, 0xC8E8, 0xD757, 0xC8E9, 0xD758, 0xC8EA, 0xD759, 0xC8EB, 0xD75A, 0xC576, 0xD75B, 0xC577, + 0xD75C, 0xC578, 0xD75D, 0xC579, 0xD75E, 0xC57A, 0xD75F, 0xC581, 0xD760, 0xC8EC, 0xD761, 0xC8ED, 0xD762, 0xC582, 0xD763, 0xC8EE, + 0xD764, 0xC583, 0xD765, 0xC8EF, 0xD766, 0xC584, 0xD767, 0xC585, 0xD768, 0xC586, 0xD769, 0xC8F0, 0xD76A, 0xC587, 0xD76B, 0xC588, + 0xD76C, 0xC8F1, 0xD76D, 0xC589, 0xD76E, 0xC58A, 0xD76F, 0xC58B, 0xD770, 0xC8F2, 0xD771, 0xC58C, 0xD772, 0xC58D, 0xD773, 0xC58E, + 0xD774, 0xC8F3, 0xD775, 0xC58F, 0xD776, 0xC590, 0xD777, 0xC591, 0xD778, 0xC592, 0xD779, 0xC593, 0xD77A, 0xC594, 0xD77B, 0xC595, + 0xD77C, 0xC8F4, 0xD77D, 0xC8F5, 0xD77E, 0xC596, 0xD77F, 0xC597, 0xD780, 0xC598, 0xD781, 0xC8F6, 0xD782, 0xC599, 0xD783, 0xC59A, + 0xD784, 0xC59B, 0xD785, 0xC59C, 0xD786, 0xC59D, 0xD787, 0xC59E, 0xD788, 0xC8F7, 0xD789, 0xC8F8, 0xD78A, 0xC59F, 0xD78B, 0xC5A0, + 0xD78C, 0xC8F9, 0xD78D, 0xC641, 0xD78E, 0xC642, 0xD78F, 0xC643, 0xD790, 0xC8FA, 0xD791, 0xC644, 0xD792, 0xC645, 0xD793, 0xC646, + 0xD794, 0xC647, 0xD795, 0xC648, 0xD796, 0xC649, 0xD797, 0xC64A, 0xD798, 0xC8FB, 0xD799, 0xC8FC, 0xD79A, 0xC64B, 0xD79B, 0xC8FD, + 0xD79C, 0xC64C, 0xD79D, 0xC8FE, 0xD79E, 0xC64D, 0xD79F, 0xC64E, 0xD7A0, 0xC64F, 0xD7A1, 0xC650, 0xD7A2, 0xC651, 0xD7A3, 0xC652, + 0xF900, 0xCBD0, 0xF901, 0xCBD6, 0xF902, 0xCBE7, 0xF903, 0xCDCF, 0xF904, 0xCDE8, 0xF905, 0xCEAD, 0xF906, 0xCFFB, 0xF907, 0xD0A2, + 0xF908, 0xD0B8, 0xF909, 0xD0D0, 0xF90A, 0xD0DD, 0xF90B, 0xD1D4, 0xF90C, 0xD1D5, 0xF90D, 0xD1D8, 0xF90E, 0xD1DB, 0xF90F, 0xD1DC, + 0xF910, 0xD1DD, 0xF911, 0xD1DE, 0xF912, 0xD1DF, 0xF913, 0xD1E0, 0xF914, 0xD1E2, 0xF915, 0xD1E3, 0xF916, 0xD1E4, 0xF917, 0xD1E5, + 0xF918, 0xD1E6, 0xF919, 0xD1E8, 0xF91A, 0xD1E9, 0xF91B, 0xD1EA, 0xF91C, 0xD1EB, 0xF91D, 0xD1ED, 0xF91E, 0xD1EF, 0xF91F, 0xD1F0, + 0xF920, 0xD1F2, 0xF921, 0xD1F6, 0xF922, 0xD1FA, 0xF923, 0xD1FC, 0xF924, 0xD1FD, 0xF925, 0xD1FE, 0xF926, 0xD2A2, 0xF927, 0xD2A3, + 0xF928, 0xD2A7, 0xF929, 0xD2A8, 0xF92A, 0xD2A9, 0xF92B, 0xD2AA, 0xF92C, 0xD2AB, 0xF92D, 0xD2AD, 0xF92E, 0xD2B2, 0xF92F, 0xD2BE, + 0xF930, 0xD2C2, 0xF931, 0xD2C3, 0xF932, 0xD2C4, 0xF933, 0xD2C6, 0xF934, 0xD2C7, 0xF935, 0xD2C8, 0xF936, 0xD2C9, 0xF937, 0xD2CA, + 0xF938, 0xD2CB, 0xF939, 0xD2CD, 0xF93A, 0xD2CE, 0xF93B, 0xD2CF, 0xF93C, 0xD2D0, 0xF93D, 0xD2D1, 0xF93E, 0xD2D2, 0xF93F, 0xD2D3, + 0xF940, 0xD2D4, 0xF941, 0xD2D5, 0xF942, 0xD2D6, 0xF943, 0xD2D7, 0xF944, 0xD2D9, 0xF945, 0xD2DA, 0xF946, 0xD2DE, 0xF947, 0xD2DF, + 0xF948, 0xD2E1, 0xF949, 0xD2E2, 0xF94A, 0xD2E4, 0xF94B, 0xD2E5, 0xF94C, 0xD2E6, 0xF94D, 0xD2E7, 0xF94E, 0xD2E8, 0xF94F, 0xD2E9, + 0xF950, 0xD2EA, 0xF951, 0xD2EB, 0xF952, 0xD2F0, 0xF953, 0xD2F1, 0xF954, 0xD2F2, 0xF955, 0xD2F3, 0xF956, 0xD2F4, 0xF957, 0xD2F5, + 0xF958, 0xD2F7, 0xF959, 0xD2F8, 0xF95A, 0xD4E6, 0xF95B, 0xD4FC, 0xF95C, 0xD5A5, 0xF95D, 0xD5AB, 0xF95E, 0xD5AE, 0xF95F, 0xD6B8, + 0xF960, 0xD6CD, 0xF961, 0xD7CB, 0xF962, 0xD7E4, 0xF963, 0xDBC5, 0xF964, 0xDBE4, 0xF965, 0xDCA5, 0xF966, 0xDDA5, 0xF967, 0xDDD5, + 0xF968, 0xDDF4, 0xF969, 0xDEFC, 0xF96A, 0xDEFE, 0xF96B, 0xDFB3, 0xF96C, 0xDFE1, 0xF96D, 0xDFE8, 0xF96E, 0xE0F1, 0xF96F, 0xE1AD, + 0xF970, 0xE1ED, 0xF971, 0xE3F5, 0xF972, 0xE4A1, 0xF973, 0xE4A9, 0xF974, 0xE5AE, 0xF975, 0xE5B1, 0xF976, 0xE5B2, 0xF977, 0xE5B9, + 0xF978, 0xE5BB, 0xF979, 0xE5BC, 0xF97A, 0xE5C4, 0xF97B, 0xE5CE, 0xF97C, 0xE5D0, 0xF97D, 0xE5D2, 0xF97E, 0xE5D6, 0xF97F, 0xE5FA, + 0xF980, 0xE5FB, 0xF981, 0xE5FC, 0xF982, 0xE5FE, 0xF983, 0xE6A1, 0xF984, 0xE6A4, 0xF985, 0xE6A7, 0xF986, 0xE6AD, 0xF987, 0xE6AF, + 0xF988, 0xE6B0, 0xF989, 0xE6B1, 0xF98A, 0xE6B3, 0xF98B, 0xE6B7, 0xF98C, 0xE6B8, 0xF98D, 0xE6BC, 0xF98E, 0xE6C4, 0xF98F, 0xE6C6, + 0xF990, 0xE6C7, 0xF991, 0xE6CA, 0xF992, 0xE6D2, 0xF993, 0xE6D6, 0xF994, 0xE6D9, 0xF995, 0xE6DC, 0xF996, 0xE6DF, 0xF997, 0xE6E1, + 0xF998, 0xE6E4, 0xF999, 0xE6E5, 0xF99A, 0xE6E6, 0xF99B, 0xE6E8, 0xF99C, 0xE6EA, 0xF99D, 0xE6EB, 0xF99E, 0xE6EC, 0xF99F, 0xE6EF, + 0xF9A0, 0xE6F1, 0xF9A1, 0xE6F2, 0xF9A2, 0xE6F5, 0xF9A3, 0xE6F6, 0xF9A4, 0xE6F7, 0xF9A5, 0xE6F9, 0xF9A6, 0xE7A1, 0xF9A7, 0xE7A6, + 0xF9A8, 0xE7A9, 0xF9A9, 0xE7AA, 0xF9AA, 0xE7AC, 0xF9AB, 0xE7AD, 0xF9AC, 0xE7B0, 0xF9AD, 0xE7BF, 0xF9AE, 0xE7C1, 0xF9AF, 0xE7C6, + 0xF9B0, 0xE7C7, 0xF9B1, 0xE7CB, 0xF9B2, 0xE7CD, 0xF9B3, 0xE7CF, 0xF9B4, 0xE7D0, 0xF9B5, 0xE7D3, 0xF9B6, 0xE7DF, 0xF9B7, 0xE7E4, + 0xF9B8, 0xE7E6, 0xF9B9, 0xE7F7, 0xF9BA, 0xE8E7, 0xF9BB, 0xE8E8, 0xF9BC, 0xE8F0, 0xF9BD, 0xE8F1, 0xF9BE, 0xE8F7, 0xF9BF, 0xE8F9, + 0xF9C0, 0xE8FB, 0xF9C1, 0xE8FE, 0xF9C2, 0xE9A7, 0xF9C3, 0xE9AC, 0xF9C4, 0xE9CC, 0xF9C5, 0xE9F7, 0xF9C6, 0xEAC1, 0xF9C7, 0xEAE5, + 0xF9C8, 0xEAF4, 0xF9C9, 0xEAF7, 0xF9CA, 0xEAFC, 0xF9CB, 0xEAFE, 0xF9CC, 0xEBA4, 0xF9CD, 0xEBA7, 0xF9CE, 0xEBA9, 0xF9CF, 0xEBAA, + 0xF9D0, 0xEBBA, 0xF9D1, 0xEBBB, 0xF9D2, 0xEBBD, 0xF9D3, 0xEBC1, 0xF9D4, 0xEBC2, 0xF9D5, 0xEBC6, 0xF9D6, 0xEBC7, 0xF9D7, 0xEBCC, + 0xF9D8, 0xEBCF, 0xF9D9, 0xEBD0, 0xF9DA, 0xEBD1, 0xF9DB, 0xEBD2, 0xF9DC, 0xEBD8, 0xF9DD, 0xECA6, 0xF9DE, 0xECA7, 0xF9DF, 0xECAA, + 0xF9E0, 0xECAF, 0xF9E1, 0xECB0, 0xF9E2, 0xECB1, 0xF9E3, 0xECB2, 0xF9E4, 0xECB5, 0xF9E5, 0xECB8, 0xF9E6, 0xECBA, 0xF9E7, 0xECC0, + 0xF9E8, 0xECC1, 0xF9E9, 0xECC5, 0xF9EA, 0xECC6, 0xF9EB, 0xECC9, 0xF9EC, 0xECCA, 0xF9ED, 0xECD5, 0xF9EE, 0xECDD, 0xF9EF, 0xECDE, + 0xF9F0, 0xECE1, 0xF9F1, 0xECE4, 0xF9F2, 0xECE7, 0xF9F3, 0xECE8, 0xF9F4, 0xECF7, 0xF9F5, 0xECF8, 0xF9F6, 0xECFA, 0xF9F7, 0xEDA1, + 0xF9F8, 0xEDA2, 0xF9F9, 0xEDA3, 0xF9FA, 0xEDEE, 0xF9FB, 0xEEDB, 0xF9FC, 0xF2BD, 0xF9FD, 0xF2FA, 0xF9FE, 0xF3B1, 0xF9FF, 0xF4A7, + 0xFA00, 0xF4EE, 0xFA01, 0xF6F4, 0xFA02, 0xF6F6, 0xFA03, 0xF7B8, 0xFA04, 0xF7C8, 0xFA05, 0xF7D3, 0xFA06, 0xF8DB, 0xFA07, 0xF8F0, + 0xFA08, 0xFAA1, 0xFA09, 0xFAA2, 0xFA0A, 0xFAE6, 0xFA0B, 0xFCA9, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA3A4, + 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, + 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, + 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, + 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, + 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, + 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, + 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA1AC, + 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, + 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, + 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, + 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, + 0xFF5D, 0xA3FD, 0xFF5E, 0xA2A6, 0xFFE0, 0xA1CB, 0xFFE1, 0xA1CC, 0xFFE2, 0xA1FE, 0xFFE3, 0xA3FE, 0xFFE5, 0xA1CD, 0xFFE6, 0xA3DC, + 0, 0 +}; + +static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ + 0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E, + 0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25, + 0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32, + 0x8159, 0xAC33, 0x815A, 0xAC34, 0x8161, 0xAC35, 0x8162, 0xAC36, 0x8163, 0xAC37, 0x8164, 0xAC3A, 0x8165, 0xAC3B, 0x8166, 0xAC3D, + 0x8167, 0xAC3E, 0x8168, 0xAC3F, 0x8169, 0xAC41, 0x816A, 0xAC42, 0x816B, 0xAC43, 0x816C, 0xAC44, 0x816D, 0xAC45, 0x816E, 0xAC46, + 0x816F, 0xAC47, 0x8170, 0xAC48, 0x8171, 0xAC49, 0x8172, 0xAC4A, 0x8173, 0xAC4C, 0x8174, 0xAC4E, 0x8175, 0xAC4F, 0x8176, 0xAC50, + 0x8177, 0xAC51, 0x8178, 0xAC52, 0x8179, 0xAC53, 0x817A, 0xAC55, 0x8181, 0xAC56, 0x8182, 0xAC57, 0x8183, 0xAC59, 0x8184, 0xAC5A, + 0x8185, 0xAC5B, 0x8186, 0xAC5D, 0x8187, 0xAC5E, 0x8188, 0xAC5F, 0x8189, 0xAC60, 0x818A, 0xAC61, 0x818B, 0xAC62, 0x818C, 0xAC63, + 0x818D, 0xAC64, 0x818E, 0xAC65, 0x818F, 0xAC66, 0x8190, 0xAC67, 0x8191, 0xAC68, 0x8192, 0xAC69, 0x8193, 0xAC6A, 0x8194, 0xAC6B, + 0x8195, 0xAC6C, 0x8196, 0xAC6D, 0x8197, 0xAC6E, 0x8198, 0xAC6F, 0x8199, 0xAC72, 0x819A, 0xAC73, 0x819B, 0xAC75, 0x819C, 0xAC76, + 0x819D, 0xAC79, 0x819E, 0xAC7B, 0x819F, 0xAC7C, 0x81A0, 0xAC7D, 0x81A1, 0xAC7E, 0x81A2, 0xAC7F, 0x81A3, 0xAC82, 0x81A4, 0xAC87, + 0x81A5, 0xAC88, 0x81A6, 0xAC8D, 0x81A7, 0xAC8E, 0x81A8, 0xAC8F, 0x81A9, 0xAC91, 0x81AA, 0xAC92, 0x81AB, 0xAC93, 0x81AC, 0xAC95, + 0x81AD, 0xAC96, 0x81AE, 0xAC97, 0x81AF, 0xAC98, 0x81B0, 0xAC99, 0x81B1, 0xAC9A, 0x81B2, 0xAC9B, 0x81B3, 0xAC9E, 0x81B4, 0xACA2, + 0x81B5, 0xACA3, 0x81B6, 0xACA4, 0x81B7, 0xACA5, 0x81B8, 0xACA6, 0x81B9, 0xACA7, 0x81BA, 0xACAB, 0x81BB, 0xACAD, 0x81BC, 0xACAE, + 0x81BD, 0xACB1, 0x81BE, 0xACB2, 0x81BF, 0xACB3, 0x81C0, 0xACB4, 0x81C1, 0xACB5, 0x81C2, 0xACB6, 0x81C3, 0xACB7, 0x81C4, 0xACBA, + 0x81C5, 0xACBE, 0x81C6, 0xACBF, 0x81C7, 0xACC0, 0x81C8, 0xACC2, 0x81C9, 0xACC3, 0x81CA, 0xACC5, 0x81CB, 0xACC6, 0x81CC, 0xACC7, + 0x81CD, 0xACC9, 0x81CE, 0xACCA, 0x81CF, 0xACCB, 0x81D0, 0xACCD, 0x81D1, 0xACCE, 0x81D2, 0xACCF, 0x81D3, 0xACD0, 0x81D4, 0xACD1, + 0x81D5, 0xACD2, 0x81D6, 0xACD3, 0x81D7, 0xACD4, 0x81D8, 0xACD6, 0x81D9, 0xACD8, 0x81DA, 0xACD9, 0x81DB, 0xACDA, 0x81DC, 0xACDB, + 0x81DD, 0xACDC, 0x81DE, 0xACDD, 0x81DF, 0xACDE, 0x81E0, 0xACDF, 0x81E1, 0xACE2, 0x81E2, 0xACE3, 0x81E3, 0xACE5, 0x81E4, 0xACE6, + 0x81E5, 0xACE9, 0x81E6, 0xACEB, 0x81E7, 0xACED, 0x81E8, 0xACEE, 0x81E9, 0xACF2, 0x81EA, 0xACF4, 0x81EB, 0xACF7, 0x81EC, 0xACF8, + 0x81ED, 0xACF9, 0x81EE, 0xACFA, 0x81EF, 0xACFB, 0x81F0, 0xACFE, 0x81F1, 0xACFF, 0x81F2, 0xAD01, 0x81F3, 0xAD02, 0x81F4, 0xAD03, + 0x81F5, 0xAD05, 0x81F6, 0xAD07, 0x81F7, 0xAD08, 0x81F8, 0xAD09, 0x81F9, 0xAD0A, 0x81FA, 0xAD0B, 0x81FB, 0xAD0E, 0x81FC, 0xAD10, + 0x81FD, 0xAD12, 0x81FE, 0xAD13, 0x8241, 0xAD14, 0x8242, 0xAD15, 0x8243, 0xAD16, 0x8244, 0xAD17, 0x8245, 0xAD19, 0x8246, 0xAD1A, + 0x8247, 0xAD1B, 0x8248, 0xAD1D, 0x8249, 0xAD1E, 0x824A, 0xAD1F, 0x824B, 0xAD21, 0x824C, 0xAD22, 0x824D, 0xAD23, 0x824E, 0xAD24, + 0x824F, 0xAD25, 0x8250, 0xAD26, 0x8251, 0xAD27, 0x8252, 0xAD28, 0x8253, 0xAD2A, 0x8254, 0xAD2B, 0x8255, 0xAD2E, 0x8256, 0xAD2F, + 0x8257, 0xAD30, 0x8258, 0xAD31, 0x8259, 0xAD32, 0x825A, 0xAD33, 0x8261, 0xAD36, 0x8262, 0xAD37, 0x8263, 0xAD39, 0x8264, 0xAD3A, + 0x8265, 0xAD3B, 0x8266, 0xAD3D, 0x8267, 0xAD3E, 0x8268, 0xAD3F, 0x8269, 0xAD40, 0x826A, 0xAD41, 0x826B, 0xAD42, 0x826C, 0xAD43, + 0x826D, 0xAD46, 0x826E, 0xAD48, 0x826F, 0xAD4A, 0x8270, 0xAD4B, 0x8271, 0xAD4C, 0x8272, 0xAD4D, 0x8273, 0xAD4E, 0x8274, 0xAD4F, + 0x8275, 0xAD51, 0x8276, 0xAD52, 0x8277, 0xAD53, 0x8278, 0xAD55, 0x8279, 0xAD56, 0x827A, 0xAD57, 0x8281, 0xAD59, 0x8282, 0xAD5A, + 0x8283, 0xAD5B, 0x8284, 0xAD5C, 0x8285, 0xAD5D, 0x8286, 0xAD5E, 0x8287, 0xAD5F, 0x8288, 0xAD60, 0x8289, 0xAD62, 0x828A, 0xAD64, + 0x828B, 0xAD65, 0x828C, 0xAD66, 0x828D, 0xAD67, 0x828E, 0xAD68, 0x828F, 0xAD69, 0x8290, 0xAD6A, 0x8291, 0xAD6B, 0x8292, 0xAD6E, + 0x8293, 0xAD6F, 0x8294, 0xAD71, 0x8295, 0xAD72, 0x8296, 0xAD77, 0x8297, 0xAD78, 0x8298, 0xAD79, 0x8299, 0xAD7A, 0x829A, 0xAD7E, + 0x829B, 0xAD80, 0x829C, 0xAD83, 0x829D, 0xAD84, 0x829E, 0xAD85, 0x829F, 0xAD86, 0x82A0, 0xAD87, 0x82A1, 0xAD8A, 0x82A2, 0xAD8B, + 0x82A3, 0xAD8D, 0x82A4, 0xAD8E, 0x82A5, 0xAD8F, 0x82A6, 0xAD91, 0x82A7, 0xAD92, 0x82A8, 0xAD93, 0x82A9, 0xAD94, 0x82AA, 0xAD95, + 0x82AB, 0xAD96, 0x82AC, 0xAD97, 0x82AD, 0xAD98, 0x82AE, 0xAD99, 0x82AF, 0xAD9A, 0x82B0, 0xAD9B, 0x82B1, 0xAD9E, 0x82B2, 0xAD9F, + 0x82B3, 0xADA0, 0x82B4, 0xADA1, 0x82B5, 0xADA2, 0x82B6, 0xADA3, 0x82B7, 0xADA5, 0x82B8, 0xADA6, 0x82B9, 0xADA7, 0x82BA, 0xADA8, + 0x82BB, 0xADA9, 0x82BC, 0xADAA, 0x82BD, 0xADAB, 0x82BE, 0xADAC, 0x82BF, 0xADAD, 0x82C0, 0xADAE, 0x82C1, 0xADAF, 0x82C2, 0xADB0, + 0x82C3, 0xADB1, 0x82C4, 0xADB2, 0x82C5, 0xADB3, 0x82C6, 0xADB4, 0x82C7, 0xADB5, 0x82C8, 0xADB6, 0x82C9, 0xADB8, 0x82CA, 0xADB9, + 0x82CB, 0xADBA, 0x82CC, 0xADBB, 0x82CD, 0xADBC, 0x82CE, 0xADBD, 0x82CF, 0xADBE, 0x82D0, 0xADBF, 0x82D1, 0xADC2, 0x82D2, 0xADC3, + 0x82D3, 0xADC5, 0x82D4, 0xADC6, 0x82D5, 0xADC7, 0x82D6, 0xADC9, 0x82D7, 0xADCA, 0x82D8, 0xADCB, 0x82D9, 0xADCC, 0x82DA, 0xADCD, + 0x82DB, 0xADCE, 0x82DC, 0xADCF, 0x82DD, 0xADD2, 0x82DE, 0xADD4, 0x82DF, 0xADD5, 0x82E0, 0xADD6, 0x82E1, 0xADD7, 0x82E2, 0xADD8, + 0x82E3, 0xADD9, 0x82E4, 0xADDA, 0x82E5, 0xADDB, 0x82E6, 0xADDD, 0x82E7, 0xADDE, 0x82E8, 0xADDF, 0x82E9, 0xADE1, 0x82EA, 0xADE2, + 0x82EB, 0xADE3, 0x82EC, 0xADE5, 0x82ED, 0xADE6, 0x82EE, 0xADE7, 0x82EF, 0xADE8, 0x82F0, 0xADE9, 0x82F1, 0xADEA, 0x82F2, 0xADEB, + 0x82F3, 0xADEC, 0x82F4, 0xADED, 0x82F5, 0xADEE, 0x82F6, 0xADEF, 0x82F7, 0xADF0, 0x82F8, 0xADF1, 0x82F9, 0xADF2, 0x82FA, 0xADF3, + 0x82FB, 0xADF4, 0x82FC, 0xADF5, 0x82FD, 0xADF6, 0x82FE, 0xADF7, 0x8341, 0xADFA, 0x8342, 0xADFB, 0x8343, 0xADFD, 0x8344, 0xADFE, + 0x8345, 0xAE02, 0x8346, 0xAE03, 0x8347, 0xAE04, 0x8348, 0xAE05, 0x8349, 0xAE06, 0x834A, 0xAE07, 0x834B, 0xAE0A, 0x834C, 0xAE0C, + 0x834D, 0xAE0E, 0x834E, 0xAE0F, 0x834F, 0xAE10, 0x8350, 0xAE11, 0x8351, 0xAE12, 0x8352, 0xAE13, 0x8353, 0xAE15, 0x8354, 0xAE16, + 0x8355, 0xAE17, 0x8356, 0xAE18, 0x8357, 0xAE19, 0x8358, 0xAE1A, 0x8359, 0xAE1B, 0x835A, 0xAE1C, 0x8361, 0xAE1D, 0x8362, 0xAE1E, + 0x8363, 0xAE1F, 0x8364, 0xAE20, 0x8365, 0xAE21, 0x8366, 0xAE22, 0x8367, 0xAE23, 0x8368, 0xAE24, 0x8369, 0xAE25, 0x836A, 0xAE26, + 0x836B, 0xAE27, 0x836C, 0xAE28, 0x836D, 0xAE29, 0x836E, 0xAE2A, 0x836F, 0xAE2B, 0x8370, 0xAE2C, 0x8371, 0xAE2D, 0x8372, 0xAE2E, + 0x8373, 0xAE2F, 0x8374, 0xAE32, 0x8375, 0xAE33, 0x8376, 0xAE35, 0x8377, 0xAE36, 0x8378, 0xAE39, 0x8379, 0xAE3B, 0x837A, 0xAE3C, + 0x8381, 0xAE3D, 0x8382, 0xAE3E, 0x8383, 0xAE3F, 0x8384, 0xAE42, 0x8385, 0xAE44, 0x8386, 0xAE47, 0x8387, 0xAE48, 0x8388, 0xAE49, + 0x8389, 0xAE4B, 0x838A, 0xAE4F, 0x838B, 0xAE51, 0x838C, 0xAE52, 0x838D, 0xAE53, 0x838E, 0xAE55, 0x838F, 0xAE57, 0x8390, 0xAE58, + 0x8391, 0xAE59, 0x8392, 0xAE5A, 0x8393, 0xAE5B, 0x8394, 0xAE5E, 0x8395, 0xAE62, 0x8396, 0xAE63, 0x8397, 0xAE64, 0x8398, 0xAE66, + 0x8399, 0xAE67, 0x839A, 0xAE6A, 0x839B, 0xAE6B, 0x839C, 0xAE6D, 0x839D, 0xAE6E, 0x839E, 0xAE6F, 0x839F, 0xAE71, 0x83A0, 0xAE72, + 0x83A1, 0xAE73, 0x83A2, 0xAE74, 0x83A3, 0xAE75, 0x83A4, 0xAE76, 0x83A5, 0xAE77, 0x83A6, 0xAE7A, 0x83A7, 0xAE7E, 0x83A8, 0xAE7F, + 0x83A9, 0xAE80, 0x83AA, 0xAE81, 0x83AB, 0xAE82, 0x83AC, 0xAE83, 0x83AD, 0xAE86, 0x83AE, 0xAE87, 0x83AF, 0xAE88, 0x83B0, 0xAE89, + 0x83B1, 0xAE8A, 0x83B2, 0xAE8B, 0x83B3, 0xAE8D, 0x83B4, 0xAE8E, 0x83B5, 0xAE8F, 0x83B6, 0xAE90, 0x83B7, 0xAE91, 0x83B8, 0xAE92, + 0x83B9, 0xAE93, 0x83BA, 0xAE94, 0x83BB, 0xAE95, 0x83BC, 0xAE96, 0x83BD, 0xAE97, 0x83BE, 0xAE98, 0x83BF, 0xAE99, 0x83C0, 0xAE9A, + 0x83C1, 0xAE9B, 0x83C2, 0xAE9C, 0x83C3, 0xAE9D, 0x83C4, 0xAE9E, 0x83C5, 0xAE9F, 0x83C6, 0xAEA0, 0x83C7, 0xAEA1, 0x83C8, 0xAEA2, + 0x83C9, 0xAEA3, 0x83CA, 0xAEA4, 0x83CB, 0xAEA5, 0x83CC, 0xAEA6, 0x83CD, 0xAEA7, 0x83CE, 0xAEA8, 0x83CF, 0xAEA9, 0x83D0, 0xAEAA, + 0x83D1, 0xAEAB, 0x83D2, 0xAEAC, 0x83D3, 0xAEAD, 0x83D4, 0xAEAE, 0x83D5, 0xAEAF, 0x83D6, 0xAEB0, 0x83D7, 0xAEB1, 0x83D8, 0xAEB2, + 0x83D9, 0xAEB3, 0x83DA, 0xAEB4, 0x83DB, 0xAEB5, 0x83DC, 0xAEB6, 0x83DD, 0xAEB7, 0x83DE, 0xAEB8, 0x83DF, 0xAEB9, 0x83E0, 0xAEBA, + 0x83E1, 0xAEBB, 0x83E2, 0xAEBF, 0x83E3, 0xAEC1, 0x83E4, 0xAEC2, 0x83E5, 0xAEC3, 0x83E6, 0xAEC5, 0x83E7, 0xAEC6, 0x83E8, 0xAEC7, + 0x83E9, 0xAEC8, 0x83EA, 0xAEC9, 0x83EB, 0xAECA, 0x83EC, 0xAECB, 0x83ED, 0xAECE, 0x83EE, 0xAED2, 0x83EF, 0xAED3, 0x83F0, 0xAED4, + 0x83F1, 0xAED5, 0x83F2, 0xAED6, 0x83F3, 0xAED7, 0x83F4, 0xAEDA, 0x83F5, 0xAEDB, 0x83F6, 0xAEDD, 0x83F7, 0xAEDE, 0x83F8, 0xAEDF, + 0x83F9, 0xAEE0, 0x83FA, 0xAEE1, 0x83FB, 0xAEE2, 0x83FC, 0xAEE3, 0x83FD, 0xAEE4, 0x83FE, 0xAEE5, 0x8441, 0xAEE6, 0x8442, 0xAEE7, + 0x8443, 0xAEE9, 0x8444, 0xAEEA, 0x8445, 0xAEEC, 0x8446, 0xAEEE, 0x8447, 0xAEEF, 0x8448, 0xAEF0, 0x8449, 0xAEF1, 0x844A, 0xAEF2, + 0x844B, 0xAEF3, 0x844C, 0xAEF5, 0x844D, 0xAEF6, 0x844E, 0xAEF7, 0x844F, 0xAEF9, 0x8450, 0xAEFA, 0x8451, 0xAEFB, 0x8452, 0xAEFD, + 0x8453, 0xAEFE, 0x8454, 0xAEFF, 0x8455, 0xAF00, 0x8456, 0xAF01, 0x8457, 0xAF02, 0x8458, 0xAF03, 0x8459, 0xAF04, 0x845A, 0xAF05, + 0x8461, 0xAF06, 0x8462, 0xAF09, 0x8463, 0xAF0A, 0x8464, 0xAF0B, 0x8465, 0xAF0C, 0x8466, 0xAF0E, 0x8467, 0xAF0F, 0x8468, 0xAF11, + 0x8469, 0xAF12, 0x846A, 0xAF13, 0x846B, 0xAF14, 0x846C, 0xAF15, 0x846D, 0xAF16, 0x846E, 0xAF17, 0x846F, 0xAF18, 0x8470, 0xAF19, + 0x8471, 0xAF1A, 0x8472, 0xAF1B, 0x8473, 0xAF1C, 0x8474, 0xAF1D, 0x8475, 0xAF1E, 0x8476, 0xAF1F, 0x8477, 0xAF20, 0x8478, 0xAF21, + 0x8479, 0xAF22, 0x847A, 0xAF23, 0x8481, 0xAF24, 0x8482, 0xAF25, 0x8483, 0xAF26, 0x8484, 0xAF27, 0x8485, 0xAF28, 0x8486, 0xAF29, + 0x8487, 0xAF2A, 0x8488, 0xAF2B, 0x8489, 0xAF2E, 0x848A, 0xAF2F, 0x848B, 0xAF31, 0x848C, 0xAF33, 0x848D, 0xAF35, 0x848E, 0xAF36, + 0x848F, 0xAF37, 0x8490, 0xAF38, 0x8491, 0xAF39, 0x8492, 0xAF3A, 0x8493, 0xAF3B, 0x8494, 0xAF3E, 0x8495, 0xAF40, 0x8496, 0xAF44, + 0x8497, 0xAF45, 0x8498, 0xAF46, 0x8499, 0xAF47, 0x849A, 0xAF4A, 0x849B, 0xAF4B, 0x849C, 0xAF4C, 0x849D, 0xAF4D, 0x849E, 0xAF4E, + 0x849F, 0xAF4F, 0x84A0, 0xAF51, 0x84A1, 0xAF52, 0x84A2, 0xAF53, 0x84A3, 0xAF54, 0x84A4, 0xAF55, 0x84A5, 0xAF56, 0x84A6, 0xAF57, + 0x84A7, 0xAF58, 0x84A8, 0xAF59, 0x84A9, 0xAF5A, 0x84AA, 0xAF5B, 0x84AB, 0xAF5E, 0x84AC, 0xAF5F, 0x84AD, 0xAF60, 0x84AE, 0xAF61, + 0x84AF, 0xAF62, 0x84B0, 0xAF63, 0x84B1, 0xAF66, 0x84B2, 0xAF67, 0x84B3, 0xAF68, 0x84B4, 0xAF69, 0x84B5, 0xAF6A, 0x84B6, 0xAF6B, + 0x84B7, 0xAF6C, 0x84B8, 0xAF6D, 0x84B9, 0xAF6E, 0x84BA, 0xAF6F, 0x84BB, 0xAF70, 0x84BC, 0xAF71, 0x84BD, 0xAF72, 0x84BE, 0xAF73, + 0x84BF, 0xAF74, 0x84C0, 0xAF75, 0x84C1, 0xAF76, 0x84C2, 0xAF77, 0x84C3, 0xAF78, 0x84C4, 0xAF7A, 0x84C5, 0xAF7B, 0x84C6, 0xAF7C, + 0x84C7, 0xAF7D, 0x84C8, 0xAF7E, 0x84C9, 0xAF7F, 0x84CA, 0xAF81, 0x84CB, 0xAF82, 0x84CC, 0xAF83, 0x84CD, 0xAF85, 0x84CE, 0xAF86, + 0x84CF, 0xAF87, 0x84D0, 0xAF89, 0x84D1, 0xAF8A, 0x84D2, 0xAF8B, 0x84D3, 0xAF8C, 0x84D4, 0xAF8D, 0x84D5, 0xAF8E, 0x84D6, 0xAF8F, + 0x84D7, 0xAF92, 0x84D8, 0xAF93, 0x84D9, 0xAF94, 0x84DA, 0xAF96, 0x84DB, 0xAF97, 0x84DC, 0xAF98, 0x84DD, 0xAF99, 0x84DE, 0xAF9A, + 0x84DF, 0xAF9B, 0x84E0, 0xAF9D, 0x84E1, 0xAF9E, 0x84E2, 0xAF9F, 0x84E3, 0xAFA0, 0x84E4, 0xAFA1, 0x84E5, 0xAFA2, 0x84E6, 0xAFA3, + 0x84E7, 0xAFA4, 0x84E8, 0xAFA5, 0x84E9, 0xAFA6, 0x84EA, 0xAFA7, 0x84EB, 0xAFA8, 0x84EC, 0xAFA9, 0x84ED, 0xAFAA, 0x84EE, 0xAFAB, + 0x84EF, 0xAFAC, 0x84F0, 0xAFAD, 0x84F1, 0xAFAE, 0x84F2, 0xAFAF, 0x84F3, 0xAFB0, 0x84F4, 0xAFB1, 0x84F5, 0xAFB2, 0x84F6, 0xAFB3, + 0x84F7, 0xAFB4, 0x84F8, 0xAFB5, 0x84F9, 0xAFB6, 0x84FA, 0xAFB7, 0x84FB, 0xAFBA, 0x84FC, 0xAFBB, 0x84FD, 0xAFBD, 0x84FE, 0xAFBE, + 0x8541, 0xAFBF, 0x8542, 0xAFC1, 0x8543, 0xAFC2, 0x8544, 0xAFC3, 0x8545, 0xAFC4, 0x8546, 0xAFC5, 0x8547, 0xAFC6, 0x8548, 0xAFCA, + 0x8549, 0xAFCC, 0x854A, 0xAFCF, 0x854B, 0xAFD0, 0x854C, 0xAFD1, 0x854D, 0xAFD2, 0x854E, 0xAFD3, 0x854F, 0xAFD5, 0x8550, 0xAFD6, + 0x8551, 0xAFD7, 0x8552, 0xAFD8, 0x8553, 0xAFD9, 0x8554, 0xAFDA, 0x8555, 0xAFDB, 0x8556, 0xAFDD, 0x8557, 0xAFDE, 0x8558, 0xAFDF, + 0x8559, 0xAFE0, 0x855A, 0xAFE1, 0x8561, 0xAFE2, 0x8562, 0xAFE3, 0x8563, 0xAFE4, 0x8564, 0xAFE5, 0x8565, 0xAFE6, 0x8566, 0xAFE7, + 0x8567, 0xAFEA, 0x8568, 0xAFEB, 0x8569, 0xAFEC, 0x856A, 0xAFED, 0x856B, 0xAFEE, 0x856C, 0xAFEF, 0x856D, 0xAFF2, 0x856E, 0xAFF3, + 0x856F, 0xAFF5, 0x8570, 0xAFF6, 0x8571, 0xAFF7, 0x8572, 0xAFF9, 0x8573, 0xAFFA, 0x8574, 0xAFFB, 0x8575, 0xAFFC, 0x8576, 0xAFFD, + 0x8577, 0xAFFE, 0x8578, 0xAFFF, 0x8579, 0xB002, 0x857A, 0xB003, 0x8581, 0xB005, 0x8582, 0xB006, 0x8583, 0xB007, 0x8584, 0xB008, + 0x8585, 0xB009, 0x8586, 0xB00A, 0x8587, 0xB00B, 0x8588, 0xB00D, 0x8589, 0xB00E, 0x858A, 0xB00F, 0x858B, 0xB011, 0x858C, 0xB012, + 0x858D, 0xB013, 0x858E, 0xB015, 0x858F, 0xB016, 0x8590, 0xB017, 0x8591, 0xB018, 0x8592, 0xB019, 0x8593, 0xB01A, 0x8594, 0xB01B, + 0x8595, 0xB01E, 0x8596, 0xB01F, 0x8597, 0xB020, 0x8598, 0xB021, 0x8599, 0xB022, 0x859A, 0xB023, 0x859B, 0xB024, 0x859C, 0xB025, + 0x859D, 0xB026, 0x859E, 0xB027, 0x859F, 0xB029, 0x85A0, 0xB02A, 0x85A1, 0xB02B, 0x85A2, 0xB02C, 0x85A3, 0xB02D, 0x85A4, 0xB02E, + 0x85A5, 0xB02F, 0x85A6, 0xB030, 0x85A7, 0xB031, 0x85A8, 0xB032, 0x85A9, 0xB033, 0x85AA, 0xB034, 0x85AB, 0xB035, 0x85AC, 0xB036, + 0x85AD, 0xB037, 0x85AE, 0xB038, 0x85AF, 0xB039, 0x85B0, 0xB03A, 0x85B1, 0xB03B, 0x85B2, 0xB03C, 0x85B3, 0xB03D, 0x85B4, 0xB03E, + 0x85B5, 0xB03F, 0x85B6, 0xB040, 0x85B7, 0xB041, 0x85B8, 0xB042, 0x85B9, 0xB043, 0x85BA, 0xB046, 0x85BB, 0xB047, 0x85BC, 0xB049, + 0x85BD, 0xB04B, 0x85BE, 0xB04D, 0x85BF, 0xB04F, 0x85C0, 0xB050, 0x85C1, 0xB051, 0x85C2, 0xB052, 0x85C3, 0xB056, 0x85C4, 0xB058, + 0x85C5, 0xB05A, 0x85C6, 0xB05B, 0x85C7, 0xB05C, 0x85C8, 0xB05E, 0x85C9, 0xB05F, 0x85CA, 0xB060, 0x85CB, 0xB061, 0x85CC, 0xB062, + 0x85CD, 0xB063, 0x85CE, 0xB064, 0x85CF, 0xB065, 0x85D0, 0xB066, 0x85D1, 0xB067, 0x85D2, 0xB068, 0x85D3, 0xB069, 0x85D4, 0xB06A, + 0x85D5, 0xB06B, 0x85D6, 0xB06C, 0x85D7, 0xB06D, 0x85D8, 0xB06E, 0x85D9, 0xB06F, 0x85DA, 0xB070, 0x85DB, 0xB071, 0x85DC, 0xB072, + 0x85DD, 0xB073, 0x85DE, 0xB074, 0x85DF, 0xB075, 0x85E0, 0xB076, 0x85E1, 0xB077, 0x85E2, 0xB078, 0x85E3, 0xB079, 0x85E4, 0xB07A, + 0x85E5, 0xB07B, 0x85E6, 0xB07E, 0x85E7, 0xB07F, 0x85E8, 0xB081, 0x85E9, 0xB082, 0x85EA, 0xB083, 0x85EB, 0xB085, 0x85EC, 0xB086, + 0x85ED, 0xB087, 0x85EE, 0xB088, 0x85EF, 0xB089, 0x85F0, 0xB08A, 0x85F1, 0xB08B, 0x85F2, 0xB08E, 0x85F3, 0xB090, 0x85F4, 0xB092, + 0x85F5, 0xB093, 0x85F6, 0xB094, 0x85F7, 0xB095, 0x85F8, 0xB096, 0x85F9, 0xB097, 0x85FA, 0xB09B, 0x85FB, 0xB09D, 0x85FC, 0xB09E, + 0x85FD, 0xB0A3, 0x85FE, 0xB0A4, 0x8641, 0xB0A5, 0x8642, 0xB0A6, 0x8643, 0xB0A7, 0x8644, 0xB0AA, 0x8645, 0xB0B0, 0x8646, 0xB0B2, + 0x8647, 0xB0B6, 0x8648, 0xB0B7, 0x8649, 0xB0B9, 0x864A, 0xB0BA, 0x864B, 0xB0BB, 0x864C, 0xB0BD, 0x864D, 0xB0BE, 0x864E, 0xB0BF, + 0x864F, 0xB0C0, 0x8650, 0xB0C1, 0x8651, 0xB0C2, 0x8652, 0xB0C3, 0x8653, 0xB0C6, 0x8654, 0xB0CA, 0x8655, 0xB0CB, 0x8656, 0xB0CC, + 0x8657, 0xB0CD, 0x8658, 0xB0CE, 0x8659, 0xB0CF, 0x865A, 0xB0D2, 0x8661, 0xB0D3, 0x8662, 0xB0D5, 0x8663, 0xB0D6, 0x8664, 0xB0D7, + 0x8665, 0xB0D9, 0x8666, 0xB0DA, 0x8667, 0xB0DB, 0x8668, 0xB0DC, 0x8669, 0xB0DD, 0x866A, 0xB0DE, 0x866B, 0xB0DF, 0x866C, 0xB0E1, + 0x866D, 0xB0E2, 0x866E, 0xB0E3, 0x866F, 0xB0E4, 0x8670, 0xB0E6, 0x8671, 0xB0E7, 0x8672, 0xB0E8, 0x8673, 0xB0E9, 0x8674, 0xB0EA, + 0x8675, 0xB0EB, 0x8676, 0xB0EC, 0x8677, 0xB0ED, 0x8678, 0xB0EE, 0x8679, 0xB0EF, 0x867A, 0xB0F0, 0x8681, 0xB0F1, 0x8682, 0xB0F2, + 0x8683, 0xB0F3, 0x8684, 0xB0F4, 0x8685, 0xB0F5, 0x8686, 0xB0F6, 0x8687, 0xB0F7, 0x8688, 0xB0F8, 0x8689, 0xB0F9, 0x868A, 0xB0FA, + 0x868B, 0xB0FB, 0x868C, 0xB0FC, 0x868D, 0xB0FD, 0x868E, 0xB0FE, 0x868F, 0xB0FF, 0x8690, 0xB100, 0x8691, 0xB101, 0x8692, 0xB102, + 0x8693, 0xB103, 0x8694, 0xB104, 0x8695, 0xB105, 0x8696, 0xB106, 0x8697, 0xB107, 0x8698, 0xB10A, 0x8699, 0xB10D, 0x869A, 0xB10E, + 0x869B, 0xB10F, 0x869C, 0xB111, 0x869D, 0xB114, 0x869E, 0xB115, 0x869F, 0xB116, 0x86A0, 0xB117, 0x86A1, 0xB11A, 0x86A2, 0xB11E, + 0x86A3, 0xB11F, 0x86A4, 0xB120, 0x86A5, 0xB121, 0x86A6, 0xB122, 0x86A7, 0xB126, 0x86A8, 0xB127, 0x86A9, 0xB129, 0x86AA, 0xB12A, + 0x86AB, 0xB12B, 0x86AC, 0xB12D, 0x86AD, 0xB12E, 0x86AE, 0xB12F, 0x86AF, 0xB130, 0x86B0, 0xB131, 0x86B1, 0xB132, 0x86B2, 0xB133, + 0x86B3, 0xB136, 0x86B4, 0xB13A, 0x86B5, 0xB13B, 0x86B6, 0xB13C, 0x86B7, 0xB13D, 0x86B8, 0xB13E, 0x86B9, 0xB13F, 0x86BA, 0xB142, + 0x86BB, 0xB143, 0x86BC, 0xB145, 0x86BD, 0xB146, 0x86BE, 0xB147, 0x86BF, 0xB149, 0x86C0, 0xB14A, 0x86C1, 0xB14B, 0x86C2, 0xB14C, + 0x86C3, 0xB14D, 0x86C4, 0xB14E, 0x86C5, 0xB14F, 0x86C6, 0xB152, 0x86C7, 0xB153, 0x86C8, 0xB156, 0x86C9, 0xB157, 0x86CA, 0xB159, + 0x86CB, 0xB15A, 0x86CC, 0xB15B, 0x86CD, 0xB15D, 0x86CE, 0xB15E, 0x86CF, 0xB15F, 0x86D0, 0xB161, 0x86D1, 0xB162, 0x86D2, 0xB163, + 0x86D3, 0xB164, 0x86D4, 0xB165, 0x86D5, 0xB166, 0x86D6, 0xB167, 0x86D7, 0xB168, 0x86D8, 0xB169, 0x86D9, 0xB16A, 0x86DA, 0xB16B, + 0x86DB, 0xB16C, 0x86DC, 0xB16D, 0x86DD, 0xB16E, 0x86DE, 0xB16F, 0x86DF, 0xB170, 0x86E0, 0xB171, 0x86E1, 0xB172, 0x86E2, 0xB173, + 0x86E3, 0xB174, 0x86E4, 0xB175, 0x86E5, 0xB176, 0x86E6, 0xB177, 0x86E7, 0xB17A, 0x86E8, 0xB17B, 0x86E9, 0xB17D, 0x86EA, 0xB17E, + 0x86EB, 0xB17F, 0x86EC, 0xB181, 0x86ED, 0xB183, 0x86EE, 0xB184, 0x86EF, 0xB185, 0x86F0, 0xB186, 0x86F1, 0xB187, 0x86F2, 0xB18A, + 0x86F3, 0xB18C, 0x86F4, 0xB18E, 0x86F5, 0xB18F, 0x86F6, 0xB190, 0x86F7, 0xB191, 0x86F8, 0xB195, 0x86F9, 0xB196, 0x86FA, 0xB197, + 0x86FB, 0xB199, 0x86FC, 0xB19A, 0x86FD, 0xB19B, 0x86FE, 0xB19D, 0x8741, 0xB19E, 0x8742, 0xB19F, 0x8743, 0xB1A0, 0x8744, 0xB1A1, + 0x8745, 0xB1A2, 0x8746, 0xB1A3, 0x8747, 0xB1A4, 0x8748, 0xB1A5, 0x8749, 0xB1A6, 0x874A, 0xB1A7, 0x874B, 0xB1A9, 0x874C, 0xB1AA, + 0x874D, 0xB1AB, 0x874E, 0xB1AC, 0x874F, 0xB1AD, 0x8750, 0xB1AE, 0x8751, 0xB1AF, 0x8752, 0xB1B0, 0x8753, 0xB1B1, 0x8754, 0xB1B2, + 0x8755, 0xB1B3, 0x8756, 0xB1B4, 0x8757, 0xB1B5, 0x8758, 0xB1B6, 0x8759, 0xB1B7, 0x875A, 0xB1B8, 0x8761, 0xB1B9, 0x8762, 0xB1BA, + 0x8763, 0xB1BB, 0x8764, 0xB1BC, 0x8765, 0xB1BD, 0x8766, 0xB1BE, 0x8767, 0xB1BF, 0x8768, 0xB1C0, 0x8769, 0xB1C1, 0x876A, 0xB1C2, + 0x876B, 0xB1C3, 0x876C, 0xB1C4, 0x876D, 0xB1C5, 0x876E, 0xB1C6, 0x876F, 0xB1C7, 0x8770, 0xB1C8, 0x8771, 0xB1C9, 0x8772, 0xB1CA, + 0x8773, 0xB1CB, 0x8774, 0xB1CD, 0x8775, 0xB1CE, 0x8776, 0xB1CF, 0x8777, 0xB1D1, 0x8778, 0xB1D2, 0x8779, 0xB1D3, 0x877A, 0xB1D5, + 0x8781, 0xB1D6, 0x8782, 0xB1D7, 0x8783, 0xB1D8, 0x8784, 0xB1D9, 0x8785, 0xB1DA, 0x8786, 0xB1DB, 0x8787, 0xB1DE, 0x8788, 0xB1E0, + 0x8789, 0xB1E1, 0x878A, 0xB1E2, 0x878B, 0xB1E3, 0x878C, 0xB1E4, 0x878D, 0xB1E5, 0x878E, 0xB1E6, 0x878F, 0xB1E7, 0x8790, 0xB1EA, + 0x8791, 0xB1EB, 0x8792, 0xB1ED, 0x8793, 0xB1EE, 0x8794, 0xB1EF, 0x8795, 0xB1F1, 0x8796, 0xB1F2, 0x8797, 0xB1F3, 0x8798, 0xB1F4, + 0x8799, 0xB1F5, 0x879A, 0xB1F6, 0x879B, 0xB1F7, 0x879C, 0xB1F8, 0x879D, 0xB1FA, 0x879E, 0xB1FC, 0x879F, 0xB1FE, 0x87A0, 0xB1FF, + 0x87A1, 0xB200, 0x87A2, 0xB201, 0x87A3, 0xB202, 0x87A4, 0xB203, 0x87A5, 0xB206, 0x87A6, 0xB207, 0x87A7, 0xB209, 0x87A8, 0xB20A, + 0x87A9, 0xB20D, 0x87AA, 0xB20E, 0x87AB, 0xB20F, 0x87AC, 0xB210, 0x87AD, 0xB211, 0x87AE, 0xB212, 0x87AF, 0xB213, 0x87B0, 0xB216, + 0x87B1, 0xB218, 0x87B2, 0xB21A, 0x87B3, 0xB21B, 0x87B4, 0xB21C, 0x87B5, 0xB21D, 0x87B6, 0xB21E, 0x87B7, 0xB21F, 0x87B8, 0xB221, + 0x87B9, 0xB222, 0x87BA, 0xB223, 0x87BB, 0xB224, 0x87BC, 0xB225, 0x87BD, 0xB226, 0x87BE, 0xB227, 0x87BF, 0xB228, 0x87C0, 0xB229, + 0x87C1, 0xB22A, 0x87C2, 0xB22B, 0x87C3, 0xB22C, 0x87C4, 0xB22D, 0x87C5, 0xB22E, 0x87C6, 0xB22F, 0x87C7, 0xB230, 0x87C8, 0xB231, + 0x87C9, 0xB232, 0x87CA, 0xB233, 0x87CB, 0xB235, 0x87CC, 0xB236, 0x87CD, 0xB237, 0x87CE, 0xB238, 0x87CF, 0xB239, 0x87D0, 0xB23A, + 0x87D1, 0xB23B, 0x87D2, 0xB23D, 0x87D3, 0xB23E, 0x87D4, 0xB23F, 0x87D5, 0xB240, 0x87D6, 0xB241, 0x87D7, 0xB242, 0x87D8, 0xB243, + 0x87D9, 0xB244, 0x87DA, 0xB245, 0x87DB, 0xB246, 0x87DC, 0xB247, 0x87DD, 0xB248, 0x87DE, 0xB249, 0x87DF, 0xB24A, 0x87E0, 0xB24B, + 0x87E1, 0xB24C, 0x87E2, 0xB24D, 0x87E3, 0xB24E, 0x87E4, 0xB24F, 0x87E5, 0xB250, 0x87E6, 0xB251, 0x87E7, 0xB252, 0x87E8, 0xB253, + 0x87E9, 0xB254, 0x87EA, 0xB255, 0x87EB, 0xB256, 0x87EC, 0xB257, 0x87ED, 0xB259, 0x87EE, 0xB25A, 0x87EF, 0xB25B, 0x87F0, 0xB25D, + 0x87F1, 0xB25E, 0x87F2, 0xB25F, 0x87F3, 0xB261, 0x87F4, 0xB262, 0x87F5, 0xB263, 0x87F6, 0xB264, 0x87F7, 0xB265, 0x87F8, 0xB266, + 0x87F9, 0xB267, 0x87FA, 0xB26A, 0x87FB, 0xB26B, 0x87FC, 0xB26C, 0x87FD, 0xB26D, 0x87FE, 0xB26E, 0x8841, 0xB26F, 0x8842, 0xB270, + 0x8843, 0xB271, 0x8844, 0xB272, 0x8845, 0xB273, 0x8846, 0xB276, 0x8847, 0xB277, 0x8848, 0xB278, 0x8849, 0xB279, 0x884A, 0xB27A, + 0x884B, 0xB27B, 0x884C, 0xB27D, 0x884D, 0xB27E, 0x884E, 0xB27F, 0x884F, 0xB280, 0x8850, 0xB281, 0x8851, 0xB282, 0x8852, 0xB283, + 0x8853, 0xB286, 0x8854, 0xB287, 0x8855, 0xB288, 0x8856, 0xB28A, 0x8857, 0xB28B, 0x8858, 0xB28C, 0x8859, 0xB28D, 0x885A, 0xB28E, + 0x8861, 0xB28F, 0x8862, 0xB292, 0x8863, 0xB293, 0x8864, 0xB295, 0x8865, 0xB296, 0x8866, 0xB297, 0x8867, 0xB29B, 0x8868, 0xB29C, + 0x8869, 0xB29D, 0x886A, 0xB29E, 0x886B, 0xB29F, 0x886C, 0xB2A2, 0x886D, 0xB2A4, 0x886E, 0xB2A7, 0x886F, 0xB2A8, 0x8870, 0xB2A9, + 0x8871, 0xB2AB, 0x8872, 0xB2AD, 0x8873, 0xB2AE, 0x8874, 0xB2AF, 0x8875, 0xB2B1, 0x8876, 0xB2B2, 0x8877, 0xB2B3, 0x8878, 0xB2B5, + 0x8879, 0xB2B6, 0x887A, 0xB2B7, 0x8881, 0xB2B8, 0x8882, 0xB2B9, 0x8883, 0xB2BA, 0x8884, 0xB2BB, 0x8885, 0xB2BC, 0x8886, 0xB2BD, + 0x8887, 0xB2BE, 0x8888, 0xB2BF, 0x8889, 0xB2C0, 0x888A, 0xB2C1, 0x888B, 0xB2C2, 0x888C, 0xB2C3, 0x888D, 0xB2C4, 0x888E, 0xB2C5, + 0x888F, 0xB2C6, 0x8890, 0xB2C7, 0x8891, 0xB2CA, 0x8892, 0xB2CB, 0x8893, 0xB2CD, 0x8894, 0xB2CE, 0x8895, 0xB2CF, 0x8896, 0xB2D1, + 0x8897, 0xB2D3, 0x8898, 0xB2D4, 0x8899, 0xB2D5, 0x889A, 0xB2D6, 0x889B, 0xB2D7, 0x889C, 0xB2DA, 0x889D, 0xB2DC, 0x889E, 0xB2DE, + 0x889F, 0xB2DF, 0x88A0, 0xB2E0, 0x88A1, 0xB2E1, 0x88A2, 0xB2E3, 0x88A3, 0xB2E7, 0x88A4, 0xB2E9, 0x88A5, 0xB2EA, 0x88A6, 0xB2F0, + 0x88A7, 0xB2F1, 0x88A8, 0xB2F2, 0x88A9, 0xB2F6, 0x88AA, 0xB2FC, 0x88AB, 0xB2FD, 0x88AC, 0xB2FE, 0x88AD, 0xB302, 0x88AE, 0xB303, + 0x88AF, 0xB305, 0x88B0, 0xB306, 0x88B1, 0xB307, 0x88B2, 0xB309, 0x88B3, 0xB30A, 0x88B4, 0xB30B, 0x88B5, 0xB30C, 0x88B6, 0xB30D, + 0x88B7, 0xB30E, 0x88B8, 0xB30F, 0x88B9, 0xB312, 0x88BA, 0xB316, 0x88BB, 0xB317, 0x88BC, 0xB318, 0x88BD, 0xB319, 0x88BE, 0xB31A, + 0x88BF, 0xB31B, 0x88C0, 0xB31D, 0x88C1, 0xB31E, 0x88C2, 0xB31F, 0x88C3, 0xB320, 0x88C4, 0xB321, 0x88C5, 0xB322, 0x88C6, 0xB323, + 0x88C7, 0xB324, 0x88C8, 0xB325, 0x88C9, 0xB326, 0x88CA, 0xB327, 0x88CB, 0xB328, 0x88CC, 0xB329, 0x88CD, 0xB32A, 0x88CE, 0xB32B, + 0x88CF, 0xB32C, 0x88D0, 0xB32D, 0x88D1, 0xB32E, 0x88D2, 0xB32F, 0x88D3, 0xB330, 0x88D4, 0xB331, 0x88D5, 0xB332, 0x88D6, 0xB333, + 0x88D7, 0xB334, 0x88D8, 0xB335, 0x88D9, 0xB336, 0x88DA, 0xB337, 0x88DB, 0xB338, 0x88DC, 0xB339, 0x88DD, 0xB33A, 0x88DE, 0xB33B, + 0x88DF, 0xB33C, 0x88E0, 0xB33D, 0x88E1, 0xB33E, 0x88E2, 0xB33F, 0x88E3, 0xB340, 0x88E4, 0xB341, 0x88E5, 0xB342, 0x88E6, 0xB343, + 0x88E7, 0xB344, 0x88E8, 0xB345, 0x88E9, 0xB346, 0x88EA, 0xB347, 0x88EB, 0xB348, 0x88EC, 0xB349, 0x88ED, 0xB34A, 0x88EE, 0xB34B, + 0x88EF, 0xB34C, 0x88F0, 0xB34D, 0x88F1, 0xB34E, 0x88F2, 0xB34F, 0x88F3, 0xB350, 0x88F4, 0xB351, 0x88F5, 0xB352, 0x88F6, 0xB353, + 0x88F7, 0xB357, 0x88F8, 0xB359, 0x88F9, 0xB35A, 0x88FA, 0xB35D, 0x88FB, 0xB360, 0x88FC, 0xB361, 0x88FD, 0xB362, 0x88FE, 0xB363, + 0x8941, 0xB366, 0x8942, 0xB368, 0x8943, 0xB36A, 0x8944, 0xB36C, 0x8945, 0xB36D, 0x8946, 0xB36F, 0x8947, 0xB372, 0x8948, 0xB373, + 0x8949, 0xB375, 0x894A, 0xB376, 0x894B, 0xB377, 0x894C, 0xB379, 0x894D, 0xB37A, 0x894E, 0xB37B, 0x894F, 0xB37C, 0x8950, 0xB37D, + 0x8951, 0xB37E, 0x8952, 0xB37F, 0x8953, 0xB382, 0x8954, 0xB386, 0x8955, 0xB387, 0x8956, 0xB388, 0x8957, 0xB389, 0x8958, 0xB38A, + 0x8959, 0xB38B, 0x895A, 0xB38D, 0x8961, 0xB38E, 0x8962, 0xB38F, 0x8963, 0xB391, 0x8964, 0xB392, 0x8965, 0xB393, 0x8966, 0xB395, + 0x8967, 0xB396, 0x8968, 0xB397, 0x8969, 0xB398, 0x896A, 0xB399, 0x896B, 0xB39A, 0x896C, 0xB39B, 0x896D, 0xB39C, 0x896E, 0xB39D, + 0x896F, 0xB39E, 0x8970, 0xB39F, 0x8971, 0xB3A2, 0x8972, 0xB3A3, 0x8973, 0xB3A4, 0x8974, 0xB3A5, 0x8975, 0xB3A6, 0x8976, 0xB3A7, + 0x8977, 0xB3A9, 0x8978, 0xB3AA, 0x8979, 0xB3AB, 0x897A, 0xB3AD, 0x8981, 0xB3AE, 0x8982, 0xB3AF, 0x8983, 0xB3B0, 0x8984, 0xB3B1, + 0x8985, 0xB3B2, 0x8986, 0xB3B3, 0x8987, 0xB3B4, 0x8988, 0xB3B5, 0x8989, 0xB3B6, 0x898A, 0xB3B7, 0x898B, 0xB3B8, 0x898C, 0xB3B9, + 0x898D, 0xB3BA, 0x898E, 0xB3BB, 0x898F, 0xB3BC, 0x8990, 0xB3BD, 0x8991, 0xB3BE, 0x8992, 0xB3BF, 0x8993, 0xB3C0, 0x8994, 0xB3C1, + 0x8995, 0xB3C2, 0x8996, 0xB3C3, 0x8997, 0xB3C6, 0x8998, 0xB3C7, 0x8999, 0xB3C9, 0x899A, 0xB3CA, 0x899B, 0xB3CD, 0x899C, 0xB3CF, + 0x899D, 0xB3D1, 0x899E, 0xB3D2, 0x899F, 0xB3D3, 0x89A0, 0xB3D6, 0x89A1, 0xB3D8, 0x89A2, 0xB3DA, 0x89A3, 0xB3DC, 0x89A4, 0xB3DE, + 0x89A5, 0xB3DF, 0x89A6, 0xB3E1, 0x89A7, 0xB3E2, 0x89A8, 0xB3E3, 0x89A9, 0xB3E5, 0x89AA, 0xB3E6, 0x89AB, 0xB3E7, 0x89AC, 0xB3E9, + 0x89AD, 0xB3EA, 0x89AE, 0xB3EB, 0x89AF, 0xB3EC, 0x89B0, 0xB3ED, 0x89B1, 0xB3EE, 0x89B2, 0xB3EF, 0x89B3, 0xB3F0, 0x89B4, 0xB3F1, + 0x89B5, 0xB3F2, 0x89B6, 0xB3F3, 0x89B7, 0xB3F4, 0x89B8, 0xB3F5, 0x89B9, 0xB3F6, 0x89BA, 0xB3F7, 0x89BB, 0xB3F8, 0x89BC, 0xB3F9, + 0x89BD, 0xB3FA, 0x89BE, 0xB3FB, 0x89BF, 0xB3FD, 0x89C0, 0xB3FE, 0x89C1, 0xB3FF, 0x89C2, 0xB400, 0x89C3, 0xB401, 0x89C4, 0xB402, + 0x89C5, 0xB403, 0x89C6, 0xB404, 0x89C7, 0xB405, 0x89C8, 0xB406, 0x89C9, 0xB407, 0x89CA, 0xB408, 0x89CB, 0xB409, 0x89CC, 0xB40A, + 0x89CD, 0xB40B, 0x89CE, 0xB40C, 0x89CF, 0xB40D, 0x89D0, 0xB40E, 0x89D1, 0xB40F, 0x89D2, 0xB411, 0x89D3, 0xB412, 0x89D4, 0xB413, + 0x89D5, 0xB414, 0x89D6, 0xB415, 0x89D7, 0xB416, 0x89D8, 0xB417, 0x89D9, 0xB419, 0x89DA, 0xB41A, 0x89DB, 0xB41B, 0x89DC, 0xB41D, + 0x89DD, 0xB41E, 0x89DE, 0xB41F, 0x89DF, 0xB421, 0x89E0, 0xB422, 0x89E1, 0xB423, 0x89E2, 0xB424, 0x89E3, 0xB425, 0x89E4, 0xB426, + 0x89E5, 0xB427, 0x89E6, 0xB42A, 0x89E7, 0xB42C, 0x89E8, 0xB42D, 0x89E9, 0xB42E, 0x89EA, 0xB42F, 0x89EB, 0xB430, 0x89EC, 0xB431, + 0x89ED, 0xB432, 0x89EE, 0xB433, 0x89EF, 0xB435, 0x89F0, 0xB436, 0x89F1, 0xB437, 0x89F2, 0xB438, 0x89F3, 0xB439, 0x89F4, 0xB43A, + 0x89F5, 0xB43B, 0x89F6, 0xB43C, 0x89F7, 0xB43D, 0x89F8, 0xB43E, 0x89F9, 0xB43F, 0x89FA, 0xB440, 0x89FB, 0xB441, 0x89FC, 0xB442, + 0x89FD, 0xB443, 0x89FE, 0xB444, 0x8A41, 0xB445, 0x8A42, 0xB446, 0x8A43, 0xB447, 0x8A44, 0xB448, 0x8A45, 0xB449, 0x8A46, 0xB44A, + 0x8A47, 0xB44B, 0x8A48, 0xB44C, 0x8A49, 0xB44D, 0x8A4A, 0xB44E, 0x8A4B, 0xB44F, 0x8A4C, 0xB452, 0x8A4D, 0xB453, 0x8A4E, 0xB455, + 0x8A4F, 0xB456, 0x8A50, 0xB457, 0x8A51, 0xB459, 0x8A52, 0xB45A, 0x8A53, 0xB45B, 0x8A54, 0xB45C, 0x8A55, 0xB45D, 0x8A56, 0xB45E, + 0x8A57, 0xB45F, 0x8A58, 0xB462, 0x8A59, 0xB464, 0x8A5A, 0xB466, 0x8A61, 0xB467, 0x8A62, 0xB468, 0x8A63, 0xB469, 0x8A64, 0xB46A, + 0x8A65, 0xB46B, 0x8A66, 0xB46D, 0x8A67, 0xB46E, 0x8A68, 0xB46F, 0x8A69, 0xB470, 0x8A6A, 0xB471, 0x8A6B, 0xB472, 0x8A6C, 0xB473, + 0x8A6D, 0xB474, 0x8A6E, 0xB475, 0x8A6F, 0xB476, 0x8A70, 0xB477, 0x8A71, 0xB478, 0x8A72, 0xB479, 0x8A73, 0xB47A, 0x8A74, 0xB47B, + 0x8A75, 0xB47C, 0x8A76, 0xB47D, 0x8A77, 0xB47E, 0x8A78, 0xB47F, 0x8A79, 0xB481, 0x8A7A, 0xB482, 0x8A81, 0xB483, 0x8A82, 0xB484, + 0x8A83, 0xB485, 0x8A84, 0xB486, 0x8A85, 0xB487, 0x8A86, 0xB489, 0x8A87, 0xB48A, 0x8A88, 0xB48B, 0x8A89, 0xB48C, 0x8A8A, 0xB48D, + 0x8A8B, 0xB48E, 0x8A8C, 0xB48F, 0x8A8D, 0xB490, 0x8A8E, 0xB491, 0x8A8F, 0xB492, 0x8A90, 0xB493, 0x8A91, 0xB494, 0x8A92, 0xB495, + 0x8A93, 0xB496, 0x8A94, 0xB497, 0x8A95, 0xB498, 0x8A96, 0xB499, 0x8A97, 0xB49A, 0x8A98, 0xB49B, 0x8A99, 0xB49C, 0x8A9A, 0xB49E, + 0x8A9B, 0xB49F, 0x8A9C, 0xB4A0, 0x8A9D, 0xB4A1, 0x8A9E, 0xB4A2, 0x8A9F, 0xB4A3, 0x8AA0, 0xB4A5, 0x8AA1, 0xB4A6, 0x8AA2, 0xB4A7, + 0x8AA3, 0xB4A9, 0x8AA4, 0xB4AA, 0x8AA5, 0xB4AB, 0x8AA6, 0xB4AD, 0x8AA7, 0xB4AE, 0x8AA8, 0xB4AF, 0x8AA9, 0xB4B0, 0x8AAA, 0xB4B1, + 0x8AAB, 0xB4B2, 0x8AAC, 0xB4B3, 0x8AAD, 0xB4B4, 0x8AAE, 0xB4B6, 0x8AAF, 0xB4B8, 0x8AB0, 0xB4BA, 0x8AB1, 0xB4BB, 0x8AB2, 0xB4BC, + 0x8AB3, 0xB4BD, 0x8AB4, 0xB4BE, 0x8AB5, 0xB4BF, 0x8AB6, 0xB4C1, 0x8AB7, 0xB4C2, 0x8AB8, 0xB4C3, 0x8AB9, 0xB4C5, 0x8ABA, 0xB4C6, + 0x8ABB, 0xB4C7, 0x8ABC, 0xB4C9, 0x8ABD, 0xB4CA, 0x8ABE, 0xB4CB, 0x8ABF, 0xB4CC, 0x8AC0, 0xB4CD, 0x8AC1, 0xB4CE, 0x8AC2, 0xB4CF, + 0x8AC3, 0xB4D1, 0x8AC4, 0xB4D2, 0x8AC5, 0xB4D3, 0x8AC6, 0xB4D4, 0x8AC7, 0xB4D6, 0x8AC8, 0xB4D7, 0x8AC9, 0xB4D8, 0x8ACA, 0xB4D9, + 0x8ACB, 0xB4DA, 0x8ACC, 0xB4DB, 0x8ACD, 0xB4DE, 0x8ACE, 0xB4DF, 0x8ACF, 0xB4E1, 0x8AD0, 0xB4E2, 0x8AD1, 0xB4E5, 0x8AD2, 0xB4E7, + 0x8AD3, 0xB4E8, 0x8AD4, 0xB4E9, 0x8AD5, 0xB4EA, 0x8AD6, 0xB4EB, 0x8AD7, 0xB4EE, 0x8AD8, 0xB4F0, 0x8AD9, 0xB4F2, 0x8ADA, 0xB4F3, + 0x8ADB, 0xB4F4, 0x8ADC, 0xB4F5, 0x8ADD, 0xB4F6, 0x8ADE, 0xB4F7, 0x8ADF, 0xB4F9, 0x8AE0, 0xB4FA, 0x8AE1, 0xB4FB, 0x8AE2, 0xB4FC, + 0x8AE3, 0xB4FD, 0x8AE4, 0xB4FE, 0x8AE5, 0xB4FF, 0x8AE6, 0xB500, 0x8AE7, 0xB501, 0x8AE8, 0xB502, 0x8AE9, 0xB503, 0x8AEA, 0xB504, + 0x8AEB, 0xB505, 0x8AEC, 0xB506, 0x8AED, 0xB507, 0x8AEE, 0xB508, 0x8AEF, 0xB509, 0x8AF0, 0xB50A, 0x8AF1, 0xB50B, 0x8AF2, 0xB50C, + 0x8AF3, 0xB50D, 0x8AF4, 0xB50E, 0x8AF5, 0xB50F, 0x8AF6, 0xB510, 0x8AF7, 0xB511, 0x8AF8, 0xB512, 0x8AF9, 0xB513, 0x8AFA, 0xB516, + 0x8AFB, 0xB517, 0x8AFC, 0xB519, 0x8AFD, 0xB51A, 0x8AFE, 0xB51D, 0x8B41, 0xB51E, 0x8B42, 0xB51F, 0x8B43, 0xB520, 0x8B44, 0xB521, + 0x8B45, 0xB522, 0x8B46, 0xB523, 0x8B47, 0xB526, 0x8B48, 0xB52B, 0x8B49, 0xB52C, 0x8B4A, 0xB52D, 0x8B4B, 0xB52E, 0x8B4C, 0xB52F, + 0x8B4D, 0xB532, 0x8B4E, 0xB533, 0x8B4F, 0xB535, 0x8B50, 0xB536, 0x8B51, 0xB537, 0x8B52, 0xB539, 0x8B53, 0xB53A, 0x8B54, 0xB53B, + 0x8B55, 0xB53C, 0x8B56, 0xB53D, 0x8B57, 0xB53E, 0x8B58, 0xB53F, 0x8B59, 0xB542, 0x8B5A, 0xB546, 0x8B61, 0xB547, 0x8B62, 0xB548, + 0x8B63, 0xB549, 0x8B64, 0xB54A, 0x8B65, 0xB54E, 0x8B66, 0xB54F, 0x8B67, 0xB551, 0x8B68, 0xB552, 0x8B69, 0xB553, 0x8B6A, 0xB555, + 0x8B6B, 0xB556, 0x8B6C, 0xB557, 0x8B6D, 0xB558, 0x8B6E, 0xB559, 0x8B6F, 0xB55A, 0x8B70, 0xB55B, 0x8B71, 0xB55E, 0x8B72, 0xB562, + 0x8B73, 0xB563, 0x8B74, 0xB564, 0x8B75, 0xB565, 0x8B76, 0xB566, 0x8B77, 0xB567, 0x8B78, 0xB568, 0x8B79, 0xB569, 0x8B7A, 0xB56A, + 0x8B81, 0xB56B, 0x8B82, 0xB56C, 0x8B83, 0xB56D, 0x8B84, 0xB56E, 0x8B85, 0xB56F, 0x8B86, 0xB570, 0x8B87, 0xB571, 0x8B88, 0xB572, + 0x8B89, 0xB573, 0x8B8A, 0xB574, 0x8B8B, 0xB575, 0x8B8C, 0xB576, 0x8B8D, 0xB577, 0x8B8E, 0xB578, 0x8B8F, 0xB579, 0x8B90, 0xB57A, + 0x8B91, 0xB57B, 0x8B92, 0xB57C, 0x8B93, 0xB57D, 0x8B94, 0xB57E, 0x8B95, 0xB57F, 0x8B96, 0xB580, 0x8B97, 0xB581, 0x8B98, 0xB582, + 0x8B99, 0xB583, 0x8B9A, 0xB584, 0x8B9B, 0xB585, 0x8B9C, 0xB586, 0x8B9D, 0xB587, 0x8B9E, 0xB588, 0x8B9F, 0xB589, 0x8BA0, 0xB58A, + 0x8BA1, 0xB58B, 0x8BA2, 0xB58C, 0x8BA3, 0xB58D, 0x8BA4, 0xB58E, 0x8BA5, 0xB58F, 0x8BA6, 0xB590, 0x8BA7, 0xB591, 0x8BA8, 0xB592, + 0x8BA9, 0xB593, 0x8BAA, 0xB594, 0x8BAB, 0xB595, 0x8BAC, 0xB596, 0x8BAD, 0xB597, 0x8BAE, 0xB598, 0x8BAF, 0xB599, 0x8BB0, 0xB59A, + 0x8BB1, 0xB59B, 0x8BB2, 0xB59C, 0x8BB3, 0xB59D, 0x8BB4, 0xB59E, 0x8BB5, 0xB59F, 0x8BB6, 0xB5A2, 0x8BB7, 0xB5A3, 0x8BB8, 0xB5A5, + 0x8BB9, 0xB5A6, 0x8BBA, 0xB5A7, 0x8BBB, 0xB5A9, 0x8BBC, 0xB5AC, 0x8BBD, 0xB5AD, 0x8BBE, 0xB5AE, 0x8BBF, 0xB5AF, 0x8BC0, 0xB5B2, + 0x8BC1, 0xB5B6, 0x8BC2, 0xB5B7, 0x8BC3, 0xB5B8, 0x8BC4, 0xB5B9, 0x8BC5, 0xB5BA, 0x8BC6, 0xB5BE, 0x8BC7, 0xB5BF, 0x8BC8, 0xB5C1, + 0x8BC9, 0xB5C2, 0x8BCA, 0xB5C3, 0x8BCB, 0xB5C5, 0x8BCC, 0xB5C6, 0x8BCD, 0xB5C7, 0x8BCE, 0xB5C8, 0x8BCF, 0xB5C9, 0x8BD0, 0xB5CA, + 0x8BD1, 0xB5CB, 0x8BD2, 0xB5CE, 0x8BD3, 0xB5D2, 0x8BD4, 0xB5D3, 0x8BD5, 0xB5D4, 0x8BD6, 0xB5D5, 0x8BD7, 0xB5D6, 0x8BD8, 0xB5D7, + 0x8BD9, 0xB5D9, 0x8BDA, 0xB5DA, 0x8BDB, 0xB5DB, 0x8BDC, 0xB5DC, 0x8BDD, 0xB5DD, 0x8BDE, 0xB5DE, 0x8BDF, 0xB5DF, 0x8BE0, 0xB5E0, + 0x8BE1, 0xB5E1, 0x8BE2, 0xB5E2, 0x8BE3, 0xB5E3, 0x8BE4, 0xB5E4, 0x8BE5, 0xB5E5, 0x8BE6, 0xB5E6, 0x8BE7, 0xB5E7, 0x8BE8, 0xB5E8, + 0x8BE9, 0xB5E9, 0x8BEA, 0xB5EA, 0x8BEB, 0xB5EB, 0x8BEC, 0xB5ED, 0x8BED, 0xB5EE, 0x8BEE, 0xB5EF, 0x8BEF, 0xB5F0, 0x8BF0, 0xB5F1, + 0x8BF1, 0xB5F2, 0x8BF2, 0xB5F3, 0x8BF3, 0xB5F4, 0x8BF4, 0xB5F5, 0x8BF5, 0xB5F6, 0x8BF6, 0xB5F7, 0x8BF7, 0xB5F8, 0x8BF8, 0xB5F9, + 0x8BF9, 0xB5FA, 0x8BFA, 0xB5FB, 0x8BFB, 0xB5FC, 0x8BFC, 0xB5FD, 0x8BFD, 0xB5FE, 0x8BFE, 0xB5FF, 0x8C41, 0xB600, 0x8C42, 0xB601, + 0x8C43, 0xB602, 0x8C44, 0xB603, 0x8C45, 0xB604, 0x8C46, 0xB605, 0x8C47, 0xB606, 0x8C48, 0xB607, 0x8C49, 0xB608, 0x8C4A, 0xB609, + 0x8C4B, 0xB60A, 0x8C4C, 0xB60B, 0x8C4D, 0xB60C, 0x8C4E, 0xB60D, 0x8C4F, 0xB60E, 0x8C50, 0xB60F, 0x8C51, 0xB612, 0x8C52, 0xB613, + 0x8C53, 0xB615, 0x8C54, 0xB616, 0x8C55, 0xB617, 0x8C56, 0xB619, 0x8C57, 0xB61A, 0x8C58, 0xB61B, 0x8C59, 0xB61C, 0x8C5A, 0xB61D, + 0x8C61, 0xB61E, 0x8C62, 0xB61F, 0x8C63, 0xB620, 0x8C64, 0xB621, 0x8C65, 0xB622, 0x8C66, 0xB623, 0x8C67, 0xB624, 0x8C68, 0xB626, + 0x8C69, 0xB627, 0x8C6A, 0xB628, 0x8C6B, 0xB629, 0x8C6C, 0xB62A, 0x8C6D, 0xB62B, 0x8C6E, 0xB62D, 0x8C6F, 0xB62E, 0x8C70, 0xB62F, + 0x8C71, 0xB630, 0x8C72, 0xB631, 0x8C73, 0xB632, 0x8C74, 0xB633, 0x8C75, 0xB635, 0x8C76, 0xB636, 0x8C77, 0xB637, 0x8C78, 0xB638, + 0x8C79, 0xB639, 0x8C7A, 0xB63A, 0x8C81, 0xB63B, 0x8C82, 0xB63C, 0x8C83, 0xB63D, 0x8C84, 0xB63E, 0x8C85, 0xB63F, 0x8C86, 0xB640, + 0x8C87, 0xB641, 0x8C88, 0xB642, 0x8C89, 0xB643, 0x8C8A, 0xB644, 0x8C8B, 0xB645, 0x8C8C, 0xB646, 0x8C8D, 0xB647, 0x8C8E, 0xB649, + 0x8C8F, 0xB64A, 0x8C90, 0xB64B, 0x8C91, 0xB64C, 0x8C92, 0xB64D, 0x8C93, 0xB64E, 0x8C94, 0xB64F, 0x8C95, 0xB650, 0x8C96, 0xB651, + 0x8C97, 0xB652, 0x8C98, 0xB653, 0x8C99, 0xB654, 0x8C9A, 0xB655, 0x8C9B, 0xB656, 0x8C9C, 0xB657, 0x8C9D, 0xB658, 0x8C9E, 0xB659, + 0x8C9F, 0xB65A, 0x8CA0, 0xB65B, 0x8CA1, 0xB65C, 0x8CA2, 0xB65D, 0x8CA3, 0xB65E, 0x8CA4, 0xB65F, 0x8CA5, 0xB660, 0x8CA6, 0xB661, + 0x8CA7, 0xB662, 0x8CA8, 0xB663, 0x8CA9, 0xB665, 0x8CAA, 0xB666, 0x8CAB, 0xB667, 0x8CAC, 0xB669, 0x8CAD, 0xB66A, 0x8CAE, 0xB66B, + 0x8CAF, 0xB66C, 0x8CB0, 0xB66D, 0x8CB1, 0xB66E, 0x8CB2, 0xB66F, 0x8CB3, 0xB670, 0x8CB4, 0xB671, 0x8CB5, 0xB672, 0x8CB6, 0xB673, + 0x8CB7, 0xB674, 0x8CB8, 0xB675, 0x8CB9, 0xB676, 0x8CBA, 0xB677, 0x8CBB, 0xB678, 0x8CBC, 0xB679, 0x8CBD, 0xB67A, 0x8CBE, 0xB67B, + 0x8CBF, 0xB67C, 0x8CC0, 0xB67D, 0x8CC1, 0xB67E, 0x8CC2, 0xB67F, 0x8CC3, 0xB680, 0x8CC4, 0xB681, 0x8CC5, 0xB682, 0x8CC6, 0xB683, + 0x8CC7, 0xB684, 0x8CC8, 0xB685, 0x8CC9, 0xB686, 0x8CCA, 0xB687, 0x8CCB, 0xB688, 0x8CCC, 0xB689, 0x8CCD, 0xB68A, 0x8CCE, 0xB68B, + 0x8CCF, 0xB68C, 0x8CD0, 0xB68D, 0x8CD1, 0xB68E, 0x8CD2, 0xB68F, 0x8CD3, 0xB690, 0x8CD4, 0xB691, 0x8CD5, 0xB692, 0x8CD6, 0xB693, + 0x8CD7, 0xB694, 0x8CD8, 0xB695, 0x8CD9, 0xB696, 0x8CDA, 0xB697, 0x8CDB, 0xB698, 0x8CDC, 0xB699, 0x8CDD, 0xB69A, 0x8CDE, 0xB69B, + 0x8CDF, 0xB69E, 0x8CE0, 0xB69F, 0x8CE1, 0xB6A1, 0x8CE2, 0xB6A2, 0x8CE3, 0xB6A3, 0x8CE4, 0xB6A5, 0x8CE5, 0xB6A6, 0x8CE6, 0xB6A7, + 0x8CE7, 0xB6A8, 0x8CE8, 0xB6A9, 0x8CE9, 0xB6AA, 0x8CEA, 0xB6AD, 0x8CEB, 0xB6AE, 0x8CEC, 0xB6AF, 0x8CED, 0xB6B0, 0x8CEE, 0xB6B2, + 0x8CEF, 0xB6B3, 0x8CF0, 0xB6B4, 0x8CF1, 0xB6B5, 0x8CF2, 0xB6B6, 0x8CF3, 0xB6B7, 0x8CF4, 0xB6B8, 0x8CF5, 0xB6B9, 0x8CF6, 0xB6BA, + 0x8CF7, 0xB6BB, 0x8CF8, 0xB6BC, 0x8CF9, 0xB6BD, 0x8CFA, 0xB6BE, 0x8CFB, 0xB6BF, 0x8CFC, 0xB6C0, 0x8CFD, 0xB6C1, 0x8CFE, 0xB6C2, + 0x8D41, 0xB6C3, 0x8D42, 0xB6C4, 0x8D43, 0xB6C5, 0x8D44, 0xB6C6, 0x8D45, 0xB6C7, 0x8D46, 0xB6C8, 0x8D47, 0xB6C9, 0x8D48, 0xB6CA, + 0x8D49, 0xB6CB, 0x8D4A, 0xB6CC, 0x8D4B, 0xB6CD, 0x8D4C, 0xB6CE, 0x8D4D, 0xB6CF, 0x8D4E, 0xB6D0, 0x8D4F, 0xB6D1, 0x8D50, 0xB6D2, + 0x8D51, 0xB6D3, 0x8D52, 0xB6D5, 0x8D53, 0xB6D6, 0x8D54, 0xB6D7, 0x8D55, 0xB6D8, 0x8D56, 0xB6D9, 0x8D57, 0xB6DA, 0x8D58, 0xB6DB, + 0x8D59, 0xB6DC, 0x8D5A, 0xB6DD, 0x8D61, 0xB6DE, 0x8D62, 0xB6DF, 0x8D63, 0xB6E0, 0x8D64, 0xB6E1, 0x8D65, 0xB6E2, 0x8D66, 0xB6E3, + 0x8D67, 0xB6E4, 0x8D68, 0xB6E5, 0x8D69, 0xB6E6, 0x8D6A, 0xB6E7, 0x8D6B, 0xB6E8, 0x8D6C, 0xB6E9, 0x8D6D, 0xB6EA, 0x8D6E, 0xB6EB, + 0x8D6F, 0xB6EC, 0x8D70, 0xB6ED, 0x8D71, 0xB6EE, 0x8D72, 0xB6EF, 0x8D73, 0xB6F1, 0x8D74, 0xB6F2, 0x8D75, 0xB6F3, 0x8D76, 0xB6F5, + 0x8D77, 0xB6F6, 0x8D78, 0xB6F7, 0x8D79, 0xB6F9, 0x8D7A, 0xB6FA, 0x8D81, 0xB6FB, 0x8D82, 0xB6FC, 0x8D83, 0xB6FD, 0x8D84, 0xB6FE, + 0x8D85, 0xB6FF, 0x8D86, 0xB702, 0x8D87, 0xB703, 0x8D88, 0xB704, 0x8D89, 0xB706, 0x8D8A, 0xB707, 0x8D8B, 0xB708, 0x8D8C, 0xB709, + 0x8D8D, 0xB70A, 0x8D8E, 0xB70B, 0x8D8F, 0xB70C, 0x8D90, 0xB70D, 0x8D91, 0xB70E, 0x8D92, 0xB70F, 0x8D93, 0xB710, 0x8D94, 0xB711, + 0x8D95, 0xB712, 0x8D96, 0xB713, 0x8D97, 0xB714, 0x8D98, 0xB715, 0x8D99, 0xB716, 0x8D9A, 0xB717, 0x8D9B, 0xB718, 0x8D9C, 0xB719, + 0x8D9D, 0xB71A, 0x8D9E, 0xB71B, 0x8D9F, 0xB71C, 0x8DA0, 0xB71D, 0x8DA1, 0xB71E, 0x8DA2, 0xB71F, 0x8DA3, 0xB720, 0x8DA4, 0xB721, + 0x8DA5, 0xB722, 0x8DA6, 0xB723, 0x8DA7, 0xB724, 0x8DA8, 0xB725, 0x8DA9, 0xB726, 0x8DAA, 0xB727, 0x8DAB, 0xB72A, 0x8DAC, 0xB72B, + 0x8DAD, 0xB72D, 0x8DAE, 0xB72E, 0x8DAF, 0xB731, 0x8DB0, 0xB732, 0x8DB1, 0xB733, 0x8DB2, 0xB734, 0x8DB3, 0xB735, 0x8DB4, 0xB736, + 0x8DB5, 0xB737, 0x8DB6, 0xB73A, 0x8DB7, 0xB73C, 0x8DB8, 0xB73D, 0x8DB9, 0xB73E, 0x8DBA, 0xB73F, 0x8DBB, 0xB740, 0x8DBC, 0xB741, + 0x8DBD, 0xB742, 0x8DBE, 0xB743, 0x8DBF, 0xB745, 0x8DC0, 0xB746, 0x8DC1, 0xB747, 0x8DC2, 0xB749, 0x8DC3, 0xB74A, 0x8DC4, 0xB74B, + 0x8DC5, 0xB74D, 0x8DC6, 0xB74E, 0x8DC7, 0xB74F, 0x8DC8, 0xB750, 0x8DC9, 0xB751, 0x8DCA, 0xB752, 0x8DCB, 0xB753, 0x8DCC, 0xB756, + 0x8DCD, 0xB757, 0x8DCE, 0xB758, 0x8DCF, 0xB759, 0x8DD0, 0xB75A, 0x8DD1, 0xB75B, 0x8DD2, 0xB75C, 0x8DD3, 0xB75D, 0x8DD4, 0xB75E, + 0x8DD5, 0xB75F, 0x8DD6, 0xB761, 0x8DD7, 0xB762, 0x8DD8, 0xB763, 0x8DD9, 0xB765, 0x8DDA, 0xB766, 0x8DDB, 0xB767, 0x8DDC, 0xB769, + 0x8DDD, 0xB76A, 0x8DDE, 0xB76B, 0x8DDF, 0xB76C, 0x8DE0, 0xB76D, 0x8DE1, 0xB76E, 0x8DE2, 0xB76F, 0x8DE3, 0xB772, 0x8DE4, 0xB774, + 0x8DE5, 0xB776, 0x8DE6, 0xB777, 0x8DE7, 0xB778, 0x8DE8, 0xB779, 0x8DE9, 0xB77A, 0x8DEA, 0xB77B, 0x8DEB, 0xB77E, 0x8DEC, 0xB77F, + 0x8DED, 0xB781, 0x8DEE, 0xB782, 0x8DEF, 0xB783, 0x8DF0, 0xB785, 0x8DF1, 0xB786, 0x8DF2, 0xB787, 0x8DF3, 0xB788, 0x8DF4, 0xB789, + 0x8DF5, 0xB78A, 0x8DF6, 0xB78B, 0x8DF7, 0xB78E, 0x8DF8, 0xB793, 0x8DF9, 0xB794, 0x8DFA, 0xB795, 0x8DFB, 0xB79A, 0x8DFC, 0xB79B, + 0x8DFD, 0xB79D, 0x8DFE, 0xB79E, 0x8E41, 0xB79F, 0x8E42, 0xB7A1, 0x8E43, 0xB7A2, 0x8E44, 0xB7A3, 0x8E45, 0xB7A4, 0x8E46, 0xB7A5, + 0x8E47, 0xB7A6, 0x8E48, 0xB7A7, 0x8E49, 0xB7AA, 0x8E4A, 0xB7AE, 0x8E4B, 0xB7AF, 0x8E4C, 0xB7B0, 0x8E4D, 0xB7B1, 0x8E4E, 0xB7B2, + 0x8E4F, 0xB7B3, 0x8E50, 0xB7B6, 0x8E51, 0xB7B7, 0x8E52, 0xB7B9, 0x8E53, 0xB7BA, 0x8E54, 0xB7BB, 0x8E55, 0xB7BC, 0x8E56, 0xB7BD, + 0x8E57, 0xB7BE, 0x8E58, 0xB7BF, 0x8E59, 0xB7C0, 0x8E5A, 0xB7C1, 0x8E61, 0xB7C2, 0x8E62, 0xB7C3, 0x8E63, 0xB7C4, 0x8E64, 0xB7C5, + 0x8E65, 0xB7C6, 0x8E66, 0xB7C8, 0x8E67, 0xB7CA, 0x8E68, 0xB7CB, 0x8E69, 0xB7CC, 0x8E6A, 0xB7CD, 0x8E6B, 0xB7CE, 0x8E6C, 0xB7CF, + 0x8E6D, 0xB7D0, 0x8E6E, 0xB7D1, 0x8E6F, 0xB7D2, 0x8E70, 0xB7D3, 0x8E71, 0xB7D4, 0x8E72, 0xB7D5, 0x8E73, 0xB7D6, 0x8E74, 0xB7D7, + 0x8E75, 0xB7D8, 0x8E76, 0xB7D9, 0x8E77, 0xB7DA, 0x8E78, 0xB7DB, 0x8E79, 0xB7DC, 0x8E7A, 0xB7DD, 0x8E81, 0xB7DE, 0x8E82, 0xB7DF, + 0x8E83, 0xB7E0, 0x8E84, 0xB7E1, 0x8E85, 0xB7E2, 0x8E86, 0xB7E3, 0x8E87, 0xB7E4, 0x8E88, 0xB7E5, 0x8E89, 0xB7E6, 0x8E8A, 0xB7E7, + 0x8E8B, 0xB7E8, 0x8E8C, 0xB7E9, 0x8E8D, 0xB7EA, 0x8E8E, 0xB7EB, 0x8E8F, 0xB7EE, 0x8E90, 0xB7EF, 0x8E91, 0xB7F1, 0x8E92, 0xB7F2, + 0x8E93, 0xB7F3, 0x8E94, 0xB7F5, 0x8E95, 0xB7F6, 0x8E96, 0xB7F7, 0x8E97, 0xB7F8, 0x8E98, 0xB7F9, 0x8E99, 0xB7FA, 0x8E9A, 0xB7FB, + 0x8E9B, 0xB7FE, 0x8E9C, 0xB802, 0x8E9D, 0xB803, 0x8E9E, 0xB804, 0x8E9F, 0xB805, 0x8EA0, 0xB806, 0x8EA1, 0xB80A, 0x8EA2, 0xB80B, + 0x8EA3, 0xB80D, 0x8EA4, 0xB80E, 0x8EA5, 0xB80F, 0x8EA6, 0xB811, 0x8EA7, 0xB812, 0x8EA8, 0xB813, 0x8EA9, 0xB814, 0x8EAA, 0xB815, + 0x8EAB, 0xB816, 0x8EAC, 0xB817, 0x8EAD, 0xB81A, 0x8EAE, 0xB81C, 0x8EAF, 0xB81E, 0x8EB0, 0xB81F, 0x8EB1, 0xB820, 0x8EB2, 0xB821, + 0x8EB3, 0xB822, 0x8EB4, 0xB823, 0x8EB5, 0xB826, 0x8EB6, 0xB827, 0x8EB7, 0xB829, 0x8EB8, 0xB82A, 0x8EB9, 0xB82B, 0x8EBA, 0xB82D, + 0x8EBB, 0xB82E, 0x8EBC, 0xB82F, 0x8EBD, 0xB830, 0x8EBE, 0xB831, 0x8EBF, 0xB832, 0x8EC0, 0xB833, 0x8EC1, 0xB836, 0x8EC2, 0xB83A, + 0x8EC3, 0xB83B, 0x8EC4, 0xB83C, 0x8EC5, 0xB83D, 0x8EC6, 0xB83E, 0x8EC7, 0xB83F, 0x8EC8, 0xB841, 0x8EC9, 0xB842, 0x8ECA, 0xB843, + 0x8ECB, 0xB845, 0x8ECC, 0xB846, 0x8ECD, 0xB847, 0x8ECE, 0xB848, 0x8ECF, 0xB849, 0x8ED0, 0xB84A, 0x8ED1, 0xB84B, 0x8ED2, 0xB84C, + 0x8ED3, 0xB84D, 0x8ED4, 0xB84E, 0x8ED5, 0xB84F, 0x8ED6, 0xB850, 0x8ED7, 0xB852, 0x8ED8, 0xB854, 0x8ED9, 0xB855, 0x8EDA, 0xB856, + 0x8EDB, 0xB857, 0x8EDC, 0xB858, 0x8EDD, 0xB859, 0x8EDE, 0xB85A, 0x8EDF, 0xB85B, 0x8EE0, 0xB85E, 0x8EE1, 0xB85F, 0x8EE2, 0xB861, + 0x8EE3, 0xB862, 0x8EE4, 0xB863, 0x8EE5, 0xB865, 0x8EE6, 0xB866, 0x8EE7, 0xB867, 0x8EE8, 0xB868, 0x8EE9, 0xB869, 0x8EEA, 0xB86A, + 0x8EEB, 0xB86B, 0x8EEC, 0xB86E, 0x8EED, 0xB870, 0x8EEE, 0xB872, 0x8EEF, 0xB873, 0x8EF0, 0xB874, 0x8EF1, 0xB875, 0x8EF2, 0xB876, + 0x8EF3, 0xB877, 0x8EF4, 0xB879, 0x8EF5, 0xB87A, 0x8EF6, 0xB87B, 0x8EF7, 0xB87D, 0x8EF8, 0xB87E, 0x8EF9, 0xB87F, 0x8EFA, 0xB880, + 0x8EFB, 0xB881, 0x8EFC, 0xB882, 0x8EFD, 0xB883, 0x8EFE, 0xB884, 0x8F41, 0xB885, 0x8F42, 0xB886, 0x8F43, 0xB887, 0x8F44, 0xB888, + 0x8F45, 0xB889, 0x8F46, 0xB88A, 0x8F47, 0xB88B, 0x8F48, 0xB88C, 0x8F49, 0xB88E, 0x8F4A, 0xB88F, 0x8F4B, 0xB890, 0x8F4C, 0xB891, + 0x8F4D, 0xB892, 0x8F4E, 0xB893, 0x8F4F, 0xB894, 0x8F50, 0xB895, 0x8F51, 0xB896, 0x8F52, 0xB897, 0x8F53, 0xB898, 0x8F54, 0xB899, + 0x8F55, 0xB89A, 0x8F56, 0xB89B, 0x8F57, 0xB89C, 0x8F58, 0xB89D, 0x8F59, 0xB89E, 0x8F5A, 0xB89F, 0x8F61, 0xB8A0, 0x8F62, 0xB8A1, + 0x8F63, 0xB8A2, 0x8F64, 0xB8A3, 0x8F65, 0xB8A4, 0x8F66, 0xB8A5, 0x8F67, 0xB8A6, 0x8F68, 0xB8A7, 0x8F69, 0xB8A9, 0x8F6A, 0xB8AA, + 0x8F6B, 0xB8AB, 0x8F6C, 0xB8AC, 0x8F6D, 0xB8AD, 0x8F6E, 0xB8AE, 0x8F6F, 0xB8AF, 0x8F70, 0xB8B1, 0x8F71, 0xB8B2, 0x8F72, 0xB8B3, + 0x8F73, 0xB8B5, 0x8F74, 0xB8B6, 0x8F75, 0xB8B7, 0x8F76, 0xB8B9, 0x8F77, 0xB8BA, 0x8F78, 0xB8BB, 0x8F79, 0xB8BC, 0x8F7A, 0xB8BD, + 0x8F81, 0xB8BE, 0x8F82, 0xB8BF, 0x8F83, 0xB8C2, 0x8F84, 0xB8C4, 0x8F85, 0xB8C6, 0x8F86, 0xB8C7, 0x8F87, 0xB8C8, 0x8F88, 0xB8C9, + 0x8F89, 0xB8CA, 0x8F8A, 0xB8CB, 0x8F8B, 0xB8CD, 0x8F8C, 0xB8CE, 0x8F8D, 0xB8CF, 0x8F8E, 0xB8D1, 0x8F8F, 0xB8D2, 0x8F90, 0xB8D3, + 0x8F91, 0xB8D5, 0x8F92, 0xB8D6, 0x8F93, 0xB8D7, 0x8F94, 0xB8D8, 0x8F95, 0xB8D9, 0x8F96, 0xB8DA, 0x8F97, 0xB8DB, 0x8F98, 0xB8DC, + 0x8F99, 0xB8DE, 0x8F9A, 0xB8E0, 0x8F9B, 0xB8E2, 0x8F9C, 0xB8E3, 0x8F9D, 0xB8E4, 0x8F9E, 0xB8E5, 0x8F9F, 0xB8E6, 0x8FA0, 0xB8E7, + 0x8FA1, 0xB8EA, 0x8FA2, 0xB8EB, 0x8FA3, 0xB8ED, 0x8FA4, 0xB8EE, 0x8FA5, 0xB8EF, 0x8FA6, 0xB8F1, 0x8FA7, 0xB8F2, 0x8FA8, 0xB8F3, + 0x8FA9, 0xB8F4, 0x8FAA, 0xB8F5, 0x8FAB, 0xB8F6, 0x8FAC, 0xB8F7, 0x8FAD, 0xB8FA, 0x8FAE, 0xB8FC, 0x8FAF, 0xB8FE, 0x8FB0, 0xB8FF, + 0x8FB1, 0xB900, 0x8FB2, 0xB901, 0x8FB3, 0xB902, 0x8FB4, 0xB903, 0x8FB5, 0xB905, 0x8FB6, 0xB906, 0x8FB7, 0xB907, 0x8FB8, 0xB908, + 0x8FB9, 0xB909, 0x8FBA, 0xB90A, 0x8FBB, 0xB90B, 0x8FBC, 0xB90C, 0x8FBD, 0xB90D, 0x8FBE, 0xB90E, 0x8FBF, 0xB90F, 0x8FC0, 0xB910, + 0x8FC1, 0xB911, 0x8FC2, 0xB912, 0x8FC3, 0xB913, 0x8FC4, 0xB914, 0x8FC5, 0xB915, 0x8FC6, 0xB916, 0x8FC7, 0xB917, 0x8FC8, 0xB919, + 0x8FC9, 0xB91A, 0x8FCA, 0xB91B, 0x8FCB, 0xB91C, 0x8FCC, 0xB91D, 0x8FCD, 0xB91E, 0x8FCE, 0xB91F, 0x8FCF, 0xB921, 0x8FD0, 0xB922, + 0x8FD1, 0xB923, 0x8FD2, 0xB924, 0x8FD3, 0xB925, 0x8FD4, 0xB926, 0x8FD5, 0xB927, 0x8FD6, 0xB928, 0x8FD7, 0xB929, 0x8FD8, 0xB92A, + 0x8FD9, 0xB92B, 0x8FDA, 0xB92C, 0x8FDB, 0xB92D, 0x8FDC, 0xB92E, 0x8FDD, 0xB92F, 0x8FDE, 0xB930, 0x8FDF, 0xB931, 0x8FE0, 0xB932, + 0x8FE1, 0xB933, 0x8FE2, 0xB934, 0x8FE3, 0xB935, 0x8FE4, 0xB936, 0x8FE5, 0xB937, 0x8FE6, 0xB938, 0x8FE7, 0xB939, 0x8FE8, 0xB93A, + 0x8FE9, 0xB93B, 0x8FEA, 0xB93E, 0x8FEB, 0xB93F, 0x8FEC, 0xB941, 0x8FED, 0xB942, 0x8FEE, 0xB943, 0x8FEF, 0xB945, 0x8FF0, 0xB946, + 0x8FF1, 0xB947, 0x8FF2, 0xB948, 0x8FF3, 0xB949, 0x8FF4, 0xB94A, 0x8FF5, 0xB94B, 0x8FF6, 0xB94D, 0x8FF7, 0xB94E, 0x8FF8, 0xB950, + 0x8FF9, 0xB952, 0x8FFA, 0xB953, 0x8FFB, 0xB954, 0x8FFC, 0xB955, 0x8FFD, 0xB956, 0x8FFE, 0xB957, 0x9041, 0xB95A, 0x9042, 0xB95B, + 0x9043, 0xB95D, 0x9044, 0xB95E, 0x9045, 0xB95F, 0x9046, 0xB961, 0x9047, 0xB962, 0x9048, 0xB963, 0x9049, 0xB964, 0x904A, 0xB965, + 0x904B, 0xB966, 0x904C, 0xB967, 0x904D, 0xB96A, 0x904E, 0xB96C, 0x904F, 0xB96E, 0x9050, 0xB96F, 0x9051, 0xB970, 0x9052, 0xB971, + 0x9053, 0xB972, 0x9054, 0xB973, 0x9055, 0xB976, 0x9056, 0xB977, 0x9057, 0xB979, 0x9058, 0xB97A, 0x9059, 0xB97B, 0x905A, 0xB97D, + 0x9061, 0xB97E, 0x9062, 0xB97F, 0x9063, 0xB980, 0x9064, 0xB981, 0x9065, 0xB982, 0x9066, 0xB983, 0x9067, 0xB986, 0x9068, 0xB988, + 0x9069, 0xB98B, 0x906A, 0xB98C, 0x906B, 0xB98F, 0x906C, 0xB990, 0x906D, 0xB991, 0x906E, 0xB992, 0x906F, 0xB993, 0x9070, 0xB994, + 0x9071, 0xB995, 0x9072, 0xB996, 0x9073, 0xB997, 0x9074, 0xB998, 0x9075, 0xB999, 0x9076, 0xB99A, 0x9077, 0xB99B, 0x9078, 0xB99C, + 0x9079, 0xB99D, 0x907A, 0xB99E, 0x9081, 0xB99F, 0x9082, 0xB9A0, 0x9083, 0xB9A1, 0x9084, 0xB9A2, 0x9085, 0xB9A3, 0x9086, 0xB9A4, + 0x9087, 0xB9A5, 0x9088, 0xB9A6, 0x9089, 0xB9A7, 0x908A, 0xB9A8, 0x908B, 0xB9A9, 0x908C, 0xB9AA, 0x908D, 0xB9AB, 0x908E, 0xB9AE, + 0x908F, 0xB9AF, 0x9090, 0xB9B1, 0x9091, 0xB9B2, 0x9092, 0xB9B3, 0x9093, 0xB9B5, 0x9094, 0xB9B6, 0x9095, 0xB9B7, 0x9096, 0xB9B8, + 0x9097, 0xB9B9, 0x9098, 0xB9BA, 0x9099, 0xB9BB, 0x909A, 0xB9BE, 0x909B, 0xB9C0, 0x909C, 0xB9C2, 0x909D, 0xB9C3, 0x909E, 0xB9C4, + 0x909F, 0xB9C5, 0x90A0, 0xB9C6, 0x90A1, 0xB9C7, 0x90A2, 0xB9CA, 0x90A3, 0xB9CB, 0x90A4, 0xB9CD, 0x90A5, 0xB9D3, 0x90A6, 0xB9D4, + 0x90A7, 0xB9D5, 0x90A8, 0xB9D6, 0x90A9, 0xB9D7, 0x90AA, 0xB9DA, 0x90AB, 0xB9DC, 0x90AC, 0xB9DF, 0x90AD, 0xB9E0, 0x90AE, 0xB9E2, + 0x90AF, 0xB9E6, 0x90B0, 0xB9E7, 0x90B1, 0xB9E9, 0x90B2, 0xB9EA, 0x90B3, 0xB9EB, 0x90B4, 0xB9ED, 0x90B5, 0xB9EE, 0x90B6, 0xB9EF, + 0x90B7, 0xB9F0, 0x90B8, 0xB9F1, 0x90B9, 0xB9F2, 0x90BA, 0xB9F3, 0x90BB, 0xB9F6, 0x90BC, 0xB9FB, 0x90BD, 0xB9FC, 0x90BE, 0xB9FD, + 0x90BF, 0xB9FE, 0x90C0, 0xB9FF, 0x90C1, 0xBA02, 0x90C2, 0xBA03, 0x90C3, 0xBA04, 0x90C4, 0xBA05, 0x90C5, 0xBA06, 0x90C6, 0xBA07, + 0x90C7, 0xBA09, 0x90C8, 0xBA0A, 0x90C9, 0xBA0B, 0x90CA, 0xBA0C, 0x90CB, 0xBA0D, 0x90CC, 0xBA0E, 0x90CD, 0xBA0F, 0x90CE, 0xBA10, + 0x90CF, 0xBA11, 0x90D0, 0xBA12, 0x90D1, 0xBA13, 0x90D2, 0xBA14, 0x90D3, 0xBA16, 0x90D4, 0xBA17, 0x90D5, 0xBA18, 0x90D6, 0xBA19, + 0x90D7, 0xBA1A, 0x90D8, 0xBA1B, 0x90D9, 0xBA1C, 0x90DA, 0xBA1D, 0x90DB, 0xBA1E, 0x90DC, 0xBA1F, 0x90DD, 0xBA20, 0x90DE, 0xBA21, + 0x90DF, 0xBA22, 0x90E0, 0xBA23, 0x90E1, 0xBA24, 0x90E2, 0xBA25, 0x90E3, 0xBA26, 0x90E4, 0xBA27, 0x90E5, 0xBA28, 0x90E6, 0xBA29, + 0x90E7, 0xBA2A, 0x90E8, 0xBA2B, 0x90E9, 0xBA2C, 0x90EA, 0xBA2D, 0x90EB, 0xBA2E, 0x90EC, 0xBA2F, 0x90ED, 0xBA30, 0x90EE, 0xBA31, + 0x90EF, 0xBA32, 0x90F0, 0xBA33, 0x90F1, 0xBA34, 0x90F2, 0xBA35, 0x90F3, 0xBA36, 0x90F4, 0xBA37, 0x90F5, 0xBA3A, 0x90F6, 0xBA3B, + 0x90F7, 0xBA3D, 0x90F8, 0xBA3E, 0x90F9, 0xBA3F, 0x90FA, 0xBA41, 0x90FB, 0xBA43, 0x90FC, 0xBA44, 0x90FD, 0xBA45, 0x90FE, 0xBA46, + 0x9141, 0xBA47, 0x9142, 0xBA4A, 0x9143, 0xBA4C, 0x9144, 0xBA4F, 0x9145, 0xBA50, 0x9146, 0xBA51, 0x9147, 0xBA52, 0x9148, 0xBA56, + 0x9149, 0xBA57, 0x914A, 0xBA59, 0x914B, 0xBA5A, 0x914C, 0xBA5B, 0x914D, 0xBA5D, 0x914E, 0xBA5E, 0x914F, 0xBA5F, 0x9150, 0xBA60, + 0x9151, 0xBA61, 0x9152, 0xBA62, 0x9153, 0xBA63, 0x9154, 0xBA66, 0x9155, 0xBA6A, 0x9156, 0xBA6B, 0x9157, 0xBA6C, 0x9158, 0xBA6D, + 0x9159, 0xBA6E, 0x915A, 0xBA6F, 0x9161, 0xBA72, 0x9162, 0xBA73, 0x9163, 0xBA75, 0x9164, 0xBA76, 0x9165, 0xBA77, 0x9166, 0xBA79, + 0x9167, 0xBA7A, 0x9168, 0xBA7B, 0x9169, 0xBA7C, 0x916A, 0xBA7D, 0x916B, 0xBA7E, 0x916C, 0xBA7F, 0x916D, 0xBA80, 0x916E, 0xBA81, + 0x916F, 0xBA82, 0x9170, 0xBA86, 0x9171, 0xBA88, 0x9172, 0xBA89, 0x9173, 0xBA8A, 0x9174, 0xBA8B, 0x9175, 0xBA8D, 0x9176, 0xBA8E, + 0x9177, 0xBA8F, 0x9178, 0xBA90, 0x9179, 0xBA91, 0x917A, 0xBA92, 0x9181, 0xBA93, 0x9182, 0xBA94, 0x9183, 0xBA95, 0x9184, 0xBA96, + 0x9185, 0xBA97, 0x9186, 0xBA98, 0x9187, 0xBA99, 0x9188, 0xBA9A, 0x9189, 0xBA9B, 0x918A, 0xBA9C, 0x918B, 0xBA9D, 0x918C, 0xBA9E, + 0x918D, 0xBA9F, 0x918E, 0xBAA0, 0x918F, 0xBAA1, 0x9190, 0xBAA2, 0x9191, 0xBAA3, 0x9192, 0xBAA4, 0x9193, 0xBAA5, 0x9194, 0xBAA6, + 0x9195, 0xBAA7, 0x9196, 0xBAAA, 0x9197, 0xBAAD, 0x9198, 0xBAAE, 0x9199, 0xBAAF, 0x919A, 0xBAB1, 0x919B, 0xBAB3, 0x919C, 0xBAB4, + 0x919D, 0xBAB5, 0x919E, 0xBAB6, 0x919F, 0xBAB7, 0x91A0, 0xBABA, 0x91A1, 0xBABC, 0x91A2, 0xBABE, 0x91A3, 0xBABF, 0x91A4, 0xBAC0, + 0x91A5, 0xBAC1, 0x91A6, 0xBAC2, 0x91A7, 0xBAC3, 0x91A8, 0xBAC5, 0x91A9, 0xBAC6, 0x91AA, 0xBAC7, 0x91AB, 0xBAC9, 0x91AC, 0xBACA, + 0x91AD, 0xBACB, 0x91AE, 0xBACC, 0x91AF, 0xBACD, 0x91B0, 0xBACE, 0x91B1, 0xBACF, 0x91B2, 0xBAD0, 0x91B3, 0xBAD1, 0x91B4, 0xBAD2, + 0x91B5, 0xBAD3, 0x91B6, 0xBAD4, 0x91B7, 0xBAD5, 0x91B8, 0xBAD6, 0x91B9, 0xBAD7, 0x91BA, 0xBADA, 0x91BB, 0xBADB, 0x91BC, 0xBADC, + 0x91BD, 0xBADD, 0x91BE, 0xBADE, 0x91BF, 0xBADF, 0x91C0, 0xBAE0, 0x91C1, 0xBAE1, 0x91C2, 0xBAE2, 0x91C3, 0xBAE3, 0x91C4, 0xBAE4, + 0x91C5, 0xBAE5, 0x91C6, 0xBAE6, 0x91C7, 0xBAE7, 0x91C8, 0xBAE8, 0x91C9, 0xBAE9, 0x91CA, 0xBAEA, 0x91CB, 0xBAEB, 0x91CC, 0xBAEC, + 0x91CD, 0xBAED, 0x91CE, 0xBAEE, 0x91CF, 0xBAEF, 0x91D0, 0xBAF0, 0x91D1, 0xBAF1, 0x91D2, 0xBAF2, 0x91D3, 0xBAF3, 0x91D4, 0xBAF4, + 0x91D5, 0xBAF5, 0x91D6, 0xBAF6, 0x91D7, 0xBAF7, 0x91D8, 0xBAF8, 0x91D9, 0xBAF9, 0x91DA, 0xBAFA, 0x91DB, 0xBAFB, 0x91DC, 0xBAFD, + 0x91DD, 0xBAFE, 0x91DE, 0xBAFF, 0x91DF, 0xBB01, 0x91E0, 0xBB02, 0x91E1, 0xBB03, 0x91E2, 0xBB05, 0x91E3, 0xBB06, 0x91E4, 0xBB07, + 0x91E5, 0xBB08, 0x91E6, 0xBB09, 0x91E7, 0xBB0A, 0x91E8, 0xBB0B, 0x91E9, 0xBB0C, 0x91EA, 0xBB0E, 0x91EB, 0xBB10, 0x91EC, 0xBB12, + 0x91ED, 0xBB13, 0x91EE, 0xBB14, 0x91EF, 0xBB15, 0x91F0, 0xBB16, 0x91F1, 0xBB17, 0x91F2, 0xBB19, 0x91F3, 0xBB1A, 0x91F4, 0xBB1B, + 0x91F5, 0xBB1D, 0x91F6, 0xBB1E, 0x91F7, 0xBB1F, 0x91F8, 0xBB21, 0x91F9, 0xBB22, 0x91FA, 0xBB23, 0x91FB, 0xBB24, 0x91FC, 0xBB25, + 0x91FD, 0xBB26, 0x91FE, 0xBB27, 0x9241, 0xBB28, 0x9242, 0xBB2A, 0x9243, 0xBB2C, 0x9244, 0xBB2D, 0x9245, 0xBB2E, 0x9246, 0xBB2F, + 0x9247, 0xBB30, 0x9248, 0xBB31, 0x9249, 0xBB32, 0x924A, 0xBB33, 0x924B, 0xBB37, 0x924C, 0xBB39, 0x924D, 0xBB3A, 0x924E, 0xBB3F, + 0x924F, 0xBB40, 0x9250, 0xBB41, 0x9251, 0xBB42, 0x9252, 0xBB43, 0x9253, 0xBB46, 0x9254, 0xBB48, 0x9255, 0xBB4A, 0x9256, 0xBB4B, + 0x9257, 0xBB4C, 0x9258, 0xBB4E, 0x9259, 0xBB51, 0x925A, 0xBB52, 0x9261, 0xBB53, 0x9262, 0xBB55, 0x9263, 0xBB56, 0x9264, 0xBB57, + 0x9265, 0xBB59, 0x9266, 0xBB5A, 0x9267, 0xBB5B, 0x9268, 0xBB5C, 0x9269, 0xBB5D, 0x926A, 0xBB5E, 0x926B, 0xBB5F, 0x926C, 0xBB60, + 0x926D, 0xBB62, 0x926E, 0xBB64, 0x926F, 0xBB65, 0x9270, 0xBB66, 0x9271, 0xBB67, 0x9272, 0xBB68, 0x9273, 0xBB69, 0x9274, 0xBB6A, + 0x9275, 0xBB6B, 0x9276, 0xBB6D, 0x9277, 0xBB6E, 0x9278, 0xBB6F, 0x9279, 0xBB70, 0x927A, 0xBB71, 0x9281, 0xBB72, 0x9282, 0xBB73, + 0x9283, 0xBB74, 0x9284, 0xBB75, 0x9285, 0xBB76, 0x9286, 0xBB77, 0x9287, 0xBB78, 0x9288, 0xBB79, 0x9289, 0xBB7A, 0x928A, 0xBB7B, + 0x928B, 0xBB7C, 0x928C, 0xBB7D, 0x928D, 0xBB7E, 0x928E, 0xBB7F, 0x928F, 0xBB80, 0x9290, 0xBB81, 0x9291, 0xBB82, 0x9292, 0xBB83, + 0x9293, 0xBB84, 0x9294, 0xBB85, 0x9295, 0xBB86, 0x9296, 0xBB87, 0x9297, 0xBB89, 0x9298, 0xBB8A, 0x9299, 0xBB8B, 0x929A, 0xBB8D, + 0x929B, 0xBB8E, 0x929C, 0xBB8F, 0x929D, 0xBB91, 0x929E, 0xBB92, 0x929F, 0xBB93, 0x92A0, 0xBB94, 0x92A1, 0xBB95, 0x92A2, 0xBB96, + 0x92A3, 0xBB97, 0x92A4, 0xBB98, 0x92A5, 0xBB99, 0x92A6, 0xBB9A, 0x92A7, 0xBB9B, 0x92A8, 0xBB9C, 0x92A9, 0xBB9D, 0x92AA, 0xBB9E, + 0x92AB, 0xBB9F, 0x92AC, 0xBBA0, 0x92AD, 0xBBA1, 0x92AE, 0xBBA2, 0x92AF, 0xBBA3, 0x92B0, 0xBBA5, 0x92B1, 0xBBA6, 0x92B2, 0xBBA7, + 0x92B3, 0xBBA9, 0x92B4, 0xBBAA, 0x92B5, 0xBBAB, 0x92B6, 0xBBAD, 0x92B7, 0xBBAE, 0x92B8, 0xBBAF, 0x92B9, 0xBBB0, 0x92BA, 0xBBB1, + 0x92BB, 0xBBB2, 0x92BC, 0xBBB3, 0x92BD, 0xBBB5, 0x92BE, 0xBBB6, 0x92BF, 0xBBB8, 0x92C0, 0xBBB9, 0x92C1, 0xBBBA, 0x92C2, 0xBBBB, + 0x92C3, 0xBBBC, 0x92C4, 0xBBBD, 0x92C5, 0xBBBE, 0x92C6, 0xBBBF, 0x92C7, 0xBBC1, 0x92C8, 0xBBC2, 0x92C9, 0xBBC3, 0x92CA, 0xBBC5, + 0x92CB, 0xBBC6, 0x92CC, 0xBBC7, 0x92CD, 0xBBC9, 0x92CE, 0xBBCA, 0x92CF, 0xBBCB, 0x92D0, 0xBBCC, 0x92D1, 0xBBCD, 0x92D2, 0xBBCE, + 0x92D3, 0xBBCF, 0x92D4, 0xBBD1, 0x92D5, 0xBBD2, 0x92D6, 0xBBD4, 0x92D7, 0xBBD5, 0x92D8, 0xBBD6, 0x92D9, 0xBBD7, 0x92DA, 0xBBD8, + 0x92DB, 0xBBD9, 0x92DC, 0xBBDA, 0x92DD, 0xBBDB, 0x92DE, 0xBBDC, 0x92DF, 0xBBDD, 0x92E0, 0xBBDE, 0x92E1, 0xBBDF, 0x92E2, 0xBBE0, + 0x92E3, 0xBBE1, 0x92E4, 0xBBE2, 0x92E5, 0xBBE3, 0x92E6, 0xBBE4, 0x92E7, 0xBBE5, 0x92E8, 0xBBE6, 0x92E9, 0xBBE7, 0x92EA, 0xBBE8, + 0x92EB, 0xBBE9, 0x92EC, 0xBBEA, 0x92ED, 0xBBEB, 0x92EE, 0xBBEC, 0x92EF, 0xBBED, 0x92F0, 0xBBEE, 0x92F1, 0xBBEF, 0x92F2, 0xBBF0, + 0x92F3, 0xBBF1, 0x92F4, 0xBBF2, 0x92F5, 0xBBF3, 0x92F6, 0xBBF4, 0x92F7, 0xBBF5, 0x92F8, 0xBBF6, 0x92F9, 0xBBF7, 0x92FA, 0xBBFA, + 0x92FB, 0xBBFB, 0x92FC, 0xBBFD, 0x92FD, 0xBBFE, 0x92FE, 0xBC01, 0x9341, 0xBC03, 0x9342, 0xBC04, 0x9343, 0xBC05, 0x9344, 0xBC06, + 0x9345, 0xBC07, 0x9346, 0xBC0A, 0x9347, 0xBC0E, 0x9348, 0xBC10, 0x9349, 0xBC12, 0x934A, 0xBC13, 0x934B, 0xBC19, 0x934C, 0xBC1A, + 0x934D, 0xBC20, 0x934E, 0xBC21, 0x934F, 0xBC22, 0x9350, 0xBC23, 0x9351, 0xBC26, 0x9352, 0xBC28, 0x9353, 0xBC2A, 0x9354, 0xBC2B, + 0x9355, 0xBC2C, 0x9356, 0xBC2E, 0x9357, 0xBC2F, 0x9358, 0xBC32, 0x9359, 0xBC33, 0x935A, 0xBC35, 0x9361, 0xBC36, 0x9362, 0xBC37, + 0x9363, 0xBC39, 0x9364, 0xBC3A, 0x9365, 0xBC3B, 0x9366, 0xBC3C, 0x9367, 0xBC3D, 0x9368, 0xBC3E, 0x9369, 0xBC3F, 0x936A, 0xBC42, + 0x936B, 0xBC46, 0x936C, 0xBC47, 0x936D, 0xBC48, 0x936E, 0xBC4A, 0x936F, 0xBC4B, 0x9370, 0xBC4E, 0x9371, 0xBC4F, 0x9372, 0xBC51, + 0x9373, 0xBC52, 0x9374, 0xBC53, 0x9375, 0xBC54, 0x9376, 0xBC55, 0x9377, 0xBC56, 0x9378, 0xBC57, 0x9379, 0xBC58, 0x937A, 0xBC59, + 0x9381, 0xBC5A, 0x9382, 0xBC5B, 0x9383, 0xBC5C, 0x9384, 0xBC5E, 0x9385, 0xBC5F, 0x9386, 0xBC60, 0x9387, 0xBC61, 0x9388, 0xBC62, + 0x9389, 0xBC63, 0x938A, 0xBC64, 0x938B, 0xBC65, 0x938C, 0xBC66, 0x938D, 0xBC67, 0x938E, 0xBC68, 0x938F, 0xBC69, 0x9390, 0xBC6A, + 0x9391, 0xBC6B, 0x9392, 0xBC6C, 0x9393, 0xBC6D, 0x9394, 0xBC6E, 0x9395, 0xBC6F, 0x9396, 0xBC70, 0x9397, 0xBC71, 0x9398, 0xBC72, + 0x9399, 0xBC73, 0x939A, 0xBC74, 0x939B, 0xBC75, 0x939C, 0xBC76, 0x939D, 0xBC77, 0x939E, 0xBC78, 0x939F, 0xBC79, 0x93A0, 0xBC7A, + 0x93A1, 0xBC7B, 0x93A2, 0xBC7C, 0x93A3, 0xBC7D, 0x93A4, 0xBC7E, 0x93A5, 0xBC7F, 0x93A6, 0xBC80, 0x93A7, 0xBC81, 0x93A8, 0xBC82, + 0x93A9, 0xBC83, 0x93AA, 0xBC86, 0x93AB, 0xBC87, 0x93AC, 0xBC89, 0x93AD, 0xBC8A, 0x93AE, 0xBC8D, 0x93AF, 0xBC8F, 0x93B0, 0xBC90, + 0x93B1, 0xBC91, 0x93B2, 0xBC92, 0x93B3, 0xBC93, 0x93B4, 0xBC96, 0x93B5, 0xBC98, 0x93B6, 0xBC9B, 0x93B7, 0xBC9C, 0x93B8, 0xBC9D, + 0x93B9, 0xBC9E, 0x93BA, 0xBC9F, 0x93BB, 0xBCA2, 0x93BC, 0xBCA3, 0x93BD, 0xBCA5, 0x93BE, 0xBCA6, 0x93BF, 0xBCA9, 0x93C0, 0xBCAA, + 0x93C1, 0xBCAB, 0x93C2, 0xBCAC, 0x93C3, 0xBCAD, 0x93C4, 0xBCAE, 0x93C5, 0xBCAF, 0x93C6, 0xBCB2, 0x93C7, 0xBCB6, 0x93C8, 0xBCB7, + 0x93C9, 0xBCB8, 0x93CA, 0xBCB9, 0x93CB, 0xBCBA, 0x93CC, 0xBCBB, 0x93CD, 0xBCBE, 0x93CE, 0xBCBF, 0x93CF, 0xBCC1, 0x93D0, 0xBCC2, + 0x93D1, 0xBCC3, 0x93D2, 0xBCC5, 0x93D3, 0xBCC6, 0x93D4, 0xBCC7, 0x93D5, 0xBCC8, 0x93D6, 0xBCC9, 0x93D7, 0xBCCA, 0x93D8, 0xBCCB, + 0x93D9, 0xBCCC, 0x93DA, 0xBCCE, 0x93DB, 0xBCD2, 0x93DC, 0xBCD3, 0x93DD, 0xBCD4, 0x93DE, 0xBCD6, 0x93DF, 0xBCD7, 0x93E0, 0xBCD9, + 0x93E1, 0xBCDA, 0x93E2, 0xBCDB, 0x93E3, 0xBCDD, 0x93E4, 0xBCDE, 0x93E5, 0xBCDF, 0x93E6, 0xBCE0, 0x93E7, 0xBCE1, 0x93E8, 0xBCE2, + 0x93E9, 0xBCE3, 0x93EA, 0xBCE4, 0x93EB, 0xBCE5, 0x93EC, 0xBCE6, 0x93ED, 0xBCE7, 0x93EE, 0xBCE8, 0x93EF, 0xBCE9, 0x93F0, 0xBCEA, + 0x93F1, 0xBCEB, 0x93F2, 0xBCEC, 0x93F3, 0xBCED, 0x93F4, 0xBCEE, 0x93F5, 0xBCEF, 0x93F6, 0xBCF0, 0x93F7, 0xBCF1, 0x93F8, 0xBCF2, + 0x93F9, 0xBCF3, 0x93FA, 0xBCF7, 0x93FB, 0xBCF9, 0x93FC, 0xBCFA, 0x93FD, 0xBCFB, 0x93FE, 0xBCFD, 0x9441, 0xBCFE, 0x9442, 0xBCFF, + 0x9443, 0xBD00, 0x9444, 0xBD01, 0x9445, 0xBD02, 0x9446, 0xBD03, 0x9447, 0xBD06, 0x9448, 0xBD08, 0x9449, 0xBD0A, 0x944A, 0xBD0B, + 0x944B, 0xBD0C, 0x944C, 0xBD0D, 0x944D, 0xBD0E, 0x944E, 0xBD0F, 0x944F, 0xBD11, 0x9450, 0xBD12, 0x9451, 0xBD13, 0x9452, 0xBD15, + 0x9453, 0xBD16, 0x9454, 0xBD17, 0x9455, 0xBD18, 0x9456, 0xBD19, 0x9457, 0xBD1A, 0x9458, 0xBD1B, 0x9459, 0xBD1C, 0x945A, 0xBD1D, + 0x9461, 0xBD1E, 0x9462, 0xBD1F, 0x9463, 0xBD20, 0x9464, 0xBD21, 0x9465, 0xBD22, 0x9466, 0xBD23, 0x9467, 0xBD25, 0x9468, 0xBD26, + 0x9469, 0xBD27, 0x946A, 0xBD28, 0x946B, 0xBD29, 0x946C, 0xBD2A, 0x946D, 0xBD2B, 0x946E, 0xBD2D, 0x946F, 0xBD2E, 0x9470, 0xBD2F, + 0x9471, 0xBD30, 0x9472, 0xBD31, 0x9473, 0xBD32, 0x9474, 0xBD33, 0x9475, 0xBD34, 0x9476, 0xBD35, 0x9477, 0xBD36, 0x9478, 0xBD37, + 0x9479, 0xBD38, 0x947A, 0xBD39, 0x9481, 0xBD3A, 0x9482, 0xBD3B, 0x9483, 0xBD3C, 0x9484, 0xBD3D, 0x9485, 0xBD3E, 0x9486, 0xBD3F, + 0x9487, 0xBD41, 0x9488, 0xBD42, 0x9489, 0xBD43, 0x948A, 0xBD44, 0x948B, 0xBD45, 0x948C, 0xBD46, 0x948D, 0xBD47, 0x948E, 0xBD4A, + 0x948F, 0xBD4B, 0x9490, 0xBD4D, 0x9491, 0xBD4E, 0x9492, 0xBD4F, 0x9493, 0xBD51, 0x9494, 0xBD52, 0x9495, 0xBD53, 0x9496, 0xBD54, + 0x9497, 0xBD55, 0x9498, 0xBD56, 0x9499, 0xBD57, 0x949A, 0xBD5A, 0x949B, 0xBD5B, 0x949C, 0xBD5C, 0x949D, 0xBD5D, 0x949E, 0xBD5E, + 0x949F, 0xBD5F, 0x94A0, 0xBD60, 0x94A1, 0xBD61, 0x94A2, 0xBD62, 0x94A3, 0xBD63, 0x94A4, 0xBD65, 0x94A5, 0xBD66, 0x94A6, 0xBD67, + 0x94A7, 0xBD69, 0x94A8, 0xBD6A, 0x94A9, 0xBD6B, 0x94AA, 0xBD6C, 0x94AB, 0xBD6D, 0x94AC, 0xBD6E, 0x94AD, 0xBD6F, 0x94AE, 0xBD70, + 0x94AF, 0xBD71, 0x94B0, 0xBD72, 0x94B1, 0xBD73, 0x94B2, 0xBD74, 0x94B3, 0xBD75, 0x94B4, 0xBD76, 0x94B5, 0xBD77, 0x94B6, 0xBD78, + 0x94B7, 0xBD79, 0x94B8, 0xBD7A, 0x94B9, 0xBD7B, 0x94BA, 0xBD7C, 0x94BB, 0xBD7D, 0x94BC, 0xBD7E, 0x94BD, 0xBD7F, 0x94BE, 0xBD82, + 0x94BF, 0xBD83, 0x94C0, 0xBD85, 0x94C1, 0xBD86, 0x94C2, 0xBD8B, 0x94C3, 0xBD8C, 0x94C4, 0xBD8D, 0x94C5, 0xBD8E, 0x94C6, 0xBD8F, + 0x94C7, 0xBD92, 0x94C8, 0xBD94, 0x94C9, 0xBD96, 0x94CA, 0xBD97, 0x94CB, 0xBD98, 0x94CC, 0xBD9B, 0x94CD, 0xBD9D, 0x94CE, 0xBD9E, + 0x94CF, 0xBD9F, 0x94D0, 0xBDA0, 0x94D1, 0xBDA1, 0x94D2, 0xBDA2, 0x94D3, 0xBDA3, 0x94D4, 0xBDA5, 0x94D5, 0xBDA6, 0x94D6, 0xBDA7, + 0x94D7, 0xBDA8, 0x94D8, 0xBDA9, 0x94D9, 0xBDAA, 0x94DA, 0xBDAB, 0x94DB, 0xBDAC, 0x94DC, 0xBDAD, 0x94DD, 0xBDAE, 0x94DE, 0xBDAF, + 0x94DF, 0xBDB1, 0x94E0, 0xBDB2, 0x94E1, 0xBDB3, 0x94E2, 0xBDB4, 0x94E3, 0xBDB5, 0x94E4, 0xBDB6, 0x94E5, 0xBDB7, 0x94E6, 0xBDB9, + 0x94E7, 0xBDBA, 0x94E8, 0xBDBB, 0x94E9, 0xBDBC, 0x94EA, 0xBDBD, 0x94EB, 0xBDBE, 0x94EC, 0xBDBF, 0x94ED, 0xBDC0, 0x94EE, 0xBDC1, + 0x94EF, 0xBDC2, 0x94F0, 0xBDC3, 0x94F1, 0xBDC4, 0x94F2, 0xBDC5, 0x94F3, 0xBDC6, 0x94F4, 0xBDC7, 0x94F5, 0xBDC8, 0x94F6, 0xBDC9, + 0x94F7, 0xBDCA, 0x94F8, 0xBDCB, 0x94F9, 0xBDCC, 0x94FA, 0xBDCD, 0x94FB, 0xBDCE, 0x94FC, 0xBDCF, 0x94FD, 0xBDD0, 0x94FE, 0xBDD1, + 0x9541, 0xBDD2, 0x9542, 0xBDD3, 0x9543, 0xBDD6, 0x9544, 0xBDD7, 0x9545, 0xBDD9, 0x9546, 0xBDDA, 0x9547, 0xBDDB, 0x9548, 0xBDDD, + 0x9549, 0xBDDE, 0x954A, 0xBDDF, 0x954B, 0xBDE0, 0x954C, 0xBDE1, 0x954D, 0xBDE2, 0x954E, 0xBDE3, 0x954F, 0xBDE4, 0x9550, 0xBDE5, + 0x9551, 0xBDE6, 0x9552, 0xBDE7, 0x9553, 0xBDE8, 0x9554, 0xBDEA, 0x9555, 0xBDEB, 0x9556, 0xBDEC, 0x9557, 0xBDED, 0x9558, 0xBDEE, + 0x9559, 0xBDEF, 0x955A, 0xBDF1, 0x9561, 0xBDF2, 0x9562, 0xBDF3, 0x9563, 0xBDF5, 0x9564, 0xBDF6, 0x9565, 0xBDF7, 0x9566, 0xBDF9, + 0x9567, 0xBDFA, 0x9568, 0xBDFB, 0x9569, 0xBDFC, 0x956A, 0xBDFD, 0x956B, 0xBDFE, 0x956C, 0xBDFF, 0x956D, 0xBE01, 0x956E, 0xBE02, + 0x956F, 0xBE04, 0x9570, 0xBE06, 0x9571, 0xBE07, 0x9572, 0xBE08, 0x9573, 0xBE09, 0x9574, 0xBE0A, 0x9575, 0xBE0B, 0x9576, 0xBE0E, + 0x9577, 0xBE0F, 0x9578, 0xBE11, 0x9579, 0xBE12, 0x957A, 0xBE13, 0x9581, 0xBE15, 0x9582, 0xBE16, 0x9583, 0xBE17, 0x9584, 0xBE18, + 0x9585, 0xBE19, 0x9586, 0xBE1A, 0x9587, 0xBE1B, 0x9588, 0xBE1E, 0x9589, 0xBE20, 0x958A, 0xBE21, 0x958B, 0xBE22, 0x958C, 0xBE23, + 0x958D, 0xBE24, 0x958E, 0xBE25, 0x958F, 0xBE26, 0x9590, 0xBE27, 0x9591, 0xBE28, 0x9592, 0xBE29, 0x9593, 0xBE2A, 0x9594, 0xBE2B, + 0x9595, 0xBE2C, 0x9596, 0xBE2D, 0x9597, 0xBE2E, 0x9598, 0xBE2F, 0x9599, 0xBE30, 0x959A, 0xBE31, 0x959B, 0xBE32, 0x959C, 0xBE33, + 0x959D, 0xBE34, 0x959E, 0xBE35, 0x959F, 0xBE36, 0x95A0, 0xBE37, 0x95A1, 0xBE38, 0x95A2, 0xBE39, 0x95A3, 0xBE3A, 0x95A4, 0xBE3B, + 0x95A5, 0xBE3C, 0x95A6, 0xBE3D, 0x95A7, 0xBE3E, 0x95A8, 0xBE3F, 0x95A9, 0xBE40, 0x95AA, 0xBE41, 0x95AB, 0xBE42, 0x95AC, 0xBE43, + 0x95AD, 0xBE46, 0x95AE, 0xBE47, 0x95AF, 0xBE49, 0x95B0, 0xBE4A, 0x95B1, 0xBE4B, 0x95B2, 0xBE4D, 0x95B3, 0xBE4F, 0x95B4, 0xBE50, + 0x95B5, 0xBE51, 0x95B6, 0xBE52, 0x95B7, 0xBE53, 0x95B8, 0xBE56, 0x95B9, 0xBE58, 0x95BA, 0xBE5C, 0x95BB, 0xBE5D, 0x95BC, 0xBE5E, + 0x95BD, 0xBE5F, 0x95BE, 0xBE62, 0x95BF, 0xBE63, 0x95C0, 0xBE65, 0x95C1, 0xBE66, 0x95C2, 0xBE67, 0x95C3, 0xBE69, 0x95C4, 0xBE6B, + 0x95C5, 0xBE6C, 0x95C6, 0xBE6D, 0x95C7, 0xBE6E, 0x95C8, 0xBE6F, 0x95C9, 0xBE72, 0x95CA, 0xBE76, 0x95CB, 0xBE77, 0x95CC, 0xBE78, + 0x95CD, 0xBE79, 0x95CE, 0xBE7A, 0x95CF, 0xBE7E, 0x95D0, 0xBE7F, 0x95D1, 0xBE81, 0x95D2, 0xBE82, 0x95D3, 0xBE83, 0x95D4, 0xBE85, + 0x95D5, 0xBE86, 0x95D6, 0xBE87, 0x95D7, 0xBE88, 0x95D8, 0xBE89, 0x95D9, 0xBE8A, 0x95DA, 0xBE8B, 0x95DB, 0xBE8E, 0x95DC, 0xBE92, + 0x95DD, 0xBE93, 0x95DE, 0xBE94, 0x95DF, 0xBE95, 0x95E0, 0xBE96, 0x95E1, 0xBE97, 0x95E2, 0xBE9A, 0x95E3, 0xBE9B, 0x95E4, 0xBE9C, + 0x95E5, 0xBE9D, 0x95E6, 0xBE9E, 0x95E7, 0xBE9F, 0x95E8, 0xBEA0, 0x95E9, 0xBEA1, 0x95EA, 0xBEA2, 0x95EB, 0xBEA3, 0x95EC, 0xBEA4, + 0x95ED, 0xBEA5, 0x95EE, 0xBEA6, 0x95EF, 0xBEA7, 0x95F0, 0xBEA9, 0x95F1, 0xBEAA, 0x95F2, 0xBEAB, 0x95F3, 0xBEAC, 0x95F4, 0xBEAD, + 0x95F5, 0xBEAE, 0x95F6, 0xBEAF, 0x95F7, 0xBEB0, 0x95F8, 0xBEB1, 0x95F9, 0xBEB2, 0x95FA, 0xBEB3, 0x95FB, 0xBEB4, 0x95FC, 0xBEB5, + 0x95FD, 0xBEB6, 0x95FE, 0xBEB7, 0x9641, 0xBEB8, 0x9642, 0xBEB9, 0x9643, 0xBEBA, 0x9644, 0xBEBB, 0x9645, 0xBEBC, 0x9646, 0xBEBD, + 0x9647, 0xBEBE, 0x9648, 0xBEBF, 0x9649, 0xBEC0, 0x964A, 0xBEC1, 0x964B, 0xBEC2, 0x964C, 0xBEC3, 0x964D, 0xBEC4, 0x964E, 0xBEC5, + 0x964F, 0xBEC6, 0x9650, 0xBEC7, 0x9651, 0xBEC8, 0x9652, 0xBEC9, 0x9653, 0xBECA, 0x9654, 0xBECB, 0x9655, 0xBECC, 0x9656, 0xBECD, + 0x9657, 0xBECE, 0x9658, 0xBECF, 0x9659, 0xBED2, 0x965A, 0xBED3, 0x9661, 0xBED5, 0x9662, 0xBED6, 0x9663, 0xBED9, 0x9664, 0xBEDA, + 0x9665, 0xBEDB, 0x9666, 0xBEDC, 0x9667, 0xBEDD, 0x9668, 0xBEDE, 0x9669, 0xBEDF, 0x966A, 0xBEE1, 0x966B, 0xBEE2, 0x966C, 0xBEE6, + 0x966D, 0xBEE7, 0x966E, 0xBEE8, 0x966F, 0xBEE9, 0x9670, 0xBEEA, 0x9671, 0xBEEB, 0x9672, 0xBEED, 0x9673, 0xBEEE, 0x9674, 0xBEEF, + 0x9675, 0xBEF0, 0x9676, 0xBEF1, 0x9677, 0xBEF2, 0x9678, 0xBEF3, 0x9679, 0xBEF4, 0x967A, 0xBEF5, 0x9681, 0xBEF6, 0x9682, 0xBEF7, + 0x9683, 0xBEF8, 0x9684, 0xBEF9, 0x9685, 0xBEFA, 0x9686, 0xBEFB, 0x9687, 0xBEFC, 0x9688, 0xBEFD, 0x9689, 0xBEFE, 0x968A, 0xBEFF, + 0x968B, 0xBF00, 0x968C, 0xBF02, 0x968D, 0xBF03, 0x968E, 0xBF04, 0x968F, 0xBF05, 0x9690, 0xBF06, 0x9691, 0xBF07, 0x9692, 0xBF0A, + 0x9693, 0xBF0B, 0x9694, 0xBF0C, 0x9695, 0xBF0D, 0x9696, 0xBF0E, 0x9697, 0xBF0F, 0x9698, 0xBF10, 0x9699, 0xBF11, 0x969A, 0xBF12, + 0x969B, 0xBF13, 0x969C, 0xBF14, 0x969D, 0xBF15, 0x969E, 0xBF16, 0x969F, 0xBF17, 0x96A0, 0xBF1A, 0x96A1, 0xBF1E, 0x96A2, 0xBF1F, + 0x96A3, 0xBF20, 0x96A4, 0xBF21, 0x96A5, 0xBF22, 0x96A6, 0xBF23, 0x96A7, 0xBF24, 0x96A8, 0xBF25, 0x96A9, 0xBF26, 0x96AA, 0xBF27, + 0x96AB, 0xBF28, 0x96AC, 0xBF29, 0x96AD, 0xBF2A, 0x96AE, 0xBF2B, 0x96AF, 0xBF2C, 0x96B0, 0xBF2D, 0x96B1, 0xBF2E, 0x96B2, 0xBF2F, + 0x96B3, 0xBF30, 0x96B4, 0xBF31, 0x96B5, 0xBF32, 0x96B6, 0xBF33, 0x96B7, 0xBF34, 0x96B8, 0xBF35, 0x96B9, 0xBF36, 0x96BA, 0xBF37, + 0x96BB, 0xBF38, 0x96BC, 0xBF39, 0x96BD, 0xBF3A, 0x96BE, 0xBF3B, 0x96BF, 0xBF3C, 0x96C0, 0xBF3D, 0x96C1, 0xBF3E, 0x96C2, 0xBF3F, + 0x96C3, 0xBF42, 0x96C4, 0xBF43, 0x96C5, 0xBF45, 0x96C6, 0xBF46, 0x96C7, 0xBF47, 0x96C8, 0xBF49, 0x96C9, 0xBF4A, 0x96CA, 0xBF4B, + 0x96CB, 0xBF4C, 0x96CC, 0xBF4D, 0x96CD, 0xBF4E, 0x96CE, 0xBF4F, 0x96CF, 0xBF52, 0x96D0, 0xBF53, 0x96D1, 0xBF54, 0x96D2, 0xBF56, + 0x96D3, 0xBF57, 0x96D4, 0xBF58, 0x96D5, 0xBF59, 0x96D6, 0xBF5A, 0x96D7, 0xBF5B, 0x96D8, 0xBF5C, 0x96D9, 0xBF5D, 0x96DA, 0xBF5E, + 0x96DB, 0xBF5F, 0x96DC, 0xBF60, 0x96DD, 0xBF61, 0x96DE, 0xBF62, 0x96DF, 0xBF63, 0x96E0, 0xBF64, 0x96E1, 0xBF65, 0x96E2, 0xBF66, + 0x96E3, 0xBF67, 0x96E4, 0xBF68, 0x96E5, 0xBF69, 0x96E6, 0xBF6A, 0x96E7, 0xBF6B, 0x96E8, 0xBF6C, 0x96E9, 0xBF6D, 0x96EA, 0xBF6E, + 0x96EB, 0xBF6F, 0x96EC, 0xBF70, 0x96ED, 0xBF71, 0x96EE, 0xBF72, 0x96EF, 0xBF73, 0x96F0, 0xBF74, 0x96F1, 0xBF75, 0x96F2, 0xBF76, + 0x96F3, 0xBF77, 0x96F4, 0xBF78, 0x96F5, 0xBF79, 0x96F6, 0xBF7A, 0x96F7, 0xBF7B, 0x96F8, 0xBF7C, 0x96F9, 0xBF7D, 0x96FA, 0xBF7E, + 0x96FB, 0xBF7F, 0x96FC, 0xBF80, 0x96FD, 0xBF81, 0x96FE, 0xBF82, 0x9741, 0xBF83, 0x9742, 0xBF84, 0x9743, 0xBF85, 0x9744, 0xBF86, + 0x9745, 0xBF87, 0x9746, 0xBF88, 0x9747, 0xBF89, 0x9748, 0xBF8A, 0x9749, 0xBF8B, 0x974A, 0xBF8C, 0x974B, 0xBF8D, 0x974C, 0xBF8E, + 0x974D, 0xBF8F, 0x974E, 0xBF90, 0x974F, 0xBF91, 0x9750, 0xBF92, 0x9751, 0xBF93, 0x9752, 0xBF95, 0x9753, 0xBF96, 0x9754, 0xBF97, + 0x9755, 0xBF98, 0x9756, 0xBF99, 0x9757, 0xBF9A, 0x9758, 0xBF9B, 0x9759, 0xBF9C, 0x975A, 0xBF9D, 0x9761, 0xBF9E, 0x9762, 0xBF9F, + 0x9763, 0xBFA0, 0x9764, 0xBFA1, 0x9765, 0xBFA2, 0x9766, 0xBFA3, 0x9767, 0xBFA4, 0x9768, 0xBFA5, 0x9769, 0xBFA6, 0x976A, 0xBFA7, + 0x976B, 0xBFA8, 0x976C, 0xBFA9, 0x976D, 0xBFAA, 0x976E, 0xBFAB, 0x976F, 0xBFAC, 0x9770, 0xBFAD, 0x9771, 0xBFAE, 0x9772, 0xBFAF, + 0x9773, 0xBFB1, 0x9774, 0xBFB2, 0x9775, 0xBFB3, 0x9776, 0xBFB4, 0x9777, 0xBFB5, 0x9778, 0xBFB6, 0x9779, 0xBFB7, 0x977A, 0xBFB8, + 0x9781, 0xBFB9, 0x9782, 0xBFBA, 0x9783, 0xBFBB, 0x9784, 0xBFBC, 0x9785, 0xBFBD, 0x9786, 0xBFBE, 0x9787, 0xBFBF, 0x9788, 0xBFC0, + 0x9789, 0xBFC1, 0x978A, 0xBFC2, 0x978B, 0xBFC3, 0x978C, 0xBFC4, 0x978D, 0xBFC6, 0x978E, 0xBFC7, 0x978F, 0xBFC8, 0x9790, 0xBFC9, + 0x9791, 0xBFCA, 0x9792, 0xBFCB, 0x9793, 0xBFCE, 0x9794, 0xBFCF, 0x9795, 0xBFD1, 0x9796, 0xBFD2, 0x9797, 0xBFD3, 0x9798, 0xBFD5, + 0x9799, 0xBFD6, 0x979A, 0xBFD7, 0x979B, 0xBFD8, 0x979C, 0xBFD9, 0x979D, 0xBFDA, 0x979E, 0xBFDB, 0x979F, 0xBFDD, 0x97A0, 0xBFDE, + 0x97A1, 0xBFE0, 0x97A2, 0xBFE2, 0x97A3, 0xBFE3, 0x97A4, 0xBFE4, 0x97A5, 0xBFE5, 0x97A6, 0xBFE6, 0x97A7, 0xBFE7, 0x97A8, 0xBFE8, + 0x97A9, 0xBFE9, 0x97AA, 0xBFEA, 0x97AB, 0xBFEB, 0x97AC, 0xBFEC, 0x97AD, 0xBFED, 0x97AE, 0xBFEE, 0x97AF, 0xBFEF, 0x97B0, 0xBFF0, + 0x97B1, 0xBFF1, 0x97B2, 0xBFF2, 0x97B3, 0xBFF3, 0x97B4, 0xBFF4, 0x97B5, 0xBFF5, 0x97B6, 0xBFF6, 0x97B7, 0xBFF7, 0x97B8, 0xBFF8, + 0x97B9, 0xBFF9, 0x97BA, 0xBFFA, 0x97BB, 0xBFFB, 0x97BC, 0xBFFC, 0x97BD, 0xBFFD, 0x97BE, 0xBFFE, 0x97BF, 0xBFFF, 0x97C0, 0xC000, + 0x97C1, 0xC001, 0x97C2, 0xC002, 0x97C3, 0xC003, 0x97C4, 0xC004, 0x97C5, 0xC005, 0x97C6, 0xC006, 0x97C7, 0xC007, 0x97C8, 0xC008, + 0x97C9, 0xC009, 0x97CA, 0xC00A, 0x97CB, 0xC00B, 0x97CC, 0xC00C, 0x97CD, 0xC00D, 0x97CE, 0xC00E, 0x97CF, 0xC00F, 0x97D0, 0xC010, + 0x97D1, 0xC011, 0x97D2, 0xC012, 0x97D3, 0xC013, 0x97D4, 0xC014, 0x97D5, 0xC015, 0x97D6, 0xC016, 0x97D7, 0xC017, 0x97D8, 0xC018, + 0x97D9, 0xC019, 0x97DA, 0xC01A, 0x97DB, 0xC01B, 0x97DC, 0xC01C, 0x97DD, 0xC01D, 0x97DE, 0xC01E, 0x97DF, 0xC01F, 0x97E0, 0xC020, + 0x97E1, 0xC021, 0x97E2, 0xC022, 0x97E3, 0xC023, 0x97E4, 0xC024, 0x97E5, 0xC025, 0x97E6, 0xC026, 0x97E7, 0xC027, 0x97E8, 0xC028, + 0x97E9, 0xC029, 0x97EA, 0xC02A, 0x97EB, 0xC02B, 0x97EC, 0xC02C, 0x97ED, 0xC02D, 0x97EE, 0xC02E, 0x97EF, 0xC02F, 0x97F0, 0xC030, + 0x97F1, 0xC031, 0x97F2, 0xC032, 0x97F3, 0xC033, 0x97F4, 0xC034, 0x97F5, 0xC035, 0x97F6, 0xC036, 0x97F7, 0xC037, 0x97F8, 0xC038, + 0x97F9, 0xC039, 0x97FA, 0xC03A, 0x97FB, 0xC03B, 0x97FC, 0xC03D, 0x97FD, 0xC03E, 0x97FE, 0xC03F, 0x9841, 0xC040, 0x9842, 0xC041, + 0x9843, 0xC042, 0x9844, 0xC043, 0x9845, 0xC044, 0x9846, 0xC045, 0x9847, 0xC046, 0x9848, 0xC047, 0x9849, 0xC048, 0x984A, 0xC049, + 0x984B, 0xC04A, 0x984C, 0xC04B, 0x984D, 0xC04C, 0x984E, 0xC04D, 0x984F, 0xC04E, 0x9850, 0xC04F, 0x9851, 0xC050, 0x9852, 0xC052, + 0x9853, 0xC053, 0x9854, 0xC054, 0x9855, 0xC055, 0x9856, 0xC056, 0x9857, 0xC057, 0x9858, 0xC059, 0x9859, 0xC05A, 0x985A, 0xC05B, + 0x9861, 0xC05D, 0x9862, 0xC05E, 0x9863, 0xC05F, 0x9864, 0xC061, 0x9865, 0xC062, 0x9866, 0xC063, 0x9867, 0xC064, 0x9868, 0xC065, + 0x9869, 0xC066, 0x986A, 0xC067, 0x986B, 0xC06A, 0x986C, 0xC06B, 0x986D, 0xC06C, 0x986E, 0xC06D, 0x986F, 0xC06E, 0x9870, 0xC06F, + 0x9871, 0xC070, 0x9872, 0xC071, 0x9873, 0xC072, 0x9874, 0xC073, 0x9875, 0xC074, 0x9876, 0xC075, 0x9877, 0xC076, 0x9878, 0xC077, + 0x9879, 0xC078, 0x987A, 0xC079, 0x9881, 0xC07A, 0x9882, 0xC07B, 0x9883, 0xC07C, 0x9884, 0xC07D, 0x9885, 0xC07E, 0x9886, 0xC07F, + 0x9887, 0xC080, 0x9888, 0xC081, 0x9889, 0xC082, 0x988A, 0xC083, 0x988B, 0xC084, 0x988C, 0xC085, 0x988D, 0xC086, 0x988E, 0xC087, + 0x988F, 0xC088, 0x9890, 0xC089, 0x9891, 0xC08A, 0x9892, 0xC08B, 0x9893, 0xC08C, 0x9894, 0xC08D, 0x9895, 0xC08E, 0x9896, 0xC08F, + 0x9897, 0xC092, 0x9898, 0xC093, 0x9899, 0xC095, 0x989A, 0xC096, 0x989B, 0xC097, 0x989C, 0xC099, 0x989D, 0xC09A, 0x989E, 0xC09B, + 0x989F, 0xC09C, 0x98A0, 0xC09D, 0x98A1, 0xC09E, 0x98A2, 0xC09F, 0x98A3, 0xC0A2, 0x98A4, 0xC0A4, 0x98A5, 0xC0A6, 0x98A6, 0xC0A7, + 0x98A7, 0xC0A8, 0x98A8, 0xC0A9, 0x98A9, 0xC0AA, 0x98AA, 0xC0AB, 0x98AB, 0xC0AE, 0x98AC, 0xC0B1, 0x98AD, 0xC0B2, 0x98AE, 0xC0B7, + 0x98AF, 0xC0B8, 0x98B0, 0xC0B9, 0x98B1, 0xC0BA, 0x98B2, 0xC0BB, 0x98B3, 0xC0BE, 0x98B4, 0xC0C2, 0x98B5, 0xC0C3, 0x98B6, 0xC0C4, + 0x98B7, 0xC0C6, 0x98B8, 0xC0C7, 0x98B9, 0xC0CA, 0x98BA, 0xC0CB, 0x98BB, 0xC0CD, 0x98BC, 0xC0CE, 0x98BD, 0xC0CF, 0x98BE, 0xC0D1, + 0x98BF, 0xC0D2, 0x98C0, 0xC0D3, 0x98C1, 0xC0D4, 0x98C2, 0xC0D5, 0x98C3, 0xC0D6, 0x98C4, 0xC0D7, 0x98C5, 0xC0DA, 0x98C6, 0xC0DE, + 0x98C7, 0xC0DF, 0x98C8, 0xC0E0, 0x98C9, 0xC0E1, 0x98CA, 0xC0E2, 0x98CB, 0xC0E3, 0x98CC, 0xC0E6, 0x98CD, 0xC0E7, 0x98CE, 0xC0E9, + 0x98CF, 0xC0EA, 0x98D0, 0xC0EB, 0x98D1, 0xC0ED, 0x98D2, 0xC0EE, 0x98D3, 0xC0EF, 0x98D4, 0xC0F0, 0x98D5, 0xC0F1, 0x98D6, 0xC0F2, + 0x98D7, 0xC0F3, 0x98D8, 0xC0F6, 0x98D9, 0xC0F8, 0x98DA, 0xC0FA, 0x98DB, 0xC0FB, 0x98DC, 0xC0FC, 0x98DD, 0xC0FD, 0x98DE, 0xC0FE, + 0x98DF, 0xC0FF, 0x98E0, 0xC101, 0x98E1, 0xC102, 0x98E2, 0xC103, 0x98E3, 0xC105, 0x98E4, 0xC106, 0x98E5, 0xC107, 0x98E6, 0xC109, + 0x98E7, 0xC10A, 0x98E8, 0xC10B, 0x98E9, 0xC10C, 0x98EA, 0xC10D, 0x98EB, 0xC10E, 0x98EC, 0xC10F, 0x98ED, 0xC111, 0x98EE, 0xC112, + 0x98EF, 0xC113, 0x98F0, 0xC114, 0x98F1, 0xC116, 0x98F2, 0xC117, 0x98F3, 0xC118, 0x98F4, 0xC119, 0x98F5, 0xC11A, 0x98F6, 0xC11B, + 0x98F7, 0xC121, 0x98F8, 0xC122, 0x98F9, 0xC125, 0x98FA, 0xC128, 0x98FB, 0xC129, 0x98FC, 0xC12A, 0x98FD, 0xC12B, 0x98FE, 0xC12E, + 0x9941, 0xC132, 0x9942, 0xC133, 0x9943, 0xC134, 0x9944, 0xC135, 0x9945, 0xC137, 0x9946, 0xC13A, 0x9947, 0xC13B, 0x9948, 0xC13D, + 0x9949, 0xC13E, 0x994A, 0xC13F, 0x994B, 0xC141, 0x994C, 0xC142, 0x994D, 0xC143, 0x994E, 0xC144, 0x994F, 0xC145, 0x9950, 0xC146, + 0x9951, 0xC147, 0x9952, 0xC14A, 0x9953, 0xC14E, 0x9954, 0xC14F, 0x9955, 0xC150, 0x9956, 0xC151, 0x9957, 0xC152, 0x9958, 0xC153, + 0x9959, 0xC156, 0x995A, 0xC157, 0x9961, 0xC159, 0x9962, 0xC15A, 0x9963, 0xC15B, 0x9964, 0xC15D, 0x9965, 0xC15E, 0x9966, 0xC15F, + 0x9967, 0xC160, 0x9968, 0xC161, 0x9969, 0xC162, 0x996A, 0xC163, 0x996B, 0xC166, 0x996C, 0xC16A, 0x996D, 0xC16B, 0x996E, 0xC16C, + 0x996F, 0xC16D, 0x9970, 0xC16E, 0x9971, 0xC16F, 0x9972, 0xC171, 0x9973, 0xC172, 0x9974, 0xC173, 0x9975, 0xC175, 0x9976, 0xC176, + 0x9977, 0xC177, 0x9978, 0xC179, 0x9979, 0xC17A, 0x997A, 0xC17B, 0x9981, 0xC17C, 0x9982, 0xC17D, 0x9983, 0xC17E, 0x9984, 0xC17F, + 0x9985, 0xC180, 0x9986, 0xC181, 0x9987, 0xC182, 0x9988, 0xC183, 0x9989, 0xC184, 0x998A, 0xC186, 0x998B, 0xC187, 0x998C, 0xC188, + 0x998D, 0xC189, 0x998E, 0xC18A, 0x998F, 0xC18B, 0x9990, 0xC18F, 0x9991, 0xC191, 0x9992, 0xC192, 0x9993, 0xC193, 0x9994, 0xC195, + 0x9995, 0xC197, 0x9996, 0xC198, 0x9997, 0xC199, 0x9998, 0xC19A, 0x9999, 0xC19B, 0x999A, 0xC19E, 0x999B, 0xC1A0, 0x999C, 0xC1A2, + 0x999D, 0xC1A3, 0x999E, 0xC1A4, 0x999F, 0xC1A6, 0x99A0, 0xC1A7, 0x99A1, 0xC1AA, 0x99A2, 0xC1AB, 0x99A3, 0xC1AD, 0x99A4, 0xC1AE, + 0x99A5, 0xC1AF, 0x99A6, 0xC1B1, 0x99A7, 0xC1B2, 0x99A8, 0xC1B3, 0x99A9, 0xC1B4, 0x99AA, 0xC1B5, 0x99AB, 0xC1B6, 0x99AC, 0xC1B7, + 0x99AD, 0xC1B8, 0x99AE, 0xC1B9, 0x99AF, 0xC1BA, 0x99B0, 0xC1BB, 0x99B1, 0xC1BC, 0x99B2, 0xC1BE, 0x99B3, 0xC1BF, 0x99B4, 0xC1C0, + 0x99B5, 0xC1C1, 0x99B6, 0xC1C2, 0x99B7, 0xC1C3, 0x99B8, 0xC1C5, 0x99B9, 0xC1C6, 0x99BA, 0xC1C7, 0x99BB, 0xC1C9, 0x99BC, 0xC1CA, + 0x99BD, 0xC1CB, 0x99BE, 0xC1CD, 0x99BF, 0xC1CE, 0x99C0, 0xC1CF, 0x99C1, 0xC1D0, 0x99C2, 0xC1D1, 0x99C3, 0xC1D2, 0x99C4, 0xC1D3, + 0x99C5, 0xC1D5, 0x99C6, 0xC1D6, 0x99C7, 0xC1D9, 0x99C8, 0xC1DA, 0x99C9, 0xC1DB, 0x99CA, 0xC1DC, 0x99CB, 0xC1DD, 0x99CC, 0xC1DE, + 0x99CD, 0xC1DF, 0x99CE, 0xC1E1, 0x99CF, 0xC1E2, 0x99D0, 0xC1E3, 0x99D1, 0xC1E5, 0x99D2, 0xC1E6, 0x99D3, 0xC1E7, 0x99D4, 0xC1E9, + 0x99D5, 0xC1EA, 0x99D6, 0xC1EB, 0x99D7, 0xC1EC, 0x99D8, 0xC1ED, 0x99D9, 0xC1EE, 0x99DA, 0xC1EF, 0x99DB, 0xC1F2, 0x99DC, 0xC1F4, + 0x99DD, 0xC1F5, 0x99DE, 0xC1F6, 0x99DF, 0xC1F7, 0x99E0, 0xC1F8, 0x99E1, 0xC1F9, 0x99E2, 0xC1FA, 0x99E3, 0xC1FB, 0x99E4, 0xC1FE, + 0x99E5, 0xC1FF, 0x99E6, 0xC201, 0x99E7, 0xC202, 0x99E8, 0xC203, 0x99E9, 0xC205, 0x99EA, 0xC206, 0x99EB, 0xC207, 0x99EC, 0xC208, + 0x99ED, 0xC209, 0x99EE, 0xC20A, 0x99EF, 0xC20B, 0x99F0, 0xC20E, 0x99F1, 0xC210, 0x99F2, 0xC212, 0x99F3, 0xC213, 0x99F4, 0xC214, + 0x99F5, 0xC215, 0x99F6, 0xC216, 0x99F7, 0xC217, 0x99F8, 0xC21A, 0x99F9, 0xC21B, 0x99FA, 0xC21D, 0x99FB, 0xC21E, 0x99FC, 0xC221, + 0x99FD, 0xC222, 0x99FE, 0xC223, 0x9A41, 0xC224, 0x9A42, 0xC225, 0x9A43, 0xC226, 0x9A44, 0xC227, 0x9A45, 0xC22A, 0x9A46, 0xC22C, + 0x9A47, 0xC22E, 0x9A48, 0xC230, 0x9A49, 0xC233, 0x9A4A, 0xC235, 0x9A4B, 0xC236, 0x9A4C, 0xC237, 0x9A4D, 0xC238, 0x9A4E, 0xC239, + 0x9A4F, 0xC23A, 0x9A50, 0xC23B, 0x9A51, 0xC23C, 0x9A52, 0xC23D, 0x9A53, 0xC23E, 0x9A54, 0xC23F, 0x9A55, 0xC240, 0x9A56, 0xC241, + 0x9A57, 0xC242, 0x9A58, 0xC243, 0x9A59, 0xC244, 0x9A5A, 0xC245, 0x9A61, 0xC246, 0x9A62, 0xC247, 0x9A63, 0xC249, 0x9A64, 0xC24A, + 0x9A65, 0xC24B, 0x9A66, 0xC24C, 0x9A67, 0xC24D, 0x9A68, 0xC24E, 0x9A69, 0xC24F, 0x9A6A, 0xC252, 0x9A6B, 0xC253, 0x9A6C, 0xC255, + 0x9A6D, 0xC256, 0x9A6E, 0xC257, 0x9A6F, 0xC259, 0x9A70, 0xC25A, 0x9A71, 0xC25B, 0x9A72, 0xC25C, 0x9A73, 0xC25D, 0x9A74, 0xC25E, + 0x9A75, 0xC25F, 0x9A76, 0xC261, 0x9A77, 0xC262, 0x9A78, 0xC263, 0x9A79, 0xC264, 0x9A7A, 0xC266, 0x9A81, 0xC267, 0x9A82, 0xC268, + 0x9A83, 0xC269, 0x9A84, 0xC26A, 0x9A85, 0xC26B, 0x9A86, 0xC26E, 0x9A87, 0xC26F, 0x9A88, 0xC271, 0x9A89, 0xC272, 0x9A8A, 0xC273, + 0x9A8B, 0xC275, 0x9A8C, 0xC276, 0x9A8D, 0xC277, 0x9A8E, 0xC278, 0x9A8F, 0xC279, 0x9A90, 0xC27A, 0x9A91, 0xC27B, 0x9A92, 0xC27E, + 0x9A93, 0xC280, 0x9A94, 0xC282, 0x9A95, 0xC283, 0x9A96, 0xC284, 0x9A97, 0xC285, 0x9A98, 0xC286, 0x9A99, 0xC287, 0x9A9A, 0xC28A, + 0x9A9B, 0xC28B, 0x9A9C, 0xC28C, 0x9A9D, 0xC28D, 0x9A9E, 0xC28E, 0x9A9F, 0xC28F, 0x9AA0, 0xC291, 0x9AA1, 0xC292, 0x9AA2, 0xC293, + 0x9AA3, 0xC294, 0x9AA4, 0xC295, 0x9AA5, 0xC296, 0x9AA6, 0xC297, 0x9AA7, 0xC299, 0x9AA8, 0xC29A, 0x9AA9, 0xC29C, 0x9AAA, 0xC29E, + 0x9AAB, 0xC29F, 0x9AAC, 0xC2A0, 0x9AAD, 0xC2A1, 0x9AAE, 0xC2A2, 0x9AAF, 0xC2A3, 0x9AB0, 0xC2A6, 0x9AB1, 0xC2A7, 0x9AB2, 0xC2A9, + 0x9AB3, 0xC2AA, 0x9AB4, 0xC2AB, 0x9AB5, 0xC2AE, 0x9AB6, 0xC2AF, 0x9AB7, 0xC2B0, 0x9AB8, 0xC2B1, 0x9AB9, 0xC2B2, 0x9ABA, 0xC2B3, + 0x9ABB, 0xC2B6, 0x9ABC, 0xC2B8, 0x9ABD, 0xC2BA, 0x9ABE, 0xC2BB, 0x9ABF, 0xC2BC, 0x9AC0, 0xC2BD, 0x9AC1, 0xC2BE, 0x9AC2, 0xC2BF, + 0x9AC3, 0xC2C0, 0x9AC4, 0xC2C1, 0x9AC5, 0xC2C2, 0x9AC6, 0xC2C3, 0x9AC7, 0xC2C4, 0x9AC8, 0xC2C5, 0x9AC9, 0xC2C6, 0x9ACA, 0xC2C7, + 0x9ACB, 0xC2C8, 0x9ACC, 0xC2C9, 0x9ACD, 0xC2CA, 0x9ACE, 0xC2CB, 0x9ACF, 0xC2CC, 0x9AD0, 0xC2CD, 0x9AD1, 0xC2CE, 0x9AD2, 0xC2CF, + 0x9AD3, 0xC2D0, 0x9AD4, 0xC2D1, 0x9AD5, 0xC2D2, 0x9AD6, 0xC2D3, 0x9AD7, 0xC2D4, 0x9AD8, 0xC2D5, 0x9AD9, 0xC2D6, 0x9ADA, 0xC2D7, + 0x9ADB, 0xC2D8, 0x9ADC, 0xC2D9, 0x9ADD, 0xC2DA, 0x9ADE, 0xC2DB, 0x9ADF, 0xC2DE, 0x9AE0, 0xC2DF, 0x9AE1, 0xC2E1, 0x9AE2, 0xC2E2, + 0x9AE3, 0xC2E5, 0x9AE4, 0xC2E6, 0x9AE5, 0xC2E7, 0x9AE6, 0xC2E8, 0x9AE7, 0xC2E9, 0x9AE8, 0xC2EA, 0x9AE9, 0xC2EE, 0x9AEA, 0xC2F0, + 0x9AEB, 0xC2F2, 0x9AEC, 0xC2F3, 0x9AED, 0xC2F4, 0x9AEE, 0xC2F5, 0x9AEF, 0xC2F7, 0x9AF0, 0xC2FA, 0x9AF1, 0xC2FD, 0x9AF2, 0xC2FE, + 0x9AF3, 0xC2FF, 0x9AF4, 0xC301, 0x9AF5, 0xC302, 0x9AF6, 0xC303, 0x9AF7, 0xC304, 0x9AF8, 0xC305, 0x9AF9, 0xC306, 0x9AFA, 0xC307, + 0x9AFB, 0xC30A, 0x9AFC, 0xC30B, 0x9AFD, 0xC30E, 0x9AFE, 0xC30F, 0x9B41, 0xC310, 0x9B42, 0xC311, 0x9B43, 0xC312, 0x9B44, 0xC316, + 0x9B45, 0xC317, 0x9B46, 0xC319, 0x9B47, 0xC31A, 0x9B48, 0xC31B, 0x9B49, 0xC31D, 0x9B4A, 0xC31E, 0x9B4B, 0xC31F, 0x9B4C, 0xC320, + 0x9B4D, 0xC321, 0x9B4E, 0xC322, 0x9B4F, 0xC323, 0x9B50, 0xC326, 0x9B51, 0xC327, 0x9B52, 0xC32A, 0x9B53, 0xC32B, 0x9B54, 0xC32C, + 0x9B55, 0xC32D, 0x9B56, 0xC32E, 0x9B57, 0xC32F, 0x9B58, 0xC330, 0x9B59, 0xC331, 0x9B5A, 0xC332, 0x9B61, 0xC333, 0x9B62, 0xC334, + 0x9B63, 0xC335, 0x9B64, 0xC336, 0x9B65, 0xC337, 0x9B66, 0xC338, 0x9B67, 0xC339, 0x9B68, 0xC33A, 0x9B69, 0xC33B, 0x9B6A, 0xC33C, + 0x9B6B, 0xC33D, 0x9B6C, 0xC33E, 0x9B6D, 0xC33F, 0x9B6E, 0xC340, 0x9B6F, 0xC341, 0x9B70, 0xC342, 0x9B71, 0xC343, 0x9B72, 0xC344, + 0x9B73, 0xC346, 0x9B74, 0xC347, 0x9B75, 0xC348, 0x9B76, 0xC349, 0x9B77, 0xC34A, 0x9B78, 0xC34B, 0x9B79, 0xC34C, 0x9B7A, 0xC34D, + 0x9B81, 0xC34E, 0x9B82, 0xC34F, 0x9B83, 0xC350, 0x9B84, 0xC351, 0x9B85, 0xC352, 0x9B86, 0xC353, 0x9B87, 0xC354, 0x9B88, 0xC355, + 0x9B89, 0xC356, 0x9B8A, 0xC357, 0x9B8B, 0xC358, 0x9B8C, 0xC359, 0x9B8D, 0xC35A, 0x9B8E, 0xC35B, 0x9B8F, 0xC35C, 0x9B90, 0xC35D, + 0x9B91, 0xC35E, 0x9B92, 0xC35F, 0x9B93, 0xC360, 0x9B94, 0xC361, 0x9B95, 0xC362, 0x9B96, 0xC363, 0x9B97, 0xC364, 0x9B98, 0xC365, + 0x9B99, 0xC366, 0x9B9A, 0xC367, 0x9B9B, 0xC36A, 0x9B9C, 0xC36B, 0x9B9D, 0xC36D, 0x9B9E, 0xC36E, 0x9B9F, 0xC36F, 0x9BA0, 0xC371, + 0x9BA1, 0xC373, 0x9BA2, 0xC374, 0x9BA3, 0xC375, 0x9BA4, 0xC376, 0x9BA5, 0xC377, 0x9BA6, 0xC37A, 0x9BA7, 0xC37B, 0x9BA8, 0xC37E, + 0x9BA9, 0xC37F, 0x9BAA, 0xC380, 0x9BAB, 0xC381, 0x9BAC, 0xC382, 0x9BAD, 0xC383, 0x9BAE, 0xC385, 0x9BAF, 0xC386, 0x9BB0, 0xC387, + 0x9BB1, 0xC389, 0x9BB2, 0xC38A, 0x9BB3, 0xC38B, 0x9BB4, 0xC38D, 0x9BB5, 0xC38E, 0x9BB6, 0xC38F, 0x9BB7, 0xC390, 0x9BB8, 0xC391, + 0x9BB9, 0xC392, 0x9BBA, 0xC393, 0x9BBB, 0xC394, 0x9BBC, 0xC395, 0x9BBD, 0xC396, 0x9BBE, 0xC397, 0x9BBF, 0xC398, 0x9BC0, 0xC399, + 0x9BC1, 0xC39A, 0x9BC2, 0xC39B, 0x9BC3, 0xC39C, 0x9BC4, 0xC39D, 0x9BC5, 0xC39E, 0x9BC6, 0xC39F, 0x9BC7, 0xC3A0, 0x9BC8, 0xC3A1, + 0x9BC9, 0xC3A2, 0x9BCA, 0xC3A3, 0x9BCB, 0xC3A4, 0x9BCC, 0xC3A5, 0x9BCD, 0xC3A6, 0x9BCE, 0xC3A7, 0x9BCF, 0xC3A8, 0x9BD0, 0xC3A9, + 0x9BD1, 0xC3AA, 0x9BD2, 0xC3AB, 0x9BD3, 0xC3AC, 0x9BD4, 0xC3AD, 0x9BD5, 0xC3AE, 0x9BD6, 0xC3AF, 0x9BD7, 0xC3B0, 0x9BD8, 0xC3B1, + 0x9BD9, 0xC3B2, 0x9BDA, 0xC3B3, 0x9BDB, 0xC3B4, 0x9BDC, 0xC3B5, 0x9BDD, 0xC3B6, 0x9BDE, 0xC3B7, 0x9BDF, 0xC3B8, 0x9BE0, 0xC3B9, + 0x9BE1, 0xC3BA, 0x9BE2, 0xC3BB, 0x9BE3, 0xC3BC, 0x9BE4, 0xC3BD, 0x9BE5, 0xC3BE, 0x9BE6, 0xC3BF, 0x9BE7, 0xC3C1, 0x9BE8, 0xC3C2, + 0x9BE9, 0xC3C3, 0x9BEA, 0xC3C4, 0x9BEB, 0xC3C5, 0x9BEC, 0xC3C6, 0x9BED, 0xC3C7, 0x9BEE, 0xC3C8, 0x9BEF, 0xC3C9, 0x9BF0, 0xC3CA, + 0x9BF1, 0xC3CB, 0x9BF2, 0xC3CC, 0x9BF3, 0xC3CD, 0x9BF4, 0xC3CE, 0x9BF5, 0xC3CF, 0x9BF6, 0xC3D0, 0x9BF7, 0xC3D1, 0x9BF8, 0xC3D2, + 0x9BF9, 0xC3D3, 0x9BFA, 0xC3D4, 0x9BFB, 0xC3D5, 0x9BFC, 0xC3D6, 0x9BFD, 0xC3D7, 0x9BFE, 0xC3DA, 0x9C41, 0xC3DB, 0x9C42, 0xC3DD, + 0x9C43, 0xC3DE, 0x9C44, 0xC3E1, 0x9C45, 0xC3E3, 0x9C46, 0xC3E4, 0x9C47, 0xC3E5, 0x9C48, 0xC3E6, 0x9C49, 0xC3E7, 0x9C4A, 0xC3EA, + 0x9C4B, 0xC3EB, 0x9C4C, 0xC3EC, 0x9C4D, 0xC3EE, 0x9C4E, 0xC3EF, 0x9C4F, 0xC3F0, 0x9C50, 0xC3F1, 0x9C51, 0xC3F2, 0x9C52, 0xC3F3, + 0x9C53, 0xC3F6, 0x9C54, 0xC3F7, 0x9C55, 0xC3F9, 0x9C56, 0xC3FA, 0x9C57, 0xC3FB, 0x9C58, 0xC3FC, 0x9C59, 0xC3FD, 0x9C5A, 0xC3FE, + 0x9C61, 0xC3FF, 0x9C62, 0xC400, 0x9C63, 0xC401, 0x9C64, 0xC402, 0x9C65, 0xC403, 0x9C66, 0xC404, 0x9C67, 0xC405, 0x9C68, 0xC406, + 0x9C69, 0xC407, 0x9C6A, 0xC409, 0x9C6B, 0xC40A, 0x9C6C, 0xC40B, 0x9C6D, 0xC40C, 0x9C6E, 0xC40D, 0x9C6F, 0xC40E, 0x9C70, 0xC40F, + 0x9C71, 0xC411, 0x9C72, 0xC412, 0x9C73, 0xC413, 0x9C74, 0xC414, 0x9C75, 0xC415, 0x9C76, 0xC416, 0x9C77, 0xC417, 0x9C78, 0xC418, + 0x9C79, 0xC419, 0x9C7A, 0xC41A, 0x9C81, 0xC41B, 0x9C82, 0xC41C, 0x9C83, 0xC41D, 0x9C84, 0xC41E, 0x9C85, 0xC41F, 0x9C86, 0xC420, + 0x9C87, 0xC421, 0x9C88, 0xC422, 0x9C89, 0xC423, 0x9C8A, 0xC425, 0x9C8B, 0xC426, 0x9C8C, 0xC427, 0x9C8D, 0xC428, 0x9C8E, 0xC429, + 0x9C8F, 0xC42A, 0x9C90, 0xC42B, 0x9C91, 0xC42D, 0x9C92, 0xC42E, 0x9C93, 0xC42F, 0x9C94, 0xC431, 0x9C95, 0xC432, 0x9C96, 0xC433, + 0x9C97, 0xC435, 0x9C98, 0xC436, 0x9C99, 0xC437, 0x9C9A, 0xC438, 0x9C9B, 0xC439, 0x9C9C, 0xC43A, 0x9C9D, 0xC43B, 0x9C9E, 0xC43E, + 0x9C9F, 0xC43F, 0x9CA0, 0xC440, 0x9CA1, 0xC441, 0x9CA2, 0xC442, 0x9CA3, 0xC443, 0x9CA4, 0xC444, 0x9CA5, 0xC445, 0x9CA6, 0xC446, + 0x9CA7, 0xC447, 0x9CA8, 0xC449, 0x9CA9, 0xC44A, 0x9CAA, 0xC44B, 0x9CAB, 0xC44C, 0x9CAC, 0xC44D, 0x9CAD, 0xC44E, 0x9CAE, 0xC44F, + 0x9CAF, 0xC450, 0x9CB0, 0xC451, 0x9CB1, 0xC452, 0x9CB2, 0xC453, 0x9CB3, 0xC454, 0x9CB4, 0xC455, 0x9CB5, 0xC456, 0x9CB6, 0xC457, + 0x9CB7, 0xC458, 0x9CB8, 0xC459, 0x9CB9, 0xC45A, 0x9CBA, 0xC45B, 0x9CBB, 0xC45C, 0x9CBC, 0xC45D, 0x9CBD, 0xC45E, 0x9CBE, 0xC45F, + 0x9CBF, 0xC460, 0x9CC0, 0xC461, 0x9CC1, 0xC462, 0x9CC2, 0xC463, 0x9CC3, 0xC466, 0x9CC4, 0xC467, 0x9CC5, 0xC469, 0x9CC6, 0xC46A, + 0x9CC7, 0xC46B, 0x9CC8, 0xC46D, 0x9CC9, 0xC46E, 0x9CCA, 0xC46F, 0x9CCB, 0xC470, 0x9CCC, 0xC471, 0x9CCD, 0xC472, 0x9CCE, 0xC473, + 0x9CCF, 0xC476, 0x9CD0, 0xC477, 0x9CD1, 0xC478, 0x9CD2, 0xC47A, 0x9CD3, 0xC47B, 0x9CD4, 0xC47C, 0x9CD5, 0xC47D, 0x9CD6, 0xC47E, + 0x9CD7, 0xC47F, 0x9CD8, 0xC481, 0x9CD9, 0xC482, 0x9CDA, 0xC483, 0x9CDB, 0xC484, 0x9CDC, 0xC485, 0x9CDD, 0xC486, 0x9CDE, 0xC487, + 0x9CDF, 0xC488, 0x9CE0, 0xC489, 0x9CE1, 0xC48A, 0x9CE2, 0xC48B, 0x9CE3, 0xC48C, 0x9CE4, 0xC48D, 0x9CE5, 0xC48E, 0x9CE6, 0xC48F, + 0x9CE7, 0xC490, 0x9CE8, 0xC491, 0x9CE9, 0xC492, 0x9CEA, 0xC493, 0x9CEB, 0xC495, 0x9CEC, 0xC496, 0x9CED, 0xC497, 0x9CEE, 0xC498, + 0x9CEF, 0xC499, 0x9CF0, 0xC49A, 0x9CF1, 0xC49B, 0x9CF2, 0xC49D, 0x9CF3, 0xC49E, 0x9CF4, 0xC49F, 0x9CF5, 0xC4A0, 0x9CF6, 0xC4A1, + 0x9CF7, 0xC4A2, 0x9CF8, 0xC4A3, 0x9CF9, 0xC4A4, 0x9CFA, 0xC4A5, 0x9CFB, 0xC4A6, 0x9CFC, 0xC4A7, 0x9CFD, 0xC4A8, 0x9CFE, 0xC4A9, + 0x9D41, 0xC4AA, 0x9D42, 0xC4AB, 0x9D43, 0xC4AC, 0x9D44, 0xC4AD, 0x9D45, 0xC4AE, 0x9D46, 0xC4AF, 0x9D47, 0xC4B0, 0x9D48, 0xC4B1, + 0x9D49, 0xC4B2, 0x9D4A, 0xC4B3, 0x9D4B, 0xC4B4, 0x9D4C, 0xC4B5, 0x9D4D, 0xC4B6, 0x9D4E, 0xC4B7, 0x9D4F, 0xC4B9, 0x9D50, 0xC4BA, + 0x9D51, 0xC4BB, 0x9D52, 0xC4BD, 0x9D53, 0xC4BE, 0x9D54, 0xC4BF, 0x9D55, 0xC4C0, 0x9D56, 0xC4C1, 0x9D57, 0xC4C2, 0x9D58, 0xC4C3, + 0x9D59, 0xC4C4, 0x9D5A, 0xC4C5, 0x9D61, 0xC4C6, 0x9D62, 0xC4C7, 0x9D63, 0xC4C8, 0x9D64, 0xC4C9, 0x9D65, 0xC4CA, 0x9D66, 0xC4CB, + 0x9D67, 0xC4CC, 0x9D68, 0xC4CD, 0x9D69, 0xC4CE, 0x9D6A, 0xC4CF, 0x9D6B, 0xC4D0, 0x9D6C, 0xC4D1, 0x9D6D, 0xC4D2, 0x9D6E, 0xC4D3, + 0x9D6F, 0xC4D4, 0x9D70, 0xC4D5, 0x9D71, 0xC4D6, 0x9D72, 0xC4D7, 0x9D73, 0xC4D8, 0x9D74, 0xC4D9, 0x9D75, 0xC4DA, 0x9D76, 0xC4DB, + 0x9D77, 0xC4DC, 0x9D78, 0xC4DD, 0x9D79, 0xC4DE, 0x9D7A, 0xC4DF, 0x9D81, 0xC4E0, 0x9D82, 0xC4E1, 0x9D83, 0xC4E2, 0x9D84, 0xC4E3, + 0x9D85, 0xC4E4, 0x9D86, 0xC4E5, 0x9D87, 0xC4E6, 0x9D88, 0xC4E7, 0x9D89, 0xC4E8, 0x9D8A, 0xC4EA, 0x9D8B, 0xC4EB, 0x9D8C, 0xC4EC, + 0x9D8D, 0xC4ED, 0x9D8E, 0xC4EE, 0x9D8F, 0xC4EF, 0x9D90, 0xC4F2, 0x9D91, 0xC4F3, 0x9D92, 0xC4F5, 0x9D93, 0xC4F6, 0x9D94, 0xC4F7, + 0x9D95, 0xC4F9, 0x9D96, 0xC4FB, 0x9D97, 0xC4FC, 0x9D98, 0xC4FD, 0x9D99, 0xC4FE, 0x9D9A, 0xC502, 0x9D9B, 0xC503, 0x9D9C, 0xC504, + 0x9D9D, 0xC505, 0x9D9E, 0xC506, 0x9D9F, 0xC507, 0x9DA0, 0xC508, 0x9DA1, 0xC509, 0x9DA2, 0xC50A, 0x9DA3, 0xC50B, 0x9DA4, 0xC50D, + 0x9DA5, 0xC50E, 0x9DA6, 0xC50F, 0x9DA7, 0xC511, 0x9DA8, 0xC512, 0x9DA9, 0xC513, 0x9DAA, 0xC515, 0x9DAB, 0xC516, 0x9DAC, 0xC517, + 0x9DAD, 0xC518, 0x9DAE, 0xC519, 0x9DAF, 0xC51A, 0x9DB0, 0xC51B, 0x9DB1, 0xC51D, 0x9DB2, 0xC51E, 0x9DB3, 0xC51F, 0x9DB4, 0xC520, + 0x9DB5, 0xC521, 0x9DB6, 0xC522, 0x9DB7, 0xC523, 0x9DB8, 0xC524, 0x9DB9, 0xC525, 0x9DBA, 0xC526, 0x9DBB, 0xC527, 0x9DBC, 0xC52A, + 0x9DBD, 0xC52B, 0x9DBE, 0xC52D, 0x9DBF, 0xC52E, 0x9DC0, 0xC52F, 0x9DC1, 0xC531, 0x9DC2, 0xC532, 0x9DC3, 0xC533, 0x9DC4, 0xC534, + 0x9DC5, 0xC535, 0x9DC6, 0xC536, 0x9DC7, 0xC537, 0x9DC8, 0xC53A, 0x9DC9, 0xC53C, 0x9DCA, 0xC53E, 0x9DCB, 0xC53F, 0x9DCC, 0xC540, + 0x9DCD, 0xC541, 0x9DCE, 0xC542, 0x9DCF, 0xC543, 0x9DD0, 0xC546, 0x9DD1, 0xC547, 0x9DD2, 0xC54B, 0x9DD3, 0xC54F, 0x9DD4, 0xC550, + 0x9DD5, 0xC551, 0x9DD6, 0xC552, 0x9DD7, 0xC556, 0x9DD8, 0xC55A, 0x9DD9, 0xC55B, 0x9DDA, 0xC55C, 0x9DDB, 0xC55F, 0x9DDC, 0xC562, + 0x9DDD, 0xC563, 0x9DDE, 0xC565, 0x9DDF, 0xC566, 0x9DE0, 0xC567, 0x9DE1, 0xC569, 0x9DE2, 0xC56A, 0x9DE3, 0xC56B, 0x9DE4, 0xC56C, + 0x9DE5, 0xC56D, 0x9DE6, 0xC56E, 0x9DE7, 0xC56F, 0x9DE8, 0xC572, 0x9DE9, 0xC576, 0x9DEA, 0xC577, 0x9DEB, 0xC578, 0x9DEC, 0xC579, + 0x9DED, 0xC57A, 0x9DEE, 0xC57B, 0x9DEF, 0xC57E, 0x9DF0, 0xC57F, 0x9DF1, 0xC581, 0x9DF2, 0xC582, 0x9DF3, 0xC583, 0x9DF4, 0xC585, + 0x9DF5, 0xC586, 0x9DF6, 0xC588, 0x9DF7, 0xC589, 0x9DF8, 0xC58A, 0x9DF9, 0xC58B, 0x9DFA, 0xC58E, 0x9DFB, 0xC590, 0x9DFC, 0xC592, + 0x9DFD, 0xC593, 0x9DFE, 0xC594, 0x9E41, 0xC596, 0x9E42, 0xC599, 0x9E43, 0xC59A, 0x9E44, 0xC59B, 0x9E45, 0xC59D, 0x9E46, 0xC59E, + 0x9E47, 0xC59F, 0x9E48, 0xC5A1, 0x9E49, 0xC5A2, 0x9E4A, 0xC5A3, 0x9E4B, 0xC5A4, 0x9E4C, 0xC5A5, 0x9E4D, 0xC5A6, 0x9E4E, 0xC5A7, + 0x9E4F, 0xC5A8, 0x9E50, 0xC5AA, 0x9E51, 0xC5AB, 0x9E52, 0xC5AC, 0x9E53, 0xC5AD, 0x9E54, 0xC5AE, 0x9E55, 0xC5AF, 0x9E56, 0xC5B0, + 0x9E57, 0xC5B1, 0x9E58, 0xC5B2, 0x9E59, 0xC5B3, 0x9E5A, 0xC5B6, 0x9E61, 0xC5B7, 0x9E62, 0xC5BA, 0x9E63, 0xC5BF, 0x9E64, 0xC5C0, + 0x9E65, 0xC5C1, 0x9E66, 0xC5C2, 0x9E67, 0xC5C3, 0x9E68, 0xC5CB, 0x9E69, 0xC5CD, 0x9E6A, 0xC5CF, 0x9E6B, 0xC5D2, 0x9E6C, 0xC5D3, + 0x9E6D, 0xC5D5, 0x9E6E, 0xC5D6, 0x9E6F, 0xC5D7, 0x9E70, 0xC5D9, 0x9E71, 0xC5DA, 0x9E72, 0xC5DB, 0x9E73, 0xC5DC, 0x9E74, 0xC5DD, + 0x9E75, 0xC5DE, 0x9E76, 0xC5DF, 0x9E77, 0xC5E2, 0x9E78, 0xC5E4, 0x9E79, 0xC5E6, 0x9E7A, 0xC5E7, 0x9E81, 0xC5E8, 0x9E82, 0xC5E9, + 0x9E83, 0xC5EA, 0x9E84, 0xC5EB, 0x9E85, 0xC5EF, 0x9E86, 0xC5F1, 0x9E87, 0xC5F2, 0x9E88, 0xC5F3, 0x9E89, 0xC5F5, 0x9E8A, 0xC5F8, + 0x9E8B, 0xC5F9, 0x9E8C, 0xC5FA, 0x9E8D, 0xC5FB, 0x9E8E, 0xC602, 0x9E8F, 0xC603, 0x9E90, 0xC604, 0x9E91, 0xC609, 0x9E92, 0xC60A, + 0x9E93, 0xC60B, 0x9E94, 0xC60D, 0x9E95, 0xC60E, 0x9E96, 0xC60F, 0x9E97, 0xC611, 0x9E98, 0xC612, 0x9E99, 0xC613, 0x9E9A, 0xC614, + 0x9E9B, 0xC615, 0x9E9C, 0xC616, 0x9E9D, 0xC617, 0x9E9E, 0xC61A, 0x9E9F, 0xC61D, 0x9EA0, 0xC61E, 0x9EA1, 0xC61F, 0x9EA2, 0xC620, + 0x9EA3, 0xC621, 0x9EA4, 0xC622, 0x9EA5, 0xC623, 0x9EA6, 0xC626, 0x9EA7, 0xC627, 0x9EA8, 0xC629, 0x9EA9, 0xC62A, 0x9EAA, 0xC62B, + 0x9EAB, 0xC62F, 0x9EAC, 0xC631, 0x9EAD, 0xC632, 0x9EAE, 0xC636, 0x9EAF, 0xC638, 0x9EB0, 0xC63A, 0x9EB1, 0xC63C, 0x9EB2, 0xC63D, + 0x9EB3, 0xC63E, 0x9EB4, 0xC63F, 0x9EB5, 0xC642, 0x9EB6, 0xC643, 0x9EB7, 0xC645, 0x9EB8, 0xC646, 0x9EB9, 0xC647, 0x9EBA, 0xC649, + 0x9EBB, 0xC64A, 0x9EBC, 0xC64B, 0x9EBD, 0xC64C, 0x9EBE, 0xC64D, 0x9EBF, 0xC64E, 0x9EC0, 0xC64F, 0x9EC1, 0xC652, 0x9EC2, 0xC656, + 0x9EC3, 0xC657, 0x9EC4, 0xC658, 0x9EC5, 0xC659, 0x9EC6, 0xC65A, 0x9EC7, 0xC65B, 0x9EC8, 0xC65E, 0x9EC9, 0xC65F, 0x9ECA, 0xC661, + 0x9ECB, 0xC662, 0x9ECC, 0xC663, 0x9ECD, 0xC664, 0x9ECE, 0xC665, 0x9ECF, 0xC666, 0x9ED0, 0xC667, 0x9ED1, 0xC668, 0x9ED2, 0xC669, + 0x9ED3, 0xC66A, 0x9ED4, 0xC66B, 0x9ED5, 0xC66D, 0x9ED6, 0xC66E, 0x9ED7, 0xC670, 0x9ED8, 0xC672, 0x9ED9, 0xC673, 0x9EDA, 0xC674, + 0x9EDB, 0xC675, 0x9EDC, 0xC676, 0x9EDD, 0xC677, 0x9EDE, 0xC67A, 0x9EDF, 0xC67B, 0x9EE0, 0xC67D, 0x9EE1, 0xC67E, 0x9EE2, 0xC67F, + 0x9EE3, 0xC681, 0x9EE4, 0xC682, 0x9EE5, 0xC683, 0x9EE6, 0xC684, 0x9EE7, 0xC685, 0x9EE8, 0xC686, 0x9EE9, 0xC687, 0x9EEA, 0xC68A, + 0x9EEB, 0xC68C, 0x9EEC, 0xC68E, 0x9EED, 0xC68F, 0x9EEE, 0xC690, 0x9EEF, 0xC691, 0x9EF0, 0xC692, 0x9EF1, 0xC693, 0x9EF2, 0xC696, + 0x9EF3, 0xC697, 0x9EF4, 0xC699, 0x9EF5, 0xC69A, 0x9EF6, 0xC69B, 0x9EF7, 0xC69D, 0x9EF8, 0xC69E, 0x9EF9, 0xC69F, 0x9EFA, 0xC6A0, + 0x9EFB, 0xC6A1, 0x9EFC, 0xC6A2, 0x9EFD, 0xC6A3, 0x9EFE, 0xC6A6, 0x9F41, 0xC6A8, 0x9F42, 0xC6AA, 0x9F43, 0xC6AB, 0x9F44, 0xC6AC, + 0x9F45, 0xC6AD, 0x9F46, 0xC6AE, 0x9F47, 0xC6AF, 0x9F48, 0xC6B2, 0x9F49, 0xC6B3, 0x9F4A, 0xC6B5, 0x9F4B, 0xC6B6, 0x9F4C, 0xC6B7, + 0x9F4D, 0xC6BB, 0x9F4E, 0xC6BC, 0x9F4F, 0xC6BD, 0x9F50, 0xC6BE, 0x9F51, 0xC6BF, 0x9F52, 0xC6C2, 0x9F53, 0xC6C4, 0x9F54, 0xC6C6, + 0x9F55, 0xC6C7, 0x9F56, 0xC6C8, 0x9F57, 0xC6C9, 0x9F58, 0xC6CA, 0x9F59, 0xC6CB, 0x9F5A, 0xC6CE, 0x9F61, 0xC6CF, 0x9F62, 0xC6D1, + 0x9F63, 0xC6D2, 0x9F64, 0xC6D3, 0x9F65, 0xC6D5, 0x9F66, 0xC6D6, 0x9F67, 0xC6D7, 0x9F68, 0xC6D8, 0x9F69, 0xC6D9, 0x9F6A, 0xC6DA, + 0x9F6B, 0xC6DB, 0x9F6C, 0xC6DE, 0x9F6D, 0xC6DF, 0x9F6E, 0xC6E2, 0x9F6F, 0xC6E3, 0x9F70, 0xC6E4, 0x9F71, 0xC6E5, 0x9F72, 0xC6E6, + 0x9F73, 0xC6E7, 0x9F74, 0xC6EA, 0x9F75, 0xC6EB, 0x9F76, 0xC6ED, 0x9F77, 0xC6EE, 0x9F78, 0xC6EF, 0x9F79, 0xC6F1, 0x9F7A, 0xC6F2, + 0x9F81, 0xC6F3, 0x9F82, 0xC6F4, 0x9F83, 0xC6F5, 0x9F84, 0xC6F6, 0x9F85, 0xC6F7, 0x9F86, 0xC6FA, 0x9F87, 0xC6FB, 0x9F88, 0xC6FC, + 0x9F89, 0xC6FE, 0x9F8A, 0xC6FF, 0x9F8B, 0xC700, 0x9F8C, 0xC701, 0x9F8D, 0xC702, 0x9F8E, 0xC703, 0x9F8F, 0xC706, 0x9F90, 0xC707, + 0x9F91, 0xC709, 0x9F92, 0xC70A, 0x9F93, 0xC70B, 0x9F94, 0xC70D, 0x9F95, 0xC70E, 0x9F96, 0xC70F, 0x9F97, 0xC710, 0x9F98, 0xC711, + 0x9F99, 0xC712, 0x9F9A, 0xC713, 0x9F9B, 0xC716, 0x9F9C, 0xC718, 0x9F9D, 0xC71A, 0x9F9E, 0xC71B, 0x9F9F, 0xC71C, 0x9FA0, 0xC71D, + 0x9FA1, 0xC71E, 0x9FA2, 0xC71F, 0x9FA3, 0xC722, 0x9FA4, 0xC723, 0x9FA5, 0xC725, 0x9FA6, 0xC726, 0x9FA7, 0xC727, 0x9FA8, 0xC729, + 0x9FA9, 0xC72A, 0x9FAA, 0xC72B, 0x9FAB, 0xC72C, 0x9FAC, 0xC72D, 0x9FAD, 0xC72E, 0x9FAE, 0xC72F, 0x9FAF, 0xC732, 0x9FB0, 0xC734, + 0x9FB1, 0xC736, 0x9FB2, 0xC738, 0x9FB3, 0xC739, 0x9FB4, 0xC73A, 0x9FB5, 0xC73B, 0x9FB6, 0xC73E, 0x9FB7, 0xC73F, 0x9FB8, 0xC741, + 0x9FB9, 0xC742, 0x9FBA, 0xC743, 0x9FBB, 0xC745, 0x9FBC, 0xC746, 0x9FBD, 0xC747, 0x9FBE, 0xC748, 0x9FBF, 0xC749, 0x9FC0, 0xC74B, + 0x9FC1, 0xC74E, 0x9FC2, 0xC750, 0x9FC3, 0xC759, 0x9FC4, 0xC75A, 0x9FC5, 0xC75B, 0x9FC6, 0xC75D, 0x9FC7, 0xC75E, 0x9FC8, 0xC75F, + 0x9FC9, 0xC761, 0x9FCA, 0xC762, 0x9FCB, 0xC763, 0x9FCC, 0xC764, 0x9FCD, 0xC765, 0x9FCE, 0xC766, 0x9FCF, 0xC767, 0x9FD0, 0xC769, + 0x9FD1, 0xC76A, 0x9FD2, 0xC76C, 0x9FD3, 0xC76D, 0x9FD4, 0xC76E, 0x9FD5, 0xC76F, 0x9FD6, 0xC770, 0x9FD7, 0xC771, 0x9FD8, 0xC772, + 0x9FD9, 0xC773, 0x9FDA, 0xC776, 0x9FDB, 0xC777, 0x9FDC, 0xC779, 0x9FDD, 0xC77A, 0x9FDE, 0xC77B, 0x9FDF, 0xC77F, 0x9FE0, 0xC780, + 0x9FE1, 0xC781, 0x9FE2, 0xC782, 0x9FE3, 0xC786, 0x9FE4, 0xC78B, 0x9FE5, 0xC78C, 0x9FE6, 0xC78D, 0x9FE7, 0xC78F, 0x9FE8, 0xC792, + 0x9FE9, 0xC793, 0x9FEA, 0xC795, 0x9FEB, 0xC799, 0x9FEC, 0xC79B, 0x9FED, 0xC79C, 0x9FEE, 0xC79D, 0x9FEF, 0xC79E, 0x9FF0, 0xC79F, + 0x9FF1, 0xC7A2, 0x9FF2, 0xC7A7, 0x9FF3, 0xC7A8, 0x9FF4, 0xC7A9, 0x9FF5, 0xC7AA, 0x9FF6, 0xC7AB, 0x9FF7, 0xC7AE, 0x9FF8, 0xC7AF, + 0x9FF9, 0xC7B1, 0x9FFA, 0xC7B2, 0x9FFB, 0xC7B3, 0x9FFC, 0xC7B5, 0x9FFD, 0xC7B6, 0x9FFE, 0xC7B7, 0xA041, 0xC7B8, 0xA042, 0xC7B9, + 0xA043, 0xC7BA, 0xA044, 0xC7BB, 0xA045, 0xC7BE, 0xA046, 0xC7C2, 0xA047, 0xC7C3, 0xA048, 0xC7C4, 0xA049, 0xC7C5, 0xA04A, 0xC7C6, + 0xA04B, 0xC7C7, 0xA04C, 0xC7CA, 0xA04D, 0xC7CB, 0xA04E, 0xC7CD, 0xA04F, 0xC7CF, 0xA050, 0xC7D1, 0xA051, 0xC7D2, 0xA052, 0xC7D3, + 0xA053, 0xC7D4, 0xA054, 0xC7D5, 0xA055, 0xC7D6, 0xA056, 0xC7D7, 0xA057, 0xC7D9, 0xA058, 0xC7DA, 0xA059, 0xC7DB, 0xA05A, 0xC7DC, + 0xA061, 0xC7DE, 0xA062, 0xC7DF, 0xA063, 0xC7E0, 0xA064, 0xC7E1, 0xA065, 0xC7E2, 0xA066, 0xC7E3, 0xA067, 0xC7E5, 0xA068, 0xC7E6, + 0xA069, 0xC7E7, 0xA06A, 0xC7E9, 0xA06B, 0xC7EA, 0xA06C, 0xC7EB, 0xA06D, 0xC7ED, 0xA06E, 0xC7EE, 0xA06F, 0xC7EF, 0xA070, 0xC7F0, + 0xA071, 0xC7F1, 0xA072, 0xC7F2, 0xA073, 0xC7F3, 0xA074, 0xC7F4, 0xA075, 0xC7F5, 0xA076, 0xC7F6, 0xA077, 0xC7F7, 0xA078, 0xC7F8, + 0xA079, 0xC7F9, 0xA07A, 0xC7FA, 0xA081, 0xC7FB, 0xA082, 0xC7FC, 0xA083, 0xC7FD, 0xA084, 0xC7FE, 0xA085, 0xC7FF, 0xA086, 0xC802, + 0xA087, 0xC803, 0xA088, 0xC805, 0xA089, 0xC806, 0xA08A, 0xC807, 0xA08B, 0xC809, 0xA08C, 0xC80B, 0xA08D, 0xC80C, 0xA08E, 0xC80D, + 0xA08F, 0xC80E, 0xA090, 0xC80F, 0xA091, 0xC812, 0xA092, 0xC814, 0xA093, 0xC817, 0xA094, 0xC818, 0xA095, 0xC819, 0xA096, 0xC81A, + 0xA097, 0xC81B, 0xA098, 0xC81E, 0xA099, 0xC81F, 0xA09A, 0xC821, 0xA09B, 0xC822, 0xA09C, 0xC823, 0xA09D, 0xC825, 0xA09E, 0xC826, + 0xA09F, 0xC827, 0xA0A0, 0xC828, 0xA0A1, 0xC829, 0xA0A2, 0xC82A, 0xA0A3, 0xC82B, 0xA0A4, 0xC82E, 0xA0A5, 0xC830, 0xA0A6, 0xC832, + 0xA0A7, 0xC833, 0xA0A8, 0xC834, 0xA0A9, 0xC835, 0xA0AA, 0xC836, 0xA0AB, 0xC837, 0xA0AC, 0xC839, 0xA0AD, 0xC83A, 0xA0AE, 0xC83B, + 0xA0AF, 0xC83D, 0xA0B0, 0xC83E, 0xA0B1, 0xC83F, 0xA0B2, 0xC841, 0xA0B3, 0xC842, 0xA0B4, 0xC843, 0xA0B5, 0xC844, 0xA0B6, 0xC845, + 0xA0B7, 0xC846, 0xA0B8, 0xC847, 0xA0B9, 0xC84A, 0xA0BA, 0xC84B, 0xA0BB, 0xC84E, 0xA0BC, 0xC84F, 0xA0BD, 0xC850, 0xA0BE, 0xC851, + 0xA0BF, 0xC852, 0xA0C0, 0xC853, 0xA0C1, 0xC855, 0xA0C2, 0xC856, 0xA0C3, 0xC857, 0xA0C4, 0xC858, 0xA0C5, 0xC859, 0xA0C6, 0xC85A, + 0xA0C7, 0xC85B, 0xA0C8, 0xC85C, 0xA0C9, 0xC85D, 0xA0CA, 0xC85E, 0xA0CB, 0xC85F, 0xA0CC, 0xC860, 0xA0CD, 0xC861, 0xA0CE, 0xC862, + 0xA0CF, 0xC863, 0xA0D0, 0xC864, 0xA0D1, 0xC865, 0xA0D2, 0xC866, 0xA0D3, 0xC867, 0xA0D4, 0xC868, 0xA0D5, 0xC869, 0xA0D6, 0xC86A, + 0xA0D7, 0xC86B, 0xA0D8, 0xC86C, 0xA0D9, 0xC86D, 0xA0DA, 0xC86E, 0xA0DB, 0xC86F, 0xA0DC, 0xC872, 0xA0DD, 0xC873, 0xA0DE, 0xC875, + 0xA0DF, 0xC876, 0xA0E0, 0xC877, 0xA0E1, 0xC879, 0xA0E2, 0xC87B, 0xA0E3, 0xC87C, 0xA0E4, 0xC87D, 0xA0E5, 0xC87E, 0xA0E6, 0xC87F, + 0xA0E7, 0xC882, 0xA0E8, 0xC884, 0xA0E9, 0xC888, 0xA0EA, 0xC889, 0xA0EB, 0xC88A, 0xA0EC, 0xC88E, 0xA0ED, 0xC88F, 0xA0EE, 0xC890, + 0xA0EF, 0xC891, 0xA0F0, 0xC892, 0xA0F1, 0xC893, 0xA0F2, 0xC895, 0xA0F3, 0xC896, 0xA0F4, 0xC897, 0xA0F5, 0xC898, 0xA0F6, 0xC899, + 0xA0F7, 0xC89A, 0xA0F8, 0xC89B, 0xA0F9, 0xC89C, 0xA0FA, 0xC89E, 0xA0FB, 0xC8A0, 0xA0FC, 0xC8A2, 0xA0FD, 0xC8A3, 0xA0FE, 0xC8A4, + 0xA141, 0xC8A5, 0xA142, 0xC8A6, 0xA143, 0xC8A7, 0xA144, 0xC8A9, 0xA145, 0xC8AA, 0xA146, 0xC8AB, 0xA147, 0xC8AC, 0xA148, 0xC8AD, + 0xA149, 0xC8AE, 0xA14A, 0xC8AF, 0xA14B, 0xC8B0, 0xA14C, 0xC8B1, 0xA14D, 0xC8B2, 0xA14E, 0xC8B3, 0xA14F, 0xC8B4, 0xA150, 0xC8B5, + 0xA151, 0xC8B6, 0xA152, 0xC8B7, 0xA153, 0xC8B8, 0xA154, 0xC8B9, 0xA155, 0xC8BA, 0xA156, 0xC8BB, 0xA157, 0xC8BE, 0xA158, 0xC8BF, + 0xA159, 0xC8C0, 0xA15A, 0xC8C1, 0xA161, 0xC8C2, 0xA162, 0xC8C3, 0xA163, 0xC8C5, 0xA164, 0xC8C6, 0xA165, 0xC8C7, 0xA166, 0xC8C9, + 0xA167, 0xC8CA, 0xA168, 0xC8CB, 0xA169, 0xC8CD, 0xA16A, 0xC8CE, 0xA16B, 0xC8CF, 0xA16C, 0xC8D0, 0xA16D, 0xC8D1, 0xA16E, 0xC8D2, + 0xA16F, 0xC8D3, 0xA170, 0xC8D6, 0xA171, 0xC8D8, 0xA172, 0xC8DA, 0xA173, 0xC8DB, 0xA174, 0xC8DC, 0xA175, 0xC8DD, 0xA176, 0xC8DE, + 0xA177, 0xC8DF, 0xA178, 0xC8E2, 0xA179, 0xC8E3, 0xA17A, 0xC8E5, 0xA181, 0xC8E6, 0xA182, 0xC8E7, 0xA183, 0xC8E8, 0xA184, 0xC8E9, + 0xA185, 0xC8EA, 0xA186, 0xC8EB, 0xA187, 0xC8EC, 0xA188, 0xC8ED, 0xA189, 0xC8EE, 0xA18A, 0xC8EF, 0xA18B, 0xC8F0, 0xA18C, 0xC8F1, + 0xA18D, 0xC8F2, 0xA18E, 0xC8F3, 0xA18F, 0xC8F4, 0xA190, 0xC8F6, 0xA191, 0xC8F7, 0xA192, 0xC8F8, 0xA193, 0xC8F9, 0xA194, 0xC8FA, + 0xA195, 0xC8FB, 0xA196, 0xC8FE, 0xA197, 0xC8FF, 0xA198, 0xC901, 0xA199, 0xC902, 0xA19A, 0xC903, 0xA19B, 0xC907, 0xA19C, 0xC908, + 0xA19D, 0xC909, 0xA19E, 0xC90A, 0xA19F, 0xC90B, 0xA1A0, 0xC90E, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, + 0xA1A5, 0x2025, 0xA1A6, 0x2026, 0xA1A7, 0x00A8, 0xA1A8, 0x3003, 0xA1A9, 0x00AD, 0xA1AA, 0x2015, 0xA1AB, 0x2225, 0xA1AC, 0xFF3C, + 0xA1AD, 0x223C, 0xA1AE, 0x2018, 0xA1AF, 0x2019, 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, + 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3010, + 0xA1BD, 0x3011, 0xA1BE, 0x00B1, 0xA1BF, 0x00D7, 0xA1C0, 0x00F7, 0xA1C1, 0x2260, 0xA1C2, 0x2264, 0xA1C3, 0x2265, 0xA1C4, 0x221E, + 0xA1C5, 0x2234, 0xA1C6, 0x00B0, 0xA1C7, 0x2032, 0xA1C8, 0x2033, 0xA1C9, 0x2103, 0xA1CA, 0x212B, 0xA1CB, 0xFFE0, 0xA1CC, 0xFFE1, + 0xA1CD, 0xFFE5, 0xA1CE, 0x2642, 0xA1CF, 0x2640, 0xA1D0, 0x2220, 0xA1D1, 0x22A5, 0xA1D2, 0x2312, 0xA1D3, 0x2202, 0xA1D4, 0x2207, + 0xA1D5, 0x2261, 0xA1D6, 0x2252, 0xA1D7, 0x00A7, 0xA1D8, 0x203B, 0xA1D9, 0x2606, 0xA1DA, 0x2605, 0xA1DB, 0x25CB, 0xA1DC, 0x25CF, + 0xA1DD, 0x25CE, 0xA1DE, 0x25C7, 0xA1DF, 0x25C6, 0xA1E0, 0x25A1, 0xA1E1, 0x25A0, 0xA1E2, 0x25B3, 0xA1E3, 0x25B2, 0xA1E4, 0x25BD, + 0xA1E5, 0x25BC, 0xA1E6, 0x2192, 0xA1E7, 0x2190, 0xA1E8, 0x2191, 0xA1E9, 0x2193, 0xA1EA, 0x2194, 0xA1EB, 0x3013, 0xA1EC, 0x226A, + 0xA1ED, 0x226B, 0xA1EE, 0x221A, 0xA1EF, 0x223D, 0xA1F0, 0x221D, 0xA1F1, 0x2235, 0xA1F2, 0x222B, 0xA1F3, 0x222C, 0xA1F4, 0x2208, + 0xA1F5, 0x220B, 0xA1F6, 0x2286, 0xA1F7, 0x2287, 0xA1F8, 0x2282, 0xA1F9, 0x2283, 0xA1FA, 0x222A, 0xA1FB, 0x2229, 0xA1FC, 0x2227, + 0xA1FD, 0x2228, 0xA1FE, 0xFFE2, 0xA241, 0xC910, 0xA242, 0xC912, 0xA243, 0xC913, 0xA244, 0xC914, 0xA245, 0xC915, 0xA246, 0xC916, + 0xA247, 0xC917, 0xA248, 0xC919, 0xA249, 0xC91A, 0xA24A, 0xC91B, 0xA24B, 0xC91C, 0xA24C, 0xC91D, 0xA24D, 0xC91E, 0xA24E, 0xC91F, + 0xA24F, 0xC920, 0xA250, 0xC921, 0xA251, 0xC922, 0xA252, 0xC923, 0xA253, 0xC924, 0xA254, 0xC925, 0xA255, 0xC926, 0xA256, 0xC927, + 0xA257, 0xC928, 0xA258, 0xC929, 0xA259, 0xC92A, 0xA25A, 0xC92B, 0xA261, 0xC92D, 0xA262, 0xC92E, 0xA263, 0xC92F, 0xA264, 0xC930, + 0xA265, 0xC931, 0xA266, 0xC932, 0xA267, 0xC933, 0xA268, 0xC935, 0xA269, 0xC936, 0xA26A, 0xC937, 0xA26B, 0xC938, 0xA26C, 0xC939, + 0xA26D, 0xC93A, 0xA26E, 0xC93B, 0xA26F, 0xC93C, 0xA270, 0xC93D, 0xA271, 0xC93E, 0xA272, 0xC93F, 0xA273, 0xC940, 0xA274, 0xC941, + 0xA275, 0xC942, 0xA276, 0xC943, 0xA277, 0xC944, 0xA278, 0xC945, 0xA279, 0xC946, 0xA27A, 0xC947, 0xA281, 0xC948, 0xA282, 0xC949, + 0xA283, 0xC94A, 0xA284, 0xC94B, 0xA285, 0xC94C, 0xA286, 0xC94D, 0xA287, 0xC94E, 0xA288, 0xC94F, 0xA289, 0xC952, 0xA28A, 0xC953, + 0xA28B, 0xC955, 0xA28C, 0xC956, 0xA28D, 0xC957, 0xA28E, 0xC959, 0xA28F, 0xC95A, 0xA290, 0xC95B, 0xA291, 0xC95C, 0xA292, 0xC95D, + 0xA293, 0xC95E, 0xA294, 0xC95F, 0xA295, 0xC962, 0xA296, 0xC964, 0xA297, 0xC965, 0xA298, 0xC966, 0xA299, 0xC967, 0xA29A, 0xC968, + 0xA29B, 0xC969, 0xA29C, 0xC96A, 0xA29D, 0xC96B, 0xA29E, 0xC96D, 0xA29F, 0xC96E, 0xA2A0, 0xC96F, 0xA2A1, 0x21D2, 0xA2A2, 0x21D4, + 0xA2A3, 0x2200, 0xA2A4, 0x2203, 0xA2A5, 0x00B4, 0xA2A6, 0xFF5E, 0xA2A7, 0x02C7, 0xA2A8, 0x02D8, 0xA2A9, 0x02DD, 0xA2AA, 0x02DA, + 0xA2AB, 0x02D9, 0xA2AC, 0x00B8, 0xA2AD, 0x02DB, 0xA2AE, 0x00A1, 0xA2AF, 0x00BF, 0xA2B0, 0x02D0, 0xA2B1, 0x222E, 0xA2B2, 0x2211, + 0xA2B3, 0x220F, 0xA2B4, 0x00A4, 0xA2B5, 0x2109, 0xA2B6, 0x2030, 0xA2B7, 0x25C1, 0xA2B8, 0x25C0, 0xA2B9, 0x25B7, 0xA2BA, 0x25B6, + 0xA2BB, 0x2664, 0xA2BC, 0x2660, 0xA2BD, 0x2661, 0xA2BE, 0x2665, 0xA2BF, 0x2667, 0xA2C0, 0x2663, 0xA2C1, 0x2299, 0xA2C2, 0x25C8, + 0xA2C3, 0x25A3, 0xA2C4, 0x25D0, 0xA2C5, 0x25D1, 0xA2C6, 0x2592, 0xA2C7, 0x25A4, 0xA2C8, 0x25A5, 0xA2C9, 0x25A8, 0xA2CA, 0x25A7, + 0xA2CB, 0x25A6, 0xA2CC, 0x25A9, 0xA2CD, 0x2668, 0xA2CE, 0x260F, 0xA2CF, 0x260E, 0xA2D0, 0x261C, 0xA2D1, 0x261E, 0xA2D2, 0x00B6, + 0xA2D3, 0x2020, 0xA2D4, 0x2021, 0xA2D5, 0x2195, 0xA2D6, 0x2197, 0xA2D7, 0x2199, 0xA2D8, 0x2196, 0xA2D9, 0x2198, 0xA2DA, 0x266D, + 0xA2DB, 0x2669, 0xA2DC, 0x266A, 0xA2DD, 0x266C, 0xA2DE, 0x327F, 0xA2DF, 0x321C, 0xA2E0, 0x2116, 0xA2E1, 0x33C7, 0xA2E2, 0x2122, + 0xA2E3, 0x33C2, 0xA2E4, 0x33D8, 0xA2E5, 0x2121, 0xA2E6, 0x20AC, 0xA2E7, 0x00AE, 0xA341, 0xC971, 0xA342, 0xC972, 0xA343, 0xC973, + 0xA344, 0xC975, 0xA345, 0xC976, 0xA346, 0xC977, 0xA347, 0xC978, 0xA348, 0xC979, 0xA349, 0xC97A, 0xA34A, 0xC97B, 0xA34B, 0xC97D, + 0xA34C, 0xC97E, 0xA34D, 0xC97F, 0xA34E, 0xC980, 0xA34F, 0xC981, 0xA350, 0xC982, 0xA351, 0xC983, 0xA352, 0xC984, 0xA353, 0xC985, + 0xA354, 0xC986, 0xA355, 0xC987, 0xA356, 0xC98A, 0xA357, 0xC98B, 0xA358, 0xC98D, 0xA359, 0xC98E, 0xA35A, 0xC98F, 0xA361, 0xC991, + 0xA362, 0xC992, 0xA363, 0xC993, 0xA364, 0xC994, 0xA365, 0xC995, 0xA366, 0xC996, 0xA367, 0xC997, 0xA368, 0xC99A, 0xA369, 0xC99C, + 0xA36A, 0xC99E, 0xA36B, 0xC99F, 0xA36C, 0xC9A0, 0xA36D, 0xC9A1, 0xA36E, 0xC9A2, 0xA36F, 0xC9A3, 0xA370, 0xC9A4, 0xA371, 0xC9A5, + 0xA372, 0xC9A6, 0xA373, 0xC9A7, 0xA374, 0xC9A8, 0xA375, 0xC9A9, 0xA376, 0xC9AA, 0xA377, 0xC9AB, 0xA378, 0xC9AC, 0xA379, 0xC9AD, + 0xA37A, 0xC9AE, 0xA381, 0xC9AF, 0xA382, 0xC9B0, 0xA383, 0xC9B1, 0xA384, 0xC9B2, 0xA385, 0xC9B3, 0xA386, 0xC9B4, 0xA387, 0xC9B5, + 0xA388, 0xC9B6, 0xA389, 0xC9B7, 0xA38A, 0xC9B8, 0xA38B, 0xC9B9, 0xA38C, 0xC9BA, 0xA38D, 0xC9BB, 0xA38E, 0xC9BC, 0xA38F, 0xC9BD, + 0xA390, 0xC9BE, 0xA391, 0xC9BF, 0xA392, 0xC9C2, 0xA393, 0xC9C3, 0xA394, 0xC9C5, 0xA395, 0xC9C6, 0xA396, 0xC9C9, 0xA397, 0xC9CB, + 0xA398, 0xC9CC, 0xA399, 0xC9CD, 0xA39A, 0xC9CE, 0xA39B, 0xC9CF, 0xA39C, 0xC9D2, 0xA39D, 0xC9D4, 0xA39E, 0xC9D7, 0xA39F, 0xC9D8, + 0xA3A0, 0xC9DB, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFF04, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, + 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, + 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, + 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, + 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, + 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, + 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, + 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFFE6, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, + 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, + 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, + 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, + 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA441, 0xC9DE, + 0xA442, 0xC9DF, 0xA443, 0xC9E1, 0xA444, 0xC9E3, 0xA445, 0xC9E5, 0xA446, 0xC9E6, 0xA447, 0xC9E8, 0xA448, 0xC9E9, 0xA449, 0xC9EA, + 0xA44A, 0xC9EB, 0xA44B, 0xC9EE, 0xA44C, 0xC9F2, 0xA44D, 0xC9F3, 0xA44E, 0xC9F4, 0xA44F, 0xC9F5, 0xA450, 0xC9F6, 0xA451, 0xC9F7, + 0xA452, 0xC9FA, 0xA453, 0xC9FB, 0xA454, 0xC9FD, 0xA455, 0xC9FE, 0xA456, 0xC9FF, 0xA457, 0xCA01, 0xA458, 0xCA02, 0xA459, 0xCA03, + 0xA45A, 0xCA04, 0xA461, 0xCA05, 0xA462, 0xCA06, 0xA463, 0xCA07, 0xA464, 0xCA0A, 0xA465, 0xCA0E, 0xA466, 0xCA0F, 0xA467, 0xCA10, + 0xA468, 0xCA11, 0xA469, 0xCA12, 0xA46A, 0xCA13, 0xA46B, 0xCA15, 0xA46C, 0xCA16, 0xA46D, 0xCA17, 0xA46E, 0xCA19, 0xA46F, 0xCA1A, + 0xA470, 0xCA1B, 0xA471, 0xCA1C, 0xA472, 0xCA1D, 0xA473, 0xCA1E, 0xA474, 0xCA1F, 0xA475, 0xCA20, 0xA476, 0xCA21, 0xA477, 0xCA22, + 0xA478, 0xCA23, 0xA479, 0xCA24, 0xA47A, 0xCA25, 0xA481, 0xCA26, 0xA482, 0xCA27, 0xA483, 0xCA28, 0xA484, 0xCA2A, 0xA485, 0xCA2B, + 0xA486, 0xCA2C, 0xA487, 0xCA2D, 0xA488, 0xCA2E, 0xA489, 0xCA2F, 0xA48A, 0xCA30, 0xA48B, 0xCA31, 0xA48C, 0xCA32, 0xA48D, 0xCA33, + 0xA48E, 0xCA34, 0xA48F, 0xCA35, 0xA490, 0xCA36, 0xA491, 0xCA37, 0xA492, 0xCA38, 0xA493, 0xCA39, 0xA494, 0xCA3A, 0xA495, 0xCA3B, + 0xA496, 0xCA3C, 0xA497, 0xCA3D, 0xA498, 0xCA3E, 0xA499, 0xCA3F, 0xA49A, 0xCA40, 0xA49B, 0xCA41, 0xA49C, 0xCA42, 0xA49D, 0xCA43, + 0xA49E, 0xCA44, 0xA49F, 0xCA45, 0xA4A0, 0xCA46, 0xA4A1, 0x3131, 0xA4A2, 0x3132, 0xA4A3, 0x3133, 0xA4A4, 0x3134, 0xA4A5, 0x3135, + 0xA4A6, 0x3136, 0xA4A7, 0x3137, 0xA4A8, 0x3138, 0xA4A9, 0x3139, 0xA4AA, 0x313A, 0xA4AB, 0x313B, 0xA4AC, 0x313C, 0xA4AD, 0x313D, + 0xA4AE, 0x313E, 0xA4AF, 0x313F, 0xA4B0, 0x3140, 0xA4B1, 0x3141, 0xA4B2, 0x3142, 0xA4B3, 0x3143, 0xA4B4, 0x3144, 0xA4B5, 0x3145, + 0xA4B6, 0x3146, 0xA4B7, 0x3147, 0xA4B8, 0x3148, 0xA4B9, 0x3149, 0xA4BA, 0x314A, 0xA4BB, 0x314B, 0xA4BC, 0x314C, 0xA4BD, 0x314D, + 0xA4BE, 0x314E, 0xA4BF, 0x314F, 0xA4C0, 0x3150, 0xA4C1, 0x3151, 0xA4C2, 0x3152, 0xA4C3, 0x3153, 0xA4C4, 0x3154, 0xA4C5, 0x3155, + 0xA4C6, 0x3156, 0xA4C7, 0x3157, 0xA4C8, 0x3158, 0xA4C9, 0x3159, 0xA4CA, 0x315A, 0xA4CB, 0x315B, 0xA4CC, 0x315C, 0xA4CD, 0x315D, + 0xA4CE, 0x315E, 0xA4CF, 0x315F, 0xA4D0, 0x3160, 0xA4D1, 0x3161, 0xA4D2, 0x3162, 0xA4D3, 0x3163, 0xA4D4, 0x3164, 0xA4D5, 0x3165, + 0xA4D6, 0x3166, 0xA4D7, 0x3167, 0xA4D8, 0x3168, 0xA4D9, 0x3169, 0xA4DA, 0x316A, 0xA4DB, 0x316B, 0xA4DC, 0x316C, 0xA4DD, 0x316D, + 0xA4DE, 0x316E, 0xA4DF, 0x316F, 0xA4E0, 0x3170, 0xA4E1, 0x3171, 0xA4E2, 0x3172, 0xA4E3, 0x3173, 0xA4E4, 0x3174, 0xA4E5, 0x3175, + 0xA4E6, 0x3176, 0xA4E7, 0x3177, 0xA4E8, 0x3178, 0xA4E9, 0x3179, 0xA4EA, 0x317A, 0xA4EB, 0x317B, 0xA4EC, 0x317C, 0xA4ED, 0x317D, + 0xA4EE, 0x317E, 0xA4EF, 0x317F, 0xA4F0, 0x3180, 0xA4F1, 0x3181, 0xA4F2, 0x3182, 0xA4F3, 0x3183, 0xA4F4, 0x3184, 0xA4F5, 0x3185, + 0xA4F6, 0x3186, 0xA4F7, 0x3187, 0xA4F8, 0x3188, 0xA4F9, 0x3189, 0xA4FA, 0x318A, 0xA4FB, 0x318B, 0xA4FC, 0x318C, 0xA4FD, 0x318D, + 0xA4FE, 0x318E, 0xA541, 0xCA47, 0xA542, 0xCA48, 0xA543, 0xCA49, 0xA544, 0xCA4A, 0xA545, 0xCA4B, 0xA546, 0xCA4E, 0xA547, 0xCA4F, + 0xA548, 0xCA51, 0xA549, 0xCA52, 0xA54A, 0xCA53, 0xA54B, 0xCA55, 0xA54C, 0xCA56, 0xA54D, 0xCA57, 0xA54E, 0xCA58, 0xA54F, 0xCA59, + 0xA550, 0xCA5A, 0xA551, 0xCA5B, 0xA552, 0xCA5E, 0xA553, 0xCA62, 0xA554, 0xCA63, 0xA555, 0xCA64, 0xA556, 0xCA65, 0xA557, 0xCA66, + 0xA558, 0xCA67, 0xA559, 0xCA69, 0xA55A, 0xCA6A, 0xA561, 0xCA6B, 0xA562, 0xCA6C, 0xA563, 0xCA6D, 0xA564, 0xCA6E, 0xA565, 0xCA6F, + 0xA566, 0xCA70, 0xA567, 0xCA71, 0xA568, 0xCA72, 0xA569, 0xCA73, 0xA56A, 0xCA74, 0xA56B, 0xCA75, 0xA56C, 0xCA76, 0xA56D, 0xCA77, + 0xA56E, 0xCA78, 0xA56F, 0xCA79, 0xA570, 0xCA7A, 0xA571, 0xCA7B, 0xA572, 0xCA7C, 0xA573, 0xCA7E, 0xA574, 0xCA7F, 0xA575, 0xCA80, + 0xA576, 0xCA81, 0xA577, 0xCA82, 0xA578, 0xCA83, 0xA579, 0xCA85, 0xA57A, 0xCA86, 0xA581, 0xCA87, 0xA582, 0xCA88, 0xA583, 0xCA89, + 0xA584, 0xCA8A, 0xA585, 0xCA8B, 0xA586, 0xCA8C, 0xA587, 0xCA8D, 0xA588, 0xCA8E, 0xA589, 0xCA8F, 0xA58A, 0xCA90, 0xA58B, 0xCA91, + 0xA58C, 0xCA92, 0xA58D, 0xCA93, 0xA58E, 0xCA94, 0xA58F, 0xCA95, 0xA590, 0xCA96, 0xA591, 0xCA97, 0xA592, 0xCA99, 0xA593, 0xCA9A, + 0xA594, 0xCA9B, 0xA595, 0xCA9C, 0xA596, 0xCA9D, 0xA597, 0xCA9E, 0xA598, 0xCA9F, 0xA599, 0xCAA0, 0xA59A, 0xCAA1, 0xA59B, 0xCAA2, + 0xA59C, 0xCAA3, 0xA59D, 0xCAA4, 0xA59E, 0xCAA5, 0xA59F, 0xCAA6, 0xA5A0, 0xCAA7, 0xA5A1, 0x2170, 0xA5A2, 0x2171, 0xA5A3, 0x2172, + 0xA5A4, 0x2173, 0xA5A5, 0x2174, 0xA5A6, 0x2175, 0xA5A7, 0x2176, 0xA5A8, 0x2177, 0xA5A9, 0x2178, 0xA5AA, 0x2179, 0xA5B0, 0x2160, + 0xA5B1, 0x2161, 0xA5B2, 0x2162, 0xA5B3, 0x2163, 0xA5B4, 0x2164, 0xA5B5, 0x2165, 0xA5B6, 0x2166, 0xA5B7, 0x2167, 0xA5B8, 0x2168, + 0xA5B9, 0x2169, 0xA5C1, 0x0391, 0xA5C2, 0x0392, 0xA5C3, 0x0393, 0xA5C4, 0x0394, 0xA5C5, 0x0395, 0xA5C6, 0x0396, 0xA5C7, 0x0397, + 0xA5C8, 0x0398, 0xA5C9, 0x0399, 0xA5CA, 0x039A, 0xA5CB, 0x039B, 0xA5CC, 0x039C, 0xA5CD, 0x039D, 0xA5CE, 0x039E, 0xA5CF, 0x039F, + 0xA5D0, 0x03A0, 0xA5D1, 0x03A1, 0xA5D2, 0x03A3, 0xA5D3, 0x03A4, 0xA5D4, 0x03A5, 0xA5D5, 0x03A6, 0xA5D6, 0x03A7, 0xA5D7, 0x03A8, + 0xA5D8, 0x03A9, 0xA5E1, 0x03B1, 0xA5E2, 0x03B2, 0xA5E3, 0x03B3, 0xA5E4, 0x03B4, 0xA5E5, 0x03B5, 0xA5E6, 0x03B6, 0xA5E7, 0x03B7, + 0xA5E8, 0x03B8, 0xA5E9, 0x03B9, 0xA5EA, 0x03BA, 0xA5EB, 0x03BB, 0xA5EC, 0x03BC, 0xA5ED, 0x03BD, 0xA5EE, 0x03BE, 0xA5EF, 0x03BF, + 0xA5F0, 0x03C0, 0xA5F1, 0x03C1, 0xA5F2, 0x03C3, 0xA5F3, 0x03C4, 0xA5F4, 0x03C5, 0xA5F5, 0x03C6, 0xA5F6, 0x03C7, 0xA5F7, 0x03C8, + 0xA5F8, 0x03C9, 0xA641, 0xCAA8, 0xA642, 0xCAA9, 0xA643, 0xCAAA, 0xA644, 0xCAAB, 0xA645, 0xCAAC, 0xA646, 0xCAAD, 0xA647, 0xCAAE, + 0xA648, 0xCAAF, 0xA649, 0xCAB0, 0xA64A, 0xCAB1, 0xA64B, 0xCAB2, 0xA64C, 0xCAB3, 0xA64D, 0xCAB4, 0xA64E, 0xCAB5, 0xA64F, 0xCAB6, + 0xA650, 0xCAB7, 0xA651, 0xCAB8, 0xA652, 0xCAB9, 0xA653, 0xCABA, 0xA654, 0xCABB, 0xA655, 0xCABE, 0xA656, 0xCABF, 0xA657, 0xCAC1, + 0xA658, 0xCAC2, 0xA659, 0xCAC3, 0xA65A, 0xCAC5, 0xA661, 0xCAC6, 0xA662, 0xCAC7, 0xA663, 0xCAC8, 0xA664, 0xCAC9, 0xA665, 0xCACA, + 0xA666, 0xCACB, 0xA667, 0xCACE, 0xA668, 0xCAD0, 0xA669, 0xCAD2, 0xA66A, 0xCAD4, 0xA66B, 0xCAD5, 0xA66C, 0xCAD6, 0xA66D, 0xCAD7, + 0xA66E, 0xCADA, 0xA66F, 0xCADB, 0xA670, 0xCADC, 0xA671, 0xCADD, 0xA672, 0xCADE, 0xA673, 0xCADF, 0xA674, 0xCAE1, 0xA675, 0xCAE2, + 0xA676, 0xCAE3, 0xA677, 0xCAE4, 0xA678, 0xCAE5, 0xA679, 0xCAE6, 0xA67A, 0xCAE7, 0xA681, 0xCAE8, 0xA682, 0xCAE9, 0xA683, 0xCAEA, + 0xA684, 0xCAEB, 0xA685, 0xCAED, 0xA686, 0xCAEE, 0xA687, 0xCAEF, 0xA688, 0xCAF0, 0xA689, 0xCAF1, 0xA68A, 0xCAF2, 0xA68B, 0xCAF3, + 0xA68C, 0xCAF5, 0xA68D, 0xCAF6, 0xA68E, 0xCAF7, 0xA68F, 0xCAF8, 0xA690, 0xCAF9, 0xA691, 0xCAFA, 0xA692, 0xCAFB, 0xA693, 0xCAFC, + 0xA694, 0xCAFD, 0xA695, 0xCAFE, 0xA696, 0xCAFF, 0xA697, 0xCB00, 0xA698, 0xCB01, 0xA699, 0xCB02, 0xA69A, 0xCB03, 0xA69B, 0xCB04, + 0xA69C, 0xCB05, 0xA69D, 0xCB06, 0xA69E, 0xCB07, 0xA69F, 0xCB09, 0xA6A0, 0xCB0A, 0xA6A1, 0x2500, 0xA6A2, 0x2502, 0xA6A3, 0x250C, + 0xA6A4, 0x2510, 0xA6A5, 0x2518, 0xA6A6, 0x2514, 0xA6A7, 0x251C, 0xA6A8, 0x252C, 0xA6A9, 0x2524, 0xA6AA, 0x2534, 0xA6AB, 0x253C, + 0xA6AC, 0x2501, 0xA6AD, 0x2503, 0xA6AE, 0x250F, 0xA6AF, 0x2513, 0xA6B0, 0x251B, 0xA6B1, 0x2517, 0xA6B2, 0x2523, 0xA6B3, 0x2533, + 0xA6B4, 0x252B, 0xA6B5, 0x253B, 0xA6B6, 0x254B, 0xA6B7, 0x2520, 0xA6B8, 0x252F, 0xA6B9, 0x2528, 0xA6BA, 0x2537, 0xA6BB, 0x253F, + 0xA6BC, 0x251D, 0xA6BD, 0x2530, 0xA6BE, 0x2525, 0xA6BF, 0x2538, 0xA6C0, 0x2542, 0xA6C1, 0x2512, 0xA6C2, 0x2511, 0xA6C3, 0x251A, + 0xA6C4, 0x2519, 0xA6C5, 0x2516, 0xA6C6, 0x2515, 0xA6C7, 0x250E, 0xA6C8, 0x250D, 0xA6C9, 0x251E, 0xA6CA, 0x251F, 0xA6CB, 0x2521, + 0xA6CC, 0x2522, 0xA6CD, 0x2526, 0xA6CE, 0x2527, 0xA6CF, 0x2529, 0xA6D0, 0x252A, 0xA6D1, 0x252D, 0xA6D2, 0x252E, 0xA6D3, 0x2531, + 0xA6D4, 0x2532, 0xA6D5, 0x2535, 0xA6D6, 0x2536, 0xA6D7, 0x2539, 0xA6D8, 0x253A, 0xA6D9, 0x253D, 0xA6DA, 0x253E, 0xA6DB, 0x2540, + 0xA6DC, 0x2541, 0xA6DD, 0x2543, 0xA6DE, 0x2544, 0xA6DF, 0x2545, 0xA6E0, 0x2546, 0xA6E1, 0x2547, 0xA6E2, 0x2548, 0xA6E3, 0x2549, + 0xA6E4, 0x254A, 0xA741, 0xCB0B, 0xA742, 0xCB0C, 0xA743, 0xCB0D, 0xA744, 0xCB0E, 0xA745, 0xCB0F, 0xA746, 0xCB11, 0xA747, 0xCB12, + 0xA748, 0xCB13, 0xA749, 0xCB15, 0xA74A, 0xCB16, 0xA74B, 0xCB17, 0xA74C, 0xCB19, 0xA74D, 0xCB1A, 0xA74E, 0xCB1B, 0xA74F, 0xCB1C, + 0xA750, 0xCB1D, 0xA751, 0xCB1E, 0xA752, 0xCB1F, 0xA753, 0xCB22, 0xA754, 0xCB23, 0xA755, 0xCB24, 0xA756, 0xCB25, 0xA757, 0xCB26, + 0xA758, 0xCB27, 0xA759, 0xCB28, 0xA75A, 0xCB29, 0xA761, 0xCB2A, 0xA762, 0xCB2B, 0xA763, 0xCB2C, 0xA764, 0xCB2D, 0xA765, 0xCB2E, + 0xA766, 0xCB2F, 0xA767, 0xCB30, 0xA768, 0xCB31, 0xA769, 0xCB32, 0xA76A, 0xCB33, 0xA76B, 0xCB34, 0xA76C, 0xCB35, 0xA76D, 0xCB36, + 0xA76E, 0xCB37, 0xA76F, 0xCB38, 0xA770, 0xCB39, 0xA771, 0xCB3A, 0xA772, 0xCB3B, 0xA773, 0xCB3C, 0xA774, 0xCB3D, 0xA775, 0xCB3E, + 0xA776, 0xCB3F, 0xA777, 0xCB40, 0xA778, 0xCB42, 0xA779, 0xCB43, 0xA77A, 0xCB44, 0xA781, 0xCB45, 0xA782, 0xCB46, 0xA783, 0xCB47, + 0xA784, 0xCB4A, 0xA785, 0xCB4B, 0xA786, 0xCB4D, 0xA787, 0xCB4E, 0xA788, 0xCB4F, 0xA789, 0xCB51, 0xA78A, 0xCB52, 0xA78B, 0xCB53, + 0xA78C, 0xCB54, 0xA78D, 0xCB55, 0xA78E, 0xCB56, 0xA78F, 0xCB57, 0xA790, 0xCB5A, 0xA791, 0xCB5B, 0xA792, 0xCB5C, 0xA793, 0xCB5E, + 0xA794, 0xCB5F, 0xA795, 0xCB60, 0xA796, 0xCB61, 0xA797, 0xCB62, 0xA798, 0xCB63, 0xA799, 0xCB65, 0xA79A, 0xCB66, 0xA79B, 0xCB67, + 0xA79C, 0xCB68, 0xA79D, 0xCB69, 0xA79E, 0xCB6A, 0xA79F, 0xCB6B, 0xA7A0, 0xCB6C, 0xA7A1, 0x3395, 0xA7A2, 0x3396, 0xA7A3, 0x3397, + 0xA7A4, 0x2113, 0xA7A5, 0x3398, 0xA7A6, 0x33C4, 0xA7A7, 0x33A3, 0xA7A8, 0x33A4, 0xA7A9, 0x33A5, 0xA7AA, 0x33A6, 0xA7AB, 0x3399, + 0xA7AC, 0x339A, 0xA7AD, 0x339B, 0xA7AE, 0x339C, 0xA7AF, 0x339D, 0xA7B0, 0x339E, 0xA7B1, 0x339F, 0xA7B2, 0x33A0, 0xA7B3, 0x33A1, + 0xA7B4, 0x33A2, 0xA7B5, 0x33CA, 0xA7B6, 0x338D, 0xA7B7, 0x338E, 0xA7B8, 0x338F, 0xA7B9, 0x33CF, 0xA7BA, 0x3388, 0xA7BB, 0x3389, + 0xA7BC, 0x33C8, 0xA7BD, 0x33A7, 0xA7BE, 0x33A8, 0xA7BF, 0x33B0, 0xA7C0, 0x33B1, 0xA7C1, 0x33B2, 0xA7C2, 0x33B3, 0xA7C3, 0x33B4, + 0xA7C4, 0x33B5, 0xA7C5, 0x33B6, 0xA7C6, 0x33B7, 0xA7C7, 0x33B8, 0xA7C8, 0x33B9, 0xA7C9, 0x3380, 0xA7CA, 0x3381, 0xA7CB, 0x3382, + 0xA7CC, 0x3383, 0xA7CD, 0x3384, 0xA7CE, 0x33BA, 0xA7CF, 0x33BB, 0xA7D0, 0x33BC, 0xA7D1, 0x33BD, 0xA7D2, 0x33BE, 0xA7D3, 0x33BF, + 0xA7D4, 0x3390, 0xA7D5, 0x3391, 0xA7D6, 0x3392, 0xA7D7, 0x3393, 0xA7D8, 0x3394, 0xA7D9, 0x2126, 0xA7DA, 0x33C0, 0xA7DB, 0x33C1, + 0xA7DC, 0x338A, 0xA7DD, 0x338B, 0xA7DE, 0x338C, 0xA7DF, 0x33D6, 0xA7E0, 0x33C5, 0xA7E1, 0x33AD, 0xA7E2, 0x33AE, 0xA7E3, 0x33AF, + 0xA7E4, 0x33DB, 0xA7E5, 0x33A9, 0xA7E6, 0x33AA, 0xA7E7, 0x33AB, 0xA7E8, 0x33AC, 0xA7E9, 0x33DD, 0xA7EA, 0x33D0, 0xA7EB, 0x33D3, + 0xA7EC, 0x33C3, 0xA7ED, 0x33C9, 0xA7EE, 0x33DC, 0xA7EF, 0x33C6, 0xA841, 0xCB6D, 0xA842, 0xCB6E, 0xA843, 0xCB6F, 0xA844, 0xCB70, + 0xA845, 0xCB71, 0xA846, 0xCB72, 0xA847, 0xCB73, 0xA848, 0xCB74, 0xA849, 0xCB75, 0xA84A, 0xCB76, 0xA84B, 0xCB77, 0xA84C, 0xCB7A, + 0xA84D, 0xCB7B, 0xA84E, 0xCB7C, 0xA84F, 0xCB7D, 0xA850, 0xCB7E, 0xA851, 0xCB7F, 0xA852, 0xCB80, 0xA853, 0xCB81, 0xA854, 0xCB82, + 0xA855, 0xCB83, 0xA856, 0xCB84, 0xA857, 0xCB85, 0xA858, 0xCB86, 0xA859, 0xCB87, 0xA85A, 0xCB88, 0xA861, 0xCB89, 0xA862, 0xCB8A, + 0xA863, 0xCB8B, 0xA864, 0xCB8C, 0xA865, 0xCB8D, 0xA866, 0xCB8E, 0xA867, 0xCB8F, 0xA868, 0xCB90, 0xA869, 0xCB91, 0xA86A, 0xCB92, + 0xA86B, 0xCB93, 0xA86C, 0xCB94, 0xA86D, 0xCB95, 0xA86E, 0xCB96, 0xA86F, 0xCB97, 0xA870, 0xCB98, 0xA871, 0xCB99, 0xA872, 0xCB9A, + 0xA873, 0xCB9B, 0xA874, 0xCB9D, 0xA875, 0xCB9E, 0xA876, 0xCB9F, 0xA877, 0xCBA0, 0xA878, 0xCBA1, 0xA879, 0xCBA2, 0xA87A, 0xCBA3, + 0xA881, 0xCBA4, 0xA882, 0xCBA5, 0xA883, 0xCBA6, 0xA884, 0xCBA7, 0xA885, 0xCBA8, 0xA886, 0xCBA9, 0xA887, 0xCBAA, 0xA888, 0xCBAB, + 0xA889, 0xCBAC, 0xA88A, 0xCBAD, 0xA88B, 0xCBAE, 0xA88C, 0xCBAF, 0xA88D, 0xCBB0, 0xA88E, 0xCBB1, 0xA88F, 0xCBB2, 0xA890, 0xCBB3, + 0xA891, 0xCBB4, 0xA892, 0xCBB5, 0xA893, 0xCBB6, 0xA894, 0xCBB7, 0xA895, 0xCBB9, 0xA896, 0xCBBA, 0xA897, 0xCBBB, 0xA898, 0xCBBC, + 0xA899, 0xCBBD, 0xA89A, 0xCBBE, 0xA89B, 0xCBBF, 0xA89C, 0xCBC0, 0xA89D, 0xCBC1, 0xA89E, 0xCBC2, 0xA89F, 0xCBC3, 0xA8A0, 0xCBC4, + 0xA8A1, 0x00C6, 0xA8A2, 0x00D0, 0xA8A3, 0x00AA, 0xA8A4, 0x0126, 0xA8A6, 0x0132, 0xA8A8, 0x013F, 0xA8A9, 0x0141, 0xA8AA, 0x00D8, + 0xA8AB, 0x0152, 0xA8AC, 0x00BA, 0xA8AD, 0x00DE, 0xA8AE, 0x0166, 0xA8AF, 0x014A, 0xA8B1, 0x3260, 0xA8B2, 0x3261, 0xA8B3, 0x3262, + 0xA8B4, 0x3263, 0xA8B5, 0x3264, 0xA8B6, 0x3265, 0xA8B7, 0x3266, 0xA8B8, 0x3267, 0xA8B9, 0x3268, 0xA8BA, 0x3269, 0xA8BB, 0x326A, + 0xA8BC, 0x326B, 0xA8BD, 0x326C, 0xA8BE, 0x326D, 0xA8BF, 0x326E, 0xA8C0, 0x326F, 0xA8C1, 0x3270, 0xA8C2, 0x3271, 0xA8C3, 0x3272, + 0xA8C4, 0x3273, 0xA8C5, 0x3274, 0xA8C6, 0x3275, 0xA8C7, 0x3276, 0xA8C8, 0x3277, 0xA8C9, 0x3278, 0xA8CA, 0x3279, 0xA8CB, 0x327A, + 0xA8CC, 0x327B, 0xA8CD, 0x24D0, 0xA8CE, 0x24D1, 0xA8CF, 0x24D2, 0xA8D0, 0x24D3, 0xA8D1, 0x24D4, 0xA8D2, 0x24D5, 0xA8D3, 0x24D6, + 0xA8D4, 0x24D7, 0xA8D5, 0x24D8, 0xA8D6, 0x24D9, 0xA8D7, 0x24DA, 0xA8D8, 0x24DB, 0xA8D9, 0x24DC, 0xA8DA, 0x24DD, 0xA8DB, 0x24DE, + 0xA8DC, 0x24DF, 0xA8DD, 0x24E0, 0xA8DE, 0x24E1, 0xA8DF, 0x24E2, 0xA8E0, 0x24E3, 0xA8E1, 0x24E4, 0xA8E2, 0x24E5, 0xA8E3, 0x24E6, + 0xA8E4, 0x24E7, 0xA8E5, 0x24E8, 0xA8E6, 0x24E9, 0xA8E7, 0x2460, 0xA8E8, 0x2461, 0xA8E9, 0x2462, 0xA8EA, 0x2463, 0xA8EB, 0x2464, + 0xA8EC, 0x2465, 0xA8ED, 0x2466, 0xA8EE, 0x2467, 0xA8EF, 0x2468, 0xA8F0, 0x2469, 0xA8F1, 0x246A, 0xA8F2, 0x246B, 0xA8F3, 0x246C, + 0xA8F4, 0x246D, 0xA8F5, 0x246E, 0xA8F6, 0x00BD, 0xA8F7, 0x2153, 0xA8F8, 0x2154, 0xA8F9, 0x00BC, 0xA8FA, 0x00BE, 0xA8FB, 0x215B, + 0xA8FC, 0x215C, 0xA8FD, 0x215D, 0xA8FE, 0x215E, 0xA941, 0xCBC5, 0xA942, 0xCBC6, 0xA943, 0xCBC7, 0xA944, 0xCBC8, 0xA945, 0xCBC9, + 0xA946, 0xCBCA, 0xA947, 0xCBCB, 0xA948, 0xCBCC, 0xA949, 0xCBCD, 0xA94A, 0xCBCE, 0xA94B, 0xCBCF, 0xA94C, 0xCBD0, 0xA94D, 0xCBD1, + 0xA94E, 0xCBD2, 0xA94F, 0xCBD3, 0xA950, 0xCBD5, 0xA951, 0xCBD6, 0xA952, 0xCBD7, 0xA953, 0xCBD8, 0xA954, 0xCBD9, 0xA955, 0xCBDA, + 0xA956, 0xCBDB, 0xA957, 0xCBDC, 0xA958, 0xCBDD, 0xA959, 0xCBDE, 0xA95A, 0xCBDF, 0xA961, 0xCBE0, 0xA962, 0xCBE1, 0xA963, 0xCBE2, + 0xA964, 0xCBE3, 0xA965, 0xCBE5, 0xA966, 0xCBE6, 0xA967, 0xCBE8, 0xA968, 0xCBEA, 0xA969, 0xCBEB, 0xA96A, 0xCBEC, 0xA96B, 0xCBED, + 0xA96C, 0xCBEE, 0xA96D, 0xCBEF, 0xA96E, 0xCBF0, 0xA96F, 0xCBF1, 0xA970, 0xCBF2, 0xA971, 0xCBF3, 0xA972, 0xCBF4, 0xA973, 0xCBF5, + 0xA974, 0xCBF6, 0xA975, 0xCBF7, 0xA976, 0xCBF8, 0xA977, 0xCBF9, 0xA978, 0xCBFA, 0xA979, 0xCBFB, 0xA97A, 0xCBFC, 0xA981, 0xCBFD, + 0xA982, 0xCBFE, 0xA983, 0xCBFF, 0xA984, 0xCC00, 0xA985, 0xCC01, 0xA986, 0xCC02, 0xA987, 0xCC03, 0xA988, 0xCC04, 0xA989, 0xCC05, + 0xA98A, 0xCC06, 0xA98B, 0xCC07, 0xA98C, 0xCC08, 0xA98D, 0xCC09, 0xA98E, 0xCC0A, 0xA98F, 0xCC0B, 0xA990, 0xCC0E, 0xA991, 0xCC0F, + 0xA992, 0xCC11, 0xA993, 0xCC12, 0xA994, 0xCC13, 0xA995, 0xCC15, 0xA996, 0xCC16, 0xA997, 0xCC17, 0xA998, 0xCC18, 0xA999, 0xCC19, + 0xA99A, 0xCC1A, 0xA99B, 0xCC1B, 0xA99C, 0xCC1E, 0xA99D, 0xCC1F, 0xA99E, 0xCC20, 0xA99F, 0xCC23, 0xA9A0, 0xCC24, 0xA9A1, 0x00E6, + 0xA9A2, 0x0111, 0xA9A3, 0x00F0, 0xA9A4, 0x0127, 0xA9A5, 0x0131, 0xA9A6, 0x0133, 0xA9A7, 0x0138, 0xA9A8, 0x0140, 0xA9A9, 0x0142, + 0xA9AA, 0x00F8, 0xA9AB, 0x0153, 0xA9AC, 0x00DF, 0xA9AD, 0x00FE, 0xA9AE, 0x0167, 0xA9AF, 0x014B, 0xA9B0, 0x0149, 0xA9B1, 0x3200, + 0xA9B2, 0x3201, 0xA9B3, 0x3202, 0xA9B4, 0x3203, 0xA9B5, 0x3204, 0xA9B6, 0x3205, 0xA9B7, 0x3206, 0xA9B8, 0x3207, 0xA9B9, 0x3208, + 0xA9BA, 0x3209, 0xA9BB, 0x320A, 0xA9BC, 0x320B, 0xA9BD, 0x320C, 0xA9BE, 0x320D, 0xA9BF, 0x320E, 0xA9C0, 0x320F, 0xA9C1, 0x3210, + 0xA9C2, 0x3211, 0xA9C3, 0x3212, 0xA9C4, 0x3213, 0xA9C5, 0x3214, 0xA9C6, 0x3215, 0xA9C7, 0x3216, 0xA9C8, 0x3217, 0xA9C9, 0x3218, + 0xA9CA, 0x3219, 0xA9CB, 0x321A, 0xA9CC, 0x321B, 0xA9CD, 0x249C, 0xA9CE, 0x249D, 0xA9CF, 0x249E, 0xA9D0, 0x249F, 0xA9D1, 0x24A0, + 0xA9D2, 0x24A1, 0xA9D3, 0x24A2, 0xA9D4, 0x24A3, 0xA9D5, 0x24A4, 0xA9D6, 0x24A5, 0xA9D7, 0x24A6, 0xA9D8, 0x24A7, 0xA9D9, 0x24A8, + 0xA9DA, 0x24A9, 0xA9DB, 0x24AA, 0xA9DC, 0x24AB, 0xA9DD, 0x24AC, 0xA9DE, 0x24AD, 0xA9DF, 0x24AE, 0xA9E0, 0x24AF, 0xA9E1, 0x24B0, + 0xA9E2, 0x24B1, 0xA9E3, 0x24B2, 0xA9E4, 0x24B3, 0xA9E5, 0x24B4, 0xA9E6, 0x24B5, 0xA9E7, 0x2474, 0xA9E8, 0x2475, 0xA9E9, 0x2476, + 0xA9EA, 0x2477, 0xA9EB, 0x2478, 0xA9EC, 0x2479, 0xA9ED, 0x247A, 0xA9EE, 0x247B, 0xA9EF, 0x247C, 0xA9F0, 0x247D, 0xA9F1, 0x247E, + 0xA9F2, 0x247F, 0xA9F3, 0x2480, 0xA9F4, 0x2481, 0xA9F5, 0x2482, 0xA9F6, 0x00B9, 0xA9F7, 0x00B2, 0xA9F8, 0x00B3, 0xA9F9, 0x2074, + 0xA9FA, 0x207F, 0xA9FB, 0x2081, 0xA9FC, 0x2082, 0xA9FD, 0x2083, 0xA9FE, 0x2084, 0xAA41, 0xCC25, 0xAA42, 0xCC26, 0xAA43, 0xCC2A, + 0xAA44, 0xCC2B, 0xAA45, 0xCC2D, 0xAA46, 0xCC2F, 0xAA47, 0xCC31, 0xAA48, 0xCC32, 0xAA49, 0xCC33, 0xAA4A, 0xCC34, 0xAA4B, 0xCC35, + 0xAA4C, 0xCC36, 0xAA4D, 0xCC37, 0xAA4E, 0xCC3A, 0xAA4F, 0xCC3F, 0xAA50, 0xCC40, 0xAA51, 0xCC41, 0xAA52, 0xCC42, 0xAA53, 0xCC43, + 0xAA54, 0xCC46, 0xAA55, 0xCC47, 0xAA56, 0xCC49, 0xAA57, 0xCC4A, 0xAA58, 0xCC4B, 0xAA59, 0xCC4D, 0xAA5A, 0xCC4E, 0xAA61, 0xCC4F, + 0xAA62, 0xCC50, 0xAA63, 0xCC51, 0xAA64, 0xCC52, 0xAA65, 0xCC53, 0xAA66, 0xCC56, 0xAA67, 0xCC5A, 0xAA68, 0xCC5B, 0xAA69, 0xCC5C, + 0xAA6A, 0xCC5D, 0xAA6B, 0xCC5E, 0xAA6C, 0xCC5F, 0xAA6D, 0xCC61, 0xAA6E, 0xCC62, 0xAA6F, 0xCC63, 0xAA70, 0xCC65, 0xAA71, 0xCC67, + 0xAA72, 0xCC69, 0xAA73, 0xCC6A, 0xAA74, 0xCC6B, 0xAA75, 0xCC6C, 0xAA76, 0xCC6D, 0xAA77, 0xCC6E, 0xAA78, 0xCC6F, 0xAA79, 0xCC71, + 0xAA7A, 0xCC72, 0xAA81, 0xCC73, 0xAA82, 0xCC74, 0xAA83, 0xCC76, 0xAA84, 0xCC77, 0xAA85, 0xCC78, 0xAA86, 0xCC79, 0xAA87, 0xCC7A, + 0xAA88, 0xCC7B, 0xAA89, 0xCC7C, 0xAA8A, 0xCC7D, 0xAA8B, 0xCC7E, 0xAA8C, 0xCC7F, 0xAA8D, 0xCC80, 0xAA8E, 0xCC81, 0xAA8F, 0xCC82, + 0xAA90, 0xCC83, 0xAA91, 0xCC84, 0xAA92, 0xCC85, 0xAA93, 0xCC86, 0xAA94, 0xCC87, 0xAA95, 0xCC88, 0xAA96, 0xCC89, 0xAA97, 0xCC8A, + 0xAA98, 0xCC8B, 0xAA99, 0xCC8C, 0xAA9A, 0xCC8D, 0xAA9B, 0xCC8E, 0xAA9C, 0xCC8F, 0xAA9D, 0xCC90, 0xAA9E, 0xCC91, 0xAA9F, 0xCC92, + 0xAAA0, 0xCC93, 0xAAA1, 0x3041, 0xAAA2, 0x3042, 0xAAA3, 0x3043, 0xAAA4, 0x3044, 0xAAA5, 0x3045, 0xAAA6, 0x3046, 0xAAA7, 0x3047, + 0xAAA8, 0x3048, 0xAAA9, 0x3049, 0xAAAA, 0x304A, 0xAAAB, 0x304B, 0xAAAC, 0x304C, 0xAAAD, 0x304D, 0xAAAE, 0x304E, 0xAAAF, 0x304F, + 0xAAB0, 0x3050, 0xAAB1, 0x3051, 0xAAB2, 0x3052, 0xAAB3, 0x3053, 0xAAB4, 0x3054, 0xAAB5, 0x3055, 0xAAB6, 0x3056, 0xAAB7, 0x3057, + 0xAAB8, 0x3058, 0xAAB9, 0x3059, 0xAABA, 0x305A, 0xAABB, 0x305B, 0xAABC, 0x305C, 0xAABD, 0x305D, 0xAABE, 0x305E, 0xAABF, 0x305F, + 0xAAC0, 0x3060, 0xAAC1, 0x3061, 0xAAC2, 0x3062, 0xAAC3, 0x3063, 0xAAC4, 0x3064, 0xAAC5, 0x3065, 0xAAC6, 0x3066, 0xAAC7, 0x3067, + 0xAAC8, 0x3068, 0xAAC9, 0x3069, 0xAACA, 0x306A, 0xAACB, 0x306B, 0xAACC, 0x306C, 0xAACD, 0x306D, 0xAACE, 0x306E, 0xAACF, 0x306F, + 0xAAD0, 0x3070, 0xAAD1, 0x3071, 0xAAD2, 0x3072, 0xAAD3, 0x3073, 0xAAD4, 0x3074, 0xAAD5, 0x3075, 0xAAD6, 0x3076, 0xAAD7, 0x3077, + 0xAAD8, 0x3078, 0xAAD9, 0x3079, 0xAADA, 0x307A, 0xAADB, 0x307B, 0xAADC, 0x307C, 0xAADD, 0x307D, 0xAADE, 0x307E, 0xAADF, 0x307F, + 0xAAE0, 0x3080, 0xAAE1, 0x3081, 0xAAE2, 0x3082, 0xAAE3, 0x3083, 0xAAE4, 0x3084, 0xAAE5, 0x3085, 0xAAE6, 0x3086, 0xAAE7, 0x3087, + 0xAAE8, 0x3088, 0xAAE9, 0x3089, 0xAAEA, 0x308A, 0xAAEB, 0x308B, 0xAAEC, 0x308C, 0xAAED, 0x308D, 0xAAEE, 0x308E, 0xAAEF, 0x308F, + 0xAAF0, 0x3090, 0xAAF1, 0x3091, 0xAAF2, 0x3092, 0xAAF3, 0x3093, 0xAB41, 0xCC94, 0xAB42, 0xCC95, 0xAB43, 0xCC96, 0xAB44, 0xCC97, + 0xAB45, 0xCC9A, 0xAB46, 0xCC9B, 0xAB47, 0xCC9D, 0xAB48, 0xCC9E, 0xAB49, 0xCC9F, 0xAB4A, 0xCCA1, 0xAB4B, 0xCCA2, 0xAB4C, 0xCCA3, + 0xAB4D, 0xCCA4, 0xAB4E, 0xCCA5, 0xAB4F, 0xCCA6, 0xAB50, 0xCCA7, 0xAB51, 0xCCAA, 0xAB52, 0xCCAE, 0xAB53, 0xCCAF, 0xAB54, 0xCCB0, + 0xAB55, 0xCCB1, 0xAB56, 0xCCB2, 0xAB57, 0xCCB3, 0xAB58, 0xCCB6, 0xAB59, 0xCCB7, 0xAB5A, 0xCCB9, 0xAB61, 0xCCBA, 0xAB62, 0xCCBB, + 0xAB63, 0xCCBD, 0xAB64, 0xCCBE, 0xAB65, 0xCCBF, 0xAB66, 0xCCC0, 0xAB67, 0xCCC1, 0xAB68, 0xCCC2, 0xAB69, 0xCCC3, 0xAB6A, 0xCCC6, + 0xAB6B, 0xCCC8, 0xAB6C, 0xCCCA, 0xAB6D, 0xCCCB, 0xAB6E, 0xCCCC, 0xAB6F, 0xCCCD, 0xAB70, 0xCCCE, 0xAB71, 0xCCCF, 0xAB72, 0xCCD1, + 0xAB73, 0xCCD2, 0xAB74, 0xCCD3, 0xAB75, 0xCCD5, 0xAB76, 0xCCD6, 0xAB77, 0xCCD7, 0xAB78, 0xCCD8, 0xAB79, 0xCCD9, 0xAB7A, 0xCCDA, + 0xAB81, 0xCCDB, 0xAB82, 0xCCDC, 0xAB83, 0xCCDD, 0xAB84, 0xCCDE, 0xAB85, 0xCCDF, 0xAB86, 0xCCE0, 0xAB87, 0xCCE1, 0xAB88, 0xCCE2, + 0xAB89, 0xCCE3, 0xAB8A, 0xCCE5, 0xAB8B, 0xCCE6, 0xAB8C, 0xCCE7, 0xAB8D, 0xCCE8, 0xAB8E, 0xCCE9, 0xAB8F, 0xCCEA, 0xAB90, 0xCCEB, + 0xAB91, 0xCCED, 0xAB92, 0xCCEE, 0xAB93, 0xCCEF, 0xAB94, 0xCCF1, 0xAB95, 0xCCF2, 0xAB96, 0xCCF3, 0xAB97, 0xCCF4, 0xAB98, 0xCCF5, + 0xAB99, 0xCCF6, 0xAB9A, 0xCCF7, 0xAB9B, 0xCCF8, 0xAB9C, 0xCCF9, 0xAB9D, 0xCCFA, 0xAB9E, 0xCCFB, 0xAB9F, 0xCCFC, 0xABA0, 0xCCFD, + 0xABA1, 0x30A1, 0xABA2, 0x30A2, 0xABA3, 0x30A3, 0xABA4, 0x30A4, 0xABA5, 0x30A5, 0xABA6, 0x30A6, 0xABA7, 0x30A7, 0xABA8, 0x30A8, + 0xABA9, 0x30A9, 0xABAA, 0x30AA, 0xABAB, 0x30AB, 0xABAC, 0x30AC, 0xABAD, 0x30AD, 0xABAE, 0x30AE, 0xABAF, 0x30AF, 0xABB0, 0x30B0, + 0xABB1, 0x30B1, 0xABB2, 0x30B2, 0xABB3, 0x30B3, 0xABB4, 0x30B4, 0xABB5, 0x30B5, 0xABB6, 0x30B6, 0xABB7, 0x30B7, 0xABB8, 0x30B8, + 0xABB9, 0x30B9, 0xABBA, 0x30BA, 0xABBB, 0x30BB, 0xABBC, 0x30BC, 0xABBD, 0x30BD, 0xABBE, 0x30BE, 0xABBF, 0x30BF, 0xABC0, 0x30C0, + 0xABC1, 0x30C1, 0xABC2, 0x30C2, 0xABC3, 0x30C3, 0xABC4, 0x30C4, 0xABC5, 0x30C5, 0xABC6, 0x30C6, 0xABC7, 0x30C7, 0xABC8, 0x30C8, + 0xABC9, 0x30C9, 0xABCA, 0x30CA, 0xABCB, 0x30CB, 0xABCC, 0x30CC, 0xABCD, 0x30CD, 0xABCE, 0x30CE, 0xABCF, 0x30CF, 0xABD0, 0x30D0, + 0xABD1, 0x30D1, 0xABD2, 0x30D2, 0xABD3, 0x30D3, 0xABD4, 0x30D4, 0xABD5, 0x30D5, 0xABD6, 0x30D6, 0xABD7, 0x30D7, 0xABD8, 0x30D8, + 0xABD9, 0x30D9, 0xABDA, 0x30DA, 0xABDB, 0x30DB, 0xABDC, 0x30DC, 0xABDD, 0x30DD, 0xABDE, 0x30DE, 0xABDF, 0x30DF, 0xABE0, 0x30E0, + 0xABE1, 0x30E1, 0xABE2, 0x30E2, 0xABE3, 0x30E3, 0xABE4, 0x30E4, 0xABE5, 0x30E5, 0xABE6, 0x30E6, 0xABE7, 0x30E7, 0xABE8, 0x30E8, + 0xABE9, 0x30E9, 0xABEA, 0x30EA, 0xABEB, 0x30EB, 0xABEC, 0x30EC, 0xABED, 0x30ED, 0xABEE, 0x30EE, 0xABEF, 0x30EF, 0xABF0, 0x30F0, + 0xABF1, 0x30F1, 0xABF2, 0x30F2, 0xABF3, 0x30F3, 0xABF4, 0x30F4, 0xABF5, 0x30F5, 0xABF6, 0x30F6, 0xAC41, 0xCCFE, 0xAC42, 0xCCFF, + 0xAC43, 0xCD00, 0xAC44, 0xCD02, 0xAC45, 0xCD03, 0xAC46, 0xCD04, 0xAC47, 0xCD05, 0xAC48, 0xCD06, 0xAC49, 0xCD07, 0xAC4A, 0xCD0A, + 0xAC4B, 0xCD0B, 0xAC4C, 0xCD0D, 0xAC4D, 0xCD0E, 0xAC4E, 0xCD0F, 0xAC4F, 0xCD11, 0xAC50, 0xCD12, 0xAC51, 0xCD13, 0xAC52, 0xCD14, + 0xAC53, 0xCD15, 0xAC54, 0xCD16, 0xAC55, 0xCD17, 0xAC56, 0xCD1A, 0xAC57, 0xCD1C, 0xAC58, 0xCD1E, 0xAC59, 0xCD1F, 0xAC5A, 0xCD20, + 0xAC61, 0xCD21, 0xAC62, 0xCD22, 0xAC63, 0xCD23, 0xAC64, 0xCD25, 0xAC65, 0xCD26, 0xAC66, 0xCD27, 0xAC67, 0xCD29, 0xAC68, 0xCD2A, + 0xAC69, 0xCD2B, 0xAC6A, 0xCD2D, 0xAC6B, 0xCD2E, 0xAC6C, 0xCD2F, 0xAC6D, 0xCD30, 0xAC6E, 0xCD31, 0xAC6F, 0xCD32, 0xAC70, 0xCD33, + 0xAC71, 0xCD34, 0xAC72, 0xCD35, 0xAC73, 0xCD36, 0xAC74, 0xCD37, 0xAC75, 0xCD38, 0xAC76, 0xCD3A, 0xAC77, 0xCD3B, 0xAC78, 0xCD3C, + 0xAC79, 0xCD3D, 0xAC7A, 0xCD3E, 0xAC81, 0xCD3F, 0xAC82, 0xCD40, 0xAC83, 0xCD41, 0xAC84, 0xCD42, 0xAC85, 0xCD43, 0xAC86, 0xCD44, + 0xAC87, 0xCD45, 0xAC88, 0xCD46, 0xAC89, 0xCD47, 0xAC8A, 0xCD48, 0xAC8B, 0xCD49, 0xAC8C, 0xCD4A, 0xAC8D, 0xCD4B, 0xAC8E, 0xCD4C, + 0xAC8F, 0xCD4D, 0xAC90, 0xCD4E, 0xAC91, 0xCD4F, 0xAC92, 0xCD50, 0xAC93, 0xCD51, 0xAC94, 0xCD52, 0xAC95, 0xCD53, 0xAC96, 0xCD54, + 0xAC97, 0xCD55, 0xAC98, 0xCD56, 0xAC99, 0xCD57, 0xAC9A, 0xCD58, 0xAC9B, 0xCD59, 0xAC9C, 0xCD5A, 0xAC9D, 0xCD5B, 0xAC9E, 0xCD5D, + 0xAC9F, 0xCD5E, 0xACA0, 0xCD5F, 0xACA1, 0x0410, 0xACA2, 0x0411, 0xACA3, 0x0412, 0xACA4, 0x0413, 0xACA5, 0x0414, 0xACA6, 0x0415, + 0xACA7, 0x0401, 0xACA8, 0x0416, 0xACA9, 0x0417, 0xACAA, 0x0418, 0xACAB, 0x0419, 0xACAC, 0x041A, 0xACAD, 0x041B, 0xACAE, 0x041C, + 0xACAF, 0x041D, 0xACB0, 0x041E, 0xACB1, 0x041F, 0xACB2, 0x0420, 0xACB3, 0x0421, 0xACB4, 0x0422, 0xACB5, 0x0423, 0xACB6, 0x0424, + 0xACB7, 0x0425, 0xACB8, 0x0426, 0xACB9, 0x0427, 0xACBA, 0x0428, 0xACBB, 0x0429, 0xACBC, 0x042A, 0xACBD, 0x042B, 0xACBE, 0x042C, + 0xACBF, 0x042D, 0xACC0, 0x042E, 0xACC1, 0x042F, 0xACD1, 0x0430, 0xACD2, 0x0431, 0xACD3, 0x0432, 0xACD4, 0x0433, 0xACD5, 0x0434, + 0xACD6, 0x0435, 0xACD7, 0x0451, 0xACD8, 0x0436, 0xACD9, 0x0437, 0xACDA, 0x0438, 0xACDB, 0x0439, 0xACDC, 0x043A, 0xACDD, 0x043B, + 0xACDE, 0x043C, 0xACDF, 0x043D, 0xACE0, 0x043E, 0xACE1, 0x043F, 0xACE2, 0x0440, 0xACE3, 0x0441, 0xACE4, 0x0442, 0xACE5, 0x0443, + 0xACE6, 0x0444, 0xACE7, 0x0445, 0xACE8, 0x0446, 0xACE9, 0x0447, 0xACEA, 0x0448, 0xACEB, 0x0449, 0xACEC, 0x044A, 0xACED, 0x044B, + 0xACEE, 0x044C, 0xACEF, 0x044D, 0xACF0, 0x044E, 0xACF1, 0x044F, 0xAD41, 0xCD61, 0xAD42, 0xCD62, 0xAD43, 0xCD63, 0xAD44, 0xCD65, + 0xAD45, 0xCD66, 0xAD46, 0xCD67, 0xAD47, 0xCD68, 0xAD48, 0xCD69, 0xAD49, 0xCD6A, 0xAD4A, 0xCD6B, 0xAD4B, 0xCD6E, 0xAD4C, 0xCD70, + 0xAD4D, 0xCD72, 0xAD4E, 0xCD73, 0xAD4F, 0xCD74, 0xAD50, 0xCD75, 0xAD51, 0xCD76, 0xAD52, 0xCD77, 0xAD53, 0xCD79, 0xAD54, 0xCD7A, + 0xAD55, 0xCD7B, 0xAD56, 0xCD7C, 0xAD57, 0xCD7D, 0xAD58, 0xCD7E, 0xAD59, 0xCD7F, 0xAD5A, 0xCD80, 0xAD61, 0xCD81, 0xAD62, 0xCD82, + 0xAD63, 0xCD83, 0xAD64, 0xCD84, 0xAD65, 0xCD85, 0xAD66, 0xCD86, 0xAD67, 0xCD87, 0xAD68, 0xCD89, 0xAD69, 0xCD8A, 0xAD6A, 0xCD8B, + 0xAD6B, 0xCD8C, 0xAD6C, 0xCD8D, 0xAD6D, 0xCD8E, 0xAD6E, 0xCD8F, 0xAD6F, 0xCD90, 0xAD70, 0xCD91, 0xAD71, 0xCD92, 0xAD72, 0xCD93, + 0xAD73, 0xCD96, 0xAD74, 0xCD97, 0xAD75, 0xCD99, 0xAD76, 0xCD9A, 0xAD77, 0xCD9B, 0xAD78, 0xCD9D, 0xAD79, 0xCD9E, 0xAD7A, 0xCD9F, + 0xAD81, 0xCDA0, 0xAD82, 0xCDA1, 0xAD83, 0xCDA2, 0xAD84, 0xCDA3, 0xAD85, 0xCDA6, 0xAD86, 0xCDA8, 0xAD87, 0xCDAA, 0xAD88, 0xCDAB, + 0xAD89, 0xCDAC, 0xAD8A, 0xCDAD, 0xAD8B, 0xCDAE, 0xAD8C, 0xCDAF, 0xAD8D, 0xCDB1, 0xAD8E, 0xCDB2, 0xAD8F, 0xCDB3, 0xAD90, 0xCDB4, + 0xAD91, 0xCDB5, 0xAD92, 0xCDB6, 0xAD93, 0xCDB7, 0xAD94, 0xCDB8, 0xAD95, 0xCDB9, 0xAD96, 0xCDBA, 0xAD97, 0xCDBB, 0xAD98, 0xCDBC, + 0xAD99, 0xCDBD, 0xAD9A, 0xCDBE, 0xAD9B, 0xCDBF, 0xAD9C, 0xCDC0, 0xAD9D, 0xCDC1, 0xAD9E, 0xCDC2, 0xAD9F, 0xCDC3, 0xADA0, 0xCDC5, + 0xAE41, 0xCDC6, 0xAE42, 0xCDC7, 0xAE43, 0xCDC8, 0xAE44, 0xCDC9, 0xAE45, 0xCDCA, 0xAE46, 0xCDCB, 0xAE47, 0xCDCD, 0xAE48, 0xCDCE, + 0xAE49, 0xCDCF, 0xAE4A, 0xCDD1, 0xAE4B, 0xCDD2, 0xAE4C, 0xCDD3, 0xAE4D, 0xCDD4, 0xAE4E, 0xCDD5, 0xAE4F, 0xCDD6, 0xAE50, 0xCDD7, + 0xAE51, 0xCDD8, 0xAE52, 0xCDD9, 0xAE53, 0xCDDA, 0xAE54, 0xCDDB, 0xAE55, 0xCDDC, 0xAE56, 0xCDDD, 0xAE57, 0xCDDE, 0xAE58, 0xCDDF, + 0xAE59, 0xCDE0, 0xAE5A, 0xCDE1, 0xAE61, 0xCDE2, 0xAE62, 0xCDE3, 0xAE63, 0xCDE4, 0xAE64, 0xCDE5, 0xAE65, 0xCDE6, 0xAE66, 0xCDE7, + 0xAE67, 0xCDE9, 0xAE68, 0xCDEA, 0xAE69, 0xCDEB, 0xAE6A, 0xCDED, 0xAE6B, 0xCDEE, 0xAE6C, 0xCDEF, 0xAE6D, 0xCDF1, 0xAE6E, 0xCDF2, + 0xAE6F, 0xCDF3, 0xAE70, 0xCDF4, 0xAE71, 0xCDF5, 0xAE72, 0xCDF6, 0xAE73, 0xCDF7, 0xAE74, 0xCDFA, 0xAE75, 0xCDFC, 0xAE76, 0xCDFE, + 0xAE77, 0xCDFF, 0xAE78, 0xCE00, 0xAE79, 0xCE01, 0xAE7A, 0xCE02, 0xAE81, 0xCE03, 0xAE82, 0xCE05, 0xAE83, 0xCE06, 0xAE84, 0xCE07, + 0xAE85, 0xCE09, 0xAE86, 0xCE0A, 0xAE87, 0xCE0B, 0xAE88, 0xCE0D, 0xAE89, 0xCE0E, 0xAE8A, 0xCE0F, 0xAE8B, 0xCE10, 0xAE8C, 0xCE11, + 0xAE8D, 0xCE12, 0xAE8E, 0xCE13, 0xAE8F, 0xCE15, 0xAE90, 0xCE16, 0xAE91, 0xCE17, 0xAE92, 0xCE18, 0xAE93, 0xCE1A, 0xAE94, 0xCE1B, + 0xAE95, 0xCE1C, 0xAE96, 0xCE1D, 0xAE97, 0xCE1E, 0xAE98, 0xCE1F, 0xAE99, 0xCE22, 0xAE9A, 0xCE23, 0xAE9B, 0xCE25, 0xAE9C, 0xCE26, + 0xAE9D, 0xCE27, 0xAE9E, 0xCE29, 0xAE9F, 0xCE2A, 0xAEA0, 0xCE2B, 0xAF41, 0xCE2C, 0xAF42, 0xCE2D, 0xAF43, 0xCE2E, 0xAF44, 0xCE2F, + 0xAF45, 0xCE32, 0xAF46, 0xCE34, 0xAF47, 0xCE36, 0xAF48, 0xCE37, 0xAF49, 0xCE38, 0xAF4A, 0xCE39, 0xAF4B, 0xCE3A, 0xAF4C, 0xCE3B, + 0xAF4D, 0xCE3C, 0xAF4E, 0xCE3D, 0xAF4F, 0xCE3E, 0xAF50, 0xCE3F, 0xAF51, 0xCE40, 0xAF52, 0xCE41, 0xAF53, 0xCE42, 0xAF54, 0xCE43, + 0xAF55, 0xCE44, 0xAF56, 0xCE45, 0xAF57, 0xCE46, 0xAF58, 0xCE47, 0xAF59, 0xCE48, 0xAF5A, 0xCE49, 0xAF61, 0xCE4A, 0xAF62, 0xCE4B, + 0xAF63, 0xCE4C, 0xAF64, 0xCE4D, 0xAF65, 0xCE4E, 0xAF66, 0xCE4F, 0xAF67, 0xCE50, 0xAF68, 0xCE51, 0xAF69, 0xCE52, 0xAF6A, 0xCE53, + 0xAF6B, 0xCE54, 0xAF6C, 0xCE55, 0xAF6D, 0xCE56, 0xAF6E, 0xCE57, 0xAF6F, 0xCE5A, 0xAF70, 0xCE5B, 0xAF71, 0xCE5D, 0xAF72, 0xCE5E, + 0xAF73, 0xCE62, 0xAF74, 0xCE63, 0xAF75, 0xCE64, 0xAF76, 0xCE65, 0xAF77, 0xCE66, 0xAF78, 0xCE67, 0xAF79, 0xCE6A, 0xAF7A, 0xCE6C, + 0xAF81, 0xCE6E, 0xAF82, 0xCE6F, 0xAF83, 0xCE70, 0xAF84, 0xCE71, 0xAF85, 0xCE72, 0xAF86, 0xCE73, 0xAF87, 0xCE76, 0xAF88, 0xCE77, + 0xAF89, 0xCE79, 0xAF8A, 0xCE7A, 0xAF8B, 0xCE7B, 0xAF8C, 0xCE7D, 0xAF8D, 0xCE7E, 0xAF8E, 0xCE7F, 0xAF8F, 0xCE80, 0xAF90, 0xCE81, + 0xAF91, 0xCE82, 0xAF92, 0xCE83, 0xAF93, 0xCE86, 0xAF94, 0xCE88, 0xAF95, 0xCE8A, 0xAF96, 0xCE8B, 0xAF97, 0xCE8C, 0xAF98, 0xCE8D, + 0xAF99, 0xCE8E, 0xAF9A, 0xCE8F, 0xAF9B, 0xCE92, 0xAF9C, 0xCE93, 0xAF9D, 0xCE95, 0xAF9E, 0xCE96, 0xAF9F, 0xCE97, 0xAFA0, 0xCE99, + 0xB041, 0xCE9A, 0xB042, 0xCE9B, 0xB043, 0xCE9C, 0xB044, 0xCE9D, 0xB045, 0xCE9E, 0xB046, 0xCE9F, 0xB047, 0xCEA2, 0xB048, 0xCEA6, + 0xB049, 0xCEA7, 0xB04A, 0xCEA8, 0xB04B, 0xCEA9, 0xB04C, 0xCEAA, 0xB04D, 0xCEAB, 0xB04E, 0xCEAE, 0xB04F, 0xCEAF, 0xB050, 0xCEB0, + 0xB051, 0xCEB1, 0xB052, 0xCEB2, 0xB053, 0xCEB3, 0xB054, 0xCEB4, 0xB055, 0xCEB5, 0xB056, 0xCEB6, 0xB057, 0xCEB7, 0xB058, 0xCEB8, + 0xB059, 0xCEB9, 0xB05A, 0xCEBA, 0xB061, 0xCEBB, 0xB062, 0xCEBC, 0xB063, 0xCEBD, 0xB064, 0xCEBE, 0xB065, 0xCEBF, 0xB066, 0xCEC0, + 0xB067, 0xCEC2, 0xB068, 0xCEC3, 0xB069, 0xCEC4, 0xB06A, 0xCEC5, 0xB06B, 0xCEC6, 0xB06C, 0xCEC7, 0xB06D, 0xCEC8, 0xB06E, 0xCEC9, + 0xB06F, 0xCECA, 0xB070, 0xCECB, 0xB071, 0xCECC, 0xB072, 0xCECD, 0xB073, 0xCECE, 0xB074, 0xCECF, 0xB075, 0xCED0, 0xB076, 0xCED1, + 0xB077, 0xCED2, 0xB078, 0xCED3, 0xB079, 0xCED4, 0xB07A, 0xCED5, 0xB081, 0xCED6, 0xB082, 0xCED7, 0xB083, 0xCED8, 0xB084, 0xCED9, + 0xB085, 0xCEDA, 0xB086, 0xCEDB, 0xB087, 0xCEDC, 0xB088, 0xCEDD, 0xB089, 0xCEDE, 0xB08A, 0xCEDF, 0xB08B, 0xCEE0, 0xB08C, 0xCEE1, + 0xB08D, 0xCEE2, 0xB08E, 0xCEE3, 0xB08F, 0xCEE6, 0xB090, 0xCEE7, 0xB091, 0xCEE9, 0xB092, 0xCEEA, 0xB093, 0xCEED, 0xB094, 0xCEEE, + 0xB095, 0xCEEF, 0xB096, 0xCEF0, 0xB097, 0xCEF1, 0xB098, 0xCEF2, 0xB099, 0xCEF3, 0xB09A, 0xCEF6, 0xB09B, 0xCEFA, 0xB09C, 0xCEFB, + 0xB09D, 0xCEFC, 0xB09E, 0xCEFD, 0xB09F, 0xCEFE, 0xB0A0, 0xCEFF, 0xB0A1, 0xAC00, 0xB0A2, 0xAC01, 0xB0A3, 0xAC04, 0xB0A4, 0xAC07, + 0xB0A5, 0xAC08, 0xB0A6, 0xAC09, 0xB0A7, 0xAC0A, 0xB0A8, 0xAC10, 0xB0A9, 0xAC11, 0xB0AA, 0xAC12, 0xB0AB, 0xAC13, 0xB0AC, 0xAC14, + 0xB0AD, 0xAC15, 0xB0AE, 0xAC16, 0xB0AF, 0xAC17, 0xB0B0, 0xAC19, 0xB0B1, 0xAC1A, 0xB0B2, 0xAC1B, 0xB0B3, 0xAC1C, 0xB0B4, 0xAC1D, + 0xB0B5, 0xAC20, 0xB0B6, 0xAC24, 0xB0B7, 0xAC2C, 0xB0B8, 0xAC2D, 0xB0B9, 0xAC2F, 0xB0BA, 0xAC30, 0xB0BB, 0xAC31, 0xB0BC, 0xAC38, + 0xB0BD, 0xAC39, 0xB0BE, 0xAC3C, 0xB0BF, 0xAC40, 0xB0C0, 0xAC4B, 0xB0C1, 0xAC4D, 0xB0C2, 0xAC54, 0xB0C3, 0xAC58, 0xB0C4, 0xAC5C, + 0xB0C5, 0xAC70, 0xB0C6, 0xAC71, 0xB0C7, 0xAC74, 0xB0C8, 0xAC77, 0xB0C9, 0xAC78, 0xB0CA, 0xAC7A, 0xB0CB, 0xAC80, 0xB0CC, 0xAC81, + 0xB0CD, 0xAC83, 0xB0CE, 0xAC84, 0xB0CF, 0xAC85, 0xB0D0, 0xAC86, 0xB0D1, 0xAC89, 0xB0D2, 0xAC8A, 0xB0D3, 0xAC8B, 0xB0D4, 0xAC8C, + 0xB0D5, 0xAC90, 0xB0D6, 0xAC94, 0xB0D7, 0xAC9C, 0xB0D8, 0xAC9D, 0xB0D9, 0xAC9F, 0xB0DA, 0xACA0, 0xB0DB, 0xACA1, 0xB0DC, 0xACA8, + 0xB0DD, 0xACA9, 0xB0DE, 0xACAA, 0xB0DF, 0xACAC, 0xB0E0, 0xACAF, 0xB0E1, 0xACB0, 0xB0E2, 0xACB8, 0xB0E3, 0xACB9, 0xB0E4, 0xACBB, + 0xB0E5, 0xACBC, 0xB0E6, 0xACBD, 0xB0E7, 0xACC1, 0xB0E8, 0xACC4, 0xB0E9, 0xACC8, 0xB0EA, 0xACCC, 0xB0EB, 0xACD5, 0xB0EC, 0xACD7, + 0xB0ED, 0xACE0, 0xB0EE, 0xACE1, 0xB0EF, 0xACE4, 0xB0F0, 0xACE7, 0xB0F1, 0xACE8, 0xB0F2, 0xACEA, 0xB0F3, 0xACEC, 0xB0F4, 0xACEF, + 0xB0F5, 0xACF0, 0xB0F6, 0xACF1, 0xB0F7, 0xACF3, 0xB0F8, 0xACF5, 0xB0F9, 0xACF6, 0xB0FA, 0xACFC, 0xB0FB, 0xACFD, 0xB0FC, 0xAD00, + 0xB0FD, 0xAD04, 0xB0FE, 0xAD06, 0xB141, 0xCF02, 0xB142, 0xCF03, 0xB143, 0xCF05, 0xB144, 0xCF06, 0xB145, 0xCF07, 0xB146, 0xCF09, + 0xB147, 0xCF0A, 0xB148, 0xCF0B, 0xB149, 0xCF0C, 0xB14A, 0xCF0D, 0xB14B, 0xCF0E, 0xB14C, 0xCF0F, 0xB14D, 0xCF12, 0xB14E, 0xCF14, + 0xB14F, 0xCF16, 0xB150, 0xCF17, 0xB151, 0xCF18, 0xB152, 0xCF19, 0xB153, 0xCF1A, 0xB154, 0xCF1B, 0xB155, 0xCF1D, 0xB156, 0xCF1E, + 0xB157, 0xCF1F, 0xB158, 0xCF21, 0xB159, 0xCF22, 0xB15A, 0xCF23, 0xB161, 0xCF25, 0xB162, 0xCF26, 0xB163, 0xCF27, 0xB164, 0xCF28, + 0xB165, 0xCF29, 0xB166, 0xCF2A, 0xB167, 0xCF2B, 0xB168, 0xCF2E, 0xB169, 0xCF32, 0xB16A, 0xCF33, 0xB16B, 0xCF34, 0xB16C, 0xCF35, + 0xB16D, 0xCF36, 0xB16E, 0xCF37, 0xB16F, 0xCF39, 0xB170, 0xCF3A, 0xB171, 0xCF3B, 0xB172, 0xCF3C, 0xB173, 0xCF3D, 0xB174, 0xCF3E, + 0xB175, 0xCF3F, 0xB176, 0xCF40, 0xB177, 0xCF41, 0xB178, 0xCF42, 0xB179, 0xCF43, 0xB17A, 0xCF44, 0xB181, 0xCF45, 0xB182, 0xCF46, + 0xB183, 0xCF47, 0xB184, 0xCF48, 0xB185, 0xCF49, 0xB186, 0xCF4A, 0xB187, 0xCF4B, 0xB188, 0xCF4C, 0xB189, 0xCF4D, 0xB18A, 0xCF4E, + 0xB18B, 0xCF4F, 0xB18C, 0xCF50, 0xB18D, 0xCF51, 0xB18E, 0xCF52, 0xB18F, 0xCF53, 0xB190, 0xCF56, 0xB191, 0xCF57, 0xB192, 0xCF59, + 0xB193, 0xCF5A, 0xB194, 0xCF5B, 0xB195, 0xCF5D, 0xB196, 0xCF5E, 0xB197, 0xCF5F, 0xB198, 0xCF60, 0xB199, 0xCF61, 0xB19A, 0xCF62, + 0xB19B, 0xCF63, 0xB19C, 0xCF66, 0xB19D, 0xCF68, 0xB19E, 0xCF6A, 0xB19F, 0xCF6B, 0xB1A0, 0xCF6C, 0xB1A1, 0xAD0C, 0xB1A2, 0xAD0D, + 0xB1A3, 0xAD0F, 0xB1A4, 0xAD11, 0xB1A5, 0xAD18, 0xB1A6, 0xAD1C, 0xB1A7, 0xAD20, 0xB1A8, 0xAD29, 0xB1A9, 0xAD2C, 0xB1AA, 0xAD2D, + 0xB1AB, 0xAD34, 0xB1AC, 0xAD35, 0xB1AD, 0xAD38, 0xB1AE, 0xAD3C, 0xB1AF, 0xAD44, 0xB1B0, 0xAD45, 0xB1B1, 0xAD47, 0xB1B2, 0xAD49, + 0xB1B3, 0xAD50, 0xB1B4, 0xAD54, 0xB1B5, 0xAD58, 0xB1B6, 0xAD61, 0xB1B7, 0xAD63, 0xB1B8, 0xAD6C, 0xB1B9, 0xAD6D, 0xB1BA, 0xAD70, + 0xB1BB, 0xAD73, 0xB1BC, 0xAD74, 0xB1BD, 0xAD75, 0xB1BE, 0xAD76, 0xB1BF, 0xAD7B, 0xB1C0, 0xAD7C, 0xB1C1, 0xAD7D, 0xB1C2, 0xAD7F, + 0xB1C3, 0xAD81, 0xB1C4, 0xAD82, 0xB1C5, 0xAD88, 0xB1C6, 0xAD89, 0xB1C7, 0xAD8C, 0xB1C8, 0xAD90, 0xB1C9, 0xAD9C, 0xB1CA, 0xAD9D, + 0xB1CB, 0xADA4, 0xB1CC, 0xADB7, 0xB1CD, 0xADC0, 0xB1CE, 0xADC1, 0xB1CF, 0xADC4, 0xB1D0, 0xADC8, 0xB1D1, 0xADD0, 0xB1D2, 0xADD1, + 0xB1D3, 0xADD3, 0xB1D4, 0xADDC, 0xB1D5, 0xADE0, 0xB1D6, 0xADE4, 0xB1D7, 0xADF8, 0xB1D8, 0xADF9, 0xB1D9, 0xADFC, 0xB1DA, 0xADFF, + 0xB1DB, 0xAE00, 0xB1DC, 0xAE01, 0xB1DD, 0xAE08, 0xB1DE, 0xAE09, 0xB1DF, 0xAE0B, 0xB1E0, 0xAE0D, 0xB1E1, 0xAE14, 0xB1E2, 0xAE30, + 0xB1E3, 0xAE31, 0xB1E4, 0xAE34, 0xB1E5, 0xAE37, 0xB1E6, 0xAE38, 0xB1E7, 0xAE3A, 0xB1E8, 0xAE40, 0xB1E9, 0xAE41, 0xB1EA, 0xAE43, + 0xB1EB, 0xAE45, 0xB1EC, 0xAE46, 0xB1ED, 0xAE4A, 0xB1EE, 0xAE4C, 0xB1EF, 0xAE4D, 0xB1F0, 0xAE4E, 0xB1F1, 0xAE50, 0xB1F2, 0xAE54, + 0xB1F3, 0xAE56, 0xB1F4, 0xAE5C, 0xB1F5, 0xAE5D, 0xB1F6, 0xAE5F, 0xB1F7, 0xAE60, 0xB1F8, 0xAE61, 0xB1F9, 0xAE65, 0xB1FA, 0xAE68, + 0xB1FB, 0xAE69, 0xB1FC, 0xAE6C, 0xB1FD, 0xAE70, 0xB1FE, 0xAE78, 0xB241, 0xCF6D, 0xB242, 0xCF6E, 0xB243, 0xCF6F, 0xB244, 0xCF72, + 0xB245, 0xCF73, 0xB246, 0xCF75, 0xB247, 0xCF76, 0xB248, 0xCF77, 0xB249, 0xCF79, 0xB24A, 0xCF7A, 0xB24B, 0xCF7B, 0xB24C, 0xCF7C, + 0xB24D, 0xCF7D, 0xB24E, 0xCF7E, 0xB24F, 0xCF7F, 0xB250, 0xCF81, 0xB251, 0xCF82, 0xB252, 0xCF83, 0xB253, 0xCF84, 0xB254, 0xCF86, + 0xB255, 0xCF87, 0xB256, 0xCF88, 0xB257, 0xCF89, 0xB258, 0xCF8A, 0xB259, 0xCF8B, 0xB25A, 0xCF8D, 0xB261, 0xCF8E, 0xB262, 0xCF8F, + 0xB263, 0xCF90, 0xB264, 0xCF91, 0xB265, 0xCF92, 0xB266, 0xCF93, 0xB267, 0xCF94, 0xB268, 0xCF95, 0xB269, 0xCF96, 0xB26A, 0xCF97, + 0xB26B, 0xCF98, 0xB26C, 0xCF99, 0xB26D, 0xCF9A, 0xB26E, 0xCF9B, 0xB26F, 0xCF9C, 0xB270, 0xCF9D, 0xB271, 0xCF9E, 0xB272, 0xCF9F, + 0xB273, 0xCFA0, 0xB274, 0xCFA2, 0xB275, 0xCFA3, 0xB276, 0xCFA4, 0xB277, 0xCFA5, 0xB278, 0xCFA6, 0xB279, 0xCFA7, 0xB27A, 0xCFA9, + 0xB281, 0xCFAA, 0xB282, 0xCFAB, 0xB283, 0xCFAC, 0xB284, 0xCFAD, 0xB285, 0xCFAE, 0xB286, 0xCFAF, 0xB287, 0xCFB1, 0xB288, 0xCFB2, + 0xB289, 0xCFB3, 0xB28A, 0xCFB4, 0xB28B, 0xCFB5, 0xB28C, 0xCFB6, 0xB28D, 0xCFB7, 0xB28E, 0xCFB8, 0xB28F, 0xCFB9, 0xB290, 0xCFBA, + 0xB291, 0xCFBB, 0xB292, 0xCFBC, 0xB293, 0xCFBD, 0xB294, 0xCFBE, 0xB295, 0xCFBF, 0xB296, 0xCFC0, 0xB297, 0xCFC1, 0xB298, 0xCFC2, + 0xB299, 0xCFC3, 0xB29A, 0xCFC5, 0xB29B, 0xCFC6, 0xB29C, 0xCFC7, 0xB29D, 0xCFC8, 0xB29E, 0xCFC9, 0xB29F, 0xCFCA, 0xB2A0, 0xCFCB, + 0xB2A1, 0xAE79, 0xB2A2, 0xAE7B, 0xB2A3, 0xAE7C, 0xB2A4, 0xAE7D, 0xB2A5, 0xAE84, 0xB2A6, 0xAE85, 0xB2A7, 0xAE8C, 0xB2A8, 0xAEBC, + 0xB2A9, 0xAEBD, 0xB2AA, 0xAEBE, 0xB2AB, 0xAEC0, 0xB2AC, 0xAEC4, 0xB2AD, 0xAECC, 0xB2AE, 0xAECD, 0xB2AF, 0xAECF, 0xB2B0, 0xAED0, + 0xB2B1, 0xAED1, 0xB2B2, 0xAED8, 0xB2B3, 0xAED9, 0xB2B4, 0xAEDC, 0xB2B5, 0xAEE8, 0xB2B6, 0xAEEB, 0xB2B7, 0xAEED, 0xB2B8, 0xAEF4, + 0xB2B9, 0xAEF8, 0xB2BA, 0xAEFC, 0xB2BB, 0xAF07, 0xB2BC, 0xAF08, 0xB2BD, 0xAF0D, 0xB2BE, 0xAF10, 0xB2BF, 0xAF2C, 0xB2C0, 0xAF2D, + 0xB2C1, 0xAF30, 0xB2C2, 0xAF32, 0xB2C3, 0xAF34, 0xB2C4, 0xAF3C, 0xB2C5, 0xAF3D, 0xB2C6, 0xAF3F, 0xB2C7, 0xAF41, 0xB2C8, 0xAF42, + 0xB2C9, 0xAF43, 0xB2CA, 0xAF48, 0xB2CB, 0xAF49, 0xB2CC, 0xAF50, 0xB2CD, 0xAF5C, 0xB2CE, 0xAF5D, 0xB2CF, 0xAF64, 0xB2D0, 0xAF65, + 0xB2D1, 0xAF79, 0xB2D2, 0xAF80, 0xB2D3, 0xAF84, 0xB2D4, 0xAF88, 0xB2D5, 0xAF90, 0xB2D6, 0xAF91, 0xB2D7, 0xAF95, 0xB2D8, 0xAF9C, + 0xB2D9, 0xAFB8, 0xB2DA, 0xAFB9, 0xB2DB, 0xAFBC, 0xB2DC, 0xAFC0, 0xB2DD, 0xAFC7, 0xB2DE, 0xAFC8, 0xB2DF, 0xAFC9, 0xB2E0, 0xAFCB, + 0xB2E1, 0xAFCD, 0xB2E2, 0xAFCE, 0xB2E3, 0xAFD4, 0xB2E4, 0xAFDC, 0xB2E5, 0xAFE8, 0xB2E6, 0xAFE9, 0xB2E7, 0xAFF0, 0xB2E8, 0xAFF1, + 0xB2E9, 0xAFF4, 0xB2EA, 0xAFF8, 0xB2EB, 0xB000, 0xB2EC, 0xB001, 0xB2ED, 0xB004, 0xB2EE, 0xB00C, 0xB2EF, 0xB010, 0xB2F0, 0xB014, + 0xB2F1, 0xB01C, 0xB2F2, 0xB01D, 0xB2F3, 0xB028, 0xB2F4, 0xB044, 0xB2F5, 0xB045, 0xB2F6, 0xB048, 0xB2F7, 0xB04A, 0xB2F8, 0xB04C, + 0xB2F9, 0xB04E, 0xB2FA, 0xB053, 0xB2FB, 0xB054, 0xB2FC, 0xB055, 0xB2FD, 0xB057, 0xB2FE, 0xB059, 0xB341, 0xCFCC, 0xB342, 0xCFCD, + 0xB343, 0xCFCE, 0xB344, 0xCFCF, 0xB345, 0xCFD0, 0xB346, 0xCFD1, 0xB347, 0xCFD2, 0xB348, 0xCFD3, 0xB349, 0xCFD4, 0xB34A, 0xCFD5, + 0xB34B, 0xCFD6, 0xB34C, 0xCFD7, 0xB34D, 0xCFD8, 0xB34E, 0xCFD9, 0xB34F, 0xCFDA, 0xB350, 0xCFDB, 0xB351, 0xCFDC, 0xB352, 0xCFDD, + 0xB353, 0xCFDE, 0xB354, 0xCFDF, 0xB355, 0xCFE2, 0xB356, 0xCFE3, 0xB357, 0xCFE5, 0xB358, 0xCFE6, 0xB359, 0xCFE7, 0xB35A, 0xCFE9, + 0xB361, 0xCFEA, 0xB362, 0xCFEB, 0xB363, 0xCFEC, 0xB364, 0xCFED, 0xB365, 0xCFEE, 0xB366, 0xCFEF, 0xB367, 0xCFF2, 0xB368, 0xCFF4, + 0xB369, 0xCFF6, 0xB36A, 0xCFF7, 0xB36B, 0xCFF8, 0xB36C, 0xCFF9, 0xB36D, 0xCFFA, 0xB36E, 0xCFFB, 0xB36F, 0xCFFD, 0xB370, 0xCFFE, + 0xB371, 0xCFFF, 0xB372, 0xD001, 0xB373, 0xD002, 0xB374, 0xD003, 0xB375, 0xD005, 0xB376, 0xD006, 0xB377, 0xD007, 0xB378, 0xD008, + 0xB379, 0xD009, 0xB37A, 0xD00A, 0xB381, 0xD00B, 0xB382, 0xD00C, 0xB383, 0xD00D, 0xB384, 0xD00E, 0xB385, 0xD00F, 0xB386, 0xD010, + 0xB387, 0xD012, 0xB388, 0xD013, 0xB389, 0xD014, 0xB38A, 0xD015, 0xB38B, 0xD016, 0xB38C, 0xD017, 0xB38D, 0xD019, 0xB38E, 0xD01A, + 0xB38F, 0xD01B, 0xB390, 0xD01C, 0xB391, 0xD01D, 0xB392, 0xD01E, 0xB393, 0xD01F, 0xB394, 0xD020, 0xB395, 0xD021, 0xB396, 0xD022, + 0xB397, 0xD023, 0xB398, 0xD024, 0xB399, 0xD025, 0xB39A, 0xD026, 0xB39B, 0xD027, 0xB39C, 0xD028, 0xB39D, 0xD029, 0xB39E, 0xD02A, + 0xB39F, 0xD02B, 0xB3A0, 0xD02C, 0xB3A1, 0xB05D, 0xB3A2, 0xB07C, 0xB3A3, 0xB07D, 0xB3A4, 0xB080, 0xB3A5, 0xB084, 0xB3A6, 0xB08C, + 0xB3A7, 0xB08D, 0xB3A8, 0xB08F, 0xB3A9, 0xB091, 0xB3AA, 0xB098, 0xB3AB, 0xB099, 0xB3AC, 0xB09A, 0xB3AD, 0xB09C, 0xB3AE, 0xB09F, + 0xB3AF, 0xB0A0, 0xB3B0, 0xB0A1, 0xB3B1, 0xB0A2, 0xB3B2, 0xB0A8, 0xB3B3, 0xB0A9, 0xB3B4, 0xB0AB, 0xB3B5, 0xB0AC, 0xB3B6, 0xB0AD, + 0xB3B7, 0xB0AE, 0xB3B8, 0xB0AF, 0xB3B9, 0xB0B1, 0xB3BA, 0xB0B3, 0xB3BB, 0xB0B4, 0xB3BC, 0xB0B5, 0xB3BD, 0xB0B8, 0xB3BE, 0xB0BC, + 0xB3BF, 0xB0C4, 0xB3C0, 0xB0C5, 0xB3C1, 0xB0C7, 0xB3C2, 0xB0C8, 0xB3C3, 0xB0C9, 0xB3C4, 0xB0D0, 0xB3C5, 0xB0D1, 0xB3C6, 0xB0D4, + 0xB3C7, 0xB0D8, 0xB3C8, 0xB0E0, 0xB3C9, 0xB0E5, 0xB3CA, 0xB108, 0xB3CB, 0xB109, 0xB3CC, 0xB10B, 0xB3CD, 0xB10C, 0xB3CE, 0xB110, + 0xB3CF, 0xB112, 0xB3D0, 0xB113, 0xB3D1, 0xB118, 0xB3D2, 0xB119, 0xB3D3, 0xB11B, 0xB3D4, 0xB11C, 0xB3D5, 0xB11D, 0xB3D6, 0xB123, + 0xB3D7, 0xB124, 0xB3D8, 0xB125, 0xB3D9, 0xB128, 0xB3DA, 0xB12C, 0xB3DB, 0xB134, 0xB3DC, 0xB135, 0xB3DD, 0xB137, 0xB3DE, 0xB138, + 0xB3DF, 0xB139, 0xB3E0, 0xB140, 0xB3E1, 0xB141, 0xB3E2, 0xB144, 0xB3E3, 0xB148, 0xB3E4, 0xB150, 0xB3E5, 0xB151, 0xB3E6, 0xB154, + 0xB3E7, 0xB155, 0xB3E8, 0xB158, 0xB3E9, 0xB15C, 0xB3EA, 0xB160, 0xB3EB, 0xB178, 0xB3EC, 0xB179, 0xB3ED, 0xB17C, 0xB3EE, 0xB180, + 0xB3EF, 0xB182, 0xB3F0, 0xB188, 0xB3F1, 0xB189, 0xB3F2, 0xB18B, 0xB3F3, 0xB18D, 0xB3F4, 0xB192, 0xB3F5, 0xB193, 0xB3F6, 0xB194, + 0xB3F7, 0xB198, 0xB3F8, 0xB19C, 0xB3F9, 0xB1A8, 0xB3FA, 0xB1CC, 0xB3FB, 0xB1D0, 0xB3FC, 0xB1D4, 0xB3FD, 0xB1DC, 0xB3FE, 0xB1DD, + 0xB441, 0xD02E, 0xB442, 0xD02F, 0xB443, 0xD030, 0xB444, 0xD031, 0xB445, 0xD032, 0xB446, 0xD033, 0xB447, 0xD036, 0xB448, 0xD037, + 0xB449, 0xD039, 0xB44A, 0xD03A, 0xB44B, 0xD03B, 0xB44C, 0xD03D, 0xB44D, 0xD03E, 0xB44E, 0xD03F, 0xB44F, 0xD040, 0xB450, 0xD041, + 0xB451, 0xD042, 0xB452, 0xD043, 0xB453, 0xD046, 0xB454, 0xD048, 0xB455, 0xD04A, 0xB456, 0xD04B, 0xB457, 0xD04C, 0xB458, 0xD04D, + 0xB459, 0xD04E, 0xB45A, 0xD04F, 0xB461, 0xD051, 0xB462, 0xD052, 0xB463, 0xD053, 0xB464, 0xD055, 0xB465, 0xD056, 0xB466, 0xD057, + 0xB467, 0xD059, 0xB468, 0xD05A, 0xB469, 0xD05B, 0xB46A, 0xD05C, 0xB46B, 0xD05D, 0xB46C, 0xD05E, 0xB46D, 0xD05F, 0xB46E, 0xD061, + 0xB46F, 0xD062, 0xB470, 0xD063, 0xB471, 0xD064, 0xB472, 0xD065, 0xB473, 0xD066, 0xB474, 0xD067, 0xB475, 0xD068, 0xB476, 0xD069, + 0xB477, 0xD06A, 0xB478, 0xD06B, 0xB479, 0xD06E, 0xB47A, 0xD06F, 0xB481, 0xD071, 0xB482, 0xD072, 0xB483, 0xD073, 0xB484, 0xD075, + 0xB485, 0xD076, 0xB486, 0xD077, 0xB487, 0xD078, 0xB488, 0xD079, 0xB489, 0xD07A, 0xB48A, 0xD07B, 0xB48B, 0xD07E, 0xB48C, 0xD07F, + 0xB48D, 0xD080, 0xB48E, 0xD082, 0xB48F, 0xD083, 0xB490, 0xD084, 0xB491, 0xD085, 0xB492, 0xD086, 0xB493, 0xD087, 0xB494, 0xD088, + 0xB495, 0xD089, 0xB496, 0xD08A, 0xB497, 0xD08B, 0xB498, 0xD08C, 0xB499, 0xD08D, 0xB49A, 0xD08E, 0xB49B, 0xD08F, 0xB49C, 0xD090, + 0xB49D, 0xD091, 0xB49E, 0xD092, 0xB49F, 0xD093, 0xB4A0, 0xD094, 0xB4A1, 0xB1DF, 0xB4A2, 0xB1E8, 0xB4A3, 0xB1E9, 0xB4A4, 0xB1EC, + 0xB4A5, 0xB1F0, 0xB4A6, 0xB1F9, 0xB4A7, 0xB1FB, 0xB4A8, 0xB1FD, 0xB4A9, 0xB204, 0xB4AA, 0xB205, 0xB4AB, 0xB208, 0xB4AC, 0xB20B, + 0xB4AD, 0xB20C, 0xB4AE, 0xB214, 0xB4AF, 0xB215, 0xB4B0, 0xB217, 0xB4B1, 0xB219, 0xB4B2, 0xB220, 0xB4B3, 0xB234, 0xB4B4, 0xB23C, + 0xB4B5, 0xB258, 0xB4B6, 0xB25C, 0xB4B7, 0xB260, 0xB4B8, 0xB268, 0xB4B9, 0xB269, 0xB4BA, 0xB274, 0xB4BB, 0xB275, 0xB4BC, 0xB27C, + 0xB4BD, 0xB284, 0xB4BE, 0xB285, 0xB4BF, 0xB289, 0xB4C0, 0xB290, 0xB4C1, 0xB291, 0xB4C2, 0xB294, 0xB4C3, 0xB298, 0xB4C4, 0xB299, + 0xB4C5, 0xB29A, 0xB4C6, 0xB2A0, 0xB4C7, 0xB2A1, 0xB4C8, 0xB2A3, 0xB4C9, 0xB2A5, 0xB4CA, 0xB2A6, 0xB4CB, 0xB2AA, 0xB4CC, 0xB2AC, + 0xB4CD, 0xB2B0, 0xB4CE, 0xB2B4, 0xB4CF, 0xB2C8, 0xB4D0, 0xB2C9, 0xB4D1, 0xB2CC, 0xB4D2, 0xB2D0, 0xB4D3, 0xB2D2, 0xB4D4, 0xB2D8, + 0xB4D5, 0xB2D9, 0xB4D6, 0xB2DB, 0xB4D7, 0xB2DD, 0xB4D8, 0xB2E2, 0xB4D9, 0xB2E4, 0xB4DA, 0xB2E5, 0xB4DB, 0xB2E6, 0xB4DC, 0xB2E8, + 0xB4DD, 0xB2EB, 0xB4DE, 0xB2EC, 0xB4DF, 0xB2ED, 0xB4E0, 0xB2EE, 0xB4E1, 0xB2EF, 0xB4E2, 0xB2F3, 0xB4E3, 0xB2F4, 0xB4E4, 0xB2F5, + 0xB4E5, 0xB2F7, 0xB4E6, 0xB2F8, 0xB4E7, 0xB2F9, 0xB4E8, 0xB2FA, 0xB4E9, 0xB2FB, 0xB4EA, 0xB2FF, 0xB4EB, 0xB300, 0xB4EC, 0xB301, + 0xB4ED, 0xB304, 0xB4EE, 0xB308, 0xB4EF, 0xB310, 0xB4F0, 0xB311, 0xB4F1, 0xB313, 0xB4F2, 0xB314, 0xB4F3, 0xB315, 0xB4F4, 0xB31C, + 0xB4F5, 0xB354, 0xB4F6, 0xB355, 0xB4F7, 0xB356, 0xB4F8, 0xB358, 0xB4F9, 0xB35B, 0xB4FA, 0xB35C, 0xB4FB, 0xB35E, 0xB4FC, 0xB35F, + 0xB4FD, 0xB364, 0xB4FE, 0xB365, 0xB541, 0xD095, 0xB542, 0xD096, 0xB543, 0xD097, 0xB544, 0xD098, 0xB545, 0xD099, 0xB546, 0xD09A, + 0xB547, 0xD09B, 0xB548, 0xD09C, 0xB549, 0xD09D, 0xB54A, 0xD09E, 0xB54B, 0xD09F, 0xB54C, 0xD0A0, 0xB54D, 0xD0A1, 0xB54E, 0xD0A2, + 0xB54F, 0xD0A3, 0xB550, 0xD0A6, 0xB551, 0xD0A7, 0xB552, 0xD0A9, 0xB553, 0xD0AA, 0xB554, 0xD0AB, 0xB555, 0xD0AD, 0xB556, 0xD0AE, + 0xB557, 0xD0AF, 0xB558, 0xD0B0, 0xB559, 0xD0B1, 0xB55A, 0xD0B2, 0xB561, 0xD0B3, 0xB562, 0xD0B6, 0xB563, 0xD0B8, 0xB564, 0xD0BA, + 0xB565, 0xD0BB, 0xB566, 0xD0BC, 0xB567, 0xD0BD, 0xB568, 0xD0BE, 0xB569, 0xD0BF, 0xB56A, 0xD0C2, 0xB56B, 0xD0C3, 0xB56C, 0xD0C5, + 0xB56D, 0xD0C6, 0xB56E, 0xD0C7, 0xB56F, 0xD0CA, 0xB570, 0xD0CB, 0xB571, 0xD0CC, 0xB572, 0xD0CD, 0xB573, 0xD0CE, 0xB574, 0xD0CF, + 0xB575, 0xD0D2, 0xB576, 0xD0D6, 0xB577, 0xD0D7, 0xB578, 0xD0D8, 0xB579, 0xD0D9, 0xB57A, 0xD0DA, 0xB581, 0xD0DB, 0xB582, 0xD0DE, + 0xB583, 0xD0DF, 0xB584, 0xD0E1, 0xB585, 0xD0E2, 0xB586, 0xD0E3, 0xB587, 0xD0E5, 0xB588, 0xD0E6, 0xB589, 0xD0E7, 0xB58A, 0xD0E8, + 0xB58B, 0xD0E9, 0xB58C, 0xD0EA, 0xB58D, 0xD0EB, 0xB58E, 0xD0EE, 0xB58F, 0xD0F2, 0xB590, 0xD0F3, 0xB591, 0xD0F4, 0xB592, 0xD0F5, + 0xB593, 0xD0F6, 0xB594, 0xD0F7, 0xB595, 0xD0F9, 0xB596, 0xD0FA, 0xB597, 0xD0FB, 0xB598, 0xD0FC, 0xB599, 0xD0FD, 0xB59A, 0xD0FE, + 0xB59B, 0xD0FF, 0xB59C, 0xD100, 0xB59D, 0xD101, 0xB59E, 0xD102, 0xB59F, 0xD103, 0xB5A0, 0xD104, 0xB5A1, 0xB367, 0xB5A2, 0xB369, + 0xB5A3, 0xB36B, 0xB5A4, 0xB36E, 0xB5A5, 0xB370, 0xB5A6, 0xB371, 0xB5A7, 0xB374, 0xB5A8, 0xB378, 0xB5A9, 0xB380, 0xB5AA, 0xB381, + 0xB5AB, 0xB383, 0xB5AC, 0xB384, 0xB5AD, 0xB385, 0xB5AE, 0xB38C, 0xB5AF, 0xB390, 0xB5B0, 0xB394, 0xB5B1, 0xB3A0, 0xB5B2, 0xB3A1, + 0xB5B3, 0xB3A8, 0xB5B4, 0xB3AC, 0xB5B5, 0xB3C4, 0xB5B6, 0xB3C5, 0xB5B7, 0xB3C8, 0xB5B8, 0xB3CB, 0xB5B9, 0xB3CC, 0xB5BA, 0xB3CE, + 0xB5BB, 0xB3D0, 0xB5BC, 0xB3D4, 0xB5BD, 0xB3D5, 0xB5BE, 0xB3D7, 0xB5BF, 0xB3D9, 0xB5C0, 0xB3DB, 0xB5C1, 0xB3DD, 0xB5C2, 0xB3E0, + 0xB5C3, 0xB3E4, 0xB5C4, 0xB3E8, 0xB5C5, 0xB3FC, 0xB5C6, 0xB410, 0xB5C7, 0xB418, 0xB5C8, 0xB41C, 0xB5C9, 0xB420, 0xB5CA, 0xB428, + 0xB5CB, 0xB429, 0xB5CC, 0xB42B, 0xB5CD, 0xB434, 0xB5CE, 0xB450, 0xB5CF, 0xB451, 0xB5D0, 0xB454, 0xB5D1, 0xB458, 0xB5D2, 0xB460, + 0xB5D3, 0xB461, 0xB5D4, 0xB463, 0xB5D5, 0xB465, 0xB5D6, 0xB46C, 0xB5D7, 0xB480, 0xB5D8, 0xB488, 0xB5D9, 0xB49D, 0xB5DA, 0xB4A4, + 0xB5DB, 0xB4A8, 0xB5DC, 0xB4AC, 0xB5DD, 0xB4B5, 0xB5DE, 0xB4B7, 0xB5DF, 0xB4B9, 0xB5E0, 0xB4C0, 0xB5E1, 0xB4C4, 0xB5E2, 0xB4C8, + 0xB5E3, 0xB4D0, 0xB5E4, 0xB4D5, 0xB5E5, 0xB4DC, 0xB5E6, 0xB4DD, 0xB5E7, 0xB4E0, 0xB5E8, 0xB4E3, 0xB5E9, 0xB4E4, 0xB5EA, 0xB4E6, + 0xB5EB, 0xB4EC, 0xB5EC, 0xB4ED, 0xB5ED, 0xB4EF, 0xB5EE, 0xB4F1, 0xB5EF, 0xB4F8, 0xB5F0, 0xB514, 0xB5F1, 0xB515, 0xB5F2, 0xB518, + 0xB5F3, 0xB51B, 0xB5F4, 0xB51C, 0xB5F5, 0xB524, 0xB5F6, 0xB525, 0xB5F7, 0xB527, 0xB5F8, 0xB528, 0xB5F9, 0xB529, 0xB5FA, 0xB52A, + 0xB5FB, 0xB530, 0xB5FC, 0xB531, 0xB5FD, 0xB534, 0xB5FE, 0xB538, 0xB641, 0xD105, 0xB642, 0xD106, 0xB643, 0xD107, 0xB644, 0xD108, + 0xB645, 0xD109, 0xB646, 0xD10A, 0xB647, 0xD10B, 0xB648, 0xD10C, 0xB649, 0xD10E, 0xB64A, 0xD10F, 0xB64B, 0xD110, 0xB64C, 0xD111, + 0xB64D, 0xD112, 0xB64E, 0xD113, 0xB64F, 0xD114, 0xB650, 0xD115, 0xB651, 0xD116, 0xB652, 0xD117, 0xB653, 0xD118, 0xB654, 0xD119, + 0xB655, 0xD11A, 0xB656, 0xD11B, 0xB657, 0xD11C, 0xB658, 0xD11D, 0xB659, 0xD11E, 0xB65A, 0xD11F, 0xB661, 0xD120, 0xB662, 0xD121, + 0xB663, 0xD122, 0xB664, 0xD123, 0xB665, 0xD124, 0xB666, 0xD125, 0xB667, 0xD126, 0xB668, 0xD127, 0xB669, 0xD128, 0xB66A, 0xD129, + 0xB66B, 0xD12A, 0xB66C, 0xD12B, 0xB66D, 0xD12C, 0xB66E, 0xD12D, 0xB66F, 0xD12E, 0xB670, 0xD12F, 0xB671, 0xD132, 0xB672, 0xD133, + 0xB673, 0xD135, 0xB674, 0xD136, 0xB675, 0xD137, 0xB676, 0xD139, 0xB677, 0xD13B, 0xB678, 0xD13C, 0xB679, 0xD13D, 0xB67A, 0xD13E, + 0xB681, 0xD13F, 0xB682, 0xD142, 0xB683, 0xD146, 0xB684, 0xD147, 0xB685, 0xD148, 0xB686, 0xD149, 0xB687, 0xD14A, 0xB688, 0xD14B, + 0xB689, 0xD14E, 0xB68A, 0xD14F, 0xB68B, 0xD151, 0xB68C, 0xD152, 0xB68D, 0xD153, 0xB68E, 0xD155, 0xB68F, 0xD156, 0xB690, 0xD157, + 0xB691, 0xD158, 0xB692, 0xD159, 0xB693, 0xD15A, 0xB694, 0xD15B, 0xB695, 0xD15E, 0xB696, 0xD160, 0xB697, 0xD162, 0xB698, 0xD163, + 0xB699, 0xD164, 0xB69A, 0xD165, 0xB69B, 0xD166, 0xB69C, 0xD167, 0xB69D, 0xD169, 0xB69E, 0xD16A, 0xB69F, 0xD16B, 0xB6A0, 0xD16D, + 0xB6A1, 0xB540, 0xB6A2, 0xB541, 0xB6A3, 0xB543, 0xB6A4, 0xB544, 0xB6A5, 0xB545, 0xB6A6, 0xB54B, 0xB6A7, 0xB54C, 0xB6A8, 0xB54D, + 0xB6A9, 0xB550, 0xB6AA, 0xB554, 0xB6AB, 0xB55C, 0xB6AC, 0xB55D, 0xB6AD, 0xB55F, 0xB6AE, 0xB560, 0xB6AF, 0xB561, 0xB6B0, 0xB5A0, + 0xB6B1, 0xB5A1, 0xB6B2, 0xB5A4, 0xB6B3, 0xB5A8, 0xB6B4, 0xB5AA, 0xB6B5, 0xB5AB, 0xB6B6, 0xB5B0, 0xB6B7, 0xB5B1, 0xB6B8, 0xB5B3, + 0xB6B9, 0xB5B4, 0xB6BA, 0xB5B5, 0xB6BB, 0xB5BB, 0xB6BC, 0xB5BC, 0xB6BD, 0xB5BD, 0xB6BE, 0xB5C0, 0xB6BF, 0xB5C4, 0xB6C0, 0xB5CC, + 0xB6C1, 0xB5CD, 0xB6C2, 0xB5CF, 0xB6C3, 0xB5D0, 0xB6C4, 0xB5D1, 0xB6C5, 0xB5D8, 0xB6C6, 0xB5EC, 0xB6C7, 0xB610, 0xB6C8, 0xB611, + 0xB6C9, 0xB614, 0xB6CA, 0xB618, 0xB6CB, 0xB625, 0xB6CC, 0xB62C, 0xB6CD, 0xB634, 0xB6CE, 0xB648, 0xB6CF, 0xB664, 0xB6D0, 0xB668, + 0xB6D1, 0xB69C, 0xB6D2, 0xB69D, 0xB6D3, 0xB6A0, 0xB6D4, 0xB6A4, 0xB6D5, 0xB6AB, 0xB6D6, 0xB6AC, 0xB6D7, 0xB6B1, 0xB6D8, 0xB6D4, + 0xB6D9, 0xB6F0, 0xB6DA, 0xB6F4, 0xB6DB, 0xB6F8, 0xB6DC, 0xB700, 0xB6DD, 0xB701, 0xB6DE, 0xB705, 0xB6DF, 0xB728, 0xB6E0, 0xB729, + 0xB6E1, 0xB72C, 0xB6E2, 0xB72F, 0xB6E3, 0xB730, 0xB6E4, 0xB738, 0xB6E5, 0xB739, 0xB6E6, 0xB73B, 0xB6E7, 0xB744, 0xB6E8, 0xB748, + 0xB6E9, 0xB74C, 0xB6EA, 0xB754, 0xB6EB, 0xB755, 0xB6EC, 0xB760, 0xB6ED, 0xB764, 0xB6EE, 0xB768, 0xB6EF, 0xB770, 0xB6F0, 0xB771, + 0xB6F1, 0xB773, 0xB6F2, 0xB775, 0xB6F3, 0xB77C, 0xB6F4, 0xB77D, 0xB6F5, 0xB780, 0xB6F6, 0xB784, 0xB6F7, 0xB78C, 0xB6F8, 0xB78D, + 0xB6F9, 0xB78F, 0xB6FA, 0xB790, 0xB6FB, 0xB791, 0xB6FC, 0xB792, 0xB6FD, 0xB796, 0xB6FE, 0xB797, 0xB741, 0xD16E, 0xB742, 0xD16F, + 0xB743, 0xD170, 0xB744, 0xD171, 0xB745, 0xD172, 0xB746, 0xD173, 0xB747, 0xD174, 0xB748, 0xD175, 0xB749, 0xD176, 0xB74A, 0xD177, + 0xB74B, 0xD178, 0xB74C, 0xD179, 0xB74D, 0xD17A, 0xB74E, 0xD17B, 0xB74F, 0xD17D, 0xB750, 0xD17E, 0xB751, 0xD17F, 0xB752, 0xD180, + 0xB753, 0xD181, 0xB754, 0xD182, 0xB755, 0xD183, 0xB756, 0xD185, 0xB757, 0xD186, 0xB758, 0xD187, 0xB759, 0xD189, 0xB75A, 0xD18A, + 0xB761, 0xD18B, 0xB762, 0xD18C, 0xB763, 0xD18D, 0xB764, 0xD18E, 0xB765, 0xD18F, 0xB766, 0xD190, 0xB767, 0xD191, 0xB768, 0xD192, + 0xB769, 0xD193, 0xB76A, 0xD194, 0xB76B, 0xD195, 0xB76C, 0xD196, 0xB76D, 0xD197, 0xB76E, 0xD198, 0xB76F, 0xD199, 0xB770, 0xD19A, + 0xB771, 0xD19B, 0xB772, 0xD19C, 0xB773, 0xD19D, 0xB774, 0xD19E, 0xB775, 0xD19F, 0xB776, 0xD1A2, 0xB777, 0xD1A3, 0xB778, 0xD1A5, + 0xB779, 0xD1A6, 0xB77A, 0xD1A7, 0xB781, 0xD1A9, 0xB782, 0xD1AA, 0xB783, 0xD1AB, 0xB784, 0xD1AC, 0xB785, 0xD1AD, 0xB786, 0xD1AE, + 0xB787, 0xD1AF, 0xB788, 0xD1B2, 0xB789, 0xD1B4, 0xB78A, 0xD1B6, 0xB78B, 0xD1B7, 0xB78C, 0xD1B8, 0xB78D, 0xD1B9, 0xB78E, 0xD1BB, + 0xB78F, 0xD1BD, 0xB790, 0xD1BE, 0xB791, 0xD1BF, 0xB792, 0xD1C1, 0xB793, 0xD1C2, 0xB794, 0xD1C3, 0xB795, 0xD1C4, 0xB796, 0xD1C5, + 0xB797, 0xD1C6, 0xB798, 0xD1C7, 0xB799, 0xD1C8, 0xB79A, 0xD1C9, 0xB79B, 0xD1CA, 0xB79C, 0xD1CB, 0xB79D, 0xD1CC, 0xB79E, 0xD1CD, + 0xB79F, 0xD1CE, 0xB7A0, 0xD1CF, 0xB7A1, 0xB798, 0xB7A2, 0xB799, 0xB7A3, 0xB79C, 0xB7A4, 0xB7A0, 0xB7A5, 0xB7A8, 0xB7A6, 0xB7A9, + 0xB7A7, 0xB7AB, 0xB7A8, 0xB7AC, 0xB7A9, 0xB7AD, 0xB7AA, 0xB7B4, 0xB7AB, 0xB7B5, 0xB7AC, 0xB7B8, 0xB7AD, 0xB7C7, 0xB7AE, 0xB7C9, + 0xB7AF, 0xB7EC, 0xB7B0, 0xB7ED, 0xB7B1, 0xB7F0, 0xB7B2, 0xB7F4, 0xB7B3, 0xB7FC, 0xB7B4, 0xB7FD, 0xB7B5, 0xB7FF, 0xB7B6, 0xB800, + 0xB7B7, 0xB801, 0xB7B8, 0xB807, 0xB7B9, 0xB808, 0xB7BA, 0xB809, 0xB7BB, 0xB80C, 0xB7BC, 0xB810, 0xB7BD, 0xB818, 0xB7BE, 0xB819, + 0xB7BF, 0xB81B, 0xB7C0, 0xB81D, 0xB7C1, 0xB824, 0xB7C2, 0xB825, 0xB7C3, 0xB828, 0xB7C4, 0xB82C, 0xB7C5, 0xB834, 0xB7C6, 0xB835, + 0xB7C7, 0xB837, 0xB7C8, 0xB838, 0xB7C9, 0xB839, 0xB7CA, 0xB840, 0xB7CB, 0xB844, 0xB7CC, 0xB851, 0xB7CD, 0xB853, 0xB7CE, 0xB85C, + 0xB7CF, 0xB85D, 0xB7D0, 0xB860, 0xB7D1, 0xB864, 0xB7D2, 0xB86C, 0xB7D3, 0xB86D, 0xB7D4, 0xB86F, 0xB7D5, 0xB871, 0xB7D6, 0xB878, + 0xB7D7, 0xB87C, 0xB7D8, 0xB88D, 0xB7D9, 0xB8A8, 0xB7DA, 0xB8B0, 0xB7DB, 0xB8B4, 0xB7DC, 0xB8B8, 0xB7DD, 0xB8C0, 0xB7DE, 0xB8C1, + 0xB7DF, 0xB8C3, 0xB7E0, 0xB8C5, 0xB7E1, 0xB8CC, 0xB7E2, 0xB8D0, 0xB7E3, 0xB8D4, 0xB7E4, 0xB8DD, 0xB7E5, 0xB8DF, 0xB7E6, 0xB8E1, + 0xB7E7, 0xB8E8, 0xB7E8, 0xB8E9, 0xB7E9, 0xB8EC, 0xB7EA, 0xB8F0, 0xB7EB, 0xB8F8, 0xB7EC, 0xB8F9, 0xB7ED, 0xB8FB, 0xB7EE, 0xB8FD, + 0xB7EF, 0xB904, 0xB7F0, 0xB918, 0xB7F1, 0xB920, 0xB7F2, 0xB93C, 0xB7F3, 0xB93D, 0xB7F4, 0xB940, 0xB7F5, 0xB944, 0xB7F6, 0xB94C, + 0xB7F7, 0xB94F, 0xB7F8, 0xB951, 0xB7F9, 0xB958, 0xB7FA, 0xB959, 0xB7FB, 0xB95C, 0xB7FC, 0xB960, 0xB7FD, 0xB968, 0xB7FE, 0xB969, + 0xB841, 0xD1D0, 0xB842, 0xD1D1, 0xB843, 0xD1D2, 0xB844, 0xD1D3, 0xB845, 0xD1D4, 0xB846, 0xD1D5, 0xB847, 0xD1D6, 0xB848, 0xD1D7, + 0xB849, 0xD1D9, 0xB84A, 0xD1DA, 0xB84B, 0xD1DB, 0xB84C, 0xD1DC, 0xB84D, 0xD1DD, 0xB84E, 0xD1DE, 0xB84F, 0xD1DF, 0xB850, 0xD1E0, + 0xB851, 0xD1E1, 0xB852, 0xD1E2, 0xB853, 0xD1E3, 0xB854, 0xD1E4, 0xB855, 0xD1E5, 0xB856, 0xD1E6, 0xB857, 0xD1E7, 0xB858, 0xD1E8, + 0xB859, 0xD1E9, 0xB85A, 0xD1EA, 0xB861, 0xD1EB, 0xB862, 0xD1EC, 0xB863, 0xD1ED, 0xB864, 0xD1EE, 0xB865, 0xD1EF, 0xB866, 0xD1F0, + 0xB867, 0xD1F1, 0xB868, 0xD1F2, 0xB869, 0xD1F3, 0xB86A, 0xD1F5, 0xB86B, 0xD1F6, 0xB86C, 0xD1F7, 0xB86D, 0xD1F9, 0xB86E, 0xD1FA, + 0xB86F, 0xD1FB, 0xB870, 0xD1FC, 0xB871, 0xD1FD, 0xB872, 0xD1FE, 0xB873, 0xD1FF, 0xB874, 0xD200, 0xB875, 0xD201, 0xB876, 0xD202, + 0xB877, 0xD203, 0xB878, 0xD204, 0xB879, 0xD205, 0xB87A, 0xD206, 0xB881, 0xD208, 0xB882, 0xD20A, 0xB883, 0xD20B, 0xB884, 0xD20C, + 0xB885, 0xD20D, 0xB886, 0xD20E, 0xB887, 0xD20F, 0xB888, 0xD211, 0xB889, 0xD212, 0xB88A, 0xD213, 0xB88B, 0xD214, 0xB88C, 0xD215, + 0xB88D, 0xD216, 0xB88E, 0xD217, 0xB88F, 0xD218, 0xB890, 0xD219, 0xB891, 0xD21A, 0xB892, 0xD21B, 0xB893, 0xD21C, 0xB894, 0xD21D, + 0xB895, 0xD21E, 0xB896, 0xD21F, 0xB897, 0xD220, 0xB898, 0xD221, 0xB899, 0xD222, 0xB89A, 0xD223, 0xB89B, 0xD224, 0xB89C, 0xD225, + 0xB89D, 0xD226, 0xB89E, 0xD227, 0xB89F, 0xD228, 0xB8A0, 0xD229, 0xB8A1, 0xB96B, 0xB8A2, 0xB96D, 0xB8A3, 0xB974, 0xB8A4, 0xB975, + 0xB8A5, 0xB978, 0xB8A6, 0xB97C, 0xB8A7, 0xB984, 0xB8A8, 0xB985, 0xB8A9, 0xB987, 0xB8AA, 0xB989, 0xB8AB, 0xB98A, 0xB8AC, 0xB98D, + 0xB8AD, 0xB98E, 0xB8AE, 0xB9AC, 0xB8AF, 0xB9AD, 0xB8B0, 0xB9B0, 0xB8B1, 0xB9B4, 0xB8B2, 0xB9BC, 0xB8B3, 0xB9BD, 0xB8B4, 0xB9BF, + 0xB8B5, 0xB9C1, 0xB8B6, 0xB9C8, 0xB8B7, 0xB9C9, 0xB8B8, 0xB9CC, 0xB8B9, 0xB9CE, 0xB8BA, 0xB9CF, 0xB8BB, 0xB9D0, 0xB8BC, 0xB9D1, + 0xB8BD, 0xB9D2, 0xB8BE, 0xB9D8, 0xB8BF, 0xB9D9, 0xB8C0, 0xB9DB, 0xB8C1, 0xB9DD, 0xB8C2, 0xB9DE, 0xB8C3, 0xB9E1, 0xB8C4, 0xB9E3, + 0xB8C5, 0xB9E4, 0xB8C6, 0xB9E5, 0xB8C7, 0xB9E8, 0xB8C8, 0xB9EC, 0xB8C9, 0xB9F4, 0xB8CA, 0xB9F5, 0xB8CB, 0xB9F7, 0xB8CC, 0xB9F8, + 0xB8CD, 0xB9F9, 0xB8CE, 0xB9FA, 0xB8CF, 0xBA00, 0xB8D0, 0xBA01, 0xB8D1, 0xBA08, 0xB8D2, 0xBA15, 0xB8D3, 0xBA38, 0xB8D4, 0xBA39, + 0xB8D5, 0xBA3C, 0xB8D6, 0xBA40, 0xB8D7, 0xBA42, 0xB8D8, 0xBA48, 0xB8D9, 0xBA49, 0xB8DA, 0xBA4B, 0xB8DB, 0xBA4D, 0xB8DC, 0xBA4E, + 0xB8DD, 0xBA53, 0xB8DE, 0xBA54, 0xB8DF, 0xBA55, 0xB8E0, 0xBA58, 0xB8E1, 0xBA5C, 0xB8E2, 0xBA64, 0xB8E3, 0xBA65, 0xB8E4, 0xBA67, + 0xB8E5, 0xBA68, 0xB8E6, 0xBA69, 0xB8E7, 0xBA70, 0xB8E8, 0xBA71, 0xB8E9, 0xBA74, 0xB8EA, 0xBA78, 0xB8EB, 0xBA83, 0xB8EC, 0xBA84, + 0xB8ED, 0xBA85, 0xB8EE, 0xBA87, 0xB8EF, 0xBA8C, 0xB8F0, 0xBAA8, 0xB8F1, 0xBAA9, 0xB8F2, 0xBAAB, 0xB8F3, 0xBAAC, 0xB8F4, 0xBAB0, + 0xB8F5, 0xBAB2, 0xB8F6, 0xBAB8, 0xB8F7, 0xBAB9, 0xB8F8, 0xBABB, 0xB8F9, 0xBABD, 0xB8FA, 0xBAC4, 0xB8FB, 0xBAC8, 0xB8FC, 0xBAD8, + 0xB8FD, 0xBAD9, 0xB8FE, 0xBAFC, 0xB941, 0xD22A, 0xB942, 0xD22B, 0xB943, 0xD22E, 0xB944, 0xD22F, 0xB945, 0xD231, 0xB946, 0xD232, + 0xB947, 0xD233, 0xB948, 0xD235, 0xB949, 0xD236, 0xB94A, 0xD237, 0xB94B, 0xD238, 0xB94C, 0xD239, 0xB94D, 0xD23A, 0xB94E, 0xD23B, + 0xB94F, 0xD23E, 0xB950, 0xD240, 0xB951, 0xD242, 0xB952, 0xD243, 0xB953, 0xD244, 0xB954, 0xD245, 0xB955, 0xD246, 0xB956, 0xD247, + 0xB957, 0xD249, 0xB958, 0xD24A, 0xB959, 0xD24B, 0xB95A, 0xD24C, 0xB961, 0xD24D, 0xB962, 0xD24E, 0xB963, 0xD24F, 0xB964, 0xD250, + 0xB965, 0xD251, 0xB966, 0xD252, 0xB967, 0xD253, 0xB968, 0xD254, 0xB969, 0xD255, 0xB96A, 0xD256, 0xB96B, 0xD257, 0xB96C, 0xD258, + 0xB96D, 0xD259, 0xB96E, 0xD25A, 0xB96F, 0xD25B, 0xB970, 0xD25D, 0xB971, 0xD25E, 0xB972, 0xD25F, 0xB973, 0xD260, 0xB974, 0xD261, + 0xB975, 0xD262, 0xB976, 0xD263, 0xB977, 0xD265, 0xB978, 0xD266, 0xB979, 0xD267, 0xB97A, 0xD268, 0xB981, 0xD269, 0xB982, 0xD26A, + 0xB983, 0xD26B, 0xB984, 0xD26C, 0xB985, 0xD26D, 0xB986, 0xD26E, 0xB987, 0xD26F, 0xB988, 0xD270, 0xB989, 0xD271, 0xB98A, 0xD272, + 0xB98B, 0xD273, 0xB98C, 0xD274, 0xB98D, 0xD275, 0xB98E, 0xD276, 0xB98F, 0xD277, 0xB990, 0xD278, 0xB991, 0xD279, 0xB992, 0xD27A, + 0xB993, 0xD27B, 0xB994, 0xD27C, 0xB995, 0xD27D, 0xB996, 0xD27E, 0xB997, 0xD27F, 0xB998, 0xD282, 0xB999, 0xD283, 0xB99A, 0xD285, + 0xB99B, 0xD286, 0xB99C, 0xD287, 0xB99D, 0xD289, 0xB99E, 0xD28A, 0xB99F, 0xD28B, 0xB9A0, 0xD28C, 0xB9A1, 0xBB00, 0xB9A2, 0xBB04, + 0xB9A3, 0xBB0D, 0xB9A4, 0xBB0F, 0xB9A5, 0xBB11, 0xB9A6, 0xBB18, 0xB9A7, 0xBB1C, 0xB9A8, 0xBB20, 0xB9A9, 0xBB29, 0xB9AA, 0xBB2B, + 0xB9AB, 0xBB34, 0xB9AC, 0xBB35, 0xB9AD, 0xBB36, 0xB9AE, 0xBB38, 0xB9AF, 0xBB3B, 0xB9B0, 0xBB3C, 0xB9B1, 0xBB3D, 0xB9B2, 0xBB3E, + 0xB9B3, 0xBB44, 0xB9B4, 0xBB45, 0xB9B5, 0xBB47, 0xB9B6, 0xBB49, 0xB9B7, 0xBB4D, 0xB9B8, 0xBB4F, 0xB9B9, 0xBB50, 0xB9BA, 0xBB54, + 0xB9BB, 0xBB58, 0xB9BC, 0xBB61, 0xB9BD, 0xBB63, 0xB9BE, 0xBB6C, 0xB9BF, 0xBB88, 0xB9C0, 0xBB8C, 0xB9C1, 0xBB90, 0xB9C2, 0xBBA4, + 0xB9C3, 0xBBA8, 0xB9C4, 0xBBAC, 0xB9C5, 0xBBB4, 0xB9C6, 0xBBB7, 0xB9C7, 0xBBC0, 0xB9C8, 0xBBC4, 0xB9C9, 0xBBC8, 0xB9CA, 0xBBD0, + 0xB9CB, 0xBBD3, 0xB9CC, 0xBBF8, 0xB9CD, 0xBBF9, 0xB9CE, 0xBBFC, 0xB9CF, 0xBBFF, 0xB9D0, 0xBC00, 0xB9D1, 0xBC02, 0xB9D2, 0xBC08, + 0xB9D3, 0xBC09, 0xB9D4, 0xBC0B, 0xB9D5, 0xBC0C, 0xB9D6, 0xBC0D, 0xB9D7, 0xBC0F, 0xB9D8, 0xBC11, 0xB9D9, 0xBC14, 0xB9DA, 0xBC15, + 0xB9DB, 0xBC16, 0xB9DC, 0xBC17, 0xB9DD, 0xBC18, 0xB9DE, 0xBC1B, 0xB9DF, 0xBC1C, 0xB9E0, 0xBC1D, 0xB9E1, 0xBC1E, 0xB9E2, 0xBC1F, + 0xB9E3, 0xBC24, 0xB9E4, 0xBC25, 0xB9E5, 0xBC27, 0xB9E6, 0xBC29, 0xB9E7, 0xBC2D, 0xB9E8, 0xBC30, 0xB9E9, 0xBC31, 0xB9EA, 0xBC34, + 0xB9EB, 0xBC38, 0xB9EC, 0xBC40, 0xB9ED, 0xBC41, 0xB9EE, 0xBC43, 0xB9EF, 0xBC44, 0xB9F0, 0xBC45, 0xB9F1, 0xBC49, 0xB9F2, 0xBC4C, + 0xB9F3, 0xBC4D, 0xB9F4, 0xBC50, 0xB9F5, 0xBC5D, 0xB9F6, 0xBC84, 0xB9F7, 0xBC85, 0xB9F8, 0xBC88, 0xB9F9, 0xBC8B, 0xB9FA, 0xBC8C, + 0xB9FB, 0xBC8E, 0xB9FC, 0xBC94, 0xB9FD, 0xBC95, 0xB9FE, 0xBC97, 0xBA41, 0xD28D, 0xBA42, 0xD28E, 0xBA43, 0xD28F, 0xBA44, 0xD292, + 0xBA45, 0xD293, 0xBA46, 0xD294, 0xBA47, 0xD296, 0xBA48, 0xD297, 0xBA49, 0xD298, 0xBA4A, 0xD299, 0xBA4B, 0xD29A, 0xBA4C, 0xD29B, + 0xBA4D, 0xD29D, 0xBA4E, 0xD29E, 0xBA4F, 0xD29F, 0xBA50, 0xD2A1, 0xBA51, 0xD2A2, 0xBA52, 0xD2A3, 0xBA53, 0xD2A5, 0xBA54, 0xD2A6, + 0xBA55, 0xD2A7, 0xBA56, 0xD2A8, 0xBA57, 0xD2A9, 0xBA58, 0xD2AA, 0xBA59, 0xD2AB, 0xBA5A, 0xD2AD, 0xBA61, 0xD2AE, 0xBA62, 0xD2AF, + 0xBA63, 0xD2B0, 0xBA64, 0xD2B2, 0xBA65, 0xD2B3, 0xBA66, 0xD2B4, 0xBA67, 0xD2B5, 0xBA68, 0xD2B6, 0xBA69, 0xD2B7, 0xBA6A, 0xD2BA, + 0xBA6B, 0xD2BB, 0xBA6C, 0xD2BD, 0xBA6D, 0xD2BE, 0xBA6E, 0xD2C1, 0xBA6F, 0xD2C3, 0xBA70, 0xD2C4, 0xBA71, 0xD2C5, 0xBA72, 0xD2C6, + 0xBA73, 0xD2C7, 0xBA74, 0xD2CA, 0xBA75, 0xD2CC, 0xBA76, 0xD2CD, 0xBA77, 0xD2CE, 0xBA78, 0xD2CF, 0xBA79, 0xD2D0, 0xBA7A, 0xD2D1, + 0xBA81, 0xD2D2, 0xBA82, 0xD2D3, 0xBA83, 0xD2D5, 0xBA84, 0xD2D6, 0xBA85, 0xD2D7, 0xBA86, 0xD2D9, 0xBA87, 0xD2DA, 0xBA88, 0xD2DB, + 0xBA89, 0xD2DD, 0xBA8A, 0xD2DE, 0xBA8B, 0xD2DF, 0xBA8C, 0xD2E0, 0xBA8D, 0xD2E1, 0xBA8E, 0xD2E2, 0xBA8F, 0xD2E3, 0xBA90, 0xD2E6, + 0xBA91, 0xD2E7, 0xBA92, 0xD2E8, 0xBA93, 0xD2E9, 0xBA94, 0xD2EA, 0xBA95, 0xD2EB, 0xBA96, 0xD2EC, 0xBA97, 0xD2ED, 0xBA98, 0xD2EE, + 0xBA99, 0xD2EF, 0xBA9A, 0xD2F2, 0xBA9B, 0xD2F3, 0xBA9C, 0xD2F5, 0xBA9D, 0xD2F6, 0xBA9E, 0xD2F7, 0xBA9F, 0xD2F9, 0xBAA0, 0xD2FA, + 0xBAA1, 0xBC99, 0xBAA2, 0xBC9A, 0xBAA3, 0xBCA0, 0xBAA4, 0xBCA1, 0xBAA5, 0xBCA4, 0xBAA6, 0xBCA7, 0xBAA7, 0xBCA8, 0xBAA8, 0xBCB0, + 0xBAA9, 0xBCB1, 0xBAAA, 0xBCB3, 0xBAAB, 0xBCB4, 0xBAAC, 0xBCB5, 0xBAAD, 0xBCBC, 0xBAAE, 0xBCBD, 0xBAAF, 0xBCC0, 0xBAB0, 0xBCC4, + 0xBAB1, 0xBCCD, 0xBAB2, 0xBCCF, 0xBAB3, 0xBCD0, 0xBAB4, 0xBCD1, 0xBAB5, 0xBCD5, 0xBAB6, 0xBCD8, 0xBAB7, 0xBCDC, 0xBAB8, 0xBCF4, + 0xBAB9, 0xBCF5, 0xBABA, 0xBCF6, 0xBABB, 0xBCF8, 0xBABC, 0xBCFC, 0xBABD, 0xBD04, 0xBABE, 0xBD05, 0xBABF, 0xBD07, 0xBAC0, 0xBD09, + 0xBAC1, 0xBD10, 0xBAC2, 0xBD14, 0xBAC3, 0xBD24, 0xBAC4, 0xBD2C, 0xBAC5, 0xBD40, 0xBAC6, 0xBD48, 0xBAC7, 0xBD49, 0xBAC8, 0xBD4C, + 0xBAC9, 0xBD50, 0xBACA, 0xBD58, 0xBACB, 0xBD59, 0xBACC, 0xBD64, 0xBACD, 0xBD68, 0xBACE, 0xBD80, 0xBACF, 0xBD81, 0xBAD0, 0xBD84, + 0xBAD1, 0xBD87, 0xBAD2, 0xBD88, 0xBAD3, 0xBD89, 0xBAD4, 0xBD8A, 0xBAD5, 0xBD90, 0xBAD6, 0xBD91, 0xBAD7, 0xBD93, 0xBAD8, 0xBD95, + 0xBAD9, 0xBD99, 0xBADA, 0xBD9A, 0xBADB, 0xBD9C, 0xBADC, 0xBDA4, 0xBADD, 0xBDB0, 0xBADE, 0xBDB8, 0xBADF, 0xBDD4, 0xBAE0, 0xBDD5, + 0xBAE1, 0xBDD8, 0xBAE2, 0xBDDC, 0xBAE3, 0xBDE9, 0xBAE4, 0xBDF0, 0xBAE5, 0xBDF4, 0xBAE6, 0xBDF8, 0xBAE7, 0xBE00, 0xBAE8, 0xBE03, + 0xBAE9, 0xBE05, 0xBAEA, 0xBE0C, 0xBAEB, 0xBE0D, 0xBAEC, 0xBE10, 0xBAED, 0xBE14, 0xBAEE, 0xBE1C, 0xBAEF, 0xBE1D, 0xBAF0, 0xBE1F, + 0xBAF1, 0xBE44, 0xBAF2, 0xBE45, 0xBAF3, 0xBE48, 0xBAF4, 0xBE4C, 0xBAF5, 0xBE4E, 0xBAF6, 0xBE54, 0xBAF7, 0xBE55, 0xBAF8, 0xBE57, + 0xBAF9, 0xBE59, 0xBAFA, 0xBE5A, 0xBAFB, 0xBE5B, 0xBAFC, 0xBE60, 0xBAFD, 0xBE61, 0xBAFE, 0xBE64, 0xBB41, 0xD2FB, 0xBB42, 0xD2FC, + 0xBB43, 0xD2FD, 0xBB44, 0xD2FE, 0xBB45, 0xD2FF, 0xBB46, 0xD302, 0xBB47, 0xD304, 0xBB48, 0xD306, 0xBB49, 0xD307, 0xBB4A, 0xD308, + 0xBB4B, 0xD309, 0xBB4C, 0xD30A, 0xBB4D, 0xD30B, 0xBB4E, 0xD30F, 0xBB4F, 0xD311, 0xBB50, 0xD312, 0xBB51, 0xD313, 0xBB52, 0xD315, + 0xBB53, 0xD317, 0xBB54, 0xD318, 0xBB55, 0xD319, 0xBB56, 0xD31A, 0xBB57, 0xD31B, 0xBB58, 0xD31E, 0xBB59, 0xD322, 0xBB5A, 0xD323, + 0xBB61, 0xD324, 0xBB62, 0xD326, 0xBB63, 0xD327, 0xBB64, 0xD32A, 0xBB65, 0xD32B, 0xBB66, 0xD32D, 0xBB67, 0xD32E, 0xBB68, 0xD32F, + 0xBB69, 0xD331, 0xBB6A, 0xD332, 0xBB6B, 0xD333, 0xBB6C, 0xD334, 0xBB6D, 0xD335, 0xBB6E, 0xD336, 0xBB6F, 0xD337, 0xBB70, 0xD33A, + 0xBB71, 0xD33E, 0xBB72, 0xD33F, 0xBB73, 0xD340, 0xBB74, 0xD341, 0xBB75, 0xD342, 0xBB76, 0xD343, 0xBB77, 0xD346, 0xBB78, 0xD347, + 0xBB79, 0xD348, 0xBB7A, 0xD349, 0xBB81, 0xD34A, 0xBB82, 0xD34B, 0xBB83, 0xD34C, 0xBB84, 0xD34D, 0xBB85, 0xD34E, 0xBB86, 0xD34F, + 0xBB87, 0xD350, 0xBB88, 0xD351, 0xBB89, 0xD352, 0xBB8A, 0xD353, 0xBB8B, 0xD354, 0xBB8C, 0xD355, 0xBB8D, 0xD356, 0xBB8E, 0xD357, + 0xBB8F, 0xD358, 0xBB90, 0xD359, 0xBB91, 0xD35A, 0xBB92, 0xD35B, 0xBB93, 0xD35C, 0xBB94, 0xD35D, 0xBB95, 0xD35E, 0xBB96, 0xD35F, + 0xBB97, 0xD360, 0xBB98, 0xD361, 0xBB99, 0xD362, 0xBB9A, 0xD363, 0xBB9B, 0xD364, 0xBB9C, 0xD365, 0xBB9D, 0xD366, 0xBB9E, 0xD367, + 0xBB9F, 0xD368, 0xBBA0, 0xD369, 0xBBA1, 0xBE68, 0xBBA2, 0xBE6A, 0xBBA3, 0xBE70, 0xBBA4, 0xBE71, 0xBBA5, 0xBE73, 0xBBA6, 0xBE74, + 0xBBA7, 0xBE75, 0xBBA8, 0xBE7B, 0xBBA9, 0xBE7C, 0xBBAA, 0xBE7D, 0xBBAB, 0xBE80, 0xBBAC, 0xBE84, 0xBBAD, 0xBE8C, 0xBBAE, 0xBE8D, + 0xBBAF, 0xBE8F, 0xBBB0, 0xBE90, 0xBBB1, 0xBE91, 0xBBB2, 0xBE98, 0xBBB3, 0xBE99, 0xBBB4, 0xBEA8, 0xBBB5, 0xBED0, 0xBBB6, 0xBED1, + 0xBBB7, 0xBED4, 0xBBB8, 0xBED7, 0xBBB9, 0xBED8, 0xBBBA, 0xBEE0, 0xBBBB, 0xBEE3, 0xBBBC, 0xBEE4, 0xBBBD, 0xBEE5, 0xBBBE, 0xBEEC, + 0xBBBF, 0xBF01, 0xBBC0, 0xBF08, 0xBBC1, 0xBF09, 0xBBC2, 0xBF18, 0xBBC3, 0xBF19, 0xBBC4, 0xBF1B, 0xBBC5, 0xBF1C, 0xBBC6, 0xBF1D, + 0xBBC7, 0xBF40, 0xBBC8, 0xBF41, 0xBBC9, 0xBF44, 0xBBCA, 0xBF48, 0xBBCB, 0xBF50, 0xBBCC, 0xBF51, 0xBBCD, 0xBF55, 0xBBCE, 0xBF94, + 0xBBCF, 0xBFB0, 0xBBD0, 0xBFC5, 0xBBD1, 0xBFCC, 0xBBD2, 0xBFCD, 0xBBD3, 0xBFD0, 0xBBD4, 0xBFD4, 0xBBD5, 0xBFDC, 0xBBD6, 0xBFDF, + 0xBBD7, 0xBFE1, 0xBBD8, 0xC03C, 0xBBD9, 0xC051, 0xBBDA, 0xC058, 0xBBDB, 0xC05C, 0xBBDC, 0xC060, 0xBBDD, 0xC068, 0xBBDE, 0xC069, + 0xBBDF, 0xC090, 0xBBE0, 0xC091, 0xBBE1, 0xC094, 0xBBE2, 0xC098, 0xBBE3, 0xC0A0, 0xBBE4, 0xC0A1, 0xBBE5, 0xC0A3, 0xBBE6, 0xC0A5, + 0xBBE7, 0xC0AC, 0xBBE8, 0xC0AD, 0xBBE9, 0xC0AF, 0xBBEA, 0xC0B0, 0xBBEB, 0xC0B3, 0xBBEC, 0xC0B4, 0xBBED, 0xC0B5, 0xBBEE, 0xC0B6, + 0xBBEF, 0xC0BC, 0xBBF0, 0xC0BD, 0xBBF1, 0xC0BF, 0xBBF2, 0xC0C0, 0xBBF3, 0xC0C1, 0xBBF4, 0xC0C5, 0xBBF5, 0xC0C8, 0xBBF6, 0xC0C9, + 0xBBF7, 0xC0CC, 0xBBF8, 0xC0D0, 0xBBF9, 0xC0D8, 0xBBFA, 0xC0D9, 0xBBFB, 0xC0DB, 0xBBFC, 0xC0DC, 0xBBFD, 0xC0DD, 0xBBFE, 0xC0E4, + 0xBC41, 0xD36A, 0xBC42, 0xD36B, 0xBC43, 0xD36C, 0xBC44, 0xD36D, 0xBC45, 0xD36E, 0xBC46, 0xD36F, 0xBC47, 0xD370, 0xBC48, 0xD371, + 0xBC49, 0xD372, 0xBC4A, 0xD373, 0xBC4B, 0xD374, 0xBC4C, 0xD375, 0xBC4D, 0xD376, 0xBC4E, 0xD377, 0xBC4F, 0xD378, 0xBC50, 0xD379, + 0xBC51, 0xD37A, 0xBC52, 0xD37B, 0xBC53, 0xD37E, 0xBC54, 0xD37F, 0xBC55, 0xD381, 0xBC56, 0xD382, 0xBC57, 0xD383, 0xBC58, 0xD385, + 0xBC59, 0xD386, 0xBC5A, 0xD387, 0xBC61, 0xD388, 0xBC62, 0xD389, 0xBC63, 0xD38A, 0xBC64, 0xD38B, 0xBC65, 0xD38E, 0xBC66, 0xD392, + 0xBC67, 0xD393, 0xBC68, 0xD394, 0xBC69, 0xD395, 0xBC6A, 0xD396, 0xBC6B, 0xD397, 0xBC6C, 0xD39A, 0xBC6D, 0xD39B, 0xBC6E, 0xD39D, + 0xBC6F, 0xD39E, 0xBC70, 0xD39F, 0xBC71, 0xD3A1, 0xBC72, 0xD3A2, 0xBC73, 0xD3A3, 0xBC74, 0xD3A4, 0xBC75, 0xD3A5, 0xBC76, 0xD3A6, + 0xBC77, 0xD3A7, 0xBC78, 0xD3AA, 0xBC79, 0xD3AC, 0xBC7A, 0xD3AE, 0xBC81, 0xD3AF, 0xBC82, 0xD3B0, 0xBC83, 0xD3B1, 0xBC84, 0xD3B2, + 0xBC85, 0xD3B3, 0xBC86, 0xD3B5, 0xBC87, 0xD3B6, 0xBC88, 0xD3B7, 0xBC89, 0xD3B9, 0xBC8A, 0xD3BA, 0xBC8B, 0xD3BB, 0xBC8C, 0xD3BD, + 0xBC8D, 0xD3BE, 0xBC8E, 0xD3BF, 0xBC8F, 0xD3C0, 0xBC90, 0xD3C1, 0xBC91, 0xD3C2, 0xBC92, 0xD3C3, 0xBC93, 0xD3C6, 0xBC94, 0xD3C7, + 0xBC95, 0xD3CA, 0xBC96, 0xD3CB, 0xBC97, 0xD3CC, 0xBC98, 0xD3CD, 0xBC99, 0xD3CE, 0xBC9A, 0xD3CF, 0xBC9B, 0xD3D1, 0xBC9C, 0xD3D2, + 0xBC9D, 0xD3D3, 0xBC9E, 0xD3D4, 0xBC9F, 0xD3D5, 0xBCA0, 0xD3D6, 0xBCA1, 0xC0E5, 0xBCA2, 0xC0E8, 0xBCA3, 0xC0EC, 0xBCA4, 0xC0F4, + 0xBCA5, 0xC0F5, 0xBCA6, 0xC0F7, 0xBCA7, 0xC0F9, 0xBCA8, 0xC100, 0xBCA9, 0xC104, 0xBCAA, 0xC108, 0xBCAB, 0xC110, 0xBCAC, 0xC115, + 0xBCAD, 0xC11C, 0xBCAE, 0xC11D, 0xBCAF, 0xC11E, 0xBCB0, 0xC11F, 0xBCB1, 0xC120, 0xBCB2, 0xC123, 0xBCB3, 0xC124, 0xBCB4, 0xC126, + 0xBCB5, 0xC127, 0xBCB6, 0xC12C, 0xBCB7, 0xC12D, 0xBCB8, 0xC12F, 0xBCB9, 0xC130, 0xBCBA, 0xC131, 0xBCBB, 0xC136, 0xBCBC, 0xC138, + 0xBCBD, 0xC139, 0xBCBE, 0xC13C, 0xBCBF, 0xC140, 0xBCC0, 0xC148, 0xBCC1, 0xC149, 0xBCC2, 0xC14B, 0xBCC3, 0xC14C, 0xBCC4, 0xC14D, + 0xBCC5, 0xC154, 0xBCC6, 0xC155, 0xBCC7, 0xC158, 0xBCC8, 0xC15C, 0xBCC9, 0xC164, 0xBCCA, 0xC165, 0xBCCB, 0xC167, 0xBCCC, 0xC168, + 0xBCCD, 0xC169, 0xBCCE, 0xC170, 0xBCCF, 0xC174, 0xBCD0, 0xC178, 0xBCD1, 0xC185, 0xBCD2, 0xC18C, 0xBCD3, 0xC18D, 0xBCD4, 0xC18E, + 0xBCD5, 0xC190, 0xBCD6, 0xC194, 0xBCD7, 0xC196, 0xBCD8, 0xC19C, 0xBCD9, 0xC19D, 0xBCDA, 0xC19F, 0xBCDB, 0xC1A1, 0xBCDC, 0xC1A5, + 0xBCDD, 0xC1A8, 0xBCDE, 0xC1A9, 0xBCDF, 0xC1AC, 0xBCE0, 0xC1B0, 0xBCE1, 0xC1BD, 0xBCE2, 0xC1C4, 0xBCE3, 0xC1C8, 0xBCE4, 0xC1CC, + 0xBCE5, 0xC1D4, 0xBCE6, 0xC1D7, 0xBCE7, 0xC1D8, 0xBCE8, 0xC1E0, 0xBCE9, 0xC1E4, 0xBCEA, 0xC1E8, 0xBCEB, 0xC1F0, 0xBCEC, 0xC1F1, + 0xBCED, 0xC1F3, 0xBCEE, 0xC1FC, 0xBCEF, 0xC1FD, 0xBCF0, 0xC200, 0xBCF1, 0xC204, 0xBCF2, 0xC20C, 0xBCF3, 0xC20D, 0xBCF4, 0xC20F, + 0xBCF5, 0xC211, 0xBCF6, 0xC218, 0xBCF7, 0xC219, 0xBCF8, 0xC21C, 0xBCF9, 0xC21F, 0xBCFA, 0xC220, 0xBCFB, 0xC228, 0xBCFC, 0xC229, + 0xBCFD, 0xC22B, 0xBCFE, 0xC22D, 0xBD41, 0xD3D7, 0xBD42, 0xD3D9, 0xBD43, 0xD3DA, 0xBD44, 0xD3DB, 0xBD45, 0xD3DC, 0xBD46, 0xD3DD, + 0xBD47, 0xD3DE, 0xBD48, 0xD3DF, 0xBD49, 0xD3E0, 0xBD4A, 0xD3E2, 0xBD4B, 0xD3E4, 0xBD4C, 0xD3E5, 0xBD4D, 0xD3E6, 0xBD4E, 0xD3E7, + 0xBD4F, 0xD3E8, 0xBD50, 0xD3E9, 0xBD51, 0xD3EA, 0xBD52, 0xD3EB, 0xBD53, 0xD3EE, 0xBD54, 0xD3EF, 0xBD55, 0xD3F1, 0xBD56, 0xD3F2, + 0xBD57, 0xD3F3, 0xBD58, 0xD3F5, 0xBD59, 0xD3F6, 0xBD5A, 0xD3F7, 0xBD61, 0xD3F8, 0xBD62, 0xD3F9, 0xBD63, 0xD3FA, 0xBD64, 0xD3FB, + 0xBD65, 0xD3FE, 0xBD66, 0xD400, 0xBD67, 0xD402, 0xBD68, 0xD403, 0xBD69, 0xD404, 0xBD6A, 0xD405, 0xBD6B, 0xD406, 0xBD6C, 0xD407, + 0xBD6D, 0xD409, 0xBD6E, 0xD40A, 0xBD6F, 0xD40B, 0xBD70, 0xD40C, 0xBD71, 0xD40D, 0xBD72, 0xD40E, 0xBD73, 0xD40F, 0xBD74, 0xD410, + 0xBD75, 0xD411, 0xBD76, 0xD412, 0xBD77, 0xD413, 0xBD78, 0xD414, 0xBD79, 0xD415, 0xBD7A, 0xD416, 0xBD81, 0xD417, 0xBD82, 0xD418, + 0xBD83, 0xD419, 0xBD84, 0xD41A, 0xBD85, 0xD41B, 0xBD86, 0xD41C, 0xBD87, 0xD41E, 0xBD88, 0xD41F, 0xBD89, 0xD420, 0xBD8A, 0xD421, + 0xBD8B, 0xD422, 0xBD8C, 0xD423, 0xBD8D, 0xD424, 0xBD8E, 0xD425, 0xBD8F, 0xD426, 0xBD90, 0xD427, 0xBD91, 0xD428, 0xBD92, 0xD429, + 0xBD93, 0xD42A, 0xBD94, 0xD42B, 0xBD95, 0xD42C, 0xBD96, 0xD42D, 0xBD97, 0xD42E, 0xBD98, 0xD42F, 0xBD99, 0xD430, 0xBD9A, 0xD431, + 0xBD9B, 0xD432, 0xBD9C, 0xD433, 0xBD9D, 0xD434, 0xBD9E, 0xD435, 0xBD9F, 0xD436, 0xBDA0, 0xD437, 0xBDA1, 0xC22F, 0xBDA2, 0xC231, + 0xBDA3, 0xC232, 0xBDA4, 0xC234, 0xBDA5, 0xC248, 0xBDA6, 0xC250, 0xBDA7, 0xC251, 0xBDA8, 0xC254, 0xBDA9, 0xC258, 0xBDAA, 0xC260, + 0xBDAB, 0xC265, 0xBDAC, 0xC26C, 0xBDAD, 0xC26D, 0xBDAE, 0xC270, 0xBDAF, 0xC274, 0xBDB0, 0xC27C, 0xBDB1, 0xC27D, 0xBDB2, 0xC27F, + 0xBDB3, 0xC281, 0xBDB4, 0xC288, 0xBDB5, 0xC289, 0xBDB6, 0xC290, 0xBDB7, 0xC298, 0xBDB8, 0xC29B, 0xBDB9, 0xC29D, 0xBDBA, 0xC2A4, + 0xBDBB, 0xC2A5, 0xBDBC, 0xC2A8, 0xBDBD, 0xC2AC, 0xBDBE, 0xC2AD, 0xBDBF, 0xC2B4, 0xBDC0, 0xC2B5, 0xBDC1, 0xC2B7, 0xBDC2, 0xC2B9, + 0xBDC3, 0xC2DC, 0xBDC4, 0xC2DD, 0xBDC5, 0xC2E0, 0xBDC6, 0xC2E3, 0xBDC7, 0xC2E4, 0xBDC8, 0xC2EB, 0xBDC9, 0xC2EC, 0xBDCA, 0xC2ED, + 0xBDCB, 0xC2EF, 0xBDCC, 0xC2F1, 0xBDCD, 0xC2F6, 0xBDCE, 0xC2F8, 0xBDCF, 0xC2F9, 0xBDD0, 0xC2FB, 0xBDD1, 0xC2FC, 0xBDD2, 0xC300, + 0xBDD3, 0xC308, 0xBDD4, 0xC309, 0xBDD5, 0xC30C, 0xBDD6, 0xC30D, 0xBDD7, 0xC313, 0xBDD8, 0xC314, 0xBDD9, 0xC315, 0xBDDA, 0xC318, + 0xBDDB, 0xC31C, 0xBDDC, 0xC324, 0xBDDD, 0xC325, 0xBDDE, 0xC328, 0xBDDF, 0xC329, 0xBDE0, 0xC345, 0xBDE1, 0xC368, 0xBDE2, 0xC369, + 0xBDE3, 0xC36C, 0xBDE4, 0xC370, 0xBDE5, 0xC372, 0xBDE6, 0xC378, 0xBDE7, 0xC379, 0xBDE8, 0xC37C, 0xBDE9, 0xC37D, 0xBDEA, 0xC384, + 0xBDEB, 0xC388, 0xBDEC, 0xC38C, 0xBDED, 0xC3C0, 0xBDEE, 0xC3D8, 0xBDEF, 0xC3D9, 0xBDF0, 0xC3DC, 0xBDF1, 0xC3DF, 0xBDF2, 0xC3E0, + 0xBDF3, 0xC3E2, 0xBDF4, 0xC3E8, 0xBDF5, 0xC3E9, 0xBDF6, 0xC3ED, 0xBDF7, 0xC3F4, 0xBDF8, 0xC3F5, 0xBDF9, 0xC3F8, 0xBDFA, 0xC408, + 0xBDFB, 0xC410, 0xBDFC, 0xC424, 0xBDFD, 0xC42C, 0xBDFE, 0xC430, 0xBE41, 0xD438, 0xBE42, 0xD439, 0xBE43, 0xD43A, 0xBE44, 0xD43B, + 0xBE45, 0xD43C, 0xBE46, 0xD43D, 0xBE47, 0xD43E, 0xBE48, 0xD43F, 0xBE49, 0xD441, 0xBE4A, 0xD442, 0xBE4B, 0xD443, 0xBE4C, 0xD445, + 0xBE4D, 0xD446, 0xBE4E, 0xD447, 0xBE4F, 0xD448, 0xBE50, 0xD449, 0xBE51, 0xD44A, 0xBE52, 0xD44B, 0xBE53, 0xD44C, 0xBE54, 0xD44D, + 0xBE55, 0xD44E, 0xBE56, 0xD44F, 0xBE57, 0xD450, 0xBE58, 0xD451, 0xBE59, 0xD452, 0xBE5A, 0xD453, 0xBE61, 0xD454, 0xBE62, 0xD455, + 0xBE63, 0xD456, 0xBE64, 0xD457, 0xBE65, 0xD458, 0xBE66, 0xD459, 0xBE67, 0xD45A, 0xBE68, 0xD45B, 0xBE69, 0xD45D, 0xBE6A, 0xD45E, + 0xBE6B, 0xD45F, 0xBE6C, 0xD461, 0xBE6D, 0xD462, 0xBE6E, 0xD463, 0xBE6F, 0xD465, 0xBE70, 0xD466, 0xBE71, 0xD467, 0xBE72, 0xD468, + 0xBE73, 0xD469, 0xBE74, 0xD46A, 0xBE75, 0xD46B, 0xBE76, 0xD46C, 0xBE77, 0xD46E, 0xBE78, 0xD470, 0xBE79, 0xD471, 0xBE7A, 0xD472, + 0xBE81, 0xD473, 0xBE82, 0xD474, 0xBE83, 0xD475, 0xBE84, 0xD476, 0xBE85, 0xD477, 0xBE86, 0xD47A, 0xBE87, 0xD47B, 0xBE88, 0xD47D, + 0xBE89, 0xD47E, 0xBE8A, 0xD481, 0xBE8B, 0xD483, 0xBE8C, 0xD484, 0xBE8D, 0xD485, 0xBE8E, 0xD486, 0xBE8F, 0xD487, 0xBE90, 0xD48A, + 0xBE91, 0xD48C, 0xBE92, 0xD48E, 0xBE93, 0xD48F, 0xBE94, 0xD490, 0xBE95, 0xD491, 0xBE96, 0xD492, 0xBE97, 0xD493, 0xBE98, 0xD495, + 0xBE99, 0xD496, 0xBE9A, 0xD497, 0xBE9B, 0xD498, 0xBE9C, 0xD499, 0xBE9D, 0xD49A, 0xBE9E, 0xD49B, 0xBE9F, 0xD49C, 0xBEA0, 0xD49D, + 0xBEA1, 0xC434, 0xBEA2, 0xC43C, 0xBEA3, 0xC43D, 0xBEA4, 0xC448, 0xBEA5, 0xC464, 0xBEA6, 0xC465, 0xBEA7, 0xC468, 0xBEA8, 0xC46C, + 0xBEA9, 0xC474, 0xBEAA, 0xC475, 0xBEAB, 0xC479, 0xBEAC, 0xC480, 0xBEAD, 0xC494, 0xBEAE, 0xC49C, 0xBEAF, 0xC4B8, 0xBEB0, 0xC4BC, + 0xBEB1, 0xC4E9, 0xBEB2, 0xC4F0, 0xBEB3, 0xC4F1, 0xBEB4, 0xC4F4, 0xBEB5, 0xC4F8, 0xBEB6, 0xC4FA, 0xBEB7, 0xC4FF, 0xBEB8, 0xC500, + 0xBEB9, 0xC501, 0xBEBA, 0xC50C, 0xBEBB, 0xC510, 0xBEBC, 0xC514, 0xBEBD, 0xC51C, 0xBEBE, 0xC528, 0xBEBF, 0xC529, 0xBEC0, 0xC52C, + 0xBEC1, 0xC530, 0xBEC2, 0xC538, 0xBEC3, 0xC539, 0xBEC4, 0xC53B, 0xBEC5, 0xC53D, 0xBEC6, 0xC544, 0xBEC7, 0xC545, 0xBEC8, 0xC548, + 0xBEC9, 0xC549, 0xBECA, 0xC54A, 0xBECB, 0xC54C, 0xBECC, 0xC54D, 0xBECD, 0xC54E, 0xBECE, 0xC553, 0xBECF, 0xC554, 0xBED0, 0xC555, + 0xBED1, 0xC557, 0xBED2, 0xC558, 0xBED3, 0xC559, 0xBED4, 0xC55D, 0xBED5, 0xC55E, 0xBED6, 0xC560, 0xBED7, 0xC561, 0xBED8, 0xC564, + 0xBED9, 0xC568, 0xBEDA, 0xC570, 0xBEDB, 0xC571, 0xBEDC, 0xC573, 0xBEDD, 0xC574, 0xBEDE, 0xC575, 0xBEDF, 0xC57C, 0xBEE0, 0xC57D, + 0xBEE1, 0xC580, 0xBEE2, 0xC584, 0xBEE3, 0xC587, 0xBEE4, 0xC58C, 0xBEE5, 0xC58D, 0xBEE6, 0xC58F, 0xBEE7, 0xC591, 0xBEE8, 0xC595, + 0xBEE9, 0xC597, 0xBEEA, 0xC598, 0xBEEB, 0xC59C, 0xBEEC, 0xC5A0, 0xBEED, 0xC5A9, 0xBEEE, 0xC5B4, 0xBEEF, 0xC5B5, 0xBEF0, 0xC5B8, + 0xBEF1, 0xC5B9, 0xBEF2, 0xC5BB, 0xBEF3, 0xC5BC, 0xBEF4, 0xC5BD, 0xBEF5, 0xC5BE, 0xBEF6, 0xC5C4, 0xBEF7, 0xC5C5, 0xBEF8, 0xC5C6, + 0xBEF9, 0xC5C7, 0xBEFA, 0xC5C8, 0xBEFB, 0xC5C9, 0xBEFC, 0xC5CA, 0xBEFD, 0xC5CC, 0xBEFE, 0xC5CE, 0xBF41, 0xD49E, 0xBF42, 0xD49F, + 0xBF43, 0xD4A0, 0xBF44, 0xD4A1, 0xBF45, 0xD4A2, 0xBF46, 0xD4A3, 0xBF47, 0xD4A4, 0xBF48, 0xD4A5, 0xBF49, 0xD4A6, 0xBF4A, 0xD4A7, + 0xBF4B, 0xD4A8, 0xBF4C, 0xD4AA, 0xBF4D, 0xD4AB, 0xBF4E, 0xD4AC, 0xBF4F, 0xD4AD, 0xBF50, 0xD4AE, 0xBF51, 0xD4AF, 0xBF52, 0xD4B0, + 0xBF53, 0xD4B1, 0xBF54, 0xD4B2, 0xBF55, 0xD4B3, 0xBF56, 0xD4B4, 0xBF57, 0xD4B5, 0xBF58, 0xD4B6, 0xBF59, 0xD4B7, 0xBF5A, 0xD4B8, + 0xBF61, 0xD4B9, 0xBF62, 0xD4BA, 0xBF63, 0xD4BB, 0xBF64, 0xD4BC, 0xBF65, 0xD4BD, 0xBF66, 0xD4BE, 0xBF67, 0xD4BF, 0xBF68, 0xD4C0, + 0xBF69, 0xD4C1, 0xBF6A, 0xD4C2, 0xBF6B, 0xD4C3, 0xBF6C, 0xD4C4, 0xBF6D, 0xD4C5, 0xBF6E, 0xD4C6, 0xBF6F, 0xD4C7, 0xBF70, 0xD4C8, + 0xBF71, 0xD4C9, 0xBF72, 0xD4CA, 0xBF73, 0xD4CB, 0xBF74, 0xD4CD, 0xBF75, 0xD4CE, 0xBF76, 0xD4CF, 0xBF77, 0xD4D1, 0xBF78, 0xD4D2, + 0xBF79, 0xD4D3, 0xBF7A, 0xD4D5, 0xBF81, 0xD4D6, 0xBF82, 0xD4D7, 0xBF83, 0xD4D8, 0xBF84, 0xD4D9, 0xBF85, 0xD4DA, 0xBF86, 0xD4DB, + 0xBF87, 0xD4DD, 0xBF88, 0xD4DE, 0xBF89, 0xD4E0, 0xBF8A, 0xD4E1, 0xBF8B, 0xD4E2, 0xBF8C, 0xD4E3, 0xBF8D, 0xD4E4, 0xBF8E, 0xD4E5, + 0xBF8F, 0xD4E6, 0xBF90, 0xD4E7, 0xBF91, 0xD4E9, 0xBF92, 0xD4EA, 0xBF93, 0xD4EB, 0xBF94, 0xD4ED, 0xBF95, 0xD4EE, 0xBF96, 0xD4EF, + 0xBF97, 0xD4F1, 0xBF98, 0xD4F2, 0xBF99, 0xD4F3, 0xBF9A, 0xD4F4, 0xBF9B, 0xD4F5, 0xBF9C, 0xD4F6, 0xBF9D, 0xD4F7, 0xBF9E, 0xD4F9, + 0xBF9F, 0xD4FA, 0xBFA0, 0xD4FC, 0xBFA1, 0xC5D0, 0xBFA2, 0xC5D1, 0xBFA3, 0xC5D4, 0xBFA4, 0xC5D8, 0xBFA5, 0xC5E0, 0xBFA6, 0xC5E1, + 0xBFA7, 0xC5E3, 0xBFA8, 0xC5E5, 0xBFA9, 0xC5EC, 0xBFAA, 0xC5ED, 0xBFAB, 0xC5EE, 0xBFAC, 0xC5F0, 0xBFAD, 0xC5F4, 0xBFAE, 0xC5F6, + 0xBFAF, 0xC5F7, 0xBFB0, 0xC5FC, 0xBFB1, 0xC5FD, 0xBFB2, 0xC5FE, 0xBFB3, 0xC5FF, 0xBFB4, 0xC600, 0xBFB5, 0xC601, 0xBFB6, 0xC605, + 0xBFB7, 0xC606, 0xBFB8, 0xC607, 0xBFB9, 0xC608, 0xBFBA, 0xC60C, 0xBFBB, 0xC610, 0xBFBC, 0xC618, 0xBFBD, 0xC619, 0xBFBE, 0xC61B, + 0xBFBF, 0xC61C, 0xBFC0, 0xC624, 0xBFC1, 0xC625, 0xBFC2, 0xC628, 0xBFC3, 0xC62C, 0xBFC4, 0xC62D, 0xBFC5, 0xC62E, 0xBFC6, 0xC630, + 0xBFC7, 0xC633, 0xBFC8, 0xC634, 0xBFC9, 0xC635, 0xBFCA, 0xC637, 0xBFCB, 0xC639, 0xBFCC, 0xC63B, 0xBFCD, 0xC640, 0xBFCE, 0xC641, + 0xBFCF, 0xC644, 0xBFD0, 0xC648, 0xBFD1, 0xC650, 0xBFD2, 0xC651, 0xBFD3, 0xC653, 0xBFD4, 0xC654, 0xBFD5, 0xC655, 0xBFD6, 0xC65C, + 0xBFD7, 0xC65D, 0xBFD8, 0xC660, 0xBFD9, 0xC66C, 0xBFDA, 0xC66F, 0xBFDB, 0xC671, 0xBFDC, 0xC678, 0xBFDD, 0xC679, 0xBFDE, 0xC67C, + 0xBFDF, 0xC680, 0xBFE0, 0xC688, 0xBFE1, 0xC689, 0xBFE2, 0xC68B, 0xBFE3, 0xC68D, 0xBFE4, 0xC694, 0xBFE5, 0xC695, 0xBFE6, 0xC698, + 0xBFE7, 0xC69C, 0xBFE8, 0xC6A4, 0xBFE9, 0xC6A5, 0xBFEA, 0xC6A7, 0xBFEB, 0xC6A9, 0xBFEC, 0xC6B0, 0xBFED, 0xC6B1, 0xBFEE, 0xC6B4, + 0xBFEF, 0xC6B8, 0xBFF0, 0xC6B9, 0xBFF1, 0xC6BA, 0xBFF2, 0xC6C0, 0xBFF3, 0xC6C1, 0xBFF4, 0xC6C3, 0xBFF5, 0xC6C5, 0xBFF6, 0xC6CC, + 0xBFF7, 0xC6CD, 0xBFF8, 0xC6D0, 0xBFF9, 0xC6D4, 0xBFFA, 0xC6DC, 0xBFFB, 0xC6DD, 0xBFFC, 0xC6E0, 0xBFFD, 0xC6E1, 0xBFFE, 0xC6E8, + 0xC041, 0xD4FE, 0xC042, 0xD4FF, 0xC043, 0xD500, 0xC044, 0xD501, 0xC045, 0xD502, 0xC046, 0xD503, 0xC047, 0xD505, 0xC048, 0xD506, + 0xC049, 0xD507, 0xC04A, 0xD509, 0xC04B, 0xD50A, 0xC04C, 0xD50B, 0xC04D, 0xD50D, 0xC04E, 0xD50E, 0xC04F, 0xD50F, 0xC050, 0xD510, + 0xC051, 0xD511, 0xC052, 0xD512, 0xC053, 0xD513, 0xC054, 0xD516, 0xC055, 0xD518, 0xC056, 0xD519, 0xC057, 0xD51A, 0xC058, 0xD51B, + 0xC059, 0xD51C, 0xC05A, 0xD51D, 0xC061, 0xD51E, 0xC062, 0xD51F, 0xC063, 0xD520, 0xC064, 0xD521, 0xC065, 0xD522, 0xC066, 0xD523, + 0xC067, 0xD524, 0xC068, 0xD525, 0xC069, 0xD526, 0xC06A, 0xD527, 0xC06B, 0xD528, 0xC06C, 0xD529, 0xC06D, 0xD52A, 0xC06E, 0xD52B, + 0xC06F, 0xD52C, 0xC070, 0xD52D, 0xC071, 0xD52E, 0xC072, 0xD52F, 0xC073, 0xD530, 0xC074, 0xD531, 0xC075, 0xD532, 0xC076, 0xD533, + 0xC077, 0xD534, 0xC078, 0xD535, 0xC079, 0xD536, 0xC07A, 0xD537, 0xC081, 0xD538, 0xC082, 0xD539, 0xC083, 0xD53A, 0xC084, 0xD53B, + 0xC085, 0xD53E, 0xC086, 0xD53F, 0xC087, 0xD541, 0xC088, 0xD542, 0xC089, 0xD543, 0xC08A, 0xD545, 0xC08B, 0xD546, 0xC08C, 0xD547, + 0xC08D, 0xD548, 0xC08E, 0xD549, 0xC08F, 0xD54A, 0xC090, 0xD54B, 0xC091, 0xD54E, 0xC092, 0xD550, 0xC093, 0xD552, 0xC094, 0xD553, + 0xC095, 0xD554, 0xC096, 0xD555, 0xC097, 0xD556, 0xC098, 0xD557, 0xC099, 0xD55A, 0xC09A, 0xD55B, 0xC09B, 0xD55D, 0xC09C, 0xD55E, + 0xC09D, 0xD55F, 0xC09E, 0xD561, 0xC09F, 0xD562, 0xC0A0, 0xD563, 0xC0A1, 0xC6E9, 0xC0A2, 0xC6EC, 0xC0A3, 0xC6F0, 0xC0A4, 0xC6F8, + 0xC0A5, 0xC6F9, 0xC0A6, 0xC6FD, 0xC0A7, 0xC704, 0xC0A8, 0xC705, 0xC0A9, 0xC708, 0xC0AA, 0xC70C, 0xC0AB, 0xC714, 0xC0AC, 0xC715, + 0xC0AD, 0xC717, 0xC0AE, 0xC719, 0xC0AF, 0xC720, 0xC0B0, 0xC721, 0xC0B1, 0xC724, 0xC0B2, 0xC728, 0xC0B3, 0xC730, 0xC0B4, 0xC731, + 0xC0B5, 0xC733, 0xC0B6, 0xC735, 0xC0B7, 0xC737, 0xC0B8, 0xC73C, 0xC0B9, 0xC73D, 0xC0BA, 0xC740, 0xC0BB, 0xC744, 0xC0BC, 0xC74A, + 0xC0BD, 0xC74C, 0xC0BE, 0xC74D, 0xC0BF, 0xC74F, 0xC0C0, 0xC751, 0xC0C1, 0xC752, 0xC0C2, 0xC753, 0xC0C3, 0xC754, 0xC0C4, 0xC755, + 0xC0C5, 0xC756, 0xC0C6, 0xC757, 0xC0C7, 0xC758, 0xC0C8, 0xC75C, 0xC0C9, 0xC760, 0xC0CA, 0xC768, 0xC0CB, 0xC76B, 0xC0CC, 0xC774, + 0xC0CD, 0xC775, 0xC0CE, 0xC778, 0xC0CF, 0xC77C, 0xC0D0, 0xC77D, 0xC0D1, 0xC77E, 0xC0D2, 0xC783, 0xC0D3, 0xC784, 0xC0D4, 0xC785, + 0xC0D5, 0xC787, 0xC0D6, 0xC788, 0xC0D7, 0xC789, 0xC0D8, 0xC78A, 0xC0D9, 0xC78E, 0xC0DA, 0xC790, 0xC0DB, 0xC791, 0xC0DC, 0xC794, + 0xC0DD, 0xC796, 0xC0DE, 0xC797, 0xC0DF, 0xC798, 0xC0E0, 0xC79A, 0xC0E1, 0xC7A0, 0xC0E2, 0xC7A1, 0xC0E3, 0xC7A3, 0xC0E4, 0xC7A4, + 0xC0E5, 0xC7A5, 0xC0E6, 0xC7A6, 0xC0E7, 0xC7AC, 0xC0E8, 0xC7AD, 0xC0E9, 0xC7B0, 0xC0EA, 0xC7B4, 0xC0EB, 0xC7BC, 0xC0EC, 0xC7BD, + 0xC0ED, 0xC7BF, 0xC0EE, 0xC7C0, 0xC0EF, 0xC7C1, 0xC0F0, 0xC7C8, 0xC0F1, 0xC7C9, 0xC0F2, 0xC7CC, 0xC0F3, 0xC7CE, 0xC0F4, 0xC7D0, + 0xC0F5, 0xC7D8, 0xC0F6, 0xC7DD, 0xC0F7, 0xC7E4, 0xC0F8, 0xC7E8, 0xC0F9, 0xC7EC, 0xC0FA, 0xC800, 0xC0FB, 0xC801, 0xC0FC, 0xC804, + 0xC0FD, 0xC808, 0xC0FE, 0xC80A, 0xC141, 0xD564, 0xC142, 0xD566, 0xC143, 0xD567, 0xC144, 0xD56A, 0xC145, 0xD56C, 0xC146, 0xD56E, + 0xC147, 0xD56F, 0xC148, 0xD570, 0xC149, 0xD571, 0xC14A, 0xD572, 0xC14B, 0xD573, 0xC14C, 0xD576, 0xC14D, 0xD577, 0xC14E, 0xD579, + 0xC14F, 0xD57A, 0xC150, 0xD57B, 0xC151, 0xD57D, 0xC152, 0xD57E, 0xC153, 0xD57F, 0xC154, 0xD580, 0xC155, 0xD581, 0xC156, 0xD582, + 0xC157, 0xD583, 0xC158, 0xD586, 0xC159, 0xD58A, 0xC15A, 0xD58B, 0xC161, 0xD58C, 0xC162, 0xD58D, 0xC163, 0xD58E, 0xC164, 0xD58F, + 0xC165, 0xD591, 0xC166, 0xD592, 0xC167, 0xD593, 0xC168, 0xD594, 0xC169, 0xD595, 0xC16A, 0xD596, 0xC16B, 0xD597, 0xC16C, 0xD598, + 0xC16D, 0xD599, 0xC16E, 0xD59A, 0xC16F, 0xD59B, 0xC170, 0xD59C, 0xC171, 0xD59D, 0xC172, 0xD59E, 0xC173, 0xD59F, 0xC174, 0xD5A0, + 0xC175, 0xD5A1, 0xC176, 0xD5A2, 0xC177, 0xD5A3, 0xC178, 0xD5A4, 0xC179, 0xD5A6, 0xC17A, 0xD5A7, 0xC181, 0xD5A8, 0xC182, 0xD5A9, + 0xC183, 0xD5AA, 0xC184, 0xD5AB, 0xC185, 0xD5AC, 0xC186, 0xD5AD, 0xC187, 0xD5AE, 0xC188, 0xD5AF, 0xC189, 0xD5B0, 0xC18A, 0xD5B1, + 0xC18B, 0xD5B2, 0xC18C, 0xD5B3, 0xC18D, 0xD5B4, 0xC18E, 0xD5B5, 0xC18F, 0xD5B6, 0xC190, 0xD5B7, 0xC191, 0xD5B8, 0xC192, 0xD5B9, + 0xC193, 0xD5BA, 0xC194, 0xD5BB, 0xC195, 0xD5BC, 0xC196, 0xD5BD, 0xC197, 0xD5BE, 0xC198, 0xD5BF, 0xC199, 0xD5C0, 0xC19A, 0xD5C1, + 0xC19B, 0xD5C2, 0xC19C, 0xD5C3, 0xC19D, 0xD5C4, 0xC19E, 0xD5C5, 0xC19F, 0xD5C6, 0xC1A0, 0xD5C7, 0xC1A1, 0xC810, 0xC1A2, 0xC811, + 0xC1A3, 0xC813, 0xC1A4, 0xC815, 0xC1A5, 0xC816, 0xC1A6, 0xC81C, 0xC1A7, 0xC81D, 0xC1A8, 0xC820, 0xC1A9, 0xC824, 0xC1AA, 0xC82C, + 0xC1AB, 0xC82D, 0xC1AC, 0xC82F, 0xC1AD, 0xC831, 0xC1AE, 0xC838, 0xC1AF, 0xC83C, 0xC1B0, 0xC840, 0xC1B1, 0xC848, 0xC1B2, 0xC849, + 0xC1B3, 0xC84C, 0xC1B4, 0xC84D, 0xC1B5, 0xC854, 0xC1B6, 0xC870, 0xC1B7, 0xC871, 0xC1B8, 0xC874, 0xC1B9, 0xC878, 0xC1BA, 0xC87A, + 0xC1BB, 0xC880, 0xC1BC, 0xC881, 0xC1BD, 0xC883, 0xC1BE, 0xC885, 0xC1BF, 0xC886, 0xC1C0, 0xC887, 0xC1C1, 0xC88B, 0xC1C2, 0xC88C, + 0xC1C3, 0xC88D, 0xC1C4, 0xC894, 0xC1C5, 0xC89D, 0xC1C6, 0xC89F, 0xC1C7, 0xC8A1, 0xC1C8, 0xC8A8, 0xC1C9, 0xC8BC, 0xC1CA, 0xC8BD, + 0xC1CB, 0xC8C4, 0xC1CC, 0xC8C8, 0xC1CD, 0xC8CC, 0xC1CE, 0xC8D4, 0xC1CF, 0xC8D5, 0xC1D0, 0xC8D7, 0xC1D1, 0xC8D9, 0xC1D2, 0xC8E0, + 0xC1D3, 0xC8E1, 0xC1D4, 0xC8E4, 0xC1D5, 0xC8F5, 0xC1D6, 0xC8FC, 0xC1D7, 0xC8FD, 0xC1D8, 0xC900, 0xC1D9, 0xC904, 0xC1DA, 0xC905, + 0xC1DB, 0xC906, 0xC1DC, 0xC90C, 0xC1DD, 0xC90D, 0xC1DE, 0xC90F, 0xC1DF, 0xC911, 0xC1E0, 0xC918, 0xC1E1, 0xC92C, 0xC1E2, 0xC934, + 0xC1E3, 0xC950, 0xC1E4, 0xC951, 0xC1E5, 0xC954, 0xC1E6, 0xC958, 0xC1E7, 0xC960, 0xC1E8, 0xC961, 0xC1E9, 0xC963, 0xC1EA, 0xC96C, + 0xC1EB, 0xC970, 0xC1EC, 0xC974, 0xC1ED, 0xC97C, 0xC1EE, 0xC988, 0xC1EF, 0xC989, 0xC1F0, 0xC98C, 0xC1F1, 0xC990, 0xC1F2, 0xC998, + 0xC1F3, 0xC999, 0xC1F4, 0xC99B, 0xC1F5, 0xC99D, 0xC1F6, 0xC9C0, 0xC1F7, 0xC9C1, 0xC1F8, 0xC9C4, 0xC1F9, 0xC9C7, 0xC1FA, 0xC9C8, + 0xC1FB, 0xC9CA, 0xC1FC, 0xC9D0, 0xC1FD, 0xC9D1, 0xC1FE, 0xC9D3, 0xC241, 0xD5CA, 0xC242, 0xD5CB, 0xC243, 0xD5CD, 0xC244, 0xD5CE, + 0xC245, 0xD5CF, 0xC246, 0xD5D1, 0xC247, 0xD5D3, 0xC248, 0xD5D4, 0xC249, 0xD5D5, 0xC24A, 0xD5D6, 0xC24B, 0xD5D7, 0xC24C, 0xD5DA, + 0xC24D, 0xD5DC, 0xC24E, 0xD5DE, 0xC24F, 0xD5DF, 0xC250, 0xD5E0, 0xC251, 0xD5E1, 0xC252, 0xD5E2, 0xC253, 0xD5E3, 0xC254, 0xD5E6, + 0xC255, 0xD5E7, 0xC256, 0xD5E9, 0xC257, 0xD5EA, 0xC258, 0xD5EB, 0xC259, 0xD5ED, 0xC25A, 0xD5EE, 0xC261, 0xD5EF, 0xC262, 0xD5F0, + 0xC263, 0xD5F1, 0xC264, 0xD5F2, 0xC265, 0xD5F3, 0xC266, 0xD5F6, 0xC267, 0xD5F8, 0xC268, 0xD5FA, 0xC269, 0xD5FB, 0xC26A, 0xD5FC, + 0xC26B, 0xD5FD, 0xC26C, 0xD5FE, 0xC26D, 0xD5FF, 0xC26E, 0xD602, 0xC26F, 0xD603, 0xC270, 0xD605, 0xC271, 0xD606, 0xC272, 0xD607, + 0xC273, 0xD609, 0xC274, 0xD60A, 0xC275, 0xD60B, 0xC276, 0xD60C, 0xC277, 0xD60D, 0xC278, 0xD60E, 0xC279, 0xD60F, 0xC27A, 0xD612, + 0xC281, 0xD616, 0xC282, 0xD617, 0xC283, 0xD618, 0xC284, 0xD619, 0xC285, 0xD61A, 0xC286, 0xD61B, 0xC287, 0xD61D, 0xC288, 0xD61E, + 0xC289, 0xD61F, 0xC28A, 0xD621, 0xC28B, 0xD622, 0xC28C, 0xD623, 0xC28D, 0xD625, 0xC28E, 0xD626, 0xC28F, 0xD627, 0xC290, 0xD628, + 0xC291, 0xD629, 0xC292, 0xD62A, 0xC293, 0xD62B, 0xC294, 0xD62C, 0xC295, 0xD62E, 0xC296, 0xD62F, 0xC297, 0xD630, 0xC298, 0xD631, + 0xC299, 0xD632, 0xC29A, 0xD633, 0xC29B, 0xD634, 0xC29C, 0xD635, 0xC29D, 0xD636, 0xC29E, 0xD637, 0xC29F, 0xD63A, 0xC2A0, 0xD63B, + 0xC2A1, 0xC9D5, 0xC2A2, 0xC9D6, 0xC2A3, 0xC9D9, 0xC2A4, 0xC9DA, 0xC2A5, 0xC9DC, 0xC2A6, 0xC9DD, 0xC2A7, 0xC9E0, 0xC2A8, 0xC9E2, + 0xC2A9, 0xC9E4, 0xC2AA, 0xC9E7, 0xC2AB, 0xC9EC, 0xC2AC, 0xC9ED, 0xC2AD, 0xC9EF, 0xC2AE, 0xC9F0, 0xC2AF, 0xC9F1, 0xC2B0, 0xC9F8, + 0xC2B1, 0xC9F9, 0xC2B2, 0xC9FC, 0xC2B3, 0xCA00, 0xC2B4, 0xCA08, 0xC2B5, 0xCA09, 0xC2B6, 0xCA0B, 0xC2B7, 0xCA0C, 0xC2B8, 0xCA0D, + 0xC2B9, 0xCA14, 0xC2BA, 0xCA18, 0xC2BB, 0xCA29, 0xC2BC, 0xCA4C, 0xC2BD, 0xCA4D, 0xC2BE, 0xCA50, 0xC2BF, 0xCA54, 0xC2C0, 0xCA5C, + 0xC2C1, 0xCA5D, 0xC2C2, 0xCA5F, 0xC2C3, 0xCA60, 0xC2C4, 0xCA61, 0xC2C5, 0xCA68, 0xC2C6, 0xCA7D, 0xC2C7, 0xCA84, 0xC2C8, 0xCA98, + 0xC2C9, 0xCABC, 0xC2CA, 0xCABD, 0xC2CB, 0xCAC0, 0xC2CC, 0xCAC4, 0xC2CD, 0xCACC, 0xC2CE, 0xCACD, 0xC2CF, 0xCACF, 0xC2D0, 0xCAD1, + 0xC2D1, 0xCAD3, 0xC2D2, 0xCAD8, 0xC2D3, 0xCAD9, 0xC2D4, 0xCAE0, 0xC2D5, 0xCAEC, 0xC2D6, 0xCAF4, 0xC2D7, 0xCB08, 0xC2D8, 0xCB10, + 0xC2D9, 0xCB14, 0xC2DA, 0xCB18, 0xC2DB, 0xCB20, 0xC2DC, 0xCB21, 0xC2DD, 0xCB41, 0xC2DE, 0xCB48, 0xC2DF, 0xCB49, 0xC2E0, 0xCB4C, + 0xC2E1, 0xCB50, 0xC2E2, 0xCB58, 0xC2E3, 0xCB59, 0xC2E4, 0xCB5D, 0xC2E5, 0xCB64, 0xC2E6, 0xCB78, 0xC2E7, 0xCB79, 0xC2E8, 0xCB9C, + 0xC2E9, 0xCBB8, 0xC2EA, 0xCBD4, 0xC2EB, 0xCBE4, 0xC2EC, 0xCBE7, 0xC2ED, 0xCBE9, 0xC2EE, 0xCC0C, 0xC2EF, 0xCC0D, 0xC2F0, 0xCC10, + 0xC2F1, 0xCC14, 0xC2F2, 0xCC1C, 0xC2F3, 0xCC1D, 0xC2F4, 0xCC21, 0xC2F5, 0xCC22, 0xC2F6, 0xCC27, 0xC2F7, 0xCC28, 0xC2F8, 0xCC29, + 0xC2F9, 0xCC2C, 0xC2FA, 0xCC2E, 0xC2FB, 0xCC30, 0xC2FC, 0xCC38, 0xC2FD, 0xCC39, 0xC2FE, 0xCC3B, 0xC341, 0xD63D, 0xC342, 0xD63E, + 0xC343, 0xD63F, 0xC344, 0xD641, 0xC345, 0xD642, 0xC346, 0xD643, 0xC347, 0xD644, 0xC348, 0xD646, 0xC349, 0xD647, 0xC34A, 0xD64A, + 0xC34B, 0xD64C, 0xC34C, 0xD64E, 0xC34D, 0xD64F, 0xC34E, 0xD650, 0xC34F, 0xD652, 0xC350, 0xD653, 0xC351, 0xD656, 0xC352, 0xD657, + 0xC353, 0xD659, 0xC354, 0xD65A, 0xC355, 0xD65B, 0xC356, 0xD65D, 0xC357, 0xD65E, 0xC358, 0xD65F, 0xC359, 0xD660, 0xC35A, 0xD661, + 0xC361, 0xD662, 0xC362, 0xD663, 0xC363, 0xD664, 0xC364, 0xD665, 0xC365, 0xD666, 0xC366, 0xD668, 0xC367, 0xD66A, 0xC368, 0xD66B, + 0xC369, 0xD66C, 0xC36A, 0xD66D, 0xC36B, 0xD66E, 0xC36C, 0xD66F, 0xC36D, 0xD672, 0xC36E, 0xD673, 0xC36F, 0xD675, 0xC370, 0xD676, + 0xC371, 0xD677, 0xC372, 0xD678, 0xC373, 0xD679, 0xC374, 0xD67A, 0xC375, 0xD67B, 0xC376, 0xD67C, 0xC377, 0xD67D, 0xC378, 0xD67E, + 0xC379, 0xD67F, 0xC37A, 0xD680, 0xC381, 0xD681, 0xC382, 0xD682, 0xC383, 0xD684, 0xC384, 0xD686, 0xC385, 0xD687, 0xC386, 0xD688, + 0xC387, 0xD689, 0xC388, 0xD68A, 0xC389, 0xD68B, 0xC38A, 0xD68E, 0xC38B, 0xD68F, 0xC38C, 0xD691, 0xC38D, 0xD692, 0xC38E, 0xD693, + 0xC38F, 0xD695, 0xC390, 0xD696, 0xC391, 0xD697, 0xC392, 0xD698, 0xC393, 0xD699, 0xC394, 0xD69A, 0xC395, 0xD69B, 0xC396, 0xD69C, + 0xC397, 0xD69E, 0xC398, 0xD6A0, 0xC399, 0xD6A2, 0xC39A, 0xD6A3, 0xC39B, 0xD6A4, 0xC39C, 0xD6A5, 0xC39D, 0xD6A6, 0xC39E, 0xD6A7, + 0xC39F, 0xD6A9, 0xC3A0, 0xD6AA, 0xC3A1, 0xCC3C, 0xC3A2, 0xCC3D, 0xC3A3, 0xCC3E, 0xC3A4, 0xCC44, 0xC3A5, 0xCC45, 0xC3A6, 0xCC48, + 0xC3A7, 0xCC4C, 0xC3A8, 0xCC54, 0xC3A9, 0xCC55, 0xC3AA, 0xCC57, 0xC3AB, 0xCC58, 0xC3AC, 0xCC59, 0xC3AD, 0xCC60, 0xC3AE, 0xCC64, + 0xC3AF, 0xCC66, 0xC3B0, 0xCC68, 0xC3B1, 0xCC70, 0xC3B2, 0xCC75, 0xC3B3, 0xCC98, 0xC3B4, 0xCC99, 0xC3B5, 0xCC9C, 0xC3B6, 0xCCA0, + 0xC3B7, 0xCCA8, 0xC3B8, 0xCCA9, 0xC3B9, 0xCCAB, 0xC3BA, 0xCCAC, 0xC3BB, 0xCCAD, 0xC3BC, 0xCCB4, 0xC3BD, 0xCCB5, 0xC3BE, 0xCCB8, + 0xC3BF, 0xCCBC, 0xC3C0, 0xCCC4, 0xC3C1, 0xCCC5, 0xC3C2, 0xCCC7, 0xC3C3, 0xCCC9, 0xC3C4, 0xCCD0, 0xC3C5, 0xCCD4, 0xC3C6, 0xCCE4, + 0xC3C7, 0xCCEC, 0xC3C8, 0xCCF0, 0xC3C9, 0xCD01, 0xC3CA, 0xCD08, 0xC3CB, 0xCD09, 0xC3CC, 0xCD0C, 0xC3CD, 0xCD10, 0xC3CE, 0xCD18, + 0xC3CF, 0xCD19, 0xC3D0, 0xCD1B, 0xC3D1, 0xCD1D, 0xC3D2, 0xCD24, 0xC3D3, 0xCD28, 0xC3D4, 0xCD2C, 0xC3D5, 0xCD39, 0xC3D6, 0xCD5C, + 0xC3D7, 0xCD60, 0xC3D8, 0xCD64, 0xC3D9, 0xCD6C, 0xC3DA, 0xCD6D, 0xC3DB, 0xCD6F, 0xC3DC, 0xCD71, 0xC3DD, 0xCD78, 0xC3DE, 0xCD88, + 0xC3DF, 0xCD94, 0xC3E0, 0xCD95, 0xC3E1, 0xCD98, 0xC3E2, 0xCD9C, 0xC3E3, 0xCDA4, 0xC3E4, 0xCDA5, 0xC3E5, 0xCDA7, 0xC3E6, 0xCDA9, + 0xC3E7, 0xCDB0, 0xC3E8, 0xCDC4, 0xC3E9, 0xCDCC, 0xC3EA, 0xCDD0, 0xC3EB, 0xCDE8, 0xC3EC, 0xCDEC, 0xC3ED, 0xCDF0, 0xC3EE, 0xCDF8, + 0xC3EF, 0xCDF9, 0xC3F0, 0xCDFB, 0xC3F1, 0xCDFD, 0xC3F2, 0xCE04, 0xC3F3, 0xCE08, 0xC3F4, 0xCE0C, 0xC3F5, 0xCE14, 0xC3F6, 0xCE19, + 0xC3F7, 0xCE20, 0xC3F8, 0xCE21, 0xC3F9, 0xCE24, 0xC3FA, 0xCE28, 0xC3FB, 0xCE30, 0xC3FC, 0xCE31, 0xC3FD, 0xCE33, 0xC3FE, 0xCE35, + 0xC441, 0xD6AB, 0xC442, 0xD6AD, 0xC443, 0xD6AE, 0xC444, 0xD6AF, 0xC445, 0xD6B1, 0xC446, 0xD6B2, 0xC447, 0xD6B3, 0xC448, 0xD6B4, + 0xC449, 0xD6B5, 0xC44A, 0xD6B6, 0xC44B, 0xD6B7, 0xC44C, 0xD6B8, 0xC44D, 0xD6BA, 0xC44E, 0xD6BC, 0xC44F, 0xD6BD, 0xC450, 0xD6BE, + 0xC451, 0xD6BF, 0xC452, 0xD6C0, 0xC453, 0xD6C1, 0xC454, 0xD6C2, 0xC455, 0xD6C3, 0xC456, 0xD6C6, 0xC457, 0xD6C7, 0xC458, 0xD6C9, + 0xC459, 0xD6CA, 0xC45A, 0xD6CB, 0xC461, 0xD6CD, 0xC462, 0xD6CE, 0xC463, 0xD6CF, 0xC464, 0xD6D0, 0xC465, 0xD6D2, 0xC466, 0xD6D3, + 0xC467, 0xD6D5, 0xC468, 0xD6D6, 0xC469, 0xD6D8, 0xC46A, 0xD6DA, 0xC46B, 0xD6DB, 0xC46C, 0xD6DC, 0xC46D, 0xD6DD, 0xC46E, 0xD6DE, + 0xC46F, 0xD6DF, 0xC470, 0xD6E1, 0xC471, 0xD6E2, 0xC472, 0xD6E3, 0xC473, 0xD6E5, 0xC474, 0xD6E6, 0xC475, 0xD6E7, 0xC476, 0xD6E9, + 0xC477, 0xD6EA, 0xC478, 0xD6EB, 0xC479, 0xD6EC, 0xC47A, 0xD6ED, 0xC481, 0xD6EE, 0xC482, 0xD6EF, 0xC483, 0xD6F1, 0xC484, 0xD6F2, + 0xC485, 0xD6F3, 0xC486, 0xD6F4, 0xC487, 0xD6F6, 0xC488, 0xD6F7, 0xC489, 0xD6F8, 0xC48A, 0xD6F9, 0xC48B, 0xD6FA, 0xC48C, 0xD6FB, + 0xC48D, 0xD6FE, 0xC48E, 0xD6FF, 0xC48F, 0xD701, 0xC490, 0xD702, 0xC491, 0xD703, 0xC492, 0xD705, 0xC493, 0xD706, 0xC494, 0xD707, + 0xC495, 0xD708, 0xC496, 0xD709, 0xC497, 0xD70A, 0xC498, 0xD70B, 0xC499, 0xD70C, 0xC49A, 0xD70D, 0xC49B, 0xD70E, 0xC49C, 0xD70F, + 0xC49D, 0xD710, 0xC49E, 0xD712, 0xC49F, 0xD713, 0xC4A0, 0xD714, 0xC4A1, 0xCE58, 0xC4A2, 0xCE59, 0xC4A3, 0xCE5C, 0xC4A4, 0xCE5F, + 0xC4A5, 0xCE60, 0xC4A6, 0xCE61, 0xC4A7, 0xCE68, 0xC4A8, 0xCE69, 0xC4A9, 0xCE6B, 0xC4AA, 0xCE6D, 0xC4AB, 0xCE74, 0xC4AC, 0xCE75, + 0xC4AD, 0xCE78, 0xC4AE, 0xCE7C, 0xC4AF, 0xCE84, 0xC4B0, 0xCE85, 0xC4B1, 0xCE87, 0xC4B2, 0xCE89, 0xC4B3, 0xCE90, 0xC4B4, 0xCE91, + 0xC4B5, 0xCE94, 0xC4B6, 0xCE98, 0xC4B7, 0xCEA0, 0xC4B8, 0xCEA1, 0xC4B9, 0xCEA3, 0xC4BA, 0xCEA4, 0xC4BB, 0xCEA5, 0xC4BC, 0xCEAC, + 0xC4BD, 0xCEAD, 0xC4BE, 0xCEC1, 0xC4BF, 0xCEE4, 0xC4C0, 0xCEE5, 0xC4C1, 0xCEE8, 0xC4C2, 0xCEEB, 0xC4C3, 0xCEEC, 0xC4C4, 0xCEF4, + 0xC4C5, 0xCEF5, 0xC4C6, 0xCEF7, 0xC4C7, 0xCEF8, 0xC4C8, 0xCEF9, 0xC4C9, 0xCF00, 0xC4CA, 0xCF01, 0xC4CB, 0xCF04, 0xC4CC, 0xCF08, + 0xC4CD, 0xCF10, 0xC4CE, 0xCF11, 0xC4CF, 0xCF13, 0xC4D0, 0xCF15, 0xC4D1, 0xCF1C, 0xC4D2, 0xCF20, 0xC4D3, 0xCF24, 0xC4D4, 0xCF2C, + 0xC4D5, 0xCF2D, 0xC4D6, 0xCF2F, 0xC4D7, 0xCF30, 0xC4D8, 0xCF31, 0xC4D9, 0xCF38, 0xC4DA, 0xCF54, 0xC4DB, 0xCF55, 0xC4DC, 0xCF58, + 0xC4DD, 0xCF5C, 0xC4DE, 0xCF64, 0xC4DF, 0xCF65, 0xC4E0, 0xCF67, 0xC4E1, 0xCF69, 0xC4E2, 0xCF70, 0xC4E3, 0xCF71, 0xC4E4, 0xCF74, + 0xC4E5, 0xCF78, 0xC4E6, 0xCF80, 0xC4E7, 0xCF85, 0xC4E8, 0xCF8C, 0xC4E9, 0xCFA1, 0xC4EA, 0xCFA8, 0xC4EB, 0xCFB0, 0xC4EC, 0xCFC4, + 0xC4ED, 0xCFE0, 0xC4EE, 0xCFE1, 0xC4EF, 0xCFE4, 0xC4F0, 0xCFE8, 0xC4F1, 0xCFF0, 0xC4F2, 0xCFF1, 0xC4F3, 0xCFF3, 0xC4F4, 0xCFF5, + 0xC4F5, 0xCFFC, 0xC4F6, 0xD000, 0xC4F7, 0xD004, 0xC4F8, 0xD011, 0xC4F9, 0xD018, 0xC4FA, 0xD02D, 0xC4FB, 0xD034, 0xC4FC, 0xD035, + 0xC4FD, 0xD038, 0xC4FE, 0xD03C, 0xC541, 0xD715, 0xC542, 0xD716, 0xC543, 0xD717, 0xC544, 0xD71A, 0xC545, 0xD71B, 0xC546, 0xD71D, + 0xC547, 0xD71E, 0xC548, 0xD71F, 0xC549, 0xD721, 0xC54A, 0xD722, 0xC54B, 0xD723, 0xC54C, 0xD724, 0xC54D, 0xD725, 0xC54E, 0xD726, + 0xC54F, 0xD727, 0xC550, 0xD72A, 0xC551, 0xD72C, 0xC552, 0xD72E, 0xC553, 0xD72F, 0xC554, 0xD730, 0xC555, 0xD731, 0xC556, 0xD732, + 0xC557, 0xD733, 0xC558, 0xD736, 0xC559, 0xD737, 0xC55A, 0xD739, 0xC561, 0xD73A, 0xC562, 0xD73B, 0xC563, 0xD73D, 0xC564, 0xD73E, + 0xC565, 0xD73F, 0xC566, 0xD740, 0xC567, 0xD741, 0xC568, 0xD742, 0xC569, 0xD743, 0xC56A, 0xD745, 0xC56B, 0xD746, 0xC56C, 0xD748, + 0xC56D, 0xD74A, 0xC56E, 0xD74B, 0xC56F, 0xD74C, 0xC570, 0xD74D, 0xC571, 0xD74E, 0xC572, 0xD74F, 0xC573, 0xD752, 0xC574, 0xD753, + 0xC575, 0xD755, 0xC576, 0xD75A, 0xC577, 0xD75B, 0xC578, 0xD75C, 0xC579, 0xD75D, 0xC57A, 0xD75E, 0xC581, 0xD75F, 0xC582, 0xD762, + 0xC583, 0xD764, 0xC584, 0xD766, 0xC585, 0xD767, 0xC586, 0xD768, 0xC587, 0xD76A, 0xC588, 0xD76B, 0xC589, 0xD76D, 0xC58A, 0xD76E, + 0xC58B, 0xD76F, 0xC58C, 0xD771, 0xC58D, 0xD772, 0xC58E, 0xD773, 0xC58F, 0xD775, 0xC590, 0xD776, 0xC591, 0xD777, 0xC592, 0xD778, + 0xC593, 0xD779, 0xC594, 0xD77A, 0xC595, 0xD77B, 0xC596, 0xD77E, 0xC597, 0xD77F, 0xC598, 0xD780, 0xC599, 0xD782, 0xC59A, 0xD783, + 0xC59B, 0xD784, 0xC59C, 0xD785, 0xC59D, 0xD786, 0xC59E, 0xD787, 0xC59F, 0xD78A, 0xC5A0, 0xD78B, 0xC5A1, 0xD044, 0xC5A2, 0xD045, + 0xC5A3, 0xD047, 0xC5A4, 0xD049, 0xC5A5, 0xD050, 0xC5A6, 0xD054, 0xC5A7, 0xD058, 0xC5A8, 0xD060, 0xC5A9, 0xD06C, 0xC5AA, 0xD06D, + 0xC5AB, 0xD070, 0xC5AC, 0xD074, 0xC5AD, 0xD07C, 0xC5AE, 0xD07D, 0xC5AF, 0xD081, 0xC5B0, 0xD0A4, 0xC5B1, 0xD0A5, 0xC5B2, 0xD0A8, + 0xC5B3, 0xD0AC, 0xC5B4, 0xD0B4, 0xC5B5, 0xD0B5, 0xC5B6, 0xD0B7, 0xC5B7, 0xD0B9, 0xC5B8, 0xD0C0, 0xC5B9, 0xD0C1, 0xC5BA, 0xD0C4, + 0xC5BB, 0xD0C8, 0xC5BC, 0xD0C9, 0xC5BD, 0xD0D0, 0xC5BE, 0xD0D1, 0xC5BF, 0xD0D3, 0xC5C0, 0xD0D4, 0xC5C1, 0xD0D5, 0xC5C2, 0xD0DC, + 0xC5C3, 0xD0DD, 0xC5C4, 0xD0E0, 0xC5C5, 0xD0E4, 0xC5C6, 0xD0EC, 0xC5C7, 0xD0ED, 0xC5C8, 0xD0EF, 0xC5C9, 0xD0F0, 0xC5CA, 0xD0F1, + 0xC5CB, 0xD0F8, 0xC5CC, 0xD10D, 0xC5CD, 0xD130, 0xC5CE, 0xD131, 0xC5CF, 0xD134, 0xC5D0, 0xD138, 0xC5D1, 0xD13A, 0xC5D2, 0xD140, + 0xC5D3, 0xD141, 0xC5D4, 0xD143, 0xC5D5, 0xD144, 0xC5D6, 0xD145, 0xC5D7, 0xD14C, 0xC5D8, 0xD14D, 0xC5D9, 0xD150, 0xC5DA, 0xD154, + 0xC5DB, 0xD15C, 0xC5DC, 0xD15D, 0xC5DD, 0xD15F, 0xC5DE, 0xD161, 0xC5DF, 0xD168, 0xC5E0, 0xD16C, 0xC5E1, 0xD17C, 0xC5E2, 0xD184, + 0xC5E3, 0xD188, 0xC5E4, 0xD1A0, 0xC5E5, 0xD1A1, 0xC5E6, 0xD1A4, 0xC5E7, 0xD1A8, 0xC5E8, 0xD1B0, 0xC5E9, 0xD1B1, 0xC5EA, 0xD1B3, + 0xC5EB, 0xD1B5, 0xC5EC, 0xD1BA, 0xC5ED, 0xD1BC, 0xC5EE, 0xD1C0, 0xC5EF, 0xD1D8, 0xC5F0, 0xD1F4, 0xC5F1, 0xD1F8, 0xC5F2, 0xD207, + 0xC5F3, 0xD209, 0xC5F4, 0xD210, 0xC5F5, 0xD22C, 0xC5F6, 0xD22D, 0xC5F7, 0xD230, 0xC5F8, 0xD234, 0xC5F9, 0xD23C, 0xC5FA, 0xD23D, + 0xC5FB, 0xD23F, 0xC5FC, 0xD241, 0xC5FD, 0xD248, 0xC5FE, 0xD25C, 0xC641, 0xD78D, 0xC642, 0xD78E, 0xC643, 0xD78F, 0xC644, 0xD791, + 0xC645, 0xD792, 0xC646, 0xD793, 0xC647, 0xD794, 0xC648, 0xD795, 0xC649, 0xD796, 0xC64A, 0xD797, 0xC64B, 0xD79A, 0xC64C, 0xD79C, + 0xC64D, 0xD79E, 0xC64E, 0xD79F, 0xC64F, 0xD7A0, 0xC650, 0xD7A1, 0xC651, 0xD7A2, 0xC652, 0xD7A3, 0xC6A1, 0xD264, 0xC6A2, 0xD280, + 0xC6A3, 0xD281, 0xC6A4, 0xD284, 0xC6A5, 0xD288, 0xC6A6, 0xD290, 0xC6A7, 0xD291, 0xC6A8, 0xD295, 0xC6A9, 0xD29C, 0xC6AA, 0xD2A0, + 0xC6AB, 0xD2A4, 0xC6AC, 0xD2AC, 0xC6AD, 0xD2B1, 0xC6AE, 0xD2B8, 0xC6AF, 0xD2B9, 0xC6B0, 0xD2BC, 0xC6B1, 0xD2BF, 0xC6B2, 0xD2C0, + 0xC6B3, 0xD2C2, 0xC6B4, 0xD2C8, 0xC6B5, 0xD2C9, 0xC6B6, 0xD2CB, 0xC6B7, 0xD2D4, 0xC6B8, 0xD2D8, 0xC6B9, 0xD2DC, 0xC6BA, 0xD2E4, + 0xC6BB, 0xD2E5, 0xC6BC, 0xD2F0, 0xC6BD, 0xD2F1, 0xC6BE, 0xD2F4, 0xC6BF, 0xD2F8, 0xC6C0, 0xD300, 0xC6C1, 0xD301, 0xC6C2, 0xD303, + 0xC6C3, 0xD305, 0xC6C4, 0xD30C, 0xC6C5, 0xD30D, 0xC6C6, 0xD30E, 0xC6C7, 0xD310, 0xC6C8, 0xD314, 0xC6C9, 0xD316, 0xC6CA, 0xD31C, + 0xC6CB, 0xD31D, 0xC6CC, 0xD31F, 0xC6CD, 0xD320, 0xC6CE, 0xD321, 0xC6CF, 0xD325, 0xC6D0, 0xD328, 0xC6D1, 0xD329, 0xC6D2, 0xD32C, + 0xC6D3, 0xD330, 0xC6D4, 0xD338, 0xC6D5, 0xD339, 0xC6D6, 0xD33B, 0xC6D7, 0xD33C, 0xC6D8, 0xD33D, 0xC6D9, 0xD344, 0xC6DA, 0xD345, + 0xC6DB, 0xD37C, 0xC6DC, 0xD37D, 0xC6DD, 0xD380, 0xC6DE, 0xD384, 0xC6DF, 0xD38C, 0xC6E0, 0xD38D, 0xC6E1, 0xD38F, 0xC6E2, 0xD390, + 0xC6E3, 0xD391, 0xC6E4, 0xD398, 0xC6E5, 0xD399, 0xC6E6, 0xD39C, 0xC6E7, 0xD3A0, 0xC6E8, 0xD3A8, 0xC6E9, 0xD3A9, 0xC6EA, 0xD3AB, + 0xC6EB, 0xD3AD, 0xC6EC, 0xD3B4, 0xC6ED, 0xD3B8, 0xC6EE, 0xD3BC, 0xC6EF, 0xD3C4, 0xC6F0, 0xD3C5, 0xC6F1, 0xD3C8, 0xC6F2, 0xD3C9, + 0xC6F3, 0xD3D0, 0xC6F4, 0xD3D8, 0xC6F5, 0xD3E1, 0xC6F6, 0xD3E3, 0xC6F7, 0xD3EC, 0xC6F8, 0xD3ED, 0xC6F9, 0xD3F0, 0xC6FA, 0xD3F4, + 0xC6FB, 0xD3FC, 0xC6FC, 0xD3FD, 0xC6FD, 0xD3FF, 0xC6FE, 0xD401, 0xC7A1, 0xD408, 0xC7A2, 0xD41D, 0xC7A3, 0xD440, 0xC7A4, 0xD444, + 0xC7A5, 0xD45C, 0xC7A6, 0xD460, 0xC7A7, 0xD464, 0xC7A8, 0xD46D, 0xC7A9, 0xD46F, 0xC7AA, 0xD478, 0xC7AB, 0xD479, 0xC7AC, 0xD47C, + 0xC7AD, 0xD47F, 0xC7AE, 0xD480, 0xC7AF, 0xD482, 0xC7B0, 0xD488, 0xC7B1, 0xD489, 0xC7B2, 0xD48B, 0xC7B3, 0xD48D, 0xC7B4, 0xD494, + 0xC7B5, 0xD4A9, 0xC7B6, 0xD4CC, 0xC7B7, 0xD4D0, 0xC7B8, 0xD4D4, 0xC7B9, 0xD4DC, 0xC7BA, 0xD4DF, 0xC7BB, 0xD4E8, 0xC7BC, 0xD4EC, + 0xC7BD, 0xD4F0, 0xC7BE, 0xD4F8, 0xC7BF, 0xD4FB, 0xC7C0, 0xD4FD, 0xC7C1, 0xD504, 0xC7C2, 0xD508, 0xC7C3, 0xD50C, 0xC7C4, 0xD514, + 0xC7C5, 0xD515, 0xC7C6, 0xD517, 0xC7C7, 0xD53C, 0xC7C8, 0xD53D, 0xC7C9, 0xD540, 0xC7CA, 0xD544, 0xC7CB, 0xD54C, 0xC7CC, 0xD54D, + 0xC7CD, 0xD54F, 0xC7CE, 0xD551, 0xC7CF, 0xD558, 0xC7D0, 0xD559, 0xC7D1, 0xD55C, 0xC7D2, 0xD560, 0xC7D3, 0xD565, 0xC7D4, 0xD568, + 0xC7D5, 0xD569, 0xC7D6, 0xD56B, 0xC7D7, 0xD56D, 0xC7D8, 0xD574, 0xC7D9, 0xD575, 0xC7DA, 0xD578, 0xC7DB, 0xD57C, 0xC7DC, 0xD584, + 0xC7DD, 0xD585, 0xC7DE, 0xD587, 0xC7DF, 0xD588, 0xC7E0, 0xD589, 0xC7E1, 0xD590, 0xC7E2, 0xD5A5, 0xC7E3, 0xD5C8, 0xC7E4, 0xD5C9, + 0xC7E5, 0xD5CC, 0xC7E6, 0xD5D0, 0xC7E7, 0xD5D2, 0xC7E8, 0xD5D8, 0xC7E9, 0xD5D9, 0xC7EA, 0xD5DB, 0xC7EB, 0xD5DD, 0xC7EC, 0xD5E4, + 0xC7ED, 0xD5E5, 0xC7EE, 0xD5E8, 0xC7EF, 0xD5EC, 0xC7F0, 0xD5F4, 0xC7F1, 0xD5F5, 0xC7F2, 0xD5F7, 0xC7F3, 0xD5F9, 0xC7F4, 0xD600, + 0xC7F5, 0xD601, 0xC7F6, 0xD604, 0xC7F7, 0xD608, 0xC7F8, 0xD610, 0xC7F9, 0xD611, 0xC7FA, 0xD613, 0xC7FB, 0xD614, 0xC7FC, 0xD615, + 0xC7FD, 0xD61C, 0xC7FE, 0xD620, 0xC8A1, 0xD624, 0xC8A2, 0xD62D, 0xC8A3, 0xD638, 0xC8A4, 0xD639, 0xC8A5, 0xD63C, 0xC8A6, 0xD640, + 0xC8A7, 0xD645, 0xC8A8, 0xD648, 0xC8A9, 0xD649, 0xC8AA, 0xD64B, 0xC8AB, 0xD64D, 0xC8AC, 0xD651, 0xC8AD, 0xD654, 0xC8AE, 0xD655, + 0xC8AF, 0xD658, 0xC8B0, 0xD65C, 0xC8B1, 0xD667, 0xC8B2, 0xD669, 0xC8B3, 0xD670, 0xC8B4, 0xD671, 0xC8B5, 0xD674, 0xC8B6, 0xD683, + 0xC8B7, 0xD685, 0xC8B8, 0xD68C, 0xC8B9, 0xD68D, 0xC8BA, 0xD690, 0xC8BB, 0xD694, 0xC8BC, 0xD69D, 0xC8BD, 0xD69F, 0xC8BE, 0xD6A1, + 0xC8BF, 0xD6A8, 0xC8C0, 0xD6AC, 0xC8C1, 0xD6B0, 0xC8C2, 0xD6B9, 0xC8C3, 0xD6BB, 0xC8C4, 0xD6C4, 0xC8C5, 0xD6C5, 0xC8C6, 0xD6C8, + 0xC8C7, 0xD6CC, 0xC8C8, 0xD6D1, 0xC8C9, 0xD6D4, 0xC8CA, 0xD6D7, 0xC8CB, 0xD6D9, 0xC8CC, 0xD6E0, 0xC8CD, 0xD6E4, 0xC8CE, 0xD6E8, + 0xC8CF, 0xD6F0, 0xC8D0, 0xD6F5, 0xC8D1, 0xD6FC, 0xC8D2, 0xD6FD, 0xC8D3, 0xD700, 0xC8D4, 0xD704, 0xC8D5, 0xD711, 0xC8D6, 0xD718, + 0xC8D7, 0xD719, 0xC8D8, 0xD71C, 0xC8D9, 0xD720, 0xC8DA, 0xD728, 0xC8DB, 0xD729, 0xC8DC, 0xD72B, 0xC8DD, 0xD72D, 0xC8DE, 0xD734, + 0xC8DF, 0xD735, 0xC8E0, 0xD738, 0xC8E1, 0xD73C, 0xC8E2, 0xD744, 0xC8E3, 0xD747, 0xC8E4, 0xD749, 0xC8E5, 0xD750, 0xC8E6, 0xD751, + 0xC8E7, 0xD754, 0xC8E8, 0xD756, 0xC8E9, 0xD757, 0xC8EA, 0xD758, 0xC8EB, 0xD759, 0xC8EC, 0xD760, 0xC8ED, 0xD761, 0xC8EE, 0xD763, + 0xC8EF, 0xD765, 0xC8F0, 0xD769, 0xC8F1, 0xD76C, 0xC8F2, 0xD770, 0xC8F3, 0xD774, 0xC8F4, 0xD77C, 0xC8F5, 0xD77D, 0xC8F6, 0xD781, + 0xC8F7, 0xD788, 0xC8F8, 0xD789, 0xC8F9, 0xD78C, 0xC8FA, 0xD790, 0xC8FB, 0xD798, 0xC8FC, 0xD799, 0xC8FD, 0xD79B, 0xC8FE, 0xD79D, + 0xCAA1, 0x4F3D, 0xCAA2, 0x4F73, 0xCAA3, 0x5047, 0xCAA4, 0x50F9, 0xCAA5, 0x52A0, 0xCAA6, 0x53EF, 0xCAA7, 0x5475, 0xCAA8, 0x54E5, + 0xCAA9, 0x5609, 0xCAAA, 0x5AC1, 0xCAAB, 0x5BB6, 0xCAAC, 0x6687, 0xCAAD, 0x67B6, 0xCAAE, 0x67B7, 0xCAAF, 0x67EF, 0xCAB0, 0x6B4C, + 0xCAB1, 0x73C2, 0xCAB2, 0x75C2, 0xCAB3, 0x7A3C, 0xCAB4, 0x82DB, 0xCAB5, 0x8304, 0xCAB6, 0x8857, 0xCAB7, 0x8888, 0xCAB8, 0x8A36, + 0xCAB9, 0x8CC8, 0xCABA, 0x8DCF, 0xCABB, 0x8EFB, 0xCABC, 0x8FE6, 0xCABD, 0x99D5, 0xCABE, 0x523B, 0xCABF, 0x5374, 0xCAC0, 0x5404, + 0xCAC1, 0x606A, 0xCAC2, 0x6164, 0xCAC3, 0x6BBC, 0xCAC4, 0x73CF, 0xCAC5, 0x811A, 0xCAC6, 0x89BA, 0xCAC7, 0x89D2, 0xCAC8, 0x95A3, + 0xCAC9, 0x4F83, 0xCACA, 0x520A, 0xCACB, 0x58BE, 0xCACC, 0x5978, 0xCACD, 0x59E6, 0xCACE, 0x5E72, 0xCACF, 0x5E79, 0xCAD0, 0x61C7, + 0xCAD1, 0x63C0, 0xCAD2, 0x6746, 0xCAD3, 0x67EC, 0xCAD4, 0x687F, 0xCAD5, 0x6F97, 0xCAD6, 0x764E, 0xCAD7, 0x770B, 0xCAD8, 0x78F5, + 0xCAD9, 0x7A08, 0xCADA, 0x7AFF, 0xCADB, 0x7C21, 0xCADC, 0x809D, 0xCADD, 0x826E, 0xCADE, 0x8271, 0xCADF, 0x8AEB, 0xCAE0, 0x9593, + 0xCAE1, 0x4E6B, 0xCAE2, 0x559D, 0xCAE3, 0x66F7, 0xCAE4, 0x6E34, 0xCAE5, 0x78A3, 0xCAE6, 0x7AED, 0xCAE7, 0x845B, 0xCAE8, 0x8910, + 0xCAE9, 0x874E, 0xCAEA, 0x97A8, 0xCAEB, 0x52D8, 0xCAEC, 0x574E, 0xCAED, 0x582A, 0xCAEE, 0x5D4C, 0xCAEF, 0x611F, 0xCAF0, 0x61BE, + 0xCAF1, 0x6221, 0xCAF2, 0x6562, 0xCAF3, 0x67D1, 0xCAF4, 0x6A44, 0xCAF5, 0x6E1B, 0xCAF6, 0x7518, 0xCAF7, 0x75B3, 0xCAF8, 0x76E3, + 0xCAF9, 0x77B0, 0xCAFA, 0x7D3A, 0xCAFB, 0x90AF, 0xCAFC, 0x9451, 0xCAFD, 0x9452, 0xCAFE, 0x9F95, 0xCBA1, 0x5323, 0xCBA2, 0x5CAC, + 0xCBA3, 0x7532, 0xCBA4, 0x80DB, 0xCBA5, 0x9240, 0xCBA6, 0x9598, 0xCBA7, 0x525B, 0xCBA8, 0x5808, 0xCBA9, 0x59DC, 0xCBAA, 0x5CA1, + 0xCBAB, 0x5D17, 0xCBAC, 0x5EB7, 0xCBAD, 0x5F3A, 0xCBAE, 0x5F4A, 0xCBAF, 0x6177, 0xCBB0, 0x6C5F, 0xCBB1, 0x757A, 0xCBB2, 0x7586, + 0xCBB3, 0x7CE0, 0xCBB4, 0x7D73, 0xCBB5, 0x7DB1, 0xCBB6, 0x7F8C, 0xCBB7, 0x8154, 0xCBB8, 0x8221, 0xCBB9, 0x8591, 0xCBBA, 0x8941, + 0xCBBB, 0x8B1B, 0xCBBC, 0x92FC, 0xCBBD, 0x964D, 0xCBBE, 0x9C47, 0xCBBF, 0x4ECB, 0xCBC0, 0x4EF7, 0xCBC1, 0x500B, 0xCBC2, 0x51F1, + 0xCBC3, 0x584F, 0xCBC4, 0x6137, 0xCBC5, 0x613E, 0xCBC6, 0x6168, 0xCBC7, 0x6539, 0xCBC8, 0x69EA, 0xCBC9, 0x6F11, 0xCBCA, 0x75A5, + 0xCBCB, 0x7686, 0xCBCC, 0x76D6, 0xCBCD, 0x7B87, 0xCBCE, 0x82A5, 0xCBCF, 0x84CB, 0xCBD0, 0xF900, 0xCBD1, 0x93A7, 0xCBD2, 0x958B, + 0xCBD3, 0x5580, 0xCBD4, 0x5BA2, 0xCBD5, 0x5751, 0xCBD6, 0xF901, 0xCBD7, 0x7CB3, 0xCBD8, 0x7FB9, 0xCBD9, 0x91B5, 0xCBDA, 0x5028, + 0xCBDB, 0x53BB, 0xCBDC, 0x5C45, 0xCBDD, 0x5DE8, 0xCBDE, 0x62D2, 0xCBDF, 0x636E, 0xCBE0, 0x64DA, 0xCBE1, 0x64E7, 0xCBE2, 0x6E20, + 0xCBE3, 0x70AC, 0xCBE4, 0x795B, 0xCBE5, 0x8DDD, 0xCBE6, 0x8E1E, 0xCBE7, 0xF902, 0xCBE8, 0x907D, 0xCBE9, 0x9245, 0xCBEA, 0x92F8, + 0xCBEB, 0x4E7E, 0xCBEC, 0x4EF6, 0xCBED, 0x5065, 0xCBEE, 0x5DFE, 0xCBEF, 0x5EFA, 0xCBF0, 0x6106, 0xCBF1, 0x6957, 0xCBF2, 0x8171, + 0xCBF3, 0x8654, 0xCBF4, 0x8E47, 0xCBF5, 0x9375, 0xCBF6, 0x9A2B, 0xCBF7, 0x4E5E, 0xCBF8, 0x5091, 0xCBF9, 0x6770, 0xCBFA, 0x6840, + 0xCBFB, 0x5109, 0xCBFC, 0x528D, 0xCBFD, 0x5292, 0xCBFE, 0x6AA2, 0xCCA1, 0x77BC, 0xCCA2, 0x9210, 0xCCA3, 0x9ED4, 0xCCA4, 0x52AB, + 0xCCA5, 0x602F, 0xCCA6, 0x8FF2, 0xCCA7, 0x5048, 0xCCA8, 0x61A9, 0xCCA9, 0x63ED, 0xCCAA, 0x64CA, 0xCCAB, 0x683C, 0xCCAC, 0x6A84, + 0xCCAD, 0x6FC0, 0xCCAE, 0x8188, 0xCCAF, 0x89A1, 0xCCB0, 0x9694, 0xCCB1, 0x5805, 0xCCB2, 0x727D, 0xCCB3, 0x72AC, 0xCCB4, 0x7504, + 0xCCB5, 0x7D79, 0xCCB6, 0x7E6D, 0xCCB7, 0x80A9, 0xCCB8, 0x898B, 0xCCB9, 0x8B74, 0xCCBA, 0x9063, 0xCCBB, 0x9D51, 0xCCBC, 0x6289, + 0xCCBD, 0x6C7A, 0xCCBE, 0x6F54, 0xCCBF, 0x7D50, 0xCCC0, 0x7F3A, 0xCCC1, 0x8A23, 0xCCC2, 0x517C, 0xCCC3, 0x614A, 0xCCC4, 0x7B9D, + 0xCCC5, 0x8B19, 0xCCC6, 0x9257, 0xCCC7, 0x938C, 0xCCC8, 0x4EAC, 0xCCC9, 0x4FD3, 0xCCCA, 0x501E, 0xCCCB, 0x50BE, 0xCCCC, 0x5106, + 0xCCCD, 0x52C1, 0xCCCE, 0x52CD, 0xCCCF, 0x537F, 0xCCD0, 0x5770, 0xCCD1, 0x5883, 0xCCD2, 0x5E9A, 0xCCD3, 0x5F91, 0xCCD4, 0x6176, + 0xCCD5, 0x61AC, 0xCCD6, 0x64CE, 0xCCD7, 0x656C, 0xCCD8, 0x666F, 0xCCD9, 0x66BB, 0xCCDA, 0x66F4, 0xCCDB, 0x6897, 0xCCDC, 0x6D87, + 0xCCDD, 0x7085, 0xCCDE, 0x70F1, 0xCCDF, 0x749F, 0xCCE0, 0x74A5, 0xCCE1, 0x74CA, 0xCCE2, 0x75D9, 0xCCE3, 0x786C, 0xCCE4, 0x78EC, + 0xCCE5, 0x7ADF, 0xCCE6, 0x7AF6, 0xCCE7, 0x7D45, 0xCCE8, 0x7D93, 0xCCE9, 0x8015, 0xCCEA, 0x803F, 0xCCEB, 0x811B, 0xCCEC, 0x8396, + 0xCCED, 0x8B66, 0xCCEE, 0x8F15, 0xCCEF, 0x9015, 0xCCF0, 0x93E1, 0xCCF1, 0x9803, 0xCCF2, 0x9838, 0xCCF3, 0x9A5A, 0xCCF4, 0x9BE8, + 0xCCF5, 0x4FC2, 0xCCF6, 0x5553, 0xCCF7, 0x583A, 0xCCF8, 0x5951, 0xCCF9, 0x5B63, 0xCCFA, 0x5C46, 0xCCFB, 0x60B8, 0xCCFC, 0x6212, + 0xCCFD, 0x6842, 0xCCFE, 0x68B0, 0xCDA1, 0x68E8, 0xCDA2, 0x6EAA, 0xCDA3, 0x754C, 0xCDA4, 0x7678, 0xCDA5, 0x78CE, 0xCDA6, 0x7A3D, + 0xCDA7, 0x7CFB, 0xCDA8, 0x7E6B, 0xCDA9, 0x7E7C, 0xCDAA, 0x8A08, 0xCDAB, 0x8AA1, 0xCDAC, 0x8C3F, 0xCDAD, 0x968E, 0xCDAE, 0x9DC4, + 0xCDAF, 0x53E4, 0xCDB0, 0x53E9, 0xCDB1, 0x544A, 0xCDB2, 0x5471, 0xCDB3, 0x56FA, 0xCDB4, 0x59D1, 0xCDB5, 0x5B64, 0xCDB6, 0x5C3B, + 0xCDB7, 0x5EAB, 0xCDB8, 0x62F7, 0xCDB9, 0x6537, 0xCDBA, 0x6545, 0xCDBB, 0x6572, 0xCDBC, 0x66A0, 0xCDBD, 0x67AF, 0xCDBE, 0x69C1, + 0xCDBF, 0x6CBD, 0xCDC0, 0x75FC, 0xCDC1, 0x7690, 0xCDC2, 0x777E, 0xCDC3, 0x7A3F, 0xCDC4, 0x7F94, 0xCDC5, 0x8003, 0xCDC6, 0x80A1, + 0xCDC7, 0x818F, 0xCDC8, 0x82E6, 0xCDC9, 0x82FD, 0xCDCA, 0x83F0, 0xCDCB, 0x85C1, 0xCDCC, 0x8831, 0xCDCD, 0x88B4, 0xCDCE, 0x8AA5, + 0xCDCF, 0xF903, 0xCDD0, 0x8F9C, 0xCDD1, 0x932E, 0xCDD2, 0x96C7, 0xCDD3, 0x9867, 0xCDD4, 0x9AD8, 0xCDD5, 0x9F13, 0xCDD6, 0x54ED, + 0xCDD7, 0x659B, 0xCDD8, 0x66F2, 0xCDD9, 0x688F, 0xCDDA, 0x7A40, 0xCDDB, 0x8C37, 0xCDDC, 0x9D60, 0xCDDD, 0x56F0, 0xCDDE, 0x5764, + 0xCDDF, 0x5D11, 0xCDE0, 0x6606, 0xCDE1, 0x68B1, 0xCDE2, 0x68CD, 0xCDE3, 0x6EFE, 0xCDE4, 0x7428, 0xCDE5, 0x889E, 0xCDE6, 0x9BE4, + 0xCDE7, 0x6C68, 0xCDE8, 0xF904, 0xCDE9, 0x9AA8, 0xCDEA, 0x4F9B, 0xCDEB, 0x516C, 0xCDEC, 0x5171, 0xCDED, 0x529F, 0xCDEE, 0x5B54, + 0xCDEF, 0x5DE5, 0xCDF0, 0x6050, 0xCDF1, 0x606D, 0xCDF2, 0x62F1, 0xCDF3, 0x63A7, 0xCDF4, 0x653B, 0xCDF5, 0x73D9, 0xCDF6, 0x7A7A, + 0xCDF7, 0x86A3, 0xCDF8, 0x8CA2, 0xCDF9, 0x978F, 0xCDFA, 0x4E32, 0xCDFB, 0x5BE1, 0xCDFC, 0x6208, 0xCDFD, 0x679C, 0xCDFE, 0x74DC, + 0xCEA1, 0x79D1, 0xCEA2, 0x83D3, 0xCEA3, 0x8A87, 0xCEA4, 0x8AB2, 0xCEA5, 0x8DE8, 0xCEA6, 0x904E, 0xCEA7, 0x934B, 0xCEA8, 0x9846, + 0xCEA9, 0x5ED3, 0xCEAA, 0x69E8, 0xCEAB, 0x85FF, 0xCEAC, 0x90ED, 0xCEAD, 0xF905, 0xCEAE, 0x51A0, 0xCEAF, 0x5B98, 0xCEB0, 0x5BEC, + 0xCEB1, 0x6163, 0xCEB2, 0x68FA, 0xCEB3, 0x6B3E, 0xCEB4, 0x704C, 0xCEB5, 0x742F, 0xCEB6, 0x74D8, 0xCEB7, 0x7BA1, 0xCEB8, 0x7F50, + 0xCEB9, 0x83C5, 0xCEBA, 0x89C0, 0xCEBB, 0x8CAB, 0xCEBC, 0x95DC, 0xCEBD, 0x9928, 0xCEBE, 0x522E, 0xCEBF, 0x605D, 0xCEC0, 0x62EC, + 0xCEC1, 0x9002, 0xCEC2, 0x4F8A, 0xCEC3, 0x5149, 0xCEC4, 0x5321, 0xCEC5, 0x58D9, 0xCEC6, 0x5EE3, 0xCEC7, 0x66E0, 0xCEC8, 0x6D38, + 0xCEC9, 0x709A, 0xCECA, 0x72C2, 0xCECB, 0x73D6, 0xCECC, 0x7B50, 0xCECD, 0x80F1, 0xCECE, 0x945B, 0xCECF, 0x5366, 0xCED0, 0x639B, + 0xCED1, 0x7F6B, 0xCED2, 0x4E56, 0xCED3, 0x5080, 0xCED4, 0x584A, 0xCED5, 0x58DE, 0xCED6, 0x602A, 0xCED7, 0x6127, 0xCED8, 0x62D0, + 0xCED9, 0x69D0, 0xCEDA, 0x9B41, 0xCEDB, 0x5B8F, 0xCEDC, 0x7D18, 0xCEDD, 0x80B1, 0xCEDE, 0x8F5F, 0xCEDF, 0x4EA4, 0xCEE0, 0x50D1, + 0xCEE1, 0x54AC, 0xCEE2, 0x55AC, 0xCEE3, 0x5B0C, 0xCEE4, 0x5DA0, 0xCEE5, 0x5DE7, 0xCEE6, 0x652A, 0xCEE7, 0x654E, 0xCEE8, 0x6821, + 0xCEE9, 0x6A4B, 0xCEEA, 0x72E1, 0xCEEB, 0x768E, 0xCEEC, 0x77EF, 0xCEED, 0x7D5E, 0xCEEE, 0x7FF9, 0xCEEF, 0x81A0, 0xCEF0, 0x854E, + 0xCEF1, 0x86DF, 0xCEF2, 0x8F03, 0xCEF3, 0x8F4E, 0xCEF4, 0x90CA, 0xCEF5, 0x9903, 0xCEF6, 0x9A55, 0xCEF7, 0x9BAB, 0xCEF8, 0x4E18, + 0xCEF9, 0x4E45, 0xCEFA, 0x4E5D, 0xCEFB, 0x4EC7, 0xCEFC, 0x4FF1, 0xCEFD, 0x5177, 0xCEFE, 0x52FE, 0xCFA1, 0x5340, 0xCFA2, 0x53E3, + 0xCFA3, 0x53E5, 0xCFA4, 0x548E, 0xCFA5, 0x5614, 0xCFA6, 0x5775, 0xCFA7, 0x57A2, 0xCFA8, 0x5BC7, 0xCFA9, 0x5D87, 0xCFAA, 0x5ED0, + 0xCFAB, 0x61FC, 0xCFAC, 0x62D8, 0xCFAD, 0x6551, 0xCFAE, 0x67B8, 0xCFAF, 0x67E9, 0xCFB0, 0x69CB, 0xCFB1, 0x6B50, 0xCFB2, 0x6BC6, + 0xCFB3, 0x6BEC, 0xCFB4, 0x6C42, 0xCFB5, 0x6E9D, 0xCFB6, 0x7078, 0xCFB7, 0x72D7, 0xCFB8, 0x7396, 0xCFB9, 0x7403, 0xCFBA, 0x77BF, + 0xCFBB, 0x77E9, 0xCFBC, 0x7A76, 0xCFBD, 0x7D7F, 0xCFBE, 0x8009, 0xCFBF, 0x81FC, 0xCFC0, 0x8205, 0xCFC1, 0x820A, 0xCFC2, 0x82DF, + 0xCFC3, 0x8862, 0xCFC4, 0x8B33, 0xCFC5, 0x8CFC, 0xCFC6, 0x8EC0, 0xCFC7, 0x9011, 0xCFC8, 0x90B1, 0xCFC9, 0x9264, 0xCFCA, 0x92B6, + 0xCFCB, 0x99D2, 0xCFCC, 0x9A45, 0xCFCD, 0x9CE9, 0xCFCE, 0x9DD7, 0xCFCF, 0x9F9C, 0xCFD0, 0x570B, 0xCFD1, 0x5C40, 0xCFD2, 0x83CA, + 0xCFD3, 0x97A0, 0xCFD4, 0x97AB, 0xCFD5, 0x9EB4, 0xCFD6, 0x541B, 0xCFD7, 0x7A98, 0xCFD8, 0x7FA4, 0xCFD9, 0x88D9, 0xCFDA, 0x8ECD, + 0xCFDB, 0x90E1, 0xCFDC, 0x5800, 0xCFDD, 0x5C48, 0xCFDE, 0x6398, 0xCFDF, 0x7A9F, 0xCFE0, 0x5BAE, 0xCFE1, 0x5F13, 0xCFE2, 0x7A79, + 0xCFE3, 0x7AAE, 0xCFE4, 0x828E, 0xCFE5, 0x8EAC, 0xCFE6, 0x5026, 0xCFE7, 0x5238, 0xCFE8, 0x52F8, 0xCFE9, 0x5377, 0xCFEA, 0x5708, + 0xCFEB, 0x62F3, 0xCFEC, 0x6372, 0xCFED, 0x6B0A, 0xCFEE, 0x6DC3, 0xCFEF, 0x7737, 0xCFF0, 0x53A5, 0xCFF1, 0x7357, 0xCFF2, 0x8568, + 0xCFF3, 0x8E76, 0xCFF4, 0x95D5, 0xCFF5, 0x673A, 0xCFF6, 0x6AC3, 0xCFF7, 0x6F70, 0xCFF8, 0x8A6D, 0xCFF9, 0x8ECC, 0xCFFA, 0x994B, + 0xCFFB, 0xF906, 0xCFFC, 0x6677, 0xCFFD, 0x6B78, 0xCFFE, 0x8CB4, 0xD0A1, 0x9B3C, 0xD0A2, 0xF907, 0xD0A3, 0x53EB, 0xD0A4, 0x572D, + 0xD0A5, 0x594E, 0xD0A6, 0x63C6, 0xD0A7, 0x69FB, 0xD0A8, 0x73EA, 0xD0A9, 0x7845, 0xD0AA, 0x7ABA, 0xD0AB, 0x7AC5, 0xD0AC, 0x7CFE, + 0xD0AD, 0x8475, 0xD0AE, 0x898F, 0xD0AF, 0x8D73, 0xD0B0, 0x9035, 0xD0B1, 0x95A8, 0xD0B2, 0x52FB, 0xD0B3, 0x5747, 0xD0B4, 0x7547, + 0xD0B5, 0x7B60, 0xD0B6, 0x83CC, 0xD0B7, 0x921E, 0xD0B8, 0xF908, 0xD0B9, 0x6A58, 0xD0BA, 0x514B, 0xD0BB, 0x524B, 0xD0BC, 0x5287, + 0xD0BD, 0x621F, 0xD0BE, 0x68D8, 0xD0BF, 0x6975, 0xD0C0, 0x9699, 0xD0C1, 0x50C5, 0xD0C2, 0x52A4, 0xD0C3, 0x52E4, 0xD0C4, 0x61C3, + 0xD0C5, 0x65A4, 0xD0C6, 0x6839, 0xD0C7, 0x69FF, 0xD0C8, 0x747E, 0xD0C9, 0x7B4B, 0xD0CA, 0x82B9, 0xD0CB, 0x83EB, 0xD0CC, 0x89B2, + 0xD0CD, 0x8B39, 0xD0CE, 0x8FD1, 0xD0CF, 0x9949, 0xD0D0, 0xF909, 0xD0D1, 0x4ECA, 0xD0D2, 0x5997, 0xD0D3, 0x64D2, 0xD0D4, 0x6611, + 0xD0D5, 0x6A8E, 0xD0D6, 0x7434, 0xD0D7, 0x7981, 0xD0D8, 0x79BD, 0xD0D9, 0x82A9, 0xD0DA, 0x887E, 0xD0DB, 0x887F, 0xD0DC, 0x895F, + 0xD0DD, 0xF90A, 0xD0DE, 0x9326, 0xD0DF, 0x4F0B, 0xD0E0, 0x53CA, 0xD0E1, 0x6025, 0xD0E2, 0x6271, 0xD0E3, 0x6C72, 0xD0E4, 0x7D1A, + 0xD0E5, 0x7D66, 0xD0E6, 0x4E98, 0xD0E7, 0x5162, 0xD0E8, 0x77DC, 0xD0E9, 0x80AF, 0xD0EA, 0x4F01, 0xD0EB, 0x4F0E, 0xD0EC, 0x5176, + 0xD0ED, 0x5180, 0xD0EE, 0x55DC, 0xD0EF, 0x5668, 0xD0F0, 0x573B, 0xD0F1, 0x57FA, 0xD0F2, 0x57FC, 0xD0F3, 0x5914, 0xD0F4, 0x5947, + 0xD0F5, 0x5993, 0xD0F6, 0x5BC4, 0xD0F7, 0x5C90, 0xD0F8, 0x5D0E, 0xD0F9, 0x5DF1, 0xD0FA, 0x5E7E, 0xD0FB, 0x5FCC, 0xD0FC, 0x6280, + 0xD0FD, 0x65D7, 0xD0FE, 0x65E3, 0xD1A1, 0x671E, 0xD1A2, 0x671F, 0xD1A3, 0x675E, 0xD1A4, 0x68CB, 0xD1A5, 0x68C4, 0xD1A6, 0x6A5F, + 0xD1A7, 0x6B3A, 0xD1A8, 0x6C23, 0xD1A9, 0x6C7D, 0xD1AA, 0x6C82, 0xD1AB, 0x6DC7, 0xD1AC, 0x7398, 0xD1AD, 0x7426, 0xD1AE, 0x742A, + 0xD1AF, 0x7482, 0xD1B0, 0x74A3, 0xD1B1, 0x7578, 0xD1B2, 0x757F, 0xD1B3, 0x7881, 0xD1B4, 0x78EF, 0xD1B5, 0x7941, 0xD1B6, 0x7947, + 0xD1B7, 0x7948, 0xD1B8, 0x797A, 0xD1B9, 0x7B95, 0xD1BA, 0x7D00, 0xD1BB, 0x7DBA, 0xD1BC, 0x7F88, 0xD1BD, 0x8006, 0xD1BE, 0x802D, + 0xD1BF, 0x808C, 0xD1C0, 0x8A18, 0xD1C1, 0x8B4F, 0xD1C2, 0x8C48, 0xD1C3, 0x8D77, 0xD1C4, 0x9321, 0xD1C5, 0x9324, 0xD1C6, 0x98E2, + 0xD1C7, 0x9951, 0xD1C8, 0x9A0E, 0xD1C9, 0x9A0F, 0xD1CA, 0x9A65, 0xD1CB, 0x9E92, 0xD1CC, 0x7DCA, 0xD1CD, 0x4F76, 0xD1CE, 0x5409, + 0xD1CF, 0x62EE, 0xD1D0, 0x6854, 0xD1D1, 0x91D1, 0xD1D2, 0x55AB, 0xD1D3, 0x513A, 0xD1D4, 0xF90B, 0xD1D5, 0xF90C, 0xD1D6, 0x5A1C, + 0xD1D7, 0x61E6, 0xD1D8, 0xF90D, 0xD1D9, 0x62CF, 0xD1DA, 0x62FF, 0xD1DB, 0xF90E, 0xD1DC, 0xF90F, 0xD1DD, 0xF910, 0xD1DE, 0xF911, + 0xD1DF, 0xF912, 0xD1E0, 0xF913, 0xD1E1, 0x90A3, 0xD1E2, 0xF914, 0xD1E3, 0xF915, 0xD1E4, 0xF916, 0xD1E5, 0xF917, 0xD1E6, 0xF918, + 0xD1E7, 0x8AFE, 0xD1E8, 0xF919, 0xD1E9, 0xF91A, 0xD1EA, 0xF91B, 0xD1EB, 0xF91C, 0xD1EC, 0x6696, 0xD1ED, 0xF91D, 0xD1EE, 0x7156, + 0xD1EF, 0xF91E, 0xD1F0, 0xF91F, 0xD1F1, 0x96E3, 0xD1F2, 0xF920, 0xD1F3, 0x634F, 0xD1F4, 0x637A, 0xD1F5, 0x5357, 0xD1F6, 0xF921, + 0xD1F7, 0x678F, 0xD1F8, 0x6960, 0xD1F9, 0x6E73, 0xD1FA, 0xF922, 0xD1FB, 0x7537, 0xD1FC, 0xF923, 0xD1FD, 0xF924, 0xD1FE, 0xF925, + 0xD2A1, 0x7D0D, 0xD2A2, 0xF926, 0xD2A3, 0xF927, 0xD2A4, 0x8872, 0xD2A5, 0x56CA, 0xD2A6, 0x5A18, 0xD2A7, 0xF928, 0xD2A8, 0xF929, + 0xD2A9, 0xF92A, 0xD2AA, 0xF92B, 0xD2AB, 0xF92C, 0xD2AC, 0x4E43, 0xD2AD, 0xF92D, 0xD2AE, 0x5167, 0xD2AF, 0x5948, 0xD2B0, 0x67F0, + 0xD2B1, 0x8010, 0xD2B2, 0xF92E, 0xD2B3, 0x5973, 0xD2B4, 0x5E74, 0xD2B5, 0x649A, 0xD2B6, 0x79CA, 0xD2B7, 0x5FF5, 0xD2B8, 0x606C, + 0xD2B9, 0x62C8, 0xD2BA, 0x637B, 0xD2BB, 0x5BE7, 0xD2BC, 0x5BD7, 0xD2BD, 0x52AA, 0xD2BE, 0xF92F, 0xD2BF, 0x5974, 0xD2C0, 0x5F29, + 0xD2C1, 0x6012, 0xD2C2, 0xF930, 0xD2C3, 0xF931, 0xD2C4, 0xF932, 0xD2C5, 0x7459, 0xD2C6, 0xF933, 0xD2C7, 0xF934, 0xD2C8, 0xF935, + 0xD2C9, 0xF936, 0xD2CA, 0xF937, 0xD2CB, 0xF938, 0xD2CC, 0x99D1, 0xD2CD, 0xF939, 0xD2CE, 0xF93A, 0xD2CF, 0xF93B, 0xD2D0, 0xF93C, + 0xD2D1, 0xF93D, 0xD2D2, 0xF93E, 0xD2D3, 0xF93F, 0xD2D4, 0xF940, 0xD2D5, 0xF941, 0xD2D6, 0xF942, 0xD2D7, 0xF943, 0xD2D8, 0x6FC3, + 0xD2D9, 0xF944, 0xD2DA, 0xF945, 0xD2DB, 0x81BF, 0xD2DC, 0x8FB2, 0xD2DD, 0x60F1, 0xD2DE, 0xF946, 0xD2DF, 0xF947, 0xD2E0, 0x8166, + 0xD2E1, 0xF948, 0xD2E2, 0xF949, 0xD2E3, 0x5C3F, 0xD2E4, 0xF94A, 0xD2E5, 0xF94B, 0xD2E6, 0xF94C, 0xD2E7, 0xF94D, 0xD2E8, 0xF94E, + 0xD2E9, 0xF94F, 0xD2EA, 0xF950, 0xD2EB, 0xF951, 0xD2EC, 0x5AE9, 0xD2ED, 0x8A25, 0xD2EE, 0x677B, 0xD2EF, 0x7D10, 0xD2F0, 0xF952, + 0xD2F1, 0xF953, 0xD2F2, 0xF954, 0xD2F3, 0xF955, 0xD2F4, 0xF956, 0xD2F5, 0xF957, 0xD2F6, 0x80FD, 0xD2F7, 0xF958, 0xD2F8, 0xF959, + 0xD2F9, 0x5C3C, 0xD2FA, 0x6CE5, 0xD2FB, 0x533F, 0xD2FC, 0x6EBA, 0xD2FD, 0x591A, 0xD2FE, 0x8336, 0xD3A1, 0x4E39, 0xD3A2, 0x4EB6, + 0xD3A3, 0x4F46, 0xD3A4, 0x55AE, 0xD3A5, 0x5718, 0xD3A6, 0x58C7, 0xD3A7, 0x5F56, 0xD3A8, 0x65B7, 0xD3A9, 0x65E6, 0xD3AA, 0x6A80, + 0xD3AB, 0x6BB5, 0xD3AC, 0x6E4D, 0xD3AD, 0x77ED, 0xD3AE, 0x7AEF, 0xD3AF, 0x7C1E, 0xD3B0, 0x7DDE, 0xD3B1, 0x86CB, 0xD3B2, 0x8892, + 0xD3B3, 0x9132, 0xD3B4, 0x935B, 0xD3B5, 0x64BB, 0xD3B6, 0x6FBE, 0xD3B7, 0x737A, 0xD3B8, 0x75B8, 0xD3B9, 0x9054, 0xD3BA, 0x5556, + 0xD3BB, 0x574D, 0xD3BC, 0x61BA, 0xD3BD, 0x64D4, 0xD3BE, 0x66C7, 0xD3BF, 0x6DE1, 0xD3C0, 0x6E5B, 0xD3C1, 0x6F6D, 0xD3C2, 0x6FB9, + 0xD3C3, 0x75F0, 0xD3C4, 0x8043, 0xD3C5, 0x81BD, 0xD3C6, 0x8541, 0xD3C7, 0x8983, 0xD3C8, 0x8AC7, 0xD3C9, 0x8B5A, 0xD3CA, 0x931F, + 0xD3CB, 0x6C93, 0xD3CC, 0x7553, 0xD3CD, 0x7B54, 0xD3CE, 0x8E0F, 0xD3CF, 0x905D, 0xD3D0, 0x5510, 0xD3D1, 0x5802, 0xD3D2, 0x5858, + 0xD3D3, 0x5E62, 0xD3D4, 0x6207, 0xD3D5, 0x649E, 0xD3D6, 0x68E0, 0xD3D7, 0x7576, 0xD3D8, 0x7CD6, 0xD3D9, 0x87B3, 0xD3DA, 0x9EE8, + 0xD3DB, 0x4EE3, 0xD3DC, 0x5788, 0xD3DD, 0x576E, 0xD3DE, 0x5927, 0xD3DF, 0x5C0D, 0xD3E0, 0x5CB1, 0xD3E1, 0x5E36, 0xD3E2, 0x5F85, + 0xD3E3, 0x6234, 0xD3E4, 0x64E1, 0xD3E5, 0x73B3, 0xD3E6, 0x81FA, 0xD3E7, 0x888B, 0xD3E8, 0x8CB8, 0xD3E9, 0x968A, 0xD3EA, 0x9EDB, + 0xD3EB, 0x5B85, 0xD3EC, 0x5FB7, 0xD3ED, 0x60B3, 0xD3EE, 0x5012, 0xD3EF, 0x5200, 0xD3F0, 0x5230, 0xD3F1, 0x5716, 0xD3F2, 0x5835, + 0xD3F3, 0x5857, 0xD3F4, 0x5C0E, 0xD3F5, 0x5C60, 0xD3F6, 0x5CF6, 0xD3F7, 0x5D8B, 0xD3F8, 0x5EA6, 0xD3F9, 0x5F92, 0xD3FA, 0x60BC, + 0xD3FB, 0x6311, 0xD3FC, 0x6389, 0xD3FD, 0x6417, 0xD3FE, 0x6843, 0xD4A1, 0x68F9, 0xD4A2, 0x6AC2, 0xD4A3, 0x6DD8, 0xD4A4, 0x6E21, + 0xD4A5, 0x6ED4, 0xD4A6, 0x6FE4, 0xD4A7, 0x71FE, 0xD4A8, 0x76DC, 0xD4A9, 0x7779, 0xD4AA, 0x79B1, 0xD4AB, 0x7A3B, 0xD4AC, 0x8404, + 0xD4AD, 0x89A9, 0xD4AE, 0x8CED, 0xD4AF, 0x8DF3, 0xD4B0, 0x8E48, 0xD4B1, 0x9003, 0xD4B2, 0x9014, 0xD4B3, 0x9053, 0xD4B4, 0x90FD, + 0xD4B5, 0x934D, 0xD4B6, 0x9676, 0xD4B7, 0x97DC, 0xD4B8, 0x6BD2, 0xD4B9, 0x7006, 0xD4BA, 0x7258, 0xD4BB, 0x72A2, 0xD4BC, 0x7368, + 0xD4BD, 0x7763, 0xD4BE, 0x79BF, 0xD4BF, 0x7BE4, 0xD4C0, 0x7E9B, 0xD4C1, 0x8B80, 0xD4C2, 0x58A9, 0xD4C3, 0x60C7, 0xD4C4, 0x6566, + 0xD4C5, 0x65FD, 0xD4C6, 0x66BE, 0xD4C7, 0x6C8C, 0xD4C8, 0x711E, 0xD4C9, 0x71C9, 0xD4CA, 0x8C5A, 0xD4CB, 0x9813, 0xD4CC, 0x4E6D, + 0xD4CD, 0x7A81, 0xD4CE, 0x4EDD, 0xD4CF, 0x51AC, 0xD4D0, 0x51CD, 0xD4D1, 0x52D5, 0xD4D2, 0x540C, 0xD4D3, 0x61A7, 0xD4D4, 0x6771, + 0xD4D5, 0x6850, 0xD4D6, 0x68DF, 0xD4D7, 0x6D1E, 0xD4D8, 0x6F7C, 0xD4D9, 0x75BC, 0xD4DA, 0x77B3, 0xD4DB, 0x7AE5, 0xD4DC, 0x80F4, + 0xD4DD, 0x8463, 0xD4DE, 0x9285, 0xD4DF, 0x515C, 0xD4E0, 0x6597, 0xD4E1, 0x675C, 0xD4E2, 0x6793, 0xD4E3, 0x75D8, 0xD4E4, 0x7AC7, + 0xD4E5, 0x8373, 0xD4E6, 0xF95A, 0xD4E7, 0x8C46, 0xD4E8, 0x9017, 0xD4E9, 0x982D, 0xD4EA, 0x5C6F, 0xD4EB, 0x81C0, 0xD4EC, 0x829A, + 0xD4ED, 0x9041, 0xD4EE, 0x906F, 0xD4EF, 0x920D, 0xD4F0, 0x5F97, 0xD4F1, 0x5D9D, 0xD4F2, 0x6A59, 0xD4F3, 0x71C8, 0xD4F4, 0x767B, + 0xD4F5, 0x7B49, 0xD4F6, 0x85E4, 0xD4F7, 0x8B04, 0xD4F8, 0x9127, 0xD4F9, 0x9A30, 0xD4FA, 0x5587, 0xD4FB, 0x61F6, 0xD4FC, 0xF95B, + 0xD4FD, 0x7669, 0xD4FE, 0x7F85, 0xD5A1, 0x863F, 0xD5A2, 0x87BA, 0xD5A3, 0x88F8, 0xD5A4, 0x908F, 0xD5A5, 0xF95C, 0xD5A6, 0x6D1B, + 0xD5A7, 0x70D9, 0xD5A8, 0x73DE, 0xD5A9, 0x7D61, 0xD5AA, 0x843D, 0xD5AB, 0xF95D, 0xD5AC, 0x916A, 0xD5AD, 0x99F1, 0xD5AE, 0xF95E, + 0xD5AF, 0x4E82, 0xD5B0, 0x5375, 0xD5B1, 0x6B04, 0xD5B2, 0x6B12, 0xD5B3, 0x703E, 0xD5B4, 0x721B, 0xD5B5, 0x862D, 0xD5B6, 0x9E1E, + 0xD5B7, 0x524C, 0xD5B8, 0x8FA3, 0xD5B9, 0x5D50, 0xD5BA, 0x64E5, 0xD5BB, 0x652C, 0xD5BC, 0x6B16, 0xD5BD, 0x6FEB, 0xD5BE, 0x7C43, + 0xD5BF, 0x7E9C, 0xD5C0, 0x85CD, 0xD5C1, 0x8964, 0xD5C2, 0x89BD, 0xD5C3, 0x62C9, 0xD5C4, 0x81D8, 0xD5C5, 0x881F, 0xD5C6, 0x5ECA, + 0xD5C7, 0x6717, 0xD5C8, 0x6D6A, 0xD5C9, 0x72FC, 0xD5CA, 0x7405, 0xD5CB, 0x746F, 0xD5CC, 0x8782, 0xD5CD, 0x90DE, 0xD5CE, 0x4F86, + 0xD5CF, 0x5D0D, 0xD5D0, 0x5FA0, 0xD5D1, 0x840A, 0xD5D2, 0x51B7, 0xD5D3, 0x63A0, 0xD5D4, 0x7565, 0xD5D5, 0x4EAE, 0xD5D6, 0x5006, + 0xD5D7, 0x5169, 0xD5D8, 0x51C9, 0xD5D9, 0x6881, 0xD5DA, 0x6A11, 0xD5DB, 0x7CAE, 0xD5DC, 0x7CB1, 0xD5DD, 0x7CE7, 0xD5DE, 0x826F, + 0xD5DF, 0x8AD2, 0xD5E0, 0x8F1B, 0xD5E1, 0x91CF, 0xD5E2, 0x4FB6, 0xD5E3, 0x5137, 0xD5E4, 0x52F5, 0xD5E5, 0x5442, 0xD5E6, 0x5EEC, + 0xD5E7, 0x616E, 0xD5E8, 0x623E, 0xD5E9, 0x65C5, 0xD5EA, 0x6ADA, 0xD5EB, 0x6FFE, 0xD5EC, 0x792A, 0xD5ED, 0x85DC, 0xD5EE, 0x8823, + 0xD5EF, 0x95AD, 0xD5F0, 0x9A62, 0xD5F1, 0x9A6A, 0xD5F2, 0x9E97, 0xD5F3, 0x9ECE, 0xD5F4, 0x529B, 0xD5F5, 0x66C6, 0xD5F6, 0x6B77, + 0xD5F7, 0x701D, 0xD5F8, 0x792B, 0xD5F9, 0x8F62, 0xD5FA, 0x9742, 0xD5FB, 0x6190, 0xD5FC, 0x6200, 0xD5FD, 0x6523, 0xD5FE, 0x6F23, + 0xD6A1, 0x7149, 0xD6A2, 0x7489, 0xD6A3, 0x7DF4, 0xD6A4, 0x806F, 0xD6A5, 0x84EE, 0xD6A6, 0x8F26, 0xD6A7, 0x9023, 0xD6A8, 0x934A, + 0xD6A9, 0x51BD, 0xD6AA, 0x5217, 0xD6AB, 0x52A3, 0xD6AC, 0x6D0C, 0xD6AD, 0x70C8, 0xD6AE, 0x88C2, 0xD6AF, 0x5EC9, 0xD6B0, 0x6582, + 0xD6B1, 0x6BAE, 0xD6B2, 0x6FC2, 0xD6B3, 0x7C3E, 0xD6B4, 0x7375, 0xD6B5, 0x4EE4, 0xD6B6, 0x4F36, 0xD6B7, 0x56F9, 0xD6B8, 0xF95F, + 0xD6B9, 0x5CBA, 0xD6BA, 0x5DBA, 0xD6BB, 0x601C, 0xD6BC, 0x73B2, 0xD6BD, 0x7B2D, 0xD6BE, 0x7F9A, 0xD6BF, 0x7FCE, 0xD6C0, 0x8046, + 0xD6C1, 0x901E, 0xD6C2, 0x9234, 0xD6C3, 0x96F6, 0xD6C4, 0x9748, 0xD6C5, 0x9818, 0xD6C6, 0x9F61, 0xD6C7, 0x4F8B, 0xD6C8, 0x6FA7, + 0xD6C9, 0x79AE, 0xD6CA, 0x91B4, 0xD6CB, 0x96B7, 0xD6CC, 0x52DE, 0xD6CD, 0xF960, 0xD6CE, 0x6488, 0xD6CF, 0x64C4, 0xD6D0, 0x6AD3, + 0xD6D1, 0x6F5E, 0xD6D2, 0x7018, 0xD6D3, 0x7210, 0xD6D4, 0x76E7, 0xD6D5, 0x8001, 0xD6D6, 0x8606, 0xD6D7, 0x865C, 0xD6D8, 0x8DEF, + 0xD6D9, 0x8F05, 0xD6DA, 0x9732, 0xD6DB, 0x9B6F, 0xD6DC, 0x9DFA, 0xD6DD, 0x9E75, 0xD6DE, 0x788C, 0xD6DF, 0x797F, 0xD6E0, 0x7DA0, + 0xD6E1, 0x83C9, 0xD6E2, 0x9304, 0xD6E3, 0x9E7F, 0xD6E4, 0x9E93, 0xD6E5, 0x8AD6, 0xD6E6, 0x58DF, 0xD6E7, 0x5F04, 0xD6E8, 0x6727, + 0xD6E9, 0x7027, 0xD6EA, 0x74CF, 0xD6EB, 0x7C60, 0xD6EC, 0x807E, 0xD6ED, 0x5121, 0xD6EE, 0x7028, 0xD6EF, 0x7262, 0xD6F0, 0x78CA, + 0xD6F1, 0x8CC2, 0xD6F2, 0x8CDA, 0xD6F3, 0x8CF4, 0xD6F4, 0x96F7, 0xD6F5, 0x4E86, 0xD6F6, 0x50DA, 0xD6F7, 0x5BEE, 0xD6F8, 0x5ED6, + 0xD6F9, 0x6599, 0xD6FA, 0x71CE, 0xD6FB, 0x7642, 0xD6FC, 0x77AD, 0xD6FD, 0x804A, 0xD6FE, 0x84FC, 0xD7A1, 0x907C, 0xD7A2, 0x9B27, + 0xD7A3, 0x9F8D, 0xD7A4, 0x58D8, 0xD7A5, 0x5A41, 0xD7A6, 0x5C62, 0xD7A7, 0x6A13, 0xD7A8, 0x6DDA, 0xD7A9, 0x6F0F, 0xD7AA, 0x763B, + 0xD7AB, 0x7D2F, 0xD7AC, 0x7E37, 0xD7AD, 0x851E, 0xD7AE, 0x8938, 0xD7AF, 0x93E4, 0xD7B0, 0x964B, 0xD7B1, 0x5289, 0xD7B2, 0x65D2, + 0xD7B3, 0x67F3, 0xD7B4, 0x69B4, 0xD7B5, 0x6D41, 0xD7B6, 0x6E9C, 0xD7B7, 0x700F, 0xD7B8, 0x7409, 0xD7B9, 0x7460, 0xD7BA, 0x7559, + 0xD7BB, 0x7624, 0xD7BC, 0x786B, 0xD7BD, 0x8B2C, 0xD7BE, 0x985E, 0xD7BF, 0x516D, 0xD7C0, 0x622E, 0xD7C1, 0x9678, 0xD7C2, 0x4F96, + 0xD7C3, 0x502B, 0xD7C4, 0x5D19, 0xD7C5, 0x6DEA, 0xD7C6, 0x7DB8, 0xD7C7, 0x8F2A, 0xD7C8, 0x5F8B, 0xD7C9, 0x6144, 0xD7CA, 0x6817, + 0xD7CB, 0xF961, 0xD7CC, 0x9686, 0xD7CD, 0x52D2, 0xD7CE, 0x808B, 0xD7CF, 0x51DC, 0xD7D0, 0x51CC, 0xD7D1, 0x695E, 0xD7D2, 0x7A1C, + 0xD7D3, 0x7DBE, 0xD7D4, 0x83F1, 0xD7D5, 0x9675, 0xD7D6, 0x4FDA, 0xD7D7, 0x5229, 0xD7D8, 0x5398, 0xD7D9, 0x540F, 0xD7DA, 0x550E, + 0xD7DB, 0x5C65, 0xD7DC, 0x60A7, 0xD7DD, 0x674E, 0xD7DE, 0x68A8, 0xD7DF, 0x6D6C, 0xD7E0, 0x7281, 0xD7E1, 0x72F8, 0xD7E2, 0x7406, + 0xD7E3, 0x7483, 0xD7E4, 0xF962, 0xD7E5, 0x75E2, 0xD7E6, 0x7C6C, 0xD7E7, 0x7F79, 0xD7E8, 0x7FB8, 0xD7E9, 0x8389, 0xD7EA, 0x88CF, + 0xD7EB, 0x88E1, 0xD7EC, 0x91CC, 0xD7ED, 0x91D0, 0xD7EE, 0x96E2, 0xD7EF, 0x9BC9, 0xD7F0, 0x541D, 0xD7F1, 0x6F7E, 0xD7F2, 0x71D0, + 0xD7F3, 0x7498, 0xD7F4, 0x85FA, 0xD7F5, 0x8EAA, 0xD7F6, 0x96A3, 0xD7F7, 0x9C57, 0xD7F8, 0x9E9F, 0xD7F9, 0x6797, 0xD7FA, 0x6DCB, + 0xD7FB, 0x7433, 0xD7FC, 0x81E8, 0xD7FD, 0x9716, 0xD7FE, 0x782C, 0xD8A1, 0x7ACB, 0xD8A2, 0x7B20, 0xD8A3, 0x7C92, 0xD8A4, 0x6469, + 0xD8A5, 0x746A, 0xD8A6, 0x75F2, 0xD8A7, 0x78BC, 0xD8A8, 0x78E8, 0xD8A9, 0x99AC, 0xD8AA, 0x9B54, 0xD8AB, 0x9EBB, 0xD8AC, 0x5BDE, + 0xD8AD, 0x5E55, 0xD8AE, 0x6F20, 0xD8AF, 0x819C, 0xD8B0, 0x83AB, 0xD8B1, 0x9088, 0xD8B2, 0x4E07, 0xD8B3, 0x534D, 0xD8B4, 0x5A29, + 0xD8B5, 0x5DD2, 0xD8B6, 0x5F4E, 0xD8B7, 0x6162, 0xD8B8, 0x633D, 0xD8B9, 0x6669, 0xD8BA, 0x66FC, 0xD8BB, 0x6EFF, 0xD8BC, 0x6F2B, + 0xD8BD, 0x7063, 0xD8BE, 0x779E, 0xD8BF, 0x842C, 0xD8C0, 0x8513, 0xD8C1, 0x883B, 0xD8C2, 0x8F13, 0xD8C3, 0x9945, 0xD8C4, 0x9C3B, + 0xD8C5, 0x551C, 0xD8C6, 0x62B9, 0xD8C7, 0x672B, 0xD8C8, 0x6CAB, 0xD8C9, 0x8309, 0xD8CA, 0x896A, 0xD8CB, 0x977A, 0xD8CC, 0x4EA1, + 0xD8CD, 0x5984, 0xD8CE, 0x5FD8, 0xD8CF, 0x5FD9, 0xD8D0, 0x671B, 0xD8D1, 0x7DB2, 0xD8D2, 0x7F54, 0xD8D3, 0x8292, 0xD8D4, 0x832B, + 0xD8D5, 0x83BD, 0xD8D6, 0x8F1E, 0xD8D7, 0x9099, 0xD8D8, 0x57CB, 0xD8D9, 0x59B9, 0xD8DA, 0x5A92, 0xD8DB, 0x5BD0, 0xD8DC, 0x6627, + 0xD8DD, 0x679A, 0xD8DE, 0x6885, 0xD8DF, 0x6BCF, 0xD8E0, 0x7164, 0xD8E1, 0x7F75, 0xD8E2, 0x8CB7, 0xD8E3, 0x8CE3, 0xD8E4, 0x9081, + 0xD8E5, 0x9B45, 0xD8E6, 0x8108, 0xD8E7, 0x8C8A, 0xD8E8, 0x964C, 0xD8E9, 0x9A40, 0xD8EA, 0x9EA5, 0xD8EB, 0x5B5F, 0xD8EC, 0x6C13, + 0xD8ED, 0x731B, 0xD8EE, 0x76F2, 0xD8EF, 0x76DF, 0xD8F0, 0x840C, 0xD8F1, 0x51AA, 0xD8F2, 0x8993, 0xD8F3, 0x514D, 0xD8F4, 0x5195, + 0xD8F5, 0x52C9, 0xD8F6, 0x68C9, 0xD8F7, 0x6C94, 0xD8F8, 0x7704, 0xD8F9, 0x7720, 0xD8FA, 0x7DBF, 0xD8FB, 0x7DEC, 0xD8FC, 0x9762, + 0xD8FD, 0x9EB5, 0xD8FE, 0x6EC5, 0xD9A1, 0x8511, 0xD9A2, 0x51A5, 0xD9A3, 0x540D, 0xD9A4, 0x547D, 0xD9A5, 0x660E, 0xD9A6, 0x669D, + 0xD9A7, 0x6927, 0xD9A8, 0x6E9F, 0xD9A9, 0x76BF, 0xD9AA, 0x7791, 0xD9AB, 0x8317, 0xD9AC, 0x84C2, 0xD9AD, 0x879F, 0xD9AE, 0x9169, + 0xD9AF, 0x9298, 0xD9B0, 0x9CF4, 0xD9B1, 0x8882, 0xD9B2, 0x4FAE, 0xD9B3, 0x5192, 0xD9B4, 0x52DF, 0xD9B5, 0x59C6, 0xD9B6, 0x5E3D, + 0xD9B7, 0x6155, 0xD9B8, 0x6478, 0xD9B9, 0x6479, 0xD9BA, 0x66AE, 0xD9BB, 0x67D0, 0xD9BC, 0x6A21, 0xD9BD, 0x6BCD, 0xD9BE, 0x6BDB, + 0xD9BF, 0x725F, 0xD9C0, 0x7261, 0xD9C1, 0x7441, 0xD9C2, 0x7738, 0xD9C3, 0x77DB, 0xD9C4, 0x8017, 0xD9C5, 0x82BC, 0xD9C6, 0x8305, + 0xD9C7, 0x8B00, 0xD9C8, 0x8B28, 0xD9C9, 0x8C8C, 0xD9CA, 0x6728, 0xD9CB, 0x6C90, 0xD9CC, 0x7267, 0xD9CD, 0x76EE, 0xD9CE, 0x7766, + 0xD9CF, 0x7A46, 0xD9D0, 0x9DA9, 0xD9D1, 0x6B7F, 0xD9D2, 0x6C92, 0xD9D3, 0x5922, 0xD9D4, 0x6726, 0xD9D5, 0x8499, 0xD9D6, 0x536F, + 0xD9D7, 0x5893, 0xD9D8, 0x5999, 0xD9D9, 0x5EDF, 0xD9DA, 0x63CF, 0xD9DB, 0x6634, 0xD9DC, 0x6773, 0xD9DD, 0x6E3A, 0xD9DE, 0x732B, + 0xD9DF, 0x7AD7, 0xD9E0, 0x82D7, 0xD9E1, 0x9328, 0xD9E2, 0x52D9, 0xD9E3, 0x5DEB, 0xD9E4, 0x61AE, 0xD9E5, 0x61CB, 0xD9E6, 0x620A, + 0xD9E7, 0x62C7, 0xD9E8, 0x64AB, 0xD9E9, 0x65E0, 0xD9EA, 0x6959, 0xD9EB, 0x6B66, 0xD9EC, 0x6BCB, 0xD9ED, 0x7121, 0xD9EE, 0x73F7, + 0xD9EF, 0x755D, 0xD9F0, 0x7E46, 0xD9F1, 0x821E, 0xD9F2, 0x8302, 0xD9F3, 0x856A, 0xD9F4, 0x8AA3, 0xD9F5, 0x8CBF, 0xD9F6, 0x9727, + 0xD9F7, 0x9D61, 0xD9F8, 0x58A8, 0xD9F9, 0x9ED8, 0xD9FA, 0x5011, 0xD9FB, 0x520E, 0xD9FC, 0x543B, 0xD9FD, 0x554F, 0xD9FE, 0x6587, + 0xDAA1, 0x6C76, 0xDAA2, 0x7D0A, 0xDAA3, 0x7D0B, 0xDAA4, 0x805E, 0xDAA5, 0x868A, 0xDAA6, 0x9580, 0xDAA7, 0x96EF, 0xDAA8, 0x52FF, + 0xDAA9, 0x6C95, 0xDAAA, 0x7269, 0xDAAB, 0x5473, 0xDAAC, 0x5A9A, 0xDAAD, 0x5C3E, 0xDAAE, 0x5D4B, 0xDAAF, 0x5F4C, 0xDAB0, 0x5FAE, + 0xDAB1, 0x672A, 0xDAB2, 0x68B6, 0xDAB3, 0x6963, 0xDAB4, 0x6E3C, 0xDAB5, 0x6E44, 0xDAB6, 0x7709, 0xDAB7, 0x7C73, 0xDAB8, 0x7F8E, + 0xDAB9, 0x8587, 0xDABA, 0x8B0E, 0xDABB, 0x8FF7, 0xDABC, 0x9761, 0xDABD, 0x9EF4, 0xDABE, 0x5CB7, 0xDABF, 0x60B6, 0xDAC0, 0x610D, + 0xDAC1, 0x61AB, 0xDAC2, 0x654F, 0xDAC3, 0x65FB, 0xDAC4, 0x65FC, 0xDAC5, 0x6C11, 0xDAC6, 0x6CEF, 0xDAC7, 0x739F, 0xDAC8, 0x73C9, + 0xDAC9, 0x7DE1, 0xDACA, 0x9594, 0xDACB, 0x5BC6, 0xDACC, 0x871C, 0xDACD, 0x8B10, 0xDACE, 0x525D, 0xDACF, 0x535A, 0xDAD0, 0x62CD, + 0xDAD1, 0x640F, 0xDAD2, 0x64B2, 0xDAD3, 0x6734, 0xDAD4, 0x6A38, 0xDAD5, 0x6CCA, 0xDAD6, 0x73C0, 0xDAD7, 0x749E, 0xDAD8, 0x7B94, + 0xDAD9, 0x7C95, 0xDADA, 0x7E1B, 0xDADB, 0x818A, 0xDADC, 0x8236, 0xDADD, 0x8584, 0xDADE, 0x8FEB, 0xDADF, 0x96F9, 0xDAE0, 0x99C1, + 0xDAE1, 0x4F34, 0xDAE2, 0x534A, 0xDAE3, 0x53CD, 0xDAE4, 0x53DB, 0xDAE5, 0x62CC, 0xDAE6, 0x642C, 0xDAE7, 0x6500, 0xDAE8, 0x6591, + 0xDAE9, 0x69C3, 0xDAEA, 0x6CEE, 0xDAEB, 0x6F58, 0xDAEC, 0x73ED, 0xDAED, 0x7554, 0xDAEE, 0x7622, 0xDAEF, 0x76E4, 0xDAF0, 0x76FC, + 0xDAF1, 0x78D0, 0xDAF2, 0x78FB, 0xDAF3, 0x792C, 0xDAF4, 0x7D46, 0xDAF5, 0x822C, 0xDAF6, 0x87E0, 0xDAF7, 0x8FD4, 0xDAF8, 0x9812, + 0xDAF9, 0x98EF, 0xDAFA, 0x52C3, 0xDAFB, 0x62D4, 0xDAFC, 0x64A5, 0xDAFD, 0x6E24, 0xDAFE, 0x6F51, 0xDBA1, 0x767C, 0xDBA2, 0x8DCB, + 0xDBA3, 0x91B1, 0xDBA4, 0x9262, 0xDBA5, 0x9AEE, 0xDBA6, 0x9B43, 0xDBA7, 0x5023, 0xDBA8, 0x508D, 0xDBA9, 0x574A, 0xDBAA, 0x59A8, + 0xDBAB, 0x5C28, 0xDBAC, 0x5E47, 0xDBAD, 0x5F77, 0xDBAE, 0x623F, 0xDBAF, 0x653E, 0xDBB0, 0x65B9, 0xDBB1, 0x65C1, 0xDBB2, 0x6609, + 0xDBB3, 0x678B, 0xDBB4, 0x699C, 0xDBB5, 0x6EC2, 0xDBB6, 0x78C5, 0xDBB7, 0x7D21, 0xDBB8, 0x80AA, 0xDBB9, 0x8180, 0xDBBA, 0x822B, + 0xDBBB, 0x82B3, 0xDBBC, 0x84A1, 0xDBBD, 0x868C, 0xDBBE, 0x8A2A, 0xDBBF, 0x8B17, 0xDBC0, 0x90A6, 0xDBC1, 0x9632, 0xDBC2, 0x9F90, + 0xDBC3, 0x500D, 0xDBC4, 0x4FF3, 0xDBC5, 0xF963, 0xDBC6, 0x57F9, 0xDBC7, 0x5F98, 0xDBC8, 0x62DC, 0xDBC9, 0x6392, 0xDBCA, 0x676F, + 0xDBCB, 0x6E43, 0xDBCC, 0x7119, 0xDBCD, 0x76C3, 0xDBCE, 0x80CC, 0xDBCF, 0x80DA, 0xDBD0, 0x88F4, 0xDBD1, 0x88F5, 0xDBD2, 0x8919, + 0xDBD3, 0x8CE0, 0xDBD4, 0x8F29, 0xDBD5, 0x914D, 0xDBD6, 0x966A, 0xDBD7, 0x4F2F, 0xDBD8, 0x4F70, 0xDBD9, 0x5E1B, 0xDBDA, 0x67CF, + 0xDBDB, 0x6822, 0xDBDC, 0x767D, 0xDBDD, 0x767E, 0xDBDE, 0x9B44, 0xDBDF, 0x5E61, 0xDBE0, 0x6A0A, 0xDBE1, 0x7169, 0xDBE2, 0x71D4, + 0xDBE3, 0x756A, 0xDBE4, 0xF964, 0xDBE5, 0x7E41, 0xDBE6, 0x8543, 0xDBE7, 0x85E9, 0xDBE8, 0x98DC, 0xDBE9, 0x4F10, 0xDBEA, 0x7B4F, + 0xDBEB, 0x7F70, 0xDBEC, 0x95A5, 0xDBED, 0x51E1, 0xDBEE, 0x5E06, 0xDBEF, 0x68B5, 0xDBF0, 0x6C3E, 0xDBF1, 0x6C4E, 0xDBF2, 0x6CDB, + 0xDBF3, 0x72AF, 0xDBF4, 0x7BC4, 0xDBF5, 0x8303, 0xDBF6, 0x6CD5, 0xDBF7, 0x743A, 0xDBF8, 0x50FB, 0xDBF9, 0x5288, 0xDBFA, 0x58C1, + 0xDBFB, 0x64D8, 0xDBFC, 0x6A97, 0xDBFD, 0x74A7, 0xDBFE, 0x7656, 0xDCA1, 0x78A7, 0xDCA2, 0x8617, 0xDCA3, 0x95E2, 0xDCA4, 0x9739, + 0xDCA5, 0xF965, 0xDCA6, 0x535E, 0xDCA7, 0x5F01, 0xDCA8, 0x8B8A, 0xDCA9, 0x8FA8, 0xDCAA, 0x8FAF, 0xDCAB, 0x908A, 0xDCAC, 0x5225, + 0xDCAD, 0x77A5, 0xDCAE, 0x9C49, 0xDCAF, 0x9F08, 0xDCB0, 0x4E19, 0xDCB1, 0x5002, 0xDCB2, 0x5175, 0xDCB3, 0x5C5B, 0xDCB4, 0x5E77, + 0xDCB5, 0x661E, 0xDCB6, 0x663A, 0xDCB7, 0x67C4, 0xDCB8, 0x68C5, 0xDCB9, 0x70B3, 0xDCBA, 0x7501, 0xDCBB, 0x75C5, 0xDCBC, 0x79C9, + 0xDCBD, 0x7ADD, 0xDCBE, 0x8F27, 0xDCBF, 0x9920, 0xDCC0, 0x9A08, 0xDCC1, 0x4FDD, 0xDCC2, 0x5821, 0xDCC3, 0x5831, 0xDCC4, 0x5BF6, + 0xDCC5, 0x666E, 0xDCC6, 0x6B65, 0xDCC7, 0x6D11, 0xDCC8, 0x6E7A, 0xDCC9, 0x6F7D, 0xDCCA, 0x73E4, 0xDCCB, 0x752B, 0xDCCC, 0x83E9, + 0xDCCD, 0x88DC, 0xDCCE, 0x8913, 0xDCCF, 0x8B5C, 0xDCD0, 0x8F14, 0xDCD1, 0x4F0F, 0xDCD2, 0x50D5, 0xDCD3, 0x5310, 0xDCD4, 0x535C, + 0xDCD5, 0x5B93, 0xDCD6, 0x5FA9, 0xDCD7, 0x670D, 0xDCD8, 0x798F, 0xDCD9, 0x8179, 0xDCDA, 0x832F, 0xDCDB, 0x8514, 0xDCDC, 0x8907, + 0xDCDD, 0x8986, 0xDCDE, 0x8F39, 0xDCDF, 0x8F3B, 0xDCE0, 0x99A5, 0xDCE1, 0x9C12, 0xDCE2, 0x672C, 0xDCE3, 0x4E76, 0xDCE4, 0x4FF8, + 0xDCE5, 0x5949, 0xDCE6, 0x5C01, 0xDCE7, 0x5CEF, 0xDCE8, 0x5CF0, 0xDCE9, 0x6367, 0xDCEA, 0x68D2, 0xDCEB, 0x70FD, 0xDCEC, 0x71A2, + 0xDCED, 0x742B, 0xDCEE, 0x7E2B, 0xDCEF, 0x84EC, 0xDCF0, 0x8702, 0xDCF1, 0x9022, 0xDCF2, 0x92D2, 0xDCF3, 0x9CF3, 0xDCF4, 0x4E0D, + 0xDCF5, 0x4ED8, 0xDCF6, 0x4FEF, 0xDCF7, 0x5085, 0xDCF8, 0x5256, 0xDCF9, 0x526F, 0xDCFA, 0x5426, 0xDCFB, 0x5490, 0xDCFC, 0x57E0, + 0xDCFD, 0x592B, 0xDCFE, 0x5A66, 0xDDA1, 0x5B5A, 0xDDA2, 0x5B75, 0xDDA3, 0x5BCC, 0xDDA4, 0x5E9C, 0xDDA5, 0xF966, 0xDDA6, 0x6276, + 0xDDA7, 0x6577, 0xDDA8, 0x65A7, 0xDDA9, 0x6D6E, 0xDDAA, 0x6EA5, 0xDDAB, 0x7236, 0xDDAC, 0x7B26, 0xDDAD, 0x7C3F, 0xDDAE, 0x7F36, + 0xDDAF, 0x8150, 0xDDB0, 0x8151, 0xDDB1, 0x819A, 0xDDB2, 0x8240, 0xDDB3, 0x8299, 0xDDB4, 0x83A9, 0xDDB5, 0x8A03, 0xDDB6, 0x8CA0, + 0xDDB7, 0x8CE6, 0xDDB8, 0x8CFB, 0xDDB9, 0x8D74, 0xDDBA, 0x8DBA, 0xDDBB, 0x90E8, 0xDDBC, 0x91DC, 0xDDBD, 0x961C, 0xDDBE, 0x9644, + 0xDDBF, 0x99D9, 0xDDC0, 0x9CE7, 0xDDC1, 0x5317, 0xDDC2, 0x5206, 0xDDC3, 0x5429, 0xDDC4, 0x5674, 0xDDC5, 0x58B3, 0xDDC6, 0x5954, + 0xDDC7, 0x596E, 0xDDC8, 0x5FFF, 0xDDC9, 0x61A4, 0xDDCA, 0x626E, 0xDDCB, 0x6610, 0xDDCC, 0x6C7E, 0xDDCD, 0x711A, 0xDDCE, 0x76C6, + 0xDDCF, 0x7C89, 0xDDD0, 0x7CDE, 0xDDD1, 0x7D1B, 0xDDD2, 0x82AC, 0xDDD3, 0x8CC1, 0xDDD4, 0x96F0, 0xDDD5, 0xF967, 0xDDD6, 0x4F5B, + 0xDDD7, 0x5F17, 0xDDD8, 0x5F7F, 0xDDD9, 0x62C2, 0xDDDA, 0x5D29, 0xDDDB, 0x670B, 0xDDDC, 0x68DA, 0xDDDD, 0x787C, 0xDDDE, 0x7E43, + 0xDDDF, 0x9D6C, 0xDDE0, 0x4E15, 0xDDE1, 0x5099, 0xDDE2, 0x5315, 0xDDE3, 0x532A, 0xDDE4, 0x5351, 0xDDE5, 0x5983, 0xDDE6, 0x5A62, + 0xDDE7, 0x5E87, 0xDDE8, 0x60B2, 0xDDE9, 0x618A, 0xDDEA, 0x6249, 0xDDEB, 0x6279, 0xDDEC, 0x6590, 0xDDED, 0x6787, 0xDDEE, 0x69A7, + 0xDDEF, 0x6BD4, 0xDDF0, 0x6BD6, 0xDDF1, 0x6BD7, 0xDDF2, 0x6BD8, 0xDDF3, 0x6CB8, 0xDDF4, 0xF968, 0xDDF5, 0x7435, 0xDDF6, 0x75FA, + 0xDDF7, 0x7812, 0xDDF8, 0x7891, 0xDDF9, 0x79D5, 0xDDFA, 0x79D8, 0xDDFB, 0x7C83, 0xDDFC, 0x7DCB, 0xDDFD, 0x7FE1, 0xDDFE, 0x80A5, + 0xDEA1, 0x813E, 0xDEA2, 0x81C2, 0xDEA3, 0x83F2, 0xDEA4, 0x871A, 0xDEA5, 0x88E8, 0xDEA6, 0x8AB9, 0xDEA7, 0x8B6C, 0xDEA8, 0x8CBB, + 0xDEA9, 0x9119, 0xDEAA, 0x975E, 0xDEAB, 0x98DB, 0xDEAC, 0x9F3B, 0xDEAD, 0x56AC, 0xDEAE, 0x5B2A, 0xDEAF, 0x5F6C, 0xDEB0, 0x658C, + 0xDEB1, 0x6AB3, 0xDEB2, 0x6BAF, 0xDEB3, 0x6D5C, 0xDEB4, 0x6FF1, 0xDEB5, 0x7015, 0xDEB6, 0x725D, 0xDEB7, 0x73AD, 0xDEB8, 0x8CA7, + 0xDEB9, 0x8CD3, 0xDEBA, 0x983B, 0xDEBB, 0x6191, 0xDEBC, 0x6C37, 0xDEBD, 0x8058, 0xDEBE, 0x9A01, 0xDEBF, 0x4E4D, 0xDEC0, 0x4E8B, + 0xDEC1, 0x4E9B, 0xDEC2, 0x4ED5, 0xDEC3, 0x4F3A, 0xDEC4, 0x4F3C, 0xDEC5, 0x4F7F, 0xDEC6, 0x4FDF, 0xDEC7, 0x50FF, 0xDEC8, 0x53F2, + 0xDEC9, 0x53F8, 0xDECA, 0x5506, 0xDECB, 0x55E3, 0xDECC, 0x56DB, 0xDECD, 0x58EB, 0xDECE, 0x5962, 0xDECF, 0x5A11, 0xDED0, 0x5BEB, + 0xDED1, 0x5BFA, 0xDED2, 0x5C04, 0xDED3, 0x5DF3, 0xDED4, 0x5E2B, 0xDED5, 0x5F99, 0xDED6, 0x601D, 0xDED7, 0x6368, 0xDED8, 0x659C, + 0xDED9, 0x65AF, 0xDEDA, 0x67F6, 0xDEDB, 0x67FB, 0xDEDC, 0x68AD, 0xDEDD, 0x6B7B, 0xDEDE, 0x6C99, 0xDEDF, 0x6CD7, 0xDEE0, 0x6E23, + 0xDEE1, 0x7009, 0xDEE2, 0x7345, 0xDEE3, 0x7802, 0xDEE4, 0x793E, 0xDEE5, 0x7940, 0xDEE6, 0x7960, 0xDEE7, 0x79C1, 0xDEE8, 0x7BE9, + 0xDEE9, 0x7D17, 0xDEEA, 0x7D72, 0xDEEB, 0x8086, 0xDEEC, 0x820D, 0xDEED, 0x838E, 0xDEEE, 0x84D1, 0xDEEF, 0x86C7, 0xDEF0, 0x88DF, + 0xDEF1, 0x8A50, 0xDEF2, 0x8A5E, 0xDEF3, 0x8B1D, 0xDEF4, 0x8CDC, 0xDEF5, 0x8D66, 0xDEF6, 0x8FAD, 0xDEF7, 0x90AA, 0xDEF8, 0x98FC, + 0xDEF9, 0x99DF, 0xDEFA, 0x9E9D, 0xDEFB, 0x524A, 0xDEFC, 0xF969, 0xDEFD, 0x6714, 0xDEFE, 0xF96A, 0xDFA1, 0x5098, 0xDFA2, 0x522A, + 0xDFA3, 0x5C71, 0xDFA4, 0x6563, 0xDFA5, 0x6C55, 0xDFA6, 0x73CA, 0xDFA7, 0x7523, 0xDFA8, 0x759D, 0xDFA9, 0x7B97, 0xDFAA, 0x849C, + 0xDFAB, 0x9178, 0xDFAC, 0x9730, 0xDFAD, 0x4E77, 0xDFAE, 0x6492, 0xDFAF, 0x6BBA, 0xDFB0, 0x715E, 0xDFB1, 0x85A9, 0xDFB2, 0x4E09, + 0xDFB3, 0xF96B, 0xDFB4, 0x6749, 0xDFB5, 0x68EE, 0xDFB6, 0x6E17, 0xDFB7, 0x829F, 0xDFB8, 0x8518, 0xDFB9, 0x886B, 0xDFBA, 0x63F7, + 0xDFBB, 0x6F81, 0xDFBC, 0x9212, 0xDFBD, 0x98AF, 0xDFBE, 0x4E0A, 0xDFBF, 0x50B7, 0xDFC0, 0x50CF, 0xDFC1, 0x511F, 0xDFC2, 0x5546, + 0xDFC3, 0x55AA, 0xDFC4, 0x5617, 0xDFC5, 0x5B40, 0xDFC6, 0x5C19, 0xDFC7, 0x5CE0, 0xDFC8, 0x5E38, 0xDFC9, 0x5E8A, 0xDFCA, 0x5EA0, + 0xDFCB, 0x5EC2, 0xDFCC, 0x60F3, 0xDFCD, 0x6851, 0xDFCE, 0x6A61, 0xDFCF, 0x6E58, 0xDFD0, 0x723D, 0xDFD1, 0x7240, 0xDFD2, 0x72C0, + 0xDFD3, 0x76F8, 0xDFD4, 0x7965, 0xDFD5, 0x7BB1, 0xDFD6, 0x7FD4, 0xDFD7, 0x88F3, 0xDFD8, 0x89F4, 0xDFD9, 0x8A73, 0xDFDA, 0x8C61, + 0xDFDB, 0x8CDE, 0xDFDC, 0x971C, 0xDFDD, 0x585E, 0xDFDE, 0x74BD, 0xDFDF, 0x8CFD, 0xDFE0, 0x55C7, 0xDFE1, 0xF96C, 0xDFE2, 0x7A61, + 0xDFE3, 0x7D22, 0xDFE4, 0x8272, 0xDFE5, 0x7272, 0xDFE6, 0x751F, 0xDFE7, 0x7525, 0xDFE8, 0xF96D, 0xDFE9, 0x7B19, 0xDFEA, 0x5885, + 0xDFEB, 0x58FB, 0xDFEC, 0x5DBC, 0xDFED, 0x5E8F, 0xDFEE, 0x5EB6, 0xDFEF, 0x5F90, 0xDFF0, 0x6055, 0xDFF1, 0x6292, 0xDFF2, 0x637F, + 0xDFF3, 0x654D, 0xDFF4, 0x6691, 0xDFF5, 0x66D9, 0xDFF6, 0x66F8, 0xDFF7, 0x6816, 0xDFF8, 0x68F2, 0xDFF9, 0x7280, 0xDFFA, 0x745E, + 0xDFFB, 0x7B6E, 0xDFFC, 0x7D6E, 0xDFFD, 0x7DD6, 0xDFFE, 0x7F72, 0xE0A1, 0x80E5, 0xE0A2, 0x8212, 0xE0A3, 0x85AF, 0xE0A4, 0x897F, + 0xE0A5, 0x8A93, 0xE0A6, 0x901D, 0xE0A7, 0x92E4, 0xE0A8, 0x9ECD, 0xE0A9, 0x9F20, 0xE0AA, 0x5915, 0xE0AB, 0x596D, 0xE0AC, 0x5E2D, + 0xE0AD, 0x60DC, 0xE0AE, 0x6614, 0xE0AF, 0x6673, 0xE0B0, 0x6790, 0xE0B1, 0x6C50, 0xE0B2, 0x6DC5, 0xE0B3, 0x6F5F, 0xE0B4, 0x77F3, + 0xE0B5, 0x78A9, 0xE0B6, 0x84C6, 0xE0B7, 0x91CB, 0xE0B8, 0x932B, 0xE0B9, 0x4ED9, 0xE0BA, 0x50CA, 0xE0BB, 0x5148, 0xE0BC, 0x5584, + 0xE0BD, 0x5B0B, 0xE0BE, 0x5BA3, 0xE0BF, 0x6247, 0xE0C0, 0x657E, 0xE0C1, 0x65CB, 0xE0C2, 0x6E32, 0xE0C3, 0x717D, 0xE0C4, 0x7401, + 0xE0C5, 0x7444, 0xE0C6, 0x7487, 0xE0C7, 0x74BF, 0xE0C8, 0x766C, 0xE0C9, 0x79AA, 0xE0CA, 0x7DDA, 0xE0CB, 0x7E55, 0xE0CC, 0x7FA8, + 0xE0CD, 0x817A, 0xE0CE, 0x81B3, 0xE0CF, 0x8239, 0xE0D0, 0x861A, 0xE0D1, 0x87EC, 0xE0D2, 0x8A75, 0xE0D3, 0x8DE3, 0xE0D4, 0x9078, + 0xE0D5, 0x9291, 0xE0D6, 0x9425, 0xE0D7, 0x994D, 0xE0D8, 0x9BAE, 0xE0D9, 0x5368, 0xE0DA, 0x5C51, 0xE0DB, 0x6954, 0xE0DC, 0x6CC4, + 0xE0DD, 0x6D29, 0xE0DE, 0x6E2B, 0xE0DF, 0x820C, 0xE0E0, 0x859B, 0xE0E1, 0x893B, 0xE0E2, 0x8A2D, 0xE0E3, 0x8AAA, 0xE0E4, 0x96EA, + 0xE0E5, 0x9F67, 0xE0E6, 0x5261, 0xE0E7, 0x66B9, 0xE0E8, 0x6BB2, 0xE0E9, 0x7E96, 0xE0EA, 0x87FE, 0xE0EB, 0x8D0D, 0xE0EC, 0x9583, + 0xE0ED, 0x965D, 0xE0EE, 0x651D, 0xE0EF, 0x6D89, 0xE0F0, 0x71EE, 0xE0F1, 0xF96E, 0xE0F2, 0x57CE, 0xE0F3, 0x59D3, 0xE0F4, 0x5BAC, + 0xE0F5, 0x6027, 0xE0F6, 0x60FA, 0xE0F7, 0x6210, 0xE0F8, 0x661F, 0xE0F9, 0x665F, 0xE0FA, 0x7329, 0xE0FB, 0x73F9, 0xE0FC, 0x76DB, + 0xE0FD, 0x7701, 0xE0FE, 0x7B6C, 0xE1A1, 0x8056, 0xE1A2, 0x8072, 0xE1A3, 0x8165, 0xE1A4, 0x8AA0, 0xE1A5, 0x9192, 0xE1A6, 0x4E16, + 0xE1A7, 0x52E2, 0xE1A8, 0x6B72, 0xE1A9, 0x6D17, 0xE1AA, 0x7A05, 0xE1AB, 0x7B39, 0xE1AC, 0x7D30, 0xE1AD, 0xF96F, 0xE1AE, 0x8CB0, + 0xE1AF, 0x53EC, 0xE1B0, 0x562F, 0xE1B1, 0x5851, 0xE1B2, 0x5BB5, 0xE1B3, 0x5C0F, 0xE1B4, 0x5C11, 0xE1B5, 0x5DE2, 0xE1B6, 0x6240, + 0xE1B7, 0x6383, 0xE1B8, 0x6414, 0xE1B9, 0x662D, 0xE1BA, 0x68B3, 0xE1BB, 0x6CBC, 0xE1BC, 0x6D88, 0xE1BD, 0x6EAF, 0xE1BE, 0x701F, + 0xE1BF, 0x70A4, 0xE1C0, 0x71D2, 0xE1C1, 0x7526, 0xE1C2, 0x758F, 0xE1C3, 0x758E, 0xE1C4, 0x7619, 0xE1C5, 0x7B11, 0xE1C6, 0x7BE0, + 0xE1C7, 0x7C2B, 0xE1C8, 0x7D20, 0xE1C9, 0x7D39, 0xE1CA, 0x852C, 0xE1CB, 0x856D, 0xE1CC, 0x8607, 0xE1CD, 0x8A34, 0xE1CE, 0x900D, + 0xE1CF, 0x9061, 0xE1D0, 0x90B5, 0xE1D1, 0x92B7, 0xE1D2, 0x97F6, 0xE1D3, 0x9A37, 0xE1D4, 0x4FD7, 0xE1D5, 0x5C6C, 0xE1D6, 0x675F, + 0xE1D7, 0x6D91, 0xE1D8, 0x7C9F, 0xE1D9, 0x7E8C, 0xE1DA, 0x8B16, 0xE1DB, 0x8D16, 0xE1DC, 0x901F, 0xE1DD, 0x5B6B, 0xE1DE, 0x5DFD, + 0xE1DF, 0x640D, 0xE1E0, 0x84C0, 0xE1E1, 0x905C, 0xE1E2, 0x98E1, 0xE1E3, 0x7387, 0xE1E4, 0x5B8B, 0xE1E5, 0x609A, 0xE1E6, 0x677E, + 0xE1E7, 0x6DDE, 0xE1E8, 0x8A1F, 0xE1E9, 0x8AA6, 0xE1EA, 0x9001, 0xE1EB, 0x980C, 0xE1EC, 0x5237, 0xE1ED, 0xF970, 0xE1EE, 0x7051, + 0xE1EF, 0x788E, 0xE1F0, 0x9396, 0xE1F1, 0x8870, 0xE1F2, 0x91D7, 0xE1F3, 0x4FEE, 0xE1F4, 0x53D7, 0xE1F5, 0x55FD, 0xE1F6, 0x56DA, + 0xE1F7, 0x5782, 0xE1F8, 0x58FD, 0xE1F9, 0x5AC2, 0xE1FA, 0x5B88, 0xE1FB, 0x5CAB, 0xE1FC, 0x5CC0, 0xE1FD, 0x5E25, 0xE1FE, 0x6101, + 0xE2A1, 0x620D, 0xE2A2, 0x624B, 0xE2A3, 0x6388, 0xE2A4, 0x641C, 0xE2A5, 0x6536, 0xE2A6, 0x6578, 0xE2A7, 0x6A39, 0xE2A8, 0x6B8A, + 0xE2A9, 0x6C34, 0xE2AA, 0x6D19, 0xE2AB, 0x6F31, 0xE2AC, 0x71E7, 0xE2AD, 0x72E9, 0xE2AE, 0x7378, 0xE2AF, 0x7407, 0xE2B0, 0x74B2, + 0xE2B1, 0x7626, 0xE2B2, 0x7761, 0xE2B3, 0x79C0, 0xE2B4, 0x7A57, 0xE2B5, 0x7AEA, 0xE2B6, 0x7CB9, 0xE2B7, 0x7D8F, 0xE2B8, 0x7DAC, + 0xE2B9, 0x7E61, 0xE2BA, 0x7F9E, 0xE2BB, 0x8129, 0xE2BC, 0x8331, 0xE2BD, 0x8490, 0xE2BE, 0x84DA, 0xE2BF, 0x85EA, 0xE2C0, 0x8896, + 0xE2C1, 0x8AB0, 0xE2C2, 0x8B90, 0xE2C3, 0x8F38, 0xE2C4, 0x9042, 0xE2C5, 0x9083, 0xE2C6, 0x916C, 0xE2C7, 0x9296, 0xE2C8, 0x92B9, + 0xE2C9, 0x968B, 0xE2CA, 0x96A7, 0xE2CB, 0x96A8, 0xE2CC, 0x96D6, 0xE2CD, 0x9700, 0xE2CE, 0x9808, 0xE2CF, 0x9996, 0xE2D0, 0x9AD3, + 0xE2D1, 0x9B1A, 0xE2D2, 0x53D4, 0xE2D3, 0x587E, 0xE2D4, 0x5919, 0xE2D5, 0x5B70, 0xE2D6, 0x5BBF, 0xE2D7, 0x6DD1, 0xE2D8, 0x6F5A, + 0xE2D9, 0x719F, 0xE2DA, 0x7421, 0xE2DB, 0x74B9, 0xE2DC, 0x8085, 0xE2DD, 0x83FD, 0xE2DE, 0x5DE1, 0xE2DF, 0x5F87, 0xE2E0, 0x5FAA, + 0xE2E1, 0x6042, 0xE2E2, 0x65EC, 0xE2E3, 0x6812, 0xE2E4, 0x696F, 0xE2E5, 0x6A53, 0xE2E6, 0x6B89, 0xE2E7, 0x6D35, 0xE2E8, 0x6DF3, + 0xE2E9, 0x73E3, 0xE2EA, 0x76FE, 0xE2EB, 0x77AC, 0xE2EC, 0x7B4D, 0xE2ED, 0x7D14, 0xE2EE, 0x8123, 0xE2EF, 0x821C, 0xE2F0, 0x8340, + 0xE2F1, 0x84F4, 0xE2F2, 0x8563, 0xE2F3, 0x8A62, 0xE2F4, 0x8AC4, 0xE2F5, 0x9187, 0xE2F6, 0x931E, 0xE2F7, 0x9806, 0xE2F8, 0x99B4, + 0xE2F9, 0x620C, 0xE2FA, 0x8853, 0xE2FB, 0x8FF0, 0xE2FC, 0x9265, 0xE2FD, 0x5D07, 0xE2FE, 0x5D27, 0xE3A1, 0x5D69, 0xE3A2, 0x745F, + 0xE3A3, 0x819D, 0xE3A4, 0x8768, 0xE3A5, 0x6FD5, 0xE3A6, 0x62FE, 0xE3A7, 0x7FD2, 0xE3A8, 0x8936, 0xE3A9, 0x8972, 0xE3AA, 0x4E1E, + 0xE3AB, 0x4E58, 0xE3AC, 0x50E7, 0xE3AD, 0x52DD, 0xE3AE, 0x5347, 0xE3AF, 0x627F, 0xE3B0, 0x6607, 0xE3B1, 0x7E69, 0xE3B2, 0x8805, + 0xE3B3, 0x965E, 0xE3B4, 0x4F8D, 0xE3B5, 0x5319, 0xE3B6, 0x5636, 0xE3B7, 0x59CB, 0xE3B8, 0x5AA4, 0xE3B9, 0x5C38, 0xE3BA, 0x5C4E, + 0xE3BB, 0x5C4D, 0xE3BC, 0x5E02, 0xE3BD, 0x5F11, 0xE3BE, 0x6043, 0xE3BF, 0x65BD, 0xE3C0, 0x662F, 0xE3C1, 0x6642, 0xE3C2, 0x67BE, + 0xE3C3, 0x67F4, 0xE3C4, 0x731C, 0xE3C5, 0x77E2, 0xE3C6, 0x793A, 0xE3C7, 0x7FC5, 0xE3C8, 0x8494, 0xE3C9, 0x84CD, 0xE3CA, 0x8996, + 0xE3CB, 0x8A66, 0xE3CC, 0x8A69, 0xE3CD, 0x8AE1, 0xE3CE, 0x8C55, 0xE3CF, 0x8C7A, 0xE3D0, 0x57F4, 0xE3D1, 0x5BD4, 0xE3D2, 0x5F0F, + 0xE3D3, 0x606F, 0xE3D4, 0x62ED, 0xE3D5, 0x690D, 0xE3D6, 0x6B96, 0xE3D7, 0x6E5C, 0xE3D8, 0x7184, 0xE3D9, 0x7BD2, 0xE3DA, 0x8755, + 0xE3DB, 0x8B58, 0xE3DC, 0x8EFE, 0xE3DD, 0x98DF, 0xE3DE, 0x98FE, 0xE3DF, 0x4F38, 0xE3E0, 0x4F81, 0xE3E1, 0x4FE1, 0xE3E2, 0x547B, + 0xE3E3, 0x5A20, 0xE3E4, 0x5BB8, 0xE3E5, 0x613C, 0xE3E6, 0x65B0, 0xE3E7, 0x6668, 0xE3E8, 0x71FC, 0xE3E9, 0x7533, 0xE3EA, 0x795E, + 0xE3EB, 0x7D33, 0xE3EC, 0x814E, 0xE3ED, 0x81E3, 0xE3EE, 0x8398, 0xE3EF, 0x85AA, 0xE3F0, 0x85CE, 0xE3F1, 0x8703, 0xE3F2, 0x8A0A, + 0xE3F3, 0x8EAB, 0xE3F4, 0x8F9B, 0xE3F5, 0xF971, 0xE3F6, 0x8FC5, 0xE3F7, 0x5931, 0xE3F8, 0x5BA4, 0xE3F9, 0x5BE6, 0xE3FA, 0x6089, + 0xE3FB, 0x5BE9, 0xE3FC, 0x5C0B, 0xE3FD, 0x5FC3, 0xE3FE, 0x6C81, 0xE4A1, 0xF972, 0xE4A2, 0x6DF1, 0xE4A3, 0x700B, 0xE4A4, 0x751A, + 0xE4A5, 0x82AF, 0xE4A6, 0x8AF6, 0xE4A7, 0x4EC0, 0xE4A8, 0x5341, 0xE4A9, 0xF973, 0xE4AA, 0x96D9, 0xE4AB, 0x6C0F, 0xE4AC, 0x4E9E, + 0xE4AD, 0x4FC4, 0xE4AE, 0x5152, 0xE4AF, 0x555E, 0xE4B0, 0x5A25, 0xE4B1, 0x5CE8, 0xE4B2, 0x6211, 0xE4B3, 0x7259, 0xE4B4, 0x82BD, + 0xE4B5, 0x83AA, 0xE4B6, 0x86FE, 0xE4B7, 0x8859, 0xE4B8, 0x8A1D, 0xE4B9, 0x963F, 0xE4BA, 0x96C5, 0xE4BB, 0x9913, 0xE4BC, 0x9D09, + 0xE4BD, 0x9D5D, 0xE4BE, 0x580A, 0xE4BF, 0x5CB3, 0xE4C0, 0x5DBD, 0xE4C1, 0x5E44, 0xE4C2, 0x60E1, 0xE4C3, 0x6115, 0xE4C4, 0x63E1, + 0xE4C5, 0x6A02, 0xE4C6, 0x6E25, 0xE4C7, 0x9102, 0xE4C8, 0x9354, 0xE4C9, 0x984E, 0xE4CA, 0x9C10, 0xE4CB, 0x9F77, 0xE4CC, 0x5B89, + 0xE4CD, 0x5CB8, 0xE4CE, 0x6309, 0xE4CF, 0x664F, 0xE4D0, 0x6848, 0xE4D1, 0x773C, 0xE4D2, 0x96C1, 0xE4D3, 0x978D, 0xE4D4, 0x9854, + 0xE4D5, 0x9B9F, 0xE4D6, 0x65A1, 0xE4D7, 0x8B01, 0xE4D8, 0x8ECB, 0xE4D9, 0x95BC, 0xE4DA, 0x5535, 0xE4DB, 0x5CA9, 0xE4DC, 0x5DD6, + 0xE4DD, 0x5EB5, 0xE4DE, 0x6697, 0xE4DF, 0x764C, 0xE4E0, 0x83F4, 0xE4E1, 0x95C7, 0xE4E2, 0x58D3, 0xE4E3, 0x62BC, 0xE4E4, 0x72CE, + 0xE4E5, 0x9D28, 0xE4E6, 0x4EF0, 0xE4E7, 0x592E, 0xE4E8, 0x600F, 0xE4E9, 0x663B, 0xE4EA, 0x6B83, 0xE4EB, 0x79E7, 0xE4EC, 0x9D26, + 0xE4ED, 0x5393, 0xE4EE, 0x54C0, 0xE4EF, 0x57C3, 0xE4F0, 0x5D16, 0xE4F1, 0x611B, 0xE4F2, 0x66D6, 0xE4F3, 0x6DAF, 0xE4F4, 0x788D, + 0xE4F5, 0x827E, 0xE4F6, 0x9698, 0xE4F7, 0x9744, 0xE4F8, 0x5384, 0xE4F9, 0x627C, 0xE4FA, 0x6396, 0xE4FB, 0x6DB2, 0xE4FC, 0x7E0A, + 0xE4FD, 0x814B, 0xE4FE, 0x984D, 0xE5A1, 0x6AFB, 0xE5A2, 0x7F4C, 0xE5A3, 0x9DAF, 0xE5A4, 0x9E1A, 0xE5A5, 0x4E5F, 0xE5A6, 0x503B, + 0xE5A7, 0x51B6, 0xE5A8, 0x591C, 0xE5A9, 0x60F9, 0xE5AA, 0x63F6, 0xE5AB, 0x6930, 0xE5AC, 0x723A, 0xE5AD, 0x8036, 0xE5AE, 0xF974, + 0xE5AF, 0x91CE, 0xE5B0, 0x5F31, 0xE5B1, 0xF975, 0xE5B2, 0xF976, 0xE5B3, 0x7D04, 0xE5B4, 0x82E5, 0xE5B5, 0x846F, 0xE5B6, 0x84BB, + 0xE5B7, 0x85E5, 0xE5B8, 0x8E8D, 0xE5B9, 0xF977, 0xE5BA, 0x4F6F, 0xE5BB, 0xF978, 0xE5BC, 0xF979, 0xE5BD, 0x58E4, 0xE5BE, 0x5B43, + 0xE5BF, 0x6059, 0xE5C0, 0x63DA, 0xE5C1, 0x6518, 0xE5C2, 0x656D, 0xE5C3, 0x6698, 0xE5C4, 0xF97A, 0xE5C5, 0x694A, 0xE5C6, 0x6A23, + 0xE5C7, 0x6D0B, 0xE5C8, 0x7001, 0xE5C9, 0x716C, 0xE5CA, 0x75D2, 0xE5CB, 0x760D, 0xE5CC, 0x79B3, 0xE5CD, 0x7A70, 0xE5CE, 0xF97B, + 0xE5CF, 0x7F8A, 0xE5D0, 0xF97C, 0xE5D1, 0x8944, 0xE5D2, 0xF97D, 0xE5D3, 0x8B93, 0xE5D4, 0x91C0, 0xE5D5, 0x967D, 0xE5D6, 0xF97E, + 0xE5D7, 0x990A, 0xE5D8, 0x5704, 0xE5D9, 0x5FA1, 0xE5DA, 0x65BC, 0xE5DB, 0x6F01, 0xE5DC, 0x7600, 0xE5DD, 0x79A6, 0xE5DE, 0x8A9E, + 0xE5DF, 0x99AD, 0xE5E0, 0x9B5A, 0xE5E1, 0x9F6C, 0xE5E2, 0x5104, 0xE5E3, 0x61B6, 0xE5E4, 0x6291, 0xE5E5, 0x6A8D, 0xE5E6, 0x81C6, + 0xE5E7, 0x5043, 0xE5E8, 0x5830, 0xE5E9, 0x5F66, 0xE5EA, 0x7109, 0xE5EB, 0x8A00, 0xE5EC, 0x8AFA, 0xE5ED, 0x5B7C, 0xE5EE, 0x8616, + 0xE5EF, 0x4FFA, 0xE5F0, 0x513C, 0xE5F1, 0x56B4, 0xE5F2, 0x5944, 0xE5F3, 0x63A9, 0xE5F4, 0x6DF9, 0xE5F5, 0x5DAA, 0xE5F6, 0x696D, + 0xE5F7, 0x5186, 0xE5F8, 0x4E88, 0xE5F9, 0x4F59, 0xE5FA, 0xF97F, 0xE5FB, 0xF980, 0xE5FC, 0xF981, 0xE5FD, 0x5982, 0xE5FE, 0xF982, + 0xE6A1, 0xF983, 0xE6A2, 0x6B5F, 0xE6A3, 0x6C5D, 0xE6A4, 0xF984, 0xE6A5, 0x74B5, 0xE6A6, 0x7916, 0xE6A7, 0xF985, 0xE6A8, 0x8207, + 0xE6A9, 0x8245, 0xE6AA, 0x8339, 0xE6AB, 0x8F3F, 0xE6AC, 0x8F5D, 0xE6AD, 0xF986, 0xE6AE, 0x9918, 0xE6AF, 0xF987, 0xE6B0, 0xF988, + 0xE6B1, 0xF989, 0xE6B2, 0x4EA6, 0xE6B3, 0xF98A, 0xE6B4, 0x57DF, 0xE6B5, 0x5F79, 0xE6B6, 0x6613, 0xE6B7, 0xF98B, 0xE6B8, 0xF98C, + 0xE6B9, 0x75AB, 0xE6BA, 0x7E79, 0xE6BB, 0x8B6F, 0xE6BC, 0xF98D, 0xE6BD, 0x9006, 0xE6BE, 0x9A5B, 0xE6BF, 0x56A5, 0xE6C0, 0x5827, + 0xE6C1, 0x59F8, 0xE6C2, 0x5A1F, 0xE6C3, 0x5BB4, 0xE6C4, 0xF98E, 0xE6C5, 0x5EF6, 0xE6C6, 0xF98F, 0xE6C7, 0xF990, 0xE6C8, 0x6350, + 0xE6C9, 0x633B, 0xE6CA, 0xF991, 0xE6CB, 0x693D, 0xE6CC, 0x6C87, 0xE6CD, 0x6CBF, 0xE6CE, 0x6D8E, 0xE6CF, 0x6D93, 0xE6D0, 0x6DF5, + 0xE6D1, 0x6F14, 0xE6D2, 0xF992, 0xE6D3, 0x70DF, 0xE6D4, 0x7136, 0xE6D5, 0x7159, 0xE6D6, 0xF993, 0xE6D7, 0x71C3, 0xE6D8, 0x71D5, + 0xE6D9, 0xF994, 0xE6DA, 0x784F, 0xE6DB, 0x786F, 0xE6DC, 0xF995, 0xE6DD, 0x7B75, 0xE6DE, 0x7DE3, 0xE6DF, 0xF996, 0xE6E0, 0x7E2F, + 0xE6E1, 0xF997, 0xE6E2, 0x884D, 0xE6E3, 0x8EDF, 0xE6E4, 0xF998, 0xE6E5, 0xF999, 0xE6E6, 0xF99A, 0xE6E7, 0x925B, 0xE6E8, 0xF99B, + 0xE6E9, 0x9CF6, 0xE6EA, 0xF99C, 0xE6EB, 0xF99D, 0xE6EC, 0xF99E, 0xE6ED, 0x6085, 0xE6EE, 0x6D85, 0xE6EF, 0xF99F, 0xE6F0, 0x71B1, + 0xE6F1, 0xF9A0, 0xE6F2, 0xF9A1, 0xE6F3, 0x95B1, 0xE6F4, 0x53AD, 0xE6F5, 0xF9A2, 0xE6F6, 0xF9A3, 0xE6F7, 0xF9A4, 0xE6F8, 0x67D3, + 0xE6F9, 0xF9A5, 0xE6FA, 0x708E, 0xE6FB, 0x7130, 0xE6FC, 0x7430, 0xE6FD, 0x8276, 0xE6FE, 0x82D2, 0xE7A1, 0xF9A6, 0xE7A2, 0x95BB, + 0xE7A3, 0x9AE5, 0xE7A4, 0x9E7D, 0xE7A5, 0x66C4, 0xE7A6, 0xF9A7, 0xE7A7, 0x71C1, 0xE7A8, 0x8449, 0xE7A9, 0xF9A8, 0xE7AA, 0xF9A9, + 0xE7AB, 0x584B, 0xE7AC, 0xF9AA, 0xE7AD, 0xF9AB, 0xE7AE, 0x5DB8, 0xE7AF, 0x5F71, 0xE7B0, 0xF9AC, 0xE7B1, 0x6620, 0xE7B2, 0x668E, + 0xE7B3, 0x6979, 0xE7B4, 0x69AE, 0xE7B5, 0x6C38, 0xE7B6, 0x6CF3, 0xE7B7, 0x6E36, 0xE7B8, 0x6F41, 0xE7B9, 0x6FDA, 0xE7BA, 0x701B, + 0xE7BB, 0x702F, 0xE7BC, 0x7150, 0xE7BD, 0x71DF, 0xE7BE, 0x7370, 0xE7BF, 0xF9AD, 0xE7C0, 0x745B, 0xE7C1, 0xF9AE, 0xE7C2, 0x74D4, + 0xE7C3, 0x76C8, 0xE7C4, 0x7A4E, 0xE7C5, 0x7E93, 0xE7C6, 0xF9AF, 0xE7C7, 0xF9B0, 0xE7C8, 0x82F1, 0xE7C9, 0x8A60, 0xE7CA, 0x8FCE, + 0xE7CB, 0xF9B1, 0xE7CC, 0x9348, 0xE7CD, 0xF9B2, 0xE7CE, 0x9719, 0xE7CF, 0xF9B3, 0xE7D0, 0xF9B4, 0xE7D1, 0x4E42, 0xE7D2, 0x502A, + 0xE7D3, 0xF9B5, 0xE7D4, 0x5208, 0xE7D5, 0x53E1, 0xE7D6, 0x66F3, 0xE7D7, 0x6C6D, 0xE7D8, 0x6FCA, 0xE7D9, 0x730A, 0xE7DA, 0x777F, + 0xE7DB, 0x7A62, 0xE7DC, 0x82AE, 0xE7DD, 0x85DD, 0xE7DE, 0x8602, 0xE7DF, 0xF9B6, 0xE7E0, 0x88D4, 0xE7E1, 0x8A63, 0xE7E2, 0x8B7D, + 0xE7E3, 0x8C6B, 0xE7E4, 0xF9B7, 0xE7E5, 0x92B3, 0xE7E6, 0xF9B8, 0xE7E7, 0x9713, 0xE7E8, 0x9810, 0xE7E9, 0x4E94, 0xE7EA, 0x4F0D, + 0xE7EB, 0x4FC9, 0xE7EC, 0x50B2, 0xE7ED, 0x5348, 0xE7EE, 0x543E, 0xE7EF, 0x5433, 0xE7F0, 0x55DA, 0xE7F1, 0x5862, 0xE7F2, 0x58BA, + 0xE7F3, 0x5967, 0xE7F4, 0x5A1B, 0xE7F5, 0x5BE4, 0xE7F6, 0x609F, 0xE7F7, 0xF9B9, 0xE7F8, 0x61CA, 0xE7F9, 0x6556, 0xE7FA, 0x65FF, + 0xE7FB, 0x6664, 0xE7FC, 0x68A7, 0xE7FD, 0x6C5A, 0xE7FE, 0x6FB3, 0xE8A1, 0x70CF, 0xE8A2, 0x71AC, 0xE8A3, 0x7352, 0xE8A4, 0x7B7D, + 0xE8A5, 0x8708, 0xE8A6, 0x8AA4, 0xE8A7, 0x9C32, 0xE8A8, 0x9F07, 0xE8A9, 0x5C4B, 0xE8AA, 0x6C83, 0xE8AB, 0x7344, 0xE8AC, 0x7389, + 0xE8AD, 0x923A, 0xE8AE, 0x6EAB, 0xE8AF, 0x7465, 0xE8B0, 0x761F, 0xE8B1, 0x7A69, 0xE8B2, 0x7E15, 0xE8B3, 0x860A, 0xE8B4, 0x5140, + 0xE8B5, 0x58C5, 0xE8B6, 0x64C1, 0xE8B7, 0x74EE, 0xE8B8, 0x7515, 0xE8B9, 0x7670, 0xE8BA, 0x7FC1, 0xE8BB, 0x9095, 0xE8BC, 0x96CD, + 0xE8BD, 0x9954, 0xE8BE, 0x6E26, 0xE8BF, 0x74E6, 0xE8C0, 0x7AA9, 0xE8C1, 0x7AAA, 0xE8C2, 0x81E5, 0xE8C3, 0x86D9, 0xE8C4, 0x8778, + 0xE8C5, 0x8A1B, 0xE8C6, 0x5A49, 0xE8C7, 0x5B8C, 0xE8C8, 0x5B9B, 0xE8C9, 0x68A1, 0xE8CA, 0x6900, 0xE8CB, 0x6D63, 0xE8CC, 0x73A9, + 0xE8CD, 0x7413, 0xE8CE, 0x742C, 0xE8CF, 0x7897, 0xE8D0, 0x7DE9, 0xE8D1, 0x7FEB, 0xE8D2, 0x8118, 0xE8D3, 0x8155, 0xE8D4, 0x839E, + 0xE8D5, 0x8C4C, 0xE8D6, 0x962E, 0xE8D7, 0x9811, 0xE8D8, 0x66F0, 0xE8D9, 0x5F80, 0xE8DA, 0x65FA, 0xE8DB, 0x6789, 0xE8DC, 0x6C6A, + 0xE8DD, 0x738B, 0xE8DE, 0x502D, 0xE8DF, 0x5A03, 0xE8E0, 0x6B6A, 0xE8E1, 0x77EE, 0xE8E2, 0x5916, 0xE8E3, 0x5D6C, 0xE8E4, 0x5DCD, + 0xE8E5, 0x7325, 0xE8E6, 0x754F, 0xE8E7, 0xF9BA, 0xE8E8, 0xF9BB, 0xE8E9, 0x50E5, 0xE8EA, 0x51F9, 0xE8EB, 0x582F, 0xE8EC, 0x592D, + 0xE8ED, 0x5996, 0xE8EE, 0x59DA, 0xE8EF, 0x5BE5, 0xE8F0, 0xF9BC, 0xE8F1, 0xF9BD, 0xE8F2, 0x5DA2, 0xE8F3, 0x62D7, 0xE8F4, 0x6416, + 0xE8F5, 0x6493, 0xE8F6, 0x64FE, 0xE8F7, 0xF9BE, 0xE8F8, 0x66DC, 0xE8F9, 0xF9BF, 0xE8FA, 0x6A48, 0xE8FB, 0xF9C0, 0xE8FC, 0x71FF, + 0xE8FD, 0x7464, 0xE8FE, 0xF9C1, 0xE9A1, 0x7A88, 0xE9A2, 0x7AAF, 0xE9A3, 0x7E47, 0xE9A4, 0x7E5E, 0xE9A5, 0x8000, 0xE9A6, 0x8170, + 0xE9A7, 0xF9C2, 0xE9A8, 0x87EF, 0xE9A9, 0x8981, 0xE9AA, 0x8B20, 0xE9AB, 0x9059, 0xE9AC, 0xF9C3, 0xE9AD, 0x9080, 0xE9AE, 0x9952, + 0xE9AF, 0x617E, 0xE9B0, 0x6B32, 0xE9B1, 0x6D74, 0xE9B2, 0x7E1F, 0xE9B3, 0x8925, 0xE9B4, 0x8FB1, 0xE9B5, 0x4FD1, 0xE9B6, 0x50AD, + 0xE9B7, 0x5197, 0xE9B8, 0x52C7, 0xE9B9, 0x57C7, 0xE9BA, 0x5889, 0xE9BB, 0x5BB9, 0xE9BC, 0x5EB8, 0xE9BD, 0x6142, 0xE9BE, 0x6995, + 0xE9BF, 0x6D8C, 0xE9C0, 0x6E67, 0xE9C1, 0x6EB6, 0xE9C2, 0x7194, 0xE9C3, 0x7462, 0xE9C4, 0x7528, 0xE9C5, 0x752C, 0xE9C6, 0x8073, + 0xE9C7, 0x8338, 0xE9C8, 0x84C9, 0xE9C9, 0x8E0A, 0xE9CA, 0x9394, 0xE9CB, 0x93DE, 0xE9CC, 0xF9C4, 0xE9CD, 0x4E8E, 0xE9CE, 0x4F51, + 0xE9CF, 0x5076, 0xE9D0, 0x512A, 0xE9D1, 0x53C8, 0xE9D2, 0x53CB, 0xE9D3, 0x53F3, 0xE9D4, 0x5B87, 0xE9D5, 0x5BD3, 0xE9D6, 0x5C24, + 0xE9D7, 0x611A, 0xE9D8, 0x6182, 0xE9D9, 0x65F4, 0xE9DA, 0x725B, 0xE9DB, 0x7397, 0xE9DC, 0x7440, 0xE9DD, 0x76C2, 0xE9DE, 0x7950, + 0xE9DF, 0x7991, 0xE9E0, 0x79B9, 0xE9E1, 0x7D06, 0xE9E2, 0x7FBD, 0xE9E3, 0x828B, 0xE9E4, 0x85D5, 0xE9E5, 0x865E, 0xE9E6, 0x8FC2, + 0xE9E7, 0x9047, 0xE9E8, 0x90F5, 0xE9E9, 0x91EA, 0xE9EA, 0x9685, 0xE9EB, 0x96E8, 0xE9EC, 0x96E9, 0xE9ED, 0x52D6, 0xE9EE, 0x5F67, + 0xE9EF, 0x65ED, 0xE9F0, 0x6631, 0xE9F1, 0x682F, 0xE9F2, 0x715C, 0xE9F3, 0x7A36, 0xE9F4, 0x90C1, 0xE9F5, 0x980A, 0xE9F6, 0x4E91, + 0xE9F7, 0xF9C5, 0xE9F8, 0x6A52, 0xE9F9, 0x6B9E, 0xE9FA, 0x6F90, 0xE9FB, 0x7189, 0xE9FC, 0x8018, 0xE9FD, 0x82B8, 0xE9FE, 0x8553, + 0xEAA1, 0x904B, 0xEAA2, 0x9695, 0xEAA3, 0x96F2, 0xEAA4, 0x97FB, 0xEAA5, 0x851A, 0xEAA6, 0x9B31, 0xEAA7, 0x4E90, 0xEAA8, 0x718A, + 0xEAA9, 0x96C4, 0xEAAA, 0x5143, 0xEAAB, 0x539F, 0xEAAC, 0x54E1, 0xEAAD, 0x5713, 0xEAAE, 0x5712, 0xEAAF, 0x57A3, 0xEAB0, 0x5A9B, + 0xEAB1, 0x5AC4, 0xEAB2, 0x5BC3, 0xEAB3, 0x6028, 0xEAB4, 0x613F, 0xEAB5, 0x63F4, 0xEAB6, 0x6C85, 0xEAB7, 0x6D39, 0xEAB8, 0x6E72, + 0xEAB9, 0x6E90, 0xEABA, 0x7230, 0xEABB, 0x733F, 0xEABC, 0x7457, 0xEABD, 0x82D1, 0xEABE, 0x8881, 0xEABF, 0x8F45, 0xEAC0, 0x9060, + 0xEAC1, 0xF9C6, 0xEAC2, 0x9662, 0xEAC3, 0x9858, 0xEAC4, 0x9D1B, 0xEAC5, 0x6708, 0xEAC6, 0x8D8A, 0xEAC7, 0x925E, 0xEAC8, 0x4F4D, + 0xEAC9, 0x5049, 0xEACA, 0x50DE, 0xEACB, 0x5371, 0xEACC, 0x570D, 0xEACD, 0x59D4, 0xEACE, 0x5A01, 0xEACF, 0x5C09, 0xEAD0, 0x6170, + 0xEAD1, 0x6690, 0xEAD2, 0x6E2D, 0xEAD3, 0x7232, 0xEAD4, 0x744B, 0xEAD5, 0x7DEF, 0xEAD6, 0x80C3, 0xEAD7, 0x840E, 0xEAD8, 0x8466, + 0xEAD9, 0x853F, 0xEADA, 0x875F, 0xEADB, 0x885B, 0xEADC, 0x8918, 0xEADD, 0x8B02, 0xEADE, 0x9055, 0xEADF, 0x97CB, 0xEAE0, 0x9B4F, + 0xEAE1, 0x4E73, 0xEAE2, 0x4F91, 0xEAE3, 0x5112, 0xEAE4, 0x516A, 0xEAE5, 0xF9C7, 0xEAE6, 0x552F, 0xEAE7, 0x55A9, 0xEAE8, 0x5B7A, + 0xEAE9, 0x5BA5, 0xEAEA, 0x5E7C, 0xEAEB, 0x5E7D, 0xEAEC, 0x5EBE, 0xEAED, 0x60A0, 0xEAEE, 0x60DF, 0xEAEF, 0x6108, 0xEAF0, 0x6109, + 0xEAF1, 0x63C4, 0xEAF2, 0x6538, 0xEAF3, 0x6709, 0xEAF4, 0xF9C8, 0xEAF5, 0x67D4, 0xEAF6, 0x67DA, 0xEAF7, 0xF9C9, 0xEAF8, 0x6961, + 0xEAF9, 0x6962, 0xEAFA, 0x6CB9, 0xEAFB, 0x6D27, 0xEAFC, 0xF9CA, 0xEAFD, 0x6E38, 0xEAFE, 0xF9CB, 0xEBA1, 0x6FE1, 0xEBA2, 0x7336, + 0xEBA3, 0x7337, 0xEBA4, 0xF9CC, 0xEBA5, 0x745C, 0xEBA6, 0x7531, 0xEBA7, 0xF9CD, 0xEBA8, 0x7652, 0xEBA9, 0xF9CE, 0xEBAA, 0xF9CF, + 0xEBAB, 0x7DAD, 0xEBAC, 0x81FE, 0xEBAD, 0x8438, 0xEBAE, 0x88D5, 0xEBAF, 0x8A98, 0xEBB0, 0x8ADB, 0xEBB1, 0x8AED, 0xEBB2, 0x8E30, + 0xEBB3, 0x8E42, 0xEBB4, 0x904A, 0xEBB5, 0x903E, 0xEBB6, 0x907A, 0xEBB7, 0x9149, 0xEBB8, 0x91C9, 0xEBB9, 0x936E, 0xEBBA, 0xF9D0, + 0xEBBB, 0xF9D1, 0xEBBC, 0x5809, 0xEBBD, 0xF9D2, 0xEBBE, 0x6BD3, 0xEBBF, 0x8089, 0xEBC0, 0x80B2, 0xEBC1, 0xF9D3, 0xEBC2, 0xF9D4, + 0xEBC3, 0x5141, 0xEBC4, 0x596B, 0xEBC5, 0x5C39, 0xEBC6, 0xF9D5, 0xEBC7, 0xF9D6, 0xEBC8, 0x6F64, 0xEBC9, 0x73A7, 0xEBCA, 0x80E4, + 0xEBCB, 0x8D07, 0xEBCC, 0xF9D7, 0xEBCD, 0x9217, 0xEBCE, 0x958F, 0xEBCF, 0xF9D8, 0xEBD0, 0xF9D9, 0xEBD1, 0xF9DA, 0xEBD2, 0xF9DB, + 0xEBD3, 0x807F, 0xEBD4, 0x620E, 0xEBD5, 0x701C, 0xEBD6, 0x7D68, 0xEBD7, 0x878D, 0xEBD8, 0xF9DC, 0xEBD9, 0x57A0, 0xEBDA, 0x6069, + 0xEBDB, 0x6147, 0xEBDC, 0x6BB7, 0xEBDD, 0x8ABE, 0xEBDE, 0x9280, 0xEBDF, 0x96B1, 0xEBE0, 0x4E59, 0xEBE1, 0x541F, 0xEBE2, 0x6DEB, + 0xEBE3, 0x852D, 0xEBE4, 0x9670, 0xEBE5, 0x97F3, 0xEBE6, 0x98EE, 0xEBE7, 0x63D6, 0xEBE8, 0x6CE3, 0xEBE9, 0x9091, 0xEBEA, 0x51DD, + 0xEBEB, 0x61C9, 0xEBEC, 0x81BA, 0xEBED, 0x9DF9, 0xEBEE, 0x4F9D, 0xEBEF, 0x501A, 0xEBF0, 0x5100, 0xEBF1, 0x5B9C, 0xEBF2, 0x610F, + 0xEBF3, 0x61FF, 0xEBF4, 0x64EC, 0xEBF5, 0x6905, 0xEBF6, 0x6BC5, 0xEBF7, 0x7591, 0xEBF8, 0x77E3, 0xEBF9, 0x7FA9, 0xEBFA, 0x8264, + 0xEBFB, 0x858F, 0xEBFC, 0x87FB, 0xEBFD, 0x8863, 0xEBFE, 0x8ABC, 0xECA1, 0x8B70, 0xECA2, 0x91AB, 0xECA3, 0x4E8C, 0xECA4, 0x4EE5, + 0xECA5, 0x4F0A, 0xECA6, 0xF9DD, 0xECA7, 0xF9DE, 0xECA8, 0x5937, 0xECA9, 0x59E8, 0xECAA, 0xF9DF, 0xECAB, 0x5DF2, 0xECAC, 0x5F1B, + 0xECAD, 0x5F5B, 0xECAE, 0x6021, 0xECAF, 0xF9E0, 0xECB0, 0xF9E1, 0xECB1, 0xF9E2, 0xECB2, 0xF9E3, 0xECB3, 0x723E, 0xECB4, 0x73E5, + 0xECB5, 0xF9E4, 0xECB6, 0x7570, 0xECB7, 0x75CD, 0xECB8, 0xF9E5, 0xECB9, 0x79FB, 0xECBA, 0xF9E6, 0xECBB, 0x800C, 0xECBC, 0x8033, + 0xECBD, 0x8084, 0xECBE, 0x82E1, 0xECBF, 0x8351, 0xECC0, 0xF9E7, 0xECC1, 0xF9E8, 0xECC2, 0x8CBD, 0xECC3, 0x8CB3, 0xECC4, 0x9087, + 0xECC5, 0xF9E9, 0xECC6, 0xF9EA, 0xECC7, 0x98F4, 0xECC8, 0x990C, 0xECC9, 0xF9EB, 0xECCA, 0xF9EC, 0xECCB, 0x7037, 0xECCC, 0x76CA, + 0xECCD, 0x7FCA, 0xECCE, 0x7FCC, 0xECCF, 0x7FFC, 0xECD0, 0x8B1A, 0xECD1, 0x4EBA, 0xECD2, 0x4EC1, 0xECD3, 0x5203, 0xECD4, 0x5370, + 0xECD5, 0xF9ED, 0xECD6, 0x54BD, 0xECD7, 0x56E0, 0xECD8, 0x59FB, 0xECD9, 0x5BC5, 0xECDA, 0x5F15, 0xECDB, 0x5FCD, 0xECDC, 0x6E6E, + 0xECDD, 0xF9EE, 0xECDE, 0xF9EF, 0xECDF, 0x7D6A, 0xECE0, 0x8335, 0xECE1, 0xF9F0, 0xECE2, 0x8693, 0xECE3, 0x8A8D, 0xECE4, 0xF9F1, + 0xECE5, 0x976D, 0xECE6, 0x9777, 0xECE7, 0xF9F2, 0xECE8, 0xF9F3, 0xECE9, 0x4E00, 0xECEA, 0x4F5A, 0xECEB, 0x4F7E, 0xECEC, 0x58F9, + 0xECED, 0x65E5, 0xECEE, 0x6EA2, 0xECEF, 0x9038, 0xECF0, 0x93B0, 0xECF1, 0x99B9, 0xECF2, 0x4EFB, 0xECF3, 0x58EC, 0xECF4, 0x598A, + 0xECF5, 0x59D9, 0xECF6, 0x6041, 0xECF7, 0xF9F4, 0xECF8, 0xF9F5, 0xECF9, 0x7A14, 0xECFA, 0xF9F6, 0xECFB, 0x834F, 0xECFC, 0x8CC3, + 0xECFD, 0x5165, 0xECFE, 0x5344, 0xEDA1, 0xF9F7, 0xEDA2, 0xF9F8, 0xEDA3, 0xF9F9, 0xEDA4, 0x4ECD, 0xEDA5, 0x5269, 0xEDA6, 0x5B55, + 0xEDA7, 0x82BF, 0xEDA8, 0x4ED4, 0xEDA9, 0x523A, 0xEDAA, 0x54A8, 0xEDAB, 0x59C9, 0xEDAC, 0x59FF, 0xEDAD, 0x5B50, 0xEDAE, 0x5B57, + 0xEDAF, 0x5B5C, 0xEDB0, 0x6063, 0xEDB1, 0x6148, 0xEDB2, 0x6ECB, 0xEDB3, 0x7099, 0xEDB4, 0x716E, 0xEDB5, 0x7386, 0xEDB6, 0x74F7, + 0xEDB7, 0x75B5, 0xEDB8, 0x78C1, 0xEDB9, 0x7D2B, 0xEDBA, 0x8005, 0xEDBB, 0x81EA, 0xEDBC, 0x8328, 0xEDBD, 0x8517, 0xEDBE, 0x85C9, + 0xEDBF, 0x8AEE, 0xEDC0, 0x8CC7, 0xEDC1, 0x96CC, 0xEDC2, 0x4F5C, 0xEDC3, 0x52FA, 0xEDC4, 0x56BC, 0xEDC5, 0x65AB, 0xEDC6, 0x6628, + 0xEDC7, 0x707C, 0xEDC8, 0x70B8, 0xEDC9, 0x7235, 0xEDCA, 0x7DBD, 0xEDCB, 0x828D, 0xEDCC, 0x914C, 0xEDCD, 0x96C0, 0xEDCE, 0x9D72, + 0xEDCF, 0x5B71, 0xEDD0, 0x68E7, 0xEDD1, 0x6B98, 0xEDD2, 0x6F7A, 0xEDD3, 0x76DE, 0xEDD4, 0x5C91, 0xEDD5, 0x66AB, 0xEDD6, 0x6F5B, + 0xEDD7, 0x7BB4, 0xEDD8, 0x7C2A, 0xEDD9, 0x8836, 0xEDDA, 0x96DC, 0xEDDB, 0x4E08, 0xEDDC, 0x4ED7, 0xEDDD, 0x5320, 0xEDDE, 0x5834, + 0xEDDF, 0x58BB, 0xEDE0, 0x58EF, 0xEDE1, 0x596C, 0xEDE2, 0x5C07, 0xEDE3, 0x5E33, 0xEDE4, 0x5E84, 0xEDE5, 0x5F35, 0xEDE6, 0x638C, + 0xEDE7, 0x66B2, 0xEDE8, 0x6756, 0xEDE9, 0x6A1F, 0xEDEA, 0x6AA3, 0xEDEB, 0x6B0C, 0xEDEC, 0x6F3F, 0xEDED, 0x7246, 0xEDEE, 0xF9FA, + 0xEDEF, 0x7350, 0xEDF0, 0x748B, 0xEDF1, 0x7AE0, 0xEDF2, 0x7CA7, 0xEDF3, 0x8178, 0xEDF4, 0x81DF, 0xEDF5, 0x81E7, 0xEDF6, 0x838A, + 0xEDF7, 0x846C, 0xEDF8, 0x8523, 0xEDF9, 0x8594, 0xEDFA, 0x85CF, 0xEDFB, 0x88DD, 0xEDFC, 0x8D13, 0xEDFD, 0x91AC, 0xEDFE, 0x9577, + 0xEEA1, 0x969C, 0xEEA2, 0x518D, 0xEEA3, 0x54C9, 0xEEA4, 0x5728, 0xEEA5, 0x5BB0, 0xEEA6, 0x624D, 0xEEA7, 0x6750, 0xEEA8, 0x683D, + 0xEEA9, 0x6893, 0xEEAA, 0x6E3D, 0xEEAB, 0x6ED3, 0xEEAC, 0x707D, 0xEEAD, 0x7E21, 0xEEAE, 0x88C1, 0xEEAF, 0x8CA1, 0xEEB0, 0x8F09, + 0xEEB1, 0x9F4B, 0xEEB2, 0x9F4E, 0xEEB3, 0x722D, 0xEEB4, 0x7B8F, 0xEEB5, 0x8ACD, 0xEEB6, 0x931A, 0xEEB7, 0x4F47, 0xEEB8, 0x4F4E, + 0xEEB9, 0x5132, 0xEEBA, 0x5480, 0xEEBB, 0x59D0, 0xEEBC, 0x5E95, 0xEEBD, 0x62B5, 0xEEBE, 0x6775, 0xEEBF, 0x696E, 0xEEC0, 0x6A17, + 0xEEC1, 0x6CAE, 0xEEC2, 0x6E1A, 0xEEC3, 0x72D9, 0xEEC4, 0x732A, 0xEEC5, 0x75BD, 0xEEC6, 0x7BB8, 0xEEC7, 0x7D35, 0xEEC8, 0x82E7, + 0xEEC9, 0x83F9, 0xEECA, 0x8457, 0xEECB, 0x85F7, 0xEECC, 0x8A5B, 0xEECD, 0x8CAF, 0xEECE, 0x8E87, 0xEECF, 0x9019, 0xEED0, 0x90B8, + 0xEED1, 0x96CE, 0xEED2, 0x9F5F, 0xEED3, 0x52E3, 0xEED4, 0x540A, 0xEED5, 0x5AE1, 0xEED6, 0x5BC2, 0xEED7, 0x6458, 0xEED8, 0x6575, + 0xEED9, 0x6EF4, 0xEEDA, 0x72C4, 0xEEDB, 0xF9FB, 0xEEDC, 0x7684, 0xEEDD, 0x7A4D, 0xEEDE, 0x7B1B, 0xEEDF, 0x7C4D, 0xEEE0, 0x7E3E, + 0xEEE1, 0x7FDF, 0xEEE2, 0x837B, 0xEEE3, 0x8B2B, 0xEEE4, 0x8CCA, 0xEEE5, 0x8D64, 0xEEE6, 0x8DE1, 0xEEE7, 0x8E5F, 0xEEE8, 0x8FEA, + 0xEEE9, 0x8FF9, 0xEEEA, 0x9069, 0xEEEB, 0x93D1, 0xEEEC, 0x4F43, 0xEEED, 0x4F7A, 0xEEEE, 0x50B3, 0xEEEF, 0x5168, 0xEEF0, 0x5178, + 0xEEF1, 0x524D, 0xEEF2, 0x526A, 0xEEF3, 0x5861, 0xEEF4, 0x587C, 0xEEF5, 0x5960, 0xEEF6, 0x5C08, 0xEEF7, 0x5C55, 0xEEF8, 0x5EDB, + 0xEEF9, 0x609B, 0xEEFA, 0x6230, 0xEEFB, 0x6813, 0xEEFC, 0x6BBF, 0xEEFD, 0x6C08, 0xEEFE, 0x6FB1, 0xEFA1, 0x714E, 0xEFA2, 0x7420, + 0xEFA3, 0x7530, 0xEFA4, 0x7538, 0xEFA5, 0x7551, 0xEFA6, 0x7672, 0xEFA7, 0x7B4C, 0xEFA8, 0x7B8B, 0xEFA9, 0x7BAD, 0xEFAA, 0x7BC6, + 0xEFAB, 0x7E8F, 0xEFAC, 0x8A6E, 0xEFAD, 0x8F3E, 0xEFAE, 0x8F49, 0xEFAF, 0x923F, 0xEFB0, 0x9293, 0xEFB1, 0x9322, 0xEFB2, 0x942B, + 0xEFB3, 0x96FB, 0xEFB4, 0x985A, 0xEFB5, 0x986B, 0xEFB6, 0x991E, 0xEFB7, 0x5207, 0xEFB8, 0x622A, 0xEFB9, 0x6298, 0xEFBA, 0x6D59, + 0xEFBB, 0x7664, 0xEFBC, 0x7ACA, 0xEFBD, 0x7BC0, 0xEFBE, 0x7D76, 0xEFBF, 0x5360, 0xEFC0, 0x5CBE, 0xEFC1, 0x5E97, 0xEFC2, 0x6F38, + 0xEFC3, 0x70B9, 0xEFC4, 0x7C98, 0xEFC5, 0x9711, 0xEFC6, 0x9B8E, 0xEFC7, 0x9EDE, 0xEFC8, 0x63A5, 0xEFC9, 0x647A, 0xEFCA, 0x8776, + 0xEFCB, 0x4E01, 0xEFCC, 0x4E95, 0xEFCD, 0x4EAD, 0xEFCE, 0x505C, 0xEFCF, 0x5075, 0xEFD0, 0x5448, 0xEFD1, 0x59C3, 0xEFD2, 0x5B9A, + 0xEFD3, 0x5E40, 0xEFD4, 0x5EAD, 0xEFD5, 0x5EF7, 0xEFD6, 0x5F81, 0xEFD7, 0x60C5, 0xEFD8, 0x633A, 0xEFD9, 0x653F, 0xEFDA, 0x6574, + 0xEFDB, 0x65CC, 0xEFDC, 0x6676, 0xEFDD, 0x6678, 0xEFDE, 0x67FE, 0xEFDF, 0x6968, 0xEFE0, 0x6A89, 0xEFE1, 0x6B63, 0xEFE2, 0x6C40, + 0xEFE3, 0x6DC0, 0xEFE4, 0x6DE8, 0xEFE5, 0x6E1F, 0xEFE6, 0x6E5E, 0xEFE7, 0x701E, 0xEFE8, 0x70A1, 0xEFE9, 0x738E, 0xEFEA, 0x73FD, + 0xEFEB, 0x753A, 0xEFEC, 0x775B, 0xEFED, 0x7887, 0xEFEE, 0x798E, 0xEFEF, 0x7A0B, 0xEFF0, 0x7A7D, 0xEFF1, 0x7CBE, 0xEFF2, 0x7D8E, + 0xEFF3, 0x8247, 0xEFF4, 0x8A02, 0xEFF5, 0x8AEA, 0xEFF6, 0x8C9E, 0xEFF7, 0x912D, 0xEFF8, 0x914A, 0xEFF9, 0x91D8, 0xEFFA, 0x9266, + 0xEFFB, 0x92CC, 0xEFFC, 0x9320, 0xEFFD, 0x9706, 0xEFFE, 0x9756, 0xF0A1, 0x975C, 0xF0A2, 0x9802, 0xF0A3, 0x9F0E, 0xF0A4, 0x5236, + 0xF0A5, 0x5291, 0xF0A6, 0x557C, 0xF0A7, 0x5824, 0xF0A8, 0x5E1D, 0xF0A9, 0x5F1F, 0xF0AA, 0x608C, 0xF0AB, 0x63D0, 0xF0AC, 0x68AF, + 0xF0AD, 0x6FDF, 0xF0AE, 0x796D, 0xF0AF, 0x7B2C, 0xF0B0, 0x81CD, 0xF0B1, 0x85BA, 0xF0B2, 0x88FD, 0xF0B3, 0x8AF8, 0xF0B4, 0x8E44, + 0xF0B5, 0x918D, 0xF0B6, 0x9664, 0xF0B7, 0x969B, 0xF0B8, 0x973D, 0xF0B9, 0x984C, 0xF0BA, 0x9F4A, 0xF0BB, 0x4FCE, 0xF0BC, 0x5146, + 0xF0BD, 0x51CB, 0xF0BE, 0x52A9, 0xF0BF, 0x5632, 0xF0C0, 0x5F14, 0xF0C1, 0x5F6B, 0xF0C2, 0x63AA, 0xF0C3, 0x64CD, 0xF0C4, 0x65E9, + 0xF0C5, 0x6641, 0xF0C6, 0x66FA, 0xF0C7, 0x66F9, 0xF0C8, 0x671D, 0xF0C9, 0x689D, 0xF0CA, 0x68D7, 0xF0CB, 0x69FD, 0xF0CC, 0x6F15, + 0xF0CD, 0x6F6E, 0xF0CE, 0x7167, 0xF0CF, 0x71E5, 0xF0D0, 0x722A, 0xF0D1, 0x74AA, 0xF0D2, 0x773A, 0xF0D3, 0x7956, 0xF0D4, 0x795A, + 0xF0D5, 0x79DF, 0xF0D6, 0x7A20, 0xF0D7, 0x7A95, 0xF0D8, 0x7C97, 0xF0D9, 0x7CDF, 0xF0DA, 0x7D44, 0xF0DB, 0x7E70, 0xF0DC, 0x8087, + 0xF0DD, 0x85FB, 0xF0DE, 0x86A4, 0xF0DF, 0x8A54, 0xF0E0, 0x8ABF, 0xF0E1, 0x8D99, 0xF0E2, 0x8E81, 0xF0E3, 0x9020, 0xF0E4, 0x906D, + 0xF0E5, 0x91E3, 0xF0E6, 0x963B, 0xF0E7, 0x96D5, 0xF0E8, 0x9CE5, 0xF0E9, 0x65CF, 0xF0EA, 0x7C07, 0xF0EB, 0x8DB3, 0xF0EC, 0x93C3, + 0xF0ED, 0x5B58, 0xF0EE, 0x5C0A, 0xF0EF, 0x5352, 0xF0F0, 0x62D9, 0xF0F1, 0x731D, 0xF0F2, 0x5027, 0xF0F3, 0x5B97, 0xF0F4, 0x5F9E, + 0xF0F5, 0x60B0, 0xF0F6, 0x616B, 0xF0F7, 0x68D5, 0xF0F8, 0x6DD9, 0xF0F9, 0x742E, 0xF0FA, 0x7A2E, 0xF0FB, 0x7D42, 0xF0FC, 0x7D9C, + 0xF0FD, 0x7E31, 0xF0FE, 0x816B, 0xF1A1, 0x8E2A, 0xF1A2, 0x8E35, 0xF1A3, 0x937E, 0xF1A4, 0x9418, 0xF1A5, 0x4F50, 0xF1A6, 0x5750, + 0xF1A7, 0x5DE6, 0xF1A8, 0x5EA7, 0xF1A9, 0x632B, 0xF1AA, 0x7F6A, 0xF1AB, 0x4E3B, 0xF1AC, 0x4F4F, 0xF1AD, 0x4F8F, 0xF1AE, 0x505A, + 0xF1AF, 0x59DD, 0xF1B0, 0x80C4, 0xF1B1, 0x546A, 0xF1B2, 0x5468, 0xF1B3, 0x55FE, 0xF1B4, 0x594F, 0xF1B5, 0x5B99, 0xF1B6, 0x5DDE, + 0xF1B7, 0x5EDA, 0xF1B8, 0x665D, 0xF1B9, 0x6731, 0xF1BA, 0x67F1, 0xF1BB, 0x682A, 0xF1BC, 0x6CE8, 0xF1BD, 0x6D32, 0xF1BE, 0x6E4A, + 0xF1BF, 0x6F8D, 0xF1C0, 0x70B7, 0xF1C1, 0x73E0, 0xF1C2, 0x7587, 0xF1C3, 0x7C4C, 0xF1C4, 0x7D02, 0xF1C5, 0x7D2C, 0xF1C6, 0x7DA2, + 0xF1C7, 0x821F, 0xF1C8, 0x86DB, 0xF1C9, 0x8A3B, 0xF1CA, 0x8A85, 0xF1CB, 0x8D70, 0xF1CC, 0x8E8A, 0xF1CD, 0x8F33, 0xF1CE, 0x9031, + 0xF1CF, 0x914E, 0xF1D0, 0x9152, 0xF1D1, 0x9444, 0xF1D2, 0x99D0, 0xF1D3, 0x7AF9, 0xF1D4, 0x7CA5, 0xF1D5, 0x4FCA, 0xF1D6, 0x5101, + 0xF1D7, 0x51C6, 0xF1D8, 0x57C8, 0xF1D9, 0x5BEF, 0xF1DA, 0x5CFB, 0xF1DB, 0x6659, 0xF1DC, 0x6A3D, 0xF1DD, 0x6D5A, 0xF1DE, 0x6E96, + 0xF1DF, 0x6FEC, 0xF1E0, 0x710C, 0xF1E1, 0x756F, 0xF1E2, 0x7AE3, 0xF1E3, 0x8822, 0xF1E4, 0x9021, 0xF1E5, 0x9075, 0xF1E6, 0x96CB, + 0xF1E7, 0x99FF, 0xF1E8, 0x8301, 0xF1E9, 0x4E2D, 0xF1EA, 0x4EF2, 0xF1EB, 0x8846, 0xF1EC, 0x91CD, 0xF1ED, 0x537D, 0xF1EE, 0x6ADB, + 0xF1EF, 0x696B, 0xF1F0, 0x6C41, 0xF1F1, 0x847A, 0xF1F2, 0x589E, 0xF1F3, 0x618E, 0xF1F4, 0x66FE, 0xF1F5, 0x62EF, 0xF1F6, 0x70DD, + 0xF1F7, 0x7511, 0xF1F8, 0x75C7, 0xF1F9, 0x7E52, 0xF1FA, 0x84B8, 0xF1FB, 0x8B49, 0xF1FC, 0x8D08, 0xF1FD, 0x4E4B, 0xF1FE, 0x53EA, + 0xF2A1, 0x54AB, 0xF2A2, 0x5730, 0xF2A3, 0x5740, 0xF2A4, 0x5FD7, 0xF2A5, 0x6301, 0xF2A6, 0x6307, 0xF2A7, 0x646F, 0xF2A8, 0x652F, + 0xF2A9, 0x65E8, 0xF2AA, 0x667A, 0xF2AB, 0x679D, 0xF2AC, 0x67B3, 0xF2AD, 0x6B62, 0xF2AE, 0x6C60, 0xF2AF, 0x6C9A, 0xF2B0, 0x6F2C, + 0xF2B1, 0x77E5, 0xF2B2, 0x7825, 0xF2B3, 0x7949, 0xF2B4, 0x7957, 0xF2B5, 0x7D19, 0xF2B6, 0x80A2, 0xF2B7, 0x8102, 0xF2B8, 0x81F3, + 0xF2B9, 0x829D, 0xF2BA, 0x82B7, 0xF2BB, 0x8718, 0xF2BC, 0x8A8C, 0xF2BD, 0xF9FC, 0xF2BE, 0x8D04, 0xF2BF, 0x8DBE, 0xF2C0, 0x9072, + 0xF2C1, 0x76F4, 0xF2C2, 0x7A19, 0xF2C3, 0x7A37, 0xF2C4, 0x7E54, 0xF2C5, 0x8077, 0xF2C6, 0x5507, 0xF2C7, 0x55D4, 0xF2C8, 0x5875, + 0xF2C9, 0x632F, 0xF2CA, 0x6422, 0xF2CB, 0x6649, 0xF2CC, 0x664B, 0xF2CD, 0x686D, 0xF2CE, 0x699B, 0xF2CF, 0x6B84, 0xF2D0, 0x6D25, + 0xF2D1, 0x6EB1, 0xF2D2, 0x73CD, 0xF2D3, 0x7468, 0xF2D4, 0x74A1, 0xF2D5, 0x755B, 0xF2D6, 0x75B9, 0xF2D7, 0x76E1, 0xF2D8, 0x771E, + 0xF2D9, 0x778B, 0xF2DA, 0x79E6, 0xF2DB, 0x7E09, 0xF2DC, 0x7E1D, 0xF2DD, 0x81FB, 0xF2DE, 0x852F, 0xF2DF, 0x8897, 0xF2E0, 0x8A3A, + 0xF2E1, 0x8CD1, 0xF2E2, 0x8EEB, 0xF2E3, 0x8FB0, 0xF2E4, 0x9032, 0xF2E5, 0x93AD, 0xF2E6, 0x9663, 0xF2E7, 0x9673, 0xF2E8, 0x9707, + 0xF2E9, 0x4F84, 0xF2EA, 0x53F1, 0xF2EB, 0x59EA, 0xF2EC, 0x5AC9, 0xF2ED, 0x5E19, 0xF2EE, 0x684E, 0xF2EF, 0x74C6, 0xF2F0, 0x75BE, + 0xF2F1, 0x79E9, 0xF2F2, 0x7A92, 0xF2F3, 0x81A3, 0xF2F4, 0x86ED, 0xF2F5, 0x8CEA, 0xF2F6, 0x8DCC, 0xF2F7, 0x8FED, 0xF2F8, 0x659F, + 0xF2F9, 0x6715, 0xF2FA, 0xF9FD, 0xF2FB, 0x57F7, 0xF2FC, 0x6F57, 0xF2FD, 0x7DDD, 0xF2FE, 0x8F2F, 0xF3A1, 0x93F6, 0xF3A2, 0x96C6, + 0xF3A3, 0x5FB5, 0xF3A4, 0x61F2, 0xF3A5, 0x6F84, 0xF3A6, 0x4E14, 0xF3A7, 0x4F98, 0xF3A8, 0x501F, 0xF3A9, 0x53C9, 0xF3AA, 0x55DF, + 0xF3AB, 0x5D6F, 0xF3AC, 0x5DEE, 0xF3AD, 0x6B21, 0xF3AE, 0x6B64, 0xF3AF, 0x78CB, 0xF3B0, 0x7B9A, 0xF3B1, 0xF9FE, 0xF3B2, 0x8E49, + 0xF3B3, 0x8ECA, 0xF3B4, 0x906E, 0xF3B5, 0x6349, 0xF3B6, 0x643E, 0xF3B7, 0x7740, 0xF3B8, 0x7A84, 0xF3B9, 0x932F, 0xF3BA, 0x947F, + 0xF3BB, 0x9F6A, 0xF3BC, 0x64B0, 0xF3BD, 0x6FAF, 0xF3BE, 0x71E6, 0xF3BF, 0x74A8, 0xF3C0, 0x74DA, 0xF3C1, 0x7AC4, 0xF3C2, 0x7C12, + 0xF3C3, 0x7E82, 0xF3C4, 0x7CB2, 0xF3C5, 0x7E98, 0xF3C6, 0x8B9A, 0xF3C7, 0x8D0A, 0xF3C8, 0x947D, 0xF3C9, 0x9910, 0xF3CA, 0x994C, + 0xF3CB, 0x5239, 0xF3CC, 0x5BDF, 0xF3CD, 0x64E6, 0xF3CE, 0x672D, 0xF3CF, 0x7D2E, 0xF3D0, 0x50ED, 0xF3D1, 0x53C3, 0xF3D2, 0x5879, + 0xF3D3, 0x6158, 0xF3D4, 0x6159, 0xF3D5, 0x61FA, 0xF3D6, 0x65AC, 0xF3D7, 0x7AD9, 0xF3D8, 0x8B92, 0xF3D9, 0x8B96, 0xF3DA, 0x5009, + 0xF3DB, 0x5021, 0xF3DC, 0x5275, 0xF3DD, 0x5531, 0xF3DE, 0x5A3C, 0xF3DF, 0x5EE0, 0xF3E0, 0x5F70, 0xF3E1, 0x6134, 0xF3E2, 0x655E, + 0xF3E3, 0x660C, 0xF3E4, 0x6636, 0xF3E5, 0x66A2, 0xF3E6, 0x69CD, 0xF3E7, 0x6EC4, 0xF3E8, 0x6F32, 0xF3E9, 0x7316, 0xF3EA, 0x7621, + 0xF3EB, 0x7A93, 0xF3EC, 0x8139, 0xF3ED, 0x8259, 0xF3EE, 0x83D6, 0xF3EF, 0x84BC, 0xF3F0, 0x50B5, 0xF3F1, 0x57F0, 0xF3F2, 0x5BC0, + 0xF3F3, 0x5BE8, 0xF3F4, 0x5F69, 0xF3F5, 0x63A1, 0xF3F6, 0x7826, 0xF3F7, 0x7DB5, 0xF3F8, 0x83DC, 0xF3F9, 0x8521, 0xF3FA, 0x91C7, + 0xF3FB, 0x91F5, 0xF3FC, 0x518A, 0xF3FD, 0x67F5, 0xF3FE, 0x7B56, 0xF4A1, 0x8CAC, 0xF4A2, 0x51C4, 0xF4A3, 0x59BB, 0xF4A4, 0x60BD, + 0xF4A5, 0x8655, 0xF4A6, 0x501C, 0xF4A7, 0xF9FF, 0xF4A8, 0x5254, 0xF4A9, 0x5C3A, 0xF4AA, 0x617D, 0xF4AB, 0x621A, 0xF4AC, 0x62D3, + 0xF4AD, 0x64F2, 0xF4AE, 0x65A5, 0xF4AF, 0x6ECC, 0xF4B0, 0x7620, 0xF4B1, 0x810A, 0xF4B2, 0x8E60, 0xF4B3, 0x965F, 0xF4B4, 0x96BB, + 0xF4B5, 0x4EDF, 0xF4B6, 0x5343, 0xF4B7, 0x5598, 0xF4B8, 0x5929, 0xF4B9, 0x5DDD, 0xF4BA, 0x64C5, 0xF4BB, 0x6CC9, 0xF4BC, 0x6DFA, + 0xF4BD, 0x7394, 0xF4BE, 0x7A7F, 0xF4BF, 0x821B, 0xF4C0, 0x85A6, 0xF4C1, 0x8CE4, 0xF4C2, 0x8E10, 0xF4C3, 0x9077, 0xF4C4, 0x91E7, + 0xF4C5, 0x95E1, 0xF4C6, 0x9621, 0xF4C7, 0x97C6, 0xF4C8, 0x51F8, 0xF4C9, 0x54F2, 0xF4CA, 0x5586, 0xF4CB, 0x5FB9, 0xF4CC, 0x64A4, + 0xF4CD, 0x6F88, 0xF4CE, 0x7DB4, 0xF4CF, 0x8F1F, 0xF4D0, 0x8F4D, 0xF4D1, 0x9435, 0xF4D2, 0x50C9, 0xF4D3, 0x5C16, 0xF4D4, 0x6CBE, + 0xF4D5, 0x6DFB, 0xF4D6, 0x751B, 0xF4D7, 0x77BB, 0xF4D8, 0x7C3D, 0xF4D9, 0x7C64, 0xF4DA, 0x8A79, 0xF4DB, 0x8AC2, 0xF4DC, 0x581E, + 0xF4DD, 0x59BE, 0xF4DE, 0x5E16, 0xF4DF, 0x6377, 0xF4E0, 0x7252, 0xF4E1, 0x758A, 0xF4E2, 0x776B, 0xF4E3, 0x8ADC, 0xF4E4, 0x8CBC, + 0xF4E5, 0x8F12, 0xF4E6, 0x5EF3, 0xF4E7, 0x6674, 0xF4E8, 0x6DF8, 0xF4E9, 0x807D, 0xF4EA, 0x83C1, 0xF4EB, 0x8ACB, 0xF4EC, 0x9751, + 0xF4ED, 0x9BD6, 0xF4EE, 0xFA00, 0xF4EF, 0x5243, 0xF4F0, 0x66FF, 0xF4F1, 0x6D95, 0xF4F2, 0x6EEF, 0xF4F3, 0x7DE0, 0xF4F4, 0x8AE6, + 0xF4F5, 0x902E, 0xF4F6, 0x905E, 0xF4F7, 0x9AD4, 0xF4F8, 0x521D, 0xF4F9, 0x527F, 0xF4FA, 0x54E8, 0xF4FB, 0x6194, 0xF4FC, 0x6284, + 0xF4FD, 0x62DB, 0xF4FE, 0x68A2, 0xF5A1, 0x6912, 0xF5A2, 0x695A, 0xF5A3, 0x6A35, 0xF5A4, 0x7092, 0xF5A5, 0x7126, 0xF5A6, 0x785D, + 0xF5A7, 0x7901, 0xF5A8, 0x790E, 0xF5A9, 0x79D2, 0xF5AA, 0x7A0D, 0xF5AB, 0x8096, 0xF5AC, 0x8278, 0xF5AD, 0x82D5, 0xF5AE, 0x8349, + 0xF5AF, 0x8549, 0xF5B0, 0x8C82, 0xF5B1, 0x8D85, 0xF5B2, 0x9162, 0xF5B3, 0x918B, 0xF5B4, 0x91AE, 0xF5B5, 0x4FC3, 0xF5B6, 0x56D1, + 0xF5B7, 0x71ED, 0xF5B8, 0x77D7, 0xF5B9, 0x8700, 0xF5BA, 0x89F8, 0xF5BB, 0x5BF8, 0xF5BC, 0x5FD6, 0xF5BD, 0x6751, 0xF5BE, 0x90A8, + 0xF5BF, 0x53E2, 0xF5C0, 0x585A, 0xF5C1, 0x5BF5, 0xF5C2, 0x60A4, 0xF5C3, 0x6181, 0xF5C4, 0x6460, 0xF5C5, 0x7E3D, 0xF5C6, 0x8070, + 0xF5C7, 0x8525, 0xF5C8, 0x9283, 0xF5C9, 0x64AE, 0xF5CA, 0x50AC, 0xF5CB, 0x5D14, 0xF5CC, 0x6700, 0xF5CD, 0x589C, 0xF5CE, 0x62BD, + 0xF5CF, 0x63A8, 0xF5D0, 0x690E, 0xF5D1, 0x6978, 0xF5D2, 0x6A1E, 0xF5D3, 0x6E6B, 0xF5D4, 0x76BA, 0xF5D5, 0x79CB, 0xF5D6, 0x82BB, + 0xF5D7, 0x8429, 0xF5D8, 0x8ACF, 0xF5D9, 0x8DA8, 0xF5DA, 0x8FFD, 0xF5DB, 0x9112, 0xF5DC, 0x914B, 0xF5DD, 0x919C, 0xF5DE, 0x9310, + 0xF5DF, 0x9318, 0xF5E0, 0x939A, 0xF5E1, 0x96DB, 0xF5E2, 0x9A36, 0xF5E3, 0x9C0D, 0xF5E4, 0x4E11, 0xF5E5, 0x755C, 0xF5E6, 0x795D, + 0xF5E7, 0x7AFA, 0xF5E8, 0x7B51, 0xF5E9, 0x7BC9, 0xF5EA, 0x7E2E, 0xF5EB, 0x84C4, 0xF5EC, 0x8E59, 0xF5ED, 0x8E74, 0xF5EE, 0x8EF8, + 0xF5EF, 0x9010, 0xF5F0, 0x6625, 0xF5F1, 0x693F, 0xF5F2, 0x7443, 0xF5F3, 0x51FA, 0xF5F4, 0x672E, 0xF5F5, 0x9EDC, 0xF5F6, 0x5145, + 0xF5F7, 0x5FE0, 0xF5F8, 0x6C96, 0xF5F9, 0x87F2, 0xF5FA, 0x885D, 0xF5FB, 0x8877, 0xF5FC, 0x60B4, 0xF5FD, 0x81B5, 0xF5FE, 0x8403, + 0xF6A1, 0x8D05, 0xF6A2, 0x53D6, 0xF6A3, 0x5439, 0xF6A4, 0x5634, 0xF6A5, 0x5A36, 0xF6A6, 0x5C31, 0xF6A7, 0x708A, 0xF6A8, 0x7FE0, + 0xF6A9, 0x805A, 0xF6AA, 0x8106, 0xF6AB, 0x81ED, 0xF6AC, 0x8DA3, 0xF6AD, 0x9189, 0xF6AE, 0x9A5F, 0xF6AF, 0x9DF2, 0xF6B0, 0x5074, + 0xF6B1, 0x4EC4, 0xF6B2, 0x53A0, 0xF6B3, 0x60FB, 0xF6B4, 0x6E2C, 0xF6B5, 0x5C64, 0xF6B6, 0x4F88, 0xF6B7, 0x5024, 0xF6B8, 0x55E4, + 0xF6B9, 0x5CD9, 0xF6BA, 0x5E5F, 0xF6BB, 0x6065, 0xF6BC, 0x6894, 0xF6BD, 0x6CBB, 0xF6BE, 0x6DC4, 0xF6BF, 0x71BE, 0xF6C0, 0x75D4, + 0xF6C1, 0x75F4, 0xF6C2, 0x7661, 0xF6C3, 0x7A1A, 0xF6C4, 0x7A49, 0xF6C5, 0x7DC7, 0xF6C6, 0x7DFB, 0xF6C7, 0x7F6E, 0xF6C8, 0x81F4, + 0xF6C9, 0x86A9, 0xF6CA, 0x8F1C, 0xF6CB, 0x96C9, 0xF6CC, 0x99B3, 0xF6CD, 0x9F52, 0xF6CE, 0x5247, 0xF6CF, 0x52C5, 0xF6D0, 0x98ED, + 0xF6D1, 0x89AA, 0xF6D2, 0x4E03, 0xF6D3, 0x67D2, 0xF6D4, 0x6F06, 0xF6D5, 0x4FB5, 0xF6D6, 0x5BE2, 0xF6D7, 0x6795, 0xF6D8, 0x6C88, + 0xF6D9, 0x6D78, 0xF6DA, 0x741B, 0xF6DB, 0x7827, 0xF6DC, 0x91DD, 0xF6DD, 0x937C, 0xF6DE, 0x87C4, 0xF6DF, 0x79E4, 0xF6E0, 0x7A31, + 0xF6E1, 0x5FEB, 0xF6E2, 0x4ED6, 0xF6E3, 0x54A4, 0xF6E4, 0x553E, 0xF6E5, 0x58AE, 0xF6E6, 0x59A5, 0xF6E7, 0x60F0, 0xF6E8, 0x6253, + 0xF6E9, 0x62D6, 0xF6EA, 0x6736, 0xF6EB, 0x6955, 0xF6EC, 0x8235, 0xF6ED, 0x9640, 0xF6EE, 0x99B1, 0xF6EF, 0x99DD, 0xF6F0, 0x502C, + 0xF6F1, 0x5353, 0xF6F2, 0x5544, 0xF6F3, 0x577C, 0xF6F4, 0xFA01, 0xF6F5, 0x6258, 0xF6F6, 0xFA02, 0xF6F7, 0x64E2, 0xF6F8, 0x666B, + 0xF6F9, 0x67DD, 0xF6FA, 0x6FC1, 0xF6FB, 0x6FEF, 0xF6FC, 0x7422, 0xF6FD, 0x7438, 0xF6FE, 0x8A17, 0xF7A1, 0x9438, 0xF7A2, 0x5451, + 0xF7A3, 0x5606, 0xF7A4, 0x5766, 0xF7A5, 0x5F48, 0xF7A6, 0x619A, 0xF7A7, 0x6B4E, 0xF7A8, 0x7058, 0xF7A9, 0x70AD, 0xF7AA, 0x7DBB, + 0xF7AB, 0x8A95, 0xF7AC, 0x596A, 0xF7AD, 0x812B, 0xF7AE, 0x63A2, 0xF7AF, 0x7708, 0xF7B0, 0x803D, 0xF7B1, 0x8CAA, 0xF7B2, 0x5854, + 0xF7B3, 0x642D, 0xF7B4, 0x69BB, 0xF7B5, 0x5B95, 0xF7B6, 0x5E11, 0xF7B7, 0x6E6F, 0xF7B8, 0xFA03, 0xF7B9, 0x8569, 0xF7BA, 0x514C, + 0xF7BB, 0x53F0, 0xF7BC, 0x592A, 0xF7BD, 0x6020, 0xF7BE, 0x614B, 0xF7BF, 0x6B86, 0xF7C0, 0x6C70, 0xF7C1, 0x6CF0, 0xF7C2, 0x7B1E, + 0xF7C3, 0x80CE, 0xF7C4, 0x82D4, 0xF7C5, 0x8DC6, 0xF7C6, 0x90B0, 0xF7C7, 0x98B1, 0xF7C8, 0xFA04, 0xF7C9, 0x64C7, 0xF7CA, 0x6FA4, + 0xF7CB, 0x6491, 0xF7CC, 0x6504, 0xF7CD, 0x514E, 0xF7CE, 0x5410, 0xF7CF, 0x571F, 0xF7D0, 0x8A0E, 0xF7D1, 0x615F, 0xF7D2, 0x6876, + 0xF7D3, 0xFA05, 0xF7D4, 0x75DB, 0xF7D5, 0x7B52, 0xF7D6, 0x7D71, 0xF7D7, 0x901A, 0xF7D8, 0x5806, 0xF7D9, 0x69CC, 0xF7DA, 0x817F, + 0xF7DB, 0x892A, 0xF7DC, 0x9000, 0xF7DD, 0x9839, 0xF7DE, 0x5078, 0xF7DF, 0x5957, 0xF7E0, 0x59AC, 0xF7E1, 0x6295, 0xF7E2, 0x900F, + 0xF7E3, 0x9B2A, 0xF7E4, 0x615D, 0xF7E5, 0x7279, 0xF7E6, 0x95D6, 0xF7E7, 0x5761, 0xF7E8, 0x5A46, 0xF7E9, 0x5DF4, 0xF7EA, 0x628A, + 0xF7EB, 0x64AD, 0xF7EC, 0x64FA, 0xF7ED, 0x6777, 0xF7EE, 0x6CE2, 0xF7EF, 0x6D3E, 0xF7F0, 0x722C, 0xF7F1, 0x7436, 0xF7F2, 0x7834, + 0xF7F3, 0x7F77, 0xF7F4, 0x82AD, 0xF7F5, 0x8DDB, 0xF7F6, 0x9817, 0xF7F7, 0x5224, 0xF7F8, 0x5742, 0xF7F9, 0x677F, 0xF7FA, 0x7248, + 0xF7FB, 0x74E3, 0xF7FC, 0x8CA9, 0xF7FD, 0x8FA6, 0xF7FE, 0x9211, 0xF8A1, 0x962A, 0xF8A2, 0x516B, 0xF8A3, 0x53ED, 0xF8A4, 0x634C, + 0xF8A5, 0x4F69, 0xF8A6, 0x5504, 0xF8A7, 0x6096, 0xF8A8, 0x6557, 0xF8A9, 0x6C9B, 0xF8AA, 0x6D7F, 0xF8AB, 0x724C, 0xF8AC, 0x72FD, + 0xF8AD, 0x7A17, 0xF8AE, 0x8987, 0xF8AF, 0x8C9D, 0xF8B0, 0x5F6D, 0xF8B1, 0x6F8E, 0xF8B2, 0x70F9, 0xF8B3, 0x81A8, 0xF8B4, 0x610E, + 0xF8B5, 0x4FBF, 0xF8B6, 0x504F, 0xF8B7, 0x6241, 0xF8B8, 0x7247, 0xF8B9, 0x7BC7, 0xF8BA, 0x7DE8, 0xF8BB, 0x7FE9, 0xF8BC, 0x904D, + 0xF8BD, 0x97AD, 0xF8BE, 0x9A19, 0xF8BF, 0x8CB6, 0xF8C0, 0x576A, 0xF8C1, 0x5E73, 0xF8C2, 0x67B0, 0xF8C3, 0x840D, 0xF8C4, 0x8A55, + 0xF8C5, 0x5420, 0xF8C6, 0x5B16, 0xF8C7, 0x5E63, 0xF8C8, 0x5EE2, 0xF8C9, 0x5F0A, 0xF8CA, 0x6583, 0xF8CB, 0x80BA, 0xF8CC, 0x853D, + 0xF8CD, 0x9589, 0xF8CE, 0x965B, 0xF8CF, 0x4F48, 0xF8D0, 0x5305, 0xF8D1, 0x530D, 0xF8D2, 0x530F, 0xF8D3, 0x5486, 0xF8D4, 0x54FA, + 0xF8D5, 0x5703, 0xF8D6, 0x5E03, 0xF8D7, 0x6016, 0xF8D8, 0x629B, 0xF8D9, 0x62B1, 0xF8DA, 0x6355, 0xF8DB, 0xFA06, 0xF8DC, 0x6CE1, + 0xF8DD, 0x6D66, 0xF8DE, 0x75B1, 0xF8DF, 0x7832, 0xF8E0, 0x80DE, 0xF8E1, 0x812F, 0xF8E2, 0x82DE, 0xF8E3, 0x8461, 0xF8E4, 0x84B2, + 0xF8E5, 0x888D, 0xF8E6, 0x8912, 0xF8E7, 0x900B, 0xF8E8, 0x92EA, 0xF8E9, 0x98FD, 0xF8EA, 0x9B91, 0xF8EB, 0x5E45, 0xF8EC, 0x66B4, + 0xF8ED, 0x66DD, 0xF8EE, 0x7011, 0xF8EF, 0x7206, 0xF8F0, 0xFA07, 0xF8F1, 0x4FF5, 0xF8F2, 0x527D, 0xF8F3, 0x5F6A, 0xF8F4, 0x6153, + 0xF8F5, 0x6753, 0xF8F6, 0x6A19, 0xF8F7, 0x6F02, 0xF8F8, 0x74E2, 0xF8F9, 0x7968, 0xF8FA, 0x8868, 0xF8FB, 0x8C79, 0xF8FC, 0x98C7, + 0xF8FD, 0x98C4, 0xF8FE, 0x9A43, 0xF9A1, 0x54C1, 0xF9A2, 0x7A1F, 0xF9A3, 0x6953, 0xF9A4, 0x8AF7, 0xF9A5, 0x8C4A, 0xF9A6, 0x98A8, + 0xF9A7, 0x99AE, 0xF9A8, 0x5F7C, 0xF9A9, 0x62AB, 0xF9AA, 0x75B2, 0xF9AB, 0x76AE, 0xF9AC, 0x88AB, 0xF9AD, 0x907F, 0xF9AE, 0x9642, + 0xF9AF, 0x5339, 0xF9B0, 0x5F3C, 0xF9B1, 0x5FC5, 0xF9B2, 0x6CCC, 0xF9B3, 0x73CC, 0xF9B4, 0x7562, 0xF9B5, 0x758B, 0xF9B6, 0x7B46, + 0xF9B7, 0x82FE, 0xF9B8, 0x999D, 0xF9B9, 0x4E4F, 0xF9BA, 0x903C, 0xF9BB, 0x4E0B, 0xF9BC, 0x4F55, 0xF9BD, 0x53A6, 0xF9BE, 0x590F, + 0xF9BF, 0x5EC8, 0xF9C0, 0x6630, 0xF9C1, 0x6CB3, 0xF9C2, 0x7455, 0xF9C3, 0x8377, 0xF9C4, 0x8766, 0xF9C5, 0x8CC0, 0xF9C6, 0x9050, + 0xF9C7, 0x971E, 0xF9C8, 0x9C15, 0xF9C9, 0x58D1, 0xF9CA, 0x5B78, 0xF9CB, 0x8650, 0xF9CC, 0x8B14, 0xF9CD, 0x9DB4, 0xF9CE, 0x5BD2, + 0xF9CF, 0x6068, 0xF9D0, 0x608D, 0xF9D1, 0x65F1, 0xF9D2, 0x6C57, 0xF9D3, 0x6F22, 0xF9D4, 0x6FA3, 0xF9D5, 0x701A, 0xF9D6, 0x7F55, + 0xF9D7, 0x7FF0, 0xF9D8, 0x9591, 0xF9D9, 0x9592, 0xF9DA, 0x9650, 0xF9DB, 0x97D3, 0xF9DC, 0x5272, 0xF9DD, 0x8F44, 0xF9DE, 0x51FD, + 0xF9DF, 0x542B, 0xF9E0, 0x54B8, 0xF9E1, 0x5563, 0xF9E2, 0x558A, 0xF9E3, 0x6ABB, 0xF9E4, 0x6DB5, 0xF9E5, 0x7DD8, 0xF9E6, 0x8266, + 0xF9E7, 0x929C, 0xF9E8, 0x9677, 0xF9E9, 0x9E79, 0xF9EA, 0x5408, 0xF9EB, 0x54C8, 0xF9EC, 0x76D2, 0xF9ED, 0x86E4, 0xF9EE, 0x95A4, + 0xF9EF, 0x95D4, 0xF9F0, 0x965C, 0xF9F1, 0x4EA2, 0xF9F2, 0x4F09, 0xF9F3, 0x59EE, 0xF9F4, 0x5AE6, 0xF9F5, 0x5DF7, 0xF9F6, 0x6052, + 0xF9F7, 0x6297, 0xF9F8, 0x676D, 0xF9F9, 0x6841, 0xF9FA, 0x6C86, 0xF9FB, 0x6E2F, 0xF9FC, 0x7F38, 0xF9FD, 0x809B, 0xF9FE, 0x822A, + 0xFAA1, 0xFA08, 0xFAA2, 0xFA09, 0xFAA3, 0x9805, 0xFAA4, 0x4EA5, 0xFAA5, 0x5055, 0xFAA6, 0x54B3, 0xFAA7, 0x5793, 0xFAA8, 0x595A, + 0xFAA9, 0x5B69, 0xFAAA, 0x5BB3, 0xFAAB, 0x61C8, 0xFAAC, 0x6977, 0xFAAD, 0x6D77, 0xFAAE, 0x7023, 0xFAAF, 0x87F9, 0xFAB0, 0x89E3, + 0xFAB1, 0x8A72, 0xFAB2, 0x8AE7, 0xFAB3, 0x9082, 0xFAB4, 0x99ED, 0xFAB5, 0x9AB8, 0xFAB6, 0x52BE, 0xFAB7, 0x6838, 0xFAB8, 0x5016, + 0xFAB9, 0x5E78, 0xFABA, 0x674F, 0xFABB, 0x8347, 0xFABC, 0x884C, 0xFABD, 0x4EAB, 0xFABE, 0x5411, 0xFABF, 0x56AE, 0xFAC0, 0x73E6, + 0xFAC1, 0x9115, 0xFAC2, 0x97FF, 0xFAC3, 0x9909, 0xFAC4, 0x9957, 0xFAC5, 0x9999, 0xFAC6, 0x5653, 0xFAC7, 0x589F, 0xFAC8, 0x865B, + 0xFAC9, 0x8A31, 0xFACA, 0x61B2, 0xFACB, 0x6AF6, 0xFACC, 0x737B, 0xFACD, 0x8ED2, 0xFACE, 0x6B47, 0xFACF, 0x96AA, 0xFAD0, 0x9A57, + 0xFAD1, 0x5955, 0xFAD2, 0x7200, 0xFAD3, 0x8D6B, 0xFAD4, 0x9769, 0xFAD5, 0x4FD4, 0xFAD6, 0x5CF4, 0xFAD7, 0x5F26, 0xFAD8, 0x61F8, + 0xFAD9, 0x665B, 0xFADA, 0x6CEB, 0xFADB, 0x70AB, 0xFADC, 0x7384, 0xFADD, 0x73B9, 0xFADE, 0x73FE, 0xFADF, 0x7729, 0xFAE0, 0x774D, + 0xFAE1, 0x7D43, 0xFAE2, 0x7D62, 0xFAE3, 0x7E23, 0xFAE4, 0x8237, 0xFAE5, 0x8852, 0xFAE6, 0xFA0A, 0xFAE7, 0x8CE2, 0xFAE8, 0x9249, + 0xFAE9, 0x986F, 0xFAEA, 0x5B51, 0xFAEB, 0x7A74, 0xFAEC, 0x8840, 0xFAED, 0x9801, 0xFAEE, 0x5ACC, 0xFAEF, 0x4FE0, 0xFAF0, 0x5354, + 0xFAF1, 0x593E, 0xFAF2, 0x5CFD, 0xFAF3, 0x633E, 0xFAF4, 0x6D79, 0xFAF5, 0x72F9, 0xFAF6, 0x8105, 0xFAF7, 0x8107, 0xFAF8, 0x83A2, + 0xFAF9, 0x92CF, 0xFAFA, 0x9830, 0xFAFB, 0x4EA8, 0xFAFC, 0x5144, 0xFAFD, 0x5211, 0xFAFE, 0x578B, 0xFBA1, 0x5F62, 0xFBA2, 0x6CC2, + 0xFBA3, 0x6ECE, 0xFBA4, 0x7005, 0xFBA5, 0x7050, 0xFBA6, 0x70AF, 0xFBA7, 0x7192, 0xFBA8, 0x73E9, 0xFBA9, 0x7469, 0xFBAA, 0x834A, + 0xFBAB, 0x87A2, 0xFBAC, 0x8861, 0xFBAD, 0x9008, 0xFBAE, 0x90A2, 0xFBAF, 0x93A3, 0xFBB0, 0x99A8, 0xFBB1, 0x516E, 0xFBB2, 0x5F57, + 0xFBB3, 0x60E0, 0xFBB4, 0x6167, 0xFBB5, 0x66B3, 0xFBB6, 0x8559, 0xFBB7, 0x8E4A, 0xFBB8, 0x91AF, 0xFBB9, 0x978B, 0xFBBA, 0x4E4E, + 0xFBBB, 0x4E92, 0xFBBC, 0x547C, 0xFBBD, 0x58D5, 0xFBBE, 0x58FA, 0xFBBF, 0x597D, 0xFBC0, 0x5CB5, 0xFBC1, 0x5F27, 0xFBC2, 0x6236, + 0xFBC3, 0x6248, 0xFBC4, 0x660A, 0xFBC5, 0x6667, 0xFBC6, 0x6BEB, 0xFBC7, 0x6D69, 0xFBC8, 0x6DCF, 0xFBC9, 0x6E56, 0xFBCA, 0x6EF8, + 0xFBCB, 0x6F94, 0xFBCC, 0x6FE0, 0xFBCD, 0x6FE9, 0xFBCE, 0x705D, 0xFBCF, 0x72D0, 0xFBD0, 0x7425, 0xFBD1, 0x745A, 0xFBD2, 0x74E0, + 0xFBD3, 0x7693, 0xFBD4, 0x795C, 0xFBD5, 0x7CCA, 0xFBD6, 0x7E1E, 0xFBD7, 0x80E1, 0xFBD8, 0x82A6, 0xFBD9, 0x846B, 0xFBDA, 0x84BF, + 0xFBDB, 0x864E, 0xFBDC, 0x865F, 0xFBDD, 0x8774, 0xFBDE, 0x8B77, 0xFBDF, 0x8C6A, 0xFBE0, 0x93AC, 0xFBE1, 0x9800, 0xFBE2, 0x9865, + 0xFBE3, 0x60D1, 0xFBE4, 0x6216, 0xFBE5, 0x9177, 0xFBE6, 0x5A5A, 0xFBE7, 0x660F, 0xFBE8, 0x6DF7, 0xFBE9, 0x6E3E, 0xFBEA, 0x743F, + 0xFBEB, 0x9B42, 0xFBEC, 0x5FFD, 0xFBED, 0x60DA, 0xFBEE, 0x7B0F, 0xFBEF, 0x54C4, 0xFBF0, 0x5F18, 0xFBF1, 0x6C5E, 0xFBF2, 0x6CD3, + 0xFBF3, 0x6D2A, 0xFBF4, 0x70D8, 0xFBF5, 0x7D05, 0xFBF6, 0x8679, 0xFBF7, 0x8A0C, 0xFBF8, 0x9D3B, 0xFBF9, 0x5316, 0xFBFA, 0x548C, + 0xFBFB, 0x5B05, 0xFBFC, 0x6A3A, 0xFBFD, 0x706B, 0xFBFE, 0x7575, 0xFCA1, 0x798D, 0xFCA2, 0x79BE, 0xFCA3, 0x82B1, 0xFCA4, 0x83EF, + 0xFCA5, 0x8A71, 0xFCA6, 0x8B41, 0xFCA7, 0x8CA8, 0xFCA8, 0x9774, 0xFCA9, 0xFA0B, 0xFCAA, 0x64F4, 0xFCAB, 0x652B, 0xFCAC, 0x78BA, + 0xFCAD, 0x78BB, 0xFCAE, 0x7A6B, 0xFCAF, 0x4E38, 0xFCB0, 0x559A, 0xFCB1, 0x5950, 0xFCB2, 0x5BA6, 0xFCB3, 0x5E7B, 0xFCB4, 0x60A3, + 0xFCB5, 0x63DB, 0xFCB6, 0x6B61, 0xFCB7, 0x6665, 0xFCB8, 0x6853, 0xFCB9, 0x6E19, 0xFCBA, 0x7165, 0xFCBB, 0x74B0, 0xFCBC, 0x7D08, + 0xFCBD, 0x9084, 0xFCBE, 0x9A69, 0xFCBF, 0x9C25, 0xFCC0, 0x6D3B, 0xFCC1, 0x6ED1, 0xFCC2, 0x733E, 0xFCC3, 0x8C41, 0xFCC4, 0x95CA, + 0xFCC5, 0x51F0, 0xFCC6, 0x5E4C, 0xFCC7, 0x5FA8, 0xFCC8, 0x604D, 0xFCC9, 0x60F6, 0xFCCA, 0x6130, 0xFCCB, 0x614C, 0xFCCC, 0x6643, + 0xFCCD, 0x6644, 0xFCCE, 0x69A5, 0xFCCF, 0x6CC1, 0xFCD0, 0x6E5F, 0xFCD1, 0x6EC9, 0xFCD2, 0x6F62, 0xFCD3, 0x714C, 0xFCD4, 0x749C, + 0xFCD5, 0x7687, 0xFCD6, 0x7BC1, 0xFCD7, 0x7C27, 0xFCD8, 0x8352, 0xFCD9, 0x8757, 0xFCDA, 0x9051, 0xFCDB, 0x968D, 0xFCDC, 0x9EC3, + 0xFCDD, 0x532F, 0xFCDE, 0x56DE, 0xFCDF, 0x5EFB, 0xFCE0, 0x5F8A, 0xFCE1, 0x6062, 0xFCE2, 0x6094, 0xFCE3, 0x61F7, 0xFCE4, 0x6666, + 0xFCE5, 0x6703, 0xFCE6, 0x6A9C, 0xFCE7, 0x6DEE, 0xFCE8, 0x6FAE, 0xFCE9, 0x7070, 0xFCEA, 0x736A, 0xFCEB, 0x7E6A, 0xFCEC, 0x81BE, + 0xFCED, 0x8334, 0xFCEE, 0x86D4, 0xFCEF, 0x8AA8, 0xFCF0, 0x8CC4, 0xFCF1, 0x5283, 0xFCF2, 0x7372, 0xFCF3, 0x5B96, 0xFCF4, 0x6A6B, + 0xFCF5, 0x9404, 0xFCF6, 0x54EE, 0xFCF7, 0x5686, 0xFCF8, 0x5B5D, 0xFCF9, 0x6548, 0xFCFA, 0x6585, 0xFCFB, 0x66C9, 0xFCFC, 0x689F, + 0xFCFD, 0x6D8D, 0xFCFE, 0x6DC6, 0xFDA1, 0x723B, 0xFDA2, 0x80B4, 0xFDA3, 0x9175, 0xFDA4, 0x9A4D, 0xFDA5, 0x4FAF, 0xFDA6, 0x5019, + 0xFDA7, 0x539A, 0xFDA8, 0x540E, 0xFDA9, 0x543C, 0xFDAA, 0x5589, 0xFDAB, 0x55C5, 0xFDAC, 0x5E3F, 0xFDAD, 0x5F8C, 0xFDAE, 0x673D, + 0xFDAF, 0x7166, 0xFDB0, 0x73DD, 0xFDB1, 0x9005, 0xFDB2, 0x52DB, 0xFDB3, 0x52F3, 0xFDB4, 0x5864, 0xFDB5, 0x58CE, 0xFDB6, 0x7104, + 0xFDB7, 0x718F, 0xFDB8, 0x71FB, 0xFDB9, 0x85B0, 0xFDBA, 0x8A13, 0xFDBB, 0x6688, 0xFDBC, 0x85A8, 0xFDBD, 0x55A7, 0xFDBE, 0x6684, + 0xFDBF, 0x714A, 0xFDC0, 0x8431, 0xFDC1, 0x5349, 0xFDC2, 0x5599, 0xFDC3, 0x6BC1, 0xFDC4, 0x5F59, 0xFDC5, 0x5FBD, 0xFDC6, 0x63EE, + 0xFDC7, 0x6689, 0xFDC8, 0x7147, 0xFDC9, 0x8AF1, 0xFDCA, 0x8F1D, 0xFDCB, 0x9EBE, 0xFDCC, 0x4F11, 0xFDCD, 0x643A, 0xFDCE, 0x70CB, + 0xFDCF, 0x7566, 0xFDD0, 0x8667, 0xFDD1, 0x6064, 0xFDD2, 0x8B4E, 0xFDD3, 0x9DF8, 0xFDD4, 0x5147, 0xFDD5, 0x51F6, 0xFDD6, 0x5308, + 0xFDD7, 0x6D36, 0xFDD8, 0x80F8, 0xFDD9, 0x9ED1, 0xFDDA, 0x6615, 0xFDDB, 0x6B23, 0xFDDC, 0x7098, 0xFDDD, 0x75D5, 0xFDDE, 0x5403, + 0xFDDF, 0x5C79, 0xFDE0, 0x7D07, 0xFDE1, 0x8A16, 0xFDE2, 0x6B20, 0xFDE3, 0x6B3D, 0xFDE4, 0x6B46, 0xFDE5, 0x5438, 0xFDE6, 0x6070, + 0xFDE7, 0x6D3D, 0xFDE8, 0x7FD5, 0xFDE9, 0x8208, 0xFDEA, 0x50D6, 0xFDEB, 0x51DE, 0xFDEC, 0x559C, 0xFDED, 0x566B, 0xFDEE, 0x56CD, + 0xFDEF, 0x59EC, 0xFDF0, 0x5B09, 0xFDF1, 0x5E0C, 0xFDF2, 0x6199, 0xFDF3, 0x6198, 0xFDF4, 0x6231, 0xFDF5, 0x665E, 0xFDF6, 0x66E6, + 0xFDF7, 0x7199, 0xFDF8, 0x71B9, 0xFDF9, 0x71BA, 0xFDFA, 0x72A7, 0xFDFB, 0x79A7, 0xFDFC, 0x7A00, 0xFDFD, 0x7FB2, 0xFDFE, 0x8A70, + 0, 0 +}; +#endif + +#if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */ +static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ + 0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE, + 0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346, + 0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E, + 0x039C, 0xA34F, 0x039D, 0xA350, 0x039E, 0xA351, 0x039F, 0xA352, 0x03A0, 0xA353, 0x03A1, 0xA354, 0x03A3, 0xA355, 0x03A4, 0xA356, + 0x03A5, 0xA357, 0x03A6, 0xA358, 0x03A7, 0xA359, 0x03A8, 0xA35A, 0x03A9, 0xA35B, 0x03B1, 0xA35C, 0x03B2, 0xA35D, 0x03B3, 0xA35E, + 0x03B4, 0xA35F, 0x03B5, 0xA360, 0x03B6, 0xA361, 0x03B7, 0xA362, 0x03B8, 0xA363, 0x03B9, 0xA364, 0x03BA, 0xA365, 0x03BB, 0xA366, + 0x03BC, 0xA367, 0x03BD, 0xA368, 0x03BE, 0xA369, 0x03BF, 0xA36A, 0x03C0, 0xA36B, 0x03C1, 0xA36C, 0x03C3, 0xA36D, 0x03C4, 0xA36E, + 0x03C5, 0xA36F, 0x03C6, 0xA370, 0x03C7, 0xA371, 0x03C8, 0xA372, 0x03C9, 0xA373, 0x2013, 0xA156, 0x2014, 0xA158, 0x2018, 0xA1A5, + 0x2019, 0xA1A6, 0x201C, 0xA1A7, 0x201D, 0xA1A8, 0x2025, 0xA14C, 0x2026, 0xA14B, 0x2027, 0xA145, 0x2032, 0xA1AC, 0x2035, 0xA1AB, + 0x203B, 0xA1B0, 0x20AC, 0xA3E1, 0x2103, 0xA24A, 0x2105, 0xA1C1, 0x2109, 0xA24B, 0x2160, 0xA2B9, 0x2161, 0xA2BA, 0x2162, 0xA2BB, + 0x2163, 0xA2BC, 0x2164, 0xA2BD, 0x2165, 0xA2BE, 0x2166, 0xA2BF, 0x2167, 0xA2C0, 0x2168, 0xA2C1, 0x2169, 0xA2C2, 0x2190, 0xA1F6, + 0x2191, 0xA1F4, 0x2192, 0xA1F7, 0x2193, 0xA1F5, 0x2196, 0xA1F8, 0x2197, 0xA1F9, 0x2198, 0xA1FB, 0x2199, 0xA1FA, 0x2215, 0xA241, + 0x221A, 0xA1D4, 0x221E, 0xA1DB, 0x221F, 0xA1E8, 0x2220, 0xA1E7, 0x2223, 0xA1FD, 0x2225, 0xA1FC, 0x2229, 0xA1E4, 0x222A, 0xA1E5, + 0x222B, 0xA1EC, 0x222E, 0xA1ED, 0x2234, 0xA1EF, 0x2235, 0xA1EE, 0x2252, 0xA1DC, 0x2260, 0xA1DA, 0x2261, 0xA1DD, 0x2266, 0xA1D8, + 0x2267, 0xA1D9, 0x2295, 0xA1F2, 0x2299, 0xA1F3, 0x22A5, 0xA1E6, 0x22BF, 0xA1E9, 0x2500, 0xA277, 0x2502, 0xA278, 0x250C, 0xA27A, + 0x2510, 0xA27B, 0x2514, 0xA27C, 0x2518, 0xA27D, 0x251C, 0xA275, 0x2524, 0xA274, 0x252C, 0xA273, 0x2534, 0xA272, 0x253C, 0xA271, + 0x2550, 0xA2A4, 0x2550, 0xF9F9, 0x2551, 0xF9F8, 0x2552, 0xF9E6, 0x2553, 0xF9EF, 0x2554, 0xF9DD, 0x2555, 0xF9E8, 0x2556, 0xF9F1, + 0x2557, 0xF9DF, 0x2558, 0xF9EC, 0x2559, 0xF9F5, 0x255A, 0xF9E3, 0x255B, 0xF9EE, 0x255C, 0xF9F7, 0x255D, 0xF9E5, 0x255E, 0xA2A5, + 0x255E, 0xF9E9, 0x255F, 0xF9F2, 0x2560, 0xF9E0, 0x2561, 0xA2A7, 0x2561, 0xF9EB, 0x2562, 0xF9F4, 0x2563, 0xF9E2, 0x2564, 0xF9E7, + 0x2565, 0xF9F0, 0x2566, 0xF9DE, 0x2567, 0xF9ED, 0x2568, 0xF9F6, 0x2569, 0xF9E4, 0x256A, 0xA2A6, 0x256A, 0xF9EA, 0x256B, 0xF9F3, + 0x256C, 0xF9E1, 0x256D, 0xA27E, 0x256D, 0xF9FA, 0x256E, 0xA2A1, 0x256E, 0xF9FB, 0x256F, 0xA2A3, 0x256F, 0xF9FD, 0x2570, 0xA2A2, + 0x2570, 0xF9FC, 0x2571, 0xA2AC, 0x2572, 0xA2AD, 0x2573, 0xA2AE, 0x2574, 0xA15A, 0x2581, 0xA262, 0x2582, 0xA263, 0x2583, 0xA264, + 0x2584, 0xA265, 0x2585, 0xA266, 0x2586, 0xA267, 0x2587, 0xA268, 0x2588, 0xA269, 0x2589, 0xA270, 0x258A, 0xA26F, 0x258B, 0xA26E, + 0x258C, 0xA26D, 0x258D, 0xA26C, 0x258E, 0xA26B, 0x258F, 0xA26A, 0x2593, 0xF9FE, 0x2594, 0xA276, 0x2595, 0xA279, 0x25A0, 0xA1BD, + 0x25A1, 0xA1BC, 0x25B2, 0xA1B6, 0x25B3, 0xA1B5, 0x25BC, 0xA1BF, 0x25BD, 0xA1BE, 0x25C6, 0xA1BB, 0x25C7, 0xA1BA, 0x25CB, 0xA1B3, + 0x25CE, 0xA1B7, 0x25CF, 0xA1B4, 0x25E2, 0xA2A8, 0x25E3, 0xA2A9, 0x25E4, 0xA2AB, 0x25E5, 0xA2AA, 0x2605, 0xA1B9, 0x2606, 0xA1B8, + 0x2640, 0xA1F0, 0x2642, 0xA1F1, 0x3000, 0xA140, 0x3001, 0xA142, 0x3002, 0xA143, 0x3003, 0xA1B2, 0x3008, 0xA171, 0x3009, 0xA172, + 0x300A, 0xA16D, 0x300B, 0xA16E, 0x300C, 0xA175, 0x300D, 0xA176, 0x300E, 0xA179, 0x300F, 0xA17A, 0x3010, 0xA169, 0x3011, 0xA16A, + 0x3012, 0xA245, 0x3014, 0xA165, 0x3015, 0xA166, 0x301D, 0xA1A9, 0x301E, 0xA1AA, 0x3021, 0xA2C3, 0x3022, 0xA2C4, 0x3023, 0xA2C5, + 0x3024, 0xA2C6, 0x3025, 0xA2C7, 0x3026, 0xA2C8, 0x3027, 0xA2C9, 0x3028, 0xA2CA, 0x3029, 0xA2CB, 0x3105, 0xA374, 0x3106, 0xA375, + 0x3107, 0xA376, 0x3108, 0xA377, 0x3109, 0xA378, 0x310A, 0xA379, 0x310B, 0xA37A, 0x310C, 0xA37B, 0x310D, 0xA37C, 0x310E, 0xA37D, + 0x310F, 0xA37E, 0x3110, 0xA3A1, 0x3111, 0xA3A2, 0x3112, 0xA3A3, 0x3113, 0xA3A4, 0x3114, 0xA3A5, 0x3115, 0xA3A6, 0x3116, 0xA3A7, + 0x3117, 0xA3A8, 0x3118, 0xA3A9, 0x3119, 0xA3AA, 0x311A, 0xA3AB, 0x311B, 0xA3AC, 0x311C, 0xA3AD, 0x311D, 0xA3AE, 0x311E, 0xA3AF, + 0x311F, 0xA3B0, 0x3120, 0xA3B1, 0x3121, 0xA3B2, 0x3122, 0xA3B3, 0x3123, 0xA3B4, 0x3124, 0xA3B5, 0x3125, 0xA3B6, 0x3126, 0xA3B7, + 0x3127, 0xA3B8, 0x3128, 0xA3B9, 0x3129, 0xA3BA, 0x32A3, 0xA1C0, 0x338E, 0xA255, 0x338F, 0xA256, 0x339C, 0xA250, 0x339D, 0xA251, + 0x339E, 0xA252, 0x33A1, 0xA254, 0x33C4, 0xA257, 0x33CE, 0xA253, 0x33D1, 0xA1EB, 0x33D2, 0xA1EA, 0x33D5, 0xA24F, 0x4E00, 0xA440, + 0x4E01, 0xA442, 0x4E03, 0xA443, 0x4E07, 0xC945, 0x4E08, 0xA456, 0x4E09, 0xA454, 0x4E0A, 0xA457, 0x4E0B, 0xA455, 0x4E0C, 0xC946, + 0x4E0D, 0xA4A3, 0x4E0E, 0xC94F, 0x4E0F, 0xC94D, 0x4E10, 0xA4A2, 0x4E11, 0xA4A1, 0x4E14, 0xA542, 0x4E15, 0xA541, 0x4E16, 0xA540, + 0x4E18, 0xA543, 0x4E19, 0xA4FE, 0x4E1E, 0xA5E0, 0x4E1F, 0xA5E1, 0x4E26, 0xA8C3, 0x4E2B, 0xA458, 0x4E2D, 0xA4A4, 0x4E2E, 0xC950, + 0x4E30, 0xA4A5, 0x4E31, 0xC963, 0x4E32, 0xA6EA, 0x4E33, 0xCBB1, 0x4E38, 0xA459, 0x4E39, 0xA4A6, 0x4E3B, 0xA544, 0x4E3C, 0xC964, + 0x4E42, 0xC940, 0x4E43, 0xA444, 0x4E45, 0xA45B, 0x4E47, 0xC947, 0x4E48, 0xA45C, 0x4E4B, 0xA4A7, 0x4E4D, 0xA545, 0x4E4E, 0xA547, + 0x4E4F, 0xA546, 0x4E52, 0xA5E2, 0x4E53, 0xA5E3, 0x4E56, 0xA8C4, 0x4E58, 0xADBC, 0x4E59, 0xA441, 0x4E5C, 0xC941, 0x4E5D, 0xA445, + 0x4E5E, 0xA45E, 0x4E5F, 0xA45D, 0x4E69, 0xA5E4, 0x4E73, 0xA8C5, 0x4E7E, 0xB0AE, 0x4E7F, 0xD44B, 0x4E82, 0xB6C3, 0x4E83, 0xDCB1, + 0x4E84, 0xDCB2, 0x4E86, 0xA446, 0x4E88, 0xA4A9, 0x4E8B, 0xA8C6, 0x4E8C, 0xA447, 0x4E8D, 0xC948, 0x4E8E, 0xA45F, 0x4E91, 0xA4AA, + 0x4E92, 0xA4AC, 0x4E93, 0xC951, 0x4E94, 0xA4AD, 0x4E95, 0xA4AB, 0x4E99, 0xA5E5, 0x4E9B, 0xA8C7, 0x4E9E, 0xA8C8, 0x4E9F, 0xAB45, + 0x4EA1, 0xA460, 0x4EA2, 0xA4AE, 0x4EA4, 0xA5E6, 0x4EA5, 0xA5E8, 0x4EA6, 0xA5E7, 0x4EA8, 0xA6EB, 0x4EAB, 0xA8C9, 0x4EAC, 0xA8CA, + 0x4EAD, 0xAB46, 0x4EAE, 0xAB47, 0x4EB3, 0xADBD, 0x4EB6, 0xDCB3, 0x4EB9, 0xF6D6, 0x4EBA, 0xA448, 0x4EC0, 0xA4B0, 0x4EC1, 0xA4AF, + 0x4EC2, 0xC952, 0x4EC3, 0xA4B1, 0x4EC4, 0xA4B7, 0x4EC6, 0xA4B2, 0x4EC7, 0xA4B3, 0x4EC8, 0xC954, 0x4EC9, 0xC953, 0x4ECA, 0xA4B5, + 0x4ECB, 0xA4B6, 0x4ECD, 0xA4B4, 0x4ED4, 0xA54A, 0x4ED5, 0xA54B, 0x4ED6, 0xA54C, 0x4ED7, 0xA54D, 0x4ED8, 0xA549, 0x4ED9, 0xA550, + 0x4EDA, 0xC96A, 0x4EDC, 0xC966, 0x4EDD, 0xC969, 0x4EDE, 0xA551, 0x4EDF, 0xA561, 0x4EE1, 0xC968, 0x4EE3, 0xA54E, 0x4EE4, 0xA54F, + 0x4EE5, 0xA548, 0x4EE8, 0xC965, 0x4EE9, 0xC967, 0x4EF0, 0xA5F5, 0x4EF1, 0xC9B0, 0x4EF2, 0xA5F2, 0x4EF3, 0xA5F6, 0x4EF4, 0xC9BA, + 0x4EF5, 0xC9AE, 0x4EF6, 0xA5F3, 0x4EF7, 0xC9B2, 0x4EFB, 0xA5F4, 0x4EFD, 0xA5F7, 0x4EFF, 0xA5E9, 0x4F00, 0xC9B1, 0x4F01, 0xA5F8, + 0x4F02, 0xC9B5, 0x4F04, 0xC9B9, 0x4F05, 0xC9B6, 0x4F08, 0xC9B3, 0x4F09, 0xA5EA, 0x4F0A, 0xA5EC, 0x4F0B, 0xA5F9, 0x4F0D, 0xA5EE, + 0x4F0E, 0xC9AB, 0x4F0F, 0xA5F1, 0x4F10, 0xA5EF, 0x4F11, 0xA5F0, 0x4F12, 0xC9BB, 0x4F13, 0xC9B8, 0x4F14, 0xC9AF, 0x4F15, 0xA5ED, + 0x4F18, 0xC9AC, 0x4F19, 0xA5EB, 0x4F1D, 0xC9B4, 0x4F22, 0xC9B7, 0x4F2C, 0xC9AD, 0x4F2D, 0xCA66, 0x4F2F, 0xA742, 0x4F30, 0xA6F4, + 0x4F33, 0xCA67, 0x4F34, 0xA6F1, 0x4F36, 0xA744, 0x4F38, 0xA6F9, 0x4F3A, 0xA6F8, 0x4F3B, 0xCA5B, 0x4F3C, 0xA6FC, 0x4F3D, 0xA6F7, + 0x4F3E, 0xCA60, 0x4F3F, 0xCA68, 0x4F41, 0xCA64, 0x4F43, 0xA6FA, 0x4F46, 0xA6FD, 0x4F47, 0xA6EE, 0x4F48, 0xA747, 0x4F49, 0xCA5D, + 0x4F4C, 0xCBBD, 0x4F4D, 0xA6EC, 0x4F4E, 0xA743, 0x4F4F, 0xA6ED, 0x4F50, 0xA6F5, 0x4F51, 0xA6F6, 0x4F52, 0xCA62, 0x4F53, 0xCA5E, + 0x4F54, 0xA6FB, 0x4F55, 0xA6F3, 0x4F56, 0xCA5A, 0x4F57, 0xA6EF, 0x4F58, 0xCA65, 0x4F59, 0xA745, 0x4F5A, 0xA748, 0x4F5B, 0xA6F2, + 0x4F5C, 0xA740, 0x4F5D, 0xA746, 0x4F5E, 0xA6F0, 0x4F5F, 0xCA63, 0x4F60, 0xA741, 0x4F61, 0xCA69, 0x4F62, 0xCA5C, 0x4F63, 0xA6FE, + 0x4F64, 0xCA5F, 0x4F67, 0xCA61, 0x4F69, 0xA8D8, 0x4F6A, 0xCBBF, 0x4F6B, 0xCBCB, 0x4F6C, 0xA8D0, 0x4F6E, 0xCBCC, 0x4F6F, 0xA8CB, + 0x4F70, 0xA8D5, 0x4F73, 0xA8CE, 0x4F74, 0xCBB9, 0x4F75, 0xA8D6, 0x4F76, 0xCBB8, 0x4F77, 0xCBBC, 0x4F78, 0xCBC3, 0x4F79, 0xCBC1, + 0x4F7A, 0xA8DE, 0x4F7B, 0xA8D9, 0x4F7C, 0xCBB3, 0x4F7D, 0xCBB5, 0x4F7E, 0xA8DB, 0x4F7F, 0xA8CF, 0x4F80, 0xCBB6, 0x4F81, 0xCBC2, + 0x4F82, 0xCBC9, 0x4F83, 0xA8D4, 0x4F84, 0xCBBB, 0x4F85, 0xCBB4, 0x4F86, 0xA8D3, 0x4F87, 0xCBB7, 0x4F88, 0xA8D7, 0x4F89, 0xCBBA, + 0x4F8B, 0xA8D2, 0x4F8D, 0xA8CD, 0x4F8F, 0xA8DC, 0x4F90, 0xCBC4, 0x4F91, 0xA8DD, 0x4F92, 0xCBC8, 0x4F94, 0xCBC6, 0x4F95, 0xCBCA, + 0x4F96, 0xA8DA, 0x4F97, 0xCBBE, 0x4F98, 0xCBB2, 0x4F9A, 0xCBC0, 0x4F9B, 0xA8D1, 0x4F9C, 0xCBC5, 0x4F9D, 0xA8CC, 0x4F9E, 0xCBC7, + 0x4FAE, 0xAB56, 0x4FAF, 0xAB4A, 0x4FB2, 0xCDE0, 0x4FB3, 0xCDE8, 0x4FB5, 0xAB49, 0x4FB6, 0xAB51, 0x4FB7, 0xAB5D, 0x4FB9, 0xCDEE, + 0x4FBA, 0xCDEC, 0x4FBB, 0xCDE7, 0x4FBF, 0xAB4B, 0x4FC0, 0xCDED, 0x4FC1, 0xCDE3, 0x4FC2, 0xAB59, 0x4FC3, 0xAB50, 0x4FC4, 0xAB58, + 0x4FC5, 0xCDDE, 0x4FC7, 0xCDEA, 0x4FC9, 0xCDE1, 0x4FCA, 0xAB54, 0x4FCB, 0xCDE2, 0x4FCD, 0xCDDD, 0x4FCE, 0xAB5B, 0x4FCF, 0xAB4E, + 0x4FD0, 0xAB57, 0x4FD1, 0xAB4D, 0x4FD3, 0xCDDF, 0x4FD4, 0xCDE4, 0x4FD6, 0xCDEB, 0x4FD7, 0xAB55, 0x4FD8, 0xAB52, 0x4FD9, 0xCDE6, + 0x4FDA, 0xAB5A, 0x4FDB, 0xCDE9, 0x4FDC, 0xCDE5, 0x4FDD, 0xAB4F, 0x4FDE, 0xAB5C, 0x4FDF, 0xAB53, 0x4FE0, 0xAB4C, 0x4FE1, 0xAB48, + 0x4FEC, 0xCDEF, 0x4FEE, 0xADD7, 0x4FEF, 0xADC1, 0x4FF1, 0xADD1, 0x4FF3, 0xADD6, 0x4FF4, 0xD0D0, 0x4FF5, 0xD0CF, 0x4FF6, 0xD0D4, + 0x4FF7, 0xD0D5, 0x4FF8, 0xADC4, 0x4FFA, 0xADCD, 0x4FFE, 0xADDA, 0x5000, 0xADCE, 0x5005, 0xD0C9, 0x5006, 0xADC7, 0x5007, 0xD0CA, + 0x5009, 0xADDC, 0x500B, 0xADD3, 0x500C, 0xADBE, 0x500D, 0xADBF, 0x500E, 0xD0DD, 0x500F, 0xB0BF, 0x5011, 0xADCC, 0x5012, 0xADCB, + 0x5013, 0xD0CB, 0x5014, 0xADCF, 0x5015, 0xD45B, 0x5016, 0xADC6, 0x5017, 0xD0D6, 0x5018, 0xADD5, 0x5019, 0xADD4, 0x501A, 0xADCA, + 0x501B, 0xD0CE, 0x501C, 0xD0D7, 0x501E, 0xD0C8, 0x501F, 0xADC9, 0x5020, 0xD0D8, 0x5021, 0xADD2, 0x5022, 0xD0CC, 0x5023, 0xADC0, + 0x5025, 0xADC3, 0x5026, 0xADC2, 0x5027, 0xD0D9, 0x5028, 0xADD0, 0x5029, 0xADC5, 0x502A, 0xADD9, 0x502B, 0xADDB, 0x502C, 0xD0D3, + 0x502D, 0xADD8, 0x502F, 0xD0DB, 0x5030, 0xD0CD, 0x5031, 0xD0DC, 0x5033, 0xD0D1, 0x5035, 0xD0DA, 0x5037, 0xD0D2, 0x503C, 0xADC8, + 0x5040, 0xD463, 0x5041, 0xD457, 0x5043, 0xB0B3, 0x5045, 0xD45C, 0x5046, 0xD462, 0x5047, 0xB0B2, 0x5048, 0xD455, 0x5049, 0xB0B6, + 0x504A, 0xD459, 0x504B, 0xD452, 0x504C, 0xB0B4, 0x504D, 0xD456, 0x504E, 0xB0B9, 0x504F, 0xB0BE, 0x5051, 0xD467, 0x5053, 0xD451, + 0x5055, 0xB0BA, 0x5057, 0xD466, 0x505A, 0xB0B5, 0x505B, 0xD458, 0x505C, 0xB0B1, 0x505D, 0xD453, 0x505E, 0xD44F, 0x505F, 0xD45D, + 0x5060, 0xD450, 0x5061, 0xD44E, 0x5062, 0xD45A, 0x5063, 0xD460, 0x5064, 0xD461, 0x5065, 0xB0B7, 0x5068, 0xD85B, 0x5069, 0xD45E, + 0x506A, 0xD44D, 0x506B, 0xD45F, 0x506D, 0xB0C1, 0x506E, 0xD464, 0x506F, 0xB0C0, 0x5070, 0xD44C, 0x5072, 0xD454, 0x5073, 0xD465, + 0x5074, 0xB0BC, 0x5075, 0xB0BB, 0x5076, 0xB0B8, 0x5077, 0xB0BD, 0x507A, 0xB0AF, 0x507D, 0xB0B0, 0x5080, 0xB3C8, 0x5082, 0xD85E, + 0x5083, 0xD857, 0x5085, 0xB3C5, 0x5087, 0xD85F, 0x508B, 0xD855, 0x508C, 0xD858, 0x508D, 0xB3C4, 0x508E, 0xD859, 0x5091, 0xB3C7, + 0x5092, 0xD85D, 0x5094, 0xD853, 0x5095, 0xD852, 0x5096, 0xB3C9, 0x5098, 0xB3CA, 0x5099, 0xB3C6, 0x509A, 0xB3CB, 0x509B, 0xD851, + 0x509C, 0xD85C, 0x509D, 0xD85A, 0x509E, 0xD854, 0x50A2, 0xB3C3, 0x50A3, 0xD856, 0x50AC, 0xB6CA, 0x50AD, 0xB6C4, 0x50AE, 0xDCB7, + 0x50AF, 0xB6CD, 0x50B0, 0xDCBD, 0x50B1, 0xDCC0, 0x50B2, 0xB6C6, 0x50B3, 0xB6C7, 0x50B4, 0xDCBA, 0x50B5, 0xB6C5, 0x50B6, 0xDCC3, + 0x50B7, 0xB6CB, 0x50B8, 0xDCC4, 0x50BA, 0xDCBF, 0x50BB, 0xB6CC, 0x50BD, 0xDCB4, 0x50BE, 0xB6C9, 0x50BF, 0xDCB5, 0x50C1, 0xDCBE, + 0x50C2, 0xDCBC, 0x50C4, 0xDCB8, 0x50C5, 0xB6C8, 0x50C6, 0xDCB6, 0x50C7, 0xB6CE, 0x50C8, 0xDCBB, 0x50C9, 0xDCC2, 0x50CA, 0xDCB9, + 0x50CB, 0xDCC1, 0x50CE, 0xB9B6, 0x50CF, 0xB9B3, 0x50D1, 0xB9B4, 0x50D3, 0xE0F9, 0x50D4, 0xE0F1, 0x50D5, 0xB9B2, 0x50D6, 0xB9AF, + 0x50D7, 0xE0F2, 0x50DA, 0xB9B1, 0x50DB, 0xE0F5, 0x50DD, 0xE0F7, 0x50E0, 0xE0FE, 0x50E3, 0xE0FD, 0x50E4, 0xE0F8, 0x50E5, 0xB9AE, + 0x50E6, 0xE0F0, 0x50E7, 0xB9AC, 0x50E8, 0xE0F3, 0x50E9, 0xB9B7, 0x50EA, 0xE0F6, 0x50EC, 0xE0FA, 0x50ED, 0xB9B0, 0x50EE, 0xB9AD, + 0x50EF, 0xE0FC, 0x50F0, 0xE0FB, 0x50F1, 0xB9B5, 0x50F3, 0xE0F4, 0x50F5, 0xBBF8, 0x50F6, 0xE4EC, 0x50F8, 0xE4E9, 0x50F9, 0xBBF9, + 0x50FB, 0xBBF7, 0x50FD, 0xE4F0, 0x50FE, 0xE4ED, 0x50FF, 0xE4E6, 0x5100, 0xBBF6, 0x5102, 0xBBFA, 0x5103, 0xE4E7, 0x5104, 0xBBF5, + 0x5105, 0xBBFD, 0x5106, 0xE4EA, 0x5107, 0xE4EB, 0x5108, 0xBBFB, 0x5109, 0xBBFC, 0x510A, 0xE4F1, 0x510B, 0xE4EE, 0x510C, 0xE4EF, + 0x5110, 0xBEAA, 0x5111, 0xE8F8, 0x5112, 0xBEA7, 0x5113, 0xE8F5, 0x5114, 0xBEA9, 0x5115, 0xBEAB, 0x5117, 0xE8F6, 0x5118, 0xBEA8, + 0x511A, 0xE8F7, 0x511C, 0xE8F4, 0x511F, 0xC076, 0x5120, 0xECBD, 0x5121, 0xC077, 0x5122, 0xECBB, 0x5124, 0xECBC, 0x5125, 0xECBA, + 0x5126, 0xECB9, 0x5129, 0xECBE, 0x512A, 0xC075, 0x512D, 0xEFB8, 0x512E, 0xEFB9, 0x5130, 0xE4E8, 0x5131, 0xEFB7, 0x5132, 0xC078, + 0x5133, 0xC35F, 0x5134, 0xF1EB, 0x5135, 0xF1EC, 0x5137, 0xC4D7, 0x5138, 0xC4D8, 0x5139, 0xF5C1, 0x513A, 0xF5C0, 0x513B, 0xC56C, + 0x513C, 0xC56B, 0x513D, 0xF7D0, 0x513F, 0xA449, 0x5140, 0xA461, 0x5141, 0xA4B9, 0x5143, 0xA4B8, 0x5144, 0xA553, 0x5145, 0xA552, + 0x5146, 0xA5FC, 0x5147, 0xA5FB, 0x5148, 0xA5FD, 0x5149, 0xA5FA, 0x514B, 0xA74A, 0x514C, 0xA749, 0x514D, 0xA74B, 0x5152, 0xA8E0, + 0x5154, 0xA8DF, 0x5155, 0xA8E1, 0x5157, 0xAB5E, 0x5159, 0xA259, 0x515A, 0xD0DE, 0x515B, 0xA25A, 0x515C, 0xB0C2, 0x515D, 0xA25C, + 0x515E, 0xA25B, 0x515F, 0xD860, 0x5161, 0xA25D, 0x5162, 0xB9B8, 0x5163, 0xA25E, 0x5165, 0xA44A, 0x5167, 0xA4BA, 0x5168, 0xA5FE, + 0x5169, 0xA8E2, 0x516B, 0xA44B, 0x516C, 0xA4BD, 0x516D, 0xA4BB, 0x516E, 0xA4BC, 0x5171, 0xA640, 0x5175, 0xA74C, 0x5176, 0xA8E4, + 0x5177, 0xA8E3, 0x5178, 0xA8E5, 0x517C, 0xADDD, 0x5180, 0xBEAC, 0x5187, 0xC94E, 0x5189, 0xA554, 0x518A, 0xA555, 0x518D, 0xA641, + 0x518F, 0xCA6A, 0x5191, 0xAB60, 0x5192, 0xAB5F, 0x5193, 0xD0E0, 0x5194, 0xD0DF, 0x5195, 0xB0C3, 0x5197, 0xA4BE, 0x5198, 0xC955, + 0x519E, 0xCBCD, 0x51A0, 0xAB61, 0x51A2, 0xADE0, 0x51A4, 0xADDE, 0x51A5, 0xADDF, 0x51AA, 0xBEAD, 0x51AC, 0xA556, 0x51B0, 0xA642, + 0x51B1, 0xC9BC, 0x51B6, 0xA74D, 0x51B7, 0xA74E, 0x51B9, 0xCA6B, 0x51BC, 0xCBCE, 0x51BD, 0xA8E6, 0x51BE, 0xCBCF, 0x51C4, 0xD0E2, + 0x51C5, 0xD0E3, 0x51C6, 0xADE3, 0x51C8, 0xD0E4, 0x51CA, 0xD0E1, 0x51CB, 0xADE4, 0x51CC, 0xADE2, 0x51CD, 0xADE1, 0x51CE, 0xD0E5, + 0x51D0, 0xD468, 0x51D4, 0xD861, 0x51D7, 0xDCC5, 0x51D8, 0xE140, 0x51DC, 0xBBFE, 0x51DD, 0xBEAE, 0x51DE, 0xE8F9, 0x51E0, 0xA44C, + 0x51E1, 0xA45A, 0x51F0, 0xB0C4, 0x51F1, 0xB3CD, 0x51F3, 0xB9B9, 0x51F5, 0xC942, 0x51F6, 0xA4BF, 0x51F8, 0xA559, 0x51F9, 0xA557, + 0x51FA, 0xA558, 0x51FD, 0xA8E7, 0x5200, 0xA44D, 0x5201, 0xA44E, 0x5203, 0xA462, 0x5206, 0xA4C0, 0x5207, 0xA4C1, 0x5208, 0xA4C2, + 0x5209, 0xC9BE, 0x520A, 0xA55A, 0x520C, 0xC96B, 0x520E, 0xA646, 0x5210, 0xC9BF, 0x5211, 0xA644, 0x5212, 0xA645, 0x5213, 0xC9BD, + 0x5216, 0xA647, 0x5217, 0xA643, 0x521C, 0xCA6C, 0x521D, 0xAAEC, 0x521E, 0xCA6D, 0x5221, 0xCA6E, 0x5224, 0xA750, 0x5225, 0xA74F, + 0x5228, 0xA753, 0x5229, 0xA751, 0x522A, 0xA752, 0x522E, 0xA8ED, 0x5230, 0xA8EC, 0x5231, 0xCBD4, 0x5232, 0xCBD1, 0x5233, 0xCBD2, + 0x5235, 0xCBD0, 0x5236, 0xA8EE, 0x5237, 0xA8EA, 0x5238, 0xA8E9, 0x523A, 0xA8EB, 0x523B, 0xA8E8, 0x5241, 0xA8EF, 0x5243, 0xAB63, + 0x5244, 0xCDF0, 0x5246, 0xCBD3, 0x5247, 0xAB68, 0x5249, 0xCDF1, 0x524A, 0xAB64, 0x524B, 0xAB67, 0x524C, 0xAB66, 0x524D, 0xAB65, + 0x524E, 0xAB62, 0x5252, 0xD0E8, 0x5254, 0xADE7, 0x5255, 0xD0EB, 0x5256, 0xADE5, 0x525A, 0xD0E7, 0x525B, 0xADE8, 0x525C, 0xADE6, + 0x525D, 0xADE9, 0x525E, 0xD0E9, 0x525F, 0xD0EA, 0x5261, 0xD0E6, 0x5262, 0xD0EC, 0x5269, 0xB3D1, 0x526A, 0xB0C5, 0x526B, 0xD469, + 0x526C, 0xD46B, 0x526D, 0xD46A, 0x526E, 0xD46C, 0x526F, 0xB0C6, 0x5272, 0xB3CE, 0x5274, 0xB3CF, 0x5275, 0xB3D0, 0x5277, 0xB6D0, + 0x5278, 0xDCC7, 0x527A, 0xDCC6, 0x527B, 0xDCC8, 0x527C, 0xDCC9, 0x527D, 0xB6D1, 0x527F, 0xB6CF, 0x5280, 0xE141, 0x5281, 0xE142, + 0x5282, 0xB9BB, 0x5283, 0xB9BA, 0x5284, 0xE35A, 0x5287, 0xBC40, 0x5288, 0xBC41, 0x5289, 0xBC42, 0x528A, 0xBC44, 0x528B, 0xE4F2, + 0x528C, 0xE4F3, 0x528D, 0xBC43, 0x5291, 0xBEAF, 0x5293, 0xBEB0, 0x5296, 0xF1ED, 0x5297, 0xF5C3, 0x5298, 0xF5C2, 0x5299, 0xF7D1, + 0x529B, 0xA44F, 0x529F, 0xA55C, 0x52A0, 0xA55B, 0x52A3, 0xA648, 0x52A6, 0xC9C0, 0x52A9, 0xA755, 0x52AA, 0xA756, 0x52AB, 0xA754, + 0x52AC, 0xA757, 0x52AD, 0xCA6F, 0x52AE, 0xCA70, 0x52BB, 0xA8F1, 0x52BC, 0xCBD5, 0x52BE, 0xA8F0, 0x52C0, 0xCDF2, 0x52C1, 0xAB6C, + 0x52C2, 0xCDF3, 0x52C3, 0xAB6B, 0x52C7, 0xAB69, 0x52C9, 0xAB6A, 0x52CD, 0xD0ED, 0x52D2, 0xB0C7, 0x52D3, 0xD46E, 0x52D5, 0xB0CA, + 0x52D6, 0xD46D, 0x52D7, 0xB1E5, 0x52D8, 0xB0C9, 0x52D9, 0xB0C8, 0x52DB, 0xB3D4, 0x52DD, 0xB3D3, 0x52DE, 0xB3D2, 0x52DF, 0xB6D2, + 0x52E2, 0xB6D5, 0x52E3, 0xB6D6, 0x52E4, 0xB6D4, 0x52E6, 0xB6D3, 0x52E9, 0xE143, 0x52EB, 0xE144, 0x52EF, 0xE4F5, 0x52F0, 0xBC45, + 0x52F1, 0xE4F4, 0x52F3, 0xBEB1, 0x52F4, 0xECBF, 0x52F5, 0xC079, 0x52F7, 0xF1EE, 0x52F8, 0xC455, 0x52FA, 0xA463, 0x52FB, 0xA4C3, + 0x52FC, 0xC956, 0x52FE, 0xA4C4, 0x52FF, 0xA4C5, 0x5305, 0xA55D, 0x5306, 0xA55E, 0x5308, 0xA649, 0x5309, 0xCA71, 0x530A, 0xCBD6, + 0x530B, 0xCBD7, 0x530D, 0xAB6D, 0x530E, 0xD0EE, 0x530F, 0xB0CC, 0x5310, 0xB0CB, 0x5311, 0xD863, 0x5312, 0xD862, 0x5315, 0xA450, + 0x5316, 0xA4C6, 0x5317, 0xA55F, 0x5319, 0xB0CD, 0x531A, 0xC943, 0x531C, 0xC96C, 0x531D, 0xA560, 0x531F, 0xC9C2, 0x5320, 0xA64B, + 0x5321, 0xA64A, 0x5322, 0xC9C1, 0x5323, 0xA758, 0x532A, 0xADEA, 0x532D, 0xD46F, 0x532F, 0xB6D7, 0x5330, 0xE145, 0x5331, 0xB9BC, + 0x5334, 0xE8FA, 0x5337, 0xF3FD, 0x5339, 0xA4C7, 0x533C, 0xCBD8, 0x533D, 0xCDF4, 0x533E, 0xB0D0, 0x533F, 0xB0CE, 0x5340, 0xB0CF, + 0x5341, 0xA2CC, 0x5341, 0xA451, 0x5343, 0xA464, 0x5344, 0xA2CD, 0x5345, 0xA2CE, 0x5345, 0xA4CA, 0x5347, 0xA4C9, 0x5348, 0xA4C8, + 0x5349, 0xA563, 0x534A, 0xA562, 0x534C, 0xC96D, 0x534D, 0xC9C3, 0x5351, 0xA8F5, 0x5352, 0xA8F2, 0x5353, 0xA8F4, 0x5354, 0xA8F3, + 0x5357, 0xAB6E, 0x535A, 0xB3D5, 0x535C, 0xA452, 0x535E, 0xA4CB, 0x5360, 0xA565, 0x5361, 0xA564, 0x5363, 0xCA72, 0x5366, 0xA8F6, + 0x536C, 0xC957, 0x536E, 0xA567, 0x536F, 0xA566, 0x5370, 0xA64C, 0x5371, 0xA64D, 0x5372, 0xCA73, 0x5373, 0xA759, 0x5375, 0xA75A, + 0x5377, 0xA8F7, 0x5378, 0xA8F8, 0x5379, 0xA8F9, 0x537B, 0xAB6F, 0x537C, 0xCDF5, 0x537F, 0xADEB, 0x5382, 0xC944, 0x5384, 0xA4CC, + 0x538A, 0xC9C4, 0x538E, 0xCA74, 0x538F, 0xCA75, 0x5392, 0xCBD9, 0x5394, 0xCBDA, 0x5396, 0xCDF7, 0x5397, 0xCDF6, 0x5398, 0xCDF9, + 0x5399, 0xCDF8, 0x539A, 0xAB70, 0x539C, 0xD470, 0x539D, 0xADED, 0x539E, 0xD0EF, 0x539F, 0xADEC, 0x53A4, 0xD864, 0x53A5, 0xB3D6, + 0x53A7, 0xD865, 0x53AC, 0xE146, 0x53AD, 0xB9BD, 0x53B2, 0xBC46, 0x53B4, 0xF1EF, 0x53B9, 0xC958, 0x53BB, 0xA568, 0x53C3, 0xB0D1, + 0x53C8, 0xA453, 0x53C9, 0xA465, 0x53CA, 0xA4CE, 0x53CB, 0xA4CD, 0x53CD, 0xA4CF, 0x53D4, 0xA8FB, 0x53D6, 0xA8FA, 0x53D7, 0xA8FC, + 0x53DB, 0xAB71, 0x53DF, 0xADEE, 0x53E1, 0xE8FB, 0x53E2, 0xC24F, 0x53E3, 0xA466, 0x53E4, 0xA56A, 0x53E5, 0xA579, 0x53E6, 0xA574, + 0x53E8, 0xA56F, 0x53E9, 0xA56E, 0x53EA, 0xA575, 0x53EB, 0xA573, 0x53EC, 0xA56C, 0x53ED, 0xA57A, 0x53EE, 0xA56D, 0x53EF, 0xA569, + 0x53F0, 0xA578, 0x53F1, 0xA577, 0x53F2, 0xA576, 0x53F3, 0xA56B, 0x53F5, 0xA572, 0x53F8, 0xA571, 0x53FB, 0xA57B, 0x53FC, 0xA570, + 0x5401, 0xA653, 0x5403, 0xA659, 0x5404, 0xA655, 0x5406, 0xA65B, 0x5407, 0xC9C5, 0x5408, 0xA658, 0x5409, 0xA64E, 0x540A, 0xA651, + 0x540B, 0xA654, 0x540C, 0xA650, 0x540D, 0xA657, 0x540E, 0xA65A, 0x540F, 0xA64F, 0x5410, 0xA652, 0x5411, 0xA656, 0x5412, 0xA65C, + 0x5418, 0xCA7E, 0x5419, 0xCA7B, 0x541B, 0xA767, 0x541C, 0xCA7C, 0x541D, 0xA75B, 0x541E, 0xA75D, 0x541F, 0xA775, 0x5420, 0xA770, + 0x5424, 0xCAA5, 0x5425, 0xCA7D, 0x5426, 0xA75F, 0x5427, 0xA761, 0x5428, 0xCAA4, 0x5429, 0xA768, 0x542A, 0xCA78, 0x542B, 0xA774, + 0x542C, 0xA776, 0x542D, 0xA75C, 0x542E, 0xA76D, 0x5430, 0xCA76, 0x5431, 0xA773, 0x5433, 0xA764, 0x5435, 0xA76E, 0x5436, 0xA76F, + 0x5437, 0xCA77, 0x5438, 0xA76C, 0x5439, 0xA76A, 0x543B, 0xA76B, 0x543C, 0xA771, 0x543D, 0xCAA1, 0x543E, 0xA75E, 0x5440, 0xA772, + 0x5441, 0xCAA3, 0x5442, 0xA766, 0x5443, 0xA763, 0x5445, 0xCA7A, 0x5446, 0xA762, 0x5447, 0xCAA6, 0x5448, 0xA765, 0x544A, 0xA769, + 0x544E, 0xA760, 0x544F, 0xCAA2, 0x5454, 0xCA79, 0x5460, 0xCBEB, 0x5461, 0xCBEA, 0x5462, 0xA94F, 0x5463, 0xCBED, 0x5464, 0xCBEF, + 0x5465, 0xCBE4, 0x5466, 0xCBE7, 0x5467, 0xCBEE, 0x5468, 0xA950, 0x546B, 0xCBE1, 0x546C, 0xCBE5, 0x546F, 0xCBE9, 0x5470, 0xCE49, + 0x5471, 0xA94B, 0x5472, 0xCE4D, 0x5473, 0xA8FD, 0x5474, 0xCBE6, 0x5475, 0xA8FE, 0x5476, 0xA94C, 0x5477, 0xA945, 0x5478, 0xA941, + 0x547A, 0xCBE2, 0x547B, 0xA944, 0x547C, 0xA949, 0x547D, 0xA952, 0x547E, 0xCBE3, 0x547F, 0xCBDC, 0x5480, 0xA943, 0x5481, 0xCBDD, + 0x5482, 0xCBDF, 0x5484, 0xA946, 0x5486, 0xA948, 0x5487, 0xCBDB, 0x5488, 0xCBE0, 0x548B, 0xA951, 0x548C, 0xA94D, 0x548D, 0xCBE8, + 0x548E, 0xA953, 0x5490, 0xA94A, 0x5491, 0xCBDE, 0x5492, 0xA947, 0x5495, 0xA942, 0x5496, 0xA940, 0x5498, 0xCBEC, 0x549A, 0xA94E, + 0x54A0, 0xCE48, 0x54A1, 0xCDFB, 0x54A2, 0xCE4B, 0x54A5, 0xCDFD, 0x54A6, 0xAB78, 0x54A7, 0xABA8, 0x54A8, 0xAB74, 0x54A9, 0xABA7, + 0x54AA, 0xAB7D, 0x54AB, 0xABA4, 0x54AC, 0xAB72, 0x54AD, 0xCDFC, 0x54AE, 0xCE43, 0x54AF, 0xABA3, 0x54B0, 0xCE4F, 0x54B1, 0xABA5, + 0x54B3, 0xAB79, 0x54B6, 0xCE45, 0x54B7, 0xCE42, 0x54B8, 0xAB77, 0x54BA, 0xCDFA, 0x54BB, 0xABA6, 0x54BC, 0xCE4A, 0x54BD, 0xAB7C, + 0x54BE, 0xCE4C, 0x54BF, 0xABA9, 0x54C0, 0xAB73, 0x54C1, 0xAB7E, 0x54C2, 0xAB7B, 0x54C3, 0xCE40, 0x54C4, 0xABA1, 0x54C5, 0xCE46, + 0x54C6, 0xCE47, 0x54C7, 0xAB7A, 0x54C8, 0xABA2, 0x54C9, 0xAB76, 0x54CE, 0xAB75, 0x54CF, 0xCDFE, 0x54D6, 0xCE44, 0x54DE, 0xCE4E, + 0x54E0, 0xD144, 0x54E1, 0xADFB, 0x54E2, 0xD0F1, 0x54E4, 0xD0F6, 0x54E5, 0xADF4, 0x54E6, 0xAE40, 0x54E7, 0xD0F4, 0x54E8, 0xADEF, + 0x54E9, 0xADF9, 0x54EA, 0xADFE, 0x54EB, 0xD0FB, 0x54ED, 0xADFA, 0x54EE, 0xADFD, 0x54F1, 0xD0FE, 0x54F2, 0xADF5, 0x54F3, 0xD0F5, + 0x54F7, 0xD142, 0x54F8, 0xD143, 0x54FA, 0xADF7, 0x54FB, 0xD141, 0x54FC, 0xADF3, 0x54FD, 0xAE43, 0x54FF, 0xD0F8, 0x5501, 0xADF1, + 0x5503, 0xD146, 0x5504, 0xD0F9, 0x5505, 0xD0FD, 0x5506, 0xADF6, 0x5507, 0xAE42, 0x5508, 0xD0FA, 0x5509, 0xADFC, 0x550A, 0xD140, + 0x550B, 0xD147, 0x550C, 0xD4A1, 0x550E, 0xD145, 0x550F, 0xAE44, 0x5510, 0xADF0, 0x5511, 0xD0FC, 0x5512, 0xD0F3, 0x5514, 0xADF8, + 0x5517, 0xD0F2, 0x551A, 0xD0F7, 0x5526, 0xD0F0, 0x5527, 0xAE41, 0x552A, 0xD477, 0x552C, 0xB0E4, 0x552D, 0xD4A7, 0x552E, 0xB0E2, + 0x552F, 0xB0DF, 0x5530, 0xD47C, 0x5531, 0xB0DB, 0x5532, 0xD4A2, 0x5533, 0xB0E6, 0x5534, 0xD476, 0x5535, 0xD47B, 0x5536, 0xD47A, + 0x5537, 0xADF2, 0x5538, 0xB0E1, 0x5539, 0xD4A5, 0x553B, 0xD4A8, 0x553C, 0xD473, 0x553E, 0xB3E8, 0x5540, 0xD4A9, 0x5541, 0xB0E7, + 0x5543, 0xB0D9, 0x5544, 0xB0D6, 0x5545, 0xD47E, 0x5546, 0xB0D3, 0x5548, 0xD4A6, 0x554A, 0xB0DA, 0x554B, 0xD4AA, 0x554D, 0xD474, + 0x554E, 0xD4A4, 0x554F, 0xB0DD, 0x5550, 0xD475, 0x5551, 0xD478, 0x5552, 0xD47D, 0x5555, 0xB0DE, 0x5556, 0xB0DC, 0x5557, 0xB0E8, + 0x555C, 0xB0E3, 0x555E, 0xB0D7, 0x555F, 0xB1D2, 0x5561, 0xB0D8, 0x5562, 0xD479, 0x5563, 0xB0E5, 0x5564, 0xB0E0, 0x5565, 0xD4A3, + 0x5566, 0xB0D5, 0x556A, 0xB0D4, 0x5575, 0xD471, 0x5576, 0xD472, 0x5577, 0xD86A, 0x557B, 0xB3D7, 0x557C, 0xB3DA, 0x557D, 0xD875, + 0x557E, 0xB3EE, 0x557F, 0xD878, 0x5580, 0xB3D8, 0x5581, 0xD871, 0x5582, 0xB3DE, 0x5583, 0xB3E4, 0x5584, 0xB5BD, 0x5587, 0xB3E2, + 0x5588, 0xD86E, 0x5589, 0xB3EF, 0x558A, 0xB3DB, 0x558B, 0xB3E3, 0x558C, 0xD876, 0x558D, 0xDCD7, 0x558E, 0xD87B, 0x558F, 0xD86F, + 0x5591, 0xD866, 0x5592, 0xD873, 0x5593, 0xD86D, 0x5594, 0xB3E1, 0x5595, 0xD879, 0x5598, 0xB3DD, 0x5599, 0xB3F1, 0x559A, 0xB3EA, + 0x559C, 0xB3DF, 0x559D, 0xB3DC, 0x559F, 0xB3E7, 0x55A1, 0xD87A, 0x55A2, 0xD86C, 0x55A3, 0xD872, 0x55A4, 0xD874, 0x55A5, 0xD868, + 0x55A6, 0xD877, 0x55A7, 0xB3D9, 0x55A8, 0xD867, 0x55AA, 0xB3E0, 0x55AB, 0xB3F0, 0x55AC, 0xB3EC, 0x55AD, 0xD869, 0x55AE, 0xB3E6, + 0x55B1, 0xB3ED, 0x55B2, 0xB3E9, 0x55B3, 0xB3E5, 0x55B5, 0xD870, 0x55BB, 0xB3EB, 0x55BF, 0xDCD5, 0x55C0, 0xDCD1, 0x55C2, 0xDCE0, + 0x55C3, 0xDCCA, 0x55C4, 0xDCD3, 0x55C5, 0xB6E5, 0x55C6, 0xB6E6, 0x55C7, 0xB6DE, 0x55C8, 0xDCDC, 0x55C9, 0xB6E8, 0x55CA, 0xDCCF, + 0x55CB, 0xDCCE, 0x55CC, 0xDCCC, 0x55CD, 0xDCDE, 0x55CE, 0xB6DC, 0x55CF, 0xDCD8, 0x55D0, 0xDCCD, 0x55D1, 0xB6DF, 0x55D2, 0xDCD6, + 0x55D3, 0xB6DA, 0x55D4, 0xDCD2, 0x55D5, 0xDCD9, 0x55D6, 0xDCDB, 0x55D9, 0xDCDF, 0x55DA, 0xB6E3, 0x55DB, 0xDCCB, 0x55DC, 0xB6DD, + 0x55DD, 0xDCD0, 0x55DF, 0xB6D8, 0x55E1, 0xB6E4, 0x55E2, 0xDCDA, 0x55E3, 0xB6E0, 0x55E4, 0xB6E1, 0x55E5, 0xB6E7, 0x55E6, 0xB6DB, + 0x55E7, 0xA25F, 0x55E8, 0xB6D9, 0x55E9, 0xDCD4, 0x55EF, 0xB6E2, 0x55F2, 0xDCDD, 0x55F6, 0xB9CD, 0x55F7, 0xB9C8, 0x55F9, 0xE155, + 0x55FA, 0xE151, 0x55FC, 0xE14B, 0x55FD, 0xB9C2, 0x55FE, 0xB9BE, 0x55FF, 0xE154, 0x5600, 0xB9BF, 0x5601, 0xE14E, 0x5602, 0xE150, + 0x5604, 0xE153, 0x5606, 0xB9C4, 0x5608, 0xB9CB, 0x5609, 0xB9C5, 0x560C, 0xE149, 0x560D, 0xB9C6, 0x560E, 0xB9C7, 0x560F, 0xE14C, + 0x5610, 0xB9CC, 0x5612, 0xE14A, 0x5613, 0xE14F, 0x5614, 0xB9C3, 0x5615, 0xE148, 0x5616, 0xB9C9, 0x5617, 0xB9C1, 0x561B, 0xB9C0, + 0x561C, 0xE14D, 0x561D, 0xE152, 0x561F, 0xB9CA, 0x5627, 0xE147, 0x5629, 0xBC4D, 0x562A, 0xE547, 0x562C, 0xE544, 0x562E, 0xBC47, + 0x562F, 0xBC53, 0x5630, 0xBC54, 0x5632, 0xBC4A, 0x5633, 0xE542, 0x5634, 0xBC4C, 0x5635, 0xE4F9, 0x5636, 0xBC52, 0x5638, 0xE546, + 0x5639, 0xBC49, 0x563A, 0xE548, 0x563B, 0xBC48, 0x563D, 0xE543, 0x563E, 0xE545, 0x563F, 0xBC4B, 0x5640, 0xE541, 0x5641, 0xE4FA, + 0x5642, 0xE4F7, 0x5645, 0xD86B, 0x5646, 0xE4FD, 0x5648, 0xE4F6, 0x5649, 0xE4FC, 0x564A, 0xE4FB, 0x564C, 0xE4F8, 0x564E, 0xBC4F, + 0x5653, 0xBC4E, 0x5657, 0xBC50, 0x5658, 0xE4FE, 0x5659, 0xBEB2, 0x565A, 0xE540, 0x565E, 0xE945, 0x5660, 0xE8FD, 0x5662, 0xBEBE, + 0x5663, 0xE942, 0x5664, 0xBEB6, 0x5665, 0xBEBA, 0x5666, 0xE941, 0x5668, 0xBEB9, 0x5669, 0xBEB5, 0x566A, 0xBEB8, 0x566B, 0xBEB3, + 0x566C, 0xBEBD, 0x566D, 0xE943, 0x566E, 0xE8FE, 0x566F, 0xBEBC, 0x5670, 0xE8FC, 0x5671, 0xBEBB, 0x5672, 0xE944, 0x5673, 0xE940, + 0x5674, 0xBC51, 0x5676, 0xBEBF, 0x5677, 0xE946, 0x5678, 0xBEB7, 0x5679, 0xBEB4, 0x567E, 0xECC6, 0x567F, 0xECC8, 0x5680, 0xC07B, + 0x5681, 0xECC9, 0x5682, 0xECC7, 0x5683, 0xECC5, 0x5684, 0xECC4, 0x5685, 0xC07D, 0x5686, 0xECC3, 0x5687, 0xC07E, 0x568C, 0xECC1, + 0x568D, 0xECC2, 0x568E, 0xC07A, 0x568F, 0xC0A1, 0x5690, 0xC07C, 0x5693, 0xECC0, 0x5695, 0xC250, 0x5697, 0xEFBC, 0x5698, 0xEFBA, + 0x5699, 0xEFBF, 0x569A, 0xEFBD, 0x569C, 0xEFBB, 0x569D, 0xEFBE, 0x56A5, 0xC360, 0x56A6, 0xF1F2, 0x56A7, 0xF1F3, 0x56A8, 0xC456, + 0x56AA, 0xF1F4, 0x56AB, 0xF1F0, 0x56AC, 0xF1F5, 0x56AD, 0xF1F1, 0x56AE, 0xC251, 0x56B2, 0xF3FE, 0x56B3, 0xF441, 0x56B4, 0xC459, + 0x56B5, 0xF440, 0x56B6, 0xC458, 0x56B7, 0xC457, 0x56BC, 0xC45A, 0x56BD, 0xF5C5, 0x56BE, 0xF5C6, 0x56C0, 0xC4DA, 0x56C1, 0xC4D9, + 0x56C2, 0xC4DB, 0x56C3, 0xF5C4, 0x56C5, 0xF6D8, 0x56C6, 0xF6D7, 0x56C8, 0xC56D, 0x56C9, 0xC56F, 0x56CA, 0xC56E, 0x56CB, 0xF6D9, + 0x56CC, 0xC5C8, 0x56CD, 0xF8A6, 0x56D1, 0xC5F1, 0x56D3, 0xF8A5, 0x56D4, 0xF8EE, 0x56D7, 0xC949, 0x56DA, 0xA57D, 0x56DB, 0xA57C, + 0x56DD, 0xA65F, 0x56DE, 0xA65E, 0x56DF, 0xC9C7, 0x56E0, 0xA65D, 0x56E1, 0xC9C6, 0x56E4, 0xA779, 0x56E5, 0xCAA9, 0x56E7, 0xCAA8, + 0x56EA, 0xA777, 0x56EB, 0xA77A, 0x56EE, 0xCAA7, 0x56F0, 0xA778, 0x56F7, 0xCBF0, 0x56F9, 0xCBF1, 0x56FA, 0xA954, 0x56FF, 0xABAA, + 0x5701, 0xD148, 0x5702, 0xD149, 0x5703, 0xAE45, 0x5704, 0xAE46, 0x5707, 0xD4AC, 0x5708, 0xB0E9, 0x5709, 0xB0EB, 0x570A, 0xD4AB, + 0x570B, 0xB0EA, 0x570C, 0xD87C, 0x570D, 0xB3F2, 0x5712, 0xB6E9, 0x5713, 0xB6EA, 0x5714, 0xDCE1, 0x5716, 0xB9CF, 0x5718, 0xB9CE, + 0x571A, 0xE549, 0x571B, 0xE948, 0x571C, 0xE947, 0x571E, 0xF96B, 0x571F, 0xA467, 0x5720, 0xC959, 0x5722, 0xC96E, 0x5723, 0xC96F, + 0x5728, 0xA662, 0x5729, 0xA666, 0x572A, 0xC9C9, 0x572C, 0xA664, 0x572D, 0xA663, 0x572E, 0xC9C8, 0x572F, 0xA665, 0x5730, 0xA661, + 0x5733, 0xA660, 0x5734, 0xC9CA, 0x573B, 0xA7A6, 0x573E, 0xA7A3, 0x5740, 0xA77D, 0x5741, 0xCAAA, 0x5745, 0xCAAB, 0x5747, 0xA7A1, + 0x5749, 0xCAAD, 0x574A, 0xA77B, 0x574B, 0xCAAE, 0x574C, 0xCAAC, 0x574D, 0xA77E, 0x574E, 0xA7A2, 0x574F, 0xA7A5, 0x5750, 0xA7A4, + 0x5751, 0xA77C, 0x5752, 0xCAAF, 0x5761, 0xA959, 0x5762, 0xCBFE, 0x5764, 0xA95B, 0x5766, 0xA95A, 0x5768, 0xCC40, 0x5769, 0xA958, + 0x576A, 0xA957, 0x576B, 0xCBF5, 0x576D, 0xCBF4, 0x576F, 0xCBF2, 0x5770, 0xCBF7, 0x5771, 0xCBF6, 0x5772, 0xCBF3, 0x5773, 0xCBFC, + 0x5774, 0xCBFD, 0x5775, 0xCBFA, 0x5776, 0xCBF8, 0x5777, 0xA956, 0x577B, 0xCBFB, 0x577C, 0xA95C, 0x577D, 0xCC41, 0x5780, 0xCBF9, + 0x5782, 0xABAB, 0x5783, 0xA955, 0x578B, 0xABAC, 0x578C, 0xCE54, 0x578F, 0xCE5A, 0x5793, 0xABB2, 0x5794, 0xCE58, 0x5795, 0xCE5E, + 0x5797, 0xCE55, 0x5798, 0xCE59, 0x5799, 0xCE5B, 0x579A, 0xCE5D, 0x579B, 0xCE57, 0x579D, 0xCE56, 0x579E, 0xCE51, 0x579F, 0xCE52, + 0x57A0, 0xABAD, 0x57A2, 0xABAF, 0x57A3, 0xABAE, 0x57A4, 0xCE53, 0x57A5, 0xCE5C, 0x57AE, 0xABB1, 0x57B5, 0xCE50, 0x57B6, 0xD153, + 0x57B8, 0xD152, 0x57B9, 0xD157, 0x57BA, 0xD14E, 0x57BC, 0xD151, 0x57BD, 0xD150, 0x57BF, 0xD154, 0x57C1, 0xD158, 0x57C2, 0xAE47, + 0x57C3, 0xAE4A, 0x57C6, 0xD14F, 0x57C7, 0xD155, 0x57CB, 0xAE49, 0x57CC, 0xD14A, 0x57CE, 0xABB0, 0x57CF, 0xD4BA, 0x57D0, 0xD156, + 0x57D2, 0xD14D, 0x57D4, 0xAE48, 0x57D5, 0xD14C, 0x57DC, 0xD4B1, 0x57DF, 0xB0EC, 0x57E0, 0xB0F0, 0x57E1, 0xD4C1, 0x57E2, 0xD4AF, + 0x57E3, 0xD4BD, 0x57E4, 0xB0F1, 0x57E5, 0xD4BF, 0x57E7, 0xD4C5, 0x57E9, 0xD4C9, 0x57EC, 0xD4C0, 0x57ED, 0xD4B4, 0x57EE, 0xD4BC, + 0x57F0, 0xD4CA, 0x57F1, 0xD4C8, 0x57F2, 0xD4BE, 0x57F3, 0xD4B9, 0x57F4, 0xD4B2, 0x57F5, 0xD8A6, 0x57F6, 0xD4B0, 0x57F7, 0xB0F5, + 0x57F8, 0xD4B7, 0x57F9, 0xB0F6, 0x57FA, 0xB0F2, 0x57FB, 0xD4AD, 0x57FC, 0xD4C3, 0x57FD, 0xD4B5, 0x5800, 0xD4B3, 0x5801, 0xD4C6, + 0x5802, 0xB0F3, 0x5804, 0xD4CC, 0x5805, 0xB0ED, 0x5806, 0xB0EF, 0x5807, 0xD4BB, 0x5808, 0xD4B6, 0x5809, 0xAE4B, 0x580A, 0xB0EE, + 0x580B, 0xD4B8, 0x580C, 0xD4C7, 0x580D, 0xD4CB, 0x580E, 0xD4C2, 0x5810, 0xD4C4, 0x5814, 0xD4AE, 0x5819, 0xD8A1, 0x581B, 0xD8AA, + 0x581C, 0xD8A9, 0x581D, 0xB3FA, 0x581E, 0xD8A2, 0x5820, 0xB3FB, 0x5821, 0xB3F9, 0x5823, 0xD8A4, 0x5824, 0xB3F6, 0x5825, 0xD8A8, + 0x5827, 0xD8A3, 0x5828, 0xD8A5, 0x5829, 0xD87D, 0x582A, 0xB3F4, 0x582C, 0xD8B2, 0x582D, 0xD8B1, 0x582E, 0xD8AE, 0x582F, 0xB3F3, + 0x5830, 0xB3F7, 0x5831, 0xB3F8, 0x5832, 0xD14B, 0x5833, 0xD8AB, 0x5834, 0xB3F5, 0x5835, 0xB0F4, 0x5836, 0xD8AD, 0x5837, 0xD87E, + 0x5838, 0xD8B0, 0x5839, 0xD8AF, 0x583B, 0xD8B3, 0x583D, 0xDCEF, 0x583F, 0xD8AC, 0x5848, 0xD8A7, 0x5849, 0xDCE7, 0x584A, 0xB6F4, + 0x584B, 0xB6F7, 0x584C, 0xB6F2, 0x584D, 0xDCE6, 0x584E, 0xDCEA, 0x584F, 0xDCE5, 0x5851, 0xB6EC, 0x5852, 0xB6F6, 0x5853, 0xDCE2, + 0x5854, 0xB6F0, 0x5855, 0xDCE9, 0x5857, 0xB6EE, 0x5858, 0xB6ED, 0x5859, 0xDCEC, 0x585A, 0xB6EF, 0x585B, 0xDCEE, 0x585D, 0xDCEB, + 0x585E, 0xB6EB, 0x5862, 0xB6F5, 0x5863, 0xDCF0, 0x5864, 0xDCE4, 0x5865, 0xDCED, 0x5868, 0xDCE3, 0x586B, 0xB6F1, 0x586D, 0xB6F3, + 0x586F, 0xDCE8, 0x5871, 0xDCF1, 0x5874, 0xE15D, 0x5875, 0xB9D0, 0x5876, 0xE163, 0x5879, 0xB9D5, 0x587A, 0xE15F, 0x587B, 0xE166, + 0x587C, 0xE157, 0x587D, 0xB9D7, 0x587E, 0xB9D1, 0x587F, 0xE15C, 0x5880, 0xBC55, 0x5881, 0xE15B, 0x5882, 0xE164, 0x5883, 0xB9D2, + 0x5885, 0xB9D6, 0x5886, 0xE15A, 0x5887, 0xE160, 0x5888, 0xE165, 0x5889, 0xE156, 0x588A, 0xB9D4, 0x588B, 0xE15E, 0x588E, 0xE162, + 0x588F, 0xE168, 0x5890, 0xE158, 0x5891, 0xE161, 0x5893, 0xB9D3, 0x5894, 0xE167, 0x5898, 0xE159, 0x589C, 0xBC59, 0x589D, 0xE54B, + 0x589E, 0xBC57, 0x589F, 0xBC56, 0x58A0, 0xE54D, 0x58A1, 0xE552, 0x58A3, 0xE54E, 0x58A5, 0xE551, 0x58A6, 0xBC5C, 0x58A8, 0xBEA5, + 0x58A9, 0xBC5B, 0x58AB, 0xE54A, 0x58AC, 0xE550, 0x58AE, 0xBC5A, 0x58AF, 0xE54F, 0x58B1, 0xE54C, 0x58B3, 0xBC58, 0x58BA, 0xE94D, + 0x58BB, 0xF9D9, 0x58BC, 0xE94F, 0x58BD, 0xE94A, 0x58BE, 0xBEC1, 0x58BF, 0xE94C, 0x58C1, 0xBEC0, 0x58C2, 0xE94E, 0x58C5, 0xBEC3, + 0x58C6, 0xE950, 0x58C7, 0xBEC2, 0x58C8, 0xE949, 0x58C9, 0xE94B, 0x58CE, 0xC0A5, 0x58CF, 0xECCC, 0x58D1, 0xC0A4, 0x58D2, 0xECCD, + 0x58D3, 0xC0A3, 0x58D4, 0xECCB, 0x58D5, 0xC0A2, 0x58D6, 0xECCA, 0x58D8, 0xC253, 0x58D9, 0xC252, 0x58DA, 0xF1F6, 0x58DB, 0xF1F8, + 0x58DD, 0xF1F7, 0x58DE, 0xC361, 0x58DF, 0xC362, 0x58E2, 0xC363, 0x58E3, 0xF442, 0x58E4, 0xC45B, 0x58E7, 0xF7D3, 0x58E8, 0xF7D2, + 0x58E9, 0xC5F2, 0x58EB, 0xA468, 0x58EC, 0xA4D0, 0x58EF, 0xA7A7, 0x58F4, 0xCE5F, 0x58F9, 0xB3FC, 0x58FA, 0xB3FD, 0x58FC, 0xDCF2, + 0x58FD, 0xB9D8, 0x58FE, 0xE169, 0x58FF, 0xE553, 0x5903, 0xC95A, 0x5906, 0xCAB0, 0x590C, 0xCC42, 0x590D, 0xCE60, 0x590E, 0xD159, + 0x590F, 0xAE4C, 0x5912, 0xF1F9, 0x5914, 0xC4DC, 0x5915, 0xA469, 0x5916, 0xA57E, 0x5917, 0xC970, 0x5919, 0xA667, 0x591A, 0xA668, + 0x591C, 0xA95D, 0x5920, 0xB0F7, 0x5922, 0xB9DA, 0x5924, 0xB9DB, 0x5925, 0xB9D9, 0x5927, 0xA46A, 0x5929, 0xA4D1, 0x592A, 0xA4D3, + 0x592B, 0xA4D2, 0x592C, 0xC95B, 0x592D, 0xA4D4, 0x592E, 0xA5A1, 0x592F, 0xC971, 0x5931, 0xA5A2, 0x5937, 0xA669, 0x5938, 0xA66A, + 0x593C, 0xC9CB, 0x593E, 0xA7A8, 0x5940, 0xCAB1, 0x5944, 0xA961, 0x5945, 0xCC43, 0x5947, 0xA95F, 0x5948, 0xA960, 0x5949, 0xA95E, + 0x594A, 0xD15A, 0x594E, 0xABB6, 0x594F, 0xABB5, 0x5950, 0xABB7, 0x5951, 0xABB4, 0x5953, 0xCE61, 0x5954, 0xA962, 0x5955, 0xABB3, + 0x5957, 0xAE4D, 0x5958, 0xAE4E, 0x595A, 0xAE4F, 0x595C, 0xD4CD, 0x5960, 0xB3FE, 0x5961, 0xD8B4, 0x5962, 0xB0F8, 0x5967, 0xB6F8, + 0x5969, 0xB9DD, 0x596A, 0xB9DC, 0x596B, 0xE16A, 0x596D, 0xBC5D, 0x596E, 0xBEC4, 0x5970, 0xEFC0, 0x5971, 0xF6DA, 0x5972, 0xF7D4, + 0x5973, 0xA46B, 0x5974, 0xA5A3, 0x5976, 0xA5A4, 0x5977, 0xC9D1, 0x5978, 0xA66C, 0x5979, 0xA66F, 0x597B, 0xC9CF, 0x597C, 0xC9CD, + 0x597D, 0xA66E, 0x597E, 0xC9D0, 0x597F, 0xC9D2, 0x5980, 0xC9CC, 0x5981, 0xA671, 0x5982, 0xA670, 0x5983, 0xA66D, 0x5984, 0xA66B, + 0x5985, 0xC9CE, 0x598A, 0xA7B3, 0x598D, 0xA7B0, 0x598E, 0xCAB6, 0x598F, 0xCAB9, 0x5990, 0xCAB8, 0x5992, 0xA7AA, 0x5993, 0xA7B2, + 0x5996, 0xA7AF, 0x5997, 0xCAB5, 0x5998, 0xCAB3, 0x5999, 0xA7AE, 0x599D, 0xA7A9, 0x599E, 0xA7AC, 0x59A0, 0xCAB4, 0x59A1, 0xCABB, + 0x59A2, 0xCAB7, 0x59A3, 0xA7AD, 0x59A4, 0xA7B1, 0x59A5, 0xA7B4, 0x59A6, 0xCAB2, 0x59A7, 0xCABA, 0x59A8, 0xA7AB, 0x59AE, 0xA967, + 0x59AF, 0xA96F, 0x59B1, 0xCC4F, 0x59B2, 0xCC48, 0x59B3, 0xA970, 0x59B4, 0xCC53, 0x59B5, 0xCC44, 0x59B6, 0xCC4B, 0x59B9, 0xA966, + 0x59BA, 0xCC45, 0x59BB, 0xA964, 0x59BC, 0xCC4C, 0x59BD, 0xCC50, 0x59BE, 0xA963, 0x59C0, 0xCC51, 0x59C1, 0xCC4A, 0x59C3, 0xCC4D, + 0x59C5, 0xA972, 0x59C6, 0xA969, 0x59C7, 0xCC54, 0x59C8, 0xCC52, 0x59CA, 0xA96E, 0x59CB, 0xA96C, 0x59CC, 0xCC49, 0x59CD, 0xA96B, + 0x59CE, 0xCC47, 0x59CF, 0xCC46, 0x59D0, 0xA96A, 0x59D1, 0xA968, 0x59D2, 0xA971, 0x59D3, 0xA96D, 0x59D4, 0xA965, 0x59D6, 0xCC4E, + 0x59D8, 0xABB9, 0x59DA, 0xABC0, 0x59DB, 0xCE6F, 0x59DC, 0xABB8, 0x59DD, 0xCE67, 0x59DE, 0xCE63, 0x59E0, 0xCE73, 0x59E1, 0xCE62, + 0x59E3, 0xABBB, 0x59E4, 0xCE6C, 0x59E5, 0xABBE, 0x59E6, 0xABC1, 0x59E8, 0xABBC, 0x59E9, 0xCE70, 0x59EA, 0xABBF, 0x59EC, 0xAE56, + 0x59ED, 0xCE76, 0x59EE, 0xCE64, 0x59F1, 0xCE66, 0x59F2, 0xCE6D, 0x59F3, 0xCE71, 0x59F4, 0xCE75, 0x59F5, 0xCE72, 0x59F6, 0xCE6B, + 0x59F7, 0xCE6E, 0x59FA, 0xCE68, 0x59FB, 0xABC3, 0x59FC, 0xCE6A, 0x59FD, 0xCE69, 0x59FE, 0xCE74, 0x59FF, 0xABBA, 0x5A00, 0xCE65, + 0x5A01, 0xABC2, 0x5A03, 0xABBD, 0x5A09, 0xAE5C, 0x5A0A, 0xD162, 0x5A0C, 0xAE5B, 0x5A0F, 0xD160, 0x5A11, 0xAE50, 0x5A13, 0xAE55, + 0x5A15, 0xD15F, 0x5A16, 0xD15C, 0x5A17, 0xD161, 0x5A18, 0xAE51, 0x5A19, 0xD15B, 0x5A1B, 0xAE54, 0x5A1C, 0xAE52, 0x5A1E, 0xD163, + 0x5A1F, 0xAE53, 0x5A20, 0xAE57, 0x5A23, 0xAE58, 0x5A25, 0xAE5A, 0x5A29, 0xAE59, 0x5A2D, 0xD15D, 0x5A2E, 0xD15E, 0x5A33, 0xD164, + 0x5A35, 0xD4D4, 0x5A36, 0xB0F9, 0x5A37, 0xD8C2, 0x5A38, 0xD4D3, 0x5A39, 0xD4E6, 0x5A3C, 0xB140, 0x5A3E, 0xD4E4, 0x5A40, 0xB0FE, + 0x5A41, 0xB0FA, 0x5A42, 0xD4ED, 0x5A43, 0xD4DD, 0x5A44, 0xD4E0, 0x5A46, 0xB143, 0x5A47, 0xD4EA, 0x5A48, 0xD4E2, 0x5A49, 0xB0FB, + 0x5A4A, 0xB144, 0x5A4C, 0xD4E7, 0x5A4D, 0xD4E5, 0x5A50, 0xD4D6, 0x5A51, 0xD4EB, 0x5A52, 0xD4DF, 0x5A53, 0xD4DA, 0x5A55, 0xD4D0, + 0x5A56, 0xD4EC, 0x5A57, 0xD4DC, 0x5A58, 0xD4CF, 0x5A5A, 0xB142, 0x5A5B, 0xD4E1, 0x5A5C, 0xD4EE, 0x5A5D, 0xD4DE, 0x5A5E, 0xD4D2, + 0x5A5F, 0xD4D7, 0x5A60, 0xD4CE, 0x5A62, 0xB141, 0x5A64, 0xD4DB, 0x5A65, 0xD4D8, 0x5A66, 0xB0FC, 0x5A67, 0xD4D1, 0x5A69, 0xD4E9, + 0x5A6A, 0xB0FD, 0x5A6C, 0xD4D9, 0x5A6D, 0xD4D5, 0x5A70, 0xD4E8, 0x5A77, 0xB440, 0x5A78, 0xD8BB, 0x5A7A, 0xD8B8, 0x5A7B, 0xD8C9, + 0x5A7C, 0xD8BD, 0x5A7D, 0xD8CA, 0x5A7F, 0xB442, 0x5A83, 0xD8C6, 0x5A84, 0xD8C3, 0x5A8A, 0xD8C4, 0x5A8B, 0xD8C7, 0x5A8C, 0xD8CB, + 0x5A8E, 0xD4E3, 0x5A8F, 0xD8CD, 0x5A90, 0xDD47, 0x5A92, 0xB443, 0x5A93, 0xD8CE, 0x5A94, 0xD8B6, 0x5A95, 0xD8C0, 0x5A97, 0xD8C5, + 0x5A9A, 0xB441, 0x5A9B, 0xB444, 0x5A9C, 0xD8CC, 0x5A9D, 0xD8CF, 0x5A9E, 0xD8BA, 0x5A9F, 0xD8B7, 0x5AA2, 0xD8B9, 0x5AA5, 0xD8BE, + 0x5AA6, 0xD8BC, 0x5AA7, 0xB445, 0x5AA9, 0xD8C8, 0x5AAC, 0xD8BF, 0x5AAE, 0xD8C1, 0x5AAF, 0xD8B5, 0x5AB0, 0xDCFA, 0x5AB1, 0xDCF8, + 0x5AB2, 0xB742, 0x5AB3, 0xB740, 0x5AB4, 0xDD43, 0x5AB5, 0xDCF9, 0x5AB6, 0xDD44, 0x5AB7, 0xDD40, 0x5AB8, 0xDCF7, 0x5AB9, 0xDD46, + 0x5ABA, 0xDCF6, 0x5ABB, 0xDCFD, 0x5ABC, 0xB6FE, 0x5ABD, 0xB6FD, 0x5ABE, 0xB6FC, 0x5ABF, 0xDCFB, 0x5AC0, 0xDD41, 0x5AC1, 0xB6F9, + 0x5AC2, 0xB741, 0x5AC4, 0xDCF4, 0x5AC6, 0xDCFE, 0x5AC7, 0xDCF3, 0x5AC8, 0xDCFC, 0x5AC9, 0xB6FA, 0x5ACA, 0xDD42, 0x5ACB, 0xDCF5, + 0x5ACC, 0xB6FB, 0x5ACD, 0xDD45, 0x5AD5, 0xE16E, 0x5AD6, 0xB9E2, 0x5AD7, 0xB9E1, 0x5AD8, 0xB9E3, 0x5AD9, 0xE17A, 0x5ADA, 0xE170, + 0x5ADB, 0xE176, 0x5ADC, 0xE16B, 0x5ADD, 0xE179, 0x5ADE, 0xE178, 0x5ADF, 0xE17C, 0x5AE0, 0xE175, 0x5AE1, 0xB9DE, 0x5AE2, 0xE174, + 0x5AE3, 0xB9E4, 0x5AE5, 0xE16D, 0x5AE6, 0xB9DF, 0x5AE8, 0xE17B, 0x5AE9, 0xB9E0, 0x5AEA, 0xE16F, 0x5AEB, 0xE172, 0x5AEC, 0xE177, + 0x5AED, 0xE171, 0x5AEE, 0xE16C, 0x5AF3, 0xE173, 0x5AF4, 0xE555, 0x5AF5, 0xBC61, 0x5AF6, 0xE558, 0x5AF7, 0xE557, 0x5AF8, 0xE55A, + 0x5AF9, 0xE55C, 0x5AFA, 0xF9DC, 0x5AFB, 0xBC5F, 0x5AFD, 0xE556, 0x5AFF, 0xE554, 0x5B01, 0xE55D, 0x5B02, 0xE55B, 0x5B03, 0xE559, + 0x5B05, 0xE55F, 0x5B07, 0xE55E, 0x5B08, 0xBC63, 0x5B09, 0xBC5E, 0x5B0B, 0xBC60, 0x5B0C, 0xBC62, 0x5B0F, 0xE560, 0x5B10, 0xE957, + 0x5B13, 0xE956, 0x5B14, 0xE955, 0x5B16, 0xE958, 0x5B17, 0xE951, 0x5B19, 0xE952, 0x5B1A, 0xE95A, 0x5B1B, 0xE953, 0x5B1D, 0xBEC5, + 0x5B1E, 0xE95C, 0x5B20, 0xE95B, 0x5B21, 0xE954, 0x5B23, 0xECD1, 0x5B24, 0xC0A8, 0x5B25, 0xECCF, 0x5B26, 0xECD4, 0x5B27, 0xECD3, + 0x5B28, 0xE959, 0x5B2A, 0xC0A7, 0x5B2C, 0xECD2, 0x5B2D, 0xECCE, 0x5B2E, 0xECD6, 0x5B2F, 0xECD5, 0x5B30, 0xC0A6, 0x5B32, 0xECD0, + 0x5B34, 0xBEC6, 0x5B38, 0xC254, 0x5B3C, 0xEFC1, 0x5B3D, 0xF1FA, 0x5B3E, 0xF1FB, 0x5B3F, 0xF1FC, 0x5B40, 0xC45C, 0x5B43, 0xC45D, + 0x5B45, 0xF443, 0x5B47, 0xF5C8, 0x5B48, 0xF5C7, 0x5B4B, 0xF6DB, 0x5B4C, 0xF6DC, 0x5B4D, 0xF7D5, 0x5B4E, 0xF8A7, 0x5B50, 0xA46C, + 0x5B51, 0xA46D, 0x5B53, 0xA46E, 0x5B54, 0xA4D5, 0x5B55, 0xA5A5, 0x5B56, 0xC9D3, 0x5B57, 0xA672, 0x5B58, 0xA673, 0x5B5A, 0xA7B7, + 0x5B5B, 0xA7B8, 0x5B5C, 0xA7B6, 0x5B5D, 0xA7B5, 0x5B5F, 0xA973, 0x5B62, 0xCC55, 0x5B63, 0xA975, 0x5B64, 0xA974, 0x5B65, 0xCC56, + 0x5B69, 0xABC4, 0x5B6B, 0xAE5D, 0x5B6C, 0xD165, 0x5B6E, 0xD4F0, 0x5B70, 0xB145, 0x5B71, 0xB447, 0x5B72, 0xD4EF, 0x5B73, 0xB446, + 0x5B75, 0xB9E5, 0x5B77, 0xE17D, 0x5B78, 0xBEC7, 0x5B7A, 0xC0A9, 0x5B7B, 0xECD7, 0x5B7D, 0xC45E, 0x5B7F, 0xC570, 0x5B81, 0xC972, + 0x5B83, 0xA5A6, 0x5B84, 0xC973, 0x5B85, 0xA676, 0x5B87, 0xA674, 0x5B88, 0xA675, 0x5B89, 0xA677, 0x5B8B, 0xA7BA, 0x5B8C, 0xA7B9, + 0x5B8E, 0xCABC, 0x5B8F, 0xA7BB, 0x5B92, 0xCABD, 0x5B93, 0xCC57, 0x5B95, 0xCC58, 0x5B97, 0xA976, 0x5B98, 0xA978, 0x5B99, 0xA97A, + 0x5B9A, 0xA977, 0x5B9B, 0xA97B, 0x5B9C, 0xA979, 0x5BA2, 0xABC8, 0x5BA3, 0xABC5, 0x5BA4, 0xABC7, 0x5BA5, 0xABC9, 0x5BA6, 0xABC6, + 0x5BA7, 0xD166, 0x5BA8, 0xCE77, 0x5BAC, 0xD168, 0x5BAD, 0xD167, 0x5BAE, 0xAE63, 0x5BB0, 0xAE5F, 0x5BB3, 0xAE60, 0x5BB4, 0xAE62, + 0x5BB5, 0xAE64, 0x5BB6, 0xAE61, 0x5BB8, 0xAE66, 0x5BB9, 0xAE65, 0x5BBF, 0xB14A, 0x5BC0, 0xD4F2, 0x5BC1, 0xD4F1, 0x5BC2, 0xB149, + 0x5BC4, 0xB148, 0x5BC5, 0xB147, 0x5BC6, 0xB14B, 0x5BC7, 0xB146, 0x5BCA, 0xD8D5, 0x5BCB, 0xD8D2, 0x5BCC, 0xB449, 0x5BCD, 0xD8D1, + 0x5BCE, 0xD8D6, 0x5BD0, 0xB44B, 0x5BD1, 0xD8D4, 0x5BD2, 0xB448, 0x5BD3, 0xB44A, 0x5BD4, 0xD8D3, 0x5BD6, 0xDD48, 0x5BD8, 0xDD49, + 0x5BD9, 0xDD4A, 0x5BDE, 0xB9E6, 0x5BDF, 0xB9EE, 0x5BE0, 0xE17E, 0x5BE1, 0xB9E8, 0x5BE2, 0xB9EC, 0x5BE3, 0xE1A1, 0x5BE4, 0xB9ED, + 0x5BE5, 0xB9E9, 0x5BE6, 0xB9EA, 0x5BE7, 0xB9E7, 0x5BE8, 0xB9EB, 0x5BE9, 0xBC66, 0x5BEA, 0xD8D0, 0x5BEB, 0xBC67, 0x5BEC, 0xBC65, + 0x5BEE, 0xBC64, 0x5BEF, 0xE95D, 0x5BF0, 0xBEC8, 0x5BF1, 0xECD8, 0x5BF2, 0xECD9, 0x5BF5, 0xC364, 0x5BF6, 0xC45F, 0x5BF8, 0xA46F, + 0x5BFA, 0xA678, 0x5C01, 0xABCA, 0x5C03, 0xD169, 0x5C04, 0xAE67, 0x5C07, 0xB14E, 0x5C08, 0xB14D, 0x5C09, 0xB14C, 0x5C0A, 0xB44C, + 0x5C0B, 0xB44D, 0x5C0C, 0xD8D7, 0x5C0D, 0xB9EF, 0x5C0E, 0xBEC9, 0x5C0F, 0xA470, 0x5C10, 0xC95C, 0x5C11, 0xA4D6, 0x5C12, 0xC974, + 0x5C15, 0xC9D4, 0x5C16, 0xA679, 0x5C1A, 0xA97C, 0x5C1F, 0xDD4B, 0x5C22, 0xA471, 0x5C24, 0xA4D7, 0x5C25, 0xC9D5, 0x5C28, 0xCABE, + 0x5C2A, 0xCABF, 0x5C2C, 0xA7BC, 0x5C30, 0xD8D8, 0x5C31, 0xB44E, 0x5C33, 0xDD4C, 0x5C37, 0xC0AA, 0x5C38, 0xA472, 0x5C39, 0xA4A8, + 0x5C3A, 0xA4D8, 0x5C3B, 0xC975, 0x5C3C, 0xA5A7, 0x5C3E, 0xA7C0, 0x5C3F, 0xA7BF, 0x5C40, 0xA7BD, 0x5C41, 0xA7BE, 0x5C44, 0xCC59, + 0x5C45, 0xA97E, 0x5C46, 0xA9A1, 0x5C47, 0xCC5A, 0x5C48, 0xA97D, 0x5C4B, 0xABCE, 0x5C4C, 0xCE78, 0x5C4D, 0xABCD, 0x5C4E, 0xABCB, + 0x5C4F, 0xABCC, 0x5C50, 0xAE6A, 0x5C51, 0xAE68, 0x5C54, 0xD16B, 0x5C55, 0xAE69, 0x5C56, 0xD16A, 0x5C58, 0xAE5E, 0x5C59, 0xD4F3, + 0x5C5C, 0xB150, 0x5C5D, 0xB151, 0x5C60, 0xB14F, 0x5C62, 0xB9F0, 0x5C63, 0xE1A2, 0x5C64, 0xBC68, 0x5C65, 0xBC69, 0x5C67, 0xE561, + 0x5C68, 0xC0AB, 0x5C69, 0xEFC2, 0x5C6A, 0xEFC3, 0x5C6C, 0xC4DD, 0x5C6D, 0xF8A8, 0x5C6E, 0xC94B, 0x5C6F, 0xA4D9, 0x5C71, 0xA473, + 0x5C73, 0xC977, 0x5C74, 0xC976, 0x5C79, 0xA67A, 0x5C7A, 0xC9D7, 0x5C7B, 0xC9D8, 0x5C7C, 0xC9D6, 0x5C7E, 0xC9D9, 0x5C86, 0xCAC7, + 0x5C88, 0xCAC2, 0x5C89, 0xCAC4, 0x5C8A, 0xCAC6, 0x5C8B, 0xCAC3, 0x5C8C, 0xA7C4, 0x5C8D, 0xCAC0, 0x5C8F, 0xCAC1, 0x5C90, 0xA7C1, + 0x5C91, 0xA7C2, 0x5C92, 0xCAC5, 0x5C93, 0xCAC8, 0x5C94, 0xA7C3, 0x5C95, 0xCAC9, 0x5C9D, 0xCC68, 0x5C9F, 0xCC62, 0x5CA0, 0xCC5D, + 0x5CA1, 0xA9A3, 0x5CA2, 0xCC65, 0x5CA3, 0xCC63, 0x5CA4, 0xCC5C, 0x5CA5, 0xCC69, 0x5CA6, 0xCC6C, 0x5CA7, 0xCC67, 0x5CA8, 0xCC60, + 0x5CA9, 0xA9A5, 0x5CAA, 0xCC66, 0x5CAB, 0xA9A6, 0x5CAC, 0xCC61, 0x5CAD, 0xCC64, 0x5CAE, 0xCC5B, 0x5CAF, 0xCC5F, 0x5CB0, 0xCC6B, + 0x5CB1, 0xA9A7, 0x5CB3, 0xA9A8, 0x5CB5, 0xCC5E, 0x5CB6, 0xCC6A, 0x5CB7, 0xA9A2, 0x5CB8, 0xA9A4, 0x5CC6, 0xCEAB, 0x5CC7, 0xCEA4, + 0x5CC8, 0xCEAA, 0x5CC9, 0xCEA3, 0x5CCA, 0xCEA5, 0x5CCB, 0xCE7D, 0x5CCC, 0xCE7B, 0x5CCE, 0xCEAC, 0x5CCF, 0xCEA9, 0x5CD0, 0xCE79, + 0x5CD2, 0xABD0, 0x5CD3, 0xCEA7, 0x5CD4, 0xCEA8, 0x5CD6, 0xCEA6, 0x5CD7, 0xCE7C, 0x5CD8, 0xCE7A, 0x5CD9, 0xABCF, 0x5CDA, 0xCEA2, + 0x5CDB, 0xCE7E, 0x5CDE, 0xCEA1, 0x5CDF, 0xCEAD, 0x5CE8, 0xAE6F, 0x5CEA, 0xAE6E, 0x5CEC, 0xD16C, 0x5CED, 0xAE6B, 0x5CEE, 0xD16E, + 0x5CF0, 0xAE70, 0x5CF1, 0xD16F, 0x5CF4, 0xAE73, 0x5CF6, 0xAE71, 0x5CF7, 0xD170, 0x5CF8, 0xCEAE, 0x5CF9, 0xD172, 0x5CFB, 0xAE6D, + 0x5CFD, 0xAE6C, 0x5CFF, 0xD16D, 0x5D00, 0xD171, 0x5D01, 0xAE72, 0x5D06, 0xB153, 0x5D07, 0xB152, 0x5D0B, 0xD4F5, 0x5D0C, 0xD4F9, + 0x5D0D, 0xD4FB, 0x5D0E, 0xB154, 0x5D0F, 0xD4FE, 0x5D11, 0xB158, 0x5D12, 0xD541, 0x5D14, 0xB15A, 0x5D16, 0xB156, 0x5D17, 0xB15E, + 0x5D19, 0xB15B, 0x5D1A, 0xD4F7, 0x5D1B, 0xB155, 0x5D1D, 0xD4F6, 0x5D1E, 0xD4F4, 0x5D1F, 0xD543, 0x5D20, 0xD4F8, 0x5D22, 0xB157, + 0x5D23, 0xD542, 0x5D24, 0xB15C, 0x5D25, 0xD4FD, 0x5D26, 0xD4FC, 0x5D27, 0xB15D, 0x5D28, 0xD4FA, 0x5D29, 0xB159, 0x5D2E, 0xD544, + 0x5D30, 0xD540, 0x5D31, 0xD8E7, 0x5D32, 0xD8EE, 0x5D33, 0xD8E3, 0x5D34, 0xB451, 0x5D35, 0xD8DF, 0x5D36, 0xD8EF, 0x5D37, 0xD8D9, + 0x5D38, 0xD8EC, 0x5D39, 0xD8EA, 0x5D3A, 0xD8E4, 0x5D3C, 0xD8ED, 0x5D3D, 0xD8E6, 0x5D3F, 0xD8DE, 0x5D40, 0xD8F0, 0x5D41, 0xD8DC, + 0x5D42, 0xD8E9, 0x5D43, 0xD8DA, 0x5D45, 0xD8F1, 0x5D47, 0xB452, 0x5D49, 0xD8EB, 0x5D4A, 0xDD4F, 0x5D4B, 0xD8DD, 0x5D4C, 0xB44F, + 0x5D4E, 0xD8E1, 0x5D50, 0xB450, 0x5D51, 0xD8E0, 0x5D52, 0xD8E5, 0x5D55, 0xD8E2, 0x5D59, 0xD8E8, 0x5D5E, 0xDD53, 0x5D62, 0xDD56, + 0x5D63, 0xDD4E, 0x5D65, 0xDD50, 0x5D67, 0xDD55, 0x5D68, 0xDD54, 0x5D69, 0xB743, 0x5D6B, 0xD8DB, 0x5D6C, 0xDD52, 0x5D6F, 0xB744, + 0x5D71, 0xDD4D, 0x5D72, 0xDD51, 0x5D77, 0xE1A9, 0x5D79, 0xE1B0, 0x5D7A, 0xE1A7, 0x5D7C, 0xE1AE, 0x5D7D, 0xE1A5, 0x5D7E, 0xE1AD, + 0x5D7F, 0xE1B1, 0x5D80, 0xE1A4, 0x5D81, 0xE1A8, 0x5D82, 0xE1A3, 0x5D84, 0xB9F1, 0x5D86, 0xE1A6, 0x5D87, 0xB9F2, 0x5D88, 0xE1AC, + 0x5D89, 0xE1AB, 0x5D8A, 0xE1AA, 0x5D8D, 0xE1AF, 0x5D92, 0xE565, 0x5D93, 0xE567, 0x5D94, 0xBC6B, 0x5D95, 0xE568, 0x5D97, 0xE563, + 0x5D99, 0xE562, 0x5D9A, 0xE56C, 0x5D9C, 0xE56A, 0x5D9D, 0xBC6A, 0x5D9E, 0xE56D, 0x5D9F, 0xE564, 0x5DA0, 0xE569, 0x5DA1, 0xE56B, + 0x5DA2, 0xE566, 0x5DA7, 0xE961, 0x5DA8, 0xE966, 0x5DA9, 0xE960, 0x5DAA, 0xE965, 0x5DAC, 0xE95E, 0x5DAD, 0xE968, 0x5DAE, 0xE964, + 0x5DAF, 0xE969, 0x5DB0, 0xE963, 0x5DB1, 0xE95F, 0x5DB2, 0xE967, 0x5DB4, 0xE96A, 0x5DB5, 0xE962, 0x5DB7, 0xECDA, 0x5DB8, 0xC0AF, + 0x5DBA, 0xC0AD, 0x5DBC, 0xC0AC, 0x5DBD, 0xC0AE, 0x5DC0, 0xEFC4, 0x5DC2, 0xF172, 0x5DC3, 0xF1FD, 0x5DC6, 0xF444, 0x5DC7, 0xF445, + 0x5DC9, 0xC460, 0x5DCB, 0xF5C9, 0x5DCD, 0xC4DE, 0x5DCF, 0xF5CA, 0x5DD1, 0xF6DE, 0x5DD2, 0xC572, 0x5DD4, 0xC571, 0x5DD5, 0xF6DD, + 0x5DD6, 0xC5C9, 0x5DD8, 0xF7D6, 0x5DDD, 0xA474, 0x5DDE, 0xA67B, 0x5DDF, 0xC9DA, 0x5DE0, 0xCACA, 0x5DE1, 0xA8B5, 0x5DE2, 0xB15F, + 0x5DE5, 0xA475, 0x5DE6, 0xA5AA, 0x5DE7, 0xA5A9, 0x5DE8, 0xA5A8, 0x5DEB, 0xA7C5, 0x5DEE, 0xAE74, 0x5DF0, 0xDD57, 0x5DF1, 0xA476, + 0x5DF2, 0xA477, 0x5DF3, 0xA478, 0x5DF4, 0xA4DA, 0x5DF7, 0xABD1, 0x5DF9, 0xCEAF, 0x5DFD, 0xB453, 0x5DFE, 0xA479, 0x5DFF, 0xC95D, + 0x5E02, 0xA5AB, 0x5E03, 0xA5AC, 0x5E04, 0xC978, 0x5E06, 0xA67C, 0x5E0A, 0xCACB, 0x5E0C, 0xA7C6, 0x5E0E, 0xCACC, 0x5E11, 0xA9AE, + 0x5E14, 0xCC6E, 0x5E15, 0xA9AC, 0x5E16, 0xA9AB, 0x5E17, 0xCC6D, 0x5E18, 0xA9A9, 0x5E19, 0xCC6F, 0x5E1A, 0xA9AA, 0x5E1B, 0xA9AD, + 0x5E1D, 0xABD2, 0x5E1F, 0xABD4, 0x5E20, 0xCEB3, 0x5E21, 0xCEB0, 0x5E22, 0xCEB1, 0x5E23, 0xCEB2, 0x5E24, 0xCEB4, 0x5E25, 0xABD3, + 0x5E28, 0xD174, 0x5E29, 0xD173, 0x5E2B, 0xAE76, 0x5E2D, 0xAE75, 0x5E33, 0xB162, 0x5E34, 0xD546, 0x5E36, 0xB161, 0x5E37, 0xB163, + 0x5E38, 0xB160, 0x5E3D, 0xB455, 0x5E3E, 0xD545, 0x5E40, 0xB456, 0x5E41, 0xD8F3, 0x5E43, 0xB457, 0x5E44, 0xD8F2, 0x5E45, 0xB454, + 0x5E4A, 0xDD5A, 0x5E4B, 0xDD5C, 0x5E4C, 0xB745, 0x5E4D, 0xDD5B, 0x5E4E, 0xDD59, 0x5E4F, 0xDD58, 0x5E53, 0xE1B4, 0x5E54, 0xB9F7, + 0x5E55, 0xB9F5, 0x5E57, 0xB9F6, 0x5E58, 0xE1B2, 0x5E59, 0xE1B3, 0x5E5B, 0xB9F3, 0x5E5C, 0xE571, 0x5E5D, 0xE56F, 0x5E5F, 0xBC6D, + 0x5E60, 0xE570, 0x5E61, 0xBC6E, 0x5E62, 0xBC6C, 0x5E63, 0xB9F4, 0x5E66, 0xE96D, 0x5E67, 0xE96B, 0x5E68, 0xE96C, 0x5E69, 0xE56E, + 0x5E6A, 0xECDC, 0x5E6B, 0xC0B0, 0x5E6C, 0xECDB, 0x5E6D, 0xEFC5, 0x5E6E, 0xEFC6, 0x5E6F, 0xE96E, 0x5E70, 0xF1FE, 0x5E72, 0xA47A, + 0x5E73, 0xA5AD, 0x5E74, 0xA67E, 0x5E75, 0xC9DB, 0x5E76, 0xA67D, 0x5E78, 0xA9AF, 0x5E79, 0xB746, 0x5E7B, 0xA4DB, 0x5E7C, 0xA5AE, + 0x5E7D, 0xABD5, 0x5E7E, 0xB458, 0x5E80, 0xC979, 0x5E82, 0xC97A, 0x5E84, 0xC9DC, 0x5E87, 0xA7C8, 0x5E88, 0xCAD0, 0x5E89, 0xCACE, + 0x5E8A, 0xA7C9, 0x5E8B, 0xCACD, 0x5E8C, 0xCACF, 0x5E8D, 0xCAD1, 0x5E8F, 0xA7C7, 0x5E95, 0xA9B3, 0x5E96, 0xA9B4, 0x5E97, 0xA9B1, + 0x5E9A, 0xA9B0, 0x5E9B, 0xCEB8, 0x5E9C, 0xA9B2, 0x5EA0, 0xABD6, 0x5EA2, 0xCEB7, 0x5EA3, 0xCEB9, 0x5EA4, 0xCEB6, 0x5EA5, 0xCEBA, + 0x5EA6, 0xABD7, 0x5EA7, 0xAE79, 0x5EA8, 0xD175, 0x5EAA, 0xD177, 0x5EAB, 0xAE77, 0x5EAC, 0xD178, 0x5EAD, 0xAE78, 0x5EAE, 0xD176, + 0x5EB0, 0xCEB5, 0x5EB1, 0xD547, 0x5EB2, 0xD54A, 0x5EB3, 0xD54B, 0x5EB4, 0xD548, 0x5EB5, 0xB167, 0x5EB6, 0xB166, 0x5EB7, 0xB164, + 0x5EB8, 0xB165, 0x5EB9, 0xD549, 0x5EBE, 0xB168, 0x5EC1, 0xB45A, 0x5EC2, 0xB45B, 0x5EC4, 0xB45C, 0x5EC5, 0xDD5D, 0x5EC6, 0xDD5F, + 0x5EC7, 0xDD61, 0x5EC8, 0xB748, 0x5EC9, 0xB747, 0x5ECA, 0xB459, 0x5ECB, 0xDD60, 0x5ECC, 0xDD5E, 0x5ECE, 0xE1B8, 0x5ED1, 0xE1B6, + 0x5ED2, 0xE1BC, 0x5ED3, 0xB9F8, 0x5ED4, 0xE1BD, 0x5ED5, 0xE1BA, 0x5ED6, 0xB9F9, 0x5ED7, 0xE1B7, 0x5ED8, 0xE1B5, 0x5ED9, 0xE1BB, + 0x5EDA, 0xBC70, 0x5EDB, 0xE573, 0x5EDC, 0xE1B9, 0x5EDD, 0xBC72, 0x5EDE, 0xE574, 0x5EDF, 0xBC71, 0x5EE0, 0xBC74, 0x5EE1, 0xE575, + 0x5EE2, 0xBC6F, 0x5EE3, 0xBC73, 0x5EE5, 0xE973, 0x5EE6, 0xE971, 0x5EE7, 0xE970, 0x5EE8, 0xE972, 0x5EE9, 0xE96F, 0x5EEC, 0xC366, + 0x5EEE, 0xF446, 0x5EEF, 0xF447, 0x5EF1, 0xF5CB, 0x5EF2, 0xF6DF, 0x5EF3, 0xC655, 0x5EF6, 0xA9B5, 0x5EF7, 0xA7CA, 0x5EFA, 0xABD8, + 0x5EFE, 0xA47B, 0x5EFF, 0xA4DC, 0x5F01, 0xA5AF, 0x5F02, 0xC9DD, 0x5F04, 0xA7CB, 0x5F05, 0xCAD2, 0x5F07, 0xCEBB, 0x5F08, 0xABD9, + 0x5F0A, 0xB9FA, 0x5F0B, 0xA47C, 0x5F0F, 0xA6A1, 0x5F12, 0xB749, 0x5F13, 0xA47D, 0x5F14, 0xA4DD, 0x5F15, 0xA4DE, 0x5F17, 0xA5B1, + 0x5F18, 0xA5B0, 0x5F1A, 0xC9DE, 0x5F1B, 0xA6A2, 0x5F1D, 0xCAD3, 0x5F1F, 0xA7CC, 0x5F22, 0xCC71, 0x5F23, 0xCC72, 0x5F24, 0xCC73, + 0x5F26, 0xA9B6, 0x5F27, 0xA9B7, 0x5F28, 0xCC70, 0x5F29, 0xA9B8, 0x5F2D, 0xABDA, 0x5F2E, 0xCEBC, 0x5F30, 0xD17A, 0x5F31, 0xAE7A, + 0x5F33, 0xD179, 0x5F35, 0xB169, 0x5F36, 0xD54C, 0x5F37, 0xB16A, 0x5F38, 0xD54D, 0x5F3C, 0xB45D, 0x5F40, 0xDD62, 0x5F43, 0xE1BF, + 0x5F44, 0xE1BE, 0x5F46, 0xB9FB, 0x5F48, 0xBC75, 0x5F49, 0xE576, 0x5F4A, 0xBECA, 0x5F4B, 0xE974, 0x5F4C, 0xC0B1, 0x5F4E, 0xC573, + 0x5F4F, 0xF7D8, 0x5F54, 0xCC74, 0x5F56, 0xCEBD, 0x5F57, 0xB16B, 0x5F58, 0xD8F4, 0x5F59, 0xB74A, 0x5F5D, 0xC255, 0x5F62, 0xA7CE, + 0x5F64, 0xA7CD, 0x5F65, 0xABDB, 0x5F67, 0xD17B, 0x5F69, 0xB16D, 0x5F6A, 0xB343, 0x5F6B, 0xB16E, 0x5F6C, 0xB16C, 0x5F6D, 0xB45E, + 0x5F6F, 0xE1C0, 0x5F70, 0xB9FC, 0x5F71, 0xBC76, 0x5F73, 0xC94C, 0x5F74, 0xC9DF, 0x5F76, 0xCAD5, 0x5F77, 0xA7CF, 0x5F78, 0xCAD4, + 0x5F79, 0xA7D0, 0x5F7C, 0xA9BC, 0x5F7D, 0xCC77, 0x5F7E, 0xCC76, 0x5F7F, 0xA9BB, 0x5F80, 0xA9B9, 0x5F81, 0xA9BA, 0x5F82, 0xCC75, + 0x5F85, 0xABDD, 0x5F86, 0xCEBE, 0x5F87, 0xABE0, 0x5F88, 0xABDC, 0x5F89, 0xABE2, 0x5F8A, 0xABDE, 0x5F8B, 0xABDF, 0x5F8C, 0xABE1, + 0x5F90, 0xAE7D, 0x5F91, 0xAE7C, 0x5F92, 0xAE7B, 0x5F96, 0xD54F, 0x5F97, 0xB16F, 0x5F98, 0xB172, 0x5F99, 0xB170, 0x5F9B, 0xD54E, + 0x5F9C, 0xB175, 0x5F9E, 0xB171, 0x5F9F, 0xD550, 0x5FA0, 0xB174, 0x5FA1, 0xB173, 0x5FA5, 0xD8F6, 0x5FA6, 0xD8F5, 0x5FA8, 0xB461, + 0x5FA9, 0xB45F, 0x5FAA, 0xB460, 0x5FAB, 0xD8F7, 0x5FAC, 0xB74B, 0x5FAD, 0xDD64, 0x5FAE, 0xB74C, 0x5FAF, 0xDD63, 0x5FB2, 0xE577, + 0x5FB5, 0xBC78, 0x5FB6, 0xE1C1, 0x5FB7, 0xBC77, 0x5FB9, 0xB9FD, 0x5FBB, 0xECDE, 0x5FBC, 0xE975, 0x5FBD, 0xC0B2, 0x5FBE, 0xECDD, + 0x5FBF, 0xF240, 0x5FC0, 0xF448, 0x5FC1, 0xF449, 0x5FC3, 0xA4DF, 0x5FC5, 0xA5B2, 0x5FC9, 0xC97B, 0x5FCC, 0xA7D2, 0x5FCD, 0xA7D4, + 0x5FCF, 0xC9E2, 0x5FD0, 0xCAD8, 0x5FD1, 0xCAD7, 0x5FD2, 0xCAD6, 0x5FD4, 0xC9E1, 0x5FD5, 0xC9E0, 0x5FD6, 0xA6A4, 0x5FD7, 0xA7D3, + 0x5FD8, 0xA7D1, 0x5FD9, 0xA6A3, 0x5FDD, 0xA9BD, 0x5FDE, 0xCC78, 0x5FE0, 0xA9BE, 0x5FE1, 0xCADD, 0x5FE3, 0xCADF, 0x5FE4, 0xCADE, + 0x5FE5, 0xCC79, 0x5FE8, 0xCADA, 0x5FEA, 0xA7D8, 0x5FEB, 0xA7D6, 0x5FED, 0xCAD9, 0x5FEE, 0xCADB, 0x5FEF, 0xCAE1, 0x5FF1, 0xA7D5, + 0x5FF3, 0xCADC, 0x5FF4, 0xCAE5, 0x5FF5, 0xA9C0, 0x5FF7, 0xCAE2, 0x5FF8, 0xA7D7, 0x5FFA, 0xCAE0, 0x5FFB, 0xCAE3, 0x5FFD, 0xA9BF, + 0x5FFF, 0xA9C1, 0x6000, 0xCAE4, 0x6009, 0xCCAF, 0x600A, 0xCCA2, 0x600B, 0xCC7E, 0x600C, 0xCCAE, 0x600D, 0xCCA9, 0x600E, 0xABE7, + 0x600F, 0xA9C2, 0x6010, 0xCCAA, 0x6011, 0xCCAD, 0x6012, 0xABE3, 0x6013, 0xCCAC, 0x6014, 0xA9C3, 0x6015, 0xA9C8, 0x6016, 0xA9C6, + 0x6017, 0xCCA3, 0x6019, 0xCC7C, 0x601A, 0xCCA5, 0x601B, 0xA9CD, 0x601C, 0xCCB0, 0x601D, 0xABE4, 0x601E, 0xCCA6, 0x6020, 0xABE5, + 0x6021, 0xA9C9, 0x6022, 0xCCA8, 0x6024, 0xCECD, 0x6025, 0xABE6, 0x6026, 0xCC7B, 0x6027, 0xA9CA, 0x6028, 0xABE8, 0x6029, 0xA9CB, + 0x602A, 0xA9C7, 0x602B, 0xA9CC, 0x602C, 0xCCA7, 0x602D, 0xCC7A, 0x602E, 0xCCAB, 0x602F, 0xA9C4, 0x6032, 0xCC7D, 0x6033, 0xCCA4, + 0x6034, 0xCCA1, 0x6035, 0xA9C5, 0x6037, 0xCEBF, 0x6039, 0xCEC0, 0x6040, 0xCECA, 0x6041, 0xD1A1, 0x6042, 0xCECB, 0x6043, 0xABEE, + 0x6044, 0xCECE, 0x6045, 0xCEC4, 0x6046, 0xABED, 0x6047, 0xCEC6, 0x6049, 0xCEC7, 0x604C, 0xCEC9, 0x604D, 0xABE9, 0x6050, 0xAEA3, + 0x6052, 0xF9DA, 0x6053, 0xCEC5, 0x6054, 0xCEC1, 0x6055, 0xAEA4, 0x6058, 0xCECF, 0x6059, 0xAE7E, 0x605A, 0xD17D, 0x605B, 0xCEC8, + 0x605D, 0xD17C, 0x605E, 0xCEC3, 0x605F, 0xCECC, 0x6062, 0xABEC, 0x6063, 0xAEA1, 0x6064, 0xABF2, 0x6065, 0xAEA2, 0x6066, 0xCED0, + 0x6067, 0xD17E, 0x6068, 0xABEB, 0x6069, 0xAEA6, 0x606A, 0xABF1, 0x606B, 0xABF0, 0x606C, 0xABEF, 0x606D, 0xAEA5, 0x606E, 0xCED1, + 0x606F, 0xAEA7, 0x6070, 0xABEA, 0x6072, 0xCEC2, 0x607F, 0xB176, 0x6080, 0xD1A4, 0x6081, 0xD1A6, 0x6083, 0xD1A8, 0x6084, 0xAEA8, + 0x6085, 0xAEAE, 0x6086, 0xD553, 0x6087, 0xD1AC, 0x6088, 0xD1A3, 0x6089, 0xB178, 0x608A, 0xD551, 0x608C, 0xAEAD, 0x608D, 0xAEAB, + 0x608E, 0xD1AE, 0x6090, 0xD552, 0x6092, 0xD1A5, 0x6094, 0xAEAC, 0x6095, 0xD1A9, 0x6096, 0xAEAF, 0x6097, 0xD1AB, 0x609A, 0xAEAA, + 0x609B, 0xD1AA, 0x609C, 0xD1AD, 0x609D, 0xD1A7, 0x609F, 0xAEA9, 0x60A0, 0xB179, 0x60A2, 0xD1A2, 0x60A3, 0xB177, 0x60A8, 0xB17A, + 0x60B0, 0xD555, 0x60B1, 0xD55E, 0x60B2, 0xB464, 0x60B4, 0xB17C, 0x60B5, 0xB1A3, 0x60B6, 0xB465, 0x60B7, 0xD560, 0x60B8, 0xB1AA, + 0x60B9, 0xD8F9, 0x60BA, 0xD556, 0x60BB, 0xB1A2, 0x60BC, 0xB1A5, 0x60BD, 0xB17E, 0x60BE, 0xD554, 0x60BF, 0xD562, 0x60C0, 0xD565, + 0x60C1, 0xD949, 0x60C3, 0xD563, 0x60C4, 0xD8FD, 0x60C5, 0xB1A1, 0x60C6, 0xB1A8, 0x60C7, 0xB1AC, 0x60C8, 0xD55D, 0x60C9, 0xD8F8, + 0x60CA, 0xD561, 0x60CB, 0xB17B, 0x60CC, 0xD8FA, 0x60CD, 0xD564, 0x60CE, 0xD8FC, 0x60CF, 0xD559, 0x60D1, 0xB462, 0x60D3, 0xD557, + 0x60D4, 0xD558, 0x60D5, 0xB1A7, 0x60D8, 0xB1A6, 0x60D9, 0xD55B, 0x60DA, 0xB1AB, 0x60DB, 0xD55F, 0x60DC, 0xB1A4, 0x60DD, 0xD55C, + 0x60DF, 0xB1A9, 0x60E0, 0xB466, 0x60E1, 0xB463, 0x60E2, 0xD8FB, 0x60E4, 0xD55A, 0x60E6, 0xB17D, 0x60F0, 0xB46B, 0x60F1, 0xB46F, + 0x60F2, 0xD940, 0x60F3, 0xB751, 0x60F4, 0xB46D, 0x60F5, 0xD944, 0x60F6, 0xB471, 0x60F7, 0xDD65, 0x60F8, 0xD946, 0x60F9, 0xB753, + 0x60FA, 0xB469, 0x60FB, 0xB46C, 0x60FC, 0xD947, 0x60FE, 0xD948, 0x60FF, 0xD94E, 0x6100, 0xB473, 0x6101, 0xB754, 0x6103, 0xD94A, + 0x6104, 0xD94F, 0x6105, 0xD943, 0x6106, 0xB75E, 0x6108, 0xB755, 0x6109, 0xB472, 0x610A, 0xD941, 0x610B, 0xD950, 0x610D, 0xB75D, + 0x610E, 0xB470, 0x610F, 0xB74E, 0x6110, 0xD94D, 0x6112, 0xB474, 0x6113, 0xD945, 0x6114, 0xD8FE, 0x6115, 0xB46A, 0x6116, 0xD942, + 0x6118, 0xD94B, 0x611A, 0xB74D, 0x611B, 0xB752, 0x611C, 0xB467, 0x611D, 0xD94C, 0x611F, 0xB750, 0x6123, 0xB468, 0x6127, 0xB75C, + 0x6128, 0xE1C3, 0x6129, 0xDD70, 0x612B, 0xDD68, 0x612C, 0xE1C2, 0x612E, 0xDD6C, 0x612F, 0xDD6E, 0x6132, 0xDD6B, 0x6134, 0xB75B, + 0x6136, 0xDD6A, 0x6137, 0xB75F, 0x613B, 0xE1D2, 0x613E, 0xB75A, 0x613F, 0xBA40, 0x6140, 0xDD71, 0x6141, 0xE1C4, 0x6144, 0xB758, + 0x6145, 0xDD69, 0x6146, 0xDD6D, 0x6147, 0xB9FE, 0x6148, 0xB74F, 0x6149, 0xDD66, 0x614A, 0xDD67, 0x614B, 0xBA41, 0x614C, 0xB757, + 0x614D, 0xB759, 0x614E, 0xB756, 0x614F, 0xDD6F, 0x6152, 0xE1C8, 0x6153, 0xE1C9, 0x6154, 0xE1CE, 0x6155, 0xBC7D, 0x6156, 0xE1D5, + 0x6158, 0xBA47, 0x615A, 0xBA46, 0x615B, 0xE1D0, 0x615D, 0xBC7C, 0x615E, 0xE1C5, 0x615F, 0xBA45, 0x6161, 0xE1D4, 0x6162, 0xBA43, + 0x6163, 0xBA44, 0x6165, 0xE1D1, 0x6166, 0xE5AA, 0x6167, 0xBC7A, 0x6168, 0xB46E, 0x616A, 0xE1D3, 0x616B, 0xBCA3, 0x616C, 0xE1CB, + 0x616E, 0xBC7B, 0x6170, 0xBCA2, 0x6171, 0xE1C6, 0x6172, 0xE1CA, 0x6173, 0xE1C7, 0x6174, 0xE1CD, 0x6175, 0xBA48, 0x6176, 0xBC79, + 0x6177, 0xBA42, 0x6179, 0xE57A, 0x617A, 0xE1CF, 0x617C, 0xBCA1, 0x617E, 0xBCA4, 0x6180, 0xE1CC, 0x6182, 0xBC7E, 0x6183, 0xE579, + 0x6189, 0xE57E, 0x618A, 0xBECE, 0x618B, 0xE578, 0x618C, 0xE9A3, 0x618D, 0xE5A9, 0x618E, 0xBCA8, 0x6190, 0xBCA6, 0x6191, 0xBECC, + 0x6192, 0xE5A6, 0x6193, 0xE5A2, 0x6194, 0xBCAC, 0x6196, 0xE978, 0x619A, 0xBCAA, 0x619B, 0xE5A1, 0x619D, 0xE976, 0x619F, 0xE5A5, + 0x61A1, 0xE5A8, 0x61A2, 0xE57D, 0x61A4, 0xBCAB, 0x61A7, 0xBCA5, 0x61A8, 0xE977, 0x61A9, 0xBECD, 0x61AA, 0xE5A7, 0x61AB, 0xBCA7, + 0x61AC, 0xBCA9, 0x61AD, 0xE5A4, 0x61AE, 0xBCAD, 0x61AF, 0xE5A3, 0x61B0, 0xE57C, 0x61B1, 0xE57B, 0x61B2, 0xBECB, 0x61B3, 0xE5AB, + 0x61B4, 0xE97A, 0x61B5, 0xECE0, 0x61B6, 0xBED0, 0x61B8, 0xE9A2, 0x61BA, 0xE97E, 0x61BC, 0xECE1, 0x61BE, 0xBED1, 0x61BF, 0xE9A1, + 0x61C1, 0xE97C, 0x61C2, 0xC0B4, 0x61C3, 0xECDF, 0x61C5, 0xE979, 0x61C6, 0xE97B, 0x61C7, 0xC0B5, 0x61C8, 0xBED3, 0x61C9, 0xC0B3, + 0x61CA, 0xBED2, 0x61CB, 0xC0B7, 0x61CC, 0xE97D, 0x61CD, 0xBECF, 0x61D6, 0xEFCF, 0x61D8, 0xEFC7, 0x61DE, 0xECE7, 0x61DF, 0xEFC8, + 0x61E0, 0xECE3, 0x61E3, 0xC256, 0x61E4, 0xECE5, 0x61E5, 0xECE4, 0x61E6, 0xC0B6, 0x61E7, 0xECE2, 0x61E8, 0xECE6, 0x61E9, 0xEFD0, + 0x61EA, 0xEFCC, 0x61EB, 0xEFCE, 0x61ED, 0xEFC9, 0x61EE, 0xEFCA, 0x61F0, 0xEFCD, 0x61F1, 0xEFCB, 0x61F2, 0xC367, 0x61F5, 0xC36A, + 0x61F6, 0xC369, 0x61F7, 0xC368, 0x61F8, 0xC461, 0x61F9, 0xF44A, 0x61FA, 0xC462, 0x61FB, 0xF241, 0x61FC, 0xC4DF, 0x61FD, 0xF5CC, + 0x61FE, 0xC4E0, 0x61FF, 0xC574, 0x6200, 0xC5CA, 0x6201, 0xF7D9, 0x6203, 0xF7DA, 0x6204, 0xF7DB, 0x6207, 0xF9BA, 0x6208, 0xA4E0, + 0x6209, 0xC97C, 0x620A, 0xA5B3, 0x620C, 0xA6A6, 0x620D, 0xA6A7, 0x620E, 0xA6A5, 0x6210, 0xA6A8, 0x6211, 0xA7DA, 0x6212, 0xA7D9, + 0x6214, 0xCCB1, 0x6215, 0xA9CF, 0x6216, 0xA9CE, 0x6219, 0xD1AF, 0x621A, 0xB1AD, 0x621B, 0xB1AE, 0x621F, 0xB475, 0x6220, 0xDD72, + 0x6221, 0xB760, 0x6222, 0xB761, 0x6223, 0xDD74, 0x6224, 0xDD76, 0x6225, 0xDD75, 0x6227, 0xE1D7, 0x6229, 0xE1D6, 0x622A, 0xBA49, + 0x622B, 0xE1D8, 0x622D, 0xE5AC, 0x622E, 0xBCAE, 0x6230, 0xBED4, 0x6232, 0xC0B8, 0x6233, 0xC257, 0x6234, 0xC0B9, 0x6236, 0xA4E1, + 0x623A, 0xCAE6, 0x623D, 0xCCB2, 0x623E, 0xA9D1, 0x623F, 0xA9D0, 0x6240, 0xA9D2, 0x6241, 0xABF3, 0x6242, 0xCED2, 0x6243, 0xCED3, + 0x6246, 0xD1B0, 0x6247, 0xAEB0, 0x6248, 0xB1AF, 0x6249, 0xB476, 0x624A, 0xD951, 0x624B, 0xA4E2, 0x624D, 0xA47E, 0x624E, 0xA4E3, + 0x6250, 0xC97D, 0x6251, 0xA5B7, 0x6252, 0xA5B6, 0x6253, 0xA5B4, 0x6254, 0xA5B5, 0x6258, 0xA6AB, 0x6259, 0xC9E9, 0x625A, 0xC9EB, + 0x625B, 0xA6AA, 0x625C, 0xC9E3, 0x625E, 0xC9E4, 0x6260, 0xC9EA, 0x6261, 0xC9E6, 0x6262, 0xC9E8, 0x6263, 0xA6A9, 0x6264, 0xC9E5, + 0x6265, 0xC9EC, 0x6266, 0xC9E7, 0x626D, 0xA7E1, 0x626E, 0xA7EA, 0x626F, 0xA7E8, 0x6270, 0xCAF0, 0x6271, 0xCAED, 0x6272, 0xCAF5, + 0x6273, 0xA7E6, 0x6274, 0xCAF6, 0x6276, 0xA7DF, 0x6277, 0xCAF3, 0x6279, 0xA7E5, 0x627A, 0xCAEF, 0x627B, 0xCAEE, 0x627C, 0xA7E3, + 0x627D, 0xCAF4, 0x627E, 0xA7E4, 0x627F, 0xA9D3, 0x6280, 0xA7DE, 0x6281, 0xCAF1, 0x6283, 0xCAE7, 0x6284, 0xA7DB, 0x6286, 0xA7EE, + 0x6287, 0xCAEC, 0x6288, 0xCAF2, 0x6289, 0xA7E0, 0x628A, 0xA7E2, 0x628C, 0xCAE8, 0x628E, 0xCAE9, 0x628F, 0xCAEA, 0x6291, 0xA7ED, + 0x6292, 0xA7E7, 0x6293, 0xA7EC, 0x6294, 0xCAEB, 0x6295, 0xA7EB, 0x6296, 0xA7DD, 0x6297, 0xA7DC, 0x6298, 0xA7E9, 0x62A8, 0xA9E1, + 0x62A9, 0xCCBE, 0x62AA, 0xCCB7, 0x62AB, 0xA9DC, 0x62AC, 0xA9EF, 0x62AD, 0xCCB3, 0x62AE, 0xCCBA, 0x62AF, 0xCCBC, 0x62B0, 0xCCBF, + 0x62B1, 0xA9EA, 0x62B3, 0xCCBB, 0x62B4, 0xCCB4, 0x62B5, 0xA9E8, 0x62B6, 0xCCB8, 0x62B8, 0xCCC0, 0x62B9, 0xA9D9, 0x62BB, 0xCCBD, + 0x62BC, 0xA9E3, 0x62BD, 0xA9E2, 0x62BE, 0xCCB6, 0x62BF, 0xA9D7, 0x62C2, 0xA9D8, 0x62C4, 0xA9D6, 0x62C6, 0xA9EE, 0x62C7, 0xA9E6, + 0x62C8, 0xA9E0, 0x62C9, 0xA9D4, 0x62CA, 0xCCB9, 0x62CB, 0xA9DF, 0x62CC, 0xA9D5, 0x62CD, 0xA9E7, 0x62CE, 0xA9F0, 0x62CF, 0xCED4, + 0x62D0, 0xA9E4, 0x62D1, 0xCCB5, 0x62D2, 0xA9DA, 0x62D3, 0xA9DD, 0x62D4, 0xA9DE, 0x62D6, 0xA9EC, 0x62D7, 0xA9ED, 0x62D8, 0xA9EB, + 0x62D9, 0xA9E5, 0x62DA, 0xA9E9, 0x62DB, 0xA9DB, 0x62DC, 0xABF4, 0x62EB, 0xCEDA, 0x62EC, 0xAC41, 0x62ED, 0xABF8, 0x62EE, 0xABFA, + 0x62EF, 0xAC40, 0x62F0, 0xCEE6, 0x62F1, 0xABFD, 0x62F2, 0xD1B1, 0x62F3, 0xAEB1, 0x62F4, 0xAC43, 0x62F5, 0xCED7, 0x62F6, 0xCEDF, + 0x62F7, 0xABFE, 0x62F8, 0xCEDE, 0x62F9, 0xCEDB, 0x62FA, 0xCEE3, 0x62FB, 0xCEE5, 0x62FC, 0xABF7, 0x62FD, 0xABFB, 0x62FE, 0xAC42, + 0x62FF, 0xAEB3, 0x6300, 0xCEE0, 0x6301, 0xABF9, 0x6302, 0xAC45, 0x6303, 0xCED9, 0x6307, 0xABFC, 0x6308, 0xAEB2, 0x6309, 0xABF6, + 0x630B, 0xCED6, 0x630C, 0xCEDD, 0x630D, 0xCED5, 0x630E, 0xCED8, 0x630F, 0xCEDC, 0x6310, 0xD1B2, 0x6311, 0xAC44, 0x6313, 0xCEE1, + 0x6314, 0xCEE2, 0x6315, 0xCEE4, 0x6316, 0xABF5, 0x6328, 0xAEC1, 0x6329, 0xD1BE, 0x632A, 0xAEBF, 0x632B, 0xAEC0, 0x632C, 0xD1B4, + 0x632D, 0xD1C4, 0x632F, 0xAEB6, 0x6332, 0xD566, 0x6333, 0xD1C6, 0x6334, 0xD1C0, 0x6336, 0xD1B7, 0x6338, 0xD1C9, 0x6339, 0xD1BA, + 0x633A, 0xAEBC, 0x633B, 0xD57D, 0x633C, 0xD1BD, 0x633D, 0xAEBE, 0x633E, 0xAEB5, 0x6340, 0xD1CB, 0x6341, 0xD1BF, 0x6342, 0xAEB8, + 0x6343, 0xD1B8, 0x6344, 0xD1B5, 0x6345, 0xD1B6, 0x6346, 0xAEB9, 0x6347, 0xD1C5, 0x6348, 0xD1CC, 0x6349, 0xAEBB, 0x634A, 0xD1BC, + 0x634B, 0xD1BB, 0x634C, 0xAEC3, 0x634D, 0xAEC2, 0x634E, 0xAEB4, 0x634F, 0xAEBA, 0x6350, 0xAEBD, 0x6351, 0xD1C8, 0x6354, 0xD1C2, + 0x6355, 0xAEB7, 0x6356, 0xD1B3, 0x6357, 0xD1CA, 0x6358, 0xD1C1, 0x6359, 0xD1C3, 0x635A, 0xD1C7, 0x6365, 0xD567, 0x6367, 0xB1B7, + 0x6368, 0xB1CB, 0x6369, 0xB1CA, 0x636B, 0xB1BF, 0x636D, 0xD579, 0x636E, 0xD575, 0x636F, 0xD572, 0x6370, 0xD5A6, 0x6371, 0xB1BA, + 0x6372, 0xB1B2, 0x6375, 0xD577, 0x6376, 0xB4A8, 0x6377, 0xB1B6, 0x6378, 0xD5A1, 0x637A, 0xB1CC, 0x637B, 0xB1C9, 0x637C, 0xD57B, + 0x637D, 0xD56A, 0x6380, 0xB1C8, 0x6381, 0xD5A3, 0x6382, 0xD569, 0x6383, 0xB1BD, 0x6384, 0xB1C1, 0x6385, 0xD5A2, 0x6387, 0xD573, + 0x6388, 0xB1C2, 0x6389, 0xB1BC, 0x638A, 0xD568, 0x638C, 0xB478, 0x638D, 0xD5A5, 0x638E, 0xD571, 0x638F, 0xB1C7, 0x6390, 0xD574, + 0x6391, 0xD5A4, 0x6392, 0xB1C6, 0x6394, 0xD952, 0x6396, 0xB1B3, 0x6397, 0xD56F, 0x6398, 0xB1B8, 0x6399, 0xB1C3, 0x639B, 0xB1BE, + 0x639C, 0xD578, 0x639D, 0xD56E, 0x639E, 0xD56C, 0x639F, 0xD57E, 0x63A0, 0xB1B0, 0x63A1, 0xB1C4, 0x63A2, 0xB1B4, 0x63A3, 0xB477, + 0x63A4, 0xD57C, 0x63A5, 0xB1B5, 0x63A7, 0xB1B1, 0x63A8, 0xB1C0, 0x63A9, 0xB1BB, 0x63AA, 0xB1B9, 0x63AB, 0xD570, 0x63AC, 0xB1C5, + 0x63AD, 0xD56D, 0x63AE, 0xD57A, 0x63AF, 0xD576, 0x63B0, 0xD954, 0x63B1, 0xD953, 0x63BD, 0xD56B, 0x63BE, 0xD964, 0x63C0, 0xB47A, + 0x63C2, 0xD96A, 0x63C3, 0xD959, 0x63C4, 0xD967, 0x63C5, 0xDD77, 0x63C6, 0xB47D, 0x63C7, 0xD96B, 0x63C8, 0xD96E, 0x63C9, 0xB47C, + 0x63CA, 0xD95C, 0x63CB, 0xD96D, 0x63CC, 0xD96C, 0x63CD, 0xB47E, 0x63CE, 0xD955, 0x63CF, 0xB479, 0x63D0, 0xB4A3, 0x63D2, 0xB4A1, + 0x63D3, 0xD969, 0x63D5, 0xD95F, 0x63D6, 0xB4A5, 0x63D7, 0xD970, 0x63D8, 0xD968, 0x63D9, 0xD971, 0x63DA, 0xB4AD, 0x63DB, 0xB4AB, + 0x63DC, 0xD966, 0x63DD, 0xD965, 0x63DF, 0xD963, 0x63E0, 0xD95D, 0x63E1, 0xB4A4, 0x63E3, 0xB4A2, 0x63E4, 0xD1B9, 0x63E5, 0xD956, + 0x63E7, 0xDDB7, 0x63E8, 0xD957, 0x63E9, 0xB47B, 0x63EA, 0xB4AA, 0x63EB, 0xDD79, 0x63ED, 0xB4A6, 0x63EE, 0xB4A7, 0x63EF, 0xD958, + 0x63F0, 0xD96F, 0x63F1, 0xDD78, 0x63F2, 0xD960, 0x63F3, 0xD95B, 0x63F4, 0xB4A9, 0x63F5, 0xD961, 0x63F6, 0xD95E, 0x63F9, 0xB4AE, + 0x6406, 0xB770, 0x6409, 0xDD7C, 0x640A, 0xDDB1, 0x640B, 0xDDB6, 0x640C, 0xDDAA, 0x640D, 0xB76C, 0x640E, 0xDDBB, 0x640F, 0xB769, + 0x6410, 0xDD7A, 0x6412, 0xDD7B, 0x6413, 0xB762, 0x6414, 0xB76B, 0x6415, 0xDDA4, 0x6416, 0xB76E, 0x6417, 0xB76F, 0x6418, 0xDDA5, + 0x641A, 0xDDB2, 0x641B, 0xDDB8, 0x641C, 0xB76A, 0x641E, 0xB764, 0x641F, 0xDDA3, 0x6420, 0xDD7D, 0x6421, 0xDDBA, 0x6422, 0xDDA8, + 0x6423, 0xDDA9, 0x6424, 0xDD7E, 0x6425, 0xDDB4, 0x6426, 0xDDAB, 0x6427, 0xDDB5, 0x6428, 0xDDAD, 0x642A, 0xB765, 0x642B, 0xE1D9, + 0x642C, 0xB768, 0x642D, 0xB766, 0x642E, 0xDDB9, 0x642F, 0xDDB0, 0x6430, 0xDDAC, 0x6433, 0xDDA1, 0x6434, 0xBA53, 0x6435, 0xDDAF, + 0x6436, 0xB76D, 0x6437, 0xDDA7, 0x6439, 0xDDA6, 0x643D, 0xB767, 0x643E, 0xB763, 0x643F, 0xE1EE, 0x6440, 0xDDB3, 0x6441, 0xDDAE, + 0x6443, 0xDDA2, 0x644B, 0xE1E9, 0x644D, 0xE1DA, 0x644E, 0xE1E5, 0x6450, 0xE1EC, 0x6451, 0xBA51, 0x6452, 0xB4AC, 0x6453, 0xE1EA, + 0x6454, 0xBA4C, 0x6458, 0xBA4B, 0x6459, 0xE1F1, 0x645B, 0xE1DB, 0x645C, 0xE1E8, 0x645D, 0xE1DC, 0x645E, 0xE1E7, 0x645F, 0xBA4F, + 0x6460, 0xE1EB, 0x6461, 0xD962, 0x6465, 0xE1F2, 0x6466, 0xE1E3, 0x6467, 0xBA52, 0x6468, 0xE5BA, 0x6469, 0xBCAF, 0x646B, 0xE1F0, + 0x646C, 0xE1EF, 0x646D, 0xBA54, 0x646E, 0xE5AD, 0x646F, 0xBCB0, 0x6470, 0xE5AE, 0x6472, 0xE1DF, 0x6473, 0xE1E0, 0x6474, 0xE1DD, + 0x6475, 0xE1E2, 0x6476, 0xE1DE, 0x6477, 0xE1F3, 0x6478, 0xBA4E, 0x6479, 0xBCB1, 0x647A, 0xBA50, 0x647B, 0xBA55, 0x647D, 0xE1E1, + 0x647F, 0xE1ED, 0x6482, 0xE1E6, 0x6485, 0xE5B1, 0x6487, 0xBA4A, 0x6488, 0xBCB4, 0x6489, 0xE9AA, 0x648A, 0xE5B6, 0x648B, 0xE5B5, + 0x648C, 0xE5B7, 0x648F, 0xE5B4, 0x6490, 0xBCB5, 0x6492, 0xBCBB, 0x6493, 0xBCB8, 0x6495, 0xBCB9, 0x6496, 0xE5AF, 0x6497, 0xE5B2, + 0x6498, 0xE5BC, 0x6499, 0xBCC1, 0x649A, 0xBCBF, 0x649C, 0xE5B3, 0x649D, 0xD95A, 0x649E, 0xBCB2, 0x649F, 0xE5B9, 0x64A0, 0xE5B0, + 0x64A2, 0xBCC2, 0x64A3, 0xE5B8, 0x64A4, 0xBA4D, 0x64A5, 0xBCB7, 0x64A6, 0xE1E4, 0x64A9, 0xBCBA, 0x64AB, 0xBCBE, 0x64AC, 0xBCC0, + 0x64AD, 0xBCBD, 0x64AE, 0xBCBC, 0x64B0, 0xBCB6, 0x64B1, 0xE5BB, 0x64B2, 0xBCB3, 0x64B3, 0xBCC3, 0x64BB, 0xBED8, 0x64BC, 0xBED9, + 0x64BD, 0xE9A9, 0x64BE, 0xBEE2, 0x64BF, 0xBEDF, 0x64C1, 0xBED6, 0x64C2, 0xBEDD, 0x64C3, 0xE9AB, 0x64C4, 0xBEDB, 0x64C5, 0xBED5, + 0x64C7, 0xBEDC, 0x64C9, 0xE9A8, 0x64CA, 0xC0BB, 0x64CB, 0xBED7, 0x64CD, 0xBEDE, 0x64CE, 0xC0BA, 0x64CF, 0xE9A7, 0x64D0, 0xE9A6, + 0x64D2, 0xBEE0, 0x64D4, 0xBEE1, 0x64D6, 0xE9A5, 0x64D7, 0xE9A4, 0x64D8, 0xC0BC, 0x64D9, 0xE9AE, 0x64DA, 0xBEDA, 0x64DB, 0xE9AC, + 0x64E0, 0xC0BD, 0x64E2, 0xC0C2, 0x64E3, 0xECEA, 0x64E4, 0xECEC, 0x64E6, 0xC0BF, 0x64E8, 0xECED, 0x64E9, 0xECE9, 0x64EB, 0xECEB, + 0x64EC, 0xC0C0, 0x64ED, 0xC0C3, 0x64EF, 0xECE8, 0x64F0, 0xC0BE, 0x64F1, 0xC0C1, 0x64F2, 0xC259, 0x64F3, 0xE9AD, 0x64F4, 0xC258, + 0x64F7, 0xC25E, 0x64F8, 0xEFD4, 0x64FA, 0xC25C, 0x64FB, 0xC25D, 0x64FC, 0xEFD7, 0x64FD, 0xEFD3, 0x64FE, 0xC25A, 0x64FF, 0xEFD1, + 0x6500, 0xC36B, 0x6501, 0xEFD5, 0x6503, 0xEFD6, 0x6504, 0xEFD2, 0x6506, 0xC25B, 0x6507, 0xF242, 0x6509, 0xF245, 0x650C, 0xF246, + 0x650D, 0xF244, 0x650E, 0xF247, 0x650F, 0xC36C, 0x6510, 0xF243, 0x6513, 0xF44E, 0x6514, 0xC464, 0x6515, 0xF44D, 0x6516, 0xF44C, + 0x6517, 0xF44B, 0x6518, 0xC463, 0x6519, 0xC465, 0x651B, 0xF5CD, 0x651C, 0xC4E2, 0x651D, 0xC4E1, 0x6520, 0xF6E1, 0x6521, 0xF6E0, + 0x6522, 0xF6E3, 0x6523, 0xC5CB, 0x6524, 0xC575, 0x6525, 0xF7DD, 0x6526, 0xF6E2, 0x6529, 0xF7DC, 0x652A, 0xC5CD, 0x652B, 0xC5CC, + 0x652C, 0xC5F3, 0x652D, 0xF8A9, 0x652E, 0xF8EF, 0x652F, 0xA4E4, 0x6532, 0xD972, 0x6533, 0xE9AF, 0x6536, 0xA6AC, 0x6537, 0xCAF7, + 0x6538, 0xA7F1, 0x6539, 0xA7EF, 0x653B, 0xA7F0, 0x653D, 0xCCC1, 0x653E, 0xA9F1, 0x653F, 0xAC46, 0x6541, 0xCEE7, 0x6543, 0xCEE8, + 0x6545, 0xAC47, 0x6546, 0xD1CE, 0x6548, 0xAEC4, 0x6549, 0xAEC5, 0x654A, 0xD1CD, 0x654F, 0xB1D3, 0x6551, 0xB1CF, 0x6553, 0xD5A7, + 0x6554, 0xB1D6, 0x6555, 0xB1D5, 0x6556, 0xB1CE, 0x6557, 0xB1D1, 0x6558, 0xB1D4, 0x6559, 0xB1D0, 0x655C, 0xD976, 0x655D, 0xB1CD, + 0x655E, 0xB4AF, 0x6562, 0xB4B1, 0x6563, 0xB4B2, 0x6564, 0xD975, 0x6565, 0xD978, 0x6566, 0xB4B0, 0x6567, 0xD973, 0x6568, 0xD977, + 0x656A, 0xD974, 0x656C, 0xB771, 0x656F, 0xDDBC, 0x6572, 0xBA56, 0x6573, 0xE1F4, 0x6574, 0xBEE3, 0x6575, 0xBCC4, 0x6576, 0xE5BD, + 0x6577, 0xBCC5, 0x6578, 0xBCC6, 0x6579, 0xE5BF, 0x657A, 0xE5BE, 0x657B, 0xE5C0, 0x657C, 0xE9B1, 0x657F, 0xE9B0, 0x6580, 0xECEF, + 0x6581, 0xECEE, 0x6582, 0xC0C4, 0x6583, 0xC0C5, 0x6584, 0xF248, 0x6587, 0xA4E5, 0x658C, 0xD979, 0x6590, 0xB4B4, 0x6591, 0xB4B3, + 0x6592, 0xDDBD, 0x6594, 0xEFD8, 0x6595, 0xC4E3, 0x6596, 0xF7DE, 0x6597, 0xA4E6, 0x6599, 0xAEC6, 0x659B, 0xB1D8, 0x659C, 0xB1D7, + 0x659D, 0xD97A, 0x659E, 0xD97B, 0x659F, 0xB772, 0x65A0, 0xE1F5, 0x65A1, 0xBA57, 0x65A2, 0xE9B2, 0x65A4, 0xA4E7, 0x65A5, 0xA5B8, + 0x65A7, 0xA9F2, 0x65A8, 0xCCC2, 0x65AA, 0xCEE9, 0x65AB, 0xAC48, 0x65AC, 0xB1D9, 0x65AE, 0xD97C, 0x65AF, 0xB4B5, 0x65B0, 0xB773, + 0x65B2, 0xE5C1, 0x65B3, 0xE5C2, 0x65B6, 0xECF0, 0x65B7, 0xC25F, 0x65B8, 0xF8F0, 0x65B9, 0xA4E8, 0x65BB, 0xCCC3, 0x65BC, 0xA9F3, + 0x65BD, 0xAC49, 0x65BF, 0xCEEA, 0x65C1, 0xAEC7, 0x65C2, 0xD1D2, 0x65C3, 0xD1D0, 0x65C4, 0xD1D1, 0x65C5, 0xAEC8, 0x65C6, 0xD1CF, + 0x65CB, 0xB1DB, 0x65CC, 0xB1DC, 0x65CD, 0xD5A8, 0x65CE, 0xB1DD, 0x65CF, 0xB1DA, 0x65D0, 0xD97D, 0x65D2, 0xD97E, 0x65D3, 0xDDBE, + 0x65D6, 0xBA59, 0x65D7, 0xBA58, 0x65DA, 0xECF1, 0x65DB, 0xEFD9, 0x65DD, 0xF24A, 0x65DE, 0xF249, 0x65DF, 0xF44F, 0x65E1, 0xC95E, + 0x65E2, 0xAC4A, 0x65E5, 0xA4E9, 0x65E6, 0xA5B9, 0x65E8, 0xA6AE, 0x65E9, 0xA6AD, 0x65EC, 0xA6AF, 0x65ED, 0xA6B0, 0x65EE, 0xC9EE, + 0x65EF, 0xC9ED, 0x65F0, 0xCAF8, 0x65F1, 0xA7F2, 0x65F2, 0xCAFB, 0x65F3, 0xCAFA, 0x65F4, 0xCAF9, 0x65F5, 0xCAFC, 0x65FA, 0xA9F4, + 0x65FB, 0xCCC9, 0x65FC, 0xCCC5, 0x65FD, 0xCCCE, 0x6600, 0xA9FB, 0x6602, 0xA9F9, 0x6603, 0xCCCA, 0x6604, 0xCCC6, 0x6605, 0xCCCD, + 0x6606, 0xA9F8, 0x6607, 0xAA40, 0x6608, 0xCCC8, 0x6609, 0xCCC4, 0x660A, 0xA9FE, 0x660B, 0xCCCB, 0x660C, 0xA9F7, 0x660D, 0xCCCC, + 0x660E, 0xA9FA, 0x660F, 0xA9FC, 0x6610, 0xCCD0, 0x6611, 0xCCCF, 0x6612, 0xCCC7, 0x6613, 0xA9F6, 0x6614, 0xA9F5, 0x6615, 0xA9FD, + 0x661C, 0xCEEF, 0x661D, 0xCEF5, 0x661F, 0xAC50, 0x6620, 0xAC4D, 0x6621, 0xCEEC, 0x6622, 0xCEF1, 0x6624, 0xAC53, 0x6625, 0xAC4B, + 0x6626, 0xCEF0, 0x6627, 0xAC4E, 0x6628, 0xAC51, 0x662B, 0xCEF3, 0x662D, 0xAC4C, 0x662E, 0xCEF8, 0x662F, 0xAC4F, 0x6631, 0xAC52, + 0x6632, 0xCEED, 0x6633, 0xCEF2, 0x6634, 0xCEF6, 0x6635, 0xCEEE, 0x6636, 0xCEEB, 0x6639, 0xCEF7, 0x663A, 0xCEF4, 0x6641, 0xAED0, + 0x6642, 0xAEC9, 0x6643, 0xAECC, 0x6645, 0xAECF, 0x6647, 0xD1D5, 0x6649, 0xAECA, 0x664A, 0xD1D3, 0x664C, 0xAECE, 0x664F, 0xAECB, + 0x6651, 0xD1D6, 0x6652, 0xAECD, 0x6659, 0xD5AC, 0x665A, 0xB1DF, 0x665B, 0xD5AB, 0x665C, 0xD5AD, 0x665D, 0xB1DE, 0x665E, 0xB1E3, + 0x665F, 0xD1D4, 0x6661, 0xD5AA, 0x6662, 0xD5AE, 0x6664, 0xB1E0, 0x6665, 0xD5A9, 0x6666, 0xB1E2, 0x6668, 0xB1E1, 0x666A, 0xD9A7, + 0x666C, 0xD9A2, 0x666E, 0xB4B6, 0x666F, 0xB4BA, 0x6670, 0xB4B7, 0x6671, 0xD9A5, 0x6672, 0xD9A8, 0x6674, 0xB4B8, 0x6676, 0xB4B9, + 0x6677, 0xB4BE, 0x6678, 0xDDC7, 0x6679, 0xD9A6, 0x667A, 0xB4BC, 0x667B, 0xD9A3, 0x667C, 0xD9A1, 0x667E, 0xB4BD, 0x6680, 0xD9A4, + 0x6684, 0xB779, 0x6686, 0xDDBF, 0x6687, 0xB776, 0x6688, 0xB777, 0x6689, 0xB775, 0x668A, 0xDDC4, 0x668B, 0xDDC3, 0x668C, 0xDDC0, + 0x668D, 0xB77B, 0x6690, 0xDDC2, 0x6691, 0xB4BB, 0x6694, 0xDDC6, 0x6695, 0xDDC1, 0x6696, 0xB778, 0x6697, 0xB774, 0x6698, 0xB77A, + 0x6699, 0xDDC5, 0x669D, 0xBA5C, 0x669F, 0xE1F8, 0x66A0, 0xE1F7, 0x66A1, 0xE1F6, 0x66A2, 0xBA5A, 0x66A8, 0xBA5B, 0x66A9, 0xE5C5, + 0x66AA, 0xE5C8, 0x66AB, 0xBCC8, 0x66AE, 0xBCC7, 0x66AF, 0xE5C9, 0x66B0, 0xE5C4, 0x66B1, 0xBCCA, 0x66B2, 0xE5C6, 0x66B4, 0xBCC9, + 0x66B5, 0xE5C3, 0x66B7, 0xE5C7, 0x66B8, 0xBEE9, 0x66B9, 0xBEE6, 0x66BA, 0xE9BB, 0x66BB, 0xE9BA, 0x66BD, 0xE9B9, 0x66BE, 0xE9B4, + 0x66C0, 0xE9B5, 0x66C4, 0xBEE7, 0x66C6, 0xBEE4, 0x66C7, 0xBEE8, 0x66C8, 0xE9B3, 0x66C9, 0xBEE5, 0x66CA, 0xE9B6, 0x66CB, 0xE9B7, + 0x66CC, 0xE9BC, 0x66CF, 0xE9B8, 0x66D2, 0xECF2, 0x66D6, 0xC0C7, 0x66D8, 0xEFDC, 0x66D9, 0xC0C6, 0x66DA, 0xEFDA, 0x66DB, 0xEFDB, + 0x66DC, 0xC260, 0x66DD, 0xC36E, 0x66DE, 0xF24B, 0x66E0, 0xC36D, 0x66E3, 0xF451, 0x66E4, 0xF452, 0x66E6, 0xC466, 0x66E8, 0xF450, + 0x66E9, 0xC4E4, 0x66EB, 0xF7DF, 0x66EC, 0xC5CE, 0x66ED, 0xF8AA, 0x66EE, 0xF8AB, 0x66F0, 0xA4EA, 0x66F2, 0xA6B1, 0x66F3, 0xA6B2, + 0x66F4, 0xA7F3, 0x66F6, 0xCCD1, 0x66F7, 0xAC54, 0x66F8, 0xAED1, 0x66F9, 0xB1E4, 0x66FC, 0xB0D2, 0x66FE, 0xB4BF, 0x66FF, 0xB4C0, + 0x6700, 0xB3CC, 0x6701, 0xD9A9, 0x6703, 0xB77C, 0x6704, 0xE1FA, 0x6705, 0xE1F9, 0x6708, 0xA4EB, 0x6709, 0xA6B3, 0x670A, 0xCCD2, + 0x670B, 0xAA42, 0x670D, 0xAA41, 0x670F, 0xCEF9, 0x6710, 0xCEFA, 0x6712, 0xD1D7, 0x6713, 0xD1D8, 0x6714, 0xAED2, 0x6715, 0xAED3, + 0x6717, 0xAED4, 0x6718, 0xD5AF, 0x671B, 0xB1E6, 0x671D, 0xB4C2, 0x671F, 0xB4C1, 0x6720, 0xDDC8, 0x6721, 0xDF7A, 0x6722, 0xE1FB, + 0x6723, 0xE9BD, 0x6726, 0xC261, 0x6727, 0xC467, 0x6728, 0xA4EC, 0x672A, 0xA5BC, 0x672B, 0xA5BD, 0x672C, 0xA5BB, 0x672D, 0xA5BE, + 0x672E, 0xA5BA, 0x6731, 0xA6B6, 0x6733, 0xC9F6, 0x6734, 0xA6B5, 0x6735, 0xA6B7, 0x6738, 0xC9F1, 0x6739, 0xC9F0, 0x673A, 0xC9F3, + 0x673B, 0xC9F2, 0x673C, 0xC9F5, 0x673D, 0xA6B4, 0x673E, 0xC9EF, 0x673F, 0xC9F4, 0x6745, 0xCAFD, 0x6746, 0xA7FD, 0x6747, 0xCAFE, + 0x6748, 0xCB43, 0x6749, 0xA7FC, 0x674B, 0xCB47, 0x674C, 0xCB42, 0x674D, 0xCB45, 0x674E, 0xA7F5, 0x674F, 0xA7F6, 0x6750, 0xA7F7, + 0x6751, 0xA7F8, 0x6753, 0xA840, 0x6755, 0xCB41, 0x6756, 0xA7FA, 0x6757, 0xA841, 0x6759, 0xCB40, 0x675A, 0xCB46, 0x675C, 0xA7F9, + 0x675D, 0xCB44, 0x675E, 0xA7FB, 0x675F, 0xA7F4, 0x6760, 0xA7FE, 0x676A, 0xAA57, 0x676C, 0xCCD4, 0x676D, 0xAA43, 0x676F, 0xAA4D, + 0x6770, 0xAA4E, 0x6771, 0xAA46, 0x6772, 0xAA58, 0x6773, 0xAA48, 0x6774, 0xCCDC, 0x6775, 0xAA53, 0x6776, 0xCCD7, 0x6777, 0xAA49, + 0x6778, 0xCCE6, 0x6779, 0xCCE7, 0x677A, 0xCCDF, 0x677B, 0xCCD8, 0x677C, 0xAA56, 0x677D, 0xCCE4, 0x677E, 0xAA51, 0x677F, 0xAA4F, + 0x6781, 0xCCE5, 0x6783, 0xCCE3, 0x6784, 0xCCDB, 0x6785, 0xCCD3, 0x6786, 0xCCDA, 0x6787, 0xAA4A, 0x6789, 0xAA50, 0x678B, 0xAA44, + 0x678C, 0xCCDE, 0x678D, 0xCCDD, 0x678E, 0xCCD5, 0x6790, 0xAA52, 0x6791, 0xCCE1, 0x6792, 0xCCD6, 0x6793, 0xAA55, 0x6794, 0xCCE8, + 0x6795, 0xAA45, 0x6797, 0xAA4C, 0x6798, 0xCCD9, 0x6799, 0xCCE2, 0x679A, 0xAA54, 0x679C, 0xAA47, 0x679D, 0xAA4B, 0x679F, 0xCCE0, + 0x67AE, 0xCF5B, 0x67AF, 0xAC5C, 0x67B0, 0xAC69, 0x67B2, 0xCF56, 0x67B3, 0xCF4C, 0x67B4, 0xAC62, 0x67B5, 0xCF4A, 0x67B6, 0xAC5B, + 0x67B7, 0xCF45, 0x67B8, 0xAC65, 0x67B9, 0xCF52, 0x67BA, 0xCEFE, 0x67BB, 0xCF41, 0x67C0, 0xCF44, 0x67C1, 0xCEFB, 0x67C2, 0xCF51, + 0x67C3, 0xCF61, 0x67C4, 0xAC60, 0x67C5, 0xCF46, 0x67C6, 0xCF58, 0x67C8, 0xCEFD, 0x67C9, 0xCF5F, 0x67CA, 0xCF60, 0x67CB, 0xCF63, + 0x67CC, 0xCF5A, 0x67CD, 0xCF4B, 0x67CE, 0xCF53, 0x67CF, 0xAC66, 0x67D0, 0xAC59, 0x67D1, 0xAC61, 0x67D2, 0xAC6D, 0x67D3, 0xAC56, + 0x67D4, 0xAC58, 0x67D8, 0xCF43, 0x67D9, 0xAC6A, 0x67DA, 0xAC63, 0x67DB, 0xCF5D, 0x67DC, 0xCF40, 0x67DD, 0xAC6C, 0x67DE, 0xAC67, + 0x67DF, 0xCF49, 0x67E2, 0xAC6B, 0x67E3, 0xCF50, 0x67E4, 0xCF48, 0x67E5, 0xAC64, 0x67E6, 0xCF5C, 0x67E7, 0xCF54, 0x67E9, 0xAC5E, + 0x67EA, 0xCF62, 0x67EB, 0xCF47, 0x67EC, 0xAC5A, 0x67ED, 0xCF59, 0x67EE, 0xCF4F, 0x67EF, 0xAC5F, 0x67F0, 0xCF55, 0x67F1, 0xAC57, + 0x67F2, 0xCEFC, 0x67F3, 0xAC68, 0x67F4, 0xAEE3, 0x67F5, 0xAC5D, 0x67F6, 0xCF4E, 0x67F7, 0xCF4D, 0x67F8, 0xCF42, 0x67FA, 0xCF5E, + 0x67FC, 0xCF57, 0x67FF, 0xAC55, 0x6812, 0xD1EC, 0x6813, 0xAEEA, 0x6814, 0xD1ED, 0x6816, 0xD1E1, 0x6817, 0xAEDF, 0x6818, 0xAEEB, + 0x681A, 0xD1DA, 0x681C, 0xD1E3, 0x681D, 0xD1EB, 0x681F, 0xD1D9, 0x6820, 0xD1F4, 0x6821, 0xAED5, 0x6825, 0xD1F3, 0x6826, 0xD1EE, + 0x6828, 0xD1EF, 0x6829, 0xAEDD, 0x682A, 0xAEE8, 0x682B, 0xD1E5, 0x682D, 0xD1E6, 0x682E, 0xD1F0, 0x682F, 0xD1E7, 0x6831, 0xD1E2, + 0x6832, 0xD1DC, 0x6833, 0xD1DD, 0x6834, 0xD1EA, 0x6835, 0xD1E4, 0x6838, 0xAED6, 0x6839, 0xAEDA, 0x683A, 0xD1F2, 0x683B, 0xD1DE, + 0x683C, 0xAEE6, 0x683D, 0xAEE2, 0x6840, 0xAEE5, 0x6841, 0xAEEC, 0x6842, 0xAEDB, 0x6843, 0xAEE7, 0x6844, 0xD1E9, 0x6845, 0xAEE9, + 0x6846, 0xAED8, 0x6848, 0xAED7, 0x6849, 0xD1DB, 0x684B, 0xD1DF, 0x684C, 0xAEE0, 0x684D, 0xD1F1, 0x684E, 0xD1E8, 0x684F, 0xD1E0, + 0x6850, 0xAEE4, 0x6851, 0xAEE1, 0x6853, 0xAED9, 0x6854, 0xAEDC, 0x686B, 0xD5C4, 0x686D, 0xD5B4, 0x686E, 0xD5B5, 0x686F, 0xD5B9, + 0x6871, 0xD5C8, 0x6872, 0xD5C5, 0x6874, 0xD5BE, 0x6875, 0xD5BD, 0x6876, 0xB1ED, 0x6877, 0xD5C1, 0x6878, 0xD5D0, 0x6879, 0xD5B0, + 0x687B, 0xD5D1, 0x687C, 0xD5C3, 0x687D, 0xD5D5, 0x687E, 0xD5C9, 0x687F, 0xB1EC, 0x6880, 0xD5C7, 0x6881, 0xB1E7, 0x6882, 0xB1FC, + 0x6883, 0xB1F2, 0x6885, 0xB1F6, 0x6886, 0xB1F5, 0x6887, 0xD5B1, 0x6889, 0xD5CE, 0x688A, 0xD5D4, 0x688B, 0xD5CC, 0x688C, 0xD5D3, + 0x688F, 0xD5C0, 0x6890, 0xD5B2, 0x6891, 0xD5D2, 0x6892, 0xD5C2, 0x6893, 0xB1EA, 0x6894, 0xB1F7, 0x6896, 0xD5CB, 0x6897, 0xB1F0, + 0x689B, 0xD5CA, 0x689C, 0xD5B3, 0x689D, 0xB1F8, 0x689F, 0xB1FA, 0x68A0, 0xD5CD, 0x68A1, 0xB1FB, 0x68A2, 0xB1E9, 0x68A3, 0xD5BA, + 0x68A4, 0xD5CF, 0x68A7, 0xB1EF, 0x68A8, 0xB1F9, 0x68A9, 0xD5BC, 0x68AA, 0xD5C6, 0x68AB, 0xD5B7, 0x68AC, 0xD5BB, 0x68AD, 0xB1F4, + 0x68AE, 0xD5B6, 0x68AF, 0xB1E8, 0x68B0, 0xB1F1, 0x68B1, 0xB1EE, 0x68B2, 0xD5BF, 0x68B3, 0xAEDE, 0x68B4, 0xD9C0, 0x68B5, 0xB1EB, + 0x68C4, 0xB1F3, 0x68C6, 0xD9C3, 0x68C7, 0xD9D9, 0x68C8, 0xD9CE, 0x68C9, 0xB4D6, 0x68CB, 0xB4D1, 0x68CC, 0xD9BD, 0x68CD, 0xB4D2, + 0x68CE, 0xD9CD, 0x68D0, 0xD9C6, 0x68D1, 0xD9D3, 0x68D2, 0xB4CE, 0x68D3, 0xD9AB, 0x68D4, 0xD9D5, 0x68D5, 0xB4C4, 0x68D6, 0xD9B3, + 0x68D7, 0xB4C7, 0x68D8, 0xB4C6, 0x68DA, 0xB4D7, 0x68DC, 0xD9AD, 0x68DD, 0xD9CF, 0x68DE, 0xD9D0, 0x68DF, 0xB4C9, 0x68E0, 0xB4C5, + 0x68E1, 0xD9BB, 0x68E3, 0xB4D0, 0x68E4, 0xD9B6, 0x68E6, 0xD9D1, 0x68E7, 0xB4CC, 0x68E8, 0xD9C9, 0x68E9, 0xD9D6, 0x68EA, 0xD9B0, + 0x68EB, 0xD9B5, 0x68EC, 0xD9AF, 0x68EE, 0xB4CB, 0x68EF, 0xD9C2, 0x68F0, 0xDDDE, 0x68F1, 0xD9B1, 0x68F2, 0xB4CF, 0x68F3, 0xD9BA, + 0x68F4, 0xD9D2, 0x68F5, 0xB4CA, 0x68F6, 0xD9B7, 0x68F7, 0xD9B4, 0x68F8, 0xD9C5, 0x68F9, 0xB4CD, 0x68FA, 0xB4C3, 0x68FB, 0xB4D9, + 0x68FC, 0xD9C8, 0x68FD, 0xD9C7, 0x6904, 0xD9AC, 0x6905, 0xB4C8, 0x6906, 0xD9D4, 0x6907, 0xD9BC, 0x6908, 0xD9BE, 0x690A, 0xD9CB, + 0x690B, 0xD9CA, 0x690C, 0xD9AA, 0x690D, 0xB4D3, 0x690E, 0xB4D5, 0x690F, 0xD9B2, 0x6910, 0xD9B9, 0x6911, 0xD9C1, 0x6912, 0xB4D4, + 0x6913, 0xD9B8, 0x6914, 0xD9C4, 0x6915, 0xD9D7, 0x6917, 0xD9CC, 0x6925, 0xD9D8, 0x692A, 0xD9AE, 0x692F, 0xDDF2, 0x6930, 0xB7A6, + 0x6932, 0xDDF0, 0x6933, 0xDDDB, 0x6934, 0xDDE0, 0x6935, 0xDDD9, 0x6937, 0xDDEC, 0x6938, 0xDDCB, 0x6939, 0xDDD2, 0x693B, 0xDDEA, + 0x693C, 0xDDF4, 0x693D, 0xDDDC, 0x693F, 0xDDCF, 0x6940, 0xDDE2, 0x6941, 0xDDE7, 0x6942, 0xDDD3, 0x6944, 0xDDE4, 0x6945, 0xDDD0, + 0x6948, 0xDDD7, 0x6949, 0xDDD8, 0x694A, 0xB7A8, 0x694B, 0xDDEB, 0x694C, 0xDDE9, 0x694E, 0xDDCC, 0x694F, 0xDDEE, 0x6951, 0xDDEF, + 0x6952, 0xDDF1, 0x6953, 0xB7AC, 0x6954, 0xB7A4, 0x6956, 0xD5B8, 0x6957, 0xDDD4, 0x6958, 0xDDE6, 0x6959, 0xDDD5, 0x695A, 0xB7A1, + 0x695B, 0xB7B1, 0x695C, 0xDDED, 0x695D, 0xB7AF, 0x695E, 0xB7AB, 0x695F, 0xDDCA, 0x6960, 0xB7A3, 0x6962, 0xDDCD, 0x6963, 0xB7B0, + 0x6965, 0xDDDD, 0x6966, 0xDDC9, 0x6968, 0xB7A9, 0x6969, 0xDDE1, 0x696A, 0xDDD1, 0x696B, 0xB7AA, 0x696C, 0xDDDA, 0x696D, 0xB77E, + 0x696E, 0xB4D8, 0x696F, 0xDDE3, 0x6970, 0xD9BF, 0x6971, 0xDDCE, 0x6974, 0xDDE8, 0x6975, 0xB7A5, 0x6976, 0xDDE5, 0x6977, 0xB7A2, + 0x6978, 0xDDDF, 0x6979, 0xB7AD, 0x697A, 0xDDD6, 0x697B, 0xDDF3, 0x6982, 0xB7A7, 0x6983, 0xDEC6, 0x6986, 0xB7AE, 0x698D, 0xE24A, + 0x698E, 0xE248, 0x6990, 0xE25E, 0x6991, 0xE246, 0x6993, 0xE258, 0x6994, 0xB77D, 0x6995, 0xBA5F, 0x6996, 0xE242, 0x6997, 0xE25D, + 0x6999, 0xE247, 0x699A, 0xE255, 0x699B, 0xBA64, 0x699C, 0xBA5D, 0x699E, 0xE25B, 0x69A0, 0xE240, 0x69A1, 0xE25A, 0x69A3, 0xBA6F, + 0x69A4, 0xE251, 0x69A5, 0xE261, 0x69A6, 0xBA6D, 0x69A7, 0xE249, 0x69A8, 0xBA5E, 0x69A9, 0xE24B, 0x69AA, 0xE259, 0x69AB, 0xBA67, + 0x69AC, 0xE244, 0x69AD, 0xBA6B, 0x69AE, 0xBA61, 0x69AF, 0xE24D, 0x69B0, 0xE243, 0x69B1, 0xE1FC, 0x69B3, 0xE257, 0x69B4, 0xBA68, + 0x69B5, 0xE260, 0x69B6, 0xE1FD, 0x69B7, 0xBA65, 0x69B9, 0xE253, 0x69BB, 0xBA66, 0x69BC, 0xE245, 0x69BD, 0xE250, 0x69BE, 0xE24C, + 0x69BF, 0xE24E, 0x69C1, 0xBA60, 0x69C2, 0xE25F, 0x69C3, 0xBA6E, 0x69C4, 0xE24F, 0x69C6, 0xE262, 0x69C9, 0xE1FE, 0x69CA, 0xE254, + 0x69CB, 0xBA63, 0x69CC, 0xBA6C, 0x69CD, 0xBA6A, 0x69CE, 0xE241, 0x69CF, 0xE256, 0x69D0, 0xBA69, 0x69D3, 0xBA62, 0x69D4, 0xE252, + 0x69D9, 0xE25C, 0x69E2, 0xE5D5, 0x69E4, 0xE5D1, 0x69E5, 0xE5CD, 0x69E6, 0xE5E1, 0x69E7, 0xE5DE, 0x69E8, 0xBCCD, 0x69EB, 0xE5E5, + 0x69EC, 0xE5D4, 0x69ED, 0xBCD8, 0x69EE, 0xE5DB, 0x69F1, 0xE5D0, 0x69F2, 0xE5DA, 0x69F3, 0xBCD5, 0x69F4, 0xE5EE, 0x69F6, 0xE5EB, + 0x69F7, 0xE5DD, 0x69F8, 0xE5CE, 0x69FB, 0xE5E2, 0x69FC, 0xE5E4, 0x69FD, 0xBCD1, 0x69FE, 0xE5D8, 0x69FF, 0xE5D3, 0x6A00, 0xE5CA, + 0x6A01, 0xBCCE, 0x6A02, 0xBCD6, 0x6A04, 0xE5E7, 0x6A05, 0xBCD7, 0x6A06, 0xE5CB, 0x6A07, 0xE5ED, 0x6A08, 0xE5E0, 0x6A09, 0xE5E6, + 0x6A0A, 0xBCD4, 0x6A0D, 0xE5E3, 0x6A0F, 0xE5EA, 0x6A11, 0xBCD9, 0x6A13, 0xBCD3, 0x6A14, 0xE5DC, 0x6A15, 0xE5CF, 0x6A16, 0xE5EF, + 0x6A17, 0xE5CC, 0x6A18, 0xE5E8, 0x6A19, 0xBCD0, 0x6A1B, 0xE5D6, 0x6A1D, 0xE5D7, 0x6A1E, 0xBCCF, 0x6A1F, 0xBCCC, 0x6A20, 0xE5D2, + 0x6A21, 0xBCD2, 0x6A23, 0xBCCB, 0x6A25, 0xE5E9, 0x6A26, 0xE5EC, 0x6A27, 0xE5D9, 0x6A28, 0xE9CA, 0x6A32, 0xE9C2, 0x6A34, 0xE9BE, + 0x6A35, 0xBEF6, 0x6A38, 0xBEEB, 0x6A39, 0xBEF0, 0x6A3A, 0xBEEC, 0x6A3B, 0xE9CC, 0x6A3C, 0xE9D7, 0x6A3D, 0xBEEA, 0x6A3E, 0xE9C4, + 0x6A3F, 0xE9CD, 0x6A40, 0xE5DF, 0x6A41, 0xE9CE, 0x6A44, 0xBEF1, 0x6A46, 0xE9DD, 0x6A47, 0xBEF5, 0x6A48, 0xBEF8, 0x6A49, 0xE9C0, + 0x6A4B, 0xBEF4, 0x6A4D, 0xE9DB, 0x6A4E, 0xE9DC, 0x6A4F, 0xE9D2, 0x6A50, 0xE9D1, 0x6A51, 0xE9C9, 0x6A54, 0xE9D3, 0x6A55, 0xE9DA, + 0x6A56, 0xE9D9, 0x6A58, 0xBEEF, 0x6A59, 0xBEED, 0x6A5A, 0xE9CB, 0x6A5B, 0xE9C8, 0x6A5D, 0xE9C5, 0x6A5E, 0xE9D8, 0x6A5F, 0xBEF7, + 0x6A60, 0xE9D6, 0x6A61, 0xBEF3, 0x6A62, 0xBEF2, 0x6A64, 0xE9D0, 0x6A66, 0xE9BF, 0x6A67, 0xE9C1, 0x6A68, 0xE9C3, 0x6A69, 0xE9D5, + 0x6A6A, 0xE9CF, 0x6A6B, 0xBEEE, 0x6A6D, 0xE9C6, 0x6A6F, 0xE9D4, 0x6A76, 0xE9C7, 0x6A7E, 0xC0CF, 0x6A7F, 0xED45, 0x6A80, 0xC0C8, + 0x6A81, 0xECF5, 0x6A83, 0xED41, 0x6A84, 0xC0CA, 0x6A85, 0xED48, 0x6A87, 0xECFC, 0x6A89, 0xECF7, 0x6A8C, 0xED49, 0x6A8D, 0xECF3, + 0x6A8E, 0xECFE, 0x6A90, 0xC0D1, 0x6A91, 0xED44, 0x6A92, 0xED4A, 0x6A93, 0xECFD, 0x6A94, 0xC0C9, 0x6A95, 0xED40, 0x6A96, 0xECF4, + 0x6A97, 0xC0D0, 0x6A9A, 0xED47, 0x6A9B, 0xECF9, 0x6A9C, 0xC0CC, 0x6A9E, 0xECFB, 0x6A9F, 0xECF8, 0x6AA0, 0xC0D2, 0x6AA1, 0xECFA, + 0x6AA2, 0xC0CB, 0x6AA3, 0xC0CE, 0x6AA4, 0xED43, 0x6AA5, 0xECF6, 0x6AA6, 0xED46, 0x6AA8, 0xED42, 0x6AAC, 0xC263, 0x6AAD, 0xEFE7, + 0x6AAE, 0xC268, 0x6AAF, 0xC269, 0x6AB3, 0xC262, 0x6AB4, 0xEFE6, 0x6AB6, 0xEFE3, 0x6AB7, 0xEFE4, 0x6AB8, 0xC266, 0x6AB9, 0xEFDE, + 0x6ABA, 0xEFE2, 0x6ABB, 0xC265, 0x6ABD, 0xEFDF, 0x6AC2, 0xC267, 0x6AC3, 0xC264, 0x6AC5, 0xEFDD, 0x6AC6, 0xEFE1, 0x6AC7, 0xEFE5, + 0x6ACB, 0xF251, 0x6ACC, 0xF24E, 0x6ACD, 0xF257, 0x6ACF, 0xF256, 0x6AD0, 0xF254, 0x6AD1, 0xF24F, 0x6AD3, 0xC372, 0x6AD9, 0xF250, + 0x6ADA, 0xC371, 0x6ADB, 0xC0CD, 0x6ADC, 0xF253, 0x6ADD, 0xC370, 0x6ADE, 0xF258, 0x6ADF, 0xF252, 0x6AE0, 0xF24D, 0x6AE1, 0xEFE0, + 0x6AE5, 0xC36F, 0x6AE7, 0xF24C, 0x6AE8, 0xF456, 0x6AEA, 0xF455, 0x6AEB, 0xF255, 0x6AEC, 0xC468, 0x6AEE, 0xF459, 0x6AEF, 0xF45A, + 0x6AF0, 0xF454, 0x6AF1, 0xF458, 0x6AF3, 0xF453, 0x6AF8, 0xF5D1, 0x6AF9, 0xF457, 0x6AFA, 0xC4E7, 0x6AFB, 0xC4E5, 0x6AFC, 0xF5CF, + 0x6B00, 0xF5D2, 0x6B02, 0xF5CE, 0x6B03, 0xF5D0, 0x6B04, 0xC4E6, 0x6B08, 0xF6E5, 0x6B09, 0xF6E6, 0x6B0A, 0xC576, 0x6B0B, 0xF6E4, + 0x6B0F, 0xF7E2, 0x6B10, 0xC5CF, 0x6B11, 0xF7E0, 0x6B12, 0xF7E1, 0x6B13, 0xF8AC, 0x6B16, 0xC656, 0x6B17, 0xF8F3, 0x6B18, 0xF8F1, + 0x6B19, 0xF8F2, 0x6B1A, 0xF8F4, 0x6B1E, 0xF9BB, 0x6B20, 0xA4ED, 0x6B21, 0xA6B8, 0x6B23, 0xAA59, 0x6B25, 0xCCE9, 0x6B28, 0xCF64, + 0x6B2C, 0xD1F5, 0x6B2D, 0xD1F7, 0x6B2F, 0xD1F6, 0x6B31, 0xD1F8, 0x6B32, 0xB1FD, 0x6B33, 0xD5D7, 0x6B34, 0xD1F9, 0x6B36, 0xD5D6, + 0x6B37, 0xD5D8, 0x6B38, 0xD5D9, 0x6B39, 0xD9DA, 0x6B3A, 0xB4DB, 0x6B3B, 0xD9DB, 0x6B3C, 0xD9DD, 0x6B3D, 0xB4DC, 0x6B3E, 0xB4DA, + 0x6B3F, 0xD9DC, 0x6B41, 0xDDFA, 0x6B42, 0xDDF8, 0x6B43, 0xDDF7, 0x6B45, 0xDDF6, 0x6B46, 0xDDF5, 0x6B47, 0xB7B2, 0x6B48, 0xDDF9, + 0x6B49, 0xBA70, 0x6B4A, 0xE263, 0x6B4B, 0xE265, 0x6B4C, 0xBA71, 0x6B4D, 0xE264, 0x6B4E, 0xBCDB, 0x6B50, 0xBCDA, 0x6B51, 0xE5F0, + 0x6B54, 0xE9DF, 0x6B55, 0xE9DE, 0x6B56, 0xE9E0, 0x6B59, 0xBEF9, 0x6B5B, 0xED4B, 0x6B5C, 0xC0D3, 0x6B5E, 0xEFE8, 0x6B5F, 0xC26A, + 0x6B60, 0xF259, 0x6B61, 0xC577, 0x6B62, 0xA4EE, 0x6B63, 0xA5BF, 0x6B64, 0xA6B9, 0x6B65, 0xA842, 0x6B66, 0xAA5A, 0x6B67, 0xAA5B, + 0x6B6A, 0xAC6E, 0x6B6D, 0xD1FA, 0x6B72, 0xB7B3, 0x6B76, 0xE6D1, 0x6B77, 0xBEFA, 0x6B78, 0xC26B, 0x6B79, 0xA4EF, 0x6B7B, 0xA6BA, + 0x6B7E, 0xCCEB, 0x6B7F, 0xAA5C, 0x6B80, 0xCCEA, 0x6B82, 0xCF65, 0x6B83, 0xAC6F, 0x6B84, 0xCF66, 0x6B86, 0xAC70, 0x6B88, 0xD1FC, + 0x6B89, 0xAEEE, 0x6B8A, 0xAEED, 0x6B8C, 0xD5DE, 0x6B8D, 0xD5DC, 0x6B8E, 0xD5DD, 0x6B8F, 0xD5DB, 0x6B91, 0xD5DA, 0x6B94, 0xD9DE, + 0x6B95, 0xD9E1, 0x6B96, 0xB4DE, 0x6B97, 0xD9DF, 0x6B98, 0xB4DD, 0x6B99, 0xD9E0, 0x6B9B, 0xDDFB, 0x6B9E, 0xE266, 0x6B9F, 0xE267, + 0x6BA0, 0xE268, 0x6BA2, 0xE5F3, 0x6BA3, 0xE5F2, 0x6BA4, 0xBCDC, 0x6BA5, 0xE5F1, 0x6BA6, 0xE5F4, 0x6BA7, 0xE9E1, 0x6BAA, 0xE9E2, + 0x6BAB, 0xE9E3, 0x6BAD, 0xED4C, 0x6BAE, 0xC0D4, 0x6BAF, 0xC26C, 0x6BB0, 0xF25A, 0x6BB2, 0xC4E8, 0x6BB3, 0xC95F, 0x6BB5, 0xAC71, + 0x6BB6, 0xCF67, 0x6BB7, 0xAEEF, 0x6BBA, 0xB1FE, 0x6BBC, 0xB4DF, 0x6BBD, 0xD9E2, 0x6BBF, 0xB7B5, 0x6BC0, 0xB7B4, 0x6BC3, 0xE269, + 0x6BC4, 0xE26A, 0x6BC5, 0xBCDD, 0x6BC6, 0xBCDE, 0x6BC7, 0xE9E5, 0x6BC8, 0xE9E4, 0x6BC9, 0xEFE9, 0x6BCA, 0xF7E3, 0x6BCB, 0xA4F0, + 0x6BCC, 0xC960, 0x6BCD, 0xA5C0, 0x6BCF, 0xA843, 0x6BD0, 0xCB48, 0x6BD2, 0xAC72, 0x6BD3, 0xB7B6, 0x6BD4, 0xA4F1, 0x6BD6, 0xCF68, + 0x6BD7, 0xAC73, 0x6BD8, 0xCF69, 0x6BDA, 0xC0D5, 0x6BDB, 0xA4F2, 0x6BDE, 0xCCEC, 0x6BE0, 0xCF6A, 0x6BE2, 0xD242, 0x6BE3, 0xD241, + 0x6BE4, 0xD1FE, 0x6BE6, 0xD1FD, 0x6BE7, 0xD243, 0x6BE8, 0xD240, 0x6BEB, 0xB240, 0x6BEC, 0xB241, 0x6BEF, 0xB4E0, 0x6BF0, 0xD9E3, + 0x6BF2, 0xD9E4, 0x6BF3, 0xD9E5, 0x6BF7, 0xDE41, 0x6BF8, 0xDE42, 0x6BF9, 0xDE40, 0x6BFB, 0xDDFD, 0x6BFC, 0xDDFE, 0x6BFD, 0xB7B7, + 0x6BFE, 0xE26B, 0x6BFF, 0xE5F7, 0x6C00, 0xE5F6, 0x6C01, 0xE5F5, 0x6C02, 0xE5F8, 0x6C03, 0xE9E7, 0x6C04, 0xE9E6, 0x6C05, 0xBEFB, + 0x6C06, 0xE9E8, 0x6C08, 0xC0D6, 0x6C09, 0xED4D, 0x6C0B, 0xEFEA, 0x6C0C, 0xF25B, 0x6C0D, 0xF6E7, 0x6C0F, 0xA4F3, 0x6C10, 0xA5C2, + 0x6C11, 0xA5C1, 0x6C13, 0xAA5D, 0x6C14, 0xC961, 0x6C15, 0xC97E, 0x6C16, 0xA6BB, 0x6C18, 0xC9F7, 0x6C19, 0xCB49, 0x6C1A, 0xCB4A, + 0x6C1B, 0xAA5E, 0x6C1D, 0xCCED, 0x6C1F, 0xAC74, 0x6C20, 0xCF6B, 0x6C21, 0xCF6C, 0x6C23, 0xAEF0, 0x6C24, 0xAEF4, 0x6C25, 0xD244, + 0x6C26, 0xAEF3, 0x6C27, 0xAEF1, 0x6C28, 0xAEF2, 0x6C2A, 0xD5DF, 0x6C2B, 0xB242, 0x6C2C, 0xB4E3, 0x6C2E, 0xB4E1, 0x6C2F, 0xB4E2, + 0x6C30, 0xD9E6, 0x6C33, 0xBA72, 0x6C34, 0xA4F4, 0x6C36, 0xC9A1, 0x6C38, 0xA5C3, 0x6C3B, 0xC9A4, 0x6C3E, 0xA5C6, 0x6C3F, 0xC9A3, + 0x6C40, 0xA5C5, 0x6C41, 0xA5C4, 0x6C42, 0xA844, 0x6C43, 0xC9A2, 0x6C46, 0xC9F8, 0x6C4A, 0xC9FC, 0x6C4B, 0xC9FE, 0x6C4C, 0xCA40, + 0x6C4D, 0xA6C5, 0x6C4E, 0xA6C6, 0x6C4F, 0xC9FB, 0x6C50, 0xA6C1, 0x6C52, 0xC9F9, 0x6C54, 0xC9FD, 0x6C55, 0xA6C2, 0x6C57, 0xA6BD, + 0x6C59, 0xA6BE, 0x6C5B, 0xA6C4, 0x6C5C, 0xC9FA, 0x6C5D, 0xA6BC, 0x6C5E, 0xA845, 0x6C5F, 0xA6BF, 0x6C60, 0xA6C0, 0x6C61, 0xA6C3, + 0x6C65, 0xCB5B, 0x6C66, 0xCB59, 0x6C67, 0xCB4C, 0x6C68, 0xA851, 0x6C69, 0xCB53, 0x6C6A, 0xA84C, 0x6C6B, 0xCB4D, 0x6C6D, 0xCB55, + 0x6C6F, 0xCB52, 0x6C70, 0xA84F, 0x6C71, 0xCB51, 0x6C72, 0xA856, 0x6C73, 0xCB5A, 0x6C74, 0xA858, 0x6C76, 0xA85A, 0x6C78, 0xCB4B, + 0x6C7A, 0xA84D, 0x6C7B, 0xCB5C, 0x6C7D, 0xA854, 0x6C7E, 0xA857, 0x6C80, 0xCD45, 0x6C81, 0xA847, 0x6C82, 0xA85E, 0x6C83, 0xA855, + 0x6C84, 0xCB4E, 0x6C85, 0xA84A, 0x6C86, 0xA859, 0x6C87, 0xCB56, 0x6C88, 0xA848, 0x6C89, 0xA849, 0x6C8A, 0xCD43, 0x6C8B, 0xCB4F, + 0x6C8C, 0xA850, 0x6C8D, 0xA85B, 0x6C8E, 0xCB5D, 0x6C8F, 0xCB50, 0x6C90, 0xA84E, 0x6C92, 0xA853, 0x6C93, 0xCCEE, 0x6C94, 0xA85C, + 0x6C95, 0xCB57, 0x6C96, 0xA852, 0x6C98, 0xA85D, 0x6C99, 0xA846, 0x6C9A, 0xCB54, 0x6C9B, 0xA84B, 0x6C9C, 0xCB58, 0x6C9D, 0xCD44, + 0x6CAB, 0xAA6A, 0x6CAC, 0xAA7A, 0x6CAD, 0xCCF5, 0x6CAE, 0xAA71, 0x6CB0, 0xCD4B, 0x6CB1, 0xAA62, 0x6CB3, 0xAA65, 0x6CB4, 0xCD42, + 0x6CB6, 0xCCF3, 0x6CB7, 0xCCF7, 0x6CB8, 0xAA6D, 0x6CB9, 0xAA6F, 0x6CBA, 0xCCFA, 0x6CBB, 0xAA76, 0x6CBC, 0xAA68, 0x6CBD, 0xAA66, + 0x6CBE, 0xAA67, 0x6CBF, 0xAA75, 0x6CC0, 0xCD47, 0x6CC1, 0xAA70, 0x6CC2, 0xCCF9, 0x6CC3, 0xCCFB, 0x6CC4, 0xAA6E, 0x6CC5, 0xAA73, + 0x6CC6, 0xCCFC, 0x6CC7, 0xCD4A, 0x6CC9, 0xAC75, 0x6CCA, 0xAA79, 0x6CCC, 0xAA63, 0x6CCD, 0xCD49, 0x6CCF, 0xCD4D, 0x6CD0, 0xCCF8, + 0x6CD1, 0xCD4F, 0x6CD2, 0xCD40, 0x6CD3, 0xAA6C, 0x6CD4, 0xCCF4, 0x6CD5, 0xAA6B, 0x6CD6, 0xAA7D, 0x6CD7, 0xAA72, 0x6CD9, 0xCCF2, + 0x6CDA, 0xCF75, 0x6CDB, 0xAA78, 0x6CDC, 0xAA7C, 0x6CDD, 0xCD41, 0x6CDE, 0xCD46, 0x6CE0, 0xAA7E, 0x6CE1, 0xAA77, 0x6CE2, 0xAA69, + 0x6CE3, 0xAA5F, 0x6CE5, 0xAA64, 0x6CE7, 0xCCF6, 0x6CE8, 0xAA60, 0x6CE9, 0xCD4E, 0x6CEB, 0xCCF0, 0x6CEC, 0xCCEF, 0x6CED, 0xCCFD, + 0x6CEE, 0xCCF1, 0x6CEF, 0xAA7B, 0x6CF0, 0xAEF5, 0x6CF1, 0xAA74, 0x6CF2, 0xCCFE, 0x6CF3, 0xAA61, 0x6CF5, 0xACA6, 0x6CF9, 0xCD4C, + 0x6D00, 0xCF7C, 0x6D01, 0xCFA1, 0x6D03, 0xCFA4, 0x6D04, 0xCF77, 0x6D07, 0xCFA7, 0x6D08, 0xCFAA, 0x6D09, 0xCFAC, 0x6D0A, 0xCF74, + 0x6D0B, 0xAC76, 0x6D0C, 0xAC7B, 0x6D0D, 0xD249, 0x6D0E, 0xACAD, 0x6D0F, 0xCFA5, 0x6D10, 0xCFAD, 0x6D11, 0xCF7B, 0x6D12, 0xCF73, + 0x6D16, 0xD264, 0x6D17, 0xAC7E, 0x6D18, 0xCFA2, 0x6D19, 0xCF78, 0x6D1A, 0xCF7A, 0x6D1B, 0xACA5, 0x6D1D, 0xCF7D, 0x6D1E, 0xAC7D, + 0x6D1F, 0xCF70, 0x6D20, 0xCFA8, 0x6D22, 0xCFAB, 0x6D25, 0xAC7A, 0x6D27, 0xACA8, 0x6D28, 0xCF6D, 0x6D29, 0xACAA, 0x6D2A, 0xAC78, + 0x6D2B, 0xACAE, 0x6D2C, 0xCFA9, 0x6D2D, 0xCF6F, 0x6D2E, 0xACAB, 0x6D2F, 0xD25E, 0x6D30, 0xCD48, 0x6D31, 0xAC7C, 0x6D32, 0xAC77, + 0x6D33, 0xCF76, 0x6D34, 0xCF6E, 0x6D35, 0xACAC, 0x6D36, 0xACA4, 0x6D37, 0xCFA3, 0x6D38, 0xACA9, 0x6D39, 0xACA7, 0x6D3A, 0xCF79, + 0x6D3B, 0xACA1, 0x6D3C, 0xCF71, 0x6D3D, 0xACA2, 0x6D3E, 0xACA3, 0x6D3F, 0xCF72, 0x6D40, 0xCFA6, 0x6D41, 0xAC79, 0x6D42, 0xCF7E, + 0x6D58, 0xD24C, 0x6D59, 0xAEFD, 0x6D5A, 0xAF43, 0x6D5E, 0xD255, 0x6D5F, 0xD25B, 0x6D60, 0xD257, 0x6D61, 0xD24A, 0x6D62, 0xD24D, + 0x6D63, 0xD246, 0x6D64, 0xD247, 0x6D65, 0xAF4A, 0x6D66, 0xAEFA, 0x6D67, 0xD256, 0x6D68, 0xD25F, 0x6D69, 0xAF45, 0x6D6A, 0xAEF6, + 0x6D6C, 0xAF40, 0x6D6D, 0xD24E, 0x6D6E, 0xAF42, 0x6D6F, 0xD24F, 0x6D70, 0xD259, 0x6D74, 0xAF44, 0x6D75, 0xD268, 0x6D76, 0xD248, + 0x6D77, 0xAEFC, 0x6D78, 0xAEFB, 0x6D79, 0xAF48, 0x6D7A, 0xD245, 0x6D7B, 0xD266, 0x6D7C, 0xD25A, 0x6D7D, 0xD267, 0x6D7E, 0xD261, + 0x6D7F, 0xD253, 0x6D80, 0xD262, 0x6D82, 0xD25C, 0x6D83, 0xD265, 0x6D84, 0xD263, 0x6D85, 0xAF49, 0x6D86, 0xD254, 0x6D87, 0xAEF9, + 0x6D88, 0xAEF8, 0x6D89, 0xAF41, 0x6D8A, 0xAF47, 0x6D8B, 0xD260, 0x6D8C, 0xAF46, 0x6D8D, 0xD251, 0x6D8E, 0xB243, 0x6D90, 0xD269, + 0x6D91, 0xD250, 0x6D92, 0xD24B, 0x6D93, 0xAEFE, 0x6D94, 0xAF4B, 0x6D95, 0xAEF7, 0x6D97, 0xD258, 0x6D98, 0xD25D, 0x6DAA, 0xB265, + 0x6DAB, 0xD5E1, 0x6DAC, 0xD5E5, 0x6DAE, 0xB252, 0x6DAF, 0xB250, 0x6DB2, 0xB247, 0x6DB3, 0xD5E3, 0x6DB4, 0xD5E2, 0x6DB5, 0xB25B, + 0x6DB7, 0xD5E8, 0x6DB8, 0xB255, 0x6DBA, 0xD5FA, 0x6DBB, 0xD647, 0x6DBC, 0xB244, 0x6DBD, 0xD5F7, 0x6DBE, 0xD5F0, 0x6DBF, 0xB267, + 0x6DC0, 0xD5E0, 0x6DC2, 0xD5FC, 0x6DC4, 0xB264, 0x6DC5, 0xB258, 0x6DC6, 0xB263, 0x6DC7, 0xB24E, 0x6DC8, 0xD5EC, 0x6DC9, 0xD5FE, + 0x6DCA, 0xD5F6, 0x6DCB, 0xB24F, 0x6DCC, 0xB249, 0x6DCD, 0xD645, 0x6DCF, 0xD5FD, 0x6DD0, 0xD640, 0x6DD1, 0xB251, 0x6DD2, 0xB259, + 0x6DD3, 0xD642, 0x6DD4, 0xD5EA, 0x6DD5, 0xD5FB, 0x6DD6, 0xD5EF, 0x6DD7, 0xD644, 0x6DD8, 0xB25E, 0x6DD9, 0xB246, 0x6DDA, 0xB25C, + 0x6DDB, 0xD5F4, 0x6DDC, 0xD5F2, 0x6DDD, 0xD5F3, 0x6DDE, 0xB253, 0x6DDF, 0xD5EE, 0x6DE0, 0xD5ED, 0x6DE1, 0xB248, 0x6DE2, 0xD5E7, + 0x6DE3, 0xD646, 0x6DE4, 0xB24A, 0x6DE5, 0xD5F1, 0x6DE6, 0xB268, 0x6DE8, 0xB262, 0x6DE9, 0xD5E6, 0x6DEA, 0xB25F, 0x6DEB, 0xB25D, + 0x6DEC, 0xB266, 0x6DED, 0xD5F8, 0x6DEE, 0xB261, 0x6DEF, 0xD252, 0x6DF0, 0xD5F9, 0x6DF1, 0xB260, 0x6DF2, 0xD641, 0x6DF3, 0xB245, + 0x6DF4, 0xD5F5, 0x6DF5, 0xB257, 0x6DF6, 0xD5E9, 0x6DF7, 0xB256, 0x6DF9, 0xB254, 0x6DFA, 0xB24C, 0x6DFB, 0xB24B, 0x6DFC, 0xD9E7, + 0x6DFD, 0xD643, 0x6E00, 0xD5EB, 0x6E03, 0xD9FC, 0x6E05, 0xB24D, 0x6E19, 0xB541, 0x6E1A, 0xB25A, 0x6E1B, 0xB4EE, 0x6E1C, 0xD9F6, + 0x6E1D, 0xB4FC, 0x6E1F, 0xD9EA, 0x6E20, 0xB4EB, 0x6E21, 0xB4E7, 0x6E22, 0xDA49, 0x6E23, 0xB4ED, 0x6E24, 0xB4F1, 0x6E25, 0xB4EC, + 0x6E26, 0xB4F5, 0x6E27, 0xDA4D, 0x6E28, 0xDA44, 0x6E2B, 0xD9F1, 0x6E2C, 0xB4FA, 0x6E2D, 0xB4F4, 0x6E2E, 0xD9FD, 0x6E2F, 0xB4E4, + 0x6E30, 0xDA4A, 0x6E31, 0xDA43, 0x6E32, 0xB4E8, 0x6E33, 0xD9F7, 0x6E34, 0xB4F7, 0x6E35, 0xDA55, 0x6E36, 0xDA56, 0x6E38, 0xB4E5, + 0x6E39, 0xDA48, 0x6E3A, 0xB4F9, 0x6E3B, 0xD9FB, 0x6E3C, 0xD9ED, 0x6E3D, 0xD9EE, 0x6E3E, 0xB4FD, 0x6E3F, 0xD9F2, 0x6E40, 0xD9F9, + 0x6E41, 0xD9F3, 0x6E43, 0xB4FB, 0x6E44, 0xB544, 0x6E45, 0xD9EF, 0x6E46, 0xD9E8, 0x6E47, 0xD9E9, 0x6E49, 0xD9EB, 0x6E4A, 0xB4EA, + 0x6E4B, 0xD9F8, 0x6E4D, 0xB4F8, 0x6E4E, 0xB542, 0x6E51, 0xD9FA, 0x6E52, 0xDA53, 0x6E53, 0xDA4B, 0x6E54, 0xB4E6, 0x6E55, 0xDA51, + 0x6E56, 0xB4F2, 0x6E58, 0xB4F0, 0x6E5A, 0xDA57, 0x6E5B, 0xB4EF, 0x6E5C, 0xDA41, 0x6E5D, 0xD9F4, 0x6E5E, 0xD9FE, 0x6E5F, 0xB547, + 0x6E60, 0xDA45, 0x6E61, 0xDA42, 0x6E62, 0xD9F0, 0x6E63, 0xB543, 0x6E64, 0xDA4F, 0x6E65, 0xDA4C, 0x6E66, 0xDA54, 0x6E67, 0xB4E9, + 0x6E68, 0xDA40, 0x6E69, 0xB546, 0x6E6B, 0xDA47, 0x6E6E, 0xB4F3, 0x6E6F, 0xB4F6, 0x6E71, 0xDA46, 0x6E72, 0xB545, 0x6E73, 0xD9F5, + 0x6E74, 0xD5E4, 0x6E77, 0xDA50, 0x6E78, 0xDA4E, 0x6E79, 0xDA52, 0x6E88, 0xD9EC, 0x6E89, 0xB540, 0x6E8D, 0xDE61, 0x6E8E, 0xDE60, + 0x6E8F, 0xDE46, 0x6E90, 0xB7BD, 0x6E92, 0xDE5F, 0x6E93, 0xDE49, 0x6E94, 0xDE4A, 0x6E96, 0xB7C7, 0x6E97, 0xDE68, 0x6E98, 0xB7C2, + 0x6E99, 0xDE5E, 0x6E9B, 0xDE43, 0x6E9C, 0xB7C8, 0x6E9D, 0xB7BE, 0x6E9E, 0xDE52, 0x6E9F, 0xDE48, 0x6EA0, 0xDE4B, 0x6EA1, 0xDE63, + 0x6EA2, 0xB7B8, 0x6EA3, 0xDE6A, 0x6EA4, 0xDE62, 0x6EA5, 0xB7C1, 0x6EA6, 0xDE57, 0x6EA7, 0xB7CC, 0x6EAA, 0xB7CB, 0x6EAB, 0xB7C5, + 0x6EAE, 0xDE69, 0x6EAF, 0xB7B9, 0x6EB0, 0xDE55, 0x6EB1, 0xDE4C, 0x6EB2, 0xDE59, 0x6EB3, 0xDE65, 0x6EB4, 0xB7CD, 0x6EB6, 0xB7BB, + 0x6EB7, 0xDE54, 0x6EB9, 0xDE4D, 0x6EBA, 0xB7C4, 0x6EBC, 0xB7C3, 0x6EBD, 0xDE50, 0x6EBE, 0xDE5A, 0x6EBF, 0xDE64, 0x6EC0, 0xDE47, + 0x6EC1, 0xDE51, 0x6EC2, 0xB7BC, 0x6EC3, 0xDE5B, 0x6EC4, 0xB7C9, 0x6EC5, 0xB7C0, 0x6EC6, 0xDE4E, 0x6EC7, 0xB7BF, 0x6EC8, 0xDE45, + 0x6EC9, 0xDE53, 0x6ECA, 0xDE67, 0x6ECB, 0xB4FE, 0x6ECC, 0xBAB0, 0x6ECD, 0xDE56, 0x6ECE, 0xE26C, 0x6ECF, 0xDE58, 0x6ED0, 0xDE66, + 0x6ED1, 0xB7C6, 0x6ED2, 0xDE4F, 0x6ED3, 0xB7BA, 0x6ED4, 0xB7CA, 0x6ED5, 0xBCF0, 0x6ED6, 0xDE44, 0x6ED8, 0xDE5D, 0x6EDC, 0xDE5C, + 0x6EEB, 0xE2AA, 0x6EEC, 0xBAAD, 0x6EED, 0xE27D, 0x6EEE, 0xE2A4, 0x6EEF, 0xBAA2, 0x6EF1, 0xE26E, 0x6EF2, 0xBAAF, 0x6EF4, 0xBA77, + 0x6EF5, 0xE26D, 0x6EF6, 0xE2B0, 0x6EF7, 0xBAB1, 0x6EF8, 0xE271, 0x6EF9, 0xE2A3, 0x6EFB, 0xE273, 0x6EFC, 0xE2B3, 0x6EFD, 0xE2AF, + 0x6EFE, 0xBA75, 0x6EFF, 0xBAA1, 0x6F00, 0xE653, 0x6F01, 0xBAAE, 0x6F02, 0xBA7D, 0x6F03, 0xE26F, 0x6F05, 0xE2AE, 0x6F06, 0xBAA3, + 0x6F07, 0xE2AB, 0x6F08, 0xE2B8, 0x6F09, 0xE275, 0x6F0A, 0xE27E, 0x6F0D, 0xE2B6, 0x6F0E, 0xE2AC, 0x6F0F, 0xBA7C, 0x6F12, 0xE27C, + 0x6F13, 0xBA76, 0x6F14, 0xBA74, 0x6F15, 0xBAA8, 0x6F18, 0xE27A, 0x6F19, 0xE277, 0x6F1A, 0xE278, 0x6F1C, 0xE2B2, 0x6F1E, 0xE2B7, + 0x6F1F, 0xE2B5, 0x6F20, 0xBA7A, 0x6F21, 0xE2B9, 0x6F22, 0xBA7E, 0x6F23, 0xBAA7, 0x6F25, 0xE270, 0x6F26, 0xE5FA, 0x6F27, 0xE279, + 0x6F29, 0xBA78, 0x6F2A, 0xBAAC, 0x6F2B, 0xBAA9, 0x6F2C, 0xBA7B, 0x6F2D, 0xE2A5, 0x6F2E, 0xE274, 0x6F2F, 0xBAAA, 0x6F30, 0xE2A7, + 0x6F31, 0xBAA4, 0x6F32, 0xBAA6, 0x6F33, 0xBA73, 0x6F35, 0xE2A9, 0x6F36, 0xE2A1, 0x6F37, 0xE272, 0x6F38, 0xBAA5, 0x6F39, 0xE2B1, + 0x6F3A, 0xE2B4, 0x6F3B, 0xE27B, 0x6F3C, 0xE2A8, 0x6F3E, 0xBA79, 0x6F3F, 0xBCDF, 0x6F40, 0xE2A6, 0x6F41, 0xE5F9, 0x6F43, 0xE2AD, + 0x6F4E, 0xE276, 0x6F4F, 0xE644, 0x6F50, 0xE64E, 0x6F51, 0xBCE2, 0x6F52, 0xE64D, 0x6F53, 0xE659, 0x6F54, 0xBCE4, 0x6F55, 0xE64B, + 0x6F57, 0xE64F, 0x6F58, 0xBCEF, 0x6F5A, 0xE646, 0x6F5B, 0xBCE7, 0x6F5D, 0xE652, 0x6F5E, 0xE9F0, 0x6F5F, 0xBCF3, 0x6F60, 0xBCF2, + 0x6F61, 0xE654, 0x6F62, 0xE643, 0x6F63, 0xE65E, 0x6F64, 0xBCED, 0x6F66, 0xBCE3, 0x6F67, 0xE657, 0x6F69, 0xE65B, 0x6F6A, 0xE660, + 0x6F6B, 0xE655, 0x6F6C, 0xE649, 0x6F6D, 0xBCE6, 0x6F6E, 0xBCE9, 0x6F6F, 0xBCF1, 0x6F70, 0xBCEC, 0x6F72, 0xE64C, 0x6F73, 0xE2A2, + 0x6F76, 0xE648, 0x6F77, 0xE65F, 0x6F78, 0xBCE8, 0x6F7A, 0xBCEB, 0x6F7B, 0xE661, 0x6F7C, 0xBCE0, 0x6F7D, 0xE656, 0x6F7E, 0xE5FB, + 0x6F7F, 0xE65C, 0x6F80, 0xC0DF, 0x6F82, 0xE64A, 0x6F84, 0xBCE1, 0x6F85, 0xE645, 0x6F86, 0xBCE5, 0x6F87, 0xE5FC, 0x6F88, 0xBAAB, + 0x6F89, 0xE641, 0x6F8B, 0xE65A, 0x6F8C, 0xE642, 0x6F8D, 0xE640, 0x6F8E, 0xBCEA, 0x6F90, 0xE658, 0x6F92, 0xE5FE, 0x6F93, 0xE651, + 0x6F94, 0xE650, 0x6F95, 0xE65D, 0x6F96, 0xE647, 0x6F97, 0xBCEE, 0x6F9E, 0xE9F3, 0x6FA0, 0xBF49, 0x6FA1, 0xBEFE, 0x6FA2, 0xEA40, + 0x6FA3, 0xE9EB, 0x6FA4, 0xBF41, 0x6FA5, 0xE9F7, 0x6FA6, 0xBF48, 0x6FA7, 0xBF43, 0x6FA8, 0xE9F5, 0x6FA9, 0xED4F, 0x6FAA, 0xE9FB, + 0x6FAB, 0xEA42, 0x6FAC, 0xE9FA, 0x6FAD, 0xE9E9, 0x6FAE, 0xE9F8, 0x6FAF, 0xEA44, 0x6FB0, 0xEA46, 0x6FB1, 0xBEFD, 0x6FB2, 0xEA45, + 0x6FB3, 0xBF44, 0x6FB4, 0xBF4A, 0x6FB6, 0xBF47, 0x6FB8, 0xE9FE, 0x6FB9, 0xBF46, 0x6FBA, 0xE9F9, 0x6FBC, 0xE9ED, 0x6FBD, 0xE9F2, + 0x6FBF, 0xE9FD, 0x6FC0, 0xBF45, 0x6FC1, 0xBF42, 0x6FC2, 0xBEFC, 0x6FC3, 0xBF40, 0x6FC4, 0xE9F1, 0x6FC6, 0xE5FD, 0x6FC7, 0xE9EC, + 0x6FC8, 0xE9EF, 0x6FC9, 0xEA41, 0x6FCA, 0xE9F4, 0x6FCB, 0xE9EA, 0x6FCC, 0xED4E, 0x6FCD, 0xEA43, 0x6FCE, 0xE9EE, 0x6FCF, 0xE9FC, + 0x6FD4, 0xED51, 0x6FD5, 0xC0E3, 0x6FD8, 0xC0D7, 0x6FDB, 0xC0DB, 0x6FDC, 0xED53, 0x6FDD, 0xED59, 0x6FDE, 0xED57, 0x6FDF, 0xC0D9, + 0x6FE0, 0xC0DA, 0x6FE1, 0xC0E1, 0x6FE2, 0xED5A, 0x6FE3, 0xED52, 0x6FE4, 0xC0DC, 0x6FE6, 0xED56, 0x6FE7, 0xED55, 0x6FE8, 0xED5B, + 0x6FE9, 0xC0E2, 0x6FEB, 0xC0DD, 0x6FEC, 0xC0E0, 0x6FED, 0xED54, 0x6FEE, 0xC0E4, 0x6FEF, 0xC0DE, 0x6FF0, 0xC0E5, 0x6FF1, 0xC0D8, + 0x6FF2, 0xED58, 0x6FF4, 0xED50, 0x6FF7, 0xEFF7, 0x6FFA, 0xC271, 0x6FFB, 0xEFF4, 0x6FFC, 0xEFF6, 0x6FFE, 0xC26F, 0x6FFF, 0xEFF2, + 0x7000, 0xEFF3, 0x7001, 0xEFEE, 0x7004, 0xE9F6, 0x7005, 0xEFEF, 0x7006, 0xC270, 0x7007, 0xEFEB, 0x7009, 0xC26D, 0x700A, 0xEFF8, + 0x700B, 0xC26E, 0x700C, 0xEFEC, 0x700D, 0xEFED, 0x700E, 0xEFF1, 0x700F, 0xC273, 0x7011, 0xC272, 0x7014, 0xEFF0, 0x7015, 0xC378, + 0x7016, 0xF25F, 0x7017, 0xF265, 0x7018, 0xC379, 0x7019, 0xF25C, 0x701A, 0xC376, 0x701B, 0xC373, 0x701C, 0xF267, 0x701D, 0xC377, + 0x701F, 0xC374, 0x7020, 0xF25E, 0x7021, 0xF261, 0x7022, 0xF262, 0x7023, 0xF263, 0x7024, 0xF266, 0x7026, 0xEFF5, 0x7027, 0xF25D, + 0x7028, 0xC375, 0x7029, 0xF264, 0x702A, 0xF268, 0x702B, 0xF260, 0x702F, 0xF45D, 0x7030, 0xC46A, 0x7031, 0xF460, 0x7032, 0xC46B, + 0x7033, 0xF468, 0x7034, 0xF45F, 0x7035, 0xF45C, 0x7037, 0xF45E, 0x7038, 0xF462, 0x7039, 0xF465, 0x703A, 0xF464, 0x703B, 0xF467, + 0x703C, 0xF45B, 0x703E, 0xC469, 0x703F, 0xF463, 0x7040, 0xF466, 0x7041, 0xF469, 0x7042, 0xF461, 0x7043, 0xF5D3, 0x7044, 0xF5D4, + 0x7045, 0xF5D8, 0x7046, 0xF5D9, 0x7048, 0xF5D6, 0x7049, 0xF5D7, 0x704A, 0xF5D5, 0x704C, 0xC4E9, 0x7051, 0xC578, 0x7052, 0xF6EB, + 0x7055, 0xF6E8, 0x7056, 0xF6E9, 0x7057, 0xF6EA, 0x7058, 0xC579, 0x705A, 0xF7E5, 0x705B, 0xF7E4, 0x705D, 0xF8AF, 0x705E, 0xC5F4, + 0x705F, 0xF8AD, 0x7060, 0xF8B0, 0x7061, 0xF8AE, 0x7062, 0xF8F5, 0x7063, 0xC657, 0x7064, 0xC665, 0x7065, 0xF9A3, 0x7066, 0xF96C, + 0x7068, 0xF9A2, 0x7069, 0xF9D0, 0x706A, 0xF9D1, 0x706B, 0xA4F5, 0x7070, 0xA6C7, 0x7071, 0xCA41, 0x7074, 0xCB5E, 0x7076, 0xA85F, + 0x7078, 0xA862, 0x707A, 0xCB5F, 0x707C, 0xA860, 0x707D, 0xA861, 0x7082, 0xCD58, 0x7083, 0xCD5A, 0x7084, 0xCD55, 0x7085, 0xCD52, + 0x7086, 0xCD54, 0x708A, 0xAAA4, 0x708E, 0xAAA2, 0x7091, 0xCD56, 0x7092, 0xAAA3, 0x7093, 0xCD53, 0x7094, 0xCD50, 0x7095, 0xAAA1, + 0x7096, 0xCD57, 0x7098, 0xCD51, 0x7099, 0xAAA5, 0x709A, 0xCD59, 0x709F, 0xCFAF, 0x70A1, 0xCFB3, 0x70A4, 0xACB7, 0x70A9, 0xCFB6, + 0x70AB, 0xACAF, 0x70AC, 0xACB2, 0x70AD, 0xACB4, 0x70AE, 0xACB6, 0x70AF, 0xACB3, 0x70B0, 0xCFB2, 0x70B1, 0xCFB1, 0x70B3, 0xACB1, + 0x70B4, 0xCFB4, 0x70B5, 0xCFB5, 0x70B7, 0xCFAE, 0x70B8, 0xACB5, 0x70BA, 0xACB0, 0x70BE, 0xCFB0, 0x70C5, 0xD277, 0x70C6, 0xD278, + 0x70C7, 0xD279, 0x70C8, 0xAF50, 0x70CA, 0xAF4C, 0x70CB, 0xD26E, 0x70CD, 0xD276, 0x70CE, 0xD27B, 0x70CF, 0xAF51, 0x70D1, 0xD26C, + 0x70D2, 0xD272, 0x70D3, 0xD26B, 0x70D4, 0xD275, 0x70D7, 0xD271, 0x70D8, 0xAF4D, 0x70D9, 0xAF4F, 0x70DA, 0xD27A, 0x70DC, 0xD26A, + 0x70DD, 0xD26D, 0x70DE, 0xD273, 0x70E0, 0xD274, 0x70E1, 0xD27C, 0x70E2, 0xD270, 0x70E4, 0xAF4E, 0x70EF, 0xB26D, 0x70F0, 0xD64E, + 0x70F3, 0xD650, 0x70F4, 0xD64C, 0x70F6, 0xD658, 0x70F7, 0xD64A, 0x70F8, 0xD657, 0x70F9, 0xB269, 0x70FA, 0xD648, 0x70FB, 0xDA5B, + 0x70FC, 0xD652, 0x70FD, 0xB26C, 0x70FF, 0xD653, 0x7100, 0xD656, 0x7102, 0xD65A, 0x7104, 0xD64F, 0x7106, 0xD654, 0x7109, 0xB26A, + 0x710A, 0xB26B, 0x710B, 0xD659, 0x710C, 0xD64D, 0x710D, 0xD649, 0x710E, 0xD65B, 0x7110, 0xD651, 0x7113, 0xD655, 0x7117, 0xD64B, + 0x7119, 0xB548, 0x711A, 0xB549, 0x711B, 0xDA65, 0x711C, 0xB54F, 0x711E, 0xDA59, 0x711F, 0xDA62, 0x7120, 0xDA58, 0x7121, 0xB54C, + 0x7122, 0xDA60, 0x7123, 0xDA5E, 0x7125, 0xDA5F, 0x7126, 0xB54A, 0x7128, 0xDA63, 0x712E, 0xDA5C, 0x712F, 0xDA5A, 0x7130, 0xB54B, + 0x7131, 0xDA5D, 0x7132, 0xDA61, 0x7136, 0xB54D, 0x713A, 0xDA64, 0x7141, 0xDE70, 0x7142, 0xDE77, 0x7143, 0xDE79, 0x7144, 0xDEA1, + 0x7146, 0xB7DA, 0x7147, 0xDE6B, 0x7149, 0xB7D2, 0x714B, 0xDE7A, 0x714C, 0xB7D7, 0x714D, 0xDEA2, 0x714E, 0xB7CE, 0x7150, 0xDE7D, + 0x7152, 0xDE6D, 0x7153, 0xDE7E, 0x7154, 0xDE6C, 0x7156, 0xB7DC, 0x7158, 0xDE78, 0x7159, 0xB7CF, 0x715A, 0xDEA3, 0x715C, 0xB7D4, + 0x715D, 0xDE71, 0x715E, 0xB7D9, 0x715F, 0xDE7C, 0x7160, 0xDE6F, 0x7161, 0xDE76, 0x7162, 0xDE72, 0x7163, 0xDE6E, 0x7164, 0xB7D1, + 0x7165, 0xB7D8, 0x7166, 0xB7D6, 0x7167, 0xB7D3, 0x7168, 0xB7DB, 0x7169, 0xB7D0, 0x716A, 0xDE75, 0x716C, 0xB7D5, 0x716E, 0xB54E, + 0x7170, 0xDE7B, 0x7172, 0xDE73, 0x7178, 0xDE74, 0x717B, 0xE2C1, 0x717D, 0xBAB4, 0x7180, 0xE2BD, 0x7181, 0xE2C3, 0x7182, 0xE2BF, + 0x7184, 0xBAB6, 0x7185, 0xE2BE, 0x7186, 0xE2C2, 0x7187, 0xE2BA, 0x7189, 0xE2BC, 0x718A, 0xBAB5, 0x718F, 0xE2C0, 0x7190, 0xE2BB, + 0x7192, 0xBAB7, 0x7194, 0xBAB2, 0x7197, 0xE2C4, 0x7199, 0xBAB3, 0x719A, 0xE667, 0x719B, 0xE664, 0x719C, 0xE670, 0x719D, 0xE66A, + 0x719E, 0xE66C, 0x719F, 0xBCF4, 0x71A0, 0xE666, 0x71A1, 0xE66E, 0x71A4, 0xE66D, 0x71A5, 0xE66B, 0x71A7, 0xE671, 0x71A8, 0xBCF7, + 0x71A9, 0xE668, 0x71AA, 0xE66F, 0x71AC, 0xBCF5, 0x71AF, 0xE663, 0x71B0, 0xE665, 0x71B1, 0xBCF6, 0x71B2, 0xE662, 0x71B3, 0xE672, + 0x71B5, 0xE669, 0x71B8, 0xEA4A, 0x71B9, 0xBF51, 0x71BC, 0xEA55, 0x71BD, 0xEA53, 0x71BE, 0xBF4B, 0x71BF, 0xEA49, 0x71C0, 0xEA4C, + 0x71C1, 0xEA4D, 0x71C2, 0xEA48, 0x71C3, 0xBF55, 0x71C4, 0xBF56, 0x71C5, 0xEA47, 0x71C6, 0xEA56, 0x71C7, 0xEA51, 0x71C8, 0xBF4F, + 0x71C9, 0xBF4C, 0x71CA, 0xEA50, 0x71CB, 0xEA4E, 0x71CE, 0xBF52, 0x71CF, 0xEA52, 0x71D0, 0xBF4D, 0x71D2, 0xBF4E, 0x71D4, 0xEA4F, + 0x71D5, 0xBF50, 0x71D6, 0xEA4B, 0x71D8, 0xEA54, 0x71D9, 0xBF53, 0x71DA, 0xEA57, 0x71DB, 0xEA58, 0x71DC, 0xBF54, 0x71DF, 0xC0E7, + 0x71E0, 0xC0EE, 0x71E1, 0xED5C, 0x71E2, 0xED62, 0x71E4, 0xED60, 0x71E5, 0xC0EA, 0x71E6, 0xC0E9, 0x71E7, 0xC0E6, 0x71E8, 0xED5E, + 0x71EC, 0xC0EC, 0x71ED, 0xC0EB, 0x71EE, 0xC0E8, 0x71F0, 0xED61, 0x71F1, 0xED5D, 0x71F2, 0xED5F, 0x71F4, 0xC0ED, 0x71F8, 0xC277, + 0x71F9, 0xEFFB, 0x71FB, 0xC274, 0x71FC, 0xC275, 0x71FD, 0xEFFD, 0x71FE, 0xC276, 0x71FF, 0xEFFA, 0x7201, 0xEFF9, 0x7202, 0xF26C, + 0x7203, 0xEFFC, 0x7205, 0xF26D, 0x7206, 0xC37A, 0x7207, 0xF26B, 0x720A, 0xF26A, 0x720C, 0xF269, 0x720D, 0xC37B, 0x7210, 0xC46C, + 0x7213, 0xF46A, 0x7214, 0xF46B, 0x7219, 0xF5DC, 0x721A, 0xF5DB, 0x721B, 0xC4EA, 0x721D, 0xF5DA, 0x721E, 0xF6EC, 0x721F, 0xF6ED, + 0x7222, 0xF7E6, 0x7223, 0xF8B1, 0x7226, 0xF8F6, 0x7227, 0xF9BC, 0x7228, 0xC679, 0x7229, 0xF9C6, 0x722A, 0xA4F6, 0x722C, 0xAAA6, + 0x722D, 0xAAA7, 0x7230, 0xACB8, 0x7235, 0xC0EF, 0x7236, 0xA4F7, 0x7238, 0xAAA8, 0x7239, 0xAF52, 0x723A, 0xB7DD, 0x723B, 0xA4F8, + 0x723D, 0xB26E, 0x723E, 0xBAB8, 0x723F, 0xC962, 0x7241, 0xCFB7, 0x7242, 0xD27D, 0x7244, 0xE2C5, 0x7246, 0xC0F0, 0x7247, 0xA4F9, + 0x7248, 0xAAA9, 0x7249, 0xCFB8, 0x724A, 0xCFB9, 0x724B, 0xDA66, 0x724C, 0xB550, 0x724F, 0xDEA4, 0x7252, 0xB7DE, 0x7253, 0xE2C6, + 0x7256, 0xBCF8, 0x7258, 0xC37C, 0x7259, 0xA4FA, 0x725A, 0xDA67, 0x725B, 0xA4FB, 0x725D, 0xA6C9, 0x725E, 0xCA42, 0x725F, 0xA6C8, + 0x7260, 0xA865, 0x7261, 0xA864, 0x7262, 0xA863, 0x7263, 0xCB60, 0x7267, 0xAAAA, 0x7269, 0xAAAB, 0x726A, 0xCD5B, 0x726C, 0xCFBA, + 0x726E, 0xCFBD, 0x726F, 0xACBA, 0x7270, 0xCFBB, 0x7272, 0xACB9, 0x7273, 0xCFBC, 0x7274, 0xACBB, 0x7276, 0xD2A2, 0x7277, 0xD2A1, + 0x7278, 0xD27E, 0x7279, 0xAF53, 0x727B, 0xD65D, 0x727C, 0xD65E, 0x727D, 0xB26F, 0x727E, 0xD65C, 0x727F, 0xD65F, 0x7280, 0xB552, + 0x7281, 0xB270, 0x7284, 0xB551, 0x7285, 0xDA6B, 0x7286, 0xDA6A, 0x7288, 0xDA68, 0x7289, 0xDA69, 0x728B, 0xDA6C, 0x728C, 0xDEA6, + 0x728D, 0xDEA5, 0x728E, 0xDEA9, 0x7290, 0xDEA8, 0x7291, 0xDEA7, 0x7292, 0xBAB9, 0x7293, 0xE2C9, 0x7295, 0xE2C8, 0x7296, 0xBABA, + 0x7297, 0xE2C7, 0x7298, 0xE673, 0x729A, 0xE674, 0x729B, 0xBCF9, 0x729D, 0xEA59, 0x729E, 0xEA5A, 0x72A1, 0xF272, 0x72A2, 0xC37D, + 0x72A3, 0xF271, 0x72A4, 0xF270, 0x72A5, 0xF26E, 0x72A6, 0xF26F, 0x72A7, 0xC4EB, 0x72A8, 0xF46C, 0x72A9, 0xF6EE, 0x72AA, 0xF8F7, + 0x72AC, 0xA4FC, 0x72AE, 0xC9A5, 0x72AF, 0xA5C7, 0x72B0, 0xC9A6, 0x72B4, 0xCA43, 0x72B5, 0xCA44, 0x72BA, 0xCB66, 0x72BD, 0xCB62, + 0x72BF, 0xCB61, 0x72C0, 0xAAAC, 0x72C1, 0xCB65, 0x72C2, 0xA867, 0x72C3, 0xCB63, 0x72C4, 0xA866, 0x72C5, 0xCB67, 0x72C6, 0xCB64, + 0x72C9, 0xCD5F, 0x72CA, 0xCFBE, 0x72CB, 0xCD5D, 0x72CC, 0xCD64, 0x72CE, 0xAAAD, 0x72D0, 0xAAB0, 0x72D1, 0xCD65, 0x72D2, 0xCD61, + 0x72D4, 0xCD62, 0x72D6, 0xCD5C, 0x72D7, 0xAAAF, 0x72D8, 0xCD5E, 0x72D9, 0xAAAE, 0x72DA, 0xCD63, 0x72DC, 0xCD60, 0x72DF, 0xCFC2, + 0x72E0, 0xACBD, 0x72E1, 0xACBE, 0x72E3, 0xCFC5, 0x72E4, 0xCFBF, 0x72E6, 0xCFC4, 0x72E8, 0xCFC0, 0x72E9, 0xACBC, 0x72EA, 0xCFC3, + 0x72EB, 0xCFC1, 0x72F3, 0xD2A8, 0x72F4, 0xD2A5, 0x72F6, 0xD2A7, 0x72F7, 0xAF58, 0x72F8, 0xAF57, 0x72F9, 0xAF55, 0x72FA, 0xD2A4, + 0x72FB, 0xD2A9, 0x72FC, 0xAF54, 0x72FD, 0xAF56, 0x72FE, 0xD2A6, 0x72FF, 0xD667, 0x7300, 0xD2A3, 0x7301, 0xD2AA, 0x7307, 0xD662, + 0x7308, 0xD666, 0x730A, 0xD665, 0x730B, 0xDA6E, 0x730C, 0xDA79, 0x730F, 0xD668, 0x7311, 0xD663, 0x7312, 0xDA6D, 0x7313, 0xB274, + 0x7316, 0xB273, 0x7317, 0xD661, 0x7318, 0xD664, 0x7319, 0xB275, 0x731B, 0xB272, 0x731C, 0xB271, 0x731D, 0xD660, 0x731E, 0xD669, + 0x7322, 0xDA70, 0x7323, 0xDA77, 0x7325, 0xB554, 0x7326, 0xDA76, 0x7327, 0xDA73, 0x7329, 0xB556, 0x732D, 0xDA75, 0x7330, 0xDA6F, + 0x7331, 0xDA71, 0x7332, 0xDA74, 0x7333, 0xDA72, 0x7334, 0xB555, 0x7335, 0xDA78, 0x7336, 0xB553, 0x7337, 0xB7DF, 0x733A, 0xDEAD, + 0x733B, 0xDEAC, 0x733C, 0xDEAA, 0x733E, 0xB7E2, 0x733F, 0xB7E1, 0x7340, 0xDEAE, 0x7342, 0xDEAB, 0x7343, 0xE2CA, 0x7344, 0xBABB, + 0x7345, 0xB7E0, 0x7349, 0xDEB0, 0x734A, 0xDEAF, 0x734C, 0xE2CD, 0x734D, 0xE2CB, 0x734E, 0xBCFA, 0x7350, 0xBABC, 0x7351, 0xE2CC, + 0x7352, 0xE676, 0x7357, 0xBCFB, 0x7358, 0xE675, 0x7359, 0xE67E, 0x735A, 0xE67D, 0x735B, 0xE67B, 0x735D, 0xE67A, 0x735E, 0xE677, + 0x735F, 0xE678, 0x7360, 0xE679, 0x7361, 0xE67C, 0x7362, 0xE6A1, 0x7365, 0xEA5F, 0x7366, 0xEA5C, 0x7367, 0xEA5D, 0x7368, 0xBF57, + 0x7369, 0xEA5B, 0x736A, 0xEA61, 0x736B, 0xEA60, 0x736C, 0xEA5E, 0x736E, 0xED64, 0x736F, 0xED65, 0x7370, 0xC0F1, 0x7372, 0xC0F2, + 0x7373, 0xED63, 0x7375, 0xC279, 0x7376, 0xEFFE, 0x7377, 0xC278, 0x7378, 0xC37E, 0x737A, 0xC3A1, 0x737B, 0xC46D, 0x737C, 0xF46E, + 0x737D, 0xF46D, 0x737E, 0xF5DD, 0x737F, 0xF6EF, 0x7380, 0xC57A, 0x7381, 0xF7E8, 0x7382, 0xF7E7, 0x7383, 0xF7E9, 0x7384, 0xA5C8, + 0x7385, 0xCFC6, 0x7386, 0xAF59, 0x7387, 0xB276, 0x7388, 0xD66A, 0x7389, 0xA5C9, 0x738A, 0xC9A7, 0x738B, 0xA4FD, 0x738E, 0xCA45, + 0x7392, 0xCB6C, 0x7393, 0xCB6A, 0x7394, 0xCB6B, 0x7395, 0xCB68, 0x7396, 0xA868, 0x7397, 0xCB69, 0x739D, 0xCD6D, 0x739F, 0xAAB3, + 0x73A0, 0xCD6B, 0x73A1, 0xCD67, 0x73A2, 0xCD6A, 0x73A4, 0xCD66, 0x73A5, 0xAAB5, 0x73A6, 0xCD69, 0x73A8, 0xAAB2, 0x73A9, 0xAAB1, + 0x73AB, 0xAAB4, 0x73AC, 0xCD6C, 0x73AD, 0xCD68, 0x73B2, 0xACC2, 0x73B3, 0xACC5, 0x73B4, 0xCFCE, 0x73B5, 0xCFCD, 0x73B6, 0xCFCC, + 0x73B7, 0xACBF, 0x73B8, 0xCFD5, 0x73B9, 0xCFCB, 0x73BB, 0xACC1, 0x73BC, 0xD2AF, 0x73BE, 0xCFD2, 0x73BF, 0xCFD0, 0x73C0, 0xACC4, + 0x73C2, 0xCFC8, 0x73C3, 0xCFD3, 0x73C5, 0xCFCA, 0x73C6, 0xCFD4, 0x73C7, 0xCFD1, 0x73C8, 0xCFC9, 0x73CA, 0xACC0, 0x73CB, 0xCFD6, + 0x73CC, 0xCFC7, 0x73CD, 0xACC3, 0x73D2, 0xD2B4, 0x73D3, 0xD2AB, 0x73D4, 0xD2B6, 0x73D6, 0xD2AE, 0x73D7, 0xD2B9, 0x73D8, 0xD2BA, + 0x73D9, 0xD2AC, 0x73DA, 0xD2B8, 0x73DB, 0xD2B5, 0x73DC, 0xD2B3, 0x73DD, 0xD2B7, 0x73DE, 0xAF5F, 0x73E0, 0xAF5D, 0x73E3, 0xD2B1, + 0x73E5, 0xD2AD, 0x73E7, 0xD2B0, 0x73E8, 0xD2BB, 0x73E9, 0xD2B2, 0x73EA, 0xAF5E, 0x73EB, 0xCFCF, 0x73ED, 0xAF5A, 0x73EE, 0xAF5C, + 0x73F4, 0xD678, 0x73F5, 0xD66D, 0x73F6, 0xD66B, 0x73F8, 0xD66C, 0x73FA, 0xD673, 0x73FC, 0xD674, 0x73FD, 0xD670, 0x73FE, 0xB27B, + 0x73FF, 0xD675, 0x7400, 0xD672, 0x7401, 0xD66F, 0x7403, 0xB279, 0x7404, 0xD66E, 0x7405, 0xB277, 0x7406, 0xB27A, 0x7407, 0xD671, + 0x7408, 0xD679, 0x7409, 0xAF5B, 0x740A, 0xB278, 0x740B, 0xD677, 0x740C, 0xD676, 0x740D, 0xB27C, 0x7416, 0xDA7E, 0x741A, 0xDAA1, + 0x741B, 0xB560, 0x741D, 0xDAA7, 0x7420, 0xDAA9, 0x7421, 0xDAA2, 0x7422, 0xB55A, 0x7423, 0xDAA6, 0x7424, 0xDAA5, 0x7425, 0xB55B, + 0x7426, 0xB561, 0x7428, 0xB562, 0x7429, 0xDAA8, 0x742A, 0xB558, 0x742B, 0xDA7D, 0x742C, 0xDA7B, 0x742D, 0xDAA3, 0x742E, 0xDA7A, + 0x742F, 0xB55F, 0x7430, 0xDA7C, 0x7431, 0xDAA4, 0x7432, 0xDAAA, 0x7433, 0xB559, 0x7434, 0xB55E, 0x7435, 0xB55C, 0x7436, 0xB55D, + 0x743A, 0xB557, 0x743F, 0xB7E9, 0x7440, 0xDEB7, 0x7441, 0xB7E8, 0x7442, 0xDEBB, 0x7444, 0xDEB1, 0x7446, 0xDEBC, 0x744A, 0xDEB2, + 0x744B, 0xDEB3, 0x744D, 0xDEBD, 0x744E, 0xDEBA, 0x744F, 0xDEB8, 0x7450, 0xDEB9, 0x7451, 0xDEB5, 0x7452, 0xDEB4, 0x7454, 0xDEBE, + 0x7455, 0xB7E5, 0x7457, 0xDEB6, 0x7459, 0xB7EA, 0x745A, 0xB7E4, 0x745B, 0xB7EB, 0x745C, 0xB7EC, 0x745E, 0xB7E7, 0x745F, 0xB7E6, + 0x7462, 0xE2CE, 0x7463, 0xBABE, 0x7464, 0xBABD, 0x7467, 0xE2D3, 0x7469, 0xBCFC, 0x746A, 0xBABF, 0x746D, 0xBAC1, 0x746E, 0xE2D4, + 0x746F, 0xB7E3, 0x7470, 0xBAC0, 0x7471, 0xE2D0, 0x7472, 0xE2D2, 0x7473, 0xE2CF, 0x7475, 0xE2D1, 0x7479, 0xE6AB, 0x747C, 0xE6AA, + 0x747D, 0xE6A7, 0x747E, 0xBD40, 0x747F, 0xEA62, 0x7480, 0xBD41, 0x7481, 0xE6A6, 0x7483, 0xBCFE, 0x7485, 0xE6A8, 0x7486, 0xE6A5, + 0x7487, 0xE6A2, 0x7488, 0xE6A9, 0x7489, 0xE6A3, 0x748A, 0xE6A4, 0x748B, 0xBCFD, 0x7490, 0xED69, 0x7492, 0xEA66, 0x7494, 0xEA65, + 0x7495, 0xEA67, 0x7497, 0xED66, 0x7498, 0xBF5A, 0x749A, 0xEA63, 0x749C, 0xBF58, 0x749E, 0xBF5C, 0x749F, 0xBF5B, 0x74A0, 0xEA64, + 0x74A1, 0xEA68, 0x74A3, 0xBF59, 0x74A5, 0xED6D, 0x74A6, 0xC0F5, 0x74A7, 0xC27A, 0x74A8, 0xC0F6, 0x74A9, 0xC0F3, 0x74AA, 0xED6A, + 0x74AB, 0xED68, 0x74AD, 0xED6B, 0x74AF, 0xED6E, 0x74B0, 0xC0F4, 0x74B1, 0xED6C, 0x74B2, 0xED67, 0x74B5, 0xF042, 0x74B6, 0xF045, + 0x74B7, 0xF275, 0x74B8, 0xF040, 0x74BA, 0xF46F, 0x74BB, 0xF046, 0x74BD, 0xC3A2, 0x74BE, 0xF044, 0x74BF, 0xC27B, 0x74C0, 0xF041, + 0x74C1, 0xF043, 0x74C2, 0xF047, 0x74C3, 0xF276, 0x74C5, 0xF274, 0x74CA, 0xC3A3, 0x74CB, 0xF273, 0x74CF, 0xC46E, 0x74D4, 0xC4ED, + 0x74D5, 0xF6F1, 0x74D6, 0xC4EC, 0x74D7, 0xF6F3, 0x74D8, 0xF6F0, 0x74D9, 0xF6F2, 0x74DA, 0xC5D0, 0x74DB, 0xF8B2, 0x74DC, 0xA5CA, + 0x74DD, 0xCD6E, 0x74DE, 0xD2BC, 0x74DF, 0xD2BD, 0x74E0, 0xB27D, 0x74E1, 0xDEBF, 0x74E2, 0xBF5D, 0x74E3, 0xC3A4, 0x74E4, 0xC57B, + 0x74E5, 0xF8B3, 0x74E6, 0xA5CB, 0x74E8, 0xCD6F, 0x74E9, 0xA260, 0x74EC, 0xCFD7, 0x74EE, 0xCFD8, 0x74F4, 0xD2BE, 0x74F5, 0xD2BF, + 0x74F6, 0xB27E, 0x74F7, 0xB2A1, 0x74FB, 0xDAAB, 0x74FD, 0xDEC2, 0x74FE, 0xDEC1, 0x74FF, 0xDEC0, 0x7500, 0xE2D5, 0x7502, 0xE2D6, + 0x7503, 0xE2D7, 0x7504, 0xBAC2, 0x7507, 0xE6AD, 0x7508, 0xE6AC, 0x750B, 0xEA69, 0x750C, 0xBF5E, 0x750D, 0xBF5F, 0x750F, 0xED72, + 0x7510, 0xED6F, 0x7511, 0xED70, 0x7512, 0xED71, 0x7513, 0xF049, 0x7514, 0xF048, 0x7515, 0xC27C, 0x7516, 0xF277, 0x7517, 0xF5DE, + 0x7518, 0xA5CC, 0x751A, 0xACC6, 0x751C, 0xB2A2, 0x751D, 0xDEC3, 0x751F, 0xA5CD, 0x7521, 0xD2C0, 0x7522, 0xB2A3, 0x7525, 0xB563, + 0x7526, 0xB564, 0x7528, 0xA5CE, 0x7529, 0xA5CF, 0x752A, 0xCA46, 0x752B, 0xA86A, 0x752C, 0xA869, 0x752D, 0xACC7, 0x752E, 0xCFD9, + 0x752F, 0xDAAC, 0x7530, 0xA5D0, 0x7531, 0xA5D1, 0x7532, 0xA5D2, 0x7533, 0xA5D3, 0x7537, 0xA86B, 0x7538, 0xA86C, 0x7539, 0xCB6E, + 0x753A, 0xCB6D, 0x753D, 0xAAB6, 0x753E, 0xCD72, 0x753F, 0xCD70, 0x7540, 0xCD71, 0x7547, 0xCFDA, 0x7548, 0xCFDB, 0x754B, 0xACCB, + 0x754C, 0xACC9, 0x754E, 0xACCA, 0x754F, 0xACC8, 0x7554, 0xAF60, 0x7559, 0xAF64, 0x755A, 0xAF63, 0x755B, 0xD2C1, 0x755C, 0xAF62, + 0x755D, 0xAF61, 0x755F, 0xD2C2, 0x7562, 0xB2A6, 0x7563, 0xD67B, 0x7564, 0xD67A, 0x7565, 0xB2A4, 0x7566, 0xB2A5, 0x756A, 0xB566, + 0x756B, 0xB565, 0x756C, 0xDAAE, 0x756F, 0xDAAD, 0x7570, 0xB2A7, 0x7576, 0xB7ED, 0x7577, 0xDEC5, 0x7578, 0xB7EE, 0x7579, 0xDEC4, + 0x757D, 0xE2D8, 0x757E, 0xE6AE, 0x757F, 0xBD42, 0x7580, 0xEA6A, 0x7584, 0xED73, 0x7586, 0xC3A6, 0x7587, 0xC3A5, 0x758A, 0xC57C, + 0x758B, 0xA5D4, 0x758C, 0xCD73, 0x758F, 0xB2A8, 0x7590, 0xE2D9, 0x7591, 0xBAC3, 0x7594, 0xCB6F, 0x7595, 0xCB70, 0x7598, 0xCD74, + 0x7599, 0xAAB8, 0x759A, 0xAAB9, 0x759D, 0xAAB7, 0x75A2, 0xACCF, 0x75A3, 0xACD0, 0x75A4, 0xACCD, 0x75A5, 0xACCE, 0x75A7, 0xCFDC, + 0x75AA, 0xCFDD, 0x75AB, 0xACCC, 0x75B0, 0xD2C3, 0x75B2, 0xAF68, 0x75B3, 0xAF69, 0x75B5, 0xB2AB, 0x75B6, 0xD2C9, 0x75B8, 0xAF6E, + 0x75B9, 0xAF6C, 0x75BA, 0xD2CA, 0x75BB, 0xD2C5, 0x75BC, 0xAF6B, 0x75BD, 0xAF6A, 0x75BE, 0xAF65, 0x75BF, 0xD2C8, 0x75C0, 0xD2C7, + 0x75C1, 0xD2C4, 0x75C2, 0xAF6D, 0x75C4, 0xD2C6, 0x75C5, 0xAF66, 0x75C7, 0xAF67, 0x75CA, 0xB2AC, 0x75CB, 0xD6A1, 0x75CC, 0xD6A2, + 0x75CD, 0xB2AD, 0x75CE, 0xD67C, 0x75CF, 0xD67E, 0x75D0, 0xD6A4, 0x75D1, 0xD6A3, 0x75D2, 0xD67D, 0x75D4, 0xB2A9, 0x75D5, 0xB2AA, + 0x75D7, 0xDAB6, 0x75D8, 0xB56B, 0x75D9, 0xB56A, 0x75DA, 0xDAB0, 0x75DB, 0xB568, 0x75DD, 0xDAB3, 0x75DE, 0xB56C, 0x75DF, 0xDAB4, + 0x75E0, 0xB56D, 0x75E1, 0xDAB1, 0x75E2, 0xB567, 0x75E3, 0xB569, 0x75E4, 0xDAB5, 0x75E6, 0xDAB2, 0x75E7, 0xDAAF, 0x75ED, 0xDED2, + 0x75EF, 0xDEC7, 0x75F0, 0xB7F0, 0x75F1, 0xB7F3, 0x75F2, 0xB7F2, 0x75F3, 0xB7F7, 0x75F4, 0xB7F6, 0x75F5, 0xDED3, 0x75F6, 0xDED1, + 0x75F7, 0xDECA, 0x75F8, 0xDECE, 0x75F9, 0xDECD, 0x75FA, 0xB7F4, 0x75FB, 0xDED0, 0x75FC, 0xDECC, 0x75FD, 0xDED4, 0x75FE, 0xDECB, + 0x75FF, 0xB7F5, 0x7600, 0xB7EF, 0x7601, 0xB7F1, 0x7603, 0xDEC9, 0x7608, 0xE2DB, 0x7609, 0xBAC7, 0x760A, 0xE2DF, 0x760B, 0xBAC6, + 0x760C, 0xE2DC, 0x760D, 0xBAC5, 0x760F, 0xDEC8, 0x7610, 0xDECF, 0x7611, 0xE2DE, 0x7613, 0xBAC8, 0x7614, 0xE2E0, 0x7615, 0xE2DD, + 0x7616, 0xE2DA, 0x7619, 0xE6B1, 0x761A, 0xE6B5, 0x761B, 0xE6B7, 0x761C, 0xE6B3, 0x761D, 0xE6B2, 0x761E, 0xE6B0, 0x761F, 0xBD45, + 0x7620, 0xBD43, 0x7621, 0xBD48, 0x7622, 0xBD49, 0x7623, 0xE6B4, 0x7624, 0xBD46, 0x7625, 0xE6AF, 0x7626, 0xBD47, 0x7627, 0xBAC4, + 0x7628, 0xE6B6, 0x7629, 0xBD44, 0x762D, 0xEA6C, 0x762F, 0xEA6B, 0x7630, 0xEA73, 0x7631, 0xEA6D, 0x7632, 0xEA72, 0x7633, 0xEA6F, + 0x7634, 0xBF60, 0x7635, 0xEA71, 0x7638, 0xBF61, 0x763A, 0xBF62, 0x763C, 0xEA70, 0x763D, 0xEA6E, 0x7642, 0xC0F8, 0x7643, 0xED74, + 0x7646, 0xC0F7, 0x7647, 0xED77, 0x7648, 0xED75, 0x7649, 0xED76, 0x764C, 0xC0F9, 0x7650, 0xF04D, 0x7652, 0xC2A1, 0x7653, 0xF04E, + 0x7656, 0xC27D, 0x7657, 0xF04F, 0x7658, 0xC27E, 0x7659, 0xF04C, 0x765A, 0xF050, 0x765C, 0xF04A, 0x765F, 0xC3A7, 0x7660, 0xF278, + 0x7661, 0xC3A8, 0x7662, 0xC46F, 0x7664, 0xF04B, 0x7665, 0xC470, 0x7669, 0xC4EE, 0x766A, 0xF5DF, 0x766C, 0xC57E, 0x766D, 0xF6F4, + 0x766E, 0xC57D, 0x7670, 0xF7EA, 0x7671, 0xC5F5, 0x7672, 0xC5F6, 0x7675, 0xF9CC, 0x7678, 0xACD1, 0x7679, 0xCFDE, 0x767B, 0xB56E, + 0x767C, 0xB56F, 0x767D, 0xA5D5, 0x767E, 0xA6CA, 0x767F, 0xCA47, 0x7681, 0xCB71, 0x7682, 0xA86D, 0x7684, 0xAABA, 0x7686, 0xACD2, + 0x7687, 0xACD3, 0x7688, 0xACD4, 0x7689, 0xD6A6, 0x768A, 0xD2CB, 0x768B, 0xAF6F, 0x768E, 0xB2AE, 0x768F, 0xD6A5, 0x7692, 0xDAB8, + 0x7693, 0xB571, 0x7695, 0xDAB7, 0x7696, 0xB570, 0x7699, 0xDED5, 0x769A, 0xBD4A, 0x769B, 0xE6BB, 0x769C, 0xE6B8, 0x769D, 0xE6B9, + 0x769E, 0xE6BA, 0x76A4, 0xED78, 0x76A6, 0xF051, 0x76AA, 0xF471, 0x76AB, 0xF470, 0x76AD, 0xF6F5, 0x76AE, 0xA5D6, 0x76AF, 0xCD75, + 0x76B0, 0xAF70, 0x76B4, 0xB572, 0x76B5, 0xDED6, 0x76B8, 0xE2E1, 0x76BA, 0xBD4B, 0x76BB, 0xEA74, 0x76BD, 0xF052, 0x76BE, 0xF472, + 0x76BF, 0xA5D7, 0x76C2, 0xAABB, 0x76C3, 0xACD7, 0x76C4, 0xCFDF, 0x76C5, 0xACD8, 0x76C6, 0xACD6, 0x76C8, 0xACD5, 0x76C9, 0xD2CC, + 0x76CA, 0xAF71, 0x76CD, 0xAF72, 0x76CE, 0xAF73, 0x76D2, 0xB2B0, 0x76D3, 0xD6A7, 0x76D4, 0xB2AF, 0x76DA, 0xDAB9, 0x76DB, 0xB2B1, + 0x76DC, 0xB573, 0x76DD, 0xDED7, 0x76DE, 0xB7F8, 0x76DF, 0xB7F9, 0x76E1, 0xBAC9, 0x76E3, 0xBACA, 0x76E4, 0xBD4C, 0x76E5, 0xBF64, + 0x76E6, 0xEA75, 0x76E7, 0xBF63, 0x76E9, 0xED79, 0x76EA, 0xC0FA, 0x76EC, 0xF053, 0x76ED, 0xF473, 0x76EE, 0xA5D8, 0x76EF, 0xA86E, + 0x76F0, 0xCD78, 0x76F1, 0xCD77, 0x76F2, 0xAABC, 0x76F3, 0xCD76, 0x76F4, 0xAABD, 0x76F5, 0xCD79, 0x76F7, 0xCFE5, 0x76F8, 0xACDB, + 0x76F9, 0xACDA, 0x76FA, 0xCFE7, 0x76FB, 0xCFE6, 0x76FC, 0xACDF, 0x76FE, 0xACDE, 0x7701, 0xACD9, 0x7703, 0xCFE1, 0x7704, 0xCFE2, + 0x7705, 0xCFE3, 0x7707, 0xACE0, 0x7708, 0xCFE0, 0x7709, 0xACDC, 0x770A, 0xCFE4, 0x770B, 0xACDD, 0x7710, 0xD2CF, 0x7711, 0xD2D3, + 0x7712, 0xD2D1, 0x7713, 0xD2D0, 0x7715, 0xD2D4, 0x7719, 0xD2D5, 0x771A, 0xD2D6, 0x771B, 0xD2CE, 0x771D, 0xD2CD, 0x771F, 0xAF75, + 0x7720, 0xAF76, 0x7722, 0xD2D7, 0x7723, 0xD2D2, 0x7725, 0xD6B0, 0x7727, 0xD2D8, 0x7728, 0xAF77, 0x7729, 0xAF74, 0x772D, 0xD6AA, + 0x772F, 0xD6A9, 0x7731, 0xD6AB, 0x7732, 0xD6AC, 0x7733, 0xD6AE, 0x7734, 0xD6AD, 0x7735, 0xD6B2, 0x7736, 0xB2B5, 0x7737, 0xB2B2, + 0x7738, 0xB2B6, 0x7739, 0xD6A8, 0x773A, 0xB2B7, 0x773B, 0xD6B1, 0x773C, 0xB2B4, 0x773D, 0xD6AF, 0x773E, 0xB2B3, 0x7744, 0xDABC, + 0x7745, 0xDABE, 0x7746, 0xDABA, 0x7747, 0xDABB, 0x774A, 0xDABF, 0x774B, 0xDAC1, 0x774C, 0xDAC2, 0x774D, 0xDABD, 0x774E, 0xDAC0, + 0x774F, 0xB574, 0x7752, 0xDEDB, 0x7754, 0xDEE0, 0x7755, 0xDED8, 0x7756, 0xDEDC, 0x7759, 0xDEE1, 0x775A, 0xDEDD, 0x775B, 0xB7FA, + 0x775C, 0xB843, 0x775E, 0xB7FD, 0x775F, 0xDED9, 0x7760, 0xDEDA, 0x7761, 0xBACE, 0x7762, 0xB846, 0x7763, 0xB7FE, 0x7765, 0xB844, + 0x7766, 0xB7FC, 0x7767, 0xDEDF, 0x7768, 0xB845, 0x7769, 0xDEDE, 0x776A, 0xB841, 0x776B, 0xB7FB, 0x776C, 0xB842, 0x776D, 0xDEE2, + 0x776E, 0xE2E6, 0x776F, 0xE2E8, 0x7779, 0xB840, 0x777C, 0xE2E3, 0x777D, 0xBACC, 0x777E, 0xE2E9, 0x777F, 0xBACD, 0x7780, 0xE2E7, + 0x7781, 0xE2E2, 0x7782, 0xE2E5, 0x7783, 0xE2EA, 0x7784, 0xBACB, 0x7785, 0xE2E4, 0x7787, 0xBD4E, 0x7788, 0xE6BF, 0x7789, 0xE6BE, + 0x778B, 0xBD51, 0x778C, 0xBD4F, 0x778D, 0xE6BC, 0x778E, 0xBD4D, 0x778F, 0xE6BD, 0x7791, 0xBD50, 0x7795, 0xEA7D, 0x7797, 0xEAA1, + 0x7799, 0xEA7E, 0x779A, 0xEA76, 0x779B, 0xEA7A, 0x779C, 0xEA79, 0x779D, 0xEA77, 0x779E, 0xBF66, 0x779F, 0xBF67, 0x77A0, 0xBF65, + 0x77A1, 0xEA78, 0x77A2, 0xEA7B, 0x77A3, 0xEA7C, 0x77A5, 0xBF68, 0x77A7, 0xC140, 0x77A8, 0xEDA3, 0x77AA, 0xC0FC, 0x77AB, 0xED7B, + 0x77AC, 0xC0FE, 0x77AD, 0xC141, 0x77B0, 0xC0FD, 0x77B1, 0xEDA2, 0x77B2, 0xED7C, 0x77B3, 0xC0FB, 0x77B4, 0xEDA1, 0x77B5, 0xED7A, + 0x77B6, 0xED7E, 0x77B7, 0xED7D, 0x77BA, 0xF055, 0x77BB, 0xC2A4, 0x77BC, 0xC2A5, 0x77BD, 0xC2A2, 0x77BF, 0xC2A3, 0x77C2, 0xF054, + 0x77C4, 0xF27B, 0x77C7, 0xC3A9, 0x77C9, 0xF279, 0x77CA, 0xF27A, 0x77CC, 0xF474, 0x77CD, 0xF477, 0x77CE, 0xF475, 0x77CF, 0xF476, + 0x77D0, 0xF5E0, 0x77D3, 0xC4EF, 0x77D4, 0xF7EB, 0x77D5, 0xF8B4, 0x77D7, 0xC5F7, 0x77D8, 0xF8F8, 0x77D9, 0xF8F9, 0x77DA, 0xC666, + 0x77DB, 0xA5D9, 0x77DC, 0xACE1, 0x77DE, 0xDAC3, 0x77E0, 0xDEE3, 0x77E2, 0xA5DA, 0x77E3, 0xA86F, 0x77E5, 0xAABE, 0x77E7, 0xCFE8, + 0x77E8, 0xCFE9, 0x77E9, 0xAF78, 0x77EC, 0xDAC4, 0x77ED, 0xB575, 0x77EE, 0xB847, 0x77EF, 0xC142, 0x77F0, 0xEDA4, 0x77F1, 0xF27C, + 0x77F2, 0xF478, 0x77F3, 0xA5DB, 0x77F7, 0xCDA1, 0x77F8, 0xCD7A, 0x77F9, 0xCD7C, 0x77FA, 0xCD7E, 0x77FB, 0xCD7D, 0x77FC, 0xCD7B, + 0x77FD, 0xAABF, 0x7802, 0xACE2, 0x7803, 0xCFF2, 0x7805, 0xCFED, 0x7806, 0xCFEA, 0x7809, 0xCFF1, 0x780C, 0xACE4, 0x780D, 0xACE5, + 0x780E, 0xCFF0, 0x780F, 0xCFEF, 0x7810, 0xCFEE, 0x7811, 0xCFEB, 0x7812, 0xCFEC, 0x7813, 0xCFF3, 0x7814, 0xACE3, 0x781D, 0xAF7C, + 0x781F, 0xAFA4, 0x7820, 0xAFA3, 0x7821, 0xD2E1, 0x7822, 0xD2DB, 0x7823, 0xD2D9, 0x7825, 0xAFA1, 0x7826, 0xD6B9, 0x7827, 0xAF7A, + 0x7828, 0xD2DE, 0x7829, 0xD2E2, 0x782A, 0xD2E4, 0x782B, 0xD2E0, 0x782C, 0xD2DA, 0x782D, 0xAFA2, 0x782E, 0xD2DF, 0x782F, 0xD2DD, + 0x7830, 0xAF79, 0x7831, 0xD2E5, 0x7832, 0xAFA5, 0x7833, 0xD2E3, 0x7834, 0xAF7D, 0x7835, 0xD2DC, 0x7837, 0xAF7E, 0x7838, 0xAF7B, + 0x7843, 0xB2B9, 0x7845, 0xD6BA, 0x7848, 0xD6B3, 0x7849, 0xD6B5, 0x784A, 0xD6B7, 0x784C, 0xD6B8, 0x784D, 0xD6B6, 0x784E, 0xB2BA, + 0x7850, 0xD6BB, 0x7852, 0xD6B4, 0x785C, 0xDAC8, 0x785D, 0xB576, 0x785E, 0xDAD0, 0x7860, 0xDAC5, 0x7862, 0xDAD1, 0x7864, 0xDAC6, + 0x7865, 0xDAC7, 0x7868, 0xDACF, 0x7869, 0xDACE, 0x786A, 0xDACB, 0x786B, 0xB2B8, 0x786C, 0xB577, 0x786D, 0xDAC9, 0x786E, 0xDACC, + 0x786F, 0xB578, 0x7870, 0xDACD, 0x7871, 0xDACA, 0x7879, 0xDEEE, 0x787B, 0xDEF2, 0x787C, 0xB84E, 0x787E, 0xE2F0, 0x787F, 0xB851, + 0x7880, 0xDEF0, 0x7881, 0xF9D6, 0x7883, 0xDEED, 0x7884, 0xDEE8, 0x7885, 0xDEEA, 0x7886, 0xDEEB, 0x7887, 0xDEE4, 0x7889, 0xB84D, + 0x788C, 0xB84C, 0x788E, 0xB848, 0x788F, 0xDEE7, 0x7891, 0xB84F, 0x7893, 0xB850, 0x7894, 0xDEE6, 0x7895, 0xDEE9, 0x7896, 0xDEF1, + 0x7897, 0xB84A, 0x7898, 0xB84B, 0x7899, 0xDEEF, 0x789A, 0xDEE5, 0x789E, 0xE2F2, 0x789F, 0xBAD0, 0x78A0, 0xE2F4, 0x78A1, 0xDEEC, + 0x78A2, 0xE2F6, 0x78A3, 0xBAD4, 0x78A4, 0xE2F7, 0x78A5, 0xE2F3, 0x78A7, 0xBAD1, 0x78A8, 0xE2EF, 0x78A9, 0xBAD3, 0x78AA, 0xE2EC, + 0x78AB, 0xE2F1, 0x78AC, 0xE2F5, 0x78AD, 0xE2EE, 0x78B0, 0xB849, 0x78B2, 0xE2EB, 0x78B3, 0xBAD2, 0x78B4, 0xE2ED, 0x78BA, 0xBD54, + 0x78BB, 0xE6C1, 0x78BC, 0xBD58, 0x78BE, 0xBD56, 0x78C1, 0xBACF, 0x78C3, 0xE6C8, 0x78C4, 0xE6C9, 0x78C5, 0xBD53, 0x78C8, 0xE6C7, + 0x78C9, 0xE6CA, 0x78CA, 0xBD55, 0x78CB, 0xBD52, 0x78CC, 0xE6C3, 0x78CD, 0xE6C0, 0x78CE, 0xE6C5, 0x78CF, 0xE6C2, 0x78D0, 0xBD59, + 0x78D1, 0xE6C4, 0x78D4, 0xE6C6, 0x78D5, 0xBD57, 0x78DA, 0xBF6A, 0x78DB, 0xEAA8, 0x78DD, 0xEAA2, 0x78DE, 0xEAA6, 0x78DF, 0xEAAC, + 0x78E0, 0xEAAD, 0x78E1, 0xEAA9, 0x78E2, 0xEAAA, 0x78E3, 0xEAA7, 0x78E5, 0xEAA4, 0x78E7, 0xBF6C, 0x78E8, 0xBF69, 0x78E9, 0xEAA3, + 0x78EA, 0xEAA5, 0x78EC, 0xBF6B, 0x78ED, 0xEAAB, 0x78EF, 0xC146, 0x78F2, 0xEDAA, 0x78F3, 0xEDA5, 0x78F4, 0xC145, 0x78F7, 0xC143, + 0x78F9, 0xEDAC, 0x78FA, 0xC144, 0x78FB, 0xEDA8, 0x78FC, 0xEDA9, 0x78FD, 0xEDA6, 0x78FE, 0xEDAD, 0x78FF, 0xF056, 0x7901, 0xC147, + 0x7902, 0xEDA7, 0x7904, 0xEDAE, 0x7905, 0xEDAB, 0x7909, 0xF05A, 0x790C, 0xF057, 0x790E, 0xC2A6, 0x7910, 0xF05B, 0x7911, 0xF05D, + 0x7912, 0xF05C, 0x7913, 0xF058, 0x7914, 0xF059, 0x7917, 0xF2A3, 0x7919, 0xC3AA, 0x791B, 0xF27E, 0x791C, 0xF2A2, 0x791D, 0xF27D, + 0x791E, 0xF2A4, 0x7921, 0xF2A1, 0x7923, 0xF47A, 0x7924, 0xF47D, 0x7925, 0xF479, 0x7926, 0xC471, 0x7927, 0xF47B, 0x7928, 0xF47C, + 0x7929, 0xF47E, 0x792A, 0xC472, 0x792B, 0xC474, 0x792C, 0xC473, 0x792D, 0xF5E1, 0x792F, 0xF5E3, 0x7931, 0xF5E2, 0x7935, 0xF6F6, + 0x7938, 0xF8B5, 0x7939, 0xF8FA, 0x793A, 0xA5DC, 0x793D, 0xCB72, 0x793E, 0xAAC0, 0x793F, 0xCDA3, 0x7940, 0xAAC1, 0x7941, 0xAAC2, + 0x7942, 0xCDA2, 0x7944, 0xCFF8, 0x7945, 0xCFF7, 0x7946, 0xACE6, 0x7947, 0xACE9, 0x7948, 0xACE8, 0x7949, 0xACE7, 0x794A, 0xCFF4, + 0x794B, 0xCFF6, 0x794C, 0xCFF5, 0x794F, 0xD2E8, 0x7950, 0xAFA7, 0x7951, 0xD2EC, 0x7952, 0xD2EB, 0x7953, 0xD2EA, 0x7954, 0xD2E6, + 0x7955, 0xAFA6, 0x7956, 0xAFAA, 0x7957, 0xAFAD, 0x795A, 0xAFAE, 0x795B, 0xD2E7, 0x795C, 0xD2E9, 0x795D, 0xAFAC, 0x795E, 0xAFAB, + 0x795F, 0xAFA9, 0x7960, 0xAFA8, 0x7961, 0xD6C2, 0x7963, 0xD6C0, 0x7964, 0xD6BC, 0x7965, 0xB2BB, 0x7967, 0xD6BD, 0x7968, 0xB2BC, + 0x7969, 0xD6BE, 0x796A, 0xD6BF, 0x796B, 0xD6C1, 0x796D, 0xB2BD, 0x7970, 0xDAD5, 0x7972, 0xDAD4, 0x7973, 0xDAD3, 0x7974, 0xDAD2, + 0x7979, 0xDEF6, 0x797A, 0xB852, 0x797C, 0xDEF3, 0x797D, 0xDEF5, 0x797F, 0xB853, 0x7981, 0xB854, 0x7982, 0xDEF4, 0x7988, 0xE341, + 0x798A, 0xE2F9, 0x798B, 0xE2FA, 0x798D, 0xBAD7, 0x798E, 0xBAD5, 0x798F, 0xBAD6, 0x7990, 0xE343, 0x7992, 0xE342, 0x7993, 0xE2FE, + 0x7994, 0xE2FD, 0x7995, 0xE2FC, 0x7996, 0xE2FB, 0x7997, 0xE340, 0x7998, 0xE2F8, 0x799A, 0xE6CB, 0x799B, 0xE6D0, 0x799C, 0xE6CE, + 0x79A0, 0xE6CD, 0x79A1, 0xE6CC, 0x79A2, 0xE6CF, 0x79A4, 0xEAAE, 0x79A6, 0xBF6D, 0x79A7, 0xC148, 0x79A8, 0xEDB0, 0x79AA, 0xC149, + 0x79AB, 0xEDAF, 0x79AC, 0xF05F, 0x79AD, 0xF05E, 0x79AE, 0xC2A7, 0x79B0, 0xF2A5, 0x79B1, 0xC3AB, 0x79B2, 0xF4A1, 0x79B3, 0xC5A1, + 0x79B4, 0xF6F7, 0x79B6, 0xF8B7, 0x79B7, 0xF8B6, 0x79B8, 0xC9A8, 0x79B9, 0xACEA, 0x79BA, 0xACEB, 0x79BB, 0xD6C3, 0x79BD, 0xB856, + 0x79BE, 0xA5DD, 0x79BF, 0xA872, 0x79C0, 0xA871, 0x79C1, 0xA870, 0x79C5, 0xCDA4, 0x79C8, 0xAAC4, 0x79C9, 0xAAC3, 0x79CB, 0xACEE, + 0x79CD, 0xCFFA, 0x79CE, 0xCFFD, 0x79CF, 0xCFFB, 0x79D1, 0xACEC, 0x79D2, 0xACED, 0x79D5, 0xCFF9, 0x79D6, 0xCFFC, 0x79D8, 0xAFB5, + 0x79DC, 0xD2F3, 0x79DD, 0xD2F5, 0x79DE, 0xD2F4, 0x79DF, 0xAFB2, 0x79E0, 0xD2EF, 0x79E3, 0xAFB0, 0x79E4, 0xAFAF, 0x79E6, 0xAFB3, + 0x79E7, 0xAFB1, 0x79E9, 0xAFB4, 0x79EA, 0xD2F2, 0x79EB, 0xD2ED, 0x79EC, 0xD2EE, 0x79ED, 0xD2F1, 0x79EE, 0xD2F0, 0x79F6, 0xD6C6, + 0x79F7, 0xD6C7, 0x79F8, 0xD6C5, 0x79FA, 0xD6C4, 0x79FB, 0xB2BE, 0x7A00, 0xB57D, 0x7A02, 0xDAD6, 0x7A03, 0xDAD8, 0x7A04, 0xDADA, + 0x7A05, 0xB57C, 0x7A08, 0xB57A, 0x7A0A, 0xDAD7, 0x7A0B, 0xB57B, 0x7A0C, 0xDAD9, 0x7A0D, 0xB579, 0x7A10, 0xDF41, 0x7A11, 0xDEF7, + 0x7A12, 0xDEFA, 0x7A13, 0xDEFE, 0x7A14, 0xB85A, 0x7A15, 0xDEFC, 0x7A17, 0xDEFB, 0x7A18, 0xDEF8, 0x7A19, 0xDEF9, 0x7A1A, 0xB858, + 0x7A1B, 0xDF40, 0x7A1C, 0xB857, 0x7A1E, 0xB85C, 0x7A1F, 0xB85B, 0x7A20, 0xB859, 0x7A22, 0xDEFD, 0x7A26, 0xE349, 0x7A28, 0xE348, + 0x7A2B, 0xE344, 0x7A2E, 0xBAD8, 0x7A2F, 0xE347, 0x7A30, 0xE346, 0x7A31, 0xBAD9, 0x7A37, 0xBD5E, 0x7A39, 0xE6D2, 0x7A3B, 0xBD5F, + 0x7A3C, 0xBD5B, 0x7A3D, 0xBD5D, 0x7A3F, 0xBD5A, 0x7A40, 0xBD5C, 0x7A44, 0xEAAF, 0x7A46, 0xBF70, 0x7A47, 0xEAB1, 0x7A48, 0xEAB0, + 0x7A4A, 0xE345, 0x7A4B, 0xBF72, 0x7A4C, 0xBF71, 0x7A4D, 0xBF6E, 0x7A4E, 0xBF6F, 0x7A54, 0xEDB5, 0x7A56, 0xEDB3, 0x7A57, 0xC14A, + 0x7A58, 0xEDB4, 0x7A5A, 0xEDB6, 0x7A5B, 0xEDB2, 0x7A5C, 0xEDB1, 0x7A5F, 0xF060, 0x7A60, 0xC2AA, 0x7A61, 0xC2A8, 0x7A62, 0xC2A9, + 0x7A67, 0xF2A6, 0x7A68, 0xF2A7, 0x7A69, 0xC3AD, 0x7A6B, 0xC3AC, 0x7A6C, 0xF4A3, 0x7A6D, 0xF4A4, 0x7A6E, 0xF4A2, 0x7A70, 0xF6F8, + 0x7A71, 0xF6F9, 0x7A74, 0xA5DE, 0x7A75, 0xCA48, 0x7A76, 0xA873, 0x7A78, 0xCDA5, 0x7A79, 0xAAC6, 0x7A7A, 0xAAC5, 0x7A7B, 0xCDA6, + 0x7A7E, 0xD040, 0x7A7F, 0xACEF, 0x7A80, 0xCFFE, 0x7A81, 0xACF0, 0x7A84, 0xAFB6, 0x7A85, 0xD2F8, 0x7A86, 0xD2F6, 0x7A87, 0xD2FC, + 0x7A88, 0xAFB7, 0x7A89, 0xD2F7, 0x7A8A, 0xD2FB, 0x7A8B, 0xD2F9, 0x7A8C, 0xD2FA, 0x7A8F, 0xD6C8, 0x7A90, 0xD6CA, 0x7A92, 0xB2BF, + 0x7A94, 0xD6C9, 0x7A95, 0xB2C0, 0x7A96, 0xB5A2, 0x7A97, 0xB5A1, 0x7A98, 0xB57E, 0x7A99, 0xDADB, 0x7A9E, 0xDF44, 0x7A9F, 0xB85D, + 0x7AA0, 0xB85E, 0x7AA2, 0xDF43, 0x7AA3, 0xDF42, 0x7AA8, 0xE34A, 0x7AA9, 0xBADB, 0x7AAA, 0xBADA, 0x7AAB, 0xE34B, 0x7AAC, 0xE34C, + 0x7AAE, 0xBD61, 0x7AAF, 0xBD60, 0x7AB1, 0xEAB5, 0x7AB2, 0xE6D3, 0x7AB3, 0xE6D5, 0x7AB4, 0xE6D4, 0x7AB5, 0xEAB4, 0x7AB6, 0xEAB2, + 0x7AB7, 0xEAB6, 0x7AB8, 0xEAB3, 0x7ABA, 0xBF73, 0x7ABE, 0xEDB7, 0x7ABF, 0xC14B, 0x7AC0, 0xEDB8, 0x7AC1, 0xEDB9, 0x7AC4, 0xC2AB, + 0x7AC5, 0xC2AC, 0x7AC7, 0xC475, 0x7ACA, 0xC5D1, 0x7ACB, 0xA5DF, 0x7AD1, 0xD041, 0x7AD8, 0xD2FD, 0x7AD9, 0xAFB8, 0x7ADF, 0xB3BA, + 0x7AE0, 0xB3B9, 0x7AE3, 0xB5A4, 0x7AE4, 0xDADD, 0x7AE5, 0xB5A3, 0x7AE6, 0xDADC, 0x7AEB, 0xDF45, 0x7AED, 0xBADC, 0x7AEE, 0xE34D, + 0x7AEF, 0xBADD, 0x7AF6, 0xC476, 0x7AF7, 0xF4A5, 0x7AF9, 0xA6CB, 0x7AFA, 0xAAC7, 0x7AFB, 0xCDA7, 0x7AFD, 0xACF2, 0x7AFF, 0xACF1, + 0x7B00, 0xD042, 0x7B01, 0xD043, 0x7B04, 0xD340, 0x7B05, 0xD342, 0x7B06, 0xAFB9, 0x7B08, 0xD344, 0x7B09, 0xD347, 0x7B0A, 0xD345, + 0x7B0E, 0xD346, 0x7B0F, 0xD343, 0x7B10, 0xD2FE, 0x7B11, 0xAFBA, 0x7B12, 0xD348, 0x7B13, 0xD341, 0x7B18, 0xD6D3, 0x7B19, 0xB2C6, + 0x7B1A, 0xD6DC, 0x7B1B, 0xB2C3, 0x7B1D, 0xD6D5, 0x7B1E, 0xB2C7, 0x7B20, 0xB2C1, 0x7B22, 0xD6D0, 0x7B23, 0xD6DD, 0x7B24, 0xD6D1, + 0x7B25, 0xD6CE, 0x7B26, 0xB2C5, 0x7B28, 0xB2C2, 0x7B2A, 0xD6D4, 0x7B2B, 0xD6D7, 0x7B2C, 0xB2C4, 0x7B2D, 0xD6D8, 0x7B2E, 0xB2C8, + 0x7B2F, 0xD6D9, 0x7B30, 0xD6CF, 0x7B31, 0xD6D6, 0x7B32, 0xD6DA, 0x7B33, 0xD6D2, 0x7B34, 0xD6CD, 0x7B35, 0xD6CB, 0x7B38, 0xD6DB, + 0x7B3B, 0xDADF, 0x7B40, 0xDAE4, 0x7B44, 0xDAE0, 0x7B45, 0xDAE6, 0x7B46, 0xB5A7, 0x7B47, 0xD6CC, 0x7B48, 0xDAE1, 0x7B49, 0xB5A5, + 0x7B4A, 0xDADE, 0x7B4B, 0xB5AC, 0x7B4C, 0xDAE2, 0x7B4D, 0xB5AB, 0x7B4E, 0xDAE3, 0x7B4F, 0xB5AD, 0x7B50, 0xB5A8, 0x7B51, 0xB5AE, + 0x7B52, 0xB5A9, 0x7B54, 0xB5AA, 0x7B56, 0xB5A6, 0x7B58, 0xDAE5, 0x7B60, 0xB861, 0x7B61, 0xDF50, 0x7B63, 0xDF53, 0x7B64, 0xDF47, + 0x7B65, 0xDF4C, 0x7B66, 0xDF46, 0x7B67, 0xB863, 0x7B69, 0xDF4A, 0x7B6D, 0xDF48, 0x7B6E, 0xB862, 0x7B70, 0xDF4F, 0x7B71, 0xDF4E, + 0x7B72, 0xDF4B, 0x7B73, 0xDF4D, 0x7B74, 0xDF49, 0x7B75, 0xBAE1, 0x7B76, 0xDF52, 0x7B77, 0xB85F, 0x7B78, 0xDF51, 0x7B82, 0xE35D, + 0x7B84, 0xBAE8, 0x7B85, 0xE358, 0x7B87, 0xBAE7, 0x7B88, 0xE34E, 0x7B8A, 0xE350, 0x7B8B, 0xBAE0, 0x7B8C, 0xE355, 0x7B8D, 0xE354, + 0x7B8E, 0xE357, 0x7B8F, 0xBAE5, 0x7B90, 0xE352, 0x7B91, 0xE351, 0x7B94, 0xBAE4, 0x7B95, 0xBADF, 0x7B96, 0xE353, 0x7B97, 0xBAE2, + 0x7B98, 0xE359, 0x7B99, 0xE35B, 0x7B9B, 0xE356, 0x7B9C, 0xE34F, 0x7B9D, 0xBAE3, 0x7BA0, 0xBD69, 0x7BA1, 0xBADE, 0x7BA4, 0xE35C, + 0x7BAC, 0xE6D9, 0x7BAD, 0xBD62, 0x7BAF, 0xE6DB, 0x7BB1, 0xBD63, 0x7BB4, 0xBD65, 0x7BB5, 0xE6DE, 0x7BB7, 0xE6D6, 0x7BB8, 0xBAE6, + 0x7BB9, 0xE6DC, 0x7BBE, 0xE6D8, 0x7BC0, 0xB860, 0x7BC1, 0xBD68, 0x7BC4, 0xBD64, 0x7BC6, 0xBD66, 0x7BC7, 0xBD67, 0x7BC9, 0xBF76, + 0x7BCA, 0xE6DD, 0x7BCB, 0xE6D7, 0x7BCC, 0xBD6A, 0x7BCE, 0xE6DA, 0x7BD4, 0xEAC0, 0x7BD5, 0xEABB, 0x7BD8, 0xEAC5, 0x7BD9, 0xBF74, + 0x7BDA, 0xEABD, 0x7BDB, 0xBF78, 0x7BDC, 0xEAC3, 0x7BDD, 0xEABA, 0x7BDE, 0xEAB7, 0x7BDF, 0xEAC6, 0x7BE0, 0xC151, 0x7BE1, 0xBF79, + 0x7BE2, 0xEAC2, 0x7BE3, 0xEAB8, 0x7BE4, 0xBF77, 0x7BE5, 0xEABC, 0x7BE6, 0xBF7B, 0x7BE7, 0xEAB9, 0x7BE8, 0xEABE, 0x7BE9, 0xBF7A, + 0x7BEA, 0xEAC1, 0x7BEB, 0xEAC4, 0x7BF0, 0xEDCB, 0x7BF1, 0xEDCC, 0x7BF2, 0xEDBC, 0x7BF3, 0xEDC3, 0x7BF4, 0xEDC1, 0x7BF7, 0xC14F, + 0x7BF8, 0xEDC8, 0x7BF9, 0xEABF, 0x7BFB, 0xEDBF, 0x7BFD, 0xEDC9, 0x7BFE, 0xC14E, 0x7BFF, 0xEDBE, 0x7C00, 0xEDBD, 0x7C01, 0xEDC7, + 0x7C02, 0xEDC4, 0x7C03, 0xEDC6, 0x7C05, 0xEDBA, 0x7C06, 0xEDCA, 0x7C07, 0xC14C, 0x7C09, 0xEDC5, 0x7C0A, 0xEDCE, 0x7C0B, 0xEDC2, + 0x7C0C, 0xC150, 0x7C0D, 0xC14D, 0x7C0E, 0xEDC0, 0x7C0F, 0xEDBB, 0x7C10, 0xEDCD, 0x7C11, 0xBF75, 0x7C19, 0xF063, 0x7C1C, 0xF061, + 0x7C1D, 0xF067, 0x7C1E, 0xC2B0, 0x7C1F, 0xF065, 0x7C20, 0xF064, 0x7C21, 0xC2B2, 0x7C22, 0xF06A, 0x7C23, 0xC2B1, 0x7C25, 0xF06B, + 0x7C26, 0xF068, 0x7C27, 0xC2AE, 0x7C28, 0xF069, 0x7C29, 0xF062, 0x7C2A, 0xC2AF, 0x7C2B, 0xC2AD, 0x7C2C, 0xF2AB, 0x7C2D, 0xF066, + 0x7C30, 0xF06C, 0x7C33, 0xF2A8, 0x7C37, 0xC3B2, 0x7C38, 0xC3B0, 0x7C39, 0xF2AA, 0x7C3B, 0xF2AC, 0x7C3C, 0xF2A9, 0x7C3D, 0xC3B1, + 0x7C3E, 0xC3AE, 0x7C3F, 0xC3AF, 0x7C40, 0xC3B3, 0x7C43, 0xC478, 0x7C45, 0xF4AA, 0x7C47, 0xF4A9, 0x7C48, 0xF4A7, 0x7C49, 0xF4A6, + 0x7C4A, 0xF4A8, 0x7C4C, 0xC477, 0x7C4D, 0xC479, 0x7C50, 0xC4F0, 0x7C53, 0xF5E5, 0x7C54, 0xF5E4, 0x7C57, 0xF6FA, 0x7C59, 0xF6FC, + 0x7C5A, 0xF6FE, 0x7C5B, 0xF6FD, 0x7C5C, 0xF6FB, 0x7C5F, 0xC5A3, 0x7C60, 0xC5A2, 0x7C63, 0xC5D3, 0x7C64, 0xC5D2, 0x7C65, 0xC5D4, + 0x7C66, 0xF7ED, 0x7C67, 0xF7EC, 0x7C69, 0xF8FB, 0x7C6A, 0xF8B8, 0x7C6B, 0xF8FC, 0x7C6C, 0xC658, 0x7C6E, 0xC659, 0x7C6F, 0xF96D, + 0x7C72, 0xC67E, 0x7C73, 0xA6CC, 0x7C75, 0xCDA8, 0x7C78, 0xD045, 0x7C79, 0xD046, 0x7C7A, 0xD044, 0x7C7D, 0xACF3, 0x7C7F, 0xD047, + 0x7C80, 0xD048, 0x7C81, 0xD049, 0x7C84, 0xD349, 0x7C85, 0xD34F, 0x7C88, 0xD34D, 0x7C89, 0xAFBB, 0x7C8A, 0xD34B, 0x7C8C, 0xD34C, + 0x7C8D, 0xD34E, 0x7C91, 0xD34A, 0x7C92, 0xB2C9, 0x7C94, 0xD6DE, 0x7C95, 0xB2CB, 0x7C96, 0xD6E0, 0x7C97, 0xB2CA, 0x7C98, 0xD6DF, + 0x7C9E, 0xDAE8, 0x7C9F, 0xB5AF, 0x7CA1, 0xDAEA, 0x7CA2, 0xDAE7, 0x7CA3, 0xD6E1, 0x7CA5, 0xB5B0, 0x7CA7, 0xF9DB, 0x7CA8, 0xDAE9, + 0x7CAF, 0xDF56, 0x7CB1, 0xB864, 0x7CB2, 0xDF54, 0x7CB3, 0xB865, 0x7CB4, 0xDF55, 0x7CB5, 0xB866, 0x7CB9, 0xBAE9, 0x7CBA, 0xE361, + 0x7CBB, 0xE35E, 0x7CBC, 0xE360, 0x7CBD, 0xBAEA, 0x7CBE, 0xBAEB, 0x7CBF, 0xE35F, 0x7CC5, 0xE6DF, 0x7CC8, 0xE6E0, 0x7CCA, 0xBD6B, + 0x7CCB, 0xE6E2, 0x7CCC, 0xE6E1, 0x7CCE, 0xA261, 0x7CD0, 0xEACA, 0x7CD1, 0xEACB, 0x7CD2, 0xEAC7, 0x7CD4, 0xEAC8, 0x7CD5, 0xBF7C, + 0x7CD6, 0xBF7D, 0x7CD7, 0xEAC9, 0x7CD9, 0xC157, 0x7CDC, 0xC153, 0x7CDD, 0xC158, 0x7CDE, 0xC154, 0x7CDF, 0xC156, 0x7CE0, 0xC152, + 0x7CE2, 0xC155, 0x7CE7, 0xC2B3, 0x7CE8, 0xEDCF, 0x7CEA, 0xF2AE, 0x7CEC, 0xF2AD, 0x7CEE, 0xF4AB, 0x7CEF, 0xC47A, 0x7CF0, 0xC47B, + 0x7CF1, 0xF741, 0x7CF2, 0xF5E6, 0x7CF4, 0xF740, 0x7CF6, 0xF8FD, 0x7CF7, 0xF9A4, 0x7CF8, 0xA6CD, 0x7CFB, 0xA874, 0x7CFD, 0xCDA9, + 0x7CFE, 0xAAC8, 0x7D00, 0xACF6, 0x7D01, 0xD04C, 0x7D02, 0xACF4, 0x7D03, 0xD04A, 0x7D04, 0xACF9, 0x7D05, 0xACF5, 0x7D06, 0xACFA, + 0x7D07, 0xACF8, 0x7D08, 0xD04B, 0x7D09, 0xACF7, 0x7D0A, 0xAFBF, 0x7D0B, 0xAFBE, 0x7D0C, 0xD35A, 0x7D0D, 0xAFC7, 0x7D0E, 0xD353, + 0x7D0F, 0xD359, 0x7D10, 0xAFC3, 0x7D11, 0xD352, 0x7D12, 0xD358, 0x7D13, 0xD356, 0x7D14, 0xAFC2, 0x7D15, 0xAFC4, 0x7D16, 0xD355, + 0x7D17, 0xAFBD, 0x7D18, 0xD354, 0x7D19, 0xAFC8, 0x7D1A, 0xAFC5, 0x7D1B, 0xAFC9, 0x7D1C, 0xAFC6, 0x7D1D, 0xD351, 0x7D1E, 0xD350, + 0x7D1F, 0xD357, 0x7D20, 0xAFC0, 0x7D21, 0xAFBC, 0x7D22, 0xAFC1, 0x7D28, 0xD6F0, 0x7D29, 0xD6E9, 0x7D2B, 0xB5B5, 0x7D2C, 0xD6E8, + 0x7D2E, 0xB2CF, 0x7D2F, 0xB2D6, 0x7D30, 0xB2D3, 0x7D31, 0xB2D9, 0x7D32, 0xB2D8, 0x7D33, 0xB2D4, 0x7D35, 0xD6E2, 0x7D36, 0xD6E5, + 0x7D38, 0xD6E4, 0x7D39, 0xB2D0, 0x7D3A, 0xD6E6, 0x7D3B, 0xD6EF, 0x7D3C, 0xB2D1, 0x7D3D, 0xD6E3, 0x7D3E, 0xD6EC, 0x7D3F, 0xD6ED, + 0x7D40, 0xB2D2, 0x7D41, 0xD6EA, 0x7D42, 0xB2D7, 0x7D43, 0xB2CD, 0x7D44, 0xB2D5, 0x7D45, 0xD6E7, 0x7D46, 0xB2CC, 0x7D47, 0xD6EB, + 0x7D4A, 0xD6EE, 0x7D4E, 0xDAFB, 0x7D4F, 0xDAF2, 0x7D50, 0xB5B2, 0x7D51, 0xDAF9, 0x7D52, 0xDAF6, 0x7D53, 0xDAEE, 0x7D54, 0xDAF7, + 0x7D55, 0xB5B4, 0x7D56, 0xDAEF, 0x7D58, 0xDAEB, 0x7D5B, 0xB86C, 0x7D5C, 0xDAF4, 0x7D5E, 0xB5B1, 0x7D5F, 0xDAFA, 0x7D61, 0xB5B8, + 0x7D62, 0xB5BA, 0x7D63, 0xDAED, 0x7D66, 0xB5B9, 0x7D67, 0xDAF0, 0x7D68, 0xB5B3, 0x7D69, 0xDAF8, 0x7D6A, 0xDAF1, 0x7D6B, 0xDAF5, + 0x7D6D, 0xDAF3, 0x7D6E, 0xB5B6, 0x7D6F, 0xDAEC, 0x7D70, 0xB5BB, 0x7D71, 0xB2CE, 0x7D72, 0xB5B7, 0x7D73, 0xB5BC, 0x7D79, 0xB868, + 0x7D7A, 0xDF5D, 0x7D7B, 0xDF5F, 0x7D7C, 0xDF61, 0x7D7D, 0xDF65, 0x7D7F, 0xDF5B, 0x7D80, 0xDF59, 0x7D81, 0xB86A, 0x7D83, 0xDF60, + 0x7D84, 0xDF64, 0x7D85, 0xDF5C, 0x7D86, 0xDF58, 0x7D88, 0xDF57, 0x7D8C, 0xDF62, 0x7D8D, 0xDF5A, 0x7D8E, 0xDF5E, 0x7D8F, 0xB86B, + 0x7D91, 0xB869, 0x7D92, 0xDF66, 0x7D93, 0xB867, 0x7D94, 0xDF63, 0x7D96, 0xE372, 0x7D9C, 0xBAEE, 0x7D9D, 0xE36A, 0x7D9E, 0xBD78, + 0x7D9F, 0xE374, 0x7DA0, 0xBAF1, 0x7DA1, 0xE378, 0x7DA2, 0xBAF7, 0x7DA3, 0xE365, 0x7DA6, 0xE375, 0x7DA7, 0xE362, 0x7DA9, 0xE377, + 0x7DAA, 0xE366, 0x7DAC, 0xBAFE, 0x7DAD, 0xBAFB, 0x7DAE, 0xE376, 0x7DAF, 0xE370, 0x7DB0, 0xBAED, 0x7DB1, 0xBAF5, 0x7DB2, 0xBAF4, + 0x7DB4, 0xBAF3, 0x7DB5, 0xBAF9, 0x7DB7, 0xE363, 0x7DB8, 0xBAFA, 0x7DB9, 0xE371, 0x7DBA, 0xBAF6, 0x7DBB, 0xBAEC, 0x7DBC, 0xE373, + 0x7DBD, 0xBAEF, 0x7DBE, 0xBAF0, 0x7DBF, 0xBAF8, 0x7DC0, 0xE368, 0x7DC1, 0xE367, 0x7DC2, 0xE364, 0x7DC4, 0xE36C, 0x7DC5, 0xE369, + 0x7DC6, 0xE36D, 0x7DC7, 0xBAFD, 0x7DC9, 0xE379, 0x7DCA, 0xBAF2, 0x7DCB, 0xE36E, 0x7DCC, 0xE36F, 0x7DCE, 0xE36B, 0x7DD2, 0xBAFC, + 0x7DD7, 0xE6E7, 0x7DD8, 0xBD70, 0x7DD9, 0xBD79, 0x7DDA, 0xBD75, 0x7DDB, 0xE6E4, 0x7DDD, 0xBD72, 0x7DDE, 0xBD76, 0x7DDF, 0xE6F0, + 0x7DE0, 0xBD6C, 0x7DE1, 0xE6E8, 0x7DE3, 0xBD74, 0x7DE6, 0xE6EB, 0x7DE7, 0xE6E6, 0x7DE8, 0xBD73, 0x7DE9, 0xBD77, 0x7DEA, 0xE6E5, + 0x7DEC, 0xBD71, 0x7DEE, 0xE6EF, 0x7DEF, 0xBD6E, 0x7DF0, 0xE6EE, 0x7DF1, 0xE6ED, 0x7DF2, 0xBD7A, 0x7DF3, 0xE572, 0x7DF4, 0xBD6D, + 0x7DF6, 0xE6EC, 0x7DF7, 0xE6E3, 0x7DF9, 0xBD7B, 0x7DFA, 0xE6EA, 0x7DFB, 0xBD6F, 0x7E03, 0xE6E9, 0x7E08, 0xBFA2, 0x7E09, 0xBFA7, + 0x7E0A, 0xBF7E, 0x7E0B, 0xEAD8, 0x7E0C, 0xEACF, 0x7E0D, 0xEADB, 0x7E0E, 0xEAD3, 0x7E0F, 0xEAD9, 0x7E10, 0xBFA8, 0x7E11, 0xBFA1, + 0x7E12, 0xEACC, 0x7E13, 0xEAD2, 0x7E14, 0xEADC, 0x7E15, 0xEAD5, 0x7E16, 0xEADA, 0x7E17, 0xEACE, 0x7E1A, 0xEAD6, 0x7E1B, 0xBFA3, + 0x7E1C, 0xEAD4, 0x7E1D, 0xBFA6, 0x7E1E, 0xBFA5, 0x7E1F, 0xEAD0, 0x7E20, 0xEAD1, 0x7E21, 0xEACD, 0x7E22, 0xEAD7, 0x7E23, 0xBFA4, + 0x7E24, 0xEADE, 0x7E25, 0xEADD, 0x7E29, 0xEDDA, 0x7E2A, 0xEDD6, 0x7E2B, 0xC15F, 0x7E2D, 0xEDD0, 0x7E2E, 0xC159, 0x7E2F, 0xC169, + 0x7E30, 0xEDDC, 0x7E31, 0xC161, 0x7E32, 0xC15D, 0x7E33, 0xEDD3, 0x7E34, 0xC164, 0x7E35, 0xC167, 0x7E36, 0xEDDE, 0x7E37, 0xC15C, + 0x7E38, 0xEDD5, 0x7E39, 0xC165, 0x7E3A, 0xEDE0, 0x7E3B, 0xEDDD, 0x7E3C, 0xEDD1, 0x7E3D, 0xC160, 0x7E3E, 0xC15A, 0x7E3F, 0xC168, + 0x7E40, 0xEDD8, 0x7E41, 0xC163, 0x7E42, 0xEDD2, 0x7E43, 0xC15E, 0x7E44, 0xEDDF, 0x7E45, 0xC162, 0x7E46, 0xC15B, 0x7E47, 0xEDD9, + 0x7E48, 0xC166, 0x7E49, 0xEDD7, 0x7E4C, 0xEDDB, 0x7E50, 0xF06E, 0x7E51, 0xF074, 0x7E52, 0xC2B9, 0x7E53, 0xF077, 0x7E54, 0xC2B4, + 0x7E55, 0xC2B5, 0x7E56, 0xF06F, 0x7E57, 0xF076, 0x7E58, 0xF071, 0x7E59, 0xC2BA, 0x7E5A, 0xC2B7, 0x7E5C, 0xF06D, 0x7E5E, 0xC2B6, + 0x7E5F, 0xF073, 0x7E60, 0xF075, 0x7E61, 0xC2B8, 0x7E62, 0xF072, 0x7E63, 0xF070, 0x7E68, 0xF2B8, 0x7E69, 0xC3B7, 0x7E6A, 0xC3B8, + 0x7E6B, 0xC3B4, 0x7E6D, 0xC3B5, 0x7E6F, 0xF2B4, 0x7E70, 0xF2B2, 0x7E72, 0xF2B6, 0x7E73, 0xC3BA, 0x7E74, 0xF2B7, 0x7E75, 0xF2B0, + 0x7E76, 0xF2AF, 0x7E77, 0xF2B3, 0x7E78, 0xF2B1, 0x7E79, 0xC3B6, 0x7E7A, 0xF2B5, 0x7E7B, 0xF4AC, 0x7E7C, 0xC47E, 0x7E7D, 0xC47D, + 0x7E7E, 0xF4AD, 0x7E80, 0xF4AF, 0x7E81, 0xF4AE, 0x7E82, 0xC4A1, 0x7E86, 0xF5EB, 0x7E87, 0xF5E8, 0x7E88, 0xF5E9, 0x7E8A, 0xF5E7, + 0x7E8B, 0xF5EA, 0x7E8C, 0xC4F2, 0x7E8D, 0xF5EC, 0x7E8F, 0xC4F1, 0x7E91, 0xF742, 0x7E93, 0xC5D5, 0x7E94, 0xC5D7, 0x7E95, 0xF7EE, + 0x7E96, 0xC5D6, 0x7E97, 0xF8B9, 0x7E98, 0xF940, 0x7E99, 0xF942, 0x7E9A, 0xF8FE, 0x7E9B, 0xF941, 0x7E9C, 0xC66C, 0x7F36, 0xA6CE, + 0x7F38, 0xACFB, 0x7F39, 0xD26F, 0x7F3A, 0xAFCA, 0x7F3D, 0xB2DA, 0x7F3E, 0xDAFC, 0x7F3F, 0xDAFD, 0x7F43, 0xEADF, 0x7F44, 0xC16A, + 0x7F45, 0xEDE1, 0x7F48, 0xC2BB, 0x7F4A, 0xF2BA, 0x7F4B, 0xF2B9, 0x7F4C, 0xC4A2, 0x7F4D, 0xF5ED, 0x7F4F, 0xF743, 0x7F50, 0xC5F8, + 0x7F51, 0xCA49, 0x7F54, 0xAAC9, 0x7F55, 0xA875, 0x7F58, 0xD04D, 0x7F5B, 0xD360, 0x7F5C, 0xD35B, 0x7F5D, 0xD35F, 0x7F5E, 0xD35D, + 0x7F5F, 0xAFCB, 0x7F60, 0xD35E, 0x7F61, 0xD35C, 0x7F63, 0xD6F1, 0x7F65, 0xDAFE, 0x7F66, 0xDB40, 0x7F67, 0xDF69, 0x7F68, 0xDF6A, + 0x7F69, 0xB86E, 0x7F6A, 0xB86F, 0x7F6B, 0xDF68, 0x7F6C, 0xDF6B, 0x7F6D, 0xDF67, 0x7F6E, 0xB86D, 0x7F70, 0xBB40, 0x7F72, 0xB870, + 0x7F73, 0xE37A, 0x7F75, 0xBD7C, 0x7F76, 0xE6F1, 0x7F77, 0xBD7D, 0x7F79, 0xBFA9, 0x7F7A, 0xEAE2, 0x7F7B, 0xEAE0, 0x7F7C, 0xEAE1, + 0x7F7D, 0xEDE4, 0x7F7E, 0xEDE3, 0x7F7F, 0xEDE2, 0x7F83, 0xF2BB, 0x7F85, 0xC3B9, 0x7F86, 0xF2BC, 0x7F87, 0xF744, 0x7F88, 0xC5F9, + 0x7F89, 0xF8BA, 0x7F8A, 0xA6CF, 0x7F8B, 0xAACB, 0x7F8C, 0xAACA, 0x7F8D, 0xD04F, 0x7F8E, 0xACFC, 0x7F91, 0xD04E, 0x7F92, 0xD362, + 0x7F94, 0xAFCC, 0x7F95, 0xD6F2, 0x7F96, 0xD361, 0x7F9A, 0xB2DC, 0x7F9B, 0xD6F5, 0x7F9C, 0xD6F3, 0x7F9D, 0xD6F4, 0x7F9E, 0xB2DB, + 0x7FA0, 0xDB42, 0x7FA1, 0xDB43, 0x7FA2, 0xDB41, 0x7FA4, 0xB873, 0x7FA5, 0xDF6D, 0x7FA6, 0xDF6C, 0x7FA7, 0xDF6E, 0x7FA8, 0xB872, + 0x7FA9, 0xB871, 0x7FAC, 0xE6F2, 0x7FAD, 0xE6F4, 0x7FAF, 0xBD7E, 0x7FB0, 0xE6F3, 0x7FB1, 0xEAE3, 0x7FB2, 0xBFAA, 0x7FB3, 0xF079, + 0x7FB5, 0xF078, 0x7FB6, 0xC3BB, 0x7FB7, 0xF2BD, 0x7FB8, 0xC3BD, 0x7FB9, 0xC3BC, 0x7FBA, 0xF4B0, 0x7FBB, 0xF5EE, 0x7FBC, 0xC4F3, + 0x7FBD, 0xA6D0, 0x7FBE, 0xD050, 0x7FBF, 0xACFD, 0x7FC0, 0xD365, 0x7FC1, 0xAFCE, 0x7FC2, 0xD364, 0x7FC3, 0xD363, 0x7FC5, 0xAFCD, + 0x7FC7, 0xD6FB, 0x7FC9, 0xD6FD, 0x7FCA, 0xD6F6, 0x7FCB, 0xD6F7, 0x7FCC, 0xB2DD, 0x7FCD, 0xD6F8, 0x7FCE, 0xB2DE, 0x7FCF, 0xD6FC, + 0x7FD0, 0xD6F9, 0x7FD1, 0xD6FA, 0x7FD2, 0xB2DF, 0x7FD4, 0xB5BE, 0x7FD5, 0xB5BF, 0x7FD7, 0xDB44, 0x7FDB, 0xDF6F, 0x7FDC, 0xDF70, + 0x7FDE, 0xE37E, 0x7FDF, 0xBB43, 0x7FE0, 0xBB41, 0x7FE1, 0xBB42, 0x7FE2, 0xE37B, 0x7FE3, 0xE37C, 0x7FE5, 0xE37D, 0x7FE6, 0xE6F9, + 0x7FE8, 0xE6FA, 0x7FE9, 0xBDA1, 0x7FEA, 0xE6F7, 0x7FEB, 0xE6F6, 0x7FEC, 0xE6F8, 0x7FED, 0xE6F5, 0x7FEE, 0xBFAD, 0x7FEF, 0xEAE4, + 0x7FF0, 0xBFAB, 0x7FF1, 0xBFAC, 0x7FF2, 0xEDE6, 0x7FF3, 0xC16B, 0x7FF4, 0xEDE5, 0x7FF5, 0xEFA8, 0x7FF7, 0xF07A, 0x7FF8, 0xF07B, + 0x7FF9, 0xC2BC, 0x7FFB, 0xC2BD, 0x7FFC, 0xC16C, 0x7FFD, 0xF2BE, 0x7FFE, 0xF2BF, 0x7FFF, 0xF4B1, 0x8000, 0xC4A3, 0x8001, 0xA6D1, + 0x8003, 0xA6D2, 0x8004, 0xACFE, 0x8005, 0xAACC, 0x8006, 0xAFCF, 0x8007, 0xD051, 0x800B, 0xB5C0, 0x800C, 0xA6D3, 0x800D, 0xAD41, + 0x800E, 0xD052, 0x800F, 0xD053, 0x8010, 0xAD40, 0x8011, 0xAD42, 0x8012, 0xA6D4, 0x8014, 0xD054, 0x8015, 0xAFD1, 0x8016, 0xD366, + 0x8017, 0xAFD3, 0x8018, 0xAFD0, 0x8019, 0xAFD2, 0x801B, 0xD741, 0x801C, 0xB2E0, 0x801E, 0xD740, 0x801F, 0xD6FE, 0x8021, 0xDF71, + 0x8024, 0xE3A1, 0x8026, 0xBDA2, 0x8028, 0xBFAE, 0x8029, 0xEAE6, 0x802A, 0xEAE5, 0x802C, 0xEDE7, 0x8030, 0xF5EF, 0x8033, 0xA6D5, + 0x8034, 0xCB73, 0x8035, 0xCDAA, 0x8036, 0xAD43, 0x8037, 0xD055, 0x8039, 0xD368, 0x803D, 0xAFD4, 0x803E, 0xD367, 0x803F, 0xAFD5, + 0x8043, 0xD743, 0x8046, 0xB2E2, 0x8047, 0xD742, 0x8048, 0xD744, 0x804A, 0xB2E1, 0x804F, 0xDB46, 0x8050, 0xDB47, 0x8051, 0xDB45, + 0x8052, 0xB5C1, 0x8056, 0xB874, 0x8058, 0xB875, 0x805A, 0xBB45, 0x805C, 0xE3A3, 0x805D, 0xE3A2, 0x805E, 0xBB44, 0x8064, 0xE6FB, + 0x8067, 0xE6FC, 0x806C, 0xEAE7, 0x806F, 0xC170, 0x8070, 0xC16F, 0x8071, 0xC16D, 0x8072, 0xC16E, 0x8073, 0xC171, 0x8075, 0xF07C, + 0x8076, 0xC2BF, 0x8077, 0xC2BE, 0x8078, 0xF2C0, 0x8079, 0xF4B2, 0x807D, 0xC5A5, 0x807E, 0xC5A4, 0x807F, 0xA6D6, 0x8082, 0xD1FB, + 0x8084, 0xB877, 0x8085, 0xB5C2, 0x8086, 0xB876, 0x8087, 0xBB46, 0x8089, 0xA6D7, 0x808A, 0xC9A9, 0x808B, 0xA6D8, 0x808C, 0xA6D9, + 0x808F, 0xCDAB, 0x8090, 0xCB76, 0x8092, 0xCB77, 0x8093, 0xA877, 0x8095, 0xCB74, 0x8096, 0xA876, 0x8098, 0xA879, 0x8099, 0xCB75, + 0x809A, 0xA87B, 0x809B, 0xA87A, 0x809C, 0xCB78, 0x809D, 0xA878, 0x80A1, 0xAAD1, 0x80A2, 0xAACF, 0x80A3, 0xCDAD, 0x80A5, 0xAACE, + 0x80A9, 0xAAD3, 0x80AA, 0xAAD5, 0x80AB, 0xAAD2, 0x80AD, 0xCDB0, 0x80AE, 0xCDAC, 0x80AF, 0xAAD6, 0x80B1, 0xAAD0, 0x80B2, 0xA87C, + 0x80B4, 0xAAD4, 0x80B5, 0xCDAF, 0x80B8, 0xCDAE, 0x80BA, 0xAACD, 0x80C2, 0xD05B, 0x80C3, 0xAD47, 0x80C4, 0xAD48, 0x80C5, 0xD05D, + 0x80C7, 0xD057, 0x80C8, 0xD05A, 0x80C9, 0xD063, 0x80CA, 0xD061, 0x80CC, 0xAD49, 0x80CD, 0xD067, 0x80CE, 0xAD4C, 0x80CF, 0xD064, + 0x80D0, 0xD05C, 0x80D1, 0xD059, 0x80D4, 0xDB49, 0x80D5, 0xD062, 0x80D6, 0xAD44, 0x80D7, 0xD065, 0x80D8, 0xD056, 0x80D9, 0xD05F, + 0x80DA, 0xAD46, 0x80DB, 0xAD4B, 0x80DC, 0xD060, 0x80DD, 0xAD4F, 0x80DE, 0xAD4D, 0x80E0, 0xD058, 0x80E1, 0xAD4A, 0x80E3, 0xD05E, + 0x80E4, 0xAD4E, 0x80E5, 0xAD45, 0x80E6, 0xD066, 0x80ED, 0xAFDA, 0x80EF, 0xAFE3, 0x80F0, 0xAFD8, 0x80F1, 0xAFD6, 0x80F2, 0xD36A, + 0x80F3, 0xAFDE, 0x80F4, 0xAFDB, 0x80F5, 0xD36C, 0x80F8, 0xAFDD, 0x80F9, 0xD36B, 0x80FA, 0xD369, 0x80FB, 0xD36E, 0x80FC, 0xAFE2, + 0x80FD, 0xAFE0, 0x80FE, 0xDB48, 0x8100, 0xD36F, 0x8101, 0xD36D, 0x8102, 0xAFD7, 0x8105, 0xAFD9, 0x8106, 0xAFDC, 0x8108, 0xAFDF, + 0x810A, 0xAFE1, 0x8115, 0xD74E, 0x8116, 0xB2E4, 0x8118, 0xD745, 0x8119, 0xD747, 0x811B, 0xD748, 0x811D, 0xD750, 0x811E, 0xD74C, + 0x811F, 0xD74A, 0x8121, 0xD74D, 0x8122, 0xD751, 0x8123, 0xB2E5, 0x8124, 0xB2E9, 0x8125, 0xD746, 0x8127, 0xD74F, 0x8129, 0xB2E7, + 0x812B, 0xB2E6, 0x812C, 0xD74B, 0x812D, 0xD749, 0x812F, 0xB2E3, 0x8130, 0xB2E8, 0x8139, 0xB5C8, 0x813A, 0xDB51, 0x813D, 0xDB4F, + 0x813E, 0xB5CA, 0x8143, 0xDB4A, 0x8144, 0xDFA1, 0x8146, 0xB5C9, 0x8147, 0xDB4E, 0x814A, 0xDB4B, 0x814B, 0xB5C5, 0x814C, 0xB5CB, + 0x814D, 0xDB50, 0x814E, 0xB5C7, 0x814F, 0xDB4D, 0x8150, 0xBB47, 0x8151, 0xB5C6, 0x8152, 0xDB4C, 0x8153, 0xB5CC, 0x8154, 0xB5C4, + 0x8155, 0xB5C3, 0x815B, 0xDF77, 0x815C, 0xDF75, 0x815E, 0xDF7B, 0x8160, 0xDF73, 0x8161, 0xDFA2, 0x8162, 0xDF78, 0x8164, 0xDF72, + 0x8165, 0xB87B, 0x8166, 0xB8A3, 0x8167, 0xDF7D, 0x8169, 0xDF76, 0x816B, 0xB87E, 0x816E, 0xB87C, 0x816F, 0xDF7E, 0x8170, 0xB879, + 0x8171, 0xB878, 0x8172, 0xDF79, 0x8173, 0xB87D, 0x8174, 0xB5CD, 0x8176, 0xDF7C, 0x8177, 0xDF74, 0x8178, 0xB87A, 0x8179, 0xB8A1, + 0x817A, 0xB8A2, 0x817F, 0xBB4C, 0x8180, 0xBB48, 0x8182, 0xBB4D, 0x8183, 0xE3A6, 0x8186, 0xE3A5, 0x8187, 0xE3A7, 0x8188, 0xBB4A, + 0x8189, 0xE3A4, 0x818A, 0xBB4B, 0x818B, 0xE3AA, 0x818C, 0xE3A9, 0x818D, 0xE3A8, 0x818F, 0xBB49, 0x8195, 0xE741, 0x8197, 0xE744, + 0x8198, 0xBDA8, 0x8199, 0xE743, 0x819A, 0xBDA7, 0x819B, 0xBDA3, 0x819C, 0xBDA4, 0x819D, 0xBDA5, 0x819E, 0xE740, 0x819F, 0xE6FE, + 0x81A0, 0xBDA6, 0x81A2, 0xE742, 0x81A3, 0xE6FD, 0x81A6, 0xEAE9, 0x81A7, 0xEAF3, 0x81A8, 0xBFB1, 0x81A9, 0xBFB0, 0x81AB, 0xEAED, + 0x81AC, 0xEAEF, 0x81AE, 0xEAEA, 0x81B0, 0xEAEE, 0x81B1, 0xEAE8, 0x81B2, 0xEAF1, 0x81B3, 0xBFAF, 0x81B4, 0xEAF0, 0x81B5, 0xEAEC, + 0x81B7, 0xEAF2, 0x81B9, 0xEAEB, 0x81BA, 0xC174, 0x81BB, 0xEDE8, 0x81BC, 0xEDEE, 0x81BD, 0xC178, 0x81BE, 0xC17A, 0x81BF, 0xC177, + 0x81C0, 0xC176, 0x81C2, 0xC175, 0x81C3, 0xC173, 0x81C4, 0xEDE9, 0x81C5, 0xEDEC, 0x81C6, 0xC172, 0x81C7, 0xEDED, 0x81C9, 0xC179, + 0x81CA, 0xEDEB, 0x81CC, 0xEDEA, 0x81CD, 0xC2C0, 0x81CF, 0xC2C1, 0x81D0, 0xF0A1, 0x81D1, 0xF07D, 0x81D2, 0xF07E, 0x81D5, 0xF2C2, + 0x81D7, 0xF2C1, 0x81D8, 0xC3BE, 0x81D9, 0xF4B4, 0x81DA, 0xC4A4, 0x81DB, 0xF4B3, 0x81DD, 0xF5F0, 0x81DE, 0xF745, 0x81DF, 0xC5A6, + 0x81E0, 0xF943, 0x81E1, 0xF944, 0x81E2, 0xC5D8, 0x81E3, 0xA6DA, 0x81E5, 0xAAD7, 0x81E6, 0xDB52, 0x81E7, 0xBB4E, 0x81E8, 0xC17B, + 0x81E9, 0xEDEF, 0x81EA, 0xA6DB, 0x81EC, 0xAFE5, 0x81ED, 0xAFE4, 0x81EE, 0xDB53, 0x81F2, 0xEAF4, 0x81F3, 0xA6DC, 0x81F4, 0xAD50, + 0x81F7, 0xDB54, 0x81F8, 0xDB55, 0x81F9, 0xDB56, 0x81FA, 0xBB4F, 0x81FB, 0xBFB2, 0x81FC, 0xA6DD, 0x81FE, 0xAAD8, 0x81FF, 0xD068, + 0x8200, 0xAFE6, 0x8201, 0xD370, 0x8202, 0xB2EA, 0x8204, 0xDB57, 0x8205, 0xB8A4, 0x8207, 0xBB50, 0x8208, 0xBFB3, 0x8209, 0xC17C, + 0x820A, 0xC2C2, 0x820B, 0xF4B5, 0x820C, 0xA6DE, 0x820D, 0xAAD9, 0x8210, 0xAFE7, 0x8211, 0xD752, 0x8212, 0xB5CE, 0x8214, 0xBB51, + 0x8215, 0xE3AB, 0x8216, 0xE745, 0x821B, 0xA6DF, 0x821C, 0xB5CF, 0x821D, 0xDFA3, 0x821E, 0xBB52, 0x821F, 0xA6E0, 0x8220, 0xCDB1, + 0x8221, 0xD069, 0x8222, 0xAD51, 0x8225, 0xD372, 0x8228, 0xAFEA, 0x822A, 0xAFE8, 0x822B, 0xAFE9, 0x822C, 0xAFEB, 0x822F, 0xD371, + 0x8232, 0xD757, 0x8233, 0xD754, 0x8234, 0xD756, 0x8235, 0xB2EB, 0x8236, 0xB2ED, 0x8237, 0xB2EC, 0x8238, 0xD753, 0x8239, 0xB2EE, + 0x823A, 0xD755, 0x823C, 0xDB58, 0x823D, 0xDB59, 0x823F, 0xDB5A, 0x8240, 0xDFA6, 0x8242, 0xDFA7, 0x8244, 0xDFA5, 0x8245, 0xDFA8, + 0x8247, 0xB8A5, 0x8249, 0xDFA4, 0x824B, 0xBB53, 0x824E, 0xE74A, 0x824F, 0xE746, 0x8250, 0xE749, 0x8251, 0xE74B, 0x8252, 0xE748, + 0x8253, 0xE747, 0x8255, 0xEAF5, 0x8256, 0xEAF6, 0x8257, 0xEAF7, 0x8258, 0xBFB4, 0x8259, 0xBFB5, 0x825A, 0xEDF1, 0x825B, 0xEDF0, + 0x825C, 0xEDF2, 0x825E, 0xF0A3, 0x825F, 0xF0A2, 0x8261, 0xF2C4, 0x8263, 0xF2C5, 0x8264, 0xF2C3, 0x8266, 0xC4A5, 0x8268, 0xF4B6, + 0x8269, 0xF4B7, 0x826B, 0xF746, 0x826C, 0xF7EF, 0x826D, 0xF8BB, 0x826E, 0xA6E1, 0x826F, 0xA87D, 0x8271, 0xC17D, 0x8272, 0xA6E2, + 0x8274, 0xD758, 0x8275, 0xDB5B, 0x8277, 0xC641, 0x8278, 0xCA4A, 0x827C, 0xCA4B, 0x827D, 0xCA4D, 0x827E, 0xA6E3, 0x827F, 0xCA4E, + 0x8280, 0xCA4C, 0x8283, 0xCBA2, 0x8284, 0xCBA3, 0x8285, 0xCB7B, 0x828A, 0xCBA1, 0x828B, 0xA8A1, 0x828D, 0xA8A2, 0x828E, 0xCB7C, + 0x828F, 0xCB7A, 0x8290, 0xCB79, 0x8291, 0xCB7D, 0x8292, 0xA87E, 0x8293, 0xCB7E, 0x8294, 0xD06A, 0x8298, 0xCDB6, 0x8299, 0xAADC, + 0x829A, 0xCDB5, 0x829B, 0xCDB7, 0x829D, 0xAADB, 0x829E, 0xCDBC, 0x829F, 0xAADF, 0x82A0, 0xCDB2, 0x82A1, 0xCDC0, 0x82A2, 0xCDC6, + 0x82A3, 0xAAE6, 0x82A4, 0xCDC3, 0x82A5, 0xAAE3, 0x82A7, 0xCDB9, 0x82A8, 0xCDBF, 0x82A9, 0xCDC1, 0x82AB, 0xCDB4, 0x82AC, 0xAAE2, + 0x82AD, 0xAADD, 0x82AE, 0xCDBA, 0x82AF, 0xAAE4, 0x82B0, 0xAAE7, 0x82B1, 0xAAE1, 0x82B3, 0xAADA, 0x82B4, 0xCDBE, 0x82B5, 0xCDB8, + 0x82B6, 0xCDC5, 0x82B7, 0xAAE9, 0x82B8, 0xAAE5, 0x82B9, 0xAAE0, 0x82BA, 0xCDBD, 0x82BB, 0xAFEC, 0x82BC, 0xCDBB, 0x82BD, 0xAADE, + 0x82BE, 0xAAE8, 0x82C0, 0xCDB3, 0x82C2, 0xCDC2, 0x82C3, 0xCDC4, 0x82D1, 0xAD62, 0x82D2, 0xAD5C, 0x82D3, 0xAD64, 0x82D4, 0xAD61, + 0x82D5, 0xD071, 0x82D6, 0xD074, 0x82D7, 0xAD5D, 0x82D9, 0xD06B, 0x82DB, 0xAD56, 0x82DC, 0xAD60, 0x82DE, 0xAD63, 0x82DF, 0xAD65, + 0x82E0, 0xD0A2, 0x82E1, 0xD077, 0x82E3, 0xAD55, 0x82E4, 0xD0A1, 0x82E5, 0xAD59, 0x82E6, 0xAD57, 0x82E7, 0xAD52, 0x82E8, 0xD06F, + 0x82EA, 0xD07E, 0x82EB, 0xD073, 0x82EC, 0xD076, 0x82ED, 0xD0A5, 0x82EF, 0xAD66, 0x82F0, 0xD07D, 0x82F1, 0xAD5E, 0x82F2, 0xD078, + 0x82F3, 0xD0A4, 0x82F4, 0xD075, 0x82F5, 0xD079, 0x82F6, 0xD07C, 0x82F9, 0xD06D, 0x82FA, 0xD0A3, 0x82FB, 0xD07B, 0x82FE, 0xD06C, + 0x8300, 0xD070, 0x8301, 0xAD5F, 0x8302, 0xAD5A, 0x8303, 0xAD53, 0x8304, 0xAD58, 0x8305, 0xAD54, 0x8306, 0xAD67, 0x8307, 0xD06E, + 0x8308, 0xD3A5, 0x8309, 0xAD5B, 0x830C, 0xD07A, 0x830D, 0xCE41, 0x8316, 0xD3A8, 0x8317, 0xAFFA, 0x8319, 0xD376, 0x831B, 0xD3A3, + 0x831C, 0xD37D, 0x831E, 0xD3B2, 0x8320, 0xD3AA, 0x8322, 0xD37E, 0x8324, 0xD3A9, 0x8325, 0xD378, 0x8326, 0xD37C, 0x8327, 0xD3B5, + 0x8328, 0xAFFD, 0x8329, 0xD3AD, 0x832A, 0xD3A4, 0x832B, 0xAFED, 0x832C, 0xD3B3, 0x832D, 0xD374, 0x832F, 0xD3AC, 0x8331, 0xAFFC, + 0x8332, 0xAFF7, 0x8333, 0xD373, 0x8334, 0xAFF5, 0x8335, 0xAFF4, 0x8336, 0xAFF9, 0x8337, 0xD3AB, 0x8338, 0xAFF1, 0x8339, 0xAFF8, + 0x833A, 0xD072, 0x833B, 0xDB5C, 0x833C, 0xD3A6, 0x833F, 0xD37A, 0x8340, 0xAFFB, 0x8341, 0xD37B, 0x8342, 0xD3A1, 0x8343, 0xAFFE, + 0x8344, 0xD375, 0x8345, 0xD3AF, 0x8347, 0xD3AE, 0x8348, 0xD3B6, 0x8349, 0xAFF3, 0x834A, 0xAFF0, 0x834B, 0xD3B4, 0x834C, 0xD3B0, + 0x834D, 0xD3A7, 0x834E, 0xD3A2, 0x834F, 0xAFF6, 0x8350, 0xAFF2, 0x8351, 0xD377, 0x8352, 0xAFEE, 0x8353, 0xD3B1, 0x8354, 0xAFEF, + 0x8356, 0xD379, 0x8373, 0xD75E, 0x8374, 0xD760, 0x8375, 0xD765, 0x8376, 0xD779, 0x8377, 0xB2FC, 0x8378, 0xB2F2, 0x837A, 0xD75D, + 0x837B, 0xB2FD, 0x837C, 0xB2FE, 0x837D, 0xD768, 0x837E, 0xD76F, 0x837F, 0xD775, 0x8381, 0xD762, 0x8383, 0xD769, 0x8386, 0xB340, + 0x8387, 0xD777, 0x8388, 0xD772, 0x8389, 0xB2FA, 0x838A, 0xB2F8, 0x838B, 0xD76E, 0x838C, 0xD76A, 0x838D, 0xD75C, 0x838E, 0xB2EF, + 0x838F, 0xD761, 0x8390, 0xD759, 0x8392, 0xB2F7, 0x8393, 0xB2F9, 0x8394, 0xD766, 0x8395, 0xD763, 0x8396, 0xB2F4, 0x8397, 0xD773, + 0x8398, 0xB2F1, 0x8399, 0xD764, 0x839A, 0xD77A, 0x839B, 0xD76C, 0x839D, 0xD76B, 0x839E, 0xB2F0, 0x83A0, 0xB2FB, 0x83A2, 0xB2F3, + 0x83A3, 0xD75A, 0x83A4, 0xD75F, 0x83A5, 0xD770, 0x83A6, 0xD776, 0x83A7, 0xB341, 0x83A8, 0xD75B, 0x83A9, 0xD767, 0x83AA, 0xD76D, + 0x83AB, 0xB2F6, 0x83AE, 0xD778, 0x83AF, 0xD771, 0x83B0, 0xD774, 0x83BD, 0xB2F5, 0x83BF, 0xDB6C, 0x83C0, 0xDB60, 0x83C1, 0xB5D7, + 0x83C2, 0xDB7D, 0x83C3, 0xDBA7, 0x83C4, 0xDBAA, 0x83C5, 0xB5D5, 0x83C6, 0xDB68, 0x83C7, 0xDBA3, 0x83C8, 0xDB69, 0x83C9, 0xDB77, + 0x83CA, 0xB5E2, 0x83CB, 0xDB73, 0x83CC, 0xB5DF, 0x83CE, 0xDB74, 0x83CF, 0xDB5D, 0x83D1, 0xDBA4, 0x83D4, 0xB5E8, 0x83D5, 0xDBA1, + 0x83D6, 0xDB75, 0x83D7, 0xDBAC, 0x83D8, 0xDB70, 0x83D9, 0xDFC8, 0x83DB, 0xDBAF, 0x83DC, 0xB5E6, 0x83DD, 0xDB6E, 0x83DE, 0xDB7A, + 0x83DF, 0xB5E9, 0x83E0, 0xB5D4, 0x83E1, 0xDB72, 0x83E2, 0xDBAD, 0x83E3, 0xDB6B, 0x83E4, 0xDB64, 0x83E5, 0xDB6F, 0x83E7, 0xDB63, + 0x83E8, 0xDB61, 0x83E9, 0xB5D0, 0x83EA, 0xDBA5, 0x83EB, 0xDB6A, 0x83EC, 0xDBA8, 0x83EE, 0xDBA9, 0x83EF, 0xB5D8, 0x83F0, 0xB5DD, + 0x83F1, 0xB5D9, 0x83F2, 0xB5E1, 0x83F3, 0xDB7E, 0x83F4, 0xB5DA, 0x83F5, 0xDB76, 0x83F6, 0xDB66, 0x83F8, 0xB5D2, 0x83F9, 0xDB5E, + 0x83FA, 0xDBA2, 0x83FB, 0xDBAB, 0x83FC, 0xDB65, 0x83FD, 0xB5E0, 0x83FE, 0xDBB0, 0x83FF, 0xDB71, 0x8401, 0xDB6D, 0x8403, 0xB5D1, + 0x8404, 0xB5E5, 0x8406, 0xDB7C, 0x8407, 0xB5E7, 0x8409, 0xDB78, 0x840A, 0xB5DC, 0x840B, 0xB5D6, 0x840C, 0xB5DE, 0x840D, 0xB5D3, + 0x840E, 0xB5E4, 0x840F, 0xDB79, 0x8410, 0xDB67, 0x8411, 0xDB7B, 0x8412, 0xDB62, 0x8413, 0xDBA6, 0x841B, 0xDBAE, 0x8423, 0xDB5F, + 0x8429, 0xDFC7, 0x842B, 0xDFDD, 0x842C, 0xB855, 0x842D, 0xDFCC, 0x842F, 0xDFCA, 0x8430, 0xDFB5, 0x8431, 0xB8A9, 0x8432, 0xDFC5, + 0x8433, 0xDFD9, 0x8434, 0xDFC1, 0x8435, 0xB8B1, 0x8436, 0xDFD8, 0x8437, 0xDFBF, 0x8438, 0xB5E3, 0x8439, 0xDFCF, 0x843A, 0xDFC0, + 0x843B, 0xDFD6, 0x843C, 0xB8B0, 0x843D, 0xB8A8, 0x843F, 0xDFAA, 0x8440, 0xDFB2, 0x8442, 0xDFCB, 0x8443, 0xDFC3, 0x8444, 0xDFDC, + 0x8445, 0xDFC6, 0x8446, 0xB8B6, 0x8447, 0xDFD7, 0x8449, 0xB8AD, 0x844B, 0xDFC9, 0x844C, 0xDFD1, 0x844D, 0xDFB6, 0x844E, 0xDFD0, + 0x8450, 0xDFE1, 0x8451, 0xDFB1, 0x8452, 0xDFD2, 0x8454, 0xDFDF, 0x8456, 0xDFAB, 0x8457, 0xB5DB, 0x8459, 0xDFB9, 0x845A, 0xDFB8, + 0x845B, 0xB8AF, 0x845D, 0xDFBC, 0x845E, 0xDFBE, 0x845F, 0xDFCD, 0x8460, 0xDFDE, 0x8461, 0xB8B2, 0x8463, 0xB8B3, 0x8465, 0xDFB0, + 0x8466, 0xB8AB, 0x8467, 0xDFB4, 0x8468, 0xDFDA, 0x8469, 0xB8B4, 0x846B, 0xB8AC, 0x846C, 0xB8AE, 0x846D, 0xB8B5, 0x846E, 0xDFE0, + 0x846F, 0xDFD3, 0x8470, 0xDFCE, 0x8473, 0xDFBB, 0x8474, 0xDFBA, 0x8475, 0xB8AA, 0x8476, 0xDFAC, 0x8477, 0xB8A7, 0x8478, 0xDFC4, + 0x8479, 0xDFAD, 0x847A, 0xDFC2, 0x847D, 0xDFB7, 0x847E, 0xDFDB, 0x8482, 0xB8A6, 0x8486, 0xDFB3, 0x848D, 0xDFAF, 0x848E, 0xDFD5, + 0x848F, 0xDFAE, 0x8490, 0xBB60, 0x8491, 0xE3D3, 0x8494, 0xE3C2, 0x8497, 0xE3AC, 0x8498, 0xE3CA, 0x8499, 0xBB58, 0x849A, 0xE3BB, + 0x849B, 0xE3C5, 0x849C, 0xBB5B, 0x849D, 0xE3BE, 0x849E, 0xBB59, 0x849F, 0xE3AF, 0x84A0, 0xE3CD, 0x84A1, 0xE3AE, 0x84A2, 0xE3C1, + 0x84A4, 0xE3AD, 0x84A7, 0xE3BF, 0x84A8, 0xE3C8, 0x84A9, 0xE3C6, 0x84AA, 0xE3BA, 0x84AB, 0xE3B5, 0x84AC, 0xE3B3, 0x84AE, 0xE3B4, + 0x84AF, 0xE3C7, 0x84B0, 0xE3D2, 0x84B1, 0xE3BC, 0x84B2, 0xBB5A, 0x84B4, 0xE3B7, 0x84B6, 0xE3CB, 0x84B8, 0xBB5D, 0x84B9, 0xE3B6, + 0x84BA, 0xE3B0, 0x84BB, 0xE3C0, 0x84BC, 0xBB61, 0x84BF, 0xBB55, 0x84C0, 0xBB5E, 0x84C1, 0xE3B8, 0x84C2, 0xE3B2, 0x84C4, 0xBB57, + 0x84C5, 0xDFD4, 0x84C6, 0xBB56, 0x84C7, 0xE3C3, 0x84C9, 0xBB54, 0x84CA, 0xBB63, 0x84CB, 0xBB5C, 0x84CC, 0xE3C4, 0x84CD, 0xE3B9, + 0x84CE, 0xE3B1, 0x84CF, 0xE3CC, 0x84D0, 0xE3BD, 0x84D1, 0xBB62, 0x84D2, 0xE3D0, 0x84D3, 0xBB5F, 0x84D4, 0xE3CF, 0x84D6, 0xE3C9, + 0x84D7, 0xE3CE, 0x84DB, 0xE3D1, 0x84E7, 0xE773, 0x84E8, 0xE774, 0x84E9, 0xE767, 0x84EA, 0xE766, 0x84EB, 0xE762, 0x84EC, 0xBDB4, + 0x84EE, 0xBDAC, 0x84EF, 0xE776, 0x84F0, 0xE775, 0x84F1, 0xDFA9, 0x84F2, 0xE75F, 0x84F3, 0xE763, 0x84F4, 0xE75D, 0x84F6, 0xE770, + 0x84F7, 0xE761, 0x84F9, 0xE777, 0x84FA, 0xE75A, 0x84FB, 0xE758, 0x84FC, 0xE764, 0x84FD, 0xE76E, 0x84FE, 0xE769, 0x84FF, 0xBDB6, + 0x8500, 0xE74F, 0x8502, 0xE76D, 0x8506, 0xBDB7, 0x8507, 0xDFBD, 0x8508, 0xE75B, 0x8509, 0xE752, 0x850A, 0xE755, 0x850B, 0xE77B, + 0x850C, 0xE75C, 0x850D, 0xE753, 0x850E, 0xE751, 0x850F, 0xE74E, 0x8511, 0xBDB0, 0x8512, 0xE765, 0x8513, 0xBDAF, 0x8514, 0xBDB3, + 0x8515, 0xE760, 0x8516, 0xE768, 0x8517, 0xBDA9, 0x8518, 0xE778, 0x8519, 0xE77C, 0x851A, 0xBDAB, 0x851C, 0xE757, 0x851D, 0xE76B, + 0x851E, 0xE76F, 0x851F, 0xE754, 0x8520, 0xE779, 0x8521, 0xBDB2, 0x8523, 0xBDB1, 0x8524, 0xE74C, 0x8525, 0xBDB5, 0x8526, 0xE772, + 0x8527, 0xE756, 0x8528, 0xE76A, 0x8529, 0xE750, 0x852A, 0xE75E, 0x852B, 0xE759, 0x852C, 0xBDAD, 0x852D, 0xBDAE, 0x852E, 0xE76C, + 0x852F, 0xE77D, 0x8530, 0xE77A, 0x8531, 0xE771, 0x853B, 0xE74D, 0x853D, 0xBDAA, 0x853E, 0xEB49, 0x8540, 0xEB40, 0x8541, 0xEB43, + 0x8543, 0xBFBB, 0x8544, 0xEB45, 0x8545, 0xEAF9, 0x8546, 0xEB41, 0x8547, 0xEB47, 0x8548, 0xBFB8, 0x8549, 0xBFBC, 0x854A, 0xBFB6, + 0x854D, 0xEAFB, 0x854E, 0xEB4C, 0x8551, 0xEB46, 0x8553, 0xEAFC, 0x8554, 0xEB55, 0x8555, 0xEB4F, 0x8556, 0xEAF8, 0x8557, 0xEE46, + 0x8558, 0xEAFE, 0x8559, 0xBFB7, 0x855B, 0xEB4A, 0x855D, 0xEB54, 0x855E, 0xBFBF, 0x8560, 0xEB51, 0x8561, 0xEAFD, 0x8562, 0xEB44, + 0x8563, 0xEB48, 0x8564, 0xEB42, 0x8565, 0xEB56, 0x8566, 0xEB53, 0x8567, 0xEB50, 0x8568, 0xBFB9, 0x8569, 0xBFBA, 0x856A, 0xBFBE, + 0x856B, 0xEAFA, 0x856C, 0xEB57, 0x856D, 0xBFBD, 0x856E, 0xEB4D, 0x8571, 0xEB4B, 0x8575, 0xEB4E, 0x8576, 0xEE53, 0x8577, 0xEE40, + 0x8578, 0xEE45, 0x8579, 0xEE52, 0x857A, 0xEE44, 0x857B, 0xEDFB, 0x857C, 0xEE41, 0x857E, 0xC1A2, 0x8580, 0xEDF4, 0x8581, 0xEE4D, + 0x8582, 0xEE4F, 0x8583, 0xEDF3, 0x8584, 0xC1A1, 0x8585, 0xEE51, 0x8586, 0xEE49, 0x8587, 0xC1A8, 0x8588, 0xEE50, 0x8589, 0xEE42, + 0x858A, 0xC1AA, 0x858B, 0xEDF9, 0x858C, 0xEB52, 0x858D, 0xEE4A, 0x858E, 0xEE47, 0x858F, 0xEDF5, 0x8590, 0xEE55, 0x8591, 0xC1A4, + 0x8594, 0xC1A5, 0x8595, 0xEDF7, 0x8596, 0xEE48, 0x8598, 0xEE54, 0x8599, 0xEE4B, 0x859A, 0xEDFD, 0x859B, 0xC1A7, 0x859C, 0xC1A3, + 0x859D, 0xEE4C, 0x859E, 0xEDFE, 0x859F, 0xEE56, 0x85A0, 0xEDF8, 0x85A1, 0xEE43, 0x85A2, 0xEE4E, 0x85A3, 0xEDFA, 0x85A4, 0xEDFC, + 0x85A6, 0xC2CB, 0x85A7, 0xEDF6, 0x85A8, 0xC1A9, 0x85A9, 0xC2C4, 0x85AA, 0xC17E, 0x85AF, 0xC1A6, 0x85B0, 0xC2C8, 0x85B1, 0xF0B3, + 0x85B3, 0xF0A9, 0x85B4, 0xF0A4, 0x85B5, 0xF0AA, 0x85B6, 0xF0B4, 0x85B7, 0xF0B8, 0x85B8, 0xF0B7, 0x85B9, 0xC2CA, 0x85BA, 0xC2C9, + 0x85BD, 0xF0AB, 0x85BE, 0xF0B9, 0x85BF, 0xF0AE, 0x85C0, 0xF0A6, 0x85C2, 0xF0A8, 0x85C3, 0xF0A7, 0x85C4, 0xF0AD, 0x85C5, 0xF0B2, + 0x85C6, 0xF0A5, 0x85C7, 0xF0AC, 0x85C8, 0xF0B1, 0x85C9, 0xC2C7, 0x85CB, 0xF0AF, 0x85CD, 0xC2C5, 0x85CE, 0xF0B0, 0x85CF, 0xC2C3, + 0x85D0, 0xC2C6, 0x85D1, 0xF2D5, 0x85D2, 0xF0B5, 0x85D5, 0xC3C2, 0x85D7, 0xF2CD, 0x85D8, 0xF2D1, 0x85D9, 0xF2C9, 0x85DA, 0xF2CC, + 0x85DC, 0xF2D4, 0x85DD, 0xC3C0, 0x85DE, 0xF2D9, 0x85DF, 0xF2D2, 0x85E1, 0xF2CA, 0x85E2, 0xF2DA, 0x85E3, 0xF2D3, 0x85E4, 0xC3C3, + 0x85E5, 0xC3C4, 0x85E6, 0xF2D7, 0x85E8, 0xF2CB, 0x85E9, 0xC3BF, 0x85EA, 0xC3C1, 0x85EB, 0xF2C6, 0x85EC, 0xF2CE, 0x85ED, 0xF2C8, + 0x85EF, 0xF2D8, 0x85F0, 0xF2D6, 0x85F1, 0xF2C7, 0x85F2, 0xF2CF, 0x85F6, 0xF4BE, 0x85F7, 0xC3C5, 0x85F8, 0xF2D0, 0x85F9, 0xC4A7, + 0x85FA, 0xC4A9, 0x85FB, 0xC4A6, 0x85FD, 0xF4C3, 0x85FE, 0xF4BB, 0x85FF, 0xF4B9, 0x8600, 0xF4BD, 0x8601, 0xF4BA, 0x8604, 0xF4BF, + 0x8605, 0xF4C1, 0x8606, 0xC4AA, 0x8607, 0xC4AC, 0x8609, 0xF4C0, 0x860A, 0xC4AD, 0x860B, 0xC4AB, 0x860C, 0xF4C2, 0x8611, 0xC4A8, + 0x8617, 0xC4F4, 0x8618, 0xF5F1, 0x8619, 0xF5F7, 0x861A, 0xC4F6, 0x861B, 0xF4BC, 0x861C, 0xF5F6, 0x861E, 0xF5FD, 0x861F, 0xF5F4, + 0x8620, 0xF5FB, 0x8621, 0xF5FA, 0x8622, 0xF4B8, 0x8623, 0xF5F5, 0x8624, 0xF0B6, 0x8625, 0xF5FE, 0x8626, 0xF5F3, 0x8627, 0xF5F8, + 0x8629, 0xF5FC, 0x862A, 0xF5F2, 0x862C, 0xF74A, 0x862D, 0xC4F5, 0x862E, 0xF5F9, 0x8631, 0xF7F4, 0x8632, 0xF74B, 0x8633, 0xF749, + 0x8634, 0xF747, 0x8635, 0xF748, 0x8636, 0xF74C, 0x8638, 0xC5D9, 0x8639, 0xF7F2, 0x863A, 0xF7F0, 0x863B, 0xF7F5, 0x863C, 0xF7F3, + 0x863E, 0xF7F6, 0x863F, 0xC5DA, 0x8640, 0xF7F1, 0x8643, 0xF8BC, 0x8646, 0xF945, 0x8647, 0xF946, 0x8648, 0xF947, 0x864B, 0xF9C7, + 0x864C, 0xF9BD, 0x864D, 0xCA4F, 0x864E, 0xAAEA, 0x8650, 0xAD68, 0x8652, 0xD3B8, 0x8653, 0xD3B7, 0x8654, 0xB040, 0x8655, 0xB342, + 0x8656, 0xD77C, 0x8659, 0xD77B, 0x865B, 0xB5EA, 0x865C, 0xB8B8, 0x865E, 0xB8B7, 0x865F, 0xB8B9, 0x8661, 0xE3D4, 0x8662, 0xE77E, + 0x8663, 0xEB58, 0x8664, 0xEB5A, 0x8665, 0xEB59, 0x8667, 0xC1AB, 0x8668, 0xEE57, 0x8669, 0xF0BA, 0x866A, 0xF9A5, 0x866B, 0xA6E4, + 0x866D, 0xCDC9, 0x866E, 0xCDCA, 0x866F, 0xCDC8, 0x8670, 0xCDC7, 0x8671, 0xAAEB, 0x8673, 0xD0A9, 0x8674, 0xD0A7, 0x8677, 0xD0A6, + 0x8679, 0xAD69, 0x867A, 0xAD6B, 0x867B, 0xAD6A, 0x867C, 0xD0A8, 0x8685, 0xD3C4, 0x8686, 0xD3C1, 0x8687, 0xD3BF, 0x868A, 0xB041, + 0x868B, 0xD3C2, 0x868C, 0xB046, 0x868D, 0xD3BC, 0x868E, 0xD3CB, 0x8690, 0xD3CD, 0x8691, 0xD3BD, 0x8693, 0xB043, 0x8694, 0xD3CE, + 0x8695, 0xD3C9, 0x8696, 0xD3BB, 0x8697, 0xD3C0, 0x8698, 0xD3CA, 0x8699, 0xD3C6, 0x869A, 0xD3C3, 0x869C, 0xB048, 0x869D, 0xD3CC, + 0x869E, 0xD3BE, 0x86A1, 0xD3C7, 0x86A2, 0xD3B9, 0x86A3, 0xB047, 0x86A4, 0xB044, 0x86A5, 0xD3C5, 0x86A7, 0xD3C8, 0x86A8, 0xD3BA, + 0x86A9, 0xB045, 0x86AA, 0xB042, 0x86AF, 0xB34C, 0x86B0, 0xD7A5, 0x86B1, 0xB34B, 0x86B3, 0xD7A8, 0x86B4, 0xD7AB, 0x86B5, 0xB348, + 0x86B6, 0xB346, 0x86B7, 0xD77E, 0x86B8, 0xD7A9, 0x86B9, 0xD7A7, 0x86BA, 0xD7A4, 0x86BB, 0xD7AC, 0x86BC, 0xD7AD, 0x86BD, 0xD7AF, + 0x86BE, 0xD7B0, 0x86BF, 0xD77D, 0x86C0, 0xB345, 0x86C1, 0xD7A2, 0x86C2, 0xD7A1, 0x86C3, 0xD7AE, 0x86C4, 0xB347, 0x86C5, 0xD7A3, + 0x86C6, 0xB349, 0x86C7, 0xB344, 0x86C8, 0xD7A6, 0x86C9, 0xB34D, 0x86CB, 0xB34A, 0x86CC, 0xD7AA, 0x86D0, 0xB5F1, 0x86D1, 0xDBBF, + 0x86D3, 0xDBB4, 0x86D4, 0xB5EE, 0x86D6, 0xDFE7, 0x86D7, 0xDBBD, 0x86D8, 0xDBB1, 0x86D9, 0xB5EC, 0x86DA, 0xDBB6, 0x86DB, 0xB5EF, + 0x86DC, 0xDBBA, 0x86DD, 0xDBB8, 0x86DE, 0xB5F2, 0x86DF, 0xB5EB, 0x86E2, 0xDBB2, 0x86E3, 0xDBB5, 0x86E4, 0xB5F0, 0x86E6, 0xDBB3, + 0x86E8, 0xDBBE, 0x86E9, 0xDBBC, 0x86EA, 0xDBB7, 0x86EB, 0xDBB9, 0x86EC, 0xDBBB, 0x86ED, 0xB5ED, 0x86F5, 0xDFE8, 0x86F6, 0xDFEE, + 0x86F7, 0xDFE4, 0x86F8, 0xDFEA, 0x86F9, 0xB8BA, 0x86FA, 0xDFE6, 0x86FB, 0xB8C0, 0x86FE, 0xB8BF, 0x8700, 0xB8BE, 0x8701, 0xDFED, + 0x8702, 0xB8C1, 0x8703, 0xB8C2, 0x8704, 0xDFE3, 0x8705, 0xDFF0, 0x8706, 0xB8C3, 0x8707, 0xB8BD, 0x8708, 0xB8BC, 0x8709, 0xDFEC, + 0x870A, 0xB8C4, 0x870B, 0xDFE2, 0x870C, 0xDFE5, 0x870D, 0xDFEF, 0x870E, 0xDFEB, 0x8711, 0xE3F4, 0x8712, 0xE3E9, 0x8713, 0xB8BB, + 0x8718, 0xBB6A, 0x8719, 0xE3DD, 0x871A, 0xE3F2, 0x871B, 0xE3DE, 0x871C, 0xBB65, 0x871E, 0xE3DB, 0x8720, 0xE3E4, 0x8721, 0xE3DC, + 0x8722, 0xBB67, 0x8723, 0xE3D6, 0x8724, 0xE3F1, 0x8725, 0xBB68, 0x8726, 0xE3EE, 0x8727, 0xE3EF, 0x8728, 0xE3D7, 0x8729, 0xBB6D, + 0x872A, 0xE3E6, 0x872C, 0xE3E0, 0x872D, 0xE3E7, 0x872E, 0xE3DA, 0x8730, 0xE3F3, 0x8731, 0xE3EB, 0x8732, 0xE3E5, 0x8733, 0xE3D5, + 0x8734, 0xBB69, 0x8735, 0xE3EC, 0x8737, 0xBB6C, 0x8738, 0xE3F0, 0x873A, 0xE3EA, 0x873B, 0xBB66, 0x873C, 0xE3E8, 0x873E, 0xE3E2, + 0x873F, 0xBB64, 0x8740, 0xE3D9, 0x8741, 0xE3E1, 0x8742, 0xE3ED, 0x8743, 0xE3DF, 0x8746, 0xE3E3, 0x874C, 0xBDC1, 0x874D, 0xDFE9, + 0x874E, 0xE7B2, 0x874F, 0xE7BB, 0x8750, 0xE7B1, 0x8751, 0xE7AD, 0x8752, 0xE7AA, 0x8753, 0xBDC2, 0x8754, 0xE7A8, 0x8755, 0xBB6B, + 0x8756, 0xE7A1, 0x8757, 0xBDC0, 0x8758, 0xE7A7, 0x8759, 0xBDBF, 0x875A, 0xE7AC, 0x875B, 0xE7A9, 0x875C, 0xE7B9, 0x875D, 0xE7B4, + 0x875E, 0xE7AE, 0x875F, 0xE7B3, 0x8760, 0xBDBB, 0x8761, 0xE7AB, 0x8762, 0xE7BE, 0x8763, 0xE7A2, 0x8764, 0xE7A3, 0x8765, 0xE7BA, + 0x8766, 0xBDBC, 0x8767, 0xE7BF, 0x8768, 0xBDBE, 0x8769, 0xE7C0, 0x876A, 0xE7B0, 0x876B, 0xE3D8, 0x876C, 0xE7B6, 0x876D, 0xE7AF, + 0x876E, 0xE7B8, 0x876F, 0xE7B5, 0x8773, 0xE7A6, 0x8774, 0xBDB9, 0x8775, 0xE7BD, 0x8776, 0xBDBA, 0x8777, 0xE7A4, 0x8778, 0xBDBD, + 0x8779, 0xEB64, 0x877A, 0xE7B7, 0x877B, 0xE7BC, 0x8781, 0xEB61, 0x8782, 0xBDB8, 0x8783, 0xBFC0, 0x8784, 0xEB6B, 0x8785, 0xEB67, + 0x8787, 0xEB65, 0x8788, 0xEB60, 0x8789, 0xEB6F, 0x878D, 0xBFC4, 0x878F, 0xEB5C, 0x8790, 0xEB68, 0x8791, 0xEB69, 0x8792, 0xEB5F, + 0x8793, 0xEB5E, 0x8794, 0xEB6C, 0x8796, 0xEB62, 0x8797, 0xEB5D, 0x8798, 0xEB63, 0x879A, 0xEB6E, 0x879B, 0xEB5B, 0x879C, 0xEB6D, + 0x879D, 0xEB6A, 0x879E, 0xBFC2, 0x879F, 0xBFC1, 0x87A2, 0xBFC3, 0x87A3, 0xEB66, 0x87A4, 0xF0CB, 0x87AA, 0xEE59, 0x87AB, 0xC1B1, + 0x87AC, 0xEE5D, 0x87AD, 0xEE5A, 0x87AE, 0xEE61, 0x87AF, 0xEE67, 0x87B0, 0xEE5C, 0x87B2, 0xEE70, 0x87B3, 0xC1AE, 0x87B4, 0xEE6A, + 0x87B5, 0xEE5F, 0x87B6, 0xEE6B, 0x87B7, 0xEE66, 0x87B8, 0xEE6D, 0x87B9, 0xEE5E, 0x87BA, 0xC1B3, 0x87BB, 0xC1B2, 0x87BC, 0xEE60, + 0x87BD, 0xEE6E, 0x87BE, 0xEE58, 0x87BF, 0xEE6C, 0x87C0, 0xC1AC, 0x87C2, 0xEE64, 0x87C3, 0xEE63, 0x87C4, 0xEE68, 0x87C5, 0xEE5B, + 0x87C6, 0xC1B0, 0x87C8, 0xC1B4, 0x87C9, 0xEE62, 0x87CA, 0xEE69, 0x87CB, 0xC1B5, 0x87CC, 0xEE65, 0x87D1, 0xC1AD, 0x87D2, 0xC1AF, + 0x87D3, 0xF0C7, 0x87D4, 0xF0C5, 0x87D7, 0xF0CC, 0x87D8, 0xF0C9, 0x87D9, 0xF0CD, 0x87DB, 0xF0BE, 0x87DC, 0xF0C6, 0x87DD, 0xF0D1, + 0x87DE, 0xEE6F, 0x87DF, 0xF0C2, 0x87E0, 0xC2CF, 0x87E1, 0xE7A5, 0x87E2, 0xF0BD, 0x87E3, 0xF0CA, 0x87E4, 0xF0C4, 0x87E5, 0xF0C1, + 0x87E6, 0xF0BC, 0x87E7, 0xF0BB, 0x87E8, 0xF0D0, 0x87EA, 0xF0C0, 0x87EB, 0xF0BF, 0x87EC, 0xC2CD, 0x87ED, 0xF0C8, 0x87EF, 0xC2CC, + 0x87F2, 0xC2CE, 0x87F3, 0xF0C3, 0x87F4, 0xF0CF, 0x87F6, 0xF2DE, 0x87F7, 0xF2DF, 0x87F9, 0xC3C9, 0x87FA, 0xF2DC, 0x87FB, 0xC3C6, + 0x87FC, 0xF2E4, 0x87FE, 0xC3CA, 0x87FF, 0xF2E6, 0x8800, 0xF2DB, 0x8801, 0xF0CE, 0x8802, 0xF2E8, 0x8803, 0xF2DD, 0x8805, 0xC3C7, + 0x8806, 0xF2E3, 0x8808, 0xF2E5, 0x8809, 0xF2E0, 0x880A, 0xF2E7, 0x880B, 0xF2E2, 0x880C, 0xF2E1, 0x880D, 0xC3C8, 0x8810, 0xF4C5, + 0x8811, 0xF4C6, 0x8813, 0xF4C8, 0x8814, 0xC4AE, 0x8815, 0xC4AF, 0x8816, 0xF4C9, 0x8817, 0xF4C7, 0x8819, 0xF4C4, 0x881B, 0xF642, + 0x881C, 0xF645, 0x881D, 0xF641, 0x881F, 0xC4FA, 0x8820, 0xF643, 0x8821, 0xC4F9, 0x8822, 0xC4F8, 0x8823, 0xC4F7, 0x8824, 0xF644, + 0x8825, 0xF751, 0x8826, 0xF74F, 0x8828, 0xF74E, 0x8829, 0xF640, 0x882A, 0xF750, 0x882B, 0xF646, 0x882C, 0xF74D, 0x882E, 0xF7F9, + 0x882F, 0xF7D7, 0x8830, 0xF7F7, 0x8831, 0xC5DB, 0x8832, 0xF7F8, 0x8833, 0xF7FA, 0x8835, 0xF8BF, 0x8836, 0xC5FA, 0x8837, 0xF8BE, + 0x8838, 0xF8BD, 0x8839, 0xC5FB, 0x883B, 0xC65A, 0x883C, 0xF96E, 0x883D, 0xF9A7, 0x883E, 0xF9A6, 0x883F, 0xF9A8, 0x8840, 0xA6E5, + 0x8841, 0xD0AA, 0x8843, 0xD3CF, 0x8844, 0xD3D0, 0x8848, 0xDBC0, 0x884A, 0xF647, 0x884B, 0xF8C0, 0x884C, 0xA6E6, 0x884D, 0xAD6C, + 0x884E, 0xD0AB, 0x8852, 0xD7B1, 0x8853, 0xB34E, 0x8855, 0xDBC2, 0x8856, 0xDBC1, 0x8857, 0xB5F3, 0x8859, 0xB8C5, 0x885A, 0xE7C1, + 0x885B, 0xBDC3, 0x885D, 0xBDC4, 0x8861, 0xBFC5, 0x8862, 0xC5FC, 0x8863, 0xA6E7, 0x8867, 0xD0AC, 0x8868, 0xAAED, 0x8869, 0xD0AE, + 0x886A, 0xD0AD, 0x886B, 0xAD6D, 0x886D, 0xD3D1, 0x886F, 0xD3D8, 0x8870, 0xB049, 0x8871, 0xD3D6, 0x8872, 0xD3D4, 0x8874, 0xD3DB, + 0x8875, 0xD3D2, 0x8876, 0xD3D3, 0x8877, 0xB04A, 0x8879, 0xB04E, 0x887C, 0xD3DC, 0x887D, 0xB04D, 0x887E, 0xD3DA, 0x887F, 0xD3D7, + 0x8880, 0xD3D5, 0x8881, 0xB04B, 0x8882, 0xB04C, 0x8883, 0xD3D9, 0x8888, 0xB350, 0x8889, 0xD7B2, 0x888B, 0xB355, 0x888C, 0xD7C2, + 0x888D, 0xB354, 0x888E, 0xD7C4, 0x8891, 0xD7B8, 0x8892, 0xB352, 0x8893, 0xD7C3, 0x8895, 0xD7B3, 0x8896, 0xB353, 0x8897, 0xD7BF, + 0x8898, 0xD7BB, 0x8899, 0xD7BD, 0x889A, 0xD7B7, 0x889B, 0xD7BE, 0x889E, 0xB34F, 0x889F, 0xD7BA, 0x88A1, 0xD7B9, 0x88A2, 0xD7B5, + 0x88A4, 0xD7C0, 0x88A7, 0xD7BC, 0x88A8, 0xD7B4, 0x88AA, 0xD7B6, 0x88AB, 0xB351, 0x88AC, 0xD7C1, 0x88B1, 0xB5F6, 0x88B2, 0xDBCD, + 0x88B6, 0xDBC9, 0x88B7, 0xDBCB, 0x88B8, 0xDBC6, 0x88B9, 0xDBC5, 0x88BA, 0xDBC3, 0x88BC, 0xDBCA, 0x88BD, 0xDBCC, 0x88BE, 0xDBC8, + 0x88C0, 0xDBC7, 0x88C1, 0xB5F4, 0x88C2, 0xB5F5, 0x88C9, 0xDBCF, 0x88CA, 0xB8CD, 0x88CB, 0xDFF2, 0x88CC, 0xDFF8, 0x88CD, 0xDFF3, + 0x88CE, 0xDFF4, 0x88CF, 0xF9D8, 0x88D0, 0xDFF9, 0x88D2, 0xB8CF, 0x88D4, 0xB8C7, 0x88D5, 0xB8CE, 0x88D6, 0xDFF1, 0x88D7, 0xDBC4, + 0x88D8, 0xB8CA, 0x88D9, 0xB8C8, 0x88DA, 0xDFF7, 0x88DB, 0xDFF6, 0x88DC, 0xB8C9, 0x88DD, 0xB8CB, 0x88DE, 0xDFF5, 0x88DF, 0xB8C6, + 0x88E1, 0xB8CC, 0x88E7, 0xE3F6, 0x88E8, 0xBB74, 0x88EB, 0xE442, 0x88EC, 0xE441, 0x88EE, 0xE3FB, 0x88EF, 0xBB76, 0x88F0, 0xE440, + 0x88F1, 0xE3F7, 0x88F2, 0xE3F8, 0x88F3, 0xBB6E, 0x88F4, 0xBB70, 0x88F6, 0xE3FD, 0x88F7, 0xE3F5, 0x88F8, 0xBB72, 0x88F9, 0xBB71, + 0x88FA, 0xE3F9, 0x88FB, 0xE3FE, 0x88FC, 0xE3FC, 0x88FD, 0xBB73, 0x88FE, 0xE3FA, 0x8901, 0xDBCE, 0x8902, 0xBB6F, 0x8905, 0xE7C2, + 0x8906, 0xE7C9, 0x8907, 0xBDC6, 0x8909, 0xE7CD, 0x890A, 0xBDCA, 0x890B, 0xE7C5, 0x890C, 0xE7C3, 0x890E, 0xE7CC, 0x8910, 0xBDC5, + 0x8911, 0xE7CB, 0x8912, 0xBDC7, 0x8913, 0xBDC8, 0x8914, 0xE7C4, 0x8915, 0xBDC9, 0x8916, 0xE7CA, 0x8917, 0xE7C6, 0x8918, 0xE7C7, + 0x8919, 0xE7C8, 0x891A, 0xBB75, 0x891E, 0xEB70, 0x891F, 0xEB7C, 0x8921, 0xBFCA, 0x8922, 0xEB77, 0x8923, 0xEB79, 0x8925, 0xBFC8, + 0x8926, 0xEB71, 0x8927, 0xEB75, 0x8929, 0xEB78, 0x892A, 0xBFC6, 0x892B, 0xBFC9, 0x892C, 0xEB7B, 0x892D, 0xEB73, 0x892E, 0xEB74, + 0x892F, 0xEB7A, 0x8930, 0xEB72, 0x8931, 0xEB76, 0x8932, 0xBFC7, 0x8933, 0xEE72, 0x8935, 0xEE71, 0x8936, 0xC1B7, 0x8937, 0xEE77, + 0x8938, 0xC1B9, 0x893B, 0xC1B6, 0x893C, 0xEE73, 0x893D, 0xC1BA, 0x893E, 0xEE74, 0x8941, 0xEE75, 0x8942, 0xEE78, 0x8944, 0xC1B8, + 0x8946, 0xF0D6, 0x8949, 0xF0D9, 0x894B, 0xF0D3, 0x894C, 0xF0D5, 0x894F, 0xF0D4, 0x8950, 0xF0D7, 0x8951, 0xF0D8, 0x8952, 0xEE76, + 0x8953, 0xF0D2, 0x8956, 0xC3CD, 0x8957, 0xF2EC, 0x8958, 0xF2EF, 0x8959, 0xF2F1, 0x895A, 0xF2EA, 0x895B, 0xF2EB, 0x895C, 0xF2EE, + 0x895D, 0xF2F0, 0x895E, 0xC3CE, 0x895F, 0xC3CC, 0x8960, 0xC3CB, 0x8961, 0xF2ED, 0x8962, 0xF2E9, 0x8963, 0xF4CA, 0x8964, 0xC4B0, + 0x8966, 0xF4CB, 0x8969, 0xF649, 0x896A, 0xC4FB, 0x896B, 0xF64B, 0x896C, 0xC4FC, 0x896D, 0xF648, 0x896E, 0xF64A, 0x896F, 0xC5A8, + 0x8971, 0xF752, 0x8972, 0xC5A7, 0x8973, 0xF7FD, 0x8974, 0xF7FC, 0x8976, 0xF7FB, 0x8979, 0xF948, 0x897A, 0xF949, 0x897B, 0xF94B, + 0x897C, 0xF94A, 0x897E, 0xCA50, 0x897F, 0xA6E8, 0x8981, 0xAD6E, 0x8982, 0xD7C5, 0x8983, 0xB5F7, 0x8985, 0xDFFA, 0x8986, 0xC2D0, + 0x8988, 0xF2F2, 0x898B, 0xA8A3, 0x898F, 0xB357, 0x8993, 0xB356, 0x8995, 0xDBD0, 0x8996, 0xB5F8, 0x8997, 0xDBD2, 0x8998, 0xDBD1, + 0x899B, 0xDFFB, 0x899C, 0xB8D0, 0x899D, 0xE443, 0x899E, 0xE446, 0x899F, 0xE445, 0x89A1, 0xE444, 0x89A2, 0xE7CE, 0x89A3, 0xE7D0, + 0x89A4, 0xE7CF, 0x89A6, 0xBFCC, 0x89AA, 0xBFCB, 0x89AC, 0xC1BB, 0x89AD, 0xEE79, 0x89AE, 0xEE7B, 0x89AF, 0xEE7A, 0x89B2, 0xC2D1, + 0x89B6, 0xF2F4, 0x89B7, 0xF2F3, 0x89B9, 0xF4CC, 0x89BA, 0xC4B1, 0x89BD, 0xC4FD, 0x89BE, 0xF754, 0x89BF, 0xF753, 0x89C0, 0xC65B, + 0x89D2, 0xA8A4, 0x89D3, 0xD0AF, 0x89D4, 0xAD6F, 0x89D5, 0xD7C8, 0x89D6, 0xD7C6, 0x89D9, 0xD7C7, 0x89DA, 0xDBD4, 0x89DB, 0xDBD5, + 0x89DC, 0xE043, 0x89DD, 0xDBD3, 0x89DF, 0xDFFC, 0x89E0, 0xE041, 0x89E1, 0xE040, 0x89E2, 0xE042, 0x89E3, 0xB8D1, 0x89E4, 0xDFFE, + 0x89E5, 0xDFFD, 0x89E6, 0xE044, 0x89E8, 0xE449, 0x89E9, 0xE447, 0x89EB, 0xE448, 0x89EC, 0xE7D3, 0x89ED, 0xE7D1, 0x89F0, 0xE7D2, + 0x89F1, 0xEB7D, 0x89F2, 0xEE7C, 0x89F3, 0xEE7D, 0x89F4, 0xC2D2, 0x89F6, 0xF2F5, 0x89F7, 0xF4CD, 0x89F8, 0xC4B2, 0x89FA, 0xF64C, + 0x89FB, 0xF755, 0x89FC, 0xC5A9, 0x89FE, 0xF7FE, 0x89FF, 0xF94C, 0x8A00, 0xA8A5, 0x8A02, 0xAD71, 0x8A03, 0xAD72, 0x8A04, 0xD0B0, + 0x8A07, 0xD0B1, 0x8A08, 0xAD70, 0x8A0A, 0xB054, 0x8A0C, 0xB052, 0x8A0E, 0xB051, 0x8A0F, 0xB058, 0x8A10, 0xB050, 0x8A11, 0xB059, + 0x8A12, 0xD3DD, 0x8A13, 0xB056, 0x8A15, 0xB053, 0x8A16, 0xB057, 0x8A17, 0xB055, 0x8A18, 0xB04F, 0x8A1B, 0xB35F, 0x8A1D, 0xB359, + 0x8A1E, 0xD7CC, 0x8A1F, 0xB35E, 0x8A22, 0xB360, 0x8A23, 0xB35A, 0x8A25, 0xB35B, 0x8A27, 0xD7CA, 0x8A2A, 0xB358, 0x8A2C, 0xD7CB, + 0x8A2D, 0xB35D, 0x8A30, 0xD7C9, 0x8A31, 0xB35C, 0x8A34, 0xB644, 0x8A36, 0xB646, 0x8A39, 0xDBD8, 0x8A3A, 0xB645, 0x8A3B, 0xB5F9, + 0x8A3C, 0xB5FD, 0x8A3E, 0xB8E4, 0x8A3F, 0xE049, 0x8A40, 0xDBDA, 0x8A41, 0xB5FE, 0x8A44, 0xDBDD, 0x8A45, 0xDBDE, 0x8A46, 0xB643, + 0x8A48, 0xDBE0, 0x8A4A, 0xDBE2, 0x8A4C, 0xDBE3, 0x8A4D, 0xDBD7, 0x8A4E, 0xDBD6, 0x8A4F, 0xDBE4, 0x8A50, 0xB642, 0x8A51, 0xDBE1, + 0x8A52, 0xDBDF, 0x8A54, 0xB640, 0x8A55, 0xB5FB, 0x8A56, 0xB647, 0x8A57, 0xDBDB, 0x8A58, 0xDBDC, 0x8A59, 0xDBD9, 0x8A5B, 0xB641, + 0x8A5E, 0xB5FC, 0x8A60, 0xB5FA, 0x8A61, 0xE048, 0x8A62, 0xB8DF, 0x8A63, 0xB8DA, 0x8A66, 0xB8D5, 0x8A68, 0xB8E5, 0x8A69, 0xB8D6, + 0x8A6B, 0xB8D2, 0x8A6C, 0xB8E1, 0x8A6D, 0xB8DE, 0x8A6E, 0xB8E0, 0x8A70, 0xB8D7, 0x8A71, 0xB8DC, 0x8A72, 0xB8D3, 0x8A73, 0xB8D4, + 0x8A74, 0xE050, 0x8A75, 0xE04D, 0x8A76, 0xE045, 0x8A77, 0xE04A, 0x8A79, 0xB8E2, 0x8A7A, 0xE051, 0x8A7B, 0xB8E3, 0x8A7C, 0xB8D9, + 0x8A7F, 0xE047, 0x8A81, 0xE04F, 0x8A82, 0xE04B, 0x8A83, 0xE04E, 0x8A84, 0xE04C, 0x8A85, 0xB8DD, 0x8A86, 0xE046, 0x8A87, 0xB8D8, + 0x8A8B, 0xE44C, 0x8A8C, 0xBB78, 0x8A8D, 0xBB7B, 0x8A8F, 0xE44E, 0x8A91, 0xBBA5, 0x8A92, 0xE44D, 0x8A93, 0xBB7D, 0x8A95, 0xBDCF, + 0x8A96, 0xE44F, 0x8A98, 0xBBA4, 0x8A99, 0xE44B, 0x8A9A, 0xBBA6, 0x8A9E, 0xBB79, 0x8AA0, 0xB8DB, 0x8AA1, 0xBB7C, 0x8AA3, 0xBB7A, + 0x8AA4, 0xBB7E, 0x8AA5, 0xBBA2, 0x8AA6, 0xBB77, 0x8AA7, 0xBBA7, 0x8AA8, 0xBBA3, 0x8AAA, 0xBBA1, 0x8AAB, 0xE44A, 0x8AB0, 0xBDD6, + 0x8AB2, 0xBDD2, 0x8AB6, 0xBDD9, 0x8AB8, 0xE7D6, 0x8AB9, 0xBDDA, 0x8ABA, 0xE7E2, 0x8ABB, 0xE7DB, 0x8ABC, 0xBDCB, 0x8ABD, 0xE7E3, + 0x8ABE, 0xE7DD, 0x8ABF, 0xBDD5, 0x8AC0, 0xE7DE, 0x8AC2, 0xBDD4, 0x8AC3, 0xE7E1, 0x8AC4, 0xBDCE, 0x8AC5, 0xE7DF, 0x8AC6, 0xE7D5, + 0x8AC7, 0xBDCD, 0x8AC8, 0xEBAA, 0x8AC9, 0xBDD3, 0x8ACB, 0xBDD0, 0x8ACD, 0xBDD8, 0x8ACF, 0xE7D4, 0x8AD1, 0xE7D8, 0x8AD2, 0xBDCC, + 0x8AD3, 0xE7D7, 0x8AD4, 0xE7D9, 0x8AD5, 0xE7DA, 0x8AD6, 0xBDD7, 0x8AD7, 0xE7DC, 0x8AD8, 0xE7E0, 0x8AD9, 0xE7E4, 0x8ADB, 0xBDDB, + 0x8ADC, 0xBFD2, 0x8ADD, 0xEBA5, 0x8ADE, 0xEBAB, 0x8ADF, 0xEBA8, 0x8AE0, 0xEB7E, 0x8AE1, 0xEBAC, 0x8AE2, 0xEBA1, 0x8AE4, 0xEBA7, + 0x8AE6, 0xBFCD, 0x8AE7, 0xBFD3, 0x8AE8, 0xEBAD, 0x8AEB, 0xBFCF, 0x8AED, 0xBFD9, 0x8AEE, 0xBFD4, 0x8AEF, 0xEBAF, 0x8AF0, 0xEBA9, + 0x8AF1, 0xBFD0, 0x8AF2, 0xEBA2, 0x8AF3, 0xBFDA, 0x8AF4, 0xEBA3, 0x8AF5, 0xEBA4, 0x8AF6, 0xBFDB, 0x8AF7, 0xBFD8, 0x8AF8, 0xBDD1, + 0x8AFA, 0xBFCE, 0x8AFB, 0xEBB0, 0x8AFC, 0xBFDC, 0x8AFE, 0xBFD5, 0x8AFF, 0xEBAE, 0x8B00, 0xBFD1, 0x8B01, 0xBFD6, 0x8B02, 0xBFD7, + 0x8B04, 0xC1C3, 0x8B05, 0xEEA4, 0x8B06, 0xEEAD, 0x8B07, 0xEEAA, 0x8B08, 0xEEAC, 0x8B0A, 0xC1C0, 0x8B0B, 0xEEA5, 0x8B0D, 0xEEAB, + 0x8B0E, 0xC1BC, 0x8B0F, 0xEEA7, 0x8B10, 0xC1C4, 0x8B11, 0xEEA3, 0x8B12, 0xEEA8, 0x8B13, 0xEEAF, 0x8B14, 0xEBA6, 0x8B15, 0xEEA9, + 0x8B16, 0xEEA2, 0x8B17, 0xC1BD, 0x8B18, 0xEEA1, 0x8B19, 0xC1BE, 0x8B1A, 0xEEB0, 0x8B1B, 0xC1BF, 0x8B1C, 0xEEAE, 0x8B1D, 0xC1C2, + 0x8B1E, 0xEE7E, 0x8B20, 0xC1C1, 0x8B22, 0xEEA6, 0x8B23, 0xF0DC, 0x8B24, 0xF0EA, 0x8B25, 0xF0E5, 0x8B26, 0xF0E7, 0x8B27, 0xF0DB, + 0x8B28, 0xC2D3, 0x8B2A, 0xF0DA, 0x8B2B, 0xC2D6, 0x8B2C, 0xC2D5, 0x8B2E, 0xF0E9, 0x8B2F, 0xF0E1, 0x8B30, 0xF0DE, 0x8B31, 0xF0E4, + 0x8B33, 0xF0DD, 0x8B35, 0xF0DF, 0x8B36, 0xF0E8, 0x8B37, 0xF0E6, 0x8B39, 0xC2D4, 0x8B3A, 0xF0ED, 0x8B3B, 0xF0EB, 0x8B3C, 0xF0E2, + 0x8B3D, 0xF0EC, 0x8B3E, 0xF0E3, 0x8B40, 0xF2F9, 0x8B41, 0xC3CF, 0x8B42, 0xF341, 0x8B45, 0xF64F, 0x8B46, 0xC3D6, 0x8B47, 0xF0E0, + 0x8B48, 0xF2F7, 0x8B49, 0xC3D2, 0x8B4A, 0xF2F8, 0x8B4B, 0xF2FD, 0x8B4E, 0xC3D4, 0x8B4F, 0xC3D5, 0x8B50, 0xF2F6, 0x8B51, 0xF340, + 0x8B52, 0xF342, 0x8B53, 0xF2FA, 0x8B54, 0xF2FC, 0x8B55, 0xF2FE, 0x8B56, 0xF2FB, 0x8B57, 0xF343, 0x8B58, 0xC3D1, 0x8B59, 0xC3D7, + 0x8B5A, 0xC3D3, 0x8B5C, 0xC3D0, 0x8B5D, 0xF4D0, 0x8B5F, 0xC4B7, 0x8B60, 0xF4CE, 0x8B63, 0xF4D2, 0x8B65, 0xF4D3, 0x8B66, 0xC4B5, + 0x8B67, 0xF4D4, 0x8B68, 0xF4D1, 0x8B6A, 0xF4CF, 0x8B6B, 0xC4B8, 0x8B6C, 0xC4B4, 0x8B6D, 0xF4D5, 0x8B6F, 0xC4B6, 0x8B70, 0xC4B3, + 0x8B74, 0xC4FE, 0x8B77, 0xC540, 0x8B78, 0xF64E, 0x8B79, 0xF64D, 0x8B7A, 0xF650, 0x8B7B, 0xF651, 0x8B7D, 0xC541, 0x8B7E, 0xF756, + 0x8B7F, 0xF75B, 0x8B80, 0xC5AA, 0x8B82, 0xF758, 0x8B84, 0xF757, 0x8B85, 0xF75A, 0x8B86, 0xF759, 0x8B88, 0xF843, 0x8B8A, 0xC5DC, + 0x8B8B, 0xF842, 0x8B8C, 0xF840, 0x8B8E, 0xF841, 0x8B92, 0xC5FE, 0x8B93, 0xC5FD, 0x8B94, 0xF8C1, 0x8B95, 0xF8C2, 0x8B96, 0xC640, + 0x8B98, 0xF94D, 0x8B99, 0xF94E, 0x8B9A, 0xC667, 0x8B9C, 0xC66D, 0x8B9E, 0xF9A9, 0x8B9F, 0xF9C8, 0x8C37, 0xA8A6, 0x8C39, 0xD7CD, + 0x8C3B, 0xD7CE, 0x8C3C, 0xE052, 0x8C3D, 0xE450, 0x8C3E, 0xE7E5, 0x8C3F, 0xC1C6, 0x8C41, 0xC1C5, 0x8C42, 0xF0EE, 0x8C43, 0xF344, + 0x8C45, 0xF844, 0x8C46, 0xA8A7, 0x8C47, 0xD3DE, 0x8C48, 0xB05A, 0x8C49, 0xB361, 0x8C4A, 0xE054, 0x8C4B, 0xE053, 0x8C4C, 0xBDDC, + 0x8C4D, 0xE7E6, 0x8C4E, 0xBDDD, 0x8C4F, 0xEEB1, 0x8C50, 0xC2D7, 0x8C54, 0xC676, 0x8C55, 0xA8A8, 0x8C56, 0xCDCB, 0x8C57, 0xD3DF, + 0x8C5A, 0xB362, 0x8C5C, 0xD7CF, 0x8C5D, 0xD7D0, 0x8C5F, 0xDBE5, 0x8C61, 0xB648, 0x8C62, 0xB8E6, 0x8C64, 0xE056, 0x8C65, 0xE055, + 0x8C66, 0xE057, 0x8C68, 0xE451, 0x8C69, 0xE452, 0x8C6A, 0xBBA8, 0x8C6B, 0xBFDD, 0x8C6C, 0xBDDE, 0x8C6D, 0xBFDE, 0x8C6F, 0xEEB5, + 0x8C70, 0xEEB2, 0x8C71, 0xEEB4, 0x8C72, 0xEEB3, 0x8C73, 0xC1C7, 0x8C75, 0xF0EF, 0x8C76, 0xF346, 0x8C77, 0xF345, 0x8C78, 0xCBA4, + 0x8C79, 0xB05C, 0x8C7A, 0xB05B, 0x8C7B, 0xD3E0, 0x8C7D, 0xD7D1, 0x8C80, 0xDBE7, 0x8C81, 0xDBE6, 0x8C82, 0xB649, 0x8C84, 0xE059, + 0x8C85, 0xE05A, 0x8C86, 0xE058, 0x8C89, 0xB8E8, 0x8C8A, 0xB8E7, 0x8C8C, 0xBBAA, 0x8C8D, 0xBBA9, 0x8C8F, 0xE7E7, 0x8C90, 0xEBB3, + 0x8C91, 0xEBB1, 0x8C92, 0xEBB2, 0x8C93, 0xBFDF, 0x8C94, 0xEEB7, 0x8C95, 0xEEB6, 0x8C97, 0xF0F2, 0x8C98, 0xF0F1, 0x8C99, 0xF0F0, + 0x8C9A, 0xF347, 0x8C9C, 0xF9AA, 0x8C9D, 0xA8A9, 0x8C9E, 0xAD73, 0x8CA0, 0xAD74, 0x8CA1, 0xB05D, 0x8CA2, 0xB05E, 0x8CA3, 0xD3E2, + 0x8CA4, 0xD3E1, 0x8CA5, 0xD7D2, 0x8CA7, 0xB368, 0x8CA8, 0xB366, 0x8CA9, 0xB363, 0x8CAA, 0xB367, 0x8CAB, 0xB365, 0x8CAC, 0xB364, + 0x8CAF, 0xB64A, 0x8CB0, 0xDBEA, 0x8CB2, 0xB8ED, 0x8CB3, 0xB64C, 0x8CB4, 0xB651, 0x8CB5, 0xDBEC, 0x8CB6, 0xB653, 0x8CB7, 0xB652, + 0x8CB8, 0xB655, 0x8CB9, 0xDBEB, 0x8CBA, 0xDBE8, 0x8CBB, 0xB64F, 0x8CBC, 0xB64B, 0x8CBD, 0xB64D, 0x8CBE, 0xDBE9, 0x8CBF, 0xB654, + 0x8CC0, 0xB650, 0x8CC1, 0xB64E, 0x8CC2, 0xB8EF, 0x8CC3, 0xB8EE, 0x8CC4, 0xB8EC, 0x8CC5, 0xB8F0, 0x8CC7, 0xB8EA, 0x8CC8, 0xB8EB, + 0x8CCA, 0xB8E9, 0x8CCC, 0xE05B, 0x8CCF, 0xE454, 0x8CD1, 0xBBAC, 0x8CD2, 0xBBAD, 0x8CD3, 0xBBAB, 0x8CD5, 0xE453, 0x8CD7, 0xE455, + 0x8CD9, 0xE7EA, 0x8CDA, 0xE7EC, 0x8CDC, 0xBDE7, 0x8CDD, 0xE7ED, 0x8CDE, 0xBDE0, 0x8CDF, 0xE7E9, 0x8CE0, 0xBDDF, 0x8CE1, 0xBDE9, + 0x8CE2, 0xBDE5, 0x8CE3, 0xBDE6, 0x8CE4, 0xBDE2, 0x8CE5, 0xE7E8, 0x8CE6, 0xBDE1, 0x8CE7, 0xE7EE, 0x8CE8, 0xE7EB, 0x8CEA, 0xBDE8, + 0x8CEC, 0xBDE3, 0x8CED, 0xBDE4, 0x8CEE, 0xEBB5, 0x8CF0, 0xEBB7, 0x8CF1, 0xEBB6, 0x8CF3, 0xEBB8, 0x8CF4, 0xBFE0, 0x8CF5, 0xEBB4, + 0x8CF8, 0xC1CB, 0x8CF9, 0xEEB8, 0x8CFA, 0xC1C8, 0x8CFB, 0xC1CC, 0x8CFC, 0xC1CA, 0x8CFD, 0xC1C9, 0x8CFE, 0xF0F3, 0x8D00, 0xF0F6, + 0x8D02, 0xF0F5, 0x8D04, 0xF0F4, 0x8D05, 0xC2D8, 0x8D06, 0xF348, 0x8D07, 0xF349, 0x8D08, 0xC3D8, 0x8D09, 0xF34A, 0x8D0A, 0xC3D9, + 0x8D0D, 0xC4BA, 0x8D0F, 0xC4B9, 0x8D10, 0xF652, 0x8D13, 0xC542, 0x8D14, 0xF653, 0x8D15, 0xF75C, 0x8D16, 0xC5AB, 0x8D17, 0xC5AC, + 0x8D19, 0xF845, 0x8D1B, 0xC642, 0x8D64, 0xA8AA, 0x8D66, 0xB36A, 0x8D67, 0xB369, 0x8D68, 0xE05C, 0x8D69, 0xE05D, 0x8D6B, 0xBBAE, + 0x8D6C, 0xEBB9, 0x8D6D, 0xBDEA, 0x8D6E, 0xEBBA, 0x8D6F, 0xEEB9, 0x8D70, 0xA8AB, 0x8D72, 0xD0B2, 0x8D73, 0xAD76, 0x8D74, 0xAD75, + 0x8D76, 0xD3E3, 0x8D77, 0xB05F, 0x8D78, 0xD3E4, 0x8D79, 0xD7D5, 0x8D7B, 0xD7D4, 0x8D7D, 0xD7D3, 0x8D80, 0xDBEE, 0x8D81, 0xB658, + 0x8D84, 0xDBED, 0x8D85, 0xB657, 0x8D89, 0xDBEF, 0x8D8A, 0xB656, 0x8D8C, 0xE05F, 0x8D8D, 0xE062, 0x8D8E, 0xE060, 0x8D8F, 0xE061, + 0x8D90, 0xE065, 0x8D91, 0xE05E, 0x8D92, 0xE066, 0x8D93, 0xE063, 0x8D94, 0xE064, 0x8D95, 0xBBB0, 0x8D96, 0xE456, 0x8D99, 0xBBAF, + 0x8D9B, 0xE7F2, 0x8D9C, 0xE7F0, 0x8D9F, 0xBDEB, 0x8DA0, 0xE7EF, 0x8DA1, 0xE7F1, 0x8DA3, 0xBDEC, 0x8DA5, 0xEBBB, 0x8DA7, 0xEBBC, + 0x8DA8, 0xC1CD, 0x8DAA, 0xF34C, 0x8DAB, 0xF34E, 0x8DAC, 0xF34B, 0x8DAD, 0xF34D, 0x8DAE, 0xF4D6, 0x8DAF, 0xF654, 0x8DB2, 0xF96F, + 0x8DB3, 0xA8AC, 0x8DB4, 0xAD77, 0x8DB5, 0xD3E5, 0x8DB6, 0xD3E7, 0x8DB7, 0xD3E6, 0x8DB9, 0xD7D8, 0x8DBA, 0xB36C, 0x8DBC, 0xD7D6, + 0x8DBE, 0xB36B, 0x8DBF, 0xD7D9, 0x8DC1, 0xD7DA, 0x8DC2, 0xD7D7, 0x8DC5, 0xDBFB, 0x8DC6, 0xB660, 0x8DC7, 0xDBF3, 0x8DC8, 0xDBF9, + 0x8DCB, 0xB65B, 0x8DCC, 0xB65E, 0x8DCD, 0xDBF2, 0x8DCE, 0xB659, 0x8DCF, 0xDBF6, 0x8DD0, 0xE06C, 0x8DD1, 0xB65D, 0x8DD3, 0xDBF1, + 0x8DD5, 0xDBF7, 0x8DD6, 0xDBF4, 0x8DD7, 0xDBFA, 0x8DD8, 0xDBF0, 0x8DD9, 0xDBF8, 0x8DDA, 0xB65C, 0x8DDB, 0xB65F, 0x8DDC, 0xDBF5, + 0x8DDD, 0xB65A, 0x8DDF, 0xB8F2, 0x8DE0, 0xE068, 0x8DE1, 0xB8F1, 0x8DE2, 0xE06F, 0x8DE3, 0xE06E, 0x8DE4, 0xB8F8, 0x8DE6, 0xB8F9, + 0x8DE7, 0xE070, 0x8DE8, 0xB8F3, 0x8DE9, 0xE06D, 0x8DEA, 0xB8F7, 0x8DEB, 0xE072, 0x8DEC, 0xE069, 0x8DEE, 0xE06B, 0x8DEF, 0xB8F4, + 0x8DF0, 0xE067, 0x8DF1, 0xE06A, 0x8DF2, 0xE071, 0x8DF3, 0xB8F5, 0x8DF4, 0xE073, 0x8DFA, 0xB8F6, 0x8DFC, 0xBBB1, 0x8DFD, 0xE45B, + 0x8DFE, 0xE461, 0x8DFF, 0xE459, 0x8E00, 0xE462, 0x8E02, 0xE458, 0x8E03, 0xE45D, 0x8E04, 0xE463, 0x8E05, 0xE460, 0x8E06, 0xE45F, + 0x8E07, 0xE45E, 0x8E09, 0xE457, 0x8E0A, 0xE45C, 0x8E0D, 0xE45A, 0x8E0F, 0xBDF1, 0x8E10, 0xBDEE, 0x8E11, 0xE7FB, 0x8E12, 0xE841, + 0x8E13, 0xE843, 0x8E14, 0xE840, 0x8E15, 0xE7F8, 0x8E16, 0xE7FA, 0x8E17, 0xE845, 0x8E18, 0xE842, 0x8E19, 0xE7FC, 0x8E1A, 0xE846, + 0x8E1B, 0xE7F9, 0x8E1C, 0xE844, 0x8E1D, 0xBDEF, 0x8E1E, 0xBDF5, 0x8E1F, 0xBDF3, 0x8E20, 0xE7F3, 0x8E21, 0xBDF4, 0x8E22, 0xBDF0, + 0x8E23, 0xE7F4, 0x8E24, 0xE7F6, 0x8E25, 0xE7F5, 0x8E26, 0xE7FD, 0x8E27, 0xE7FE, 0x8E29, 0xBDF2, 0x8E2B, 0xBDED, 0x8E2E, 0xE7F7, + 0x8E30, 0xEBC6, 0x8E31, 0xBFE2, 0x8E33, 0xEBBD, 0x8E34, 0xBFE3, 0x8E35, 0xBFE6, 0x8E36, 0xEBC2, 0x8E38, 0xEBBF, 0x8E39, 0xBFE5, + 0x8E3C, 0xEBC3, 0x8E3D, 0xEBC4, 0x8E3E, 0xEBBE, 0x8E3F, 0xEBC7, 0x8E40, 0xEBC0, 0x8E41, 0xEBC5, 0x8E42, 0xBFE4, 0x8E44, 0xBFE1, + 0x8E45, 0xEBC1, 0x8E47, 0xEEBF, 0x8E48, 0xC1D0, 0x8E49, 0xC1CE, 0x8E4A, 0xC1D1, 0x8E4B, 0xC1CF, 0x8E4C, 0xEEBE, 0x8E4D, 0xEEBB, + 0x8E4E, 0xEEBA, 0x8E50, 0xEEBD, 0x8E53, 0xEEBC, 0x8E54, 0xF145, 0x8E55, 0xC2DE, 0x8E56, 0xF0FB, 0x8E57, 0xF0FA, 0x8E59, 0xC2D9, + 0x8E5A, 0xF141, 0x8E5B, 0xF140, 0x8E5C, 0xF0F7, 0x8E5D, 0xF143, 0x8E5E, 0xF0FC, 0x8E5F, 0xC2DD, 0x8E60, 0xF0F9, 0x8E61, 0xF142, + 0x8E62, 0xF0F8, 0x8E63, 0xC2DA, 0x8E64, 0xC2DC, 0x8E65, 0xF0FD, 0x8E66, 0xC2DB, 0x8E67, 0xF0FE, 0x8E69, 0xF144, 0x8E6A, 0xF352, + 0x8E6C, 0xC3DE, 0x8E6D, 0xF34F, 0x8E6F, 0xF353, 0x8E72, 0xC3DB, 0x8E73, 0xF351, 0x8E74, 0xC3E0, 0x8E76, 0xC3DD, 0x8E78, 0xF350, + 0x8E7A, 0xC3DF, 0x8E7B, 0xF354, 0x8E7C, 0xC3DA, 0x8E81, 0xC4BC, 0x8E82, 0xC4BE, 0x8E84, 0xF4D9, 0x8E85, 0xC4BD, 0x8E86, 0xF4D7, + 0x8E87, 0xC3DC, 0x8E88, 0xF4D8, 0x8E89, 0xC4BB, 0x8E8A, 0xC543, 0x8E8B, 0xC545, 0x8E8C, 0xF656, 0x8E8D, 0xC544, 0x8E8E, 0xF655, + 0x8E90, 0xF761, 0x8E91, 0xC5AD, 0x8E92, 0xF760, 0x8E93, 0xC5AE, 0x8E94, 0xF75E, 0x8E95, 0xF75D, 0x8E96, 0xF762, 0x8E97, 0xF763, + 0x8E98, 0xF846, 0x8E9A, 0xF75F, 0x8E9D, 0xF8C6, 0x8E9E, 0xF8C3, 0x8E9F, 0xF8C4, 0x8EA0, 0xF8C5, 0x8EA1, 0xC65C, 0x8EA3, 0xF951, + 0x8EA4, 0xF950, 0x8EA5, 0xF94F, 0x8EA6, 0xF970, 0x8EA8, 0xF9BE, 0x8EA9, 0xF9AB, 0x8EAA, 0xC66E, 0x8EAB, 0xA8AD, 0x8EAC, 0xB060, + 0x8EB2, 0xB8FA, 0x8EBA, 0xBDF6, 0x8EBD, 0xEBC8, 0x8EC0, 0xC2DF, 0x8EC2, 0xF355, 0x8EC9, 0xF9AC, 0x8ECA, 0xA8AE, 0x8ECB, 0xAAEE, + 0x8ECC, 0xAD79, 0x8ECD, 0xAD78, 0x8ECF, 0xB063, 0x8ED1, 0xD3E8, 0x8ED2, 0xB061, 0x8ED3, 0xD3E9, 0x8ED4, 0xB062, 0x8ED7, 0xD7DF, + 0x8ED8, 0xD7DB, 0x8EDB, 0xB36D, 0x8EDC, 0xD7DE, 0x8EDD, 0xD7DD, 0x8EDE, 0xD7DC, 0x8EDF, 0xB36E, 0x8EE0, 0xD7E0, 0x8EE1, 0xD7E1, + 0x8EE5, 0xDC43, 0x8EE6, 0xDC41, 0x8EE7, 0xDC45, 0x8EE8, 0xDC46, 0x8EE9, 0xDC4C, 0x8EEB, 0xDC48, 0x8EEC, 0xDC4A, 0x8EEE, 0xDC42, + 0x8EEF, 0xDBFC, 0x8EF1, 0xDC49, 0x8EF4, 0xDC4B, 0x8EF5, 0xDC44, 0x8EF6, 0xDC47, 0x8EF7, 0xDBFD, 0x8EF8, 0xB662, 0x8EF9, 0xDC40, + 0x8EFA, 0xDBFE, 0x8EFB, 0xB661, 0x8EFC, 0xB663, 0x8EFE, 0xB8FD, 0x8EFF, 0xE075, 0x8F00, 0xE077, 0x8F01, 0xE076, 0x8F02, 0xE07B, + 0x8F03, 0xB8FB, 0x8F05, 0xE078, 0x8F06, 0xE074, 0x8F07, 0xE079, 0x8F08, 0xE07A, 0x8F09, 0xB8FC, 0x8F0A, 0xB8FE, 0x8F0B, 0xE07C, + 0x8F0D, 0xE467, 0x8F0E, 0xE466, 0x8F10, 0xE464, 0x8F11, 0xE465, 0x8F12, 0xBBB3, 0x8F13, 0xBBB5, 0x8F14, 0xBBB2, 0x8F15, 0xBBB4, + 0x8F16, 0xE84D, 0x8F17, 0xE84E, 0x8F18, 0xE849, 0x8F1A, 0xE84A, 0x8F1B, 0xBDF8, 0x8F1C, 0xBDFD, 0x8F1D, 0xBDF7, 0x8F1E, 0xBDFE, + 0x8F1F, 0xBDF9, 0x8F20, 0xE84B, 0x8F23, 0xE84C, 0x8F24, 0xE848, 0x8F25, 0xBE40, 0x8F26, 0xBDFB, 0x8F29, 0xBDFA, 0x8F2A, 0xBDFC, + 0x8F2C, 0xE847, 0x8F2E, 0xEBCA, 0x8F2F, 0xBFE8, 0x8F32, 0xEBCC, 0x8F33, 0xBFEA, 0x8F34, 0xEBCF, 0x8F35, 0xEBCB, 0x8F36, 0xEBC9, + 0x8F37, 0xEBCE, 0x8F38, 0xBFE9, 0x8F39, 0xEBCD, 0x8F3B, 0xBFE7, 0x8F3E, 0xC1D3, 0x8F3F, 0xC1D6, 0x8F40, 0xEEC1, 0x8F42, 0xC1D4, + 0x8F43, 0xEEC0, 0x8F44, 0xC1D2, 0x8F45, 0xC1D5, 0x8F46, 0xF146, 0x8F47, 0xF147, 0x8F48, 0xF148, 0x8F49, 0xC2E0, 0x8F4B, 0xF149, + 0x8F4D, 0xC2E1, 0x8F4E, 0xC3E2, 0x8F4F, 0xF358, 0x8F50, 0xF359, 0x8F51, 0xF357, 0x8F52, 0xF356, 0x8F53, 0xF35A, 0x8F54, 0xC3E1, + 0x8F55, 0xF4DD, 0x8F56, 0xF4DB, 0x8F57, 0xF4DC, 0x8F58, 0xF4DE, 0x8F59, 0xF4DA, 0x8F5A, 0xF4DF, 0x8F5B, 0xF658, 0x8F5D, 0xF659, + 0x8F5E, 0xF657, 0x8F5F, 0xC546, 0x8F60, 0xF764, 0x8F61, 0xC5AF, 0x8F62, 0xF765, 0x8F63, 0xF848, 0x8F64, 0xF847, 0x8F9B, 0xA8AF, + 0x8F9C, 0xB664, 0x8F9F, 0xB940, 0x8FA3, 0xBBB6, 0x8FA6, 0xBFEC, 0x8FA8, 0xBFEB, 0x8FAD, 0xC3E3, 0x8FAE, 0xC47C, 0x8FAF, 0xC547, + 0x8FB0, 0xA8B0, 0x8FB1, 0xB064, 0x8FB2, 0xB941, 0x8FB4, 0xF35B, 0x8FBF, 0xCBA6, 0x8FC2, 0xA8B1, 0x8FC4, 0xA8B4, 0x8FC5, 0xA8B3, + 0x8FC6, 0xA8B2, 0x8FC9, 0xCBA5, 0x8FCB, 0xCDCD, 0x8FCD, 0xCDCF, 0x8FCE, 0xAAEF, 0x8FD1, 0xAAF1, 0x8FD2, 0xCDCC, 0x8FD3, 0xCDCE, + 0x8FD4, 0xAAF0, 0x8FD5, 0xCDD1, 0x8FD6, 0xCDD0, 0x8FD7, 0xCDD2, 0x8FE0, 0xD0B6, 0x8FE1, 0xD0B4, 0x8FE2, 0xAD7C, 0x8FE3, 0xD0B3, + 0x8FE4, 0xADA3, 0x8FE5, 0xAD7E, 0x8FE6, 0xAD7B, 0x8FE8, 0xADA4, 0x8FEA, 0xAD7D, 0x8FEB, 0xADA2, 0x8FED, 0xADA1, 0x8FEE, 0xD0B5, + 0x8FF0, 0xAD7A, 0x8FF4, 0xB06A, 0x8FF5, 0xD3EB, 0x8FF6, 0xD3F1, 0x8FF7, 0xB067, 0x8FF8, 0xB06E, 0x8FFA, 0xB069, 0x8FFB, 0xD3EE, + 0x8FFC, 0xD3F0, 0x8FFD, 0xB06C, 0x8FFE, 0xD3EA, 0x8FFF, 0xD3ED, 0x9000, 0xB068, 0x9001, 0xB065, 0x9002, 0xD3EC, 0x9003, 0xB06B, + 0x9004, 0xD3EF, 0x9005, 0xB06D, 0x9006, 0xB066, 0x900B, 0xD7E3, 0x900C, 0xD7E6, 0x900D, 0xB370, 0x900F, 0xB37A, 0x9010, 0xB376, + 0x9011, 0xD7E4, 0x9014, 0xB37E, 0x9015, 0xB377, 0x9016, 0xB37C, 0x9017, 0xB372, 0x9019, 0xB36F, 0x901A, 0xB371, 0x901B, 0xB37D, + 0x901C, 0xD7E5, 0x901D, 0xB375, 0x901E, 0xB378, 0x901F, 0xB374, 0x9020, 0xB379, 0x9021, 0xD7E7, 0x9022, 0xB37B, 0x9023, 0xB373, + 0x9024, 0xD7E2, 0x902D, 0xDC4D, 0x902E, 0xB665, 0x902F, 0xDC4F, 0x9031, 0xB667, 0x9032, 0xB669, 0x9034, 0xDC4E, 0x9035, 0xB666, + 0x9036, 0xB66A, 0x9038, 0xB668, 0x903C, 0xB947, 0x903D, 0xE0A3, 0x903E, 0xB94F, 0x903F, 0xE07E, 0x9041, 0xB950, 0x9042, 0xB945, + 0x9044, 0xE0A1, 0x9047, 0xB94A, 0x9049, 0xE0A2, 0x904A, 0xB943, 0x904B, 0xB942, 0x904D, 0xB94D, 0x904E, 0xB94C, 0x904F, 0xB94B, + 0x9050, 0xB949, 0x9051, 0xB94E, 0x9052, 0xE07D, 0x9053, 0xB944, 0x9054, 0xB946, 0x9055, 0xB948, 0x9058, 0xBBB8, 0x9059, 0xBBBB, + 0x905B, 0xBBBF, 0x905C, 0xBBB9, 0x905D, 0xBBBE, 0x905E, 0xBBBC, 0x9060, 0xBBB7, 0x9062, 0xBBBD, 0x9063, 0xBBBA, 0x9067, 0xE852, + 0x9068, 0xBE43, 0x9069, 0xBE41, 0x906B, 0xE853, 0x906D, 0xBE44, 0x906E, 0xBE42, 0x906F, 0xE851, 0x9070, 0xE850, 0x9072, 0xBFF0, + 0x9073, 0xE84F, 0x9074, 0xBFEE, 0x9075, 0xBFED, 0x9076, 0xEBD0, 0x9077, 0xBE45, 0x9078, 0xBFEF, 0x9079, 0xEBD1, 0x907A, 0xBFF2, + 0x907B, 0xEBD2, 0x907C, 0xBFF1, 0x907D, 0xC1D8, 0x907E, 0xEEC3, 0x907F, 0xC1D7, 0x9080, 0xC1DC, 0x9081, 0xC1DA, 0x9082, 0xC1DB, + 0x9083, 0xC2E3, 0x9084, 0xC1D9, 0x9085, 0xEEC2, 0x9086, 0xEBD3, 0x9087, 0xC2E2, 0x9088, 0xC2E4, 0x908A, 0xC3E4, 0x908B, 0xC3E5, + 0x908D, 0xF4E0, 0x908F, 0xC5DE, 0x9090, 0xC5DD, 0x9091, 0xA8B6, 0x9094, 0xCA55, 0x9095, 0xB06F, 0x9097, 0xCA52, 0x9098, 0xCA53, + 0x9099, 0xCA51, 0x909B, 0xCA54, 0x909E, 0xCBAA, 0x909F, 0xCBA7, 0x90A0, 0xCBAC, 0x90A1, 0xCBA8, 0x90A2, 0xA8B7, 0x90A3, 0xA8BA, + 0x90A5, 0xCBA9, 0x90A6, 0xA8B9, 0x90A7, 0xCBAB, 0x90AA, 0xA8B8, 0x90AF, 0xCDD5, 0x90B0, 0xCDD7, 0x90B1, 0xAAF4, 0x90B2, 0xCDD3, + 0x90B3, 0xCDD6, 0x90B4, 0xCDD4, 0x90B5, 0xAAF2, 0x90B6, 0xAAF5, 0x90B8, 0xAAF3, 0x90BD, 0xD0B8, 0x90BE, 0xD0BC, 0x90BF, 0xD0B9, + 0x90C1, 0xADA7, 0x90C3, 0xADA8, 0x90C5, 0xD0BB, 0x90C7, 0xD0BD, 0x90C8, 0xD0BF, 0x90CA, 0xADA5, 0x90CB, 0xD0BE, 0x90CE, 0xADA6, + 0x90D4, 0xD7EE, 0x90D5, 0xD0BA, 0x90D6, 0xD3F2, 0x90D7, 0xD3FB, 0x90D8, 0xD3F9, 0x90D9, 0xD3F4, 0x90DA, 0xD3F5, 0x90DB, 0xD3FA, + 0x90DC, 0xD3FC, 0x90DD, 0xB071, 0x90DF, 0xD3F7, 0x90E0, 0xD3F3, 0x90E1, 0xB070, 0x90E2, 0xB072, 0x90E3, 0xD3F6, 0x90E4, 0xD3FD, + 0x90E5, 0xD3F8, 0x90E8, 0xB3A1, 0x90E9, 0xD7F1, 0x90EA, 0xD7E9, 0x90EB, 0xD7EF, 0x90EC, 0xD7F0, 0x90ED, 0xB3A2, 0x90EF, 0xD7E8, + 0x90F0, 0xD7EA, 0x90F1, 0xD0B7, 0x90F2, 0xD7EC, 0x90F3, 0xD7ED, 0x90F4, 0xD7EB, 0x90F5, 0xB66C, 0x90F9, 0xDC56, 0x90FA, 0xEBD4, + 0x90FB, 0xDC57, 0x90FC, 0xDC54, 0x90FD, 0xB3A3, 0x90FE, 0xB66E, 0x90FF, 0xDC53, 0x9100, 0xDC59, 0x9101, 0xDC58, 0x9102, 0xB66B, + 0x9103, 0xDC5C, 0x9104, 0xDC52, 0x9105, 0xDC5B, 0x9106, 0xDC50, 0x9107, 0xDC5A, 0x9108, 0xDC55, 0x9109, 0xB66D, 0x910B, 0xE0AA, + 0x910D, 0xE0A5, 0x910E, 0xE0AB, 0x910F, 0xE0A6, 0x9110, 0xE0A4, 0x9111, 0xE0A7, 0x9112, 0xB951, 0x9114, 0xE0A9, 0x9116, 0xE0A8, + 0x9117, 0xB952, 0x9118, 0xBBC1, 0x9119, 0xBBC0, 0x911A, 0xE46E, 0x911B, 0xE471, 0x911C, 0xE469, 0x911D, 0xE46D, 0x911E, 0xBBC2, + 0x911F, 0xE46C, 0x9120, 0xE46A, 0x9121, 0xE470, 0x9122, 0xE46B, 0x9123, 0xE468, 0x9124, 0xE46F, 0x9126, 0xE859, 0x9127, 0xBE48, + 0x9128, 0xF14A, 0x9129, 0xE856, 0x912A, 0xE857, 0x912B, 0xE855, 0x912C, 0xDC51, 0x912D, 0xBE47, 0x912E, 0xE85A, 0x912F, 0xE854, + 0x9130, 0xBE46, 0x9131, 0xBE49, 0x9132, 0xE858, 0x9133, 0xEBD5, 0x9134, 0xBFF3, 0x9135, 0xEBD6, 0x9136, 0xEBD7, 0x9138, 0xEEC4, + 0x9139, 0xC1DD, 0x913A, 0xF14B, 0x913B, 0xF14C, 0x913E, 0xF14D, 0x913F, 0xF35D, 0x9140, 0xF35C, 0x9141, 0xF4E2, 0x9143, 0xF4E1, + 0x9144, 0xF65B, 0x9145, 0xF65C, 0x9146, 0xF65A, 0x9147, 0xF766, 0x9148, 0xC5B0, 0x9149, 0xA8BB, 0x914A, 0xADAA, 0x914B, 0xADA9, + 0x914C, 0xB075, 0x914D, 0xB074, 0x914E, 0xD440, 0x914F, 0xD441, 0x9150, 0xD3FE, 0x9152, 0xB073, 0x9153, 0xD7F5, 0x9155, 0xD7F6, + 0x9156, 0xD7F2, 0x9157, 0xB3A4, 0x9158, 0xD7F3, 0x915A, 0xD7F4, 0x915F, 0xDC5F, 0x9160, 0xDC61, 0x9161, 0xDC5D, 0x9162, 0xDC60, + 0x9163, 0xB66F, 0x9164, 0xDC5E, 0x9165, 0xB670, 0x9168, 0xDD73, 0x9169, 0xB955, 0x916A, 0xB954, 0x916C, 0xB953, 0x916E, 0xE0AC, + 0x916F, 0xE0AD, 0x9172, 0xE473, 0x9173, 0xE475, 0x9174, 0xBBC6, 0x9175, 0xBBC3, 0x9177, 0xBBC5, 0x9178, 0xBBC4, 0x9179, 0xE474, + 0x917A, 0xE472, 0x9180, 0xE861, 0x9181, 0xE85E, 0x9182, 0xE85F, 0x9183, 0xBE4D, 0x9184, 0xE860, 0x9185, 0xE85B, 0x9186, 0xE85C, + 0x9187, 0xBE4A, 0x9189, 0xBE4B, 0x918A, 0xE85D, 0x918B, 0xBE4C, 0x918D, 0xEBDB, 0x918F, 0xEBDC, 0x9190, 0xEBD9, 0x9191, 0xEBDA, + 0x9192, 0xBFF4, 0x9193, 0xEBD8, 0x9199, 0xEEC8, 0x919A, 0xEEC5, 0x919B, 0xEEC7, 0x919C, 0xC1E0, 0x919D, 0xEECB, 0x919E, 0xC1DF, + 0x919F, 0xEEC9, 0x91A0, 0xEECC, 0x91A1, 0xEECA, 0x91A2, 0xEEC6, 0x91A3, 0xC1DE, 0x91A5, 0xF14F, 0x91A7, 0xF150, 0x91A8, 0xF14E, + 0x91AA, 0xF152, 0x91AB, 0xC2E5, 0x91AC, 0xC2E6, 0x91AD, 0xF35F, 0x91AE, 0xC3E7, 0x91AF, 0xF151, 0x91B0, 0xF35E, 0x91B1, 0xC3E6, + 0x91B2, 0xF4E5, 0x91B3, 0xF4E6, 0x91B4, 0xC4BF, 0x91B5, 0xF4E4, 0x91B7, 0xF4E3, 0x91B9, 0xF65D, 0x91BA, 0xC548, 0x91BC, 0xF849, + 0x91BD, 0xF8C8, 0x91BE, 0xF8C7, 0x91C0, 0xC643, 0x91C1, 0xC65D, 0x91C2, 0xF8C9, 0x91C3, 0xF971, 0x91C5, 0xC66F, 0x91C6, 0xA8BC, + 0x91C7, 0xAAF6, 0x91C9, 0xB956, 0x91CB, 0xC4C0, 0x91CC, 0xA8BD, 0x91CD, 0xADAB, 0x91CE, 0xB3A5, 0x91CF, 0xB671, 0x91D0, 0xC2E7, + 0x91D1, 0xAAF7, 0x91D3, 0xD0C1, 0x91D4, 0xD0C0, 0x91D5, 0xD442, 0x91D7, 0xB078, 0x91D8, 0xB076, 0x91D9, 0xB07A, 0x91DA, 0xD444, + 0x91DC, 0xB079, 0x91DD, 0xB077, 0x91E2, 0xD443, 0x91E3, 0xB3A8, 0x91E4, 0xD7FC, 0x91E6, 0xB3A7, 0x91E7, 0xB3A9, 0x91E8, 0xD842, + 0x91E9, 0xB3AB, 0x91EA, 0xD7FE, 0x91EB, 0xD840, 0x91EC, 0xD7F7, 0x91ED, 0xB3AA, 0x91EE, 0xD843, 0x91F1, 0xD7F9, 0x91F3, 0xD7FA, + 0x91F4, 0xD7F8, 0x91F5, 0xB3A6, 0x91F7, 0xD841, 0x91F8, 0xD7FB, 0x91F9, 0xD7FD, 0x91FD, 0xDC6D, 0x91FF, 0xDC6C, 0x9200, 0xDC6A, + 0x9201, 0xDC62, 0x9202, 0xDC71, 0x9203, 0xDC65, 0x9204, 0xDC6F, 0x9205, 0xDC76, 0x9206, 0xDC6E, 0x9207, 0xB679, 0x9209, 0xB675, + 0x920A, 0xDC63, 0x920C, 0xDC69, 0x920D, 0xB677, 0x920F, 0xDC68, 0x9210, 0xB678, 0x9211, 0xB67A, 0x9212, 0xDC6B, 0x9214, 0xB672, + 0x9215, 0xB673, 0x9216, 0xDC77, 0x9217, 0xDC75, 0x9219, 0xDC74, 0x921A, 0xDC66, 0x921C, 0xDC72, 0x921E, 0xB676, 0x9223, 0xB674, + 0x9224, 0xDC73, 0x9225, 0xDC64, 0x9226, 0xDC67, 0x9227, 0xDC70, 0x922D, 0xE4BA, 0x922E, 0xE0B7, 0x9230, 0xE0B0, 0x9231, 0xE0C3, + 0x9232, 0xE0CC, 0x9233, 0xE0B3, 0x9234, 0xB961, 0x9236, 0xE0C0, 0x9237, 0xB957, 0x9238, 0xB959, 0x9239, 0xB965, 0x923A, 0xE0B1, + 0x923D, 0xB95A, 0x923E, 0xB95C, 0x923F, 0xB966, 0x9240, 0xB95B, 0x9245, 0xB964, 0x9246, 0xE0B9, 0x9248, 0xE0AE, 0x9249, 0xB962, + 0x924A, 0xE0B8, 0x924B, 0xB95E, 0x924C, 0xE0CA, 0x924D, 0xB963, 0x924E, 0xE0C8, 0x924F, 0xE0BC, 0x9250, 0xE0C6, 0x9251, 0xB960, + 0x9252, 0xE0AF, 0x9253, 0xE0C9, 0x9254, 0xE0C4, 0x9256, 0xE0CB, 0x9257, 0xB958, 0x925A, 0xB967, 0x925B, 0xB95D, 0x925E, 0xE0B5, + 0x9260, 0xE0BD, 0x9261, 0xE0C1, 0x9263, 0xE0C5, 0x9264, 0xB95F, 0x9265, 0xE0B4, 0x9266, 0xE0B2, 0x9267, 0xE0BE, 0x926C, 0xE0BB, + 0x926D, 0xE0BA, 0x926F, 0xE0BF, 0x9270, 0xE0C2, 0x9272, 0xE0C7, 0x9276, 0xE478, 0x9278, 0xBBC7, 0x9279, 0xE4A4, 0x927A, 0xE47A, + 0x927B, 0xBBCC, 0x927C, 0xBBD0, 0x927D, 0xE4AD, 0x927E, 0xE4B5, 0x927F, 0xE4A6, 0x9280, 0xBBC8, 0x9282, 0xE4AA, 0x9283, 0xE0B6, + 0x9285, 0xBBC9, 0x9286, 0xE4B1, 0x9287, 0xE4B6, 0x9288, 0xE4AE, 0x928A, 0xE4B0, 0x928B, 0xE4B9, 0x928C, 0xE4B2, 0x928D, 0xE47E, + 0x928E, 0xE4A9, 0x9291, 0xBBD1, 0x9293, 0xBBCD, 0x9294, 0xE47C, 0x9295, 0xE4AB, 0x9296, 0xBBCB, 0x9297, 0xE4A5, 0x9298, 0xBBCA, + 0x9299, 0xE4B3, 0x929A, 0xE4A2, 0x929B, 0xE479, 0x929C, 0xBBCE, 0x929D, 0xE4B8, 0x92A0, 0xE47B, 0x92A1, 0xE4AF, 0x92A2, 0xE4AC, + 0x92A3, 0xE4A7, 0x92A4, 0xE477, 0x92A5, 0xE476, 0x92A6, 0xE4A1, 0x92A7, 0xE4B4, 0x92A8, 0xBBCF, 0x92A9, 0xE4B7, 0x92AA, 0xE47D, + 0x92AB, 0xE4A3, 0x92AC, 0xBE52, 0x92B2, 0xBE5A, 0x92B3, 0xBE55, 0x92B4, 0xE8A4, 0x92B5, 0xE8A1, 0x92B6, 0xE867, 0x92B7, 0xBE50, + 0x92B9, 0xF9D7, 0x92BB, 0xBE4F, 0x92BC, 0xBE56, 0x92C0, 0xE865, 0x92C1, 0xBE54, 0x92C2, 0xE871, 0x92C3, 0xE863, 0x92C4, 0xE864, + 0x92C5, 0xBE4E, 0x92C6, 0xE8A3, 0x92C7, 0xBE58, 0x92C8, 0xE874, 0x92C9, 0xE879, 0x92CA, 0xE873, 0x92CB, 0xEBEE, 0x92CC, 0xE86F, + 0x92CD, 0xE877, 0x92CE, 0xE875, 0x92CF, 0xE868, 0x92D0, 0xE862, 0x92D1, 0xE87D, 0x92D2, 0xBE57, 0x92D3, 0xE87E, 0x92D5, 0xE878, + 0x92D7, 0xE86D, 0x92D8, 0xE86B, 0x92D9, 0xE866, 0x92DD, 0xE86E, 0x92DE, 0xE87B, 0x92DF, 0xE86A, 0x92E0, 0xE87A, 0x92E1, 0xE8A2, + 0x92E4, 0xBE53, 0x92E6, 0xE876, 0x92E7, 0xE87C, 0x92E8, 0xE872, 0x92E9, 0xE86C, 0x92EA, 0xBE51, 0x92EE, 0xE4A8, 0x92EF, 0xE870, + 0x92F0, 0xBE59, 0x92F1, 0xE869, 0x92F7, 0xEBF4, 0x92F8, 0xBFF7, 0x92F9, 0xEBF3, 0x92FA, 0xEBF0, 0x92FB, 0xEC44, 0x92FC, 0xBFFB, + 0x92FE, 0xEC41, 0x92FF, 0xEBF8, 0x9300, 0xEC43, 0x9301, 0xEBE9, 0x9302, 0xEBF6, 0x9304, 0xBFFD, 0x9306, 0xEBE1, 0x9308, 0xEBDF, + 0x9309, 0xEC42, 0x930B, 0xEC40, 0x930C, 0xEBFE, 0x930D, 0xEBED, 0x930E, 0xEBEC, 0x930F, 0xEBE2, 0x9310, 0xC040, 0x9312, 0xEBE8, + 0x9313, 0xEBF2, 0x9314, 0xEBFD, 0x9315, 0xC043, 0x9316, 0xEC45, 0x9318, 0xC1E8, 0x9319, 0xC045, 0x931A, 0xBFFE, 0x931B, 0xEBE6, + 0x931D, 0xEBEF, 0x931E, 0xEBDE, 0x931F, 0xEBE0, 0x9320, 0xBFF5, 0x9321, 0xC042, 0x9322, 0xBFFA, 0x9323, 0xEBE7, 0x9324, 0xEBF7, + 0x9325, 0xEBF1, 0x9326, 0xC041, 0x9327, 0xEBDD, 0x9328, 0xC1E3, 0x9329, 0xEBF9, 0x932A, 0xEBFC, 0x932B, 0xBFFC, 0x932D, 0xEBEB, + 0x932E, 0xC044, 0x932F, 0xBFF9, 0x9333, 0xBFF8, 0x9334, 0xEBF5, 0x9335, 0xEBFB, 0x9336, 0xBFF6, 0x9338, 0xEBE4, 0x9339, 0xEBFA, + 0x933C, 0xEBE5, 0x9346, 0xEBEA, 0x9347, 0xEED2, 0x9349, 0xEED7, 0x934A, 0xC1E5, 0x934B, 0xC1E7, 0x934C, 0xEEDD, 0x934D, 0xC1E1, + 0x934E, 0xEEEC, 0x934F, 0xEEE3, 0x9350, 0xEED8, 0x9351, 0xEED9, 0x9352, 0xEEE2, 0x9354, 0xC1EE, 0x9355, 0xEEE1, 0x9356, 0xEED1, + 0x9357, 0xEEE0, 0x9358, 0xEED4, 0x9359, 0xEEED, 0x935A, 0xC1ED, 0x935B, 0xC1EB, 0x935C, 0xEED5, 0x935E, 0xEEE8, 0x9360, 0xEEDA, + 0x9361, 0xEEE7, 0x9363, 0xEEE9, 0x9364, 0xEED0, 0x9365, 0xC1E6, 0x9367, 0xEEEA, 0x936A, 0xEEDE, 0x936C, 0xC1EA, 0x936D, 0xEEDB, + 0x9370, 0xC1EC, 0x9371, 0xEEE4, 0x9375, 0xC1E4, 0x9376, 0xEED6, 0x9377, 0xEEE5, 0x9379, 0xEEDF, 0x937A, 0xEBE3, 0x937B, 0xEEE6, + 0x937C, 0xEED3, 0x937E, 0xC1E9, 0x9380, 0xEEEB, 0x9382, 0xC1E2, 0x9383, 0xEECE, 0x9388, 0xF160, 0x9389, 0xF159, 0x938A, 0xC2E9, + 0x938C, 0xF154, 0x938D, 0xF163, 0x938E, 0xF15B, 0x938F, 0xEEDC, 0x9391, 0xF165, 0x9392, 0xF155, 0x9394, 0xC2E8, 0x9395, 0xF15F, + 0x9396, 0xC2EA, 0x9397, 0xC2F2, 0x9398, 0xC2F0, 0x9399, 0xF161, 0x939A, 0xC2F1, 0x939B, 0xF157, 0x939D, 0xF158, 0x939E, 0xF15D, + 0x939F, 0xF162, 0x93A1, 0xEECD, 0x93A2, 0xC2EB, 0x93A3, 0xF16A, 0x93A4, 0xF167, 0x93A5, 0xF16B, 0x93A6, 0xF15E, 0x93A7, 0xF15A, + 0x93A8, 0xF168, 0x93A9, 0xF36A, 0x93AA, 0xF15C, 0x93AC, 0xC2EE, 0x93AE, 0xC2ED, 0x93AF, 0xEECF, 0x93B0, 0xC2EF, 0x93B1, 0xF164, + 0x93B2, 0xF166, 0x93B3, 0xC2EC, 0x93B4, 0xF169, 0x93B5, 0xF153, 0x93B7, 0xF156, 0x93C0, 0xF373, 0x93C2, 0xF363, 0x93C3, 0xC3EB, + 0x93C4, 0xF371, 0x93C7, 0xF361, 0x93C8, 0xC3EC, 0x93CA, 0xF36C, 0x93CC, 0xF368, 0x93CD, 0xC3F1, 0x93CE, 0xF372, 0x93CF, 0xF362, + 0x93D0, 0xF365, 0x93D1, 0xC3E9, 0x93D2, 0xF374, 0x93D4, 0xF36D, 0x93D5, 0xF370, 0x93D6, 0xC3EF, 0x93D7, 0xC3F4, 0x93D8, 0xC3F2, + 0x93D9, 0xF369, 0x93DA, 0xF364, 0x93DC, 0xC3ED, 0x93DD, 0xC3EE, 0x93DE, 0xF360, 0x93DF, 0xC3EA, 0x93E1, 0xC3E8, 0x93E2, 0xC3F0, + 0x93E3, 0xF36F, 0x93E4, 0xC3F3, 0x93E6, 0xF36B, 0x93E7, 0xF375, 0x93E8, 0xC3F5, 0x93EC, 0xF367, 0x93EE, 0xF36E, 0x93F5, 0xF4F3, + 0x93F6, 0xF542, 0x93F7, 0xF4F5, 0x93F8, 0xF4FC, 0x93F9, 0xF366, 0x93FA, 0xF4FA, 0x93FB, 0xF4E9, 0x93FC, 0xF540, 0x93FD, 0xC4C3, + 0x93FE, 0xF4ED, 0x93FF, 0xF4FE, 0x9400, 0xF4F4, 0x9403, 0xC4C2, 0x9406, 0xF544, 0x9407, 0xF4F6, 0x9409, 0xF4FB, 0x940A, 0xF4FD, + 0x940B, 0xF4E7, 0x940C, 0xF541, 0x940D, 0xF4F2, 0x940E, 0xF4F7, 0x940F, 0xF4EB, 0x9410, 0xF4EF, 0x9411, 0xF543, 0x9412, 0xF4F9, + 0x9413, 0xF4E8, 0x9414, 0xF4EC, 0x9415, 0xF4EE, 0x9416, 0xF4F8, 0x9418, 0xC4C1, 0x9419, 0xF4F1, 0x9420, 0xF4EA, 0x9428, 0xF4F0, + 0x9429, 0xF661, 0x942A, 0xF666, 0x942B, 0xC54F, 0x942C, 0xF668, 0x942E, 0xC549, 0x9430, 0xF664, 0x9431, 0xF66A, 0x9432, 0xC54E, + 0x9433, 0xC54A, 0x9435, 0xC54B, 0x9436, 0xF660, 0x9437, 0xF667, 0x9438, 0xC54D, 0x9439, 0xF665, 0x943A, 0xC54C, 0x943B, 0xF65F, + 0x943C, 0xF663, 0x943D, 0xF662, 0x943F, 0xF65E, 0x9440, 0xF669, 0x9444, 0xC5B1, 0x9445, 0xF76D, 0x9446, 0xF770, 0x9447, 0xF76C, + 0x9448, 0xF76E, 0x9449, 0xF76F, 0x944A, 0xF769, 0x944B, 0xF76A, 0x944C, 0xF767, 0x944F, 0xF76B, 0x9450, 0xF768, 0x9451, 0xC5B2, + 0x9452, 0xC5B3, 0x9455, 0xF84B, 0x9457, 0xF84D, 0x945D, 0xF84C, 0x945E, 0xF84E, 0x9460, 0xC5E0, 0x9462, 0xF84A, 0x9463, 0xC5DF, + 0x9464, 0xC5E1, 0x9468, 0xF8CB, 0x9469, 0xF8CC, 0x946A, 0xC644, 0x946B, 0xF8CA, 0x946D, 0xF953, 0x946E, 0xF952, 0x946F, 0xF954, + 0x9470, 0xC65F, 0x9471, 0xF955, 0x9472, 0xC65E, 0x9473, 0xF956, 0x9474, 0xF972, 0x9475, 0xF975, 0x9476, 0xF974, 0x9477, 0xC668, + 0x9478, 0xF973, 0x947C, 0xC672, 0x947D, 0xC670, 0x947E, 0xC671, 0x947F, 0xC677, 0x9480, 0xF9C0, 0x9481, 0xF9C1, 0x9482, 0xF9BF, + 0x9483, 0xF9C9, 0x9577, 0xAAF8, 0x957A, 0xD844, 0x957B, 0xDC78, 0x957C, 0xE8A5, 0x957D, 0xF376, 0x9580, 0xAAF9, 0x9582, 0xADAC, + 0x9583, 0xB07B, 0x9586, 0xD845, 0x9588, 0xD846, 0x9589, 0xB3AC, 0x958B, 0xB67D, 0x958C, 0xDC7A, 0x958D, 0xDC79, 0x958E, 0xB6A3, + 0x958F, 0xB67C, 0x9590, 0xDC7B, 0x9591, 0xB67E, 0x9592, 0xB6A2, 0x9593, 0xB6A1, 0x9594, 0xB67B, 0x9598, 0xB968, 0x959B, 0xE0D0, + 0x959C, 0xE0CE, 0x959E, 0xE0CF, 0x959F, 0xE0CD, 0x95A1, 0xBBD2, 0x95A3, 0xBBD5, 0x95A4, 0xBBD7, 0x95A5, 0xBBD6, 0x95A8, 0xBBD3, + 0x95A9, 0xBBD4, 0x95AB, 0xE8A7, 0x95AC, 0xE8A6, 0x95AD, 0xBE5B, 0x95AE, 0xE8A8, 0x95B0, 0xE8A9, 0x95B1, 0xBE5C, 0x95B5, 0xEC4D, + 0x95B6, 0xEC4B, 0x95B7, 0xEEF3, 0x95B9, 0xEC49, 0x95BA, 0xEC4A, 0x95BB, 0xC046, 0x95BC, 0xEC46, 0x95BD, 0xEC4E, 0x95BE, 0xEC48, + 0x95BF, 0xEC4C, 0x95C0, 0xEEEF, 0x95C3, 0xEEF1, 0x95C5, 0xEEF2, 0x95C6, 0xC1F3, 0x95C7, 0xEEEE, 0x95C8, 0xC1F2, 0x95C9, 0xEEF0, + 0x95CA, 0xC1EF, 0x95CB, 0xC1F0, 0x95CC, 0xC1F1, 0x95CD, 0xEC47, 0x95D0, 0xC2F5, 0x95D1, 0xF16E, 0x95D2, 0xF16C, 0x95D3, 0xF16D, + 0x95D4, 0xC2F3, 0x95D5, 0xC2F6, 0x95D6, 0xC2F4, 0x95DA, 0xF377, 0x95DB, 0xF378, 0x95DC, 0xC3F6, 0x95DE, 0xF545, 0x95DF, 0xF547, + 0x95E0, 0xF546, 0x95E1, 0xC4C4, 0x95E2, 0xC550, 0x95E3, 0xF66D, 0x95E4, 0xF66C, 0x95E5, 0xF66B, 0x961C, 0xAAFA, 0x961E, 0xC9AA, + 0x9620, 0xCA58, 0x9621, 0xA6E9, 0x9622, 0xCA56, 0x9623, 0xCA59, 0x9624, 0xCA57, 0x9628, 0xCBAE, 0x962A, 0xA8C1, 0x962C, 0xA8C2, + 0x962D, 0xCBB0, 0x962E, 0xA8BF, 0x962F, 0xCBAF, 0x9630, 0xCBAD, 0x9631, 0xA8C0, 0x9632, 0xA8BE, 0x9639, 0xCDD8, 0x963A, 0xCDDB, + 0x963B, 0xAAFD, 0x963C, 0xCDDA, 0x963D, 0xCDD9, 0x963F, 0xAAFC, 0x9640, 0xAAFB, 0x9642, 0xAB40, 0x9643, 0xCDDC, 0x9644, 0xAAFE, + 0x964A, 0xD0C6, 0x964B, 0xADAE, 0x964C, 0xADAF, 0x964D, 0xADB0, 0x964E, 0xD0C7, 0x964F, 0xD0C3, 0x9650, 0xADAD, 0x9651, 0xD0C4, + 0x9653, 0xD0C5, 0x9654, 0xD0C2, 0x9658, 0xB0A4, 0x965B, 0xB0A1, 0x965C, 0xD445, 0x965D, 0xB0A2, 0x965E, 0xB0A5, 0x965F, 0xD446, + 0x9661, 0xB07E, 0x9662, 0xB07C, 0x9663, 0xB07D, 0x9664, 0xB0A3, 0x966A, 0xB3AD, 0x966B, 0xD849, 0x966C, 0xB3B5, 0x966D, 0xD848, + 0x966F, 0xD84B, 0x9670, 0xB3B1, 0x9671, 0xD84A, 0x9672, 0xB6AB, 0x9673, 0xB3AF, 0x9674, 0xB3B2, 0x9675, 0xB3AE, 0x9676, 0xB3B3, + 0x9677, 0xB3B4, 0x9678, 0xB3B0, 0x967C, 0xD847, 0x967D, 0xB6A7, 0x967E, 0xDC7D, 0x9680, 0xDCA3, 0x9683, 0xDCA2, 0x9684, 0xB6AC, + 0x9685, 0xB6A8, 0x9686, 0xB6A9, 0x9687, 0xDC7C, 0x9688, 0xDC7E, 0x9689, 0xDCA1, 0x968A, 0xB6A4, 0x968B, 0xB6A6, 0x968D, 0xB6AA, + 0x968E, 0xB6A5, 0x9691, 0xE0D3, 0x9692, 0xE0D1, 0x9693, 0xE0D2, 0x9694, 0xB96A, 0x9695, 0xB96B, 0x9697, 0xE0D4, 0x9698, 0xB969, + 0x9699, 0xBBD8, 0x969B, 0xBBDA, 0x969C, 0xBBD9, 0x969E, 0xE4BB, 0x96A1, 0xE4BC, 0x96A2, 0xE8AB, 0x96A4, 0xE8AA, 0x96A7, 0xC047, + 0x96A8, 0xC048, 0x96A9, 0xEC4F, 0x96AA, 0xC049, 0x96AC, 0xEEF6, 0x96AE, 0xEEF4, 0x96B0, 0xEEF5, 0x96B1, 0xC1F4, 0x96B3, 0xF16F, + 0x96B4, 0xC3F7, 0x96B8, 0xC1F5, 0x96B9, 0xAB41, 0x96BB, 0xB0A6, 0x96BC, 0xD447, 0x96BF, 0xD84C, 0x96C0, 0xB3B6, 0x96C1, 0xB6AD, + 0x96C2, 0xDCA4, 0x96C3, 0xDCA6, 0x96C4, 0xB6AF, 0x96C5, 0xB6AE, 0x96C6, 0xB6B0, 0x96C7, 0xB6B1, 0x96C8, 0xDCA5, 0x96C9, 0xB96E, + 0x96CA, 0xB96F, 0x96CB, 0xB96D, 0x96CC, 0xBBDB, 0x96CD, 0xB96C, 0x96CE, 0xE0D5, 0x96D2, 0xBBDC, 0x96D3, 0xE8AC, 0x96D4, 0xEC50, + 0x96D5, 0xC04A, 0x96D6, 0xC1F6, 0x96D7, 0xF170, 0x96D8, 0xF174, 0x96D9, 0xC2F9, 0x96DA, 0xF171, 0x96DB, 0xC2FA, 0x96DC, 0xC2F8, + 0x96DD, 0xF175, 0x96DE, 0xC2FB, 0x96DF, 0xF173, 0x96E1, 0xF379, 0x96E2, 0xC2F7, 0x96E3, 0xC3F8, 0x96E5, 0xF8CD, 0x96E8, 0xAB42, + 0x96E9, 0xB3B8, 0x96EA, 0xB3B7, 0x96EF, 0xB6B2, 0x96F0, 0xDCA8, 0x96F1, 0xDCA7, 0x96F2, 0xB6B3, 0x96F5, 0xE0D9, 0x96F6, 0xB973, + 0x96F7, 0xB970, 0x96F8, 0xE0D8, 0x96F9, 0xB972, 0x96FA, 0xE0D6, 0x96FB, 0xB971, 0x96FD, 0xE0D7, 0x96FF, 0xE4BD, 0x9700, 0xBBDD, + 0x9702, 0xE8AF, 0x9704, 0xBE5D, 0x9705, 0xE8AD, 0x9706, 0xBE5E, 0x9707, 0xBE5F, 0x9708, 0xE8AE, 0x9709, 0xBE60, 0x970B, 0xEC51, + 0x970D, 0xC04E, 0x970E, 0xC04B, 0x970F, 0xC050, 0x9710, 0xEC53, 0x9711, 0xC04C, 0x9712, 0xEC52, 0x9713, 0xC04F, 0x9716, 0xC04D, + 0x9718, 0xEEF9, 0x9719, 0xEEFB, 0x971C, 0xC1F7, 0x971D, 0xEEFA, 0x971E, 0xC1F8, 0x971F, 0xEEF8, 0x9720, 0xEEF7, 0x9722, 0xF177, + 0x9723, 0xF176, 0x9724, 0xC2FC, 0x9725, 0xF178, 0x9726, 0xF37E, 0x9727, 0xC3FA, 0x9728, 0xF37D, 0x9729, 0xF37A, 0x972A, 0xC3F9, + 0x972B, 0xF37B, 0x972C, 0xF37C, 0x972E, 0xF548, 0x972F, 0xF549, 0x9730, 0xC4C5, 0x9732, 0xC553, 0x9735, 0xF66E, 0x9738, 0xC551, + 0x9739, 0xC552, 0x973A, 0xF66F, 0x973D, 0xC5B4, 0x973E, 0xC5B5, 0x973F, 0xF771, 0x9742, 0xC645, 0x9743, 0xF8CF, 0x9744, 0xC647, + 0x9746, 0xF8CE, 0x9747, 0xF8D0, 0x9748, 0xC646, 0x9749, 0xF957, 0x974B, 0xF9AD, 0x9752, 0xAB43, 0x9756, 0xB974, 0x9758, 0xE4BE, + 0x975A, 0xE8B0, 0x975B, 0xC051, 0x975C, 0xC052, 0x975E, 0xAB44, 0x9760, 0xBE61, 0x9761, 0xC3FB, 0x9762, 0xADB1, 0x9766, 0xC053, + 0x9768, 0xC5E2, 0x9769, 0xADB2, 0x976A, 0xD84D, 0x976C, 0xDCA9, 0x976E, 0xDCAB, 0x9770, 0xDCAA, 0x9772, 0xE0DD, 0x9773, 0xE0DA, + 0x9774, 0xB975, 0x9776, 0xB976, 0x9777, 0xE0DB, 0x9778, 0xE0DC, 0x977A, 0xE4C0, 0x977B, 0xE4C5, 0x977C, 0xBBDE, 0x977D, 0xE4BF, + 0x977E, 0xE4C1, 0x977F, 0xE4C8, 0x9780, 0xE4C3, 0x9781, 0xE4C7, 0x9782, 0xE4C4, 0x9783, 0xE4C2, 0x9784, 0xE4C6, 0x9785, 0xBBDF, + 0x9788, 0xE8B3, 0x978A, 0xE8B1, 0x978B, 0xBE63, 0x978D, 0xBE62, 0x978E, 0xE8B2, 0x978F, 0xBE64, 0x9794, 0xEC56, 0x9797, 0xEC55, + 0x9798, 0xC054, 0x9799, 0xEC54, 0x979A, 0xEEFC, 0x979C, 0xEEFE, 0x979D, 0xEF41, 0x979E, 0xEF40, 0x97A0, 0xC1F9, 0x97A1, 0xEEFD, + 0x97A2, 0xF1A1, 0x97A3, 0xC2FD, 0x97A4, 0xF17D, 0x97A5, 0xF1A2, 0x97A6, 0xC2FE, 0x97A8, 0xF17B, 0x97AA, 0xF17E, 0x97AB, 0xF17C, + 0x97AC, 0xF179, 0x97AD, 0xC340, 0x97AE, 0xF17A, 0x97B3, 0xF3A1, 0x97B6, 0xF3A3, 0x97B7, 0xF3A2, 0x97B9, 0xF54A, 0x97BB, 0xF54B, + 0x97BF, 0xF670, 0x97C1, 0xC5B7, 0x97C3, 0xC5B6, 0x97C4, 0xF84F, 0x97C5, 0xF850, 0x97C6, 0xC648, 0x97C7, 0xF8D1, 0x97C9, 0xC669, + 0x97CB, 0xADB3, 0x97CC, 0xB6B4, 0x97CD, 0xE4CA, 0x97CE, 0xE4C9, 0x97CF, 0xE8B5, 0x97D0, 0xE8B4, 0x97D3, 0xC1FA, 0x97D4, 0xEF43, + 0x97D5, 0xEF42, 0x97D6, 0xF1A5, 0x97D7, 0xF1A3, 0x97D8, 0xF1A6, 0x97D9, 0xF1A4, 0x97DC, 0xC3FC, 0x97DD, 0xF3A4, 0x97DE, 0xF3A5, + 0x97DF, 0xF3A6, 0x97E1, 0xF671, 0x97E3, 0xF772, 0x97E5, 0xF8D2, 0x97ED, 0xADB4, 0x97F0, 0xEC57, 0x97F1, 0xEF44, 0x97F3, 0xADB5, + 0x97F6, 0xBBE0, 0x97F8, 0xEC58, 0x97F9, 0xC341, 0x97FA, 0xF1A7, 0x97FB, 0xC3FD, 0x97FD, 0xF54C, 0x97FE, 0xF54D, 0x97FF, 0xC554, + 0x9800, 0xF851, 0x9801, 0xADB6, 0x9802, 0xB3BB, 0x9803, 0xB3BC, 0x9804, 0xD84E, 0x9805, 0xB6B5, 0x9806, 0xB6B6, 0x9807, 0xDCAC, + 0x9808, 0xB6B7, 0x980A, 0xB97A, 0x980C, 0xB97C, 0x980D, 0xE0DF, 0x980E, 0xE0E0, 0x980F, 0xE0DE, 0x9810, 0xB977, 0x9811, 0xB978, + 0x9812, 0xB97B, 0x9813, 0xB979, 0x9816, 0xE4CB, 0x9817, 0xBBE1, 0x9818, 0xBBE2, 0x981B, 0xE8BC, 0x981C, 0xBE67, 0x981D, 0xE8B7, + 0x981E, 0xE8B6, 0x9820, 0xE8BB, 0x9821, 0xBE65, 0x9824, 0xC05B, 0x9826, 0xE8B8, 0x9827, 0xE8BD, 0x9828, 0xE8BA, 0x9829, 0xE8B9, + 0x982B, 0xBE66, 0x982D, 0xC059, 0x982F, 0xEC5A, 0x9830, 0xC055, 0x9832, 0xEC5B, 0x9835, 0xEC59, 0x9837, 0xC058, 0x9838, 0xC056, + 0x9839, 0xC05A, 0x983B, 0xC057, 0x9841, 0xEF45, 0x9843, 0xEF4A, 0x9844, 0xEF46, 0x9845, 0xEF49, 0x9846, 0xC1FB, 0x9848, 0xEDD4, + 0x9849, 0xEF48, 0x984A, 0xEF47, 0x984C, 0xC344, 0x984D, 0xC342, 0x984E, 0xC345, 0x984F, 0xC343, 0x9850, 0xF1A8, 0x9851, 0xF1A9, + 0x9852, 0xF1AA, 0x9853, 0xC346, 0x9857, 0xF3AA, 0x9858, 0xC440, 0x9859, 0xF3A8, 0x985B, 0xC441, 0x985C, 0xF3A7, 0x985D, 0xF3A9, + 0x985E, 0xC3FE, 0x985F, 0xF551, 0x9860, 0xF54E, 0x9862, 0xF54F, 0x9863, 0xF550, 0x9864, 0xF672, 0x9865, 0xC556, 0x9867, 0xC555, + 0x9869, 0xF774, 0x986A, 0xF773, 0x986B, 0xC5B8, 0x986F, 0xC5E3, 0x9870, 0xC649, 0x9871, 0xC660, 0x9872, 0xF958, 0x9873, 0xF9AE, + 0x9874, 0xF9AF, 0x98A8, 0xADB7, 0x98A9, 0xDCAD, 0x98AC, 0xE0E1, 0x98AD, 0xE4CC, 0x98AE, 0xE4CD, 0x98AF, 0xBBE3, 0x98B1, 0xBBE4, + 0x98B2, 0xE8BE, 0x98B3, 0xBE68, 0x98B6, 0xC1FC, 0x98B8, 0xF1AB, 0x98BA, 0xC347, 0x98BB, 0xF3AD, 0x98BC, 0xC442, 0x98BD, 0xF3AC, + 0x98BE, 0xF3AE, 0x98BF, 0xF3AB, 0x98C0, 0xF675, 0x98C1, 0xF552, 0x98C2, 0xF553, 0x98C4, 0xC4C6, 0x98C6, 0xF674, 0x98C9, 0xF673, + 0x98CB, 0xF775, 0x98CC, 0xF9B0, 0x98DB, 0xADB8, 0x98DF, 0xADB9, 0x98E2, 0xB0A7, 0x98E3, 0xD448, 0x98E5, 0xD84F, 0x98E7, 0xB6B8, + 0x98E9, 0xB6BB, 0x98EA, 0xB6B9, 0x98EB, 0xDCAE, 0x98ED, 0xB6BD, 0x98EF, 0xB6BA, 0x98F2, 0xB6BC, 0x98F4, 0xB97E, 0x98F6, 0xE0E2, + 0x98F9, 0xE0E3, 0x98FA, 0xE8C0, 0x98FC, 0xB97D, 0x98FD, 0xB9A1, 0x98FE, 0xB9A2, 0x9900, 0xE4CF, 0x9902, 0xE4CE, 0x9903, 0xBBE5, + 0x9905, 0xBBE6, 0x9907, 0xE4D0, 0x9908, 0xE8BF, 0x9909, 0xBBE8, 0x990A, 0xBE69, 0x990C, 0xBBE7, 0x9910, 0xC05C, 0x9911, 0xE8C1, + 0x9912, 0xBE6B, 0x9913, 0xBE6A, 0x9914, 0xE8C2, 0x9915, 0xE8C5, 0x9916, 0xE8C3, 0x9917, 0xE8C4, 0x9918, 0xBE6C, 0x991A, 0xC061, + 0x991B, 0xC05F, 0x991E, 0xC05E, 0x991F, 0xEC5D, 0x9921, 0xC060, 0x9924, 0xEC5C, 0x9925, 0xEF4B, 0x9927, 0xEC5E, 0x9928, 0xC05D, + 0x9929, 0xEC5F, 0x992A, 0xEF4E, 0x992B, 0xEF4C, 0x992C, 0xEF4D, 0x992D, 0xEF52, 0x992E, 0xC34B, 0x992F, 0xEF51, 0x9930, 0xEF54, + 0x9931, 0xEF53, 0x9932, 0xEF50, 0x9933, 0xEF4F, 0x9935, 0xC1FD, 0x993A, 0xF1AE, 0x993C, 0xF1AD, 0x993D, 0xC34A, 0x993E, 0xC348, + 0x993F, 0xC349, 0x9941, 0xF1AC, 0x9943, 0xF3B1, 0x9945, 0xC443, 0x9947, 0xF3B0, 0x9948, 0xF3AF, 0x9949, 0xC444, 0x994B, 0xF558, + 0x994C, 0xF557, 0x994E, 0xF555, 0x9950, 0xF554, 0x9951, 0xC4C8, 0x9952, 0xC4C7, 0x9953, 0xF559, 0x9954, 0xF776, 0x9955, 0xC5B9, + 0x9956, 0xF677, 0x9957, 0xC557, 0x9958, 0xF676, 0x9959, 0xF556, 0x995B, 0xF777, 0x995C, 0xC5E4, 0x995E, 0xC661, 0x995F, 0xF959, + 0x9961, 0xF9B1, 0x9996, 0xADBA, 0x9997, 0xD850, 0x9998, 0xEF55, 0x9999, 0xADBB, 0x999C, 0xE4D2, 0x999D, 0xE4D1, 0x999E, 0xEC60, + 0x99A1, 0xEF57, 0x99A3, 0xEF56, 0x99A5, 0xC34C, 0x99A6, 0xF3B2, 0x99A7, 0xF3B3, 0x99A8, 0xC4C9, 0x99AB, 0xF9B2, 0x99AC, 0xB0A8, + 0x99AD, 0xB6BF, 0x99AE, 0xB6BE, 0x99AF, 0xE0E4, 0x99B0, 0xE0E6, 0x99B1, 0xB9A4, 0x99B2, 0xE0E5, 0x99B3, 0xB9A3, 0x99B4, 0xB9A5, + 0x99B5, 0xE0E7, 0x99B9, 0xE4D4, 0x99BA, 0xE4D6, 0x99BB, 0xE4D5, 0x99BD, 0xE4D8, 0x99C1, 0xBBE9, 0x99C2, 0xE4D7, 0x99C3, 0xE4D3, + 0x99C7, 0xE4D9, 0x99C9, 0xE8CC, 0x99CB, 0xE8CF, 0x99CC, 0xE8D1, 0x99CD, 0xE8C7, 0x99CE, 0xE8CB, 0x99CF, 0xE8C8, 0x99D0, 0xBE6E, + 0x99D1, 0xBE71, 0x99D2, 0xBE73, 0x99D3, 0xE8C9, 0x99D4, 0xE8CA, 0x99D5, 0xBE72, 0x99D6, 0xE8CD, 0x99D7, 0xE8D0, 0x99D8, 0xE8CE, + 0x99D9, 0xBE74, 0x99DB, 0xBE70, 0x99DC, 0xE8C6, 0x99DD, 0xBE6D, 0x99DF, 0xBE6F, 0x99E2, 0xC063, 0x99E3, 0xEC66, 0x99E4, 0xEC64, + 0x99E5, 0xEC63, 0x99E7, 0xEC69, 0x99E9, 0xEC68, 0x99EA, 0xEC67, 0x99EC, 0xEC62, 0x99ED, 0xC062, 0x99EE, 0xEC61, 0x99F0, 0xEC65, + 0x99F1, 0xC064, 0x99F4, 0xEF5A, 0x99F6, 0xEF5E, 0x99F7, 0xEF5B, 0x99F8, 0xEF5D, 0x99F9, 0xEF5C, 0x99FA, 0xEF59, 0x99FB, 0xEF5F, + 0x99FC, 0xEF62, 0x99FD, 0xEF60, 0x99FE, 0xEF61, 0x99FF, 0xC240, 0x9A01, 0xC1FE, 0x9A02, 0xEF58, 0x9A03, 0xEF63, 0x9A04, 0xF1B3, + 0x9A05, 0xF1B6, 0x9A06, 0xF1B8, 0x9A07, 0xF1B7, 0x9A09, 0xF1B1, 0x9A0A, 0xF1B5, 0x9A0B, 0xF1B0, 0x9A0D, 0xF1B2, 0x9A0E, 0xC34D, + 0x9A0F, 0xF1AF, 0x9A11, 0xF1B4, 0x9A14, 0xF3C0, 0x9A15, 0xF3B5, 0x9A16, 0xC445, 0x9A19, 0xC446, 0x9A1A, 0xF3B4, 0x9A1B, 0xF3B9, + 0x9A1C, 0xF3BF, 0x9A1D, 0xF3B7, 0x9A1E, 0xF3BE, 0x9A20, 0xF3BB, 0x9A22, 0xF3BA, 0x9A23, 0xF3BD, 0x9A24, 0xF3B8, 0x9A25, 0xF3B6, + 0x9A27, 0xF3BC, 0x9A29, 0xF560, 0x9A2A, 0xF55E, 0x9A2B, 0xC4CA, 0x9A2C, 0xF55D, 0x9A2D, 0xF563, 0x9A2E, 0xF561, 0x9A30, 0xC4CB, + 0x9A31, 0xF55C, 0x9A32, 0xF55A, 0x9A34, 0xF55B, 0x9A35, 0xC4CD, 0x9A36, 0xF55F, 0x9A37, 0xC4CC, 0x9A38, 0xF562, 0x9A39, 0xF678, + 0x9A3A, 0xF67E, 0x9A3D, 0xF679, 0x9A3E, 0xC55B, 0x9A3F, 0xF6A1, 0x9A40, 0xC55A, 0x9A41, 0xF67D, 0x9A42, 0xF67C, 0x9A43, 0xC559, + 0x9A44, 0xF67B, 0x9A45, 0xC558, 0x9A46, 0xF67A, 0x9A48, 0xF77D, 0x9A49, 0xF7A1, 0x9A4A, 0xF77E, 0x9A4C, 0xF77B, 0x9A4D, 0xC5BB, + 0x9A4E, 0xF778, 0x9A4F, 0xF77C, 0x9A50, 0xF7A3, 0x9A52, 0xF7A2, 0x9A53, 0xF779, 0x9A54, 0xF77A, 0x9A55, 0xC5BA, 0x9A56, 0xF852, + 0x9A57, 0xC5E7, 0x9A59, 0xF853, 0x9A5A, 0xC5E5, 0x9A5B, 0xC5E6, 0x9A5E, 0xF8D3, 0x9A5F, 0xC64A, 0x9A60, 0xF976, 0x9A62, 0xC66A, + 0x9A64, 0xF9B3, 0x9A65, 0xC66B, 0x9A66, 0xF9B4, 0x9A67, 0xF9B5, 0x9A68, 0xF9C3, 0x9A69, 0xF9C2, 0x9A6A, 0xC67A, 0x9A6B, 0xF9CD, + 0x9AA8, 0xB0A9, 0x9AAB, 0xE0E9, 0x9AAD, 0xE0E8, 0x9AAF, 0xBBEA, 0x9AB0, 0xBBEB, 0x9AB1, 0xE4DA, 0x9AB3, 0xE8D2, 0x9AB4, 0xEC6C, + 0x9AB7, 0xBE75, 0x9AB8, 0xC065, 0x9AB9, 0xEC6A, 0x9ABB, 0xEC6D, 0x9ABC, 0xC066, 0x9ABE, 0xEF64, 0x9ABF, 0xEC6B, 0x9AC0, 0xF1B9, + 0x9AC1, 0xC34E, 0x9AC2, 0xF3C1, 0x9AC6, 0xF566, 0x9AC7, 0xF564, 0x9ACA, 0xF565, 0x9ACD, 0xF6A2, 0x9ACF, 0xC55C, 0x9AD0, 0xF7A4, + 0x9AD1, 0xC5EA, 0x9AD2, 0xC5BC, 0x9AD3, 0xC5E8, 0x9AD4, 0xC5E9, 0x9AD5, 0xF8D4, 0x9AD6, 0xC662, 0x9AD8, 0xB0AA, 0x9ADC, 0xF1BA, + 0x9ADF, 0xD449, 0x9AE1, 0xB9A6, 0x9AE3, 0xE4DB, 0x9AE6, 0xBBEC, 0x9AE7, 0xE4DC, 0x9AEB, 0xE8D4, 0x9AEC, 0xE8D3, 0x9AED, 0xC068, + 0x9AEE, 0xBE76, 0x9AEF, 0xBE77, 0x9AF1, 0xE8D7, 0x9AF2, 0xE8D6, 0x9AF3, 0xE8D5, 0x9AF6, 0xEC6E, 0x9AF7, 0xEC71, 0x9AF9, 0xEC70, + 0x9AFA, 0xEC6F, 0x9AFB, 0xC067, 0x9AFC, 0xEF68, 0x9AFD, 0xEF66, 0x9AFE, 0xEF65, 0x9B01, 0xEF67, 0x9B03, 0xC34F, 0x9B04, 0xF1BC, + 0x9B05, 0xF1BD, 0x9B06, 0xC350, 0x9B08, 0xF1BB, 0x9B0A, 0xF3C3, 0x9B0B, 0xF3C2, 0x9B0C, 0xF3C5, 0x9B0D, 0xC447, 0x9B0E, 0xF3C4, + 0x9B10, 0xF567, 0x9B11, 0xF569, 0x9B12, 0xF568, 0x9B15, 0xF6A3, 0x9B16, 0xF6A6, 0x9B17, 0xF6A4, 0x9B18, 0xF6A5, 0x9B19, 0xF7A5, + 0x9B1A, 0xC5BD, 0x9B1E, 0xF854, 0x9B1F, 0xF855, 0x9B20, 0xF856, 0x9B22, 0xC64B, 0x9B23, 0xC663, 0x9B24, 0xF9B6, 0x9B25, 0xB0AB, + 0x9B27, 0xBE78, 0x9B28, 0xC069, 0x9B29, 0xF1BE, 0x9B2B, 0xF7A6, 0x9B2E, 0xF9C4, 0x9B2F, 0xD44A, 0x9B31, 0xC67B, 0x9B32, 0xB0AC, + 0x9B33, 0xEC72, 0x9B35, 0xF1BF, 0x9B37, 0xF3C6, 0x9B3A, 0xF6A7, 0x9B3B, 0xF7A7, 0x9B3C, 0xB0AD, 0x9B3E, 0xE4DD, 0x9B3F, 0xE4DE, + 0x9B41, 0xBBED, 0x9B42, 0xBBEE, 0x9B43, 0xE8D9, 0x9B44, 0xBE7A, 0x9B45, 0xBE79, 0x9B46, 0xE8D8, 0x9B48, 0xEF69, 0x9B4A, 0xF1C0, + 0x9B4B, 0xF1C2, 0x9B4C, 0xF1C1, 0x9B4D, 0xC353, 0x9B4E, 0xC352, 0x9B4F, 0xC351, 0x9B51, 0xC55E, 0x9B52, 0xF6A8, 0x9B54, 0xC55D, + 0x9B55, 0xF7A9, 0x9B56, 0xF7A8, 0x9B58, 0xC64C, 0x9B59, 0xF8D5, 0x9B5A, 0xB3BD, 0x9B5B, 0xE0EA, 0x9B5F, 0xE4E1, 0x9B60, 0xE4DF, + 0x9B61, 0xE4E0, 0x9B64, 0xE8E2, 0x9B66, 0xE8DD, 0x9B67, 0xE8DA, 0x9B68, 0xE8E1, 0x9B6C, 0xE8E3, 0x9B6F, 0xBE7C, 0x9B70, 0xE8E0, + 0x9B71, 0xE8DC, 0x9B74, 0xE8DB, 0x9B75, 0xE8DF, 0x9B76, 0xE8DE, 0x9B77, 0xBE7B, 0x9B7A, 0xEC7D, 0x9B7B, 0xEC78, 0x9B7C, 0xEC76, + 0x9B7D, 0xECA1, 0x9B7E, 0xEC77, 0x9B80, 0xEC73, 0x9B82, 0xEC79, 0x9B85, 0xEC74, 0x9B86, 0xEF72, 0x9B87, 0xEC75, 0x9B88, 0xECA2, + 0x9B90, 0xEC7C, 0x9B91, 0xC06A, 0x9B92, 0xEC7B, 0x9B93, 0xEC7A, 0x9B95, 0xEC7E, 0x9B9A, 0xEF6A, 0x9B9B, 0xEF6D, 0x9B9E, 0xEF6C, + 0x9BA0, 0xEF74, 0x9BA1, 0xEF6F, 0x9BA2, 0xEF73, 0x9BA4, 0xEF71, 0x9BA5, 0xEF70, 0x9BA6, 0xEF6E, 0x9BA8, 0xEF6B, 0x9BAA, 0xC243, + 0x9BAB, 0xC242, 0x9BAD, 0xC244, 0x9BAE, 0xC241, 0x9BAF, 0xEF75, 0x9BB5, 0xF1C8, 0x9BB6, 0xF1CB, 0x9BB8, 0xF1C9, 0x9BB9, 0xF1CD, + 0x9BBD, 0xF1CE, 0x9BBF, 0xF1C6, 0x9BC0, 0xC358, 0x9BC1, 0xF1C7, 0x9BC3, 0xF1C5, 0x9BC4, 0xF1CC, 0x9BC6, 0xF1C4, 0x9BC7, 0xF1C3, + 0x9BC8, 0xC357, 0x9BC9, 0xC355, 0x9BCA, 0xC354, 0x9BD3, 0xF1CA, 0x9BD4, 0xF3CF, 0x9BD5, 0xF3D5, 0x9BD6, 0xC44A, 0x9BD7, 0xF3D0, + 0x9BD9, 0xF3D3, 0x9BDA, 0xF3D7, 0x9BDB, 0xC44B, 0x9BDC, 0xF3D2, 0x9BDE, 0xF3CA, 0x9BE0, 0xF3C9, 0x9BE1, 0xF3D6, 0x9BE2, 0xF3CD, + 0x9BE4, 0xF3CB, 0x9BE5, 0xF3D4, 0x9BE6, 0xF3CC, 0x9BE7, 0xC449, 0x9BE8, 0xC448, 0x9BEA, 0xF3C7, 0x9BEB, 0xF3C8, 0x9BEC, 0xF3D1, + 0x9BF0, 0xF3CE, 0x9BF7, 0xF56C, 0x9BF8, 0xF56F, 0x9BFD, 0xC356, 0x9C05, 0xF56D, 0x9C06, 0xF573, 0x9C07, 0xF571, 0x9C08, 0xF56B, + 0x9C09, 0xF576, 0x9C0B, 0xF56A, 0x9C0D, 0xC4CF, 0x9C0E, 0xF572, 0x9C12, 0xF56E, 0x9C13, 0xC4CE, 0x9C14, 0xF575, 0x9C17, 0xF574, + 0x9C1C, 0xF6AB, 0x9C1D, 0xF6AA, 0x9C21, 0xF6B1, 0x9C23, 0xF6AD, 0x9C24, 0xF6B0, 0x9C25, 0xC560, 0x9C28, 0xF6AE, 0x9C29, 0xF6AF, + 0x9C2B, 0xF6A9, 0x9C2C, 0xF6AC, 0x9C2D, 0xC55F, 0x9C31, 0xC5BF, 0x9C32, 0xF7B4, 0x9C33, 0xF7AF, 0x9C34, 0xF7B3, 0x9C36, 0xF7B6, + 0x9C37, 0xF7B2, 0x9C39, 0xF7AE, 0x9C3B, 0xC5C1, 0x9C3C, 0xF7B1, 0x9C3D, 0xF7B5, 0x9C3E, 0xC5C0, 0x9C3F, 0xF7AC, 0x9C40, 0xF570, + 0x9C41, 0xF7B0, 0x9C44, 0xF7AD, 0x9C46, 0xF7AA, 0x9C48, 0xF7AB, 0x9C49, 0xC5BE, 0x9C4A, 0xF85A, 0x9C4B, 0xF85C, 0x9C4C, 0xF85F, + 0x9C4D, 0xF85B, 0x9C4E, 0xF860, 0x9C50, 0xF859, 0x9C52, 0xF857, 0x9C54, 0xC5EB, 0x9C55, 0xF85D, 0x9C56, 0xC5ED, 0x9C57, 0xC5EC, + 0x9C58, 0xF858, 0x9C59, 0xF85E, 0x9C5E, 0xF8DA, 0x9C5F, 0xC64D, 0x9C60, 0xF8DB, 0x9C62, 0xF8D9, 0x9C63, 0xF8D6, 0x9C66, 0xF8D8, + 0x9C67, 0xF8D7, 0x9C68, 0xF95A, 0x9C6D, 0xF95C, 0x9C6E, 0xF95B, 0x9C71, 0xF979, 0x9C73, 0xF978, 0x9C74, 0xF977, 0x9C75, 0xF97A, + 0x9C77, 0xC673, 0x9C78, 0xC674, 0x9C79, 0xF9CA, 0x9C7A, 0xF9CE, 0x9CE5, 0xB3BE, 0x9CE6, 0xDCAF, 0x9CE7, 0xE0ED, 0x9CE9, 0xB9A7, + 0x9CEA, 0xE0EB, 0x9CED, 0xE0EC, 0x9CF1, 0xE4E2, 0x9CF2, 0xE4E3, 0x9CF3, 0xBBF1, 0x9CF4, 0xBBEF, 0x9CF5, 0xE4E4, 0x9CF6, 0xBBF0, + 0x9CF7, 0xE8E8, 0x9CF9, 0xE8EB, 0x9CFA, 0xE8E5, 0x9CFB, 0xE8EC, 0x9CFC, 0xE8E4, 0x9CFD, 0xE8E6, 0x9CFF, 0xE8E7, 0x9D00, 0xE8EA, + 0x9D03, 0xBEA1, 0x9D04, 0xE8EF, 0x9D05, 0xE8EE, 0x9D06, 0xBE7D, 0x9D07, 0xE8E9, 0x9D08, 0xE8ED, 0x9D09, 0xBE7E, 0x9D10, 0xECAC, + 0x9D12, 0xC06F, 0x9D14, 0xECA7, 0x9D15, 0xC06B, 0x9D17, 0xECA4, 0x9D18, 0xECAA, 0x9D19, 0xECAD, 0x9D1B, 0xC070, 0x9D1D, 0xECA9, + 0x9D1E, 0xECA6, 0x9D1F, 0xECAE, 0x9D20, 0xECA5, 0x9D22, 0xECAB, 0x9D23, 0xC06C, 0x9D25, 0xECA3, 0x9D26, 0xC06D, 0x9D28, 0xC06E, + 0x9D29, 0xECA8, 0x9D2D, 0xEFA9, 0x9D2E, 0xEF7A, 0x9D2F, 0xEF7B, 0x9D30, 0xEF7E, 0x9D31, 0xEF7C, 0x9D33, 0xEF76, 0x9D36, 0xEF79, + 0x9D37, 0xEFA5, 0x9D38, 0xEF7D, 0x9D3B, 0xC245, 0x9D3D, 0xEFA7, 0x9D3E, 0xEFA4, 0x9D3F, 0xC246, 0x9D40, 0xEFA6, 0x9D41, 0xEF77, + 0x9D42, 0xEFA2, 0x9D43, 0xEFA3, 0x9D45, 0xEFA1, 0x9D4A, 0xF1D2, 0x9D4B, 0xF1D4, 0x9D4C, 0xF1D7, 0x9D4F, 0xF1D1, 0x9D51, 0xC359, + 0x9D52, 0xF1D9, 0x9D53, 0xF1D0, 0x9D54, 0xF1DA, 0x9D56, 0xF1D6, 0x9D57, 0xF1D8, 0x9D58, 0xF1DC, 0x9D59, 0xF1D5, 0x9D5A, 0xF1DD, + 0x9D5B, 0xF1D3, 0x9D5C, 0xF1CF, 0x9D5D, 0xC35A, 0x9D5F, 0xF1DB, 0x9D60, 0xC35B, 0x9D61, 0xC44D, 0x9D67, 0xEF78, 0x9D68, 0xF3F1, + 0x9D69, 0xF3E8, 0x9D6A, 0xC44F, 0x9D6B, 0xF3E4, 0x9D6C, 0xC450, 0x9D6F, 0xF3ED, 0x9D70, 0xF3E7, 0x9D71, 0xF3DD, 0x9D72, 0xC44E, + 0x9D73, 0xF3EA, 0x9D74, 0xF3E5, 0x9D75, 0xF3E6, 0x9D77, 0xF3D8, 0x9D78, 0xF3DF, 0x9D79, 0xF3EE, 0x9D7B, 0xF3EB, 0x9D7D, 0xF3E3, + 0x9D7F, 0xF3EF, 0x9D80, 0xF3DE, 0x9D81, 0xF3D9, 0x9D82, 0xF3EC, 0x9D84, 0xF3DB, 0x9D85, 0xF3E9, 0x9D86, 0xF3E0, 0x9D87, 0xF3F0, + 0x9D88, 0xF3DC, 0x9D89, 0xC44C, 0x9D8A, 0xF3DA, 0x9D8B, 0xF3E1, 0x9D8C, 0xF3E2, 0x9D90, 0xF57D, 0x9D92, 0xF57B, 0x9D94, 0xF5A2, + 0x9D96, 0xF5AE, 0x9D97, 0xF5A5, 0x9D98, 0xF57C, 0x9D99, 0xF578, 0x9D9A, 0xF5A7, 0x9D9B, 0xF57E, 0x9D9C, 0xF5A3, 0x9D9D, 0xF57A, + 0x9D9E, 0xF5AA, 0x9D9F, 0xF577, 0x9DA0, 0xF5A1, 0x9DA1, 0xF5A6, 0x9DA2, 0xF5A8, 0x9DA3, 0xF5AB, 0x9DA4, 0xF579, 0x9DA6, 0xF5AF, + 0x9DA7, 0xF5B0, 0x9DA8, 0xF5A9, 0x9DA9, 0xF5AD, 0x9DAA, 0xF5A4, 0x9DAC, 0xF6C1, 0x9DAD, 0xF6C4, 0x9DAF, 0xC561, 0x9DB1, 0xF6C3, + 0x9DB2, 0xF6C8, 0x9DB3, 0xF6C6, 0x9DB4, 0xC562, 0x9DB5, 0xF6BD, 0x9DB6, 0xF6B3, 0x9DB7, 0xF6B2, 0x9DB8, 0xC564, 0x9DB9, 0xF6BF, + 0x9DBA, 0xF6C0, 0x9DBB, 0xF6BC, 0x9DBC, 0xF6B4, 0x9DBE, 0xF6B9, 0x9DBF, 0xF5AC, 0x9DC1, 0xF6B5, 0x9DC2, 0xC563, 0x9DC3, 0xF6BB, + 0x9DC5, 0xF6BA, 0x9DC7, 0xF6B6, 0x9DC8, 0xF6C2, 0x9DCA, 0xF6B7, 0x9DCB, 0xF7BB, 0x9DCC, 0xF6C5, 0x9DCD, 0xF6C7, 0x9DCE, 0xF6BE, + 0x9DCF, 0xF6B8, 0x9DD0, 0xF7BC, 0x9DD1, 0xF7BE, 0x9DD2, 0xF7B8, 0x9DD3, 0xC5C2, 0x9DD5, 0xF7C5, 0x9DD6, 0xF7C3, 0x9DD7, 0xC5C3, + 0x9DD8, 0xF7C2, 0x9DD9, 0xF7C1, 0x9DDA, 0xF7BA, 0x9DDB, 0xF7B7, 0x9DDC, 0xF7BD, 0x9DDD, 0xF7C6, 0x9DDE, 0xF7B9, 0x9DDF, 0xF7BF, + 0x9DE1, 0xF869, 0x9DE2, 0xF86E, 0x9DE3, 0xF864, 0x9DE4, 0xF867, 0x9DE5, 0xC5EE, 0x9DE6, 0xF86B, 0x9DE8, 0xF872, 0x9DE9, 0xF7C0, + 0x9DEB, 0xF865, 0x9DEC, 0xF86F, 0x9DED, 0xF873, 0x9DEE, 0xF86A, 0x9DEF, 0xF863, 0x9DF0, 0xF86D, 0x9DF2, 0xF86C, 0x9DF3, 0xF871, + 0x9DF4, 0xF870, 0x9DF5, 0xF7C4, 0x9DF6, 0xF868, 0x9DF7, 0xF862, 0x9DF8, 0xF866, 0x9DF9, 0xC64E, 0x9DFA, 0xC64F, 0x9DFB, 0xF861, + 0x9DFD, 0xF8E6, 0x9DFE, 0xF8DD, 0x9DFF, 0xF8E5, 0x9E00, 0xF8E2, 0x9E01, 0xF8E3, 0x9E02, 0xF8DC, 0x9E03, 0xF8DF, 0x9E04, 0xF8E7, + 0x9E05, 0xF8E1, 0x9E06, 0xF8E0, 0x9E07, 0xF8DE, 0x9E09, 0xF8E4, 0x9E0B, 0xF95D, 0x9E0D, 0xF95E, 0x9E0F, 0xF960, 0x9E10, 0xF95F, + 0x9E11, 0xF962, 0x9E12, 0xF961, 0x9E13, 0xF97C, 0x9E14, 0xF97B, 0x9E15, 0xF9B7, 0x9E17, 0xF9B8, 0x9E19, 0xF9C5, 0x9E1A, 0xC678, + 0x9E1B, 0xC67C, 0x9E1D, 0xF9CF, 0x9E1E, 0xC67D, 0x9E75, 0xB3BF, 0x9E79, 0xC4D0, 0x9E7A, 0xF6C9, 0x9E7C, 0xC650, 0x9E7D, 0xC651, + 0x9E7F, 0xB3C0, 0x9E80, 0xE0EE, 0x9E82, 0xB9A8, 0x9E83, 0xE8F0, 0x9E86, 0xECB0, 0x9E87, 0xECB1, 0x9E88, 0xECAF, 0x9E89, 0xEFAB, + 0x9E8A, 0xEFAA, 0x9E8B, 0xC247, 0x9E8C, 0xF1DF, 0x9E8D, 0xEFAC, 0x9E8E, 0xF1DE, 0x9E91, 0xF3F3, 0x9E92, 0xC451, 0x9E93, 0xC453, + 0x9E94, 0xF3F2, 0x9E97, 0xC452, 0x9E99, 0xF5B1, 0x9E9A, 0xF5B3, 0x9E9B, 0xF5B2, 0x9E9C, 0xF6CA, 0x9E9D, 0xC565, 0x9E9F, 0xC5EF, + 0x9EA0, 0xF8E8, 0x9EA1, 0xF963, 0x9EA4, 0xF9D2, 0x9EA5, 0xB3C1, 0x9EA7, 0xE4E5, 0x9EA9, 0xBEA2, 0x9EAD, 0xECB3, 0x9EAE, 0xECB2, + 0x9EB0, 0xEFAD, 0x9EB4, 0xC454, 0x9EB5, 0xC4D1, 0x9EB6, 0xF7C7, 0x9EB7, 0xF9CB, 0x9EBB, 0xB3C2, 0x9EBC, 0xBBF2, 0x9EBE, 0xBEA3, + 0x9EC0, 0xF3F4, 0x9EC2, 0xF874, 0x9EC3, 0xB6C0, 0x9EC8, 0xEFAE, 0x9ECC, 0xC664, 0x9ECD, 0xB6C1, 0x9ECE, 0xBEA4, 0x9ECF, 0xC248, + 0x9ED0, 0xF875, 0x9ED1, 0xB6C2, 0x9ED3, 0xE8F1, 0x9ED4, 0xC072, 0x9ED5, 0xECB4, 0x9ED6, 0xECB5, 0x9ED8, 0xC071, 0x9EDA, 0xEFAF, + 0x9EDB, 0xC24C, 0x9EDC, 0xC24A, 0x9EDD, 0xC24B, 0x9EDE, 0xC249, 0x9EDF, 0xF1E0, 0x9EE0, 0xC35C, 0x9EE4, 0xF5B5, 0x9EE5, 0xF5B4, + 0x9EE6, 0xF5B7, 0x9EE7, 0xF5B6, 0x9EE8, 0xC4D2, 0x9EEB, 0xF6CB, 0x9EED, 0xF6CD, 0x9EEE, 0xF6CC, 0x9EEF, 0xC566, 0x9EF0, 0xF7C8, + 0x9EF2, 0xF876, 0x9EF3, 0xF877, 0x9EF4, 0xC5F0, 0x9EF5, 0xF964, 0x9EF6, 0xF97D, 0x9EF7, 0xC675, 0x9EF9, 0xDCB0, 0x9EFA, 0xECB6, + 0x9EFB, 0xEFB0, 0x9EFC, 0xF3F5, 0x9EFD, 0xE0EF, 0x9EFF, 0xEFB1, 0x9F00, 0xF1E2, 0x9F01, 0xF1E1, 0x9F06, 0xF878, 0x9F07, 0xC652, + 0x9F09, 0xF965, 0x9F0A, 0xF97E, 0x9F0E, 0xB9A9, 0x9F0F, 0xE8F2, 0x9F10, 0xE8F3, 0x9F12, 0xECB7, 0x9F13, 0xB9AA, 0x9F15, 0xC35D, + 0x9F16, 0xF1E3, 0x9F18, 0xF6CF, 0x9F19, 0xC567, 0x9F1A, 0xF6D0, 0x9F1B, 0xF6CE, 0x9F1C, 0xF879, 0x9F1E, 0xF8E9, 0x9F20, 0xB9AB, + 0x9F22, 0xEFB4, 0x9F23, 0xEFB3, 0x9F24, 0xEFB2, 0x9F25, 0xF1E4, 0x9F28, 0xF1E8, 0x9F29, 0xF1E7, 0x9F2A, 0xF1E6, 0x9F2B, 0xF1E5, + 0x9F2C, 0xC35E, 0x9F2D, 0xF3F6, 0x9F2E, 0xF5B9, 0x9F2F, 0xC4D3, 0x9F30, 0xF5B8, 0x9F31, 0xF6D1, 0x9F32, 0xF7CB, 0x9F33, 0xF7CA, + 0x9F34, 0xC5C4, 0x9F35, 0xF7C9, 0x9F36, 0xF87C, 0x9F37, 0xF87B, 0x9F38, 0xF87A, 0x9F3B, 0xBBF3, 0x9F3D, 0xECB8, 0x9F3E, 0xC24D, + 0x9F40, 0xF3F7, 0x9F41, 0xF3F8, 0x9F42, 0xF7CC, 0x9F43, 0xF87D, 0x9F46, 0xF8EA, 0x9F47, 0xF966, 0x9F48, 0xF9B9, 0x9F49, 0xF9D4, + 0x9F4A, 0xBBF4, 0x9F4B, 0xC24E, 0x9F4C, 0xF1E9, 0x9F4D, 0xF3F9, 0x9F4E, 0xF6D2, 0x9F4F, 0xF87E, 0x9F52, 0xBEA6, 0x9F54, 0xEFB5, + 0x9F55, 0xF1EA, 0x9F56, 0xF3FA, 0x9F57, 0xF3FB, 0x9F58, 0xF3FC, 0x9F59, 0xF5BE, 0x9F5B, 0xF5BA, 0x9F5C, 0xC568, 0x9F5D, 0xF5BD, + 0x9F5E, 0xF5BC, 0x9F5F, 0xC4D4, 0x9F60, 0xF5BB, 0x9F61, 0xC4D6, 0x9F63, 0xC4D5, 0x9F64, 0xF6D4, 0x9F65, 0xF6D3, 0x9F66, 0xC569, + 0x9F67, 0xC56A, 0x9F6A, 0xC5C6, 0x9F6B, 0xF7CD, 0x9F6C, 0xC5C5, 0x9F6E, 0xF8A3, 0x9F6F, 0xF8A4, 0x9F70, 0xF8A2, 0x9F71, 0xF8A1, + 0x9F72, 0xC654, 0x9F74, 0xF8EB, 0x9F75, 0xF8EC, 0x9F76, 0xF8ED, 0x9F77, 0xC653, 0x9F78, 0xF967, 0x9F79, 0xF96A, 0x9F7A, 0xF969, + 0x9F7B, 0xF968, 0x9F7E, 0xF9D3, 0x9F8D, 0xC073, 0x9F90, 0xC365, 0x9F91, 0xF5BF, 0x9F92, 0xF6D5, 0x9F94, 0xC5C7, 0x9F95, 0xF7CE, + 0x9F98, 0xF9D5, 0x9F9C, 0xC074, 0x9FA0, 0xEFB6, 0x9FA2, 0xF7CF, 0x9FA4, 0xF9A1, 0xFA0C, 0xC94A, 0xFA0D, 0xDDFC, 0xFE30, 0xA14A, + 0xFE31, 0xA157, 0xFE33, 0xA159, 0xFE34, 0xA15B, 0xFE35, 0xA15F, 0xFE36, 0xA160, 0xFE37, 0xA163, 0xFE38, 0xA164, 0xFE39, 0xA167, + 0xFE3A, 0xA168, 0xFE3B, 0xA16B, 0xFE3C, 0xA16C, 0xFE3D, 0xA16F, 0xFE3E, 0xA170, 0xFE3F, 0xA173, 0xFE40, 0xA174, 0xFE41, 0xA177, + 0xFE42, 0xA178, 0xFE43, 0xA17B, 0xFE44, 0xA17C, 0xFE49, 0xA1C6, 0xFE4A, 0xA1C7, 0xFE4B, 0xA1CA, 0xFE4C, 0xA1CB, 0xFE4D, 0xA1C8, + 0xFE4E, 0xA1C9, 0xFE4F, 0xA15C, 0xFE50, 0xA14D, 0xFE51, 0xA14E, 0xFE52, 0xA14F, 0xFE54, 0xA151, 0xFE55, 0xA152, 0xFE56, 0xA153, + 0xFE57, 0xA154, 0xFE59, 0xA17D, 0xFE5A, 0xA17E, 0xFE5B, 0xA1A1, 0xFE5C, 0xA1A2, 0xFE5D, 0xA1A3, 0xFE5E, 0xA1A4, 0xFE5F, 0xA1CC, + 0xFE60, 0xA1CD, 0xFE61, 0xA1CE, 0xFE62, 0xA1DE, 0xFE63, 0xA1DF, 0xFE64, 0xA1E0, 0xFE65, 0xA1E1, 0xFE66, 0xA1E2, 0xFE68, 0xA242, + 0xFE69, 0xA24C, 0xFE6A, 0xA24D, 0xFE6B, 0xA24E, 0xFF01, 0xA149, 0xFF03, 0xA1AD, 0xFF04, 0xA243, 0xFF05, 0xA248, 0xFF06, 0xA1AE, + 0xFF08, 0xA15D, 0xFF09, 0xA15E, 0xFF0A, 0xA1AF, 0xFF0B, 0xA1CF, 0xFF0C, 0xA141, 0xFF0D, 0xA1D0, 0xFF0E, 0xA144, 0xFF0F, 0xA1FE, + 0xFF10, 0xA2AF, 0xFF11, 0xA2B0, 0xFF12, 0xA2B1, 0xFF13, 0xA2B2, 0xFF14, 0xA2B3, 0xFF15, 0xA2B4, 0xFF16, 0xA2B5, 0xFF17, 0xA2B6, + 0xFF18, 0xA2B7, 0xFF19, 0xA2B8, 0xFF1A, 0xA147, 0xFF1B, 0xA146, 0xFF1C, 0xA1D5, 0xFF1D, 0xA1D7, 0xFF1E, 0xA1D6, 0xFF1F, 0xA148, + 0xFF20, 0xA249, 0xFF21, 0xA2CF, 0xFF22, 0xA2D0, 0xFF23, 0xA2D1, 0xFF24, 0xA2D2, 0xFF25, 0xA2D3, 0xFF26, 0xA2D4, 0xFF27, 0xA2D5, + 0xFF28, 0xA2D6, 0xFF29, 0xA2D7, 0xFF2A, 0xA2D8, 0xFF2B, 0xA2D9, 0xFF2C, 0xA2DA, 0xFF2D, 0xA2DB, 0xFF2E, 0xA2DC, 0xFF2F, 0xA2DD, + 0xFF30, 0xA2DE, 0xFF31, 0xA2DF, 0xFF32, 0xA2E0, 0xFF33, 0xA2E1, 0xFF34, 0xA2E2, 0xFF35, 0xA2E3, 0xFF36, 0xA2E4, 0xFF37, 0xA2E5, + 0xFF38, 0xA2E6, 0xFF39, 0xA2E7, 0xFF3A, 0xA2E8, 0xFF3C, 0xA240, 0xFF3F, 0xA1C4, 0xFF41, 0xA2E9, 0xFF42, 0xA2EA, 0xFF43, 0xA2EB, + 0xFF44, 0xA2EC, 0xFF45, 0xA2ED, 0xFF46, 0xA2EE, 0xFF47, 0xA2EF, 0xFF48, 0xA2F0, 0xFF49, 0xA2F1, 0xFF4A, 0xA2F2, 0xFF4B, 0xA2F3, + 0xFF4C, 0xA2F4, 0xFF4D, 0xA2F5, 0xFF4E, 0xA2F6, 0xFF4F, 0xA2F7, 0xFF50, 0xA2F8, 0xFF51, 0xA2F9, 0xFF52, 0xA2FA, 0xFF53, 0xA2FB, + 0xFF54, 0xA2FC, 0xFF55, 0xA2FD, 0xFF56, 0xA2FE, 0xFF57, 0xA340, 0xFF58, 0xA341, 0xFF59, 0xA342, 0xFF5A, 0xA343, 0xFF5B, 0xA161, + 0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0 +}; + +static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ + 0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A, + 0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52, + 0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31, + 0xA158, 0x2014, 0xA159, 0xFE33, 0xA15A, 0x2574, 0xA15B, 0xFE34, 0xA15C, 0xFE4F, 0xA15D, 0xFF08, 0xA15E, 0xFF09, 0xA15F, 0xFE35, + 0xA160, 0xFE36, 0xA161, 0xFF5B, 0xA162, 0xFF5D, 0xA163, 0xFE37, 0xA164, 0xFE38, 0xA165, 0x3014, 0xA166, 0x3015, 0xA167, 0xFE39, + 0xA168, 0xFE3A, 0xA169, 0x3010, 0xA16A, 0x3011, 0xA16B, 0xFE3B, 0xA16C, 0xFE3C, 0xA16D, 0x300A, 0xA16E, 0x300B, 0xA16F, 0xFE3D, + 0xA170, 0xFE3E, 0xA171, 0x3008, 0xA172, 0x3009, 0xA173, 0xFE3F, 0xA174, 0xFE40, 0xA175, 0x300C, 0xA176, 0x300D, 0xA177, 0xFE41, + 0xA178, 0xFE42, 0xA179, 0x300E, 0xA17A, 0x300F, 0xA17B, 0xFE43, 0xA17C, 0xFE44, 0xA17D, 0xFE59, 0xA17E, 0xFE5A, 0xA1A1, 0xFE5B, + 0xA1A2, 0xFE5C, 0xA1A3, 0xFE5D, 0xA1A4, 0xFE5E, 0xA1A5, 0x2018, 0xA1A6, 0x2019, 0xA1A7, 0x201C, 0xA1A8, 0x201D, 0xA1A9, 0x301D, + 0xA1AA, 0x301E, 0xA1AB, 0x2035, 0xA1AC, 0x2032, 0xA1AD, 0xFF03, 0xA1AE, 0xFF06, 0xA1AF, 0xFF0A, 0xA1B0, 0x203B, 0xA1B1, 0x00A7, + 0xA1B2, 0x3003, 0xA1B3, 0x25CB, 0xA1B4, 0x25CF, 0xA1B5, 0x25B3, 0xA1B6, 0x25B2, 0xA1B7, 0x25CE, 0xA1B8, 0x2606, 0xA1B9, 0x2605, + 0xA1BA, 0x25C7, 0xA1BB, 0x25C6, 0xA1BC, 0x25A1, 0xA1BD, 0x25A0, 0xA1BE, 0x25BD, 0xA1BF, 0x25BC, 0xA1C0, 0x32A3, 0xA1C1, 0x2105, + 0xA1C2, 0x00AF, 0xA1C3, 0xFFE3, 0xA1C4, 0xFF3F, 0xA1C5, 0x02CD, 0xA1C6, 0xFE49, 0xA1C7, 0xFE4A, 0xA1C8, 0xFE4D, 0xA1C9, 0xFE4E, + 0xA1CA, 0xFE4B, 0xA1CB, 0xFE4C, 0xA1CC, 0xFE5F, 0xA1CD, 0xFE60, 0xA1CE, 0xFE61, 0xA1CF, 0xFF0B, 0xA1D0, 0xFF0D, 0xA1D1, 0x00D7, + 0xA1D2, 0x00F7, 0xA1D3, 0x00B1, 0xA1D4, 0x221A, 0xA1D5, 0xFF1C, 0xA1D6, 0xFF1E, 0xA1D7, 0xFF1D, 0xA1D8, 0x2266, 0xA1D9, 0x2267, + 0xA1DA, 0x2260, 0xA1DB, 0x221E, 0xA1DC, 0x2252, 0xA1DD, 0x2261, 0xA1DE, 0xFE62, 0xA1DF, 0xFE63, 0xA1E0, 0xFE64, 0xA1E1, 0xFE65, + 0xA1E2, 0xFE66, 0xA1E3, 0xFF5E, 0xA1E4, 0x2229, 0xA1E5, 0x222A, 0xA1E6, 0x22A5, 0xA1E7, 0x2220, 0xA1E8, 0x221F, 0xA1E9, 0x22BF, + 0xA1EA, 0x33D2, 0xA1EB, 0x33D1, 0xA1EC, 0x222B, 0xA1ED, 0x222E, 0xA1EE, 0x2235, 0xA1EF, 0x2234, 0xA1F0, 0x2640, 0xA1F1, 0x2642, + 0xA1F2, 0x2295, 0xA1F3, 0x2299, 0xA1F4, 0x2191, 0xA1F5, 0x2193, 0xA1F6, 0x2190, 0xA1F7, 0x2192, 0xA1F8, 0x2196, 0xA1F9, 0x2197, + 0xA1FA, 0x2199, 0xA1FB, 0x2198, 0xA1FC, 0x2225, 0xA1FD, 0x2223, 0xA1FE, 0xFF0F, 0xA240, 0xFF3C, 0xA241, 0x2215, 0xA242, 0xFE68, + 0xA243, 0xFF04, 0xA244, 0xFFE5, 0xA245, 0x3012, 0xA246, 0xFFE0, 0xA247, 0xFFE1, 0xA248, 0xFF05, 0xA249, 0xFF20, 0xA24A, 0x2103, + 0xA24B, 0x2109, 0xA24C, 0xFE69, 0xA24D, 0xFE6A, 0xA24E, 0xFE6B, 0xA24F, 0x33D5, 0xA250, 0x339C, 0xA251, 0x339D, 0xA252, 0x339E, + 0xA253, 0x33CE, 0xA254, 0x33A1, 0xA255, 0x338E, 0xA256, 0x338F, 0xA257, 0x33C4, 0xA258, 0x00B0, 0xA259, 0x5159, 0xA25A, 0x515B, + 0xA25B, 0x515E, 0xA25C, 0x515D, 0xA25D, 0x5161, 0xA25E, 0x5163, 0xA25F, 0x55E7, 0xA260, 0x74E9, 0xA261, 0x7CCE, 0xA262, 0x2581, + 0xA263, 0x2582, 0xA264, 0x2583, 0xA265, 0x2584, 0xA266, 0x2585, 0xA267, 0x2586, 0xA268, 0x2587, 0xA269, 0x2588, 0xA26A, 0x258F, + 0xA26B, 0x258E, 0xA26C, 0x258D, 0xA26D, 0x258C, 0xA26E, 0x258B, 0xA26F, 0x258A, 0xA270, 0x2589, 0xA271, 0x253C, 0xA272, 0x2534, + 0xA273, 0x252C, 0xA274, 0x2524, 0xA275, 0x251C, 0xA276, 0x2594, 0xA277, 0x2500, 0xA278, 0x2502, 0xA279, 0x2595, 0xA27A, 0x250C, + 0xA27B, 0x2510, 0xA27C, 0x2514, 0xA27D, 0x2518, 0xA27E, 0x256D, 0xA2A1, 0x256E, 0xA2A2, 0x2570, 0xA2A3, 0x256F, 0xA2A4, 0x2550, + 0xA2A5, 0x255E, 0xA2A6, 0x256A, 0xA2A7, 0x2561, 0xA2A8, 0x25E2, 0xA2A9, 0x25E3, 0xA2AA, 0x25E5, 0xA2AB, 0x25E4, 0xA2AC, 0x2571, + 0xA2AD, 0x2572, 0xA2AE, 0x2573, 0xA2AF, 0xFF10, 0xA2B0, 0xFF11, 0xA2B1, 0xFF12, 0xA2B2, 0xFF13, 0xA2B3, 0xFF14, 0xA2B4, 0xFF15, + 0xA2B5, 0xFF16, 0xA2B6, 0xFF17, 0xA2B7, 0xFF18, 0xA2B8, 0xFF19, 0xA2B9, 0x2160, 0xA2BA, 0x2161, 0xA2BB, 0x2162, 0xA2BC, 0x2163, + 0xA2BD, 0x2164, 0xA2BE, 0x2165, 0xA2BF, 0x2166, 0xA2C0, 0x2167, 0xA2C1, 0x2168, 0xA2C2, 0x2169, 0xA2C3, 0x3021, 0xA2C4, 0x3022, + 0xA2C5, 0x3023, 0xA2C6, 0x3024, 0xA2C7, 0x3025, 0xA2C8, 0x3026, 0xA2C9, 0x3027, 0xA2CA, 0x3028, 0xA2CB, 0x3029, 0xA2CC, 0x5341, + 0xA2CD, 0x5344, 0xA2CE, 0x5345, 0xA2CF, 0xFF21, 0xA2D0, 0xFF22, 0xA2D1, 0xFF23, 0xA2D2, 0xFF24, 0xA2D3, 0xFF25, 0xA2D4, 0xFF26, + 0xA2D5, 0xFF27, 0xA2D6, 0xFF28, 0xA2D7, 0xFF29, 0xA2D8, 0xFF2A, 0xA2D9, 0xFF2B, 0xA2DA, 0xFF2C, 0xA2DB, 0xFF2D, 0xA2DC, 0xFF2E, + 0xA2DD, 0xFF2F, 0xA2DE, 0xFF30, 0xA2DF, 0xFF31, 0xA2E0, 0xFF32, 0xA2E1, 0xFF33, 0xA2E2, 0xFF34, 0xA2E3, 0xFF35, 0xA2E4, 0xFF36, + 0xA2E5, 0xFF37, 0xA2E6, 0xFF38, 0xA2E7, 0xFF39, 0xA2E8, 0xFF3A, 0xA2E9, 0xFF41, 0xA2EA, 0xFF42, 0xA2EB, 0xFF43, 0xA2EC, 0xFF44, + 0xA2ED, 0xFF45, 0xA2EE, 0xFF46, 0xA2EF, 0xFF47, 0xA2F0, 0xFF48, 0xA2F1, 0xFF49, 0xA2F2, 0xFF4A, 0xA2F3, 0xFF4B, 0xA2F4, 0xFF4C, + 0xA2F5, 0xFF4D, 0xA2F6, 0xFF4E, 0xA2F7, 0xFF4F, 0xA2F8, 0xFF50, 0xA2F9, 0xFF51, 0xA2FA, 0xFF52, 0xA2FB, 0xFF53, 0xA2FC, 0xFF54, + 0xA2FD, 0xFF55, 0xA2FE, 0xFF56, 0xA340, 0xFF57, 0xA341, 0xFF58, 0xA342, 0xFF59, 0xA343, 0xFF5A, 0xA344, 0x0391, 0xA345, 0x0392, + 0xA346, 0x0393, 0xA347, 0x0394, 0xA348, 0x0395, 0xA349, 0x0396, 0xA34A, 0x0397, 0xA34B, 0x0398, 0xA34C, 0x0399, 0xA34D, 0x039A, + 0xA34E, 0x039B, 0xA34F, 0x039C, 0xA350, 0x039D, 0xA351, 0x039E, 0xA352, 0x039F, 0xA353, 0x03A0, 0xA354, 0x03A1, 0xA355, 0x03A3, + 0xA356, 0x03A4, 0xA357, 0x03A5, 0xA358, 0x03A6, 0xA359, 0x03A7, 0xA35A, 0x03A8, 0xA35B, 0x03A9, 0xA35C, 0x03B1, 0xA35D, 0x03B2, + 0xA35E, 0x03B3, 0xA35F, 0x03B4, 0xA360, 0x03B5, 0xA361, 0x03B6, 0xA362, 0x03B7, 0xA363, 0x03B8, 0xA364, 0x03B9, 0xA365, 0x03BA, + 0xA366, 0x03BB, 0xA367, 0x03BC, 0xA368, 0x03BD, 0xA369, 0x03BE, 0xA36A, 0x03BF, 0xA36B, 0x03C0, 0xA36C, 0x03C1, 0xA36D, 0x03C3, + 0xA36E, 0x03C4, 0xA36F, 0x03C5, 0xA370, 0x03C6, 0xA371, 0x03C7, 0xA372, 0x03C8, 0xA373, 0x03C9, 0xA374, 0x3105, 0xA375, 0x3106, + 0xA376, 0x3107, 0xA377, 0x3108, 0xA378, 0x3109, 0xA379, 0x310A, 0xA37A, 0x310B, 0xA37B, 0x310C, 0xA37C, 0x310D, 0xA37D, 0x310E, + 0xA37E, 0x310F, 0xA3A1, 0x3110, 0xA3A2, 0x3111, 0xA3A3, 0x3112, 0xA3A4, 0x3113, 0xA3A5, 0x3114, 0xA3A6, 0x3115, 0xA3A7, 0x3116, + 0xA3A8, 0x3117, 0xA3A9, 0x3118, 0xA3AA, 0x3119, 0xA3AB, 0x311A, 0xA3AC, 0x311B, 0xA3AD, 0x311C, 0xA3AE, 0x311D, 0xA3AF, 0x311E, + 0xA3B0, 0x311F, 0xA3B1, 0x3120, 0xA3B2, 0x3121, 0xA3B3, 0x3122, 0xA3B4, 0x3123, 0xA3B5, 0x3124, 0xA3B6, 0x3125, 0xA3B7, 0x3126, + 0xA3B8, 0x3127, 0xA3B9, 0x3128, 0xA3BA, 0x3129, 0xA3BB, 0x02D9, 0xA3BC, 0x02C9, 0xA3BD, 0x02CA, 0xA3BE, 0x02C7, 0xA3BF, 0x02CB, + 0xA3E1, 0x20AC, 0xA440, 0x4E00, 0xA441, 0x4E59, 0xA442, 0x4E01, 0xA443, 0x4E03, 0xA444, 0x4E43, 0xA445, 0x4E5D, 0xA446, 0x4E86, + 0xA447, 0x4E8C, 0xA448, 0x4EBA, 0xA449, 0x513F, 0xA44A, 0x5165, 0xA44B, 0x516B, 0xA44C, 0x51E0, 0xA44D, 0x5200, 0xA44E, 0x5201, + 0xA44F, 0x529B, 0xA450, 0x5315, 0xA451, 0x5341, 0xA452, 0x535C, 0xA453, 0x53C8, 0xA454, 0x4E09, 0xA455, 0x4E0B, 0xA456, 0x4E08, + 0xA457, 0x4E0A, 0xA458, 0x4E2B, 0xA459, 0x4E38, 0xA45A, 0x51E1, 0xA45B, 0x4E45, 0xA45C, 0x4E48, 0xA45D, 0x4E5F, 0xA45E, 0x4E5E, + 0xA45F, 0x4E8E, 0xA460, 0x4EA1, 0xA461, 0x5140, 0xA462, 0x5203, 0xA463, 0x52FA, 0xA464, 0x5343, 0xA465, 0x53C9, 0xA466, 0x53E3, + 0xA467, 0x571F, 0xA468, 0x58EB, 0xA469, 0x5915, 0xA46A, 0x5927, 0xA46B, 0x5973, 0xA46C, 0x5B50, 0xA46D, 0x5B51, 0xA46E, 0x5B53, + 0xA46F, 0x5BF8, 0xA470, 0x5C0F, 0xA471, 0x5C22, 0xA472, 0x5C38, 0xA473, 0x5C71, 0xA474, 0x5DDD, 0xA475, 0x5DE5, 0xA476, 0x5DF1, + 0xA477, 0x5DF2, 0xA478, 0x5DF3, 0xA479, 0x5DFE, 0xA47A, 0x5E72, 0xA47B, 0x5EFE, 0xA47C, 0x5F0B, 0xA47D, 0x5F13, 0xA47E, 0x624D, + 0xA4A1, 0x4E11, 0xA4A2, 0x4E10, 0xA4A3, 0x4E0D, 0xA4A4, 0x4E2D, 0xA4A5, 0x4E30, 0xA4A6, 0x4E39, 0xA4A7, 0x4E4B, 0xA4A8, 0x5C39, + 0xA4A9, 0x4E88, 0xA4AA, 0x4E91, 0xA4AB, 0x4E95, 0xA4AC, 0x4E92, 0xA4AD, 0x4E94, 0xA4AE, 0x4EA2, 0xA4AF, 0x4EC1, 0xA4B0, 0x4EC0, + 0xA4B1, 0x4EC3, 0xA4B2, 0x4EC6, 0xA4B3, 0x4EC7, 0xA4B4, 0x4ECD, 0xA4B5, 0x4ECA, 0xA4B6, 0x4ECB, 0xA4B7, 0x4EC4, 0xA4B8, 0x5143, + 0xA4B9, 0x5141, 0xA4BA, 0x5167, 0xA4BB, 0x516D, 0xA4BC, 0x516E, 0xA4BD, 0x516C, 0xA4BE, 0x5197, 0xA4BF, 0x51F6, 0xA4C0, 0x5206, + 0xA4C1, 0x5207, 0xA4C2, 0x5208, 0xA4C3, 0x52FB, 0xA4C4, 0x52FE, 0xA4C5, 0x52FF, 0xA4C6, 0x5316, 0xA4C7, 0x5339, 0xA4C8, 0x5348, + 0xA4C9, 0x5347, 0xA4CA, 0x5345, 0xA4CB, 0x535E, 0xA4CC, 0x5384, 0xA4CD, 0x53CB, 0xA4CE, 0x53CA, 0xA4CF, 0x53CD, 0xA4D0, 0x58EC, + 0xA4D1, 0x5929, 0xA4D2, 0x592B, 0xA4D3, 0x592A, 0xA4D4, 0x592D, 0xA4D5, 0x5B54, 0xA4D6, 0x5C11, 0xA4D7, 0x5C24, 0xA4D8, 0x5C3A, + 0xA4D9, 0x5C6F, 0xA4DA, 0x5DF4, 0xA4DB, 0x5E7B, 0xA4DC, 0x5EFF, 0xA4DD, 0x5F14, 0xA4DE, 0x5F15, 0xA4DF, 0x5FC3, 0xA4E0, 0x6208, + 0xA4E1, 0x6236, 0xA4E2, 0x624B, 0xA4E3, 0x624E, 0xA4E4, 0x652F, 0xA4E5, 0x6587, 0xA4E6, 0x6597, 0xA4E7, 0x65A4, 0xA4E8, 0x65B9, + 0xA4E9, 0x65E5, 0xA4EA, 0x66F0, 0xA4EB, 0x6708, 0xA4EC, 0x6728, 0xA4ED, 0x6B20, 0xA4EE, 0x6B62, 0xA4EF, 0x6B79, 0xA4F0, 0x6BCB, + 0xA4F1, 0x6BD4, 0xA4F2, 0x6BDB, 0xA4F3, 0x6C0F, 0xA4F4, 0x6C34, 0xA4F5, 0x706B, 0xA4F6, 0x722A, 0xA4F7, 0x7236, 0xA4F8, 0x723B, + 0xA4F9, 0x7247, 0xA4FA, 0x7259, 0xA4FB, 0x725B, 0xA4FC, 0x72AC, 0xA4FD, 0x738B, 0xA4FE, 0x4E19, 0xA540, 0x4E16, 0xA541, 0x4E15, + 0xA542, 0x4E14, 0xA543, 0x4E18, 0xA544, 0x4E3B, 0xA545, 0x4E4D, 0xA546, 0x4E4F, 0xA547, 0x4E4E, 0xA548, 0x4EE5, 0xA549, 0x4ED8, + 0xA54A, 0x4ED4, 0xA54B, 0x4ED5, 0xA54C, 0x4ED6, 0xA54D, 0x4ED7, 0xA54E, 0x4EE3, 0xA54F, 0x4EE4, 0xA550, 0x4ED9, 0xA551, 0x4EDE, + 0xA552, 0x5145, 0xA553, 0x5144, 0xA554, 0x5189, 0xA555, 0x518A, 0xA556, 0x51AC, 0xA557, 0x51F9, 0xA558, 0x51FA, 0xA559, 0x51F8, + 0xA55A, 0x520A, 0xA55B, 0x52A0, 0xA55C, 0x529F, 0xA55D, 0x5305, 0xA55E, 0x5306, 0xA55F, 0x5317, 0xA560, 0x531D, 0xA561, 0x4EDF, + 0xA562, 0x534A, 0xA563, 0x5349, 0xA564, 0x5361, 0xA565, 0x5360, 0xA566, 0x536F, 0xA567, 0x536E, 0xA568, 0x53BB, 0xA569, 0x53EF, + 0xA56A, 0x53E4, 0xA56B, 0x53F3, 0xA56C, 0x53EC, 0xA56D, 0x53EE, 0xA56E, 0x53E9, 0xA56F, 0x53E8, 0xA570, 0x53FC, 0xA571, 0x53F8, + 0xA572, 0x53F5, 0xA573, 0x53EB, 0xA574, 0x53E6, 0xA575, 0x53EA, 0xA576, 0x53F2, 0xA577, 0x53F1, 0xA578, 0x53F0, 0xA579, 0x53E5, + 0xA57A, 0x53ED, 0xA57B, 0x53FB, 0xA57C, 0x56DB, 0xA57D, 0x56DA, 0xA57E, 0x5916, 0xA5A1, 0x592E, 0xA5A2, 0x5931, 0xA5A3, 0x5974, + 0xA5A4, 0x5976, 0xA5A5, 0x5B55, 0xA5A6, 0x5B83, 0xA5A7, 0x5C3C, 0xA5A8, 0x5DE8, 0xA5A9, 0x5DE7, 0xA5AA, 0x5DE6, 0xA5AB, 0x5E02, + 0xA5AC, 0x5E03, 0xA5AD, 0x5E73, 0xA5AE, 0x5E7C, 0xA5AF, 0x5F01, 0xA5B0, 0x5F18, 0xA5B1, 0x5F17, 0xA5B2, 0x5FC5, 0xA5B3, 0x620A, + 0xA5B4, 0x6253, 0xA5B5, 0x6254, 0xA5B6, 0x6252, 0xA5B7, 0x6251, 0xA5B8, 0x65A5, 0xA5B9, 0x65E6, 0xA5BA, 0x672E, 0xA5BB, 0x672C, + 0xA5BC, 0x672A, 0xA5BD, 0x672B, 0xA5BE, 0x672D, 0xA5BF, 0x6B63, 0xA5C0, 0x6BCD, 0xA5C1, 0x6C11, 0xA5C2, 0x6C10, 0xA5C3, 0x6C38, + 0xA5C4, 0x6C41, 0xA5C5, 0x6C40, 0xA5C6, 0x6C3E, 0xA5C7, 0x72AF, 0xA5C8, 0x7384, 0xA5C9, 0x7389, 0xA5CA, 0x74DC, 0xA5CB, 0x74E6, + 0xA5CC, 0x7518, 0xA5CD, 0x751F, 0xA5CE, 0x7528, 0xA5CF, 0x7529, 0xA5D0, 0x7530, 0xA5D1, 0x7531, 0xA5D2, 0x7532, 0xA5D3, 0x7533, + 0xA5D4, 0x758B, 0xA5D5, 0x767D, 0xA5D6, 0x76AE, 0xA5D7, 0x76BF, 0xA5D8, 0x76EE, 0xA5D9, 0x77DB, 0xA5DA, 0x77E2, 0xA5DB, 0x77F3, + 0xA5DC, 0x793A, 0xA5DD, 0x79BE, 0xA5DE, 0x7A74, 0xA5DF, 0x7ACB, 0xA5E0, 0x4E1E, 0xA5E1, 0x4E1F, 0xA5E2, 0x4E52, 0xA5E3, 0x4E53, + 0xA5E4, 0x4E69, 0xA5E5, 0x4E99, 0xA5E6, 0x4EA4, 0xA5E7, 0x4EA6, 0xA5E8, 0x4EA5, 0xA5E9, 0x4EFF, 0xA5EA, 0x4F09, 0xA5EB, 0x4F19, + 0xA5EC, 0x4F0A, 0xA5ED, 0x4F15, 0xA5EE, 0x4F0D, 0xA5EF, 0x4F10, 0xA5F0, 0x4F11, 0xA5F1, 0x4F0F, 0xA5F2, 0x4EF2, 0xA5F3, 0x4EF6, + 0xA5F4, 0x4EFB, 0xA5F5, 0x4EF0, 0xA5F6, 0x4EF3, 0xA5F7, 0x4EFD, 0xA5F8, 0x4F01, 0xA5F9, 0x4F0B, 0xA5FA, 0x5149, 0xA5FB, 0x5147, + 0xA5FC, 0x5146, 0xA5FD, 0x5148, 0xA5FE, 0x5168, 0xA640, 0x5171, 0xA641, 0x518D, 0xA642, 0x51B0, 0xA643, 0x5217, 0xA644, 0x5211, + 0xA645, 0x5212, 0xA646, 0x520E, 0xA647, 0x5216, 0xA648, 0x52A3, 0xA649, 0x5308, 0xA64A, 0x5321, 0xA64B, 0x5320, 0xA64C, 0x5370, + 0xA64D, 0x5371, 0xA64E, 0x5409, 0xA64F, 0x540F, 0xA650, 0x540C, 0xA651, 0x540A, 0xA652, 0x5410, 0xA653, 0x5401, 0xA654, 0x540B, + 0xA655, 0x5404, 0xA656, 0x5411, 0xA657, 0x540D, 0xA658, 0x5408, 0xA659, 0x5403, 0xA65A, 0x540E, 0xA65B, 0x5406, 0xA65C, 0x5412, + 0xA65D, 0x56E0, 0xA65E, 0x56DE, 0xA65F, 0x56DD, 0xA660, 0x5733, 0xA661, 0x5730, 0xA662, 0x5728, 0xA663, 0x572D, 0xA664, 0x572C, + 0xA665, 0x572F, 0xA666, 0x5729, 0xA667, 0x5919, 0xA668, 0x591A, 0xA669, 0x5937, 0xA66A, 0x5938, 0xA66B, 0x5984, 0xA66C, 0x5978, + 0xA66D, 0x5983, 0xA66E, 0x597D, 0xA66F, 0x5979, 0xA670, 0x5982, 0xA671, 0x5981, 0xA672, 0x5B57, 0xA673, 0x5B58, 0xA674, 0x5B87, + 0xA675, 0x5B88, 0xA676, 0x5B85, 0xA677, 0x5B89, 0xA678, 0x5BFA, 0xA679, 0x5C16, 0xA67A, 0x5C79, 0xA67B, 0x5DDE, 0xA67C, 0x5E06, + 0xA67D, 0x5E76, 0xA67E, 0x5E74, 0xA6A1, 0x5F0F, 0xA6A2, 0x5F1B, 0xA6A3, 0x5FD9, 0xA6A4, 0x5FD6, 0xA6A5, 0x620E, 0xA6A6, 0x620C, + 0xA6A7, 0x620D, 0xA6A8, 0x6210, 0xA6A9, 0x6263, 0xA6AA, 0x625B, 0xA6AB, 0x6258, 0xA6AC, 0x6536, 0xA6AD, 0x65E9, 0xA6AE, 0x65E8, + 0xA6AF, 0x65EC, 0xA6B0, 0x65ED, 0xA6B1, 0x66F2, 0xA6B2, 0x66F3, 0xA6B3, 0x6709, 0xA6B4, 0x673D, 0xA6B5, 0x6734, 0xA6B6, 0x6731, + 0xA6B7, 0x6735, 0xA6B8, 0x6B21, 0xA6B9, 0x6B64, 0xA6BA, 0x6B7B, 0xA6BB, 0x6C16, 0xA6BC, 0x6C5D, 0xA6BD, 0x6C57, 0xA6BE, 0x6C59, + 0xA6BF, 0x6C5F, 0xA6C0, 0x6C60, 0xA6C1, 0x6C50, 0xA6C2, 0x6C55, 0xA6C3, 0x6C61, 0xA6C4, 0x6C5B, 0xA6C5, 0x6C4D, 0xA6C6, 0x6C4E, + 0xA6C7, 0x7070, 0xA6C8, 0x725F, 0xA6C9, 0x725D, 0xA6CA, 0x767E, 0xA6CB, 0x7AF9, 0xA6CC, 0x7C73, 0xA6CD, 0x7CF8, 0xA6CE, 0x7F36, + 0xA6CF, 0x7F8A, 0xA6D0, 0x7FBD, 0xA6D1, 0x8001, 0xA6D2, 0x8003, 0xA6D3, 0x800C, 0xA6D4, 0x8012, 0xA6D5, 0x8033, 0xA6D6, 0x807F, + 0xA6D7, 0x8089, 0xA6D8, 0x808B, 0xA6D9, 0x808C, 0xA6DA, 0x81E3, 0xA6DB, 0x81EA, 0xA6DC, 0x81F3, 0xA6DD, 0x81FC, 0xA6DE, 0x820C, + 0xA6DF, 0x821B, 0xA6E0, 0x821F, 0xA6E1, 0x826E, 0xA6E2, 0x8272, 0xA6E3, 0x827E, 0xA6E4, 0x866B, 0xA6E5, 0x8840, 0xA6E6, 0x884C, + 0xA6E7, 0x8863, 0xA6E8, 0x897F, 0xA6E9, 0x9621, 0xA6EA, 0x4E32, 0xA6EB, 0x4EA8, 0xA6EC, 0x4F4D, 0xA6ED, 0x4F4F, 0xA6EE, 0x4F47, + 0xA6EF, 0x4F57, 0xA6F0, 0x4F5E, 0xA6F1, 0x4F34, 0xA6F2, 0x4F5B, 0xA6F3, 0x4F55, 0xA6F4, 0x4F30, 0xA6F5, 0x4F50, 0xA6F6, 0x4F51, + 0xA6F7, 0x4F3D, 0xA6F8, 0x4F3A, 0xA6F9, 0x4F38, 0xA6FA, 0x4F43, 0xA6FB, 0x4F54, 0xA6FC, 0x4F3C, 0xA6FD, 0x4F46, 0xA6FE, 0x4F63, + 0xA740, 0x4F5C, 0xA741, 0x4F60, 0xA742, 0x4F2F, 0xA743, 0x4F4E, 0xA744, 0x4F36, 0xA745, 0x4F59, 0xA746, 0x4F5D, 0xA747, 0x4F48, + 0xA748, 0x4F5A, 0xA749, 0x514C, 0xA74A, 0x514B, 0xA74B, 0x514D, 0xA74C, 0x5175, 0xA74D, 0x51B6, 0xA74E, 0x51B7, 0xA74F, 0x5225, + 0xA750, 0x5224, 0xA751, 0x5229, 0xA752, 0x522A, 0xA753, 0x5228, 0xA754, 0x52AB, 0xA755, 0x52A9, 0xA756, 0x52AA, 0xA757, 0x52AC, + 0xA758, 0x5323, 0xA759, 0x5373, 0xA75A, 0x5375, 0xA75B, 0x541D, 0xA75C, 0x542D, 0xA75D, 0x541E, 0xA75E, 0x543E, 0xA75F, 0x5426, + 0xA760, 0x544E, 0xA761, 0x5427, 0xA762, 0x5446, 0xA763, 0x5443, 0xA764, 0x5433, 0xA765, 0x5448, 0xA766, 0x5442, 0xA767, 0x541B, + 0xA768, 0x5429, 0xA769, 0x544A, 0xA76A, 0x5439, 0xA76B, 0x543B, 0xA76C, 0x5438, 0xA76D, 0x542E, 0xA76E, 0x5435, 0xA76F, 0x5436, + 0xA770, 0x5420, 0xA771, 0x543C, 0xA772, 0x5440, 0xA773, 0x5431, 0xA774, 0x542B, 0xA775, 0x541F, 0xA776, 0x542C, 0xA777, 0x56EA, + 0xA778, 0x56F0, 0xA779, 0x56E4, 0xA77A, 0x56EB, 0xA77B, 0x574A, 0xA77C, 0x5751, 0xA77D, 0x5740, 0xA77E, 0x574D, 0xA7A1, 0x5747, + 0xA7A2, 0x574E, 0xA7A3, 0x573E, 0xA7A4, 0x5750, 0xA7A5, 0x574F, 0xA7A6, 0x573B, 0xA7A7, 0x58EF, 0xA7A8, 0x593E, 0xA7A9, 0x599D, + 0xA7AA, 0x5992, 0xA7AB, 0x59A8, 0xA7AC, 0x599E, 0xA7AD, 0x59A3, 0xA7AE, 0x5999, 0xA7AF, 0x5996, 0xA7B0, 0x598D, 0xA7B1, 0x59A4, + 0xA7B2, 0x5993, 0xA7B3, 0x598A, 0xA7B4, 0x59A5, 0xA7B5, 0x5B5D, 0xA7B6, 0x5B5C, 0xA7B7, 0x5B5A, 0xA7B8, 0x5B5B, 0xA7B9, 0x5B8C, + 0xA7BA, 0x5B8B, 0xA7BB, 0x5B8F, 0xA7BC, 0x5C2C, 0xA7BD, 0x5C40, 0xA7BE, 0x5C41, 0xA7BF, 0x5C3F, 0xA7C0, 0x5C3E, 0xA7C1, 0x5C90, + 0xA7C2, 0x5C91, 0xA7C3, 0x5C94, 0xA7C4, 0x5C8C, 0xA7C5, 0x5DEB, 0xA7C6, 0x5E0C, 0xA7C7, 0x5E8F, 0xA7C8, 0x5E87, 0xA7C9, 0x5E8A, + 0xA7CA, 0x5EF7, 0xA7CB, 0x5F04, 0xA7CC, 0x5F1F, 0xA7CD, 0x5F64, 0xA7CE, 0x5F62, 0xA7CF, 0x5F77, 0xA7D0, 0x5F79, 0xA7D1, 0x5FD8, + 0xA7D2, 0x5FCC, 0xA7D3, 0x5FD7, 0xA7D4, 0x5FCD, 0xA7D5, 0x5FF1, 0xA7D6, 0x5FEB, 0xA7D7, 0x5FF8, 0xA7D8, 0x5FEA, 0xA7D9, 0x6212, + 0xA7DA, 0x6211, 0xA7DB, 0x6284, 0xA7DC, 0x6297, 0xA7DD, 0x6296, 0xA7DE, 0x6280, 0xA7DF, 0x6276, 0xA7E0, 0x6289, 0xA7E1, 0x626D, + 0xA7E2, 0x628A, 0xA7E3, 0x627C, 0xA7E4, 0x627E, 0xA7E5, 0x6279, 0xA7E6, 0x6273, 0xA7E7, 0x6292, 0xA7E8, 0x626F, 0xA7E9, 0x6298, + 0xA7EA, 0x626E, 0xA7EB, 0x6295, 0xA7EC, 0x6293, 0xA7ED, 0x6291, 0xA7EE, 0x6286, 0xA7EF, 0x6539, 0xA7F0, 0x653B, 0xA7F1, 0x6538, + 0xA7F2, 0x65F1, 0xA7F3, 0x66F4, 0xA7F4, 0x675F, 0xA7F5, 0x674E, 0xA7F6, 0x674F, 0xA7F7, 0x6750, 0xA7F8, 0x6751, 0xA7F9, 0x675C, + 0xA7FA, 0x6756, 0xA7FB, 0x675E, 0xA7FC, 0x6749, 0xA7FD, 0x6746, 0xA7FE, 0x6760, 0xA840, 0x6753, 0xA841, 0x6757, 0xA842, 0x6B65, + 0xA843, 0x6BCF, 0xA844, 0x6C42, 0xA845, 0x6C5E, 0xA846, 0x6C99, 0xA847, 0x6C81, 0xA848, 0x6C88, 0xA849, 0x6C89, 0xA84A, 0x6C85, + 0xA84B, 0x6C9B, 0xA84C, 0x6C6A, 0xA84D, 0x6C7A, 0xA84E, 0x6C90, 0xA84F, 0x6C70, 0xA850, 0x6C8C, 0xA851, 0x6C68, 0xA852, 0x6C96, + 0xA853, 0x6C92, 0xA854, 0x6C7D, 0xA855, 0x6C83, 0xA856, 0x6C72, 0xA857, 0x6C7E, 0xA858, 0x6C74, 0xA859, 0x6C86, 0xA85A, 0x6C76, + 0xA85B, 0x6C8D, 0xA85C, 0x6C94, 0xA85D, 0x6C98, 0xA85E, 0x6C82, 0xA85F, 0x7076, 0xA860, 0x707C, 0xA861, 0x707D, 0xA862, 0x7078, + 0xA863, 0x7262, 0xA864, 0x7261, 0xA865, 0x7260, 0xA866, 0x72C4, 0xA867, 0x72C2, 0xA868, 0x7396, 0xA869, 0x752C, 0xA86A, 0x752B, + 0xA86B, 0x7537, 0xA86C, 0x7538, 0xA86D, 0x7682, 0xA86E, 0x76EF, 0xA86F, 0x77E3, 0xA870, 0x79C1, 0xA871, 0x79C0, 0xA872, 0x79BF, + 0xA873, 0x7A76, 0xA874, 0x7CFB, 0xA875, 0x7F55, 0xA876, 0x8096, 0xA877, 0x8093, 0xA878, 0x809D, 0xA879, 0x8098, 0xA87A, 0x809B, + 0xA87B, 0x809A, 0xA87C, 0x80B2, 0xA87D, 0x826F, 0xA87E, 0x8292, 0xA8A1, 0x828B, 0xA8A2, 0x828D, 0xA8A3, 0x898B, 0xA8A4, 0x89D2, + 0xA8A5, 0x8A00, 0xA8A6, 0x8C37, 0xA8A7, 0x8C46, 0xA8A8, 0x8C55, 0xA8A9, 0x8C9D, 0xA8AA, 0x8D64, 0xA8AB, 0x8D70, 0xA8AC, 0x8DB3, + 0xA8AD, 0x8EAB, 0xA8AE, 0x8ECA, 0xA8AF, 0x8F9B, 0xA8B0, 0x8FB0, 0xA8B1, 0x8FC2, 0xA8B2, 0x8FC6, 0xA8B3, 0x8FC5, 0xA8B4, 0x8FC4, + 0xA8B5, 0x5DE1, 0xA8B6, 0x9091, 0xA8B7, 0x90A2, 0xA8B8, 0x90AA, 0xA8B9, 0x90A6, 0xA8BA, 0x90A3, 0xA8BB, 0x9149, 0xA8BC, 0x91C6, + 0xA8BD, 0x91CC, 0xA8BE, 0x9632, 0xA8BF, 0x962E, 0xA8C0, 0x9631, 0xA8C1, 0x962A, 0xA8C2, 0x962C, 0xA8C3, 0x4E26, 0xA8C4, 0x4E56, + 0xA8C5, 0x4E73, 0xA8C6, 0x4E8B, 0xA8C7, 0x4E9B, 0xA8C8, 0x4E9E, 0xA8C9, 0x4EAB, 0xA8CA, 0x4EAC, 0xA8CB, 0x4F6F, 0xA8CC, 0x4F9D, + 0xA8CD, 0x4F8D, 0xA8CE, 0x4F73, 0xA8CF, 0x4F7F, 0xA8D0, 0x4F6C, 0xA8D1, 0x4F9B, 0xA8D2, 0x4F8B, 0xA8D3, 0x4F86, 0xA8D4, 0x4F83, + 0xA8D5, 0x4F70, 0xA8D6, 0x4F75, 0xA8D7, 0x4F88, 0xA8D8, 0x4F69, 0xA8D9, 0x4F7B, 0xA8DA, 0x4F96, 0xA8DB, 0x4F7E, 0xA8DC, 0x4F8F, + 0xA8DD, 0x4F91, 0xA8DE, 0x4F7A, 0xA8DF, 0x5154, 0xA8E0, 0x5152, 0xA8E1, 0x5155, 0xA8E2, 0x5169, 0xA8E3, 0x5177, 0xA8E4, 0x5176, + 0xA8E5, 0x5178, 0xA8E6, 0x51BD, 0xA8E7, 0x51FD, 0xA8E8, 0x523B, 0xA8E9, 0x5238, 0xA8EA, 0x5237, 0xA8EB, 0x523A, 0xA8EC, 0x5230, + 0xA8ED, 0x522E, 0xA8EE, 0x5236, 0xA8EF, 0x5241, 0xA8F0, 0x52BE, 0xA8F1, 0x52BB, 0xA8F2, 0x5352, 0xA8F3, 0x5354, 0xA8F4, 0x5353, + 0xA8F5, 0x5351, 0xA8F6, 0x5366, 0xA8F7, 0x5377, 0xA8F8, 0x5378, 0xA8F9, 0x5379, 0xA8FA, 0x53D6, 0xA8FB, 0x53D4, 0xA8FC, 0x53D7, + 0xA8FD, 0x5473, 0xA8FE, 0x5475, 0xA940, 0x5496, 0xA941, 0x5478, 0xA942, 0x5495, 0xA943, 0x5480, 0xA944, 0x547B, 0xA945, 0x5477, + 0xA946, 0x5484, 0xA947, 0x5492, 0xA948, 0x5486, 0xA949, 0x547C, 0xA94A, 0x5490, 0xA94B, 0x5471, 0xA94C, 0x5476, 0xA94D, 0x548C, + 0xA94E, 0x549A, 0xA94F, 0x5462, 0xA950, 0x5468, 0xA951, 0x548B, 0xA952, 0x547D, 0xA953, 0x548E, 0xA954, 0x56FA, 0xA955, 0x5783, + 0xA956, 0x5777, 0xA957, 0x576A, 0xA958, 0x5769, 0xA959, 0x5761, 0xA95A, 0x5766, 0xA95B, 0x5764, 0xA95C, 0x577C, 0xA95D, 0x591C, + 0xA95E, 0x5949, 0xA95F, 0x5947, 0xA960, 0x5948, 0xA961, 0x5944, 0xA962, 0x5954, 0xA963, 0x59BE, 0xA964, 0x59BB, 0xA965, 0x59D4, + 0xA966, 0x59B9, 0xA967, 0x59AE, 0xA968, 0x59D1, 0xA969, 0x59C6, 0xA96A, 0x59D0, 0xA96B, 0x59CD, 0xA96C, 0x59CB, 0xA96D, 0x59D3, + 0xA96E, 0x59CA, 0xA96F, 0x59AF, 0xA970, 0x59B3, 0xA971, 0x59D2, 0xA972, 0x59C5, 0xA973, 0x5B5F, 0xA974, 0x5B64, 0xA975, 0x5B63, + 0xA976, 0x5B97, 0xA977, 0x5B9A, 0xA978, 0x5B98, 0xA979, 0x5B9C, 0xA97A, 0x5B99, 0xA97B, 0x5B9B, 0xA97C, 0x5C1A, 0xA97D, 0x5C48, + 0xA97E, 0x5C45, 0xA9A1, 0x5C46, 0xA9A2, 0x5CB7, 0xA9A3, 0x5CA1, 0xA9A4, 0x5CB8, 0xA9A5, 0x5CA9, 0xA9A6, 0x5CAB, 0xA9A7, 0x5CB1, + 0xA9A8, 0x5CB3, 0xA9A9, 0x5E18, 0xA9AA, 0x5E1A, 0xA9AB, 0x5E16, 0xA9AC, 0x5E15, 0xA9AD, 0x5E1B, 0xA9AE, 0x5E11, 0xA9AF, 0x5E78, + 0xA9B0, 0x5E9A, 0xA9B1, 0x5E97, 0xA9B2, 0x5E9C, 0xA9B3, 0x5E95, 0xA9B4, 0x5E96, 0xA9B5, 0x5EF6, 0xA9B6, 0x5F26, 0xA9B7, 0x5F27, + 0xA9B8, 0x5F29, 0xA9B9, 0x5F80, 0xA9BA, 0x5F81, 0xA9BB, 0x5F7F, 0xA9BC, 0x5F7C, 0xA9BD, 0x5FDD, 0xA9BE, 0x5FE0, 0xA9BF, 0x5FFD, + 0xA9C0, 0x5FF5, 0xA9C1, 0x5FFF, 0xA9C2, 0x600F, 0xA9C3, 0x6014, 0xA9C4, 0x602F, 0xA9C5, 0x6035, 0xA9C6, 0x6016, 0xA9C7, 0x602A, + 0xA9C8, 0x6015, 0xA9C9, 0x6021, 0xA9CA, 0x6027, 0xA9CB, 0x6029, 0xA9CC, 0x602B, 0xA9CD, 0x601B, 0xA9CE, 0x6216, 0xA9CF, 0x6215, + 0xA9D0, 0x623F, 0xA9D1, 0x623E, 0xA9D2, 0x6240, 0xA9D3, 0x627F, 0xA9D4, 0x62C9, 0xA9D5, 0x62CC, 0xA9D6, 0x62C4, 0xA9D7, 0x62BF, + 0xA9D8, 0x62C2, 0xA9D9, 0x62B9, 0xA9DA, 0x62D2, 0xA9DB, 0x62DB, 0xA9DC, 0x62AB, 0xA9DD, 0x62D3, 0xA9DE, 0x62D4, 0xA9DF, 0x62CB, + 0xA9E0, 0x62C8, 0xA9E1, 0x62A8, 0xA9E2, 0x62BD, 0xA9E3, 0x62BC, 0xA9E4, 0x62D0, 0xA9E5, 0x62D9, 0xA9E6, 0x62C7, 0xA9E7, 0x62CD, + 0xA9E8, 0x62B5, 0xA9E9, 0x62DA, 0xA9EA, 0x62B1, 0xA9EB, 0x62D8, 0xA9EC, 0x62D6, 0xA9ED, 0x62D7, 0xA9EE, 0x62C6, 0xA9EF, 0x62AC, + 0xA9F0, 0x62CE, 0xA9F1, 0x653E, 0xA9F2, 0x65A7, 0xA9F3, 0x65BC, 0xA9F4, 0x65FA, 0xA9F5, 0x6614, 0xA9F6, 0x6613, 0xA9F7, 0x660C, + 0xA9F8, 0x6606, 0xA9F9, 0x6602, 0xA9FA, 0x660E, 0xA9FB, 0x6600, 0xA9FC, 0x660F, 0xA9FD, 0x6615, 0xA9FE, 0x660A, 0xAA40, 0x6607, + 0xAA41, 0x670D, 0xAA42, 0x670B, 0xAA43, 0x676D, 0xAA44, 0x678B, 0xAA45, 0x6795, 0xAA46, 0x6771, 0xAA47, 0x679C, 0xAA48, 0x6773, + 0xAA49, 0x6777, 0xAA4A, 0x6787, 0xAA4B, 0x679D, 0xAA4C, 0x6797, 0xAA4D, 0x676F, 0xAA4E, 0x6770, 0xAA4F, 0x677F, 0xAA50, 0x6789, + 0xAA51, 0x677E, 0xAA52, 0x6790, 0xAA53, 0x6775, 0xAA54, 0x679A, 0xAA55, 0x6793, 0xAA56, 0x677C, 0xAA57, 0x676A, 0xAA58, 0x6772, + 0xAA59, 0x6B23, 0xAA5A, 0x6B66, 0xAA5B, 0x6B67, 0xAA5C, 0x6B7F, 0xAA5D, 0x6C13, 0xAA5E, 0x6C1B, 0xAA5F, 0x6CE3, 0xAA60, 0x6CE8, + 0xAA61, 0x6CF3, 0xAA62, 0x6CB1, 0xAA63, 0x6CCC, 0xAA64, 0x6CE5, 0xAA65, 0x6CB3, 0xAA66, 0x6CBD, 0xAA67, 0x6CBE, 0xAA68, 0x6CBC, + 0xAA69, 0x6CE2, 0xAA6A, 0x6CAB, 0xAA6B, 0x6CD5, 0xAA6C, 0x6CD3, 0xAA6D, 0x6CB8, 0xAA6E, 0x6CC4, 0xAA6F, 0x6CB9, 0xAA70, 0x6CC1, + 0xAA71, 0x6CAE, 0xAA72, 0x6CD7, 0xAA73, 0x6CC5, 0xAA74, 0x6CF1, 0xAA75, 0x6CBF, 0xAA76, 0x6CBB, 0xAA77, 0x6CE1, 0xAA78, 0x6CDB, + 0xAA79, 0x6CCA, 0xAA7A, 0x6CAC, 0xAA7B, 0x6CEF, 0xAA7C, 0x6CDC, 0xAA7D, 0x6CD6, 0xAA7E, 0x6CE0, 0xAAA1, 0x7095, 0xAAA2, 0x708E, + 0xAAA3, 0x7092, 0xAAA4, 0x708A, 0xAAA5, 0x7099, 0xAAA6, 0x722C, 0xAAA7, 0x722D, 0xAAA8, 0x7238, 0xAAA9, 0x7248, 0xAAAA, 0x7267, + 0xAAAB, 0x7269, 0xAAAC, 0x72C0, 0xAAAD, 0x72CE, 0xAAAE, 0x72D9, 0xAAAF, 0x72D7, 0xAAB0, 0x72D0, 0xAAB1, 0x73A9, 0xAAB2, 0x73A8, + 0xAAB3, 0x739F, 0xAAB4, 0x73AB, 0xAAB5, 0x73A5, 0xAAB6, 0x753D, 0xAAB7, 0x759D, 0xAAB8, 0x7599, 0xAAB9, 0x759A, 0xAABA, 0x7684, + 0xAABB, 0x76C2, 0xAABC, 0x76F2, 0xAABD, 0x76F4, 0xAABE, 0x77E5, 0xAABF, 0x77FD, 0xAAC0, 0x793E, 0xAAC1, 0x7940, 0xAAC2, 0x7941, + 0xAAC3, 0x79C9, 0xAAC4, 0x79C8, 0xAAC5, 0x7A7A, 0xAAC6, 0x7A79, 0xAAC7, 0x7AFA, 0xAAC8, 0x7CFE, 0xAAC9, 0x7F54, 0xAACA, 0x7F8C, + 0xAACB, 0x7F8B, 0xAACC, 0x8005, 0xAACD, 0x80BA, 0xAACE, 0x80A5, 0xAACF, 0x80A2, 0xAAD0, 0x80B1, 0xAAD1, 0x80A1, 0xAAD2, 0x80AB, + 0xAAD3, 0x80A9, 0xAAD4, 0x80B4, 0xAAD5, 0x80AA, 0xAAD6, 0x80AF, 0xAAD7, 0x81E5, 0xAAD8, 0x81FE, 0xAAD9, 0x820D, 0xAADA, 0x82B3, + 0xAADB, 0x829D, 0xAADC, 0x8299, 0xAADD, 0x82AD, 0xAADE, 0x82BD, 0xAADF, 0x829F, 0xAAE0, 0x82B9, 0xAAE1, 0x82B1, 0xAAE2, 0x82AC, + 0xAAE3, 0x82A5, 0xAAE4, 0x82AF, 0xAAE5, 0x82B8, 0xAAE6, 0x82A3, 0xAAE7, 0x82B0, 0xAAE8, 0x82BE, 0xAAE9, 0x82B7, 0xAAEA, 0x864E, + 0xAAEB, 0x8671, 0xAAEC, 0x521D, 0xAAED, 0x8868, 0xAAEE, 0x8ECB, 0xAAEF, 0x8FCE, 0xAAF0, 0x8FD4, 0xAAF1, 0x8FD1, 0xAAF2, 0x90B5, + 0xAAF3, 0x90B8, 0xAAF4, 0x90B1, 0xAAF5, 0x90B6, 0xAAF6, 0x91C7, 0xAAF7, 0x91D1, 0xAAF8, 0x9577, 0xAAF9, 0x9580, 0xAAFA, 0x961C, + 0xAAFB, 0x9640, 0xAAFC, 0x963F, 0xAAFD, 0x963B, 0xAAFE, 0x9644, 0xAB40, 0x9642, 0xAB41, 0x96B9, 0xAB42, 0x96E8, 0xAB43, 0x9752, + 0xAB44, 0x975E, 0xAB45, 0x4E9F, 0xAB46, 0x4EAD, 0xAB47, 0x4EAE, 0xAB48, 0x4FE1, 0xAB49, 0x4FB5, 0xAB4A, 0x4FAF, 0xAB4B, 0x4FBF, + 0xAB4C, 0x4FE0, 0xAB4D, 0x4FD1, 0xAB4E, 0x4FCF, 0xAB4F, 0x4FDD, 0xAB50, 0x4FC3, 0xAB51, 0x4FB6, 0xAB52, 0x4FD8, 0xAB53, 0x4FDF, + 0xAB54, 0x4FCA, 0xAB55, 0x4FD7, 0xAB56, 0x4FAE, 0xAB57, 0x4FD0, 0xAB58, 0x4FC4, 0xAB59, 0x4FC2, 0xAB5A, 0x4FDA, 0xAB5B, 0x4FCE, + 0xAB5C, 0x4FDE, 0xAB5D, 0x4FB7, 0xAB5E, 0x5157, 0xAB5F, 0x5192, 0xAB60, 0x5191, 0xAB61, 0x51A0, 0xAB62, 0x524E, 0xAB63, 0x5243, + 0xAB64, 0x524A, 0xAB65, 0x524D, 0xAB66, 0x524C, 0xAB67, 0x524B, 0xAB68, 0x5247, 0xAB69, 0x52C7, 0xAB6A, 0x52C9, 0xAB6B, 0x52C3, + 0xAB6C, 0x52C1, 0xAB6D, 0x530D, 0xAB6E, 0x5357, 0xAB6F, 0x537B, 0xAB70, 0x539A, 0xAB71, 0x53DB, 0xAB72, 0x54AC, 0xAB73, 0x54C0, + 0xAB74, 0x54A8, 0xAB75, 0x54CE, 0xAB76, 0x54C9, 0xAB77, 0x54B8, 0xAB78, 0x54A6, 0xAB79, 0x54B3, 0xAB7A, 0x54C7, 0xAB7B, 0x54C2, + 0xAB7C, 0x54BD, 0xAB7D, 0x54AA, 0xAB7E, 0x54C1, 0xABA1, 0x54C4, 0xABA2, 0x54C8, 0xABA3, 0x54AF, 0xABA4, 0x54AB, 0xABA5, 0x54B1, + 0xABA6, 0x54BB, 0xABA7, 0x54A9, 0xABA8, 0x54A7, 0xABA9, 0x54BF, 0xABAA, 0x56FF, 0xABAB, 0x5782, 0xABAC, 0x578B, 0xABAD, 0x57A0, + 0xABAE, 0x57A3, 0xABAF, 0x57A2, 0xABB0, 0x57CE, 0xABB1, 0x57AE, 0xABB2, 0x5793, 0xABB3, 0x5955, 0xABB4, 0x5951, 0xABB5, 0x594F, + 0xABB6, 0x594E, 0xABB7, 0x5950, 0xABB8, 0x59DC, 0xABB9, 0x59D8, 0xABBA, 0x59FF, 0xABBB, 0x59E3, 0xABBC, 0x59E8, 0xABBD, 0x5A03, + 0xABBE, 0x59E5, 0xABBF, 0x59EA, 0xABC0, 0x59DA, 0xABC1, 0x59E6, 0xABC2, 0x5A01, 0xABC3, 0x59FB, 0xABC4, 0x5B69, 0xABC5, 0x5BA3, + 0xABC6, 0x5BA6, 0xABC7, 0x5BA4, 0xABC8, 0x5BA2, 0xABC9, 0x5BA5, 0xABCA, 0x5C01, 0xABCB, 0x5C4E, 0xABCC, 0x5C4F, 0xABCD, 0x5C4D, + 0xABCE, 0x5C4B, 0xABCF, 0x5CD9, 0xABD0, 0x5CD2, 0xABD1, 0x5DF7, 0xABD2, 0x5E1D, 0xABD3, 0x5E25, 0xABD4, 0x5E1F, 0xABD5, 0x5E7D, + 0xABD6, 0x5EA0, 0xABD7, 0x5EA6, 0xABD8, 0x5EFA, 0xABD9, 0x5F08, 0xABDA, 0x5F2D, 0xABDB, 0x5F65, 0xABDC, 0x5F88, 0xABDD, 0x5F85, + 0xABDE, 0x5F8A, 0xABDF, 0x5F8B, 0xABE0, 0x5F87, 0xABE1, 0x5F8C, 0xABE2, 0x5F89, 0xABE3, 0x6012, 0xABE4, 0x601D, 0xABE5, 0x6020, + 0xABE6, 0x6025, 0xABE7, 0x600E, 0xABE8, 0x6028, 0xABE9, 0x604D, 0xABEA, 0x6070, 0xABEB, 0x6068, 0xABEC, 0x6062, 0xABED, 0x6046, + 0xABEE, 0x6043, 0xABEF, 0x606C, 0xABF0, 0x606B, 0xABF1, 0x606A, 0xABF2, 0x6064, 0xABF3, 0x6241, 0xABF4, 0x62DC, 0xABF5, 0x6316, + 0xABF6, 0x6309, 0xABF7, 0x62FC, 0xABF8, 0x62ED, 0xABF9, 0x6301, 0xABFA, 0x62EE, 0xABFB, 0x62FD, 0xABFC, 0x6307, 0xABFD, 0x62F1, + 0xABFE, 0x62F7, 0xAC40, 0x62EF, 0xAC41, 0x62EC, 0xAC42, 0x62FE, 0xAC43, 0x62F4, 0xAC44, 0x6311, 0xAC45, 0x6302, 0xAC46, 0x653F, + 0xAC47, 0x6545, 0xAC48, 0x65AB, 0xAC49, 0x65BD, 0xAC4A, 0x65E2, 0xAC4B, 0x6625, 0xAC4C, 0x662D, 0xAC4D, 0x6620, 0xAC4E, 0x6627, + 0xAC4F, 0x662F, 0xAC50, 0x661F, 0xAC51, 0x6628, 0xAC52, 0x6631, 0xAC53, 0x6624, 0xAC54, 0x66F7, 0xAC55, 0x67FF, 0xAC56, 0x67D3, + 0xAC57, 0x67F1, 0xAC58, 0x67D4, 0xAC59, 0x67D0, 0xAC5A, 0x67EC, 0xAC5B, 0x67B6, 0xAC5C, 0x67AF, 0xAC5D, 0x67F5, 0xAC5E, 0x67E9, + 0xAC5F, 0x67EF, 0xAC60, 0x67C4, 0xAC61, 0x67D1, 0xAC62, 0x67B4, 0xAC63, 0x67DA, 0xAC64, 0x67E5, 0xAC65, 0x67B8, 0xAC66, 0x67CF, + 0xAC67, 0x67DE, 0xAC68, 0x67F3, 0xAC69, 0x67B0, 0xAC6A, 0x67D9, 0xAC6B, 0x67E2, 0xAC6C, 0x67DD, 0xAC6D, 0x67D2, 0xAC6E, 0x6B6A, + 0xAC6F, 0x6B83, 0xAC70, 0x6B86, 0xAC71, 0x6BB5, 0xAC72, 0x6BD2, 0xAC73, 0x6BD7, 0xAC74, 0x6C1F, 0xAC75, 0x6CC9, 0xAC76, 0x6D0B, + 0xAC77, 0x6D32, 0xAC78, 0x6D2A, 0xAC79, 0x6D41, 0xAC7A, 0x6D25, 0xAC7B, 0x6D0C, 0xAC7C, 0x6D31, 0xAC7D, 0x6D1E, 0xAC7E, 0x6D17, + 0xACA1, 0x6D3B, 0xACA2, 0x6D3D, 0xACA3, 0x6D3E, 0xACA4, 0x6D36, 0xACA5, 0x6D1B, 0xACA6, 0x6CF5, 0xACA7, 0x6D39, 0xACA8, 0x6D27, + 0xACA9, 0x6D38, 0xACAA, 0x6D29, 0xACAB, 0x6D2E, 0xACAC, 0x6D35, 0xACAD, 0x6D0E, 0xACAE, 0x6D2B, 0xACAF, 0x70AB, 0xACB0, 0x70BA, + 0xACB1, 0x70B3, 0xACB2, 0x70AC, 0xACB3, 0x70AF, 0xACB4, 0x70AD, 0xACB5, 0x70B8, 0xACB6, 0x70AE, 0xACB7, 0x70A4, 0xACB8, 0x7230, + 0xACB9, 0x7272, 0xACBA, 0x726F, 0xACBB, 0x7274, 0xACBC, 0x72E9, 0xACBD, 0x72E0, 0xACBE, 0x72E1, 0xACBF, 0x73B7, 0xACC0, 0x73CA, + 0xACC1, 0x73BB, 0xACC2, 0x73B2, 0xACC3, 0x73CD, 0xACC4, 0x73C0, 0xACC5, 0x73B3, 0xACC6, 0x751A, 0xACC7, 0x752D, 0xACC8, 0x754F, + 0xACC9, 0x754C, 0xACCA, 0x754E, 0xACCB, 0x754B, 0xACCC, 0x75AB, 0xACCD, 0x75A4, 0xACCE, 0x75A5, 0xACCF, 0x75A2, 0xACD0, 0x75A3, + 0xACD1, 0x7678, 0xACD2, 0x7686, 0xACD3, 0x7687, 0xACD4, 0x7688, 0xACD5, 0x76C8, 0xACD6, 0x76C6, 0xACD7, 0x76C3, 0xACD8, 0x76C5, + 0xACD9, 0x7701, 0xACDA, 0x76F9, 0xACDB, 0x76F8, 0xACDC, 0x7709, 0xACDD, 0x770B, 0xACDE, 0x76FE, 0xACDF, 0x76FC, 0xACE0, 0x7707, + 0xACE1, 0x77DC, 0xACE2, 0x7802, 0xACE3, 0x7814, 0xACE4, 0x780C, 0xACE5, 0x780D, 0xACE6, 0x7946, 0xACE7, 0x7949, 0xACE8, 0x7948, + 0xACE9, 0x7947, 0xACEA, 0x79B9, 0xACEB, 0x79BA, 0xACEC, 0x79D1, 0xACED, 0x79D2, 0xACEE, 0x79CB, 0xACEF, 0x7A7F, 0xACF0, 0x7A81, + 0xACF1, 0x7AFF, 0xACF2, 0x7AFD, 0xACF3, 0x7C7D, 0xACF4, 0x7D02, 0xACF5, 0x7D05, 0xACF6, 0x7D00, 0xACF7, 0x7D09, 0xACF8, 0x7D07, + 0xACF9, 0x7D04, 0xACFA, 0x7D06, 0xACFB, 0x7F38, 0xACFC, 0x7F8E, 0xACFD, 0x7FBF, 0xACFE, 0x8004, 0xAD40, 0x8010, 0xAD41, 0x800D, + 0xAD42, 0x8011, 0xAD43, 0x8036, 0xAD44, 0x80D6, 0xAD45, 0x80E5, 0xAD46, 0x80DA, 0xAD47, 0x80C3, 0xAD48, 0x80C4, 0xAD49, 0x80CC, + 0xAD4A, 0x80E1, 0xAD4B, 0x80DB, 0xAD4C, 0x80CE, 0xAD4D, 0x80DE, 0xAD4E, 0x80E4, 0xAD4F, 0x80DD, 0xAD50, 0x81F4, 0xAD51, 0x8222, + 0xAD52, 0x82E7, 0xAD53, 0x8303, 0xAD54, 0x8305, 0xAD55, 0x82E3, 0xAD56, 0x82DB, 0xAD57, 0x82E6, 0xAD58, 0x8304, 0xAD59, 0x82E5, + 0xAD5A, 0x8302, 0xAD5B, 0x8309, 0xAD5C, 0x82D2, 0xAD5D, 0x82D7, 0xAD5E, 0x82F1, 0xAD5F, 0x8301, 0xAD60, 0x82DC, 0xAD61, 0x82D4, + 0xAD62, 0x82D1, 0xAD63, 0x82DE, 0xAD64, 0x82D3, 0xAD65, 0x82DF, 0xAD66, 0x82EF, 0xAD67, 0x8306, 0xAD68, 0x8650, 0xAD69, 0x8679, + 0xAD6A, 0x867B, 0xAD6B, 0x867A, 0xAD6C, 0x884D, 0xAD6D, 0x886B, 0xAD6E, 0x8981, 0xAD6F, 0x89D4, 0xAD70, 0x8A08, 0xAD71, 0x8A02, + 0xAD72, 0x8A03, 0xAD73, 0x8C9E, 0xAD74, 0x8CA0, 0xAD75, 0x8D74, 0xAD76, 0x8D73, 0xAD77, 0x8DB4, 0xAD78, 0x8ECD, 0xAD79, 0x8ECC, + 0xAD7A, 0x8FF0, 0xAD7B, 0x8FE6, 0xAD7C, 0x8FE2, 0xAD7D, 0x8FEA, 0xAD7E, 0x8FE5, 0xADA1, 0x8FED, 0xADA2, 0x8FEB, 0xADA3, 0x8FE4, + 0xADA4, 0x8FE8, 0xADA5, 0x90CA, 0xADA6, 0x90CE, 0xADA7, 0x90C1, 0xADA8, 0x90C3, 0xADA9, 0x914B, 0xADAA, 0x914A, 0xADAB, 0x91CD, + 0xADAC, 0x9582, 0xADAD, 0x9650, 0xADAE, 0x964B, 0xADAF, 0x964C, 0xADB0, 0x964D, 0xADB1, 0x9762, 0xADB2, 0x9769, 0xADB3, 0x97CB, + 0xADB4, 0x97ED, 0xADB5, 0x97F3, 0xADB6, 0x9801, 0xADB7, 0x98A8, 0xADB8, 0x98DB, 0xADB9, 0x98DF, 0xADBA, 0x9996, 0xADBB, 0x9999, + 0xADBC, 0x4E58, 0xADBD, 0x4EB3, 0xADBE, 0x500C, 0xADBF, 0x500D, 0xADC0, 0x5023, 0xADC1, 0x4FEF, 0xADC2, 0x5026, 0xADC3, 0x5025, + 0xADC4, 0x4FF8, 0xADC5, 0x5029, 0xADC6, 0x5016, 0xADC7, 0x5006, 0xADC8, 0x503C, 0xADC9, 0x501F, 0xADCA, 0x501A, 0xADCB, 0x5012, + 0xADCC, 0x5011, 0xADCD, 0x4FFA, 0xADCE, 0x5000, 0xADCF, 0x5014, 0xADD0, 0x5028, 0xADD1, 0x4FF1, 0xADD2, 0x5021, 0xADD3, 0x500B, + 0xADD4, 0x5019, 0xADD5, 0x5018, 0xADD6, 0x4FF3, 0xADD7, 0x4FEE, 0xADD8, 0x502D, 0xADD9, 0x502A, 0xADDA, 0x4FFE, 0xADDB, 0x502B, + 0xADDC, 0x5009, 0xADDD, 0x517C, 0xADDE, 0x51A4, 0xADDF, 0x51A5, 0xADE0, 0x51A2, 0xADE1, 0x51CD, 0xADE2, 0x51CC, 0xADE3, 0x51C6, + 0xADE4, 0x51CB, 0xADE5, 0x5256, 0xADE6, 0x525C, 0xADE7, 0x5254, 0xADE8, 0x525B, 0xADE9, 0x525D, 0xADEA, 0x532A, 0xADEB, 0x537F, + 0xADEC, 0x539F, 0xADED, 0x539D, 0xADEE, 0x53DF, 0xADEF, 0x54E8, 0xADF0, 0x5510, 0xADF1, 0x5501, 0xADF2, 0x5537, 0xADF3, 0x54FC, + 0xADF4, 0x54E5, 0xADF5, 0x54F2, 0xADF6, 0x5506, 0xADF7, 0x54FA, 0xADF8, 0x5514, 0xADF9, 0x54E9, 0xADFA, 0x54ED, 0xADFB, 0x54E1, + 0xADFC, 0x5509, 0xADFD, 0x54EE, 0xADFE, 0x54EA, 0xAE40, 0x54E6, 0xAE41, 0x5527, 0xAE42, 0x5507, 0xAE43, 0x54FD, 0xAE44, 0x550F, + 0xAE45, 0x5703, 0xAE46, 0x5704, 0xAE47, 0x57C2, 0xAE48, 0x57D4, 0xAE49, 0x57CB, 0xAE4A, 0x57C3, 0xAE4B, 0x5809, 0xAE4C, 0x590F, + 0xAE4D, 0x5957, 0xAE4E, 0x5958, 0xAE4F, 0x595A, 0xAE50, 0x5A11, 0xAE51, 0x5A18, 0xAE52, 0x5A1C, 0xAE53, 0x5A1F, 0xAE54, 0x5A1B, + 0xAE55, 0x5A13, 0xAE56, 0x59EC, 0xAE57, 0x5A20, 0xAE58, 0x5A23, 0xAE59, 0x5A29, 0xAE5A, 0x5A25, 0xAE5B, 0x5A0C, 0xAE5C, 0x5A09, + 0xAE5D, 0x5B6B, 0xAE5E, 0x5C58, 0xAE5F, 0x5BB0, 0xAE60, 0x5BB3, 0xAE61, 0x5BB6, 0xAE62, 0x5BB4, 0xAE63, 0x5BAE, 0xAE64, 0x5BB5, + 0xAE65, 0x5BB9, 0xAE66, 0x5BB8, 0xAE67, 0x5C04, 0xAE68, 0x5C51, 0xAE69, 0x5C55, 0xAE6A, 0x5C50, 0xAE6B, 0x5CED, 0xAE6C, 0x5CFD, + 0xAE6D, 0x5CFB, 0xAE6E, 0x5CEA, 0xAE6F, 0x5CE8, 0xAE70, 0x5CF0, 0xAE71, 0x5CF6, 0xAE72, 0x5D01, 0xAE73, 0x5CF4, 0xAE74, 0x5DEE, + 0xAE75, 0x5E2D, 0xAE76, 0x5E2B, 0xAE77, 0x5EAB, 0xAE78, 0x5EAD, 0xAE79, 0x5EA7, 0xAE7A, 0x5F31, 0xAE7B, 0x5F92, 0xAE7C, 0x5F91, + 0xAE7D, 0x5F90, 0xAE7E, 0x6059, 0xAEA1, 0x6063, 0xAEA2, 0x6065, 0xAEA3, 0x6050, 0xAEA4, 0x6055, 0xAEA5, 0x606D, 0xAEA6, 0x6069, + 0xAEA7, 0x606F, 0xAEA8, 0x6084, 0xAEA9, 0x609F, 0xAEAA, 0x609A, 0xAEAB, 0x608D, 0xAEAC, 0x6094, 0xAEAD, 0x608C, 0xAEAE, 0x6085, + 0xAEAF, 0x6096, 0xAEB0, 0x6247, 0xAEB1, 0x62F3, 0xAEB2, 0x6308, 0xAEB3, 0x62FF, 0xAEB4, 0x634E, 0xAEB5, 0x633E, 0xAEB6, 0x632F, + 0xAEB7, 0x6355, 0xAEB8, 0x6342, 0xAEB9, 0x6346, 0xAEBA, 0x634F, 0xAEBB, 0x6349, 0xAEBC, 0x633A, 0xAEBD, 0x6350, 0xAEBE, 0x633D, + 0xAEBF, 0x632A, 0xAEC0, 0x632B, 0xAEC1, 0x6328, 0xAEC2, 0x634D, 0xAEC3, 0x634C, 0xAEC4, 0x6548, 0xAEC5, 0x6549, 0xAEC6, 0x6599, + 0xAEC7, 0x65C1, 0xAEC8, 0x65C5, 0xAEC9, 0x6642, 0xAECA, 0x6649, 0xAECB, 0x664F, 0xAECC, 0x6643, 0xAECD, 0x6652, 0xAECE, 0x664C, + 0xAECF, 0x6645, 0xAED0, 0x6641, 0xAED1, 0x66F8, 0xAED2, 0x6714, 0xAED3, 0x6715, 0xAED4, 0x6717, 0xAED5, 0x6821, 0xAED6, 0x6838, + 0xAED7, 0x6848, 0xAED8, 0x6846, 0xAED9, 0x6853, 0xAEDA, 0x6839, 0xAEDB, 0x6842, 0xAEDC, 0x6854, 0xAEDD, 0x6829, 0xAEDE, 0x68B3, + 0xAEDF, 0x6817, 0xAEE0, 0x684C, 0xAEE1, 0x6851, 0xAEE2, 0x683D, 0xAEE3, 0x67F4, 0xAEE4, 0x6850, 0xAEE5, 0x6840, 0xAEE6, 0x683C, + 0xAEE7, 0x6843, 0xAEE8, 0x682A, 0xAEE9, 0x6845, 0xAEEA, 0x6813, 0xAEEB, 0x6818, 0xAEEC, 0x6841, 0xAEED, 0x6B8A, 0xAEEE, 0x6B89, + 0xAEEF, 0x6BB7, 0xAEF0, 0x6C23, 0xAEF1, 0x6C27, 0xAEF2, 0x6C28, 0xAEF3, 0x6C26, 0xAEF4, 0x6C24, 0xAEF5, 0x6CF0, 0xAEF6, 0x6D6A, + 0xAEF7, 0x6D95, 0xAEF8, 0x6D88, 0xAEF9, 0x6D87, 0xAEFA, 0x6D66, 0xAEFB, 0x6D78, 0xAEFC, 0x6D77, 0xAEFD, 0x6D59, 0xAEFE, 0x6D93, + 0xAF40, 0x6D6C, 0xAF41, 0x6D89, 0xAF42, 0x6D6E, 0xAF43, 0x6D5A, 0xAF44, 0x6D74, 0xAF45, 0x6D69, 0xAF46, 0x6D8C, 0xAF47, 0x6D8A, + 0xAF48, 0x6D79, 0xAF49, 0x6D85, 0xAF4A, 0x6D65, 0xAF4B, 0x6D94, 0xAF4C, 0x70CA, 0xAF4D, 0x70D8, 0xAF4E, 0x70E4, 0xAF4F, 0x70D9, + 0xAF50, 0x70C8, 0xAF51, 0x70CF, 0xAF52, 0x7239, 0xAF53, 0x7279, 0xAF54, 0x72FC, 0xAF55, 0x72F9, 0xAF56, 0x72FD, 0xAF57, 0x72F8, + 0xAF58, 0x72F7, 0xAF59, 0x7386, 0xAF5A, 0x73ED, 0xAF5B, 0x7409, 0xAF5C, 0x73EE, 0xAF5D, 0x73E0, 0xAF5E, 0x73EA, 0xAF5F, 0x73DE, + 0xAF60, 0x7554, 0xAF61, 0x755D, 0xAF62, 0x755C, 0xAF63, 0x755A, 0xAF64, 0x7559, 0xAF65, 0x75BE, 0xAF66, 0x75C5, 0xAF67, 0x75C7, + 0xAF68, 0x75B2, 0xAF69, 0x75B3, 0xAF6A, 0x75BD, 0xAF6B, 0x75BC, 0xAF6C, 0x75B9, 0xAF6D, 0x75C2, 0xAF6E, 0x75B8, 0xAF6F, 0x768B, + 0xAF70, 0x76B0, 0xAF71, 0x76CA, 0xAF72, 0x76CD, 0xAF73, 0x76CE, 0xAF74, 0x7729, 0xAF75, 0x771F, 0xAF76, 0x7720, 0xAF77, 0x7728, + 0xAF78, 0x77E9, 0xAF79, 0x7830, 0xAF7A, 0x7827, 0xAF7B, 0x7838, 0xAF7C, 0x781D, 0xAF7D, 0x7834, 0xAF7E, 0x7837, 0xAFA1, 0x7825, + 0xAFA2, 0x782D, 0xAFA3, 0x7820, 0xAFA4, 0x781F, 0xAFA5, 0x7832, 0xAFA6, 0x7955, 0xAFA7, 0x7950, 0xAFA8, 0x7960, 0xAFA9, 0x795F, + 0xAFAA, 0x7956, 0xAFAB, 0x795E, 0xAFAC, 0x795D, 0xAFAD, 0x7957, 0xAFAE, 0x795A, 0xAFAF, 0x79E4, 0xAFB0, 0x79E3, 0xAFB1, 0x79E7, + 0xAFB2, 0x79DF, 0xAFB3, 0x79E6, 0xAFB4, 0x79E9, 0xAFB5, 0x79D8, 0xAFB6, 0x7A84, 0xAFB7, 0x7A88, 0xAFB8, 0x7AD9, 0xAFB9, 0x7B06, + 0xAFBA, 0x7B11, 0xAFBB, 0x7C89, 0xAFBC, 0x7D21, 0xAFBD, 0x7D17, 0xAFBE, 0x7D0B, 0xAFBF, 0x7D0A, 0xAFC0, 0x7D20, 0xAFC1, 0x7D22, + 0xAFC2, 0x7D14, 0xAFC3, 0x7D10, 0xAFC4, 0x7D15, 0xAFC5, 0x7D1A, 0xAFC6, 0x7D1C, 0xAFC7, 0x7D0D, 0xAFC8, 0x7D19, 0xAFC9, 0x7D1B, + 0xAFCA, 0x7F3A, 0xAFCB, 0x7F5F, 0xAFCC, 0x7F94, 0xAFCD, 0x7FC5, 0xAFCE, 0x7FC1, 0xAFCF, 0x8006, 0xAFD0, 0x8018, 0xAFD1, 0x8015, + 0xAFD2, 0x8019, 0xAFD3, 0x8017, 0xAFD4, 0x803D, 0xAFD5, 0x803F, 0xAFD6, 0x80F1, 0xAFD7, 0x8102, 0xAFD8, 0x80F0, 0xAFD9, 0x8105, + 0xAFDA, 0x80ED, 0xAFDB, 0x80F4, 0xAFDC, 0x8106, 0xAFDD, 0x80F8, 0xAFDE, 0x80F3, 0xAFDF, 0x8108, 0xAFE0, 0x80FD, 0xAFE1, 0x810A, + 0xAFE2, 0x80FC, 0xAFE3, 0x80EF, 0xAFE4, 0x81ED, 0xAFE5, 0x81EC, 0xAFE6, 0x8200, 0xAFE7, 0x8210, 0xAFE8, 0x822A, 0xAFE9, 0x822B, + 0xAFEA, 0x8228, 0xAFEB, 0x822C, 0xAFEC, 0x82BB, 0xAFED, 0x832B, 0xAFEE, 0x8352, 0xAFEF, 0x8354, 0xAFF0, 0x834A, 0xAFF1, 0x8338, + 0xAFF2, 0x8350, 0xAFF3, 0x8349, 0xAFF4, 0x8335, 0xAFF5, 0x8334, 0xAFF6, 0x834F, 0xAFF7, 0x8332, 0xAFF8, 0x8339, 0xAFF9, 0x8336, + 0xAFFA, 0x8317, 0xAFFB, 0x8340, 0xAFFC, 0x8331, 0xAFFD, 0x8328, 0xAFFE, 0x8343, 0xB040, 0x8654, 0xB041, 0x868A, 0xB042, 0x86AA, + 0xB043, 0x8693, 0xB044, 0x86A4, 0xB045, 0x86A9, 0xB046, 0x868C, 0xB047, 0x86A3, 0xB048, 0x869C, 0xB049, 0x8870, 0xB04A, 0x8877, + 0xB04B, 0x8881, 0xB04C, 0x8882, 0xB04D, 0x887D, 0xB04E, 0x8879, 0xB04F, 0x8A18, 0xB050, 0x8A10, 0xB051, 0x8A0E, 0xB052, 0x8A0C, + 0xB053, 0x8A15, 0xB054, 0x8A0A, 0xB055, 0x8A17, 0xB056, 0x8A13, 0xB057, 0x8A16, 0xB058, 0x8A0F, 0xB059, 0x8A11, 0xB05A, 0x8C48, + 0xB05B, 0x8C7A, 0xB05C, 0x8C79, 0xB05D, 0x8CA1, 0xB05E, 0x8CA2, 0xB05F, 0x8D77, 0xB060, 0x8EAC, 0xB061, 0x8ED2, 0xB062, 0x8ED4, + 0xB063, 0x8ECF, 0xB064, 0x8FB1, 0xB065, 0x9001, 0xB066, 0x9006, 0xB067, 0x8FF7, 0xB068, 0x9000, 0xB069, 0x8FFA, 0xB06A, 0x8FF4, + 0xB06B, 0x9003, 0xB06C, 0x8FFD, 0xB06D, 0x9005, 0xB06E, 0x8FF8, 0xB06F, 0x9095, 0xB070, 0x90E1, 0xB071, 0x90DD, 0xB072, 0x90E2, + 0xB073, 0x9152, 0xB074, 0x914D, 0xB075, 0x914C, 0xB076, 0x91D8, 0xB077, 0x91DD, 0xB078, 0x91D7, 0xB079, 0x91DC, 0xB07A, 0x91D9, + 0xB07B, 0x9583, 0xB07C, 0x9662, 0xB07D, 0x9663, 0xB07E, 0x9661, 0xB0A1, 0x965B, 0xB0A2, 0x965D, 0xB0A3, 0x9664, 0xB0A4, 0x9658, + 0xB0A5, 0x965E, 0xB0A6, 0x96BB, 0xB0A7, 0x98E2, 0xB0A8, 0x99AC, 0xB0A9, 0x9AA8, 0xB0AA, 0x9AD8, 0xB0AB, 0x9B25, 0xB0AC, 0x9B32, + 0xB0AD, 0x9B3C, 0xB0AE, 0x4E7E, 0xB0AF, 0x507A, 0xB0B0, 0x507D, 0xB0B1, 0x505C, 0xB0B2, 0x5047, 0xB0B3, 0x5043, 0xB0B4, 0x504C, + 0xB0B5, 0x505A, 0xB0B6, 0x5049, 0xB0B7, 0x5065, 0xB0B8, 0x5076, 0xB0B9, 0x504E, 0xB0BA, 0x5055, 0xB0BB, 0x5075, 0xB0BC, 0x5074, + 0xB0BD, 0x5077, 0xB0BE, 0x504F, 0xB0BF, 0x500F, 0xB0C0, 0x506F, 0xB0C1, 0x506D, 0xB0C2, 0x515C, 0xB0C3, 0x5195, 0xB0C4, 0x51F0, + 0xB0C5, 0x526A, 0xB0C6, 0x526F, 0xB0C7, 0x52D2, 0xB0C8, 0x52D9, 0xB0C9, 0x52D8, 0xB0CA, 0x52D5, 0xB0CB, 0x5310, 0xB0CC, 0x530F, + 0xB0CD, 0x5319, 0xB0CE, 0x533F, 0xB0CF, 0x5340, 0xB0D0, 0x533E, 0xB0D1, 0x53C3, 0xB0D2, 0x66FC, 0xB0D3, 0x5546, 0xB0D4, 0x556A, + 0xB0D5, 0x5566, 0xB0D6, 0x5544, 0xB0D7, 0x555E, 0xB0D8, 0x5561, 0xB0D9, 0x5543, 0xB0DA, 0x554A, 0xB0DB, 0x5531, 0xB0DC, 0x5556, + 0xB0DD, 0x554F, 0xB0DE, 0x5555, 0xB0DF, 0x552F, 0xB0E0, 0x5564, 0xB0E1, 0x5538, 0xB0E2, 0x552E, 0xB0E3, 0x555C, 0xB0E4, 0x552C, + 0xB0E5, 0x5563, 0xB0E6, 0x5533, 0xB0E7, 0x5541, 0xB0E8, 0x5557, 0xB0E9, 0x5708, 0xB0EA, 0x570B, 0xB0EB, 0x5709, 0xB0EC, 0x57DF, + 0xB0ED, 0x5805, 0xB0EE, 0x580A, 0xB0EF, 0x5806, 0xB0F0, 0x57E0, 0xB0F1, 0x57E4, 0xB0F2, 0x57FA, 0xB0F3, 0x5802, 0xB0F4, 0x5835, + 0xB0F5, 0x57F7, 0xB0F6, 0x57F9, 0xB0F7, 0x5920, 0xB0F8, 0x5962, 0xB0F9, 0x5A36, 0xB0FA, 0x5A41, 0xB0FB, 0x5A49, 0xB0FC, 0x5A66, + 0xB0FD, 0x5A6A, 0xB0FE, 0x5A40, 0xB140, 0x5A3C, 0xB141, 0x5A62, 0xB142, 0x5A5A, 0xB143, 0x5A46, 0xB144, 0x5A4A, 0xB145, 0x5B70, + 0xB146, 0x5BC7, 0xB147, 0x5BC5, 0xB148, 0x5BC4, 0xB149, 0x5BC2, 0xB14A, 0x5BBF, 0xB14B, 0x5BC6, 0xB14C, 0x5C09, 0xB14D, 0x5C08, + 0xB14E, 0x5C07, 0xB14F, 0x5C60, 0xB150, 0x5C5C, 0xB151, 0x5C5D, 0xB152, 0x5D07, 0xB153, 0x5D06, 0xB154, 0x5D0E, 0xB155, 0x5D1B, + 0xB156, 0x5D16, 0xB157, 0x5D22, 0xB158, 0x5D11, 0xB159, 0x5D29, 0xB15A, 0x5D14, 0xB15B, 0x5D19, 0xB15C, 0x5D24, 0xB15D, 0x5D27, + 0xB15E, 0x5D17, 0xB15F, 0x5DE2, 0xB160, 0x5E38, 0xB161, 0x5E36, 0xB162, 0x5E33, 0xB163, 0x5E37, 0xB164, 0x5EB7, 0xB165, 0x5EB8, + 0xB166, 0x5EB6, 0xB167, 0x5EB5, 0xB168, 0x5EBE, 0xB169, 0x5F35, 0xB16A, 0x5F37, 0xB16B, 0x5F57, 0xB16C, 0x5F6C, 0xB16D, 0x5F69, + 0xB16E, 0x5F6B, 0xB16F, 0x5F97, 0xB170, 0x5F99, 0xB171, 0x5F9E, 0xB172, 0x5F98, 0xB173, 0x5FA1, 0xB174, 0x5FA0, 0xB175, 0x5F9C, + 0xB176, 0x607F, 0xB177, 0x60A3, 0xB178, 0x6089, 0xB179, 0x60A0, 0xB17A, 0x60A8, 0xB17B, 0x60CB, 0xB17C, 0x60B4, 0xB17D, 0x60E6, + 0xB17E, 0x60BD, 0xB1A1, 0x60C5, 0xB1A2, 0x60BB, 0xB1A3, 0x60B5, 0xB1A4, 0x60DC, 0xB1A5, 0x60BC, 0xB1A6, 0x60D8, 0xB1A7, 0x60D5, + 0xB1A8, 0x60C6, 0xB1A9, 0x60DF, 0xB1AA, 0x60B8, 0xB1AB, 0x60DA, 0xB1AC, 0x60C7, 0xB1AD, 0x621A, 0xB1AE, 0x621B, 0xB1AF, 0x6248, + 0xB1B0, 0x63A0, 0xB1B1, 0x63A7, 0xB1B2, 0x6372, 0xB1B3, 0x6396, 0xB1B4, 0x63A2, 0xB1B5, 0x63A5, 0xB1B6, 0x6377, 0xB1B7, 0x6367, + 0xB1B8, 0x6398, 0xB1B9, 0x63AA, 0xB1BA, 0x6371, 0xB1BB, 0x63A9, 0xB1BC, 0x6389, 0xB1BD, 0x6383, 0xB1BE, 0x639B, 0xB1BF, 0x636B, + 0xB1C0, 0x63A8, 0xB1C1, 0x6384, 0xB1C2, 0x6388, 0xB1C3, 0x6399, 0xB1C4, 0x63A1, 0xB1C5, 0x63AC, 0xB1C6, 0x6392, 0xB1C7, 0x638F, + 0xB1C8, 0x6380, 0xB1C9, 0x637B, 0xB1CA, 0x6369, 0xB1CB, 0x6368, 0xB1CC, 0x637A, 0xB1CD, 0x655D, 0xB1CE, 0x6556, 0xB1CF, 0x6551, + 0xB1D0, 0x6559, 0xB1D1, 0x6557, 0xB1D2, 0x555F, 0xB1D3, 0x654F, 0xB1D4, 0x6558, 0xB1D5, 0x6555, 0xB1D6, 0x6554, 0xB1D7, 0x659C, + 0xB1D8, 0x659B, 0xB1D9, 0x65AC, 0xB1DA, 0x65CF, 0xB1DB, 0x65CB, 0xB1DC, 0x65CC, 0xB1DD, 0x65CE, 0xB1DE, 0x665D, 0xB1DF, 0x665A, + 0xB1E0, 0x6664, 0xB1E1, 0x6668, 0xB1E2, 0x6666, 0xB1E3, 0x665E, 0xB1E4, 0x66F9, 0xB1E5, 0x52D7, 0xB1E6, 0x671B, 0xB1E7, 0x6881, + 0xB1E8, 0x68AF, 0xB1E9, 0x68A2, 0xB1EA, 0x6893, 0xB1EB, 0x68B5, 0xB1EC, 0x687F, 0xB1ED, 0x6876, 0xB1EE, 0x68B1, 0xB1EF, 0x68A7, + 0xB1F0, 0x6897, 0xB1F1, 0x68B0, 0xB1F2, 0x6883, 0xB1F3, 0x68C4, 0xB1F4, 0x68AD, 0xB1F5, 0x6886, 0xB1F6, 0x6885, 0xB1F7, 0x6894, + 0xB1F8, 0x689D, 0xB1F9, 0x68A8, 0xB1FA, 0x689F, 0xB1FB, 0x68A1, 0xB1FC, 0x6882, 0xB1FD, 0x6B32, 0xB1FE, 0x6BBA, 0xB240, 0x6BEB, + 0xB241, 0x6BEC, 0xB242, 0x6C2B, 0xB243, 0x6D8E, 0xB244, 0x6DBC, 0xB245, 0x6DF3, 0xB246, 0x6DD9, 0xB247, 0x6DB2, 0xB248, 0x6DE1, + 0xB249, 0x6DCC, 0xB24A, 0x6DE4, 0xB24B, 0x6DFB, 0xB24C, 0x6DFA, 0xB24D, 0x6E05, 0xB24E, 0x6DC7, 0xB24F, 0x6DCB, 0xB250, 0x6DAF, + 0xB251, 0x6DD1, 0xB252, 0x6DAE, 0xB253, 0x6DDE, 0xB254, 0x6DF9, 0xB255, 0x6DB8, 0xB256, 0x6DF7, 0xB257, 0x6DF5, 0xB258, 0x6DC5, + 0xB259, 0x6DD2, 0xB25A, 0x6E1A, 0xB25B, 0x6DB5, 0xB25C, 0x6DDA, 0xB25D, 0x6DEB, 0xB25E, 0x6DD8, 0xB25F, 0x6DEA, 0xB260, 0x6DF1, + 0xB261, 0x6DEE, 0xB262, 0x6DE8, 0xB263, 0x6DC6, 0xB264, 0x6DC4, 0xB265, 0x6DAA, 0xB266, 0x6DEC, 0xB267, 0x6DBF, 0xB268, 0x6DE6, + 0xB269, 0x70F9, 0xB26A, 0x7109, 0xB26B, 0x710A, 0xB26C, 0x70FD, 0xB26D, 0x70EF, 0xB26E, 0x723D, 0xB26F, 0x727D, 0xB270, 0x7281, + 0xB271, 0x731C, 0xB272, 0x731B, 0xB273, 0x7316, 0xB274, 0x7313, 0xB275, 0x7319, 0xB276, 0x7387, 0xB277, 0x7405, 0xB278, 0x740A, + 0xB279, 0x7403, 0xB27A, 0x7406, 0xB27B, 0x73FE, 0xB27C, 0x740D, 0xB27D, 0x74E0, 0xB27E, 0x74F6, 0xB2A1, 0x74F7, 0xB2A2, 0x751C, + 0xB2A3, 0x7522, 0xB2A4, 0x7565, 0xB2A5, 0x7566, 0xB2A6, 0x7562, 0xB2A7, 0x7570, 0xB2A8, 0x758F, 0xB2A9, 0x75D4, 0xB2AA, 0x75D5, + 0xB2AB, 0x75B5, 0xB2AC, 0x75CA, 0xB2AD, 0x75CD, 0xB2AE, 0x768E, 0xB2AF, 0x76D4, 0xB2B0, 0x76D2, 0xB2B1, 0x76DB, 0xB2B2, 0x7737, + 0xB2B3, 0x773E, 0xB2B4, 0x773C, 0xB2B5, 0x7736, 0xB2B6, 0x7738, 0xB2B7, 0x773A, 0xB2B8, 0x786B, 0xB2B9, 0x7843, 0xB2BA, 0x784E, + 0xB2BB, 0x7965, 0xB2BC, 0x7968, 0xB2BD, 0x796D, 0xB2BE, 0x79FB, 0xB2BF, 0x7A92, 0xB2C0, 0x7A95, 0xB2C1, 0x7B20, 0xB2C2, 0x7B28, + 0xB2C3, 0x7B1B, 0xB2C4, 0x7B2C, 0xB2C5, 0x7B26, 0xB2C6, 0x7B19, 0xB2C7, 0x7B1E, 0xB2C8, 0x7B2E, 0xB2C9, 0x7C92, 0xB2CA, 0x7C97, + 0xB2CB, 0x7C95, 0xB2CC, 0x7D46, 0xB2CD, 0x7D43, 0xB2CE, 0x7D71, 0xB2CF, 0x7D2E, 0xB2D0, 0x7D39, 0xB2D1, 0x7D3C, 0xB2D2, 0x7D40, + 0xB2D3, 0x7D30, 0xB2D4, 0x7D33, 0xB2D5, 0x7D44, 0xB2D6, 0x7D2F, 0xB2D7, 0x7D42, 0xB2D8, 0x7D32, 0xB2D9, 0x7D31, 0xB2DA, 0x7F3D, + 0xB2DB, 0x7F9E, 0xB2DC, 0x7F9A, 0xB2DD, 0x7FCC, 0xB2DE, 0x7FCE, 0xB2DF, 0x7FD2, 0xB2E0, 0x801C, 0xB2E1, 0x804A, 0xB2E2, 0x8046, + 0xB2E3, 0x812F, 0xB2E4, 0x8116, 0xB2E5, 0x8123, 0xB2E6, 0x812B, 0xB2E7, 0x8129, 0xB2E8, 0x8130, 0xB2E9, 0x8124, 0xB2EA, 0x8202, + 0xB2EB, 0x8235, 0xB2EC, 0x8237, 0xB2ED, 0x8236, 0xB2EE, 0x8239, 0xB2EF, 0x838E, 0xB2F0, 0x839E, 0xB2F1, 0x8398, 0xB2F2, 0x8378, + 0xB2F3, 0x83A2, 0xB2F4, 0x8396, 0xB2F5, 0x83BD, 0xB2F6, 0x83AB, 0xB2F7, 0x8392, 0xB2F8, 0x838A, 0xB2F9, 0x8393, 0xB2FA, 0x8389, + 0xB2FB, 0x83A0, 0xB2FC, 0x8377, 0xB2FD, 0x837B, 0xB2FE, 0x837C, 0xB340, 0x8386, 0xB341, 0x83A7, 0xB342, 0x8655, 0xB343, 0x5F6A, + 0xB344, 0x86C7, 0xB345, 0x86C0, 0xB346, 0x86B6, 0xB347, 0x86C4, 0xB348, 0x86B5, 0xB349, 0x86C6, 0xB34A, 0x86CB, 0xB34B, 0x86B1, + 0xB34C, 0x86AF, 0xB34D, 0x86C9, 0xB34E, 0x8853, 0xB34F, 0x889E, 0xB350, 0x8888, 0xB351, 0x88AB, 0xB352, 0x8892, 0xB353, 0x8896, + 0xB354, 0x888D, 0xB355, 0x888B, 0xB356, 0x8993, 0xB357, 0x898F, 0xB358, 0x8A2A, 0xB359, 0x8A1D, 0xB35A, 0x8A23, 0xB35B, 0x8A25, + 0xB35C, 0x8A31, 0xB35D, 0x8A2D, 0xB35E, 0x8A1F, 0xB35F, 0x8A1B, 0xB360, 0x8A22, 0xB361, 0x8C49, 0xB362, 0x8C5A, 0xB363, 0x8CA9, + 0xB364, 0x8CAC, 0xB365, 0x8CAB, 0xB366, 0x8CA8, 0xB367, 0x8CAA, 0xB368, 0x8CA7, 0xB369, 0x8D67, 0xB36A, 0x8D66, 0xB36B, 0x8DBE, + 0xB36C, 0x8DBA, 0xB36D, 0x8EDB, 0xB36E, 0x8EDF, 0xB36F, 0x9019, 0xB370, 0x900D, 0xB371, 0x901A, 0xB372, 0x9017, 0xB373, 0x9023, + 0xB374, 0x901F, 0xB375, 0x901D, 0xB376, 0x9010, 0xB377, 0x9015, 0xB378, 0x901E, 0xB379, 0x9020, 0xB37A, 0x900F, 0xB37B, 0x9022, + 0xB37C, 0x9016, 0xB37D, 0x901B, 0xB37E, 0x9014, 0xB3A1, 0x90E8, 0xB3A2, 0x90ED, 0xB3A3, 0x90FD, 0xB3A4, 0x9157, 0xB3A5, 0x91CE, + 0xB3A6, 0x91F5, 0xB3A7, 0x91E6, 0xB3A8, 0x91E3, 0xB3A9, 0x91E7, 0xB3AA, 0x91ED, 0xB3AB, 0x91E9, 0xB3AC, 0x9589, 0xB3AD, 0x966A, + 0xB3AE, 0x9675, 0xB3AF, 0x9673, 0xB3B0, 0x9678, 0xB3B1, 0x9670, 0xB3B2, 0x9674, 0xB3B3, 0x9676, 0xB3B4, 0x9677, 0xB3B5, 0x966C, + 0xB3B6, 0x96C0, 0xB3B7, 0x96EA, 0xB3B8, 0x96E9, 0xB3B9, 0x7AE0, 0xB3BA, 0x7ADF, 0xB3BB, 0x9802, 0xB3BC, 0x9803, 0xB3BD, 0x9B5A, + 0xB3BE, 0x9CE5, 0xB3BF, 0x9E75, 0xB3C0, 0x9E7F, 0xB3C1, 0x9EA5, 0xB3C2, 0x9EBB, 0xB3C3, 0x50A2, 0xB3C4, 0x508D, 0xB3C5, 0x5085, + 0xB3C6, 0x5099, 0xB3C7, 0x5091, 0xB3C8, 0x5080, 0xB3C9, 0x5096, 0xB3CA, 0x5098, 0xB3CB, 0x509A, 0xB3CC, 0x6700, 0xB3CD, 0x51F1, + 0xB3CE, 0x5272, 0xB3CF, 0x5274, 0xB3D0, 0x5275, 0xB3D1, 0x5269, 0xB3D2, 0x52DE, 0xB3D3, 0x52DD, 0xB3D4, 0x52DB, 0xB3D5, 0x535A, + 0xB3D6, 0x53A5, 0xB3D7, 0x557B, 0xB3D8, 0x5580, 0xB3D9, 0x55A7, 0xB3DA, 0x557C, 0xB3DB, 0x558A, 0xB3DC, 0x559D, 0xB3DD, 0x5598, + 0xB3DE, 0x5582, 0xB3DF, 0x559C, 0xB3E0, 0x55AA, 0xB3E1, 0x5594, 0xB3E2, 0x5587, 0xB3E3, 0x558B, 0xB3E4, 0x5583, 0xB3E5, 0x55B3, + 0xB3E6, 0x55AE, 0xB3E7, 0x559F, 0xB3E8, 0x553E, 0xB3E9, 0x55B2, 0xB3EA, 0x559A, 0xB3EB, 0x55BB, 0xB3EC, 0x55AC, 0xB3ED, 0x55B1, + 0xB3EE, 0x557E, 0xB3EF, 0x5589, 0xB3F0, 0x55AB, 0xB3F1, 0x5599, 0xB3F2, 0x570D, 0xB3F3, 0x582F, 0xB3F4, 0x582A, 0xB3F5, 0x5834, + 0xB3F6, 0x5824, 0xB3F7, 0x5830, 0xB3F8, 0x5831, 0xB3F9, 0x5821, 0xB3FA, 0x581D, 0xB3FB, 0x5820, 0xB3FC, 0x58F9, 0xB3FD, 0x58FA, + 0xB3FE, 0x5960, 0xB440, 0x5A77, 0xB441, 0x5A9A, 0xB442, 0x5A7F, 0xB443, 0x5A92, 0xB444, 0x5A9B, 0xB445, 0x5AA7, 0xB446, 0x5B73, + 0xB447, 0x5B71, 0xB448, 0x5BD2, 0xB449, 0x5BCC, 0xB44A, 0x5BD3, 0xB44B, 0x5BD0, 0xB44C, 0x5C0A, 0xB44D, 0x5C0B, 0xB44E, 0x5C31, + 0xB44F, 0x5D4C, 0xB450, 0x5D50, 0xB451, 0x5D34, 0xB452, 0x5D47, 0xB453, 0x5DFD, 0xB454, 0x5E45, 0xB455, 0x5E3D, 0xB456, 0x5E40, + 0xB457, 0x5E43, 0xB458, 0x5E7E, 0xB459, 0x5ECA, 0xB45A, 0x5EC1, 0xB45B, 0x5EC2, 0xB45C, 0x5EC4, 0xB45D, 0x5F3C, 0xB45E, 0x5F6D, + 0xB45F, 0x5FA9, 0xB460, 0x5FAA, 0xB461, 0x5FA8, 0xB462, 0x60D1, 0xB463, 0x60E1, 0xB464, 0x60B2, 0xB465, 0x60B6, 0xB466, 0x60E0, + 0xB467, 0x611C, 0xB468, 0x6123, 0xB469, 0x60FA, 0xB46A, 0x6115, 0xB46B, 0x60F0, 0xB46C, 0x60FB, 0xB46D, 0x60F4, 0xB46E, 0x6168, + 0xB46F, 0x60F1, 0xB470, 0x610E, 0xB471, 0x60F6, 0xB472, 0x6109, 0xB473, 0x6100, 0xB474, 0x6112, 0xB475, 0x621F, 0xB476, 0x6249, + 0xB477, 0x63A3, 0xB478, 0x638C, 0xB479, 0x63CF, 0xB47A, 0x63C0, 0xB47B, 0x63E9, 0xB47C, 0x63C9, 0xB47D, 0x63C6, 0xB47E, 0x63CD, + 0xB4A1, 0x63D2, 0xB4A2, 0x63E3, 0xB4A3, 0x63D0, 0xB4A4, 0x63E1, 0xB4A5, 0x63D6, 0xB4A6, 0x63ED, 0xB4A7, 0x63EE, 0xB4A8, 0x6376, + 0xB4A9, 0x63F4, 0xB4AA, 0x63EA, 0xB4AB, 0x63DB, 0xB4AC, 0x6452, 0xB4AD, 0x63DA, 0xB4AE, 0x63F9, 0xB4AF, 0x655E, 0xB4B0, 0x6566, + 0xB4B1, 0x6562, 0xB4B2, 0x6563, 0xB4B3, 0x6591, 0xB4B4, 0x6590, 0xB4B5, 0x65AF, 0xB4B6, 0x666E, 0xB4B7, 0x6670, 0xB4B8, 0x6674, + 0xB4B9, 0x6676, 0xB4BA, 0x666F, 0xB4BB, 0x6691, 0xB4BC, 0x667A, 0xB4BD, 0x667E, 0xB4BE, 0x6677, 0xB4BF, 0x66FE, 0xB4C0, 0x66FF, + 0xB4C1, 0x671F, 0xB4C2, 0x671D, 0xB4C3, 0x68FA, 0xB4C4, 0x68D5, 0xB4C5, 0x68E0, 0xB4C6, 0x68D8, 0xB4C7, 0x68D7, 0xB4C8, 0x6905, + 0xB4C9, 0x68DF, 0xB4CA, 0x68F5, 0xB4CB, 0x68EE, 0xB4CC, 0x68E7, 0xB4CD, 0x68F9, 0xB4CE, 0x68D2, 0xB4CF, 0x68F2, 0xB4D0, 0x68E3, + 0xB4D1, 0x68CB, 0xB4D2, 0x68CD, 0xB4D3, 0x690D, 0xB4D4, 0x6912, 0xB4D5, 0x690E, 0xB4D6, 0x68C9, 0xB4D7, 0x68DA, 0xB4D8, 0x696E, + 0xB4D9, 0x68FB, 0xB4DA, 0x6B3E, 0xB4DB, 0x6B3A, 0xB4DC, 0x6B3D, 0xB4DD, 0x6B98, 0xB4DE, 0x6B96, 0xB4DF, 0x6BBC, 0xB4E0, 0x6BEF, + 0xB4E1, 0x6C2E, 0xB4E2, 0x6C2F, 0xB4E3, 0x6C2C, 0xB4E4, 0x6E2F, 0xB4E5, 0x6E38, 0xB4E6, 0x6E54, 0xB4E7, 0x6E21, 0xB4E8, 0x6E32, + 0xB4E9, 0x6E67, 0xB4EA, 0x6E4A, 0xB4EB, 0x6E20, 0xB4EC, 0x6E25, 0xB4ED, 0x6E23, 0xB4EE, 0x6E1B, 0xB4EF, 0x6E5B, 0xB4F0, 0x6E58, + 0xB4F1, 0x6E24, 0xB4F2, 0x6E56, 0xB4F3, 0x6E6E, 0xB4F4, 0x6E2D, 0xB4F5, 0x6E26, 0xB4F6, 0x6E6F, 0xB4F7, 0x6E34, 0xB4F8, 0x6E4D, + 0xB4F9, 0x6E3A, 0xB4FA, 0x6E2C, 0xB4FB, 0x6E43, 0xB4FC, 0x6E1D, 0xB4FD, 0x6E3E, 0xB4FE, 0x6ECB, 0xB540, 0x6E89, 0xB541, 0x6E19, + 0xB542, 0x6E4E, 0xB543, 0x6E63, 0xB544, 0x6E44, 0xB545, 0x6E72, 0xB546, 0x6E69, 0xB547, 0x6E5F, 0xB548, 0x7119, 0xB549, 0x711A, + 0xB54A, 0x7126, 0xB54B, 0x7130, 0xB54C, 0x7121, 0xB54D, 0x7136, 0xB54E, 0x716E, 0xB54F, 0x711C, 0xB550, 0x724C, 0xB551, 0x7284, + 0xB552, 0x7280, 0xB553, 0x7336, 0xB554, 0x7325, 0xB555, 0x7334, 0xB556, 0x7329, 0xB557, 0x743A, 0xB558, 0x742A, 0xB559, 0x7433, + 0xB55A, 0x7422, 0xB55B, 0x7425, 0xB55C, 0x7435, 0xB55D, 0x7436, 0xB55E, 0x7434, 0xB55F, 0x742F, 0xB560, 0x741B, 0xB561, 0x7426, + 0xB562, 0x7428, 0xB563, 0x7525, 0xB564, 0x7526, 0xB565, 0x756B, 0xB566, 0x756A, 0xB567, 0x75E2, 0xB568, 0x75DB, 0xB569, 0x75E3, + 0xB56A, 0x75D9, 0xB56B, 0x75D8, 0xB56C, 0x75DE, 0xB56D, 0x75E0, 0xB56E, 0x767B, 0xB56F, 0x767C, 0xB570, 0x7696, 0xB571, 0x7693, + 0xB572, 0x76B4, 0xB573, 0x76DC, 0xB574, 0x774F, 0xB575, 0x77ED, 0xB576, 0x785D, 0xB577, 0x786C, 0xB578, 0x786F, 0xB579, 0x7A0D, + 0xB57A, 0x7A08, 0xB57B, 0x7A0B, 0xB57C, 0x7A05, 0xB57D, 0x7A00, 0xB57E, 0x7A98, 0xB5A1, 0x7A97, 0xB5A2, 0x7A96, 0xB5A3, 0x7AE5, + 0xB5A4, 0x7AE3, 0xB5A5, 0x7B49, 0xB5A6, 0x7B56, 0xB5A7, 0x7B46, 0xB5A8, 0x7B50, 0xB5A9, 0x7B52, 0xB5AA, 0x7B54, 0xB5AB, 0x7B4D, + 0xB5AC, 0x7B4B, 0xB5AD, 0x7B4F, 0xB5AE, 0x7B51, 0xB5AF, 0x7C9F, 0xB5B0, 0x7CA5, 0xB5B1, 0x7D5E, 0xB5B2, 0x7D50, 0xB5B3, 0x7D68, + 0xB5B4, 0x7D55, 0xB5B5, 0x7D2B, 0xB5B6, 0x7D6E, 0xB5B7, 0x7D72, 0xB5B8, 0x7D61, 0xB5B9, 0x7D66, 0xB5BA, 0x7D62, 0xB5BB, 0x7D70, + 0xB5BC, 0x7D73, 0xB5BD, 0x5584, 0xB5BE, 0x7FD4, 0xB5BF, 0x7FD5, 0xB5C0, 0x800B, 0xB5C1, 0x8052, 0xB5C2, 0x8085, 0xB5C3, 0x8155, + 0xB5C4, 0x8154, 0xB5C5, 0x814B, 0xB5C6, 0x8151, 0xB5C7, 0x814E, 0xB5C8, 0x8139, 0xB5C9, 0x8146, 0xB5CA, 0x813E, 0xB5CB, 0x814C, + 0xB5CC, 0x8153, 0xB5CD, 0x8174, 0xB5CE, 0x8212, 0xB5CF, 0x821C, 0xB5D0, 0x83E9, 0xB5D1, 0x8403, 0xB5D2, 0x83F8, 0xB5D3, 0x840D, + 0xB5D4, 0x83E0, 0xB5D5, 0x83C5, 0xB5D6, 0x840B, 0xB5D7, 0x83C1, 0xB5D8, 0x83EF, 0xB5D9, 0x83F1, 0xB5DA, 0x83F4, 0xB5DB, 0x8457, + 0xB5DC, 0x840A, 0xB5DD, 0x83F0, 0xB5DE, 0x840C, 0xB5DF, 0x83CC, 0xB5E0, 0x83FD, 0xB5E1, 0x83F2, 0xB5E2, 0x83CA, 0xB5E3, 0x8438, + 0xB5E4, 0x840E, 0xB5E5, 0x8404, 0xB5E6, 0x83DC, 0xB5E7, 0x8407, 0xB5E8, 0x83D4, 0xB5E9, 0x83DF, 0xB5EA, 0x865B, 0xB5EB, 0x86DF, + 0xB5EC, 0x86D9, 0xB5ED, 0x86ED, 0xB5EE, 0x86D4, 0xB5EF, 0x86DB, 0xB5F0, 0x86E4, 0xB5F1, 0x86D0, 0xB5F2, 0x86DE, 0xB5F3, 0x8857, + 0xB5F4, 0x88C1, 0xB5F5, 0x88C2, 0xB5F6, 0x88B1, 0xB5F7, 0x8983, 0xB5F8, 0x8996, 0xB5F9, 0x8A3B, 0xB5FA, 0x8A60, 0xB5FB, 0x8A55, + 0xB5FC, 0x8A5E, 0xB5FD, 0x8A3C, 0xB5FE, 0x8A41, 0xB640, 0x8A54, 0xB641, 0x8A5B, 0xB642, 0x8A50, 0xB643, 0x8A46, 0xB644, 0x8A34, + 0xB645, 0x8A3A, 0xB646, 0x8A36, 0xB647, 0x8A56, 0xB648, 0x8C61, 0xB649, 0x8C82, 0xB64A, 0x8CAF, 0xB64B, 0x8CBC, 0xB64C, 0x8CB3, + 0xB64D, 0x8CBD, 0xB64E, 0x8CC1, 0xB64F, 0x8CBB, 0xB650, 0x8CC0, 0xB651, 0x8CB4, 0xB652, 0x8CB7, 0xB653, 0x8CB6, 0xB654, 0x8CBF, + 0xB655, 0x8CB8, 0xB656, 0x8D8A, 0xB657, 0x8D85, 0xB658, 0x8D81, 0xB659, 0x8DCE, 0xB65A, 0x8DDD, 0xB65B, 0x8DCB, 0xB65C, 0x8DDA, + 0xB65D, 0x8DD1, 0xB65E, 0x8DCC, 0xB65F, 0x8DDB, 0xB660, 0x8DC6, 0xB661, 0x8EFB, 0xB662, 0x8EF8, 0xB663, 0x8EFC, 0xB664, 0x8F9C, + 0xB665, 0x902E, 0xB666, 0x9035, 0xB667, 0x9031, 0xB668, 0x9038, 0xB669, 0x9032, 0xB66A, 0x9036, 0xB66B, 0x9102, 0xB66C, 0x90F5, + 0xB66D, 0x9109, 0xB66E, 0x90FE, 0xB66F, 0x9163, 0xB670, 0x9165, 0xB671, 0x91CF, 0xB672, 0x9214, 0xB673, 0x9215, 0xB674, 0x9223, + 0xB675, 0x9209, 0xB676, 0x921E, 0xB677, 0x920D, 0xB678, 0x9210, 0xB679, 0x9207, 0xB67A, 0x9211, 0xB67B, 0x9594, 0xB67C, 0x958F, + 0xB67D, 0x958B, 0xB67E, 0x9591, 0xB6A1, 0x9593, 0xB6A2, 0x9592, 0xB6A3, 0x958E, 0xB6A4, 0x968A, 0xB6A5, 0x968E, 0xB6A6, 0x968B, + 0xB6A7, 0x967D, 0xB6A8, 0x9685, 0xB6A9, 0x9686, 0xB6AA, 0x968D, 0xB6AB, 0x9672, 0xB6AC, 0x9684, 0xB6AD, 0x96C1, 0xB6AE, 0x96C5, + 0xB6AF, 0x96C4, 0xB6B0, 0x96C6, 0xB6B1, 0x96C7, 0xB6B2, 0x96EF, 0xB6B3, 0x96F2, 0xB6B4, 0x97CC, 0xB6B5, 0x9805, 0xB6B6, 0x9806, + 0xB6B7, 0x9808, 0xB6B8, 0x98E7, 0xB6B9, 0x98EA, 0xB6BA, 0x98EF, 0xB6BB, 0x98E9, 0xB6BC, 0x98F2, 0xB6BD, 0x98ED, 0xB6BE, 0x99AE, + 0xB6BF, 0x99AD, 0xB6C0, 0x9EC3, 0xB6C1, 0x9ECD, 0xB6C2, 0x9ED1, 0xB6C3, 0x4E82, 0xB6C4, 0x50AD, 0xB6C5, 0x50B5, 0xB6C6, 0x50B2, + 0xB6C7, 0x50B3, 0xB6C8, 0x50C5, 0xB6C9, 0x50BE, 0xB6CA, 0x50AC, 0xB6CB, 0x50B7, 0xB6CC, 0x50BB, 0xB6CD, 0x50AF, 0xB6CE, 0x50C7, + 0xB6CF, 0x527F, 0xB6D0, 0x5277, 0xB6D1, 0x527D, 0xB6D2, 0x52DF, 0xB6D3, 0x52E6, 0xB6D4, 0x52E4, 0xB6D5, 0x52E2, 0xB6D6, 0x52E3, + 0xB6D7, 0x532F, 0xB6D8, 0x55DF, 0xB6D9, 0x55E8, 0xB6DA, 0x55D3, 0xB6DB, 0x55E6, 0xB6DC, 0x55CE, 0xB6DD, 0x55DC, 0xB6DE, 0x55C7, + 0xB6DF, 0x55D1, 0xB6E0, 0x55E3, 0xB6E1, 0x55E4, 0xB6E2, 0x55EF, 0xB6E3, 0x55DA, 0xB6E4, 0x55E1, 0xB6E5, 0x55C5, 0xB6E6, 0x55C6, + 0xB6E7, 0x55E5, 0xB6E8, 0x55C9, 0xB6E9, 0x5712, 0xB6EA, 0x5713, 0xB6EB, 0x585E, 0xB6EC, 0x5851, 0xB6ED, 0x5858, 0xB6EE, 0x5857, + 0xB6EF, 0x585A, 0xB6F0, 0x5854, 0xB6F1, 0x586B, 0xB6F2, 0x584C, 0xB6F3, 0x586D, 0xB6F4, 0x584A, 0xB6F5, 0x5862, 0xB6F6, 0x5852, + 0xB6F7, 0x584B, 0xB6F8, 0x5967, 0xB6F9, 0x5AC1, 0xB6FA, 0x5AC9, 0xB6FB, 0x5ACC, 0xB6FC, 0x5ABE, 0xB6FD, 0x5ABD, 0xB6FE, 0x5ABC, + 0xB740, 0x5AB3, 0xB741, 0x5AC2, 0xB742, 0x5AB2, 0xB743, 0x5D69, 0xB744, 0x5D6F, 0xB745, 0x5E4C, 0xB746, 0x5E79, 0xB747, 0x5EC9, + 0xB748, 0x5EC8, 0xB749, 0x5F12, 0xB74A, 0x5F59, 0xB74B, 0x5FAC, 0xB74C, 0x5FAE, 0xB74D, 0x611A, 0xB74E, 0x610F, 0xB74F, 0x6148, + 0xB750, 0x611F, 0xB751, 0x60F3, 0xB752, 0x611B, 0xB753, 0x60F9, 0xB754, 0x6101, 0xB755, 0x6108, 0xB756, 0x614E, 0xB757, 0x614C, + 0xB758, 0x6144, 0xB759, 0x614D, 0xB75A, 0x613E, 0xB75B, 0x6134, 0xB75C, 0x6127, 0xB75D, 0x610D, 0xB75E, 0x6106, 0xB75F, 0x6137, + 0xB760, 0x6221, 0xB761, 0x6222, 0xB762, 0x6413, 0xB763, 0x643E, 0xB764, 0x641E, 0xB765, 0x642A, 0xB766, 0x642D, 0xB767, 0x643D, + 0xB768, 0x642C, 0xB769, 0x640F, 0xB76A, 0x641C, 0xB76B, 0x6414, 0xB76C, 0x640D, 0xB76D, 0x6436, 0xB76E, 0x6416, 0xB76F, 0x6417, + 0xB770, 0x6406, 0xB771, 0x656C, 0xB772, 0x659F, 0xB773, 0x65B0, 0xB774, 0x6697, 0xB775, 0x6689, 0xB776, 0x6687, 0xB777, 0x6688, + 0xB778, 0x6696, 0xB779, 0x6684, 0xB77A, 0x6698, 0xB77B, 0x668D, 0xB77C, 0x6703, 0xB77D, 0x6994, 0xB77E, 0x696D, 0xB7A1, 0x695A, + 0xB7A2, 0x6977, 0xB7A3, 0x6960, 0xB7A4, 0x6954, 0xB7A5, 0x6975, 0xB7A6, 0x6930, 0xB7A7, 0x6982, 0xB7A8, 0x694A, 0xB7A9, 0x6968, + 0xB7AA, 0x696B, 0xB7AB, 0x695E, 0xB7AC, 0x6953, 0xB7AD, 0x6979, 0xB7AE, 0x6986, 0xB7AF, 0x695D, 0xB7B0, 0x6963, 0xB7B1, 0x695B, + 0xB7B2, 0x6B47, 0xB7B3, 0x6B72, 0xB7B4, 0x6BC0, 0xB7B5, 0x6BBF, 0xB7B6, 0x6BD3, 0xB7B7, 0x6BFD, 0xB7B8, 0x6EA2, 0xB7B9, 0x6EAF, + 0xB7BA, 0x6ED3, 0xB7BB, 0x6EB6, 0xB7BC, 0x6EC2, 0xB7BD, 0x6E90, 0xB7BE, 0x6E9D, 0xB7BF, 0x6EC7, 0xB7C0, 0x6EC5, 0xB7C1, 0x6EA5, + 0xB7C2, 0x6E98, 0xB7C3, 0x6EBC, 0xB7C4, 0x6EBA, 0xB7C5, 0x6EAB, 0xB7C6, 0x6ED1, 0xB7C7, 0x6E96, 0xB7C8, 0x6E9C, 0xB7C9, 0x6EC4, + 0xB7CA, 0x6ED4, 0xB7CB, 0x6EAA, 0xB7CC, 0x6EA7, 0xB7CD, 0x6EB4, 0xB7CE, 0x714E, 0xB7CF, 0x7159, 0xB7D0, 0x7169, 0xB7D1, 0x7164, + 0xB7D2, 0x7149, 0xB7D3, 0x7167, 0xB7D4, 0x715C, 0xB7D5, 0x716C, 0xB7D6, 0x7166, 0xB7D7, 0x714C, 0xB7D8, 0x7165, 0xB7D9, 0x715E, + 0xB7DA, 0x7146, 0xB7DB, 0x7168, 0xB7DC, 0x7156, 0xB7DD, 0x723A, 0xB7DE, 0x7252, 0xB7DF, 0x7337, 0xB7E0, 0x7345, 0xB7E1, 0x733F, + 0xB7E2, 0x733E, 0xB7E3, 0x746F, 0xB7E4, 0x745A, 0xB7E5, 0x7455, 0xB7E6, 0x745F, 0xB7E7, 0x745E, 0xB7E8, 0x7441, 0xB7E9, 0x743F, + 0xB7EA, 0x7459, 0xB7EB, 0x745B, 0xB7EC, 0x745C, 0xB7ED, 0x7576, 0xB7EE, 0x7578, 0xB7EF, 0x7600, 0xB7F0, 0x75F0, 0xB7F1, 0x7601, + 0xB7F2, 0x75F2, 0xB7F3, 0x75F1, 0xB7F4, 0x75FA, 0xB7F5, 0x75FF, 0xB7F6, 0x75F4, 0xB7F7, 0x75F3, 0xB7F8, 0x76DE, 0xB7F9, 0x76DF, + 0xB7FA, 0x775B, 0xB7FB, 0x776B, 0xB7FC, 0x7766, 0xB7FD, 0x775E, 0xB7FE, 0x7763, 0xB840, 0x7779, 0xB841, 0x776A, 0xB842, 0x776C, + 0xB843, 0x775C, 0xB844, 0x7765, 0xB845, 0x7768, 0xB846, 0x7762, 0xB847, 0x77EE, 0xB848, 0x788E, 0xB849, 0x78B0, 0xB84A, 0x7897, + 0xB84B, 0x7898, 0xB84C, 0x788C, 0xB84D, 0x7889, 0xB84E, 0x787C, 0xB84F, 0x7891, 0xB850, 0x7893, 0xB851, 0x787F, 0xB852, 0x797A, + 0xB853, 0x797F, 0xB854, 0x7981, 0xB855, 0x842C, 0xB856, 0x79BD, 0xB857, 0x7A1C, 0xB858, 0x7A1A, 0xB859, 0x7A20, 0xB85A, 0x7A14, + 0xB85B, 0x7A1F, 0xB85C, 0x7A1E, 0xB85D, 0x7A9F, 0xB85E, 0x7AA0, 0xB85F, 0x7B77, 0xB860, 0x7BC0, 0xB861, 0x7B60, 0xB862, 0x7B6E, + 0xB863, 0x7B67, 0xB864, 0x7CB1, 0xB865, 0x7CB3, 0xB866, 0x7CB5, 0xB867, 0x7D93, 0xB868, 0x7D79, 0xB869, 0x7D91, 0xB86A, 0x7D81, + 0xB86B, 0x7D8F, 0xB86C, 0x7D5B, 0xB86D, 0x7F6E, 0xB86E, 0x7F69, 0xB86F, 0x7F6A, 0xB870, 0x7F72, 0xB871, 0x7FA9, 0xB872, 0x7FA8, + 0xB873, 0x7FA4, 0xB874, 0x8056, 0xB875, 0x8058, 0xB876, 0x8086, 0xB877, 0x8084, 0xB878, 0x8171, 0xB879, 0x8170, 0xB87A, 0x8178, + 0xB87B, 0x8165, 0xB87C, 0x816E, 0xB87D, 0x8173, 0xB87E, 0x816B, 0xB8A1, 0x8179, 0xB8A2, 0x817A, 0xB8A3, 0x8166, 0xB8A4, 0x8205, + 0xB8A5, 0x8247, 0xB8A6, 0x8482, 0xB8A7, 0x8477, 0xB8A8, 0x843D, 0xB8A9, 0x8431, 0xB8AA, 0x8475, 0xB8AB, 0x8466, 0xB8AC, 0x846B, + 0xB8AD, 0x8449, 0xB8AE, 0x846C, 0xB8AF, 0x845B, 0xB8B0, 0x843C, 0xB8B1, 0x8435, 0xB8B2, 0x8461, 0xB8B3, 0x8463, 0xB8B4, 0x8469, + 0xB8B5, 0x846D, 0xB8B6, 0x8446, 0xB8B7, 0x865E, 0xB8B8, 0x865C, 0xB8B9, 0x865F, 0xB8BA, 0x86F9, 0xB8BB, 0x8713, 0xB8BC, 0x8708, + 0xB8BD, 0x8707, 0xB8BE, 0x8700, 0xB8BF, 0x86FE, 0xB8C0, 0x86FB, 0xB8C1, 0x8702, 0xB8C2, 0x8703, 0xB8C3, 0x8706, 0xB8C4, 0x870A, + 0xB8C5, 0x8859, 0xB8C6, 0x88DF, 0xB8C7, 0x88D4, 0xB8C8, 0x88D9, 0xB8C9, 0x88DC, 0xB8CA, 0x88D8, 0xB8CB, 0x88DD, 0xB8CC, 0x88E1, + 0xB8CD, 0x88CA, 0xB8CE, 0x88D5, 0xB8CF, 0x88D2, 0xB8D0, 0x899C, 0xB8D1, 0x89E3, 0xB8D2, 0x8A6B, 0xB8D3, 0x8A72, 0xB8D4, 0x8A73, + 0xB8D5, 0x8A66, 0xB8D6, 0x8A69, 0xB8D7, 0x8A70, 0xB8D8, 0x8A87, 0xB8D9, 0x8A7C, 0xB8DA, 0x8A63, 0xB8DB, 0x8AA0, 0xB8DC, 0x8A71, + 0xB8DD, 0x8A85, 0xB8DE, 0x8A6D, 0xB8DF, 0x8A62, 0xB8E0, 0x8A6E, 0xB8E1, 0x8A6C, 0xB8E2, 0x8A79, 0xB8E3, 0x8A7B, 0xB8E4, 0x8A3E, + 0xB8E5, 0x8A68, 0xB8E6, 0x8C62, 0xB8E7, 0x8C8A, 0xB8E8, 0x8C89, 0xB8E9, 0x8CCA, 0xB8EA, 0x8CC7, 0xB8EB, 0x8CC8, 0xB8EC, 0x8CC4, + 0xB8ED, 0x8CB2, 0xB8EE, 0x8CC3, 0xB8EF, 0x8CC2, 0xB8F0, 0x8CC5, 0xB8F1, 0x8DE1, 0xB8F2, 0x8DDF, 0xB8F3, 0x8DE8, 0xB8F4, 0x8DEF, + 0xB8F5, 0x8DF3, 0xB8F6, 0x8DFA, 0xB8F7, 0x8DEA, 0xB8F8, 0x8DE4, 0xB8F9, 0x8DE6, 0xB8FA, 0x8EB2, 0xB8FB, 0x8F03, 0xB8FC, 0x8F09, + 0xB8FD, 0x8EFE, 0xB8FE, 0x8F0A, 0xB940, 0x8F9F, 0xB941, 0x8FB2, 0xB942, 0x904B, 0xB943, 0x904A, 0xB944, 0x9053, 0xB945, 0x9042, + 0xB946, 0x9054, 0xB947, 0x903C, 0xB948, 0x9055, 0xB949, 0x9050, 0xB94A, 0x9047, 0xB94B, 0x904F, 0xB94C, 0x904E, 0xB94D, 0x904D, + 0xB94E, 0x9051, 0xB94F, 0x903E, 0xB950, 0x9041, 0xB951, 0x9112, 0xB952, 0x9117, 0xB953, 0x916C, 0xB954, 0x916A, 0xB955, 0x9169, + 0xB956, 0x91C9, 0xB957, 0x9237, 0xB958, 0x9257, 0xB959, 0x9238, 0xB95A, 0x923D, 0xB95B, 0x9240, 0xB95C, 0x923E, 0xB95D, 0x925B, + 0xB95E, 0x924B, 0xB95F, 0x9264, 0xB960, 0x9251, 0xB961, 0x9234, 0xB962, 0x9249, 0xB963, 0x924D, 0xB964, 0x9245, 0xB965, 0x9239, + 0xB966, 0x923F, 0xB967, 0x925A, 0xB968, 0x9598, 0xB969, 0x9698, 0xB96A, 0x9694, 0xB96B, 0x9695, 0xB96C, 0x96CD, 0xB96D, 0x96CB, + 0xB96E, 0x96C9, 0xB96F, 0x96CA, 0xB970, 0x96F7, 0xB971, 0x96FB, 0xB972, 0x96F9, 0xB973, 0x96F6, 0xB974, 0x9756, 0xB975, 0x9774, + 0xB976, 0x9776, 0xB977, 0x9810, 0xB978, 0x9811, 0xB979, 0x9813, 0xB97A, 0x980A, 0xB97B, 0x9812, 0xB97C, 0x980C, 0xB97D, 0x98FC, + 0xB97E, 0x98F4, 0xB9A1, 0x98FD, 0xB9A2, 0x98FE, 0xB9A3, 0x99B3, 0xB9A4, 0x99B1, 0xB9A5, 0x99B4, 0xB9A6, 0x9AE1, 0xB9A7, 0x9CE9, + 0xB9A8, 0x9E82, 0xB9A9, 0x9F0E, 0xB9AA, 0x9F13, 0xB9AB, 0x9F20, 0xB9AC, 0x50E7, 0xB9AD, 0x50EE, 0xB9AE, 0x50E5, 0xB9AF, 0x50D6, + 0xB9B0, 0x50ED, 0xB9B1, 0x50DA, 0xB9B2, 0x50D5, 0xB9B3, 0x50CF, 0xB9B4, 0x50D1, 0xB9B5, 0x50F1, 0xB9B6, 0x50CE, 0xB9B7, 0x50E9, + 0xB9B8, 0x5162, 0xB9B9, 0x51F3, 0xB9BA, 0x5283, 0xB9BB, 0x5282, 0xB9BC, 0x5331, 0xB9BD, 0x53AD, 0xB9BE, 0x55FE, 0xB9BF, 0x5600, + 0xB9C0, 0x561B, 0xB9C1, 0x5617, 0xB9C2, 0x55FD, 0xB9C3, 0x5614, 0xB9C4, 0x5606, 0xB9C5, 0x5609, 0xB9C6, 0x560D, 0xB9C7, 0x560E, + 0xB9C8, 0x55F7, 0xB9C9, 0x5616, 0xB9CA, 0x561F, 0xB9CB, 0x5608, 0xB9CC, 0x5610, 0xB9CD, 0x55F6, 0xB9CE, 0x5718, 0xB9CF, 0x5716, + 0xB9D0, 0x5875, 0xB9D1, 0x587E, 0xB9D2, 0x5883, 0xB9D3, 0x5893, 0xB9D4, 0x588A, 0xB9D5, 0x5879, 0xB9D6, 0x5885, 0xB9D7, 0x587D, + 0xB9D8, 0x58FD, 0xB9D9, 0x5925, 0xB9DA, 0x5922, 0xB9DB, 0x5924, 0xB9DC, 0x596A, 0xB9DD, 0x5969, 0xB9DE, 0x5AE1, 0xB9DF, 0x5AE6, + 0xB9E0, 0x5AE9, 0xB9E1, 0x5AD7, 0xB9E2, 0x5AD6, 0xB9E3, 0x5AD8, 0xB9E4, 0x5AE3, 0xB9E5, 0x5B75, 0xB9E6, 0x5BDE, 0xB9E7, 0x5BE7, + 0xB9E8, 0x5BE1, 0xB9E9, 0x5BE5, 0xB9EA, 0x5BE6, 0xB9EB, 0x5BE8, 0xB9EC, 0x5BE2, 0xB9ED, 0x5BE4, 0xB9EE, 0x5BDF, 0xB9EF, 0x5C0D, + 0xB9F0, 0x5C62, 0xB9F1, 0x5D84, 0xB9F2, 0x5D87, 0xB9F3, 0x5E5B, 0xB9F4, 0x5E63, 0xB9F5, 0x5E55, 0xB9F6, 0x5E57, 0xB9F7, 0x5E54, + 0xB9F8, 0x5ED3, 0xB9F9, 0x5ED6, 0xB9FA, 0x5F0A, 0xB9FB, 0x5F46, 0xB9FC, 0x5F70, 0xB9FD, 0x5FB9, 0xB9FE, 0x6147, 0xBA40, 0x613F, + 0xBA41, 0x614B, 0xBA42, 0x6177, 0xBA43, 0x6162, 0xBA44, 0x6163, 0xBA45, 0x615F, 0xBA46, 0x615A, 0xBA47, 0x6158, 0xBA48, 0x6175, + 0xBA49, 0x622A, 0xBA4A, 0x6487, 0xBA4B, 0x6458, 0xBA4C, 0x6454, 0xBA4D, 0x64A4, 0xBA4E, 0x6478, 0xBA4F, 0x645F, 0xBA50, 0x647A, + 0xBA51, 0x6451, 0xBA52, 0x6467, 0xBA53, 0x6434, 0xBA54, 0x646D, 0xBA55, 0x647B, 0xBA56, 0x6572, 0xBA57, 0x65A1, 0xBA58, 0x65D7, + 0xBA59, 0x65D6, 0xBA5A, 0x66A2, 0xBA5B, 0x66A8, 0xBA5C, 0x669D, 0xBA5D, 0x699C, 0xBA5E, 0x69A8, 0xBA5F, 0x6995, 0xBA60, 0x69C1, + 0xBA61, 0x69AE, 0xBA62, 0x69D3, 0xBA63, 0x69CB, 0xBA64, 0x699B, 0xBA65, 0x69B7, 0xBA66, 0x69BB, 0xBA67, 0x69AB, 0xBA68, 0x69B4, + 0xBA69, 0x69D0, 0xBA6A, 0x69CD, 0xBA6B, 0x69AD, 0xBA6C, 0x69CC, 0xBA6D, 0x69A6, 0xBA6E, 0x69C3, 0xBA6F, 0x69A3, 0xBA70, 0x6B49, + 0xBA71, 0x6B4C, 0xBA72, 0x6C33, 0xBA73, 0x6F33, 0xBA74, 0x6F14, 0xBA75, 0x6EFE, 0xBA76, 0x6F13, 0xBA77, 0x6EF4, 0xBA78, 0x6F29, + 0xBA79, 0x6F3E, 0xBA7A, 0x6F20, 0xBA7B, 0x6F2C, 0xBA7C, 0x6F0F, 0xBA7D, 0x6F02, 0xBA7E, 0x6F22, 0xBAA1, 0x6EFF, 0xBAA2, 0x6EEF, + 0xBAA3, 0x6F06, 0xBAA4, 0x6F31, 0xBAA5, 0x6F38, 0xBAA6, 0x6F32, 0xBAA7, 0x6F23, 0xBAA8, 0x6F15, 0xBAA9, 0x6F2B, 0xBAAA, 0x6F2F, + 0xBAAB, 0x6F88, 0xBAAC, 0x6F2A, 0xBAAD, 0x6EEC, 0xBAAE, 0x6F01, 0xBAAF, 0x6EF2, 0xBAB0, 0x6ECC, 0xBAB1, 0x6EF7, 0xBAB2, 0x7194, + 0xBAB3, 0x7199, 0xBAB4, 0x717D, 0xBAB5, 0x718A, 0xBAB6, 0x7184, 0xBAB7, 0x7192, 0xBAB8, 0x723E, 0xBAB9, 0x7292, 0xBABA, 0x7296, + 0xBABB, 0x7344, 0xBABC, 0x7350, 0xBABD, 0x7464, 0xBABE, 0x7463, 0xBABF, 0x746A, 0xBAC0, 0x7470, 0xBAC1, 0x746D, 0xBAC2, 0x7504, + 0xBAC3, 0x7591, 0xBAC4, 0x7627, 0xBAC5, 0x760D, 0xBAC6, 0x760B, 0xBAC7, 0x7609, 0xBAC8, 0x7613, 0xBAC9, 0x76E1, 0xBACA, 0x76E3, + 0xBACB, 0x7784, 0xBACC, 0x777D, 0xBACD, 0x777F, 0xBACE, 0x7761, 0xBACF, 0x78C1, 0xBAD0, 0x789F, 0xBAD1, 0x78A7, 0xBAD2, 0x78B3, + 0xBAD3, 0x78A9, 0xBAD4, 0x78A3, 0xBAD5, 0x798E, 0xBAD6, 0x798F, 0xBAD7, 0x798D, 0xBAD8, 0x7A2E, 0xBAD9, 0x7A31, 0xBADA, 0x7AAA, + 0xBADB, 0x7AA9, 0xBADC, 0x7AED, 0xBADD, 0x7AEF, 0xBADE, 0x7BA1, 0xBADF, 0x7B95, 0xBAE0, 0x7B8B, 0xBAE1, 0x7B75, 0xBAE2, 0x7B97, + 0xBAE3, 0x7B9D, 0xBAE4, 0x7B94, 0xBAE5, 0x7B8F, 0xBAE6, 0x7BB8, 0xBAE7, 0x7B87, 0xBAE8, 0x7B84, 0xBAE9, 0x7CB9, 0xBAEA, 0x7CBD, + 0xBAEB, 0x7CBE, 0xBAEC, 0x7DBB, 0xBAED, 0x7DB0, 0xBAEE, 0x7D9C, 0xBAEF, 0x7DBD, 0xBAF0, 0x7DBE, 0xBAF1, 0x7DA0, 0xBAF2, 0x7DCA, + 0xBAF3, 0x7DB4, 0xBAF4, 0x7DB2, 0xBAF5, 0x7DB1, 0xBAF6, 0x7DBA, 0xBAF7, 0x7DA2, 0xBAF8, 0x7DBF, 0xBAF9, 0x7DB5, 0xBAFA, 0x7DB8, + 0xBAFB, 0x7DAD, 0xBAFC, 0x7DD2, 0xBAFD, 0x7DC7, 0xBAFE, 0x7DAC, 0xBB40, 0x7F70, 0xBB41, 0x7FE0, 0xBB42, 0x7FE1, 0xBB43, 0x7FDF, + 0xBB44, 0x805E, 0xBB45, 0x805A, 0xBB46, 0x8087, 0xBB47, 0x8150, 0xBB48, 0x8180, 0xBB49, 0x818F, 0xBB4A, 0x8188, 0xBB4B, 0x818A, + 0xBB4C, 0x817F, 0xBB4D, 0x8182, 0xBB4E, 0x81E7, 0xBB4F, 0x81FA, 0xBB50, 0x8207, 0xBB51, 0x8214, 0xBB52, 0x821E, 0xBB53, 0x824B, + 0xBB54, 0x84C9, 0xBB55, 0x84BF, 0xBB56, 0x84C6, 0xBB57, 0x84C4, 0xBB58, 0x8499, 0xBB59, 0x849E, 0xBB5A, 0x84B2, 0xBB5B, 0x849C, + 0xBB5C, 0x84CB, 0xBB5D, 0x84B8, 0xBB5E, 0x84C0, 0xBB5F, 0x84D3, 0xBB60, 0x8490, 0xBB61, 0x84BC, 0xBB62, 0x84D1, 0xBB63, 0x84CA, + 0xBB64, 0x873F, 0xBB65, 0x871C, 0xBB66, 0x873B, 0xBB67, 0x8722, 0xBB68, 0x8725, 0xBB69, 0x8734, 0xBB6A, 0x8718, 0xBB6B, 0x8755, + 0xBB6C, 0x8737, 0xBB6D, 0x8729, 0xBB6E, 0x88F3, 0xBB6F, 0x8902, 0xBB70, 0x88F4, 0xBB71, 0x88F9, 0xBB72, 0x88F8, 0xBB73, 0x88FD, + 0xBB74, 0x88E8, 0xBB75, 0x891A, 0xBB76, 0x88EF, 0xBB77, 0x8AA6, 0xBB78, 0x8A8C, 0xBB79, 0x8A9E, 0xBB7A, 0x8AA3, 0xBB7B, 0x8A8D, + 0xBB7C, 0x8AA1, 0xBB7D, 0x8A93, 0xBB7E, 0x8AA4, 0xBBA1, 0x8AAA, 0xBBA2, 0x8AA5, 0xBBA3, 0x8AA8, 0xBBA4, 0x8A98, 0xBBA5, 0x8A91, + 0xBBA6, 0x8A9A, 0xBBA7, 0x8AA7, 0xBBA8, 0x8C6A, 0xBBA9, 0x8C8D, 0xBBAA, 0x8C8C, 0xBBAB, 0x8CD3, 0xBBAC, 0x8CD1, 0xBBAD, 0x8CD2, + 0xBBAE, 0x8D6B, 0xBBAF, 0x8D99, 0xBBB0, 0x8D95, 0xBBB1, 0x8DFC, 0xBBB2, 0x8F14, 0xBBB3, 0x8F12, 0xBBB4, 0x8F15, 0xBBB5, 0x8F13, + 0xBBB6, 0x8FA3, 0xBBB7, 0x9060, 0xBBB8, 0x9058, 0xBBB9, 0x905C, 0xBBBA, 0x9063, 0xBBBB, 0x9059, 0xBBBC, 0x905E, 0xBBBD, 0x9062, + 0xBBBE, 0x905D, 0xBBBF, 0x905B, 0xBBC0, 0x9119, 0xBBC1, 0x9118, 0xBBC2, 0x911E, 0xBBC3, 0x9175, 0xBBC4, 0x9178, 0xBBC5, 0x9177, + 0xBBC6, 0x9174, 0xBBC7, 0x9278, 0xBBC8, 0x9280, 0xBBC9, 0x9285, 0xBBCA, 0x9298, 0xBBCB, 0x9296, 0xBBCC, 0x927B, 0xBBCD, 0x9293, + 0xBBCE, 0x929C, 0xBBCF, 0x92A8, 0xBBD0, 0x927C, 0xBBD1, 0x9291, 0xBBD2, 0x95A1, 0xBBD3, 0x95A8, 0xBBD4, 0x95A9, 0xBBD5, 0x95A3, + 0xBBD6, 0x95A5, 0xBBD7, 0x95A4, 0xBBD8, 0x9699, 0xBBD9, 0x969C, 0xBBDA, 0x969B, 0xBBDB, 0x96CC, 0xBBDC, 0x96D2, 0xBBDD, 0x9700, + 0xBBDE, 0x977C, 0xBBDF, 0x9785, 0xBBE0, 0x97F6, 0xBBE1, 0x9817, 0xBBE2, 0x9818, 0xBBE3, 0x98AF, 0xBBE4, 0x98B1, 0xBBE5, 0x9903, + 0xBBE6, 0x9905, 0xBBE7, 0x990C, 0xBBE8, 0x9909, 0xBBE9, 0x99C1, 0xBBEA, 0x9AAF, 0xBBEB, 0x9AB0, 0xBBEC, 0x9AE6, 0xBBED, 0x9B41, + 0xBBEE, 0x9B42, 0xBBEF, 0x9CF4, 0xBBF0, 0x9CF6, 0xBBF1, 0x9CF3, 0xBBF2, 0x9EBC, 0xBBF3, 0x9F3B, 0xBBF4, 0x9F4A, 0xBBF5, 0x5104, + 0xBBF6, 0x5100, 0xBBF7, 0x50FB, 0xBBF8, 0x50F5, 0xBBF9, 0x50F9, 0xBBFA, 0x5102, 0xBBFB, 0x5108, 0xBBFC, 0x5109, 0xBBFD, 0x5105, + 0xBBFE, 0x51DC, 0xBC40, 0x5287, 0xBC41, 0x5288, 0xBC42, 0x5289, 0xBC43, 0x528D, 0xBC44, 0x528A, 0xBC45, 0x52F0, 0xBC46, 0x53B2, + 0xBC47, 0x562E, 0xBC48, 0x563B, 0xBC49, 0x5639, 0xBC4A, 0x5632, 0xBC4B, 0x563F, 0xBC4C, 0x5634, 0xBC4D, 0x5629, 0xBC4E, 0x5653, + 0xBC4F, 0x564E, 0xBC50, 0x5657, 0xBC51, 0x5674, 0xBC52, 0x5636, 0xBC53, 0x562F, 0xBC54, 0x5630, 0xBC55, 0x5880, 0xBC56, 0x589F, + 0xBC57, 0x589E, 0xBC58, 0x58B3, 0xBC59, 0x589C, 0xBC5A, 0x58AE, 0xBC5B, 0x58A9, 0xBC5C, 0x58A6, 0xBC5D, 0x596D, 0xBC5E, 0x5B09, + 0xBC5F, 0x5AFB, 0xBC60, 0x5B0B, 0xBC61, 0x5AF5, 0xBC62, 0x5B0C, 0xBC63, 0x5B08, 0xBC64, 0x5BEE, 0xBC65, 0x5BEC, 0xBC66, 0x5BE9, + 0xBC67, 0x5BEB, 0xBC68, 0x5C64, 0xBC69, 0x5C65, 0xBC6A, 0x5D9D, 0xBC6B, 0x5D94, 0xBC6C, 0x5E62, 0xBC6D, 0x5E5F, 0xBC6E, 0x5E61, + 0xBC6F, 0x5EE2, 0xBC70, 0x5EDA, 0xBC71, 0x5EDF, 0xBC72, 0x5EDD, 0xBC73, 0x5EE3, 0xBC74, 0x5EE0, 0xBC75, 0x5F48, 0xBC76, 0x5F71, + 0xBC77, 0x5FB7, 0xBC78, 0x5FB5, 0xBC79, 0x6176, 0xBC7A, 0x6167, 0xBC7B, 0x616E, 0xBC7C, 0x615D, 0xBC7D, 0x6155, 0xBC7E, 0x6182, + 0xBCA1, 0x617C, 0xBCA2, 0x6170, 0xBCA3, 0x616B, 0xBCA4, 0x617E, 0xBCA5, 0x61A7, 0xBCA6, 0x6190, 0xBCA7, 0x61AB, 0xBCA8, 0x618E, + 0xBCA9, 0x61AC, 0xBCAA, 0x619A, 0xBCAB, 0x61A4, 0xBCAC, 0x6194, 0xBCAD, 0x61AE, 0xBCAE, 0x622E, 0xBCAF, 0x6469, 0xBCB0, 0x646F, + 0xBCB1, 0x6479, 0xBCB2, 0x649E, 0xBCB3, 0x64B2, 0xBCB4, 0x6488, 0xBCB5, 0x6490, 0xBCB6, 0x64B0, 0xBCB7, 0x64A5, 0xBCB8, 0x6493, + 0xBCB9, 0x6495, 0xBCBA, 0x64A9, 0xBCBB, 0x6492, 0xBCBC, 0x64AE, 0xBCBD, 0x64AD, 0xBCBE, 0x64AB, 0xBCBF, 0x649A, 0xBCC0, 0x64AC, + 0xBCC1, 0x6499, 0xBCC2, 0x64A2, 0xBCC3, 0x64B3, 0xBCC4, 0x6575, 0xBCC5, 0x6577, 0xBCC6, 0x6578, 0xBCC7, 0x66AE, 0xBCC8, 0x66AB, + 0xBCC9, 0x66B4, 0xBCCA, 0x66B1, 0xBCCB, 0x6A23, 0xBCCC, 0x6A1F, 0xBCCD, 0x69E8, 0xBCCE, 0x6A01, 0xBCCF, 0x6A1E, 0xBCD0, 0x6A19, + 0xBCD1, 0x69FD, 0xBCD2, 0x6A21, 0xBCD3, 0x6A13, 0xBCD4, 0x6A0A, 0xBCD5, 0x69F3, 0xBCD6, 0x6A02, 0xBCD7, 0x6A05, 0xBCD8, 0x69ED, + 0xBCD9, 0x6A11, 0xBCDA, 0x6B50, 0xBCDB, 0x6B4E, 0xBCDC, 0x6BA4, 0xBCDD, 0x6BC5, 0xBCDE, 0x6BC6, 0xBCDF, 0x6F3F, 0xBCE0, 0x6F7C, + 0xBCE1, 0x6F84, 0xBCE2, 0x6F51, 0xBCE3, 0x6F66, 0xBCE4, 0x6F54, 0xBCE5, 0x6F86, 0xBCE6, 0x6F6D, 0xBCE7, 0x6F5B, 0xBCE8, 0x6F78, + 0xBCE9, 0x6F6E, 0xBCEA, 0x6F8E, 0xBCEB, 0x6F7A, 0xBCEC, 0x6F70, 0xBCED, 0x6F64, 0xBCEE, 0x6F97, 0xBCEF, 0x6F58, 0xBCF0, 0x6ED5, + 0xBCF1, 0x6F6F, 0xBCF2, 0x6F60, 0xBCF3, 0x6F5F, 0xBCF4, 0x719F, 0xBCF5, 0x71AC, 0xBCF6, 0x71B1, 0xBCF7, 0x71A8, 0xBCF8, 0x7256, + 0xBCF9, 0x729B, 0xBCFA, 0x734E, 0xBCFB, 0x7357, 0xBCFC, 0x7469, 0xBCFD, 0x748B, 0xBCFE, 0x7483, 0xBD40, 0x747E, 0xBD41, 0x7480, + 0xBD42, 0x757F, 0xBD43, 0x7620, 0xBD44, 0x7629, 0xBD45, 0x761F, 0xBD46, 0x7624, 0xBD47, 0x7626, 0xBD48, 0x7621, 0xBD49, 0x7622, + 0xBD4A, 0x769A, 0xBD4B, 0x76BA, 0xBD4C, 0x76E4, 0xBD4D, 0x778E, 0xBD4E, 0x7787, 0xBD4F, 0x778C, 0xBD50, 0x7791, 0xBD51, 0x778B, + 0xBD52, 0x78CB, 0xBD53, 0x78C5, 0xBD54, 0x78BA, 0xBD55, 0x78CA, 0xBD56, 0x78BE, 0xBD57, 0x78D5, 0xBD58, 0x78BC, 0xBD59, 0x78D0, + 0xBD5A, 0x7A3F, 0xBD5B, 0x7A3C, 0xBD5C, 0x7A40, 0xBD5D, 0x7A3D, 0xBD5E, 0x7A37, 0xBD5F, 0x7A3B, 0xBD60, 0x7AAF, 0xBD61, 0x7AAE, + 0xBD62, 0x7BAD, 0xBD63, 0x7BB1, 0xBD64, 0x7BC4, 0xBD65, 0x7BB4, 0xBD66, 0x7BC6, 0xBD67, 0x7BC7, 0xBD68, 0x7BC1, 0xBD69, 0x7BA0, + 0xBD6A, 0x7BCC, 0xBD6B, 0x7CCA, 0xBD6C, 0x7DE0, 0xBD6D, 0x7DF4, 0xBD6E, 0x7DEF, 0xBD6F, 0x7DFB, 0xBD70, 0x7DD8, 0xBD71, 0x7DEC, + 0xBD72, 0x7DDD, 0xBD73, 0x7DE8, 0xBD74, 0x7DE3, 0xBD75, 0x7DDA, 0xBD76, 0x7DDE, 0xBD77, 0x7DE9, 0xBD78, 0x7D9E, 0xBD79, 0x7DD9, + 0xBD7A, 0x7DF2, 0xBD7B, 0x7DF9, 0xBD7C, 0x7F75, 0xBD7D, 0x7F77, 0xBD7E, 0x7FAF, 0xBDA1, 0x7FE9, 0xBDA2, 0x8026, 0xBDA3, 0x819B, + 0xBDA4, 0x819C, 0xBDA5, 0x819D, 0xBDA6, 0x81A0, 0xBDA7, 0x819A, 0xBDA8, 0x8198, 0xBDA9, 0x8517, 0xBDAA, 0x853D, 0xBDAB, 0x851A, + 0xBDAC, 0x84EE, 0xBDAD, 0x852C, 0xBDAE, 0x852D, 0xBDAF, 0x8513, 0xBDB0, 0x8511, 0xBDB1, 0x8523, 0xBDB2, 0x8521, 0xBDB3, 0x8514, + 0xBDB4, 0x84EC, 0xBDB5, 0x8525, 0xBDB6, 0x84FF, 0xBDB7, 0x8506, 0xBDB8, 0x8782, 0xBDB9, 0x8774, 0xBDBA, 0x8776, 0xBDBB, 0x8760, + 0xBDBC, 0x8766, 0xBDBD, 0x8778, 0xBDBE, 0x8768, 0xBDBF, 0x8759, 0xBDC0, 0x8757, 0xBDC1, 0x874C, 0xBDC2, 0x8753, 0xBDC3, 0x885B, + 0xBDC4, 0x885D, 0xBDC5, 0x8910, 0xBDC6, 0x8907, 0xBDC7, 0x8912, 0xBDC8, 0x8913, 0xBDC9, 0x8915, 0xBDCA, 0x890A, 0xBDCB, 0x8ABC, + 0xBDCC, 0x8AD2, 0xBDCD, 0x8AC7, 0xBDCE, 0x8AC4, 0xBDCF, 0x8A95, 0xBDD0, 0x8ACB, 0xBDD1, 0x8AF8, 0xBDD2, 0x8AB2, 0xBDD3, 0x8AC9, + 0xBDD4, 0x8AC2, 0xBDD5, 0x8ABF, 0xBDD6, 0x8AB0, 0xBDD7, 0x8AD6, 0xBDD8, 0x8ACD, 0xBDD9, 0x8AB6, 0xBDDA, 0x8AB9, 0xBDDB, 0x8ADB, + 0xBDDC, 0x8C4C, 0xBDDD, 0x8C4E, 0xBDDE, 0x8C6C, 0xBDDF, 0x8CE0, 0xBDE0, 0x8CDE, 0xBDE1, 0x8CE6, 0xBDE2, 0x8CE4, 0xBDE3, 0x8CEC, + 0xBDE4, 0x8CED, 0xBDE5, 0x8CE2, 0xBDE6, 0x8CE3, 0xBDE7, 0x8CDC, 0xBDE8, 0x8CEA, 0xBDE9, 0x8CE1, 0xBDEA, 0x8D6D, 0xBDEB, 0x8D9F, + 0xBDEC, 0x8DA3, 0xBDED, 0x8E2B, 0xBDEE, 0x8E10, 0xBDEF, 0x8E1D, 0xBDF0, 0x8E22, 0xBDF1, 0x8E0F, 0xBDF2, 0x8E29, 0xBDF3, 0x8E1F, + 0xBDF4, 0x8E21, 0xBDF5, 0x8E1E, 0xBDF6, 0x8EBA, 0xBDF7, 0x8F1D, 0xBDF8, 0x8F1B, 0xBDF9, 0x8F1F, 0xBDFA, 0x8F29, 0xBDFB, 0x8F26, + 0xBDFC, 0x8F2A, 0xBDFD, 0x8F1C, 0xBDFE, 0x8F1E, 0xBE40, 0x8F25, 0xBE41, 0x9069, 0xBE42, 0x906E, 0xBE43, 0x9068, 0xBE44, 0x906D, + 0xBE45, 0x9077, 0xBE46, 0x9130, 0xBE47, 0x912D, 0xBE48, 0x9127, 0xBE49, 0x9131, 0xBE4A, 0x9187, 0xBE4B, 0x9189, 0xBE4C, 0x918B, + 0xBE4D, 0x9183, 0xBE4E, 0x92C5, 0xBE4F, 0x92BB, 0xBE50, 0x92B7, 0xBE51, 0x92EA, 0xBE52, 0x92AC, 0xBE53, 0x92E4, 0xBE54, 0x92C1, + 0xBE55, 0x92B3, 0xBE56, 0x92BC, 0xBE57, 0x92D2, 0xBE58, 0x92C7, 0xBE59, 0x92F0, 0xBE5A, 0x92B2, 0xBE5B, 0x95AD, 0xBE5C, 0x95B1, + 0xBE5D, 0x9704, 0xBE5E, 0x9706, 0xBE5F, 0x9707, 0xBE60, 0x9709, 0xBE61, 0x9760, 0xBE62, 0x978D, 0xBE63, 0x978B, 0xBE64, 0x978F, + 0xBE65, 0x9821, 0xBE66, 0x982B, 0xBE67, 0x981C, 0xBE68, 0x98B3, 0xBE69, 0x990A, 0xBE6A, 0x9913, 0xBE6B, 0x9912, 0xBE6C, 0x9918, + 0xBE6D, 0x99DD, 0xBE6E, 0x99D0, 0xBE6F, 0x99DF, 0xBE70, 0x99DB, 0xBE71, 0x99D1, 0xBE72, 0x99D5, 0xBE73, 0x99D2, 0xBE74, 0x99D9, + 0xBE75, 0x9AB7, 0xBE76, 0x9AEE, 0xBE77, 0x9AEF, 0xBE78, 0x9B27, 0xBE79, 0x9B45, 0xBE7A, 0x9B44, 0xBE7B, 0x9B77, 0xBE7C, 0x9B6F, + 0xBE7D, 0x9D06, 0xBE7E, 0x9D09, 0xBEA1, 0x9D03, 0xBEA2, 0x9EA9, 0xBEA3, 0x9EBE, 0xBEA4, 0x9ECE, 0xBEA5, 0x58A8, 0xBEA6, 0x9F52, + 0xBEA7, 0x5112, 0xBEA8, 0x5118, 0xBEA9, 0x5114, 0xBEAA, 0x5110, 0xBEAB, 0x5115, 0xBEAC, 0x5180, 0xBEAD, 0x51AA, 0xBEAE, 0x51DD, + 0xBEAF, 0x5291, 0xBEB0, 0x5293, 0xBEB1, 0x52F3, 0xBEB2, 0x5659, 0xBEB3, 0x566B, 0xBEB4, 0x5679, 0xBEB5, 0x5669, 0xBEB6, 0x5664, + 0xBEB7, 0x5678, 0xBEB8, 0x566A, 0xBEB9, 0x5668, 0xBEBA, 0x5665, 0xBEBB, 0x5671, 0xBEBC, 0x566F, 0xBEBD, 0x566C, 0xBEBE, 0x5662, + 0xBEBF, 0x5676, 0xBEC0, 0x58C1, 0xBEC1, 0x58BE, 0xBEC2, 0x58C7, 0xBEC3, 0x58C5, 0xBEC4, 0x596E, 0xBEC5, 0x5B1D, 0xBEC6, 0x5B34, + 0xBEC7, 0x5B78, 0xBEC8, 0x5BF0, 0xBEC9, 0x5C0E, 0xBECA, 0x5F4A, 0xBECB, 0x61B2, 0xBECC, 0x6191, 0xBECD, 0x61A9, 0xBECE, 0x618A, + 0xBECF, 0x61CD, 0xBED0, 0x61B6, 0xBED1, 0x61BE, 0xBED2, 0x61CA, 0xBED3, 0x61C8, 0xBED4, 0x6230, 0xBED5, 0x64C5, 0xBED6, 0x64C1, + 0xBED7, 0x64CB, 0xBED8, 0x64BB, 0xBED9, 0x64BC, 0xBEDA, 0x64DA, 0xBEDB, 0x64C4, 0xBEDC, 0x64C7, 0xBEDD, 0x64C2, 0xBEDE, 0x64CD, + 0xBEDF, 0x64BF, 0xBEE0, 0x64D2, 0xBEE1, 0x64D4, 0xBEE2, 0x64BE, 0xBEE3, 0x6574, 0xBEE4, 0x66C6, 0xBEE5, 0x66C9, 0xBEE6, 0x66B9, + 0xBEE7, 0x66C4, 0xBEE8, 0x66C7, 0xBEE9, 0x66B8, 0xBEEA, 0x6A3D, 0xBEEB, 0x6A38, 0xBEEC, 0x6A3A, 0xBEED, 0x6A59, 0xBEEE, 0x6A6B, + 0xBEEF, 0x6A58, 0xBEF0, 0x6A39, 0xBEF1, 0x6A44, 0xBEF2, 0x6A62, 0xBEF3, 0x6A61, 0xBEF4, 0x6A4B, 0xBEF5, 0x6A47, 0xBEF6, 0x6A35, + 0xBEF7, 0x6A5F, 0xBEF8, 0x6A48, 0xBEF9, 0x6B59, 0xBEFA, 0x6B77, 0xBEFB, 0x6C05, 0xBEFC, 0x6FC2, 0xBEFD, 0x6FB1, 0xBEFE, 0x6FA1, + 0xBF40, 0x6FC3, 0xBF41, 0x6FA4, 0xBF42, 0x6FC1, 0xBF43, 0x6FA7, 0xBF44, 0x6FB3, 0xBF45, 0x6FC0, 0xBF46, 0x6FB9, 0xBF47, 0x6FB6, + 0xBF48, 0x6FA6, 0xBF49, 0x6FA0, 0xBF4A, 0x6FB4, 0xBF4B, 0x71BE, 0xBF4C, 0x71C9, 0xBF4D, 0x71D0, 0xBF4E, 0x71D2, 0xBF4F, 0x71C8, + 0xBF50, 0x71D5, 0xBF51, 0x71B9, 0xBF52, 0x71CE, 0xBF53, 0x71D9, 0xBF54, 0x71DC, 0xBF55, 0x71C3, 0xBF56, 0x71C4, 0xBF57, 0x7368, + 0xBF58, 0x749C, 0xBF59, 0x74A3, 0xBF5A, 0x7498, 0xBF5B, 0x749F, 0xBF5C, 0x749E, 0xBF5D, 0x74E2, 0xBF5E, 0x750C, 0xBF5F, 0x750D, + 0xBF60, 0x7634, 0xBF61, 0x7638, 0xBF62, 0x763A, 0xBF63, 0x76E7, 0xBF64, 0x76E5, 0xBF65, 0x77A0, 0xBF66, 0x779E, 0xBF67, 0x779F, + 0xBF68, 0x77A5, 0xBF69, 0x78E8, 0xBF6A, 0x78DA, 0xBF6B, 0x78EC, 0xBF6C, 0x78E7, 0xBF6D, 0x79A6, 0xBF6E, 0x7A4D, 0xBF6F, 0x7A4E, + 0xBF70, 0x7A46, 0xBF71, 0x7A4C, 0xBF72, 0x7A4B, 0xBF73, 0x7ABA, 0xBF74, 0x7BD9, 0xBF75, 0x7C11, 0xBF76, 0x7BC9, 0xBF77, 0x7BE4, + 0xBF78, 0x7BDB, 0xBF79, 0x7BE1, 0xBF7A, 0x7BE9, 0xBF7B, 0x7BE6, 0xBF7C, 0x7CD5, 0xBF7D, 0x7CD6, 0xBF7E, 0x7E0A, 0xBFA1, 0x7E11, + 0xBFA2, 0x7E08, 0xBFA3, 0x7E1B, 0xBFA4, 0x7E23, 0xBFA5, 0x7E1E, 0xBFA6, 0x7E1D, 0xBFA7, 0x7E09, 0xBFA8, 0x7E10, 0xBFA9, 0x7F79, + 0xBFAA, 0x7FB2, 0xBFAB, 0x7FF0, 0xBFAC, 0x7FF1, 0xBFAD, 0x7FEE, 0xBFAE, 0x8028, 0xBFAF, 0x81B3, 0xBFB0, 0x81A9, 0xBFB1, 0x81A8, + 0xBFB2, 0x81FB, 0xBFB3, 0x8208, 0xBFB4, 0x8258, 0xBFB5, 0x8259, 0xBFB6, 0x854A, 0xBFB7, 0x8559, 0xBFB8, 0x8548, 0xBFB9, 0x8568, + 0xBFBA, 0x8569, 0xBFBB, 0x8543, 0xBFBC, 0x8549, 0xBFBD, 0x856D, 0xBFBE, 0x856A, 0xBFBF, 0x855E, 0xBFC0, 0x8783, 0xBFC1, 0x879F, + 0xBFC2, 0x879E, 0xBFC3, 0x87A2, 0xBFC4, 0x878D, 0xBFC5, 0x8861, 0xBFC6, 0x892A, 0xBFC7, 0x8932, 0xBFC8, 0x8925, 0xBFC9, 0x892B, + 0xBFCA, 0x8921, 0xBFCB, 0x89AA, 0xBFCC, 0x89A6, 0xBFCD, 0x8AE6, 0xBFCE, 0x8AFA, 0xBFCF, 0x8AEB, 0xBFD0, 0x8AF1, 0xBFD1, 0x8B00, + 0xBFD2, 0x8ADC, 0xBFD3, 0x8AE7, 0xBFD4, 0x8AEE, 0xBFD5, 0x8AFE, 0xBFD6, 0x8B01, 0xBFD7, 0x8B02, 0xBFD8, 0x8AF7, 0xBFD9, 0x8AED, + 0xBFDA, 0x8AF3, 0xBFDB, 0x8AF6, 0xBFDC, 0x8AFC, 0xBFDD, 0x8C6B, 0xBFDE, 0x8C6D, 0xBFDF, 0x8C93, 0xBFE0, 0x8CF4, 0xBFE1, 0x8E44, + 0xBFE2, 0x8E31, 0xBFE3, 0x8E34, 0xBFE4, 0x8E42, 0xBFE5, 0x8E39, 0xBFE6, 0x8E35, 0xBFE7, 0x8F3B, 0xBFE8, 0x8F2F, 0xBFE9, 0x8F38, + 0xBFEA, 0x8F33, 0xBFEB, 0x8FA8, 0xBFEC, 0x8FA6, 0xBFED, 0x9075, 0xBFEE, 0x9074, 0xBFEF, 0x9078, 0xBFF0, 0x9072, 0xBFF1, 0x907C, + 0xBFF2, 0x907A, 0xBFF3, 0x9134, 0xBFF4, 0x9192, 0xBFF5, 0x9320, 0xBFF6, 0x9336, 0xBFF7, 0x92F8, 0xBFF8, 0x9333, 0xBFF9, 0x932F, + 0xBFFA, 0x9322, 0xBFFB, 0x92FC, 0xBFFC, 0x932B, 0xBFFD, 0x9304, 0xBFFE, 0x931A, 0xC040, 0x9310, 0xC041, 0x9326, 0xC042, 0x9321, + 0xC043, 0x9315, 0xC044, 0x932E, 0xC045, 0x9319, 0xC046, 0x95BB, 0xC047, 0x96A7, 0xC048, 0x96A8, 0xC049, 0x96AA, 0xC04A, 0x96D5, + 0xC04B, 0x970E, 0xC04C, 0x9711, 0xC04D, 0x9716, 0xC04E, 0x970D, 0xC04F, 0x9713, 0xC050, 0x970F, 0xC051, 0x975B, 0xC052, 0x975C, + 0xC053, 0x9766, 0xC054, 0x9798, 0xC055, 0x9830, 0xC056, 0x9838, 0xC057, 0x983B, 0xC058, 0x9837, 0xC059, 0x982D, 0xC05A, 0x9839, + 0xC05B, 0x9824, 0xC05C, 0x9910, 0xC05D, 0x9928, 0xC05E, 0x991E, 0xC05F, 0x991B, 0xC060, 0x9921, 0xC061, 0x991A, 0xC062, 0x99ED, + 0xC063, 0x99E2, 0xC064, 0x99F1, 0xC065, 0x9AB8, 0xC066, 0x9ABC, 0xC067, 0x9AFB, 0xC068, 0x9AED, 0xC069, 0x9B28, 0xC06A, 0x9B91, + 0xC06B, 0x9D15, 0xC06C, 0x9D23, 0xC06D, 0x9D26, 0xC06E, 0x9D28, 0xC06F, 0x9D12, 0xC070, 0x9D1B, 0xC071, 0x9ED8, 0xC072, 0x9ED4, + 0xC073, 0x9F8D, 0xC074, 0x9F9C, 0xC075, 0x512A, 0xC076, 0x511F, 0xC077, 0x5121, 0xC078, 0x5132, 0xC079, 0x52F5, 0xC07A, 0x568E, + 0xC07B, 0x5680, 0xC07C, 0x5690, 0xC07D, 0x5685, 0xC07E, 0x5687, 0xC0A1, 0x568F, 0xC0A2, 0x58D5, 0xC0A3, 0x58D3, 0xC0A4, 0x58D1, + 0xC0A5, 0x58CE, 0xC0A6, 0x5B30, 0xC0A7, 0x5B2A, 0xC0A8, 0x5B24, 0xC0A9, 0x5B7A, 0xC0AA, 0x5C37, 0xC0AB, 0x5C68, 0xC0AC, 0x5DBC, + 0xC0AD, 0x5DBA, 0xC0AE, 0x5DBD, 0xC0AF, 0x5DB8, 0xC0B0, 0x5E6B, 0xC0B1, 0x5F4C, 0xC0B2, 0x5FBD, 0xC0B3, 0x61C9, 0xC0B4, 0x61C2, + 0xC0B5, 0x61C7, 0xC0B6, 0x61E6, 0xC0B7, 0x61CB, 0xC0B8, 0x6232, 0xC0B9, 0x6234, 0xC0BA, 0x64CE, 0xC0BB, 0x64CA, 0xC0BC, 0x64D8, + 0xC0BD, 0x64E0, 0xC0BE, 0x64F0, 0xC0BF, 0x64E6, 0xC0C0, 0x64EC, 0xC0C1, 0x64F1, 0xC0C2, 0x64E2, 0xC0C3, 0x64ED, 0xC0C4, 0x6582, + 0xC0C5, 0x6583, 0xC0C6, 0x66D9, 0xC0C7, 0x66D6, 0xC0C8, 0x6A80, 0xC0C9, 0x6A94, 0xC0CA, 0x6A84, 0xC0CB, 0x6AA2, 0xC0CC, 0x6A9C, + 0xC0CD, 0x6ADB, 0xC0CE, 0x6AA3, 0xC0CF, 0x6A7E, 0xC0D0, 0x6A97, 0xC0D1, 0x6A90, 0xC0D2, 0x6AA0, 0xC0D3, 0x6B5C, 0xC0D4, 0x6BAE, + 0xC0D5, 0x6BDA, 0xC0D6, 0x6C08, 0xC0D7, 0x6FD8, 0xC0D8, 0x6FF1, 0xC0D9, 0x6FDF, 0xC0DA, 0x6FE0, 0xC0DB, 0x6FDB, 0xC0DC, 0x6FE4, + 0xC0DD, 0x6FEB, 0xC0DE, 0x6FEF, 0xC0DF, 0x6F80, 0xC0E0, 0x6FEC, 0xC0E1, 0x6FE1, 0xC0E2, 0x6FE9, 0xC0E3, 0x6FD5, 0xC0E4, 0x6FEE, + 0xC0E5, 0x6FF0, 0xC0E6, 0x71E7, 0xC0E7, 0x71DF, 0xC0E8, 0x71EE, 0xC0E9, 0x71E6, 0xC0EA, 0x71E5, 0xC0EB, 0x71ED, 0xC0EC, 0x71EC, + 0xC0ED, 0x71F4, 0xC0EE, 0x71E0, 0xC0EF, 0x7235, 0xC0F0, 0x7246, 0xC0F1, 0x7370, 0xC0F2, 0x7372, 0xC0F3, 0x74A9, 0xC0F4, 0x74B0, + 0xC0F5, 0x74A6, 0xC0F6, 0x74A8, 0xC0F7, 0x7646, 0xC0F8, 0x7642, 0xC0F9, 0x764C, 0xC0FA, 0x76EA, 0xC0FB, 0x77B3, 0xC0FC, 0x77AA, + 0xC0FD, 0x77B0, 0xC0FE, 0x77AC, 0xC140, 0x77A7, 0xC141, 0x77AD, 0xC142, 0x77EF, 0xC143, 0x78F7, 0xC144, 0x78FA, 0xC145, 0x78F4, + 0xC146, 0x78EF, 0xC147, 0x7901, 0xC148, 0x79A7, 0xC149, 0x79AA, 0xC14A, 0x7A57, 0xC14B, 0x7ABF, 0xC14C, 0x7C07, 0xC14D, 0x7C0D, + 0xC14E, 0x7BFE, 0xC14F, 0x7BF7, 0xC150, 0x7C0C, 0xC151, 0x7BE0, 0xC152, 0x7CE0, 0xC153, 0x7CDC, 0xC154, 0x7CDE, 0xC155, 0x7CE2, + 0xC156, 0x7CDF, 0xC157, 0x7CD9, 0xC158, 0x7CDD, 0xC159, 0x7E2E, 0xC15A, 0x7E3E, 0xC15B, 0x7E46, 0xC15C, 0x7E37, 0xC15D, 0x7E32, + 0xC15E, 0x7E43, 0xC15F, 0x7E2B, 0xC160, 0x7E3D, 0xC161, 0x7E31, 0xC162, 0x7E45, 0xC163, 0x7E41, 0xC164, 0x7E34, 0xC165, 0x7E39, + 0xC166, 0x7E48, 0xC167, 0x7E35, 0xC168, 0x7E3F, 0xC169, 0x7E2F, 0xC16A, 0x7F44, 0xC16B, 0x7FF3, 0xC16C, 0x7FFC, 0xC16D, 0x8071, + 0xC16E, 0x8072, 0xC16F, 0x8070, 0xC170, 0x806F, 0xC171, 0x8073, 0xC172, 0x81C6, 0xC173, 0x81C3, 0xC174, 0x81BA, 0xC175, 0x81C2, + 0xC176, 0x81C0, 0xC177, 0x81BF, 0xC178, 0x81BD, 0xC179, 0x81C9, 0xC17A, 0x81BE, 0xC17B, 0x81E8, 0xC17C, 0x8209, 0xC17D, 0x8271, + 0xC17E, 0x85AA, 0xC1A1, 0x8584, 0xC1A2, 0x857E, 0xC1A3, 0x859C, 0xC1A4, 0x8591, 0xC1A5, 0x8594, 0xC1A6, 0x85AF, 0xC1A7, 0x859B, + 0xC1A8, 0x8587, 0xC1A9, 0x85A8, 0xC1AA, 0x858A, 0xC1AB, 0x8667, 0xC1AC, 0x87C0, 0xC1AD, 0x87D1, 0xC1AE, 0x87B3, 0xC1AF, 0x87D2, + 0xC1B0, 0x87C6, 0xC1B1, 0x87AB, 0xC1B2, 0x87BB, 0xC1B3, 0x87BA, 0xC1B4, 0x87C8, 0xC1B5, 0x87CB, 0xC1B6, 0x893B, 0xC1B7, 0x8936, + 0xC1B8, 0x8944, 0xC1B9, 0x8938, 0xC1BA, 0x893D, 0xC1BB, 0x89AC, 0xC1BC, 0x8B0E, 0xC1BD, 0x8B17, 0xC1BE, 0x8B19, 0xC1BF, 0x8B1B, + 0xC1C0, 0x8B0A, 0xC1C1, 0x8B20, 0xC1C2, 0x8B1D, 0xC1C3, 0x8B04, 0xC1C4, 0x8B10, 0xC1C5, 0x8C41, 0xC1C6, 0x8C3F, 0xC1C7, 0x8C73, + 0xC1C8, 0x8CFA, 0xC1C9, 0x8CFD, 0xC1CA, 0x8CFC, 0xC1CB, 0x8CF8, 0xC1CC, 0x8CFB, 0xC1CD, 0x8DA8, 0xC1CE, 0x8E49, 0xC1CF, 0x8E4B, + 0xC1D0, 0x8E48, 0xC1D1, 0x8E4A, 0xC1D2, 0x8F44, 0xC1D3, 0x8F3E, 0xC1D4, 0x8F42, 0xC1D5, 0x8F45, 0xC1D6, 0x8F3F, 0xC1D7, 0x907F, + 0xC1D8, 0x907D, 0xC1D9, 0x9084, 0xC1DA, 0x9081, 0xC1DB, 0x9082, 0xC1DC, 0x9080, 0xC1DD, 0x9139, 0xC1DE, 0x91A3, 0xC1DF, 0x919E, + 0xC1E0, 0x919C, 0xC1E1, 0x934D, 0xC1E2, 0x9382, 0xC1E3, 0x9328, 0xC1E4, 0x9375, 0xC1E5, 0x934A, 0xC1E6, 0x9365, 0xC1E7, 0x934B, + 0xC1E8, 0x9318, 0xC1E9, 0x937E, 0xC1EA, 0x936C, 0xC1EB, 0x935B, 0xC1EC, 0x9370, 0xC1ED, 0x935A, 0xC1EE, 0x9354, 0xC1EF, 0x95CA, + 0xC1F0, 0x95CB, 0xC1F1, 0x95CC, 0xC1F2, 0x95C8, 0xC1F3, 0x95C6, 0xC1F4, 0x96B1, 0xC1F5, 0x96B8, 0xC1F6, 0x96D6, 0xC1F7, 0x971C, + 0xC1F8, 0x971E, 0xC1F9, 0x97A0, 0xC1FA, 0x97D3, 0xC1FB, 0x9846, 0xC1FC, 0x98B6, 0xC1FD, 0x9935, 0xC1FE, 0x9A01, 0xC240, 0x99FF, + 0xC241, 0x9BAE, 0xC242, 0x9BAB, 0xC243, 0x9BAA, 0xC244, 0x9BAD, 0xC245, 0x9D3B, 0xC246, 0x9D3F, 0xC247, 0x9E8B, 0xC248, 0x9ECF, + 0xC249, 0x9EDE, 0xC24A, 0x9EDC, 0xC24B, 0x9EDD, 0xC24C, 0x9EDB, 0xC24D, 0x9F3E, 0xC24E, 0x9F4B, 0xC24F, 0x53E2, 0xC250, 0x5695, + 0xC251, 0x56AE, 0xC252, 0x58D9, 0xC253, 0x58D8, 0xC254, 0x5B38, 0xC255, 0x5F5D, 0xC256, 0x61E3, 0xC257, 0x6233, 0xC258, 0x64F4, + 0xC259, 0x64F2, 0xC25A, 0x64FE, 0xC25B, 0x6506, 0xC25C, 0x64FA, 0xC25D, 0x64FB, 0xC25E, 0x64F7, 0xC25F, 0x65B7, 0xC260, 0x66DC, + 0xC261, 0x6726, 0xC262, 0x6AB3, 0xC263, 0x6AAC, 0xC264, 0x6AC3, 0xC265, 0x6ABB, 0xC266, 0x6AB8, 0xC267, 0x6AC2, 0xC268, 0x6AAE, + 0xC269, 0x6AAF, 0xC26A, 0x6B5F, 0xC26B, 0x6B78, 0xC26C, 0x6BAF, 0xC26D, 0x7009, 0xC26E, 0x700B, 0xC26F, 0x6FFE, 0xC270, 0x7006, + 0xC271, 0x6FFA, 0xC272, 0x7011, 0xC273, 0x700F, 0xC274, 0x71FB, 0xC275, 0x71FC, 0xC276, 0x71FE, 0xC277, 0x71F8, 0xC278, 0x7377, + 0xC279, 0x7375, 0xC27A, 0x74A7, 0xC27B, 0x74BF, 0xC27C, 0x7515, 0xC27D, 0x7656, 0xC27E, 0x7658, 0xC2A1, 0x7652, 0xC2A2, 0x77BD, + 0xC2A3, 0x77BF, 0xC2A4, 0x77BB, 0xC2A5, 0x77BC, 0xC2A6, 0x790E, 0xC2A7, 0x79AE, 0xC2A8, 0x7A61, 0xC2A9, 0x7A62, 0xC2AA, 0x7A60, + 0xC2AB, 0x7AC4, 0xC2AC, 0x7AC5, 0xC2AD, 0x7C2B, 0xC2AE, 0x7C27, 0xC2AF, 0x7C2A, 0xC2B0, 0x7C1E, 0xC2B1, 0x7C23, 0xC2B2, 0x7C21, + 0xC2B3, 0x7CE7, 0xC2B4, 0x7E54, 0xC2B5, 0x7E55, 0xC2B6, 0x7E5E, 0xC2B7, 0x7E5A, 0xC2B8, 0x7E61, 0xC2B9, 0x7E52, 0xC2BA, 0x7E59, + 0xC2BB, 0x7F48, 0xC2BC, 0x7FF9, 0xC2BD, 0x7FFB, 0xC2BE, 0x8077, 0xC2BF, 0x8076, 0xC2C0, 0x81CD, 0xC2C1, 0x81CF, 0xC2C2, 0x820A, + 0xC2C3, 0x85CF, 0xC2C4, 0x85A9, 0xC2C5, 0x85CD, 0xC2C6, 0x85D0, 0xC2C7, 0x85C9, 0xC2C8, 0x85B0, 0xC2C9, 0x85BA, 0xC2CA, 0x85B9, + 0xC2CB, 0x85A6, 0xC2CC, 0x87EF, 0xC2CD, 0x87EC, 0xC2CE, 0x87F2, 0xC2CF, 0x87E0, 0xC2D0, 0x8986, 0xC2D1, 0x89B2, 0xC2D2, 0x89F4, + 0xC2D3, 0x8B28, 0xC2D4, 0x8B39, 0xC2D5, 0x8B2C, 0xC2D6, 0x8B2B, 0xC2D7, 0x8C50, 0xC2D8, 0x8D05, 0xC2D9, 0x8E59, 0xC2DA, 0x8E63, + 0xC2DB, 0x8E66, 0xC2DC, 0x8E64, 0xC2DD, 0x8E5F, 0xC2DE, 0x8E55, 0xC2DF, 0x8EC0, 0xC2E0, 0x8F49, 0xC2E1, 0x8F4D, 0xC2E2, 0x9087, + 0xC2E3, 0x9083, 0xC2E4, 0x9088, 0xC2E5, 0x91AB, 0xC2E6, 0x91AC, 0xC2E7, 0x91D0, 0xC2E8, 0x9394, 0xC2E9, 0x938A, 0xC2EA, 0x9396, + 0xC2EB, 0x93A2, 0xC2EC, 0x93B3, 0xC2ED, 0x93AE, 0xC2EE, 0x93AC, 0xC2EF, 0x93B0, 0xC2F0, 0x9398, 0xC2F1, 0x939A, 0xC2F2, 0x9397, + 0xC2F3, 0x95D4, 0xC2F4, 0x95D6, 0xC2F5, 0x95D0, 0xC2F6, 0x95D5, 0xC2F7, 0x96E2, 0xC2F8, 0x96DC, 0xC2F9, 0x96D9, 0xC2FA, 0x96DB, + 0xC2FB, 0x96DE, 0xC2FC, 0x9724, 0xC2FD, 0x97A3, 0xC2FE, 0x97A6, 0xC340, 0x97AD, 0xC341, 0x97F9, 0xC342, 0x984D, 0xC343, 0x984F, + 0xC344, 0x984C, 0xC345, 0x984E, 0xC346, 0x9853, 0xC347, 0x98BA, 0xC348, 0x993E, 0xC349, 0x993F, 0xC34A, 0x993D, 0xC34B, 0x992E, + 0xC34C, 0x99A5, 0xC34D, 0x9A0E, 0xC34E, 0x9AC1, 0xC34F, 0x9B03, 0xC350, 0x9B06, 0xC351, 0x9B4F, 0xC352, 0x9B4E, 0xC353, 0x9B4D, + 0xC354, 0x9BCA, 0xC355, 0x9BC9, 0xC356, 0x9BFD, 0xC357, 0x9BC8, 0xC358, 0x9BC0, 0xC359, 0x9D51, 0xC35A, 0x9D5D, 0xC35B, 0x9D60, + 0xC35C, 0x9EE0, 0xC35D, 0x9F15, 0xC35E, 0x9F2C, 0xC35F, 0x5133, 0xC360, 0x56A5, 0xC361, 0x58DE, 0xC362, 0x58DF, 0xC363, 0x58E2, + 0xC364, 0x5BF5, 0xC365, 0x9F90, 0xC366, 0x5EEC, 0xC367, 0x61F2, 0xC368, 0x61F7, 0xC369, 0x61F6, 0xC36A, 0x61F5, 0xC36B, 0x6500, + 0xC36C, 0x650F, 0xC36D, 0x66E0, 0xC36E, 0x66DD, 0xC36F, 0x6AE5, 0xC370, 0x6ADD, 0xC371, 0x6ADA, 0xC372, 0x6AD3, 0xC373, 0x701B, + 0xC374, 0x701F, 0xC375, 0x7028, 0xC376, 0x701A, 0xC377, 0x701D, 0xC378, 0x7015, 0xC379, 0x7018, 0xC37A, 0x7206, 0xC37B, 0x720D, + 0xC37C, 0x7258, 0xC37D, 0x72A2, 0xC37E, 0x7378, 0xC3A1, 0x737A, 0xC3A2, 0x74BD, 0xC3A3, 0x74CA, 0xC3A4, 0x74E3, 0xC3A5, 0x7587, + 0xC3A6, 0x7586, 0xC3A7, 0x765F, 0xC3A8, 0x7661, 0xC3A9, 0x77C7, 0xC3AA, 0x7919, 0xC3AB, 0x79B1, 0xC3AC, 0x7A6B, 0xC3AD, 0x7A69, + 0xC3AE, 0x7C3E, 0xC3AF, 0x7C3F, 0xC3B0, 0x7C38, 0xC3B1, 0x7C3D, 0xC3B2, 0x7C37, 0xC3B3, 0x7C40, 0xC3B4, 0x7E6B, 0xC3B5, 0x7E6D, + 0xC3B6, 0x7E79, 0xC3B7, 0x7E69, 0xC3B8, 0x7E6A, 0xC3B9, 0x7F85, 0xC3BA, 0x7E73, 0xC3BB, 0x7FB6, 0xC3BC, 0x7FB9, 0xC3BD, 0x7FB8, + 0xC3BE, 0x81D8, 0xC3BF, 0x85E9, 0xC3C0, 0x85DD, 0xC3C1, 0x85EA, 0xC3C2, 0x85D5, 0xC3C3, 0x85E4, 0xC3C4, 0x85E5, 0xC3C5, 0x85F7, + 0xC3C6, 0x87FB, 0xC3C7, 0x8805, 0xC3C8, 0x880D, 0xC3C9, 0x87F9, 0xC3CA, 0x87FE, 0xC3CB, 0x8960, 0xC3CC, 0x895F, 0xC3CD, 0x8956, + 0xC3CE, 0x895E, 0xC3CF, 0x8B41, 0xC3D0, 0x8B5C, 0xC3D1, 0x8B58, 0xC3D2, 0x8B49, 0xC3D3, 0x8B5A, 0xC3D4, 0x8B4E, 0xC3D5, 0x8B4F, + 0xC3D6, 0x8B46, 0xC3D7, 0x8B59, 0xC3D8, 0x8D08, 0xC3D9, 0x8D0A, 0xC3DA, 0x8E7C, 0xC3DB, 0x8E72, 0xC3DC, 0x8E87, 0xC3DD, 0x8E76, + 0xC3DE, 0x8E6C, 0xC3DF, 0x8E7A, 0xC3E0, 0x8E74, 0xC3E1, 0x8F54, 0xC3E2, 0x8F4E, 0xC3E3, 0x8FAD, 0xC3E4, 0x908A, 0xC3E5, 0x908B, + 0xC3E6, 0x91B1, 0xC3E7, 0x91AE, 0xC3E8, 0x93E1, 0xC3E9, 0x93D1, 0xC3EA, 0x93DF, 0xC3EB, 0x93C3, 0xC3EC, 0x93C8, 0xC3ED, 0x93DC, + 0xC3EE, 0x93DD, 0xC3EF, 0x93D6, 0xC3F0, 0x93E2, 0xC3F1, 0x93CD, 0xC3F2, 0x93D8, 0xC3F3, 0x93E4, 0xC3F4, 0x93D7, 0xC3F5, 0x93E8, + 0xC3F6, 0x95DC, 0xC3F7, 0x96B4, 0xC3F8, 0x96E3, 0xC3F9, 0x972A, 0xC3FA, 0x9727, 0xC3FB, 0x9761, 0xC3FC, 0x97DC, 0xC3FD, 0x97FB, + 0xC3FE, 0x985E, 0xC440, 0x9858, 0xC441, 0x985B, 0xC442, 0x98BC, 0xC443, 0x9945, 0xC444, 0x9949, 0xC445, 0x9A16, 0xC446, 0x9A19, + 0xC447, 0x9B0D, 0xC448, 0x9BE8, 0xC449, 0x9BE7, 0xC44A, 0x9BD6, 0xC44B, 0x9BDB, 0xC44C, 0x9D89, 0xC44D, 0x9D61, 0xC44E, 0x9D72, + 0xC44F, 0x9D6A, 0xC450, 0x9D6C, 0xC451, 0x9E92, 0xC452, 0x9E97, 0xC453, 0x9E93, 0xC454, 0x9EB4, 0xC455, 0x52F8, 0xC456, 0x56A8, + 0xC457, 0x56B7, 0xC458, 0x56B6, 0xC459, 0x56B4, 0xC45A, 0x56BC, 0xC45B, 0x58E4, 0xC45C, 0x5B40, 0xC45D, 0x5B43, 0xC45E, 0x5B7D, + 0xC45F, 0x5BF6, 0xC460, 0x5DC9, 0xC461, 0x61F8, 0xC462, 0x61FA, 0xC463, 0x6518, 0xC464, 0x6514, 0xC465, 0x6519, 0xC466, 0x66E6, + 0xC467, 0x6727, 0xC468, 0x6AEC, 0xC469, 0x703E, 0xC46A, 0x7030, 0xC46B, 0x7032, 0xC46C, 0x7210, 0xC46D, 0x737B, 0xC46E, 0x74CF, + 0xC46F, 0x7662, 0xC470, 0x7665, 0xC471, 0x7926, 0xC472, 0x792A, 0xC473, 0x792C, 0xC474, 0x792B, 0xC475, 0x7AC7, 0xC476, 0x7AF6, + 0xC477, 0x7C4C, 0xC478, 0x7C43, 0xC479, 0x7C4D, 0xC47A, 0x7CEF, 0xC47B, 0x7CF0, 0xC47C, 0x8FAE, 0xC47D, 0x7E7D, 0xC47E, 0x7E7C, + 0xC4A1, 0x7E82, 0xC4A2, 0x7F4C, 0xC4A3, 0x8000, 0xC4A4, 0x81DA, 0xC4A5, 0x8266, 0xC4A6, 0x85FB, 0xC4A7, 0x85F9, 0xC4A8, 0x8611, + 0xC4A9, 0x85FA, 0xC4AA, 0x8606, 0xC4AB, 0x860B, 0xC4AC, 0x8607, 0xC4AD, 0x860A, 0xC4AE, 0x8814, 0xC4AF, 0x8815, 0xC4B0, 0x8964, + 0xC4B1, 0x89BA, 0xC4B2, 0x89F8, 0xC4B3, 0x8B70, 0xC4B4, 0x8B6C, 0xC4B5, 0x8B66, 0xC4B6, 0x8B6F, 0xC4B7, 0x8B5F, 0xC4B8, 0x8B6B, + 0xC4B9, 0x8D0F, 0xC4BA, 0x8D0D, 0xC4BB, 0x8E89, 0xC4BC, 0x8E81, 0xC4BD, 0x8E85, 0xC4BE, 0x8E82, 0xC4BF, 0x91B4, 0xC4C0, 0x91CB, + 0xC4C1, 0x9418, 0xC4C2, 0x9403, 0xC4C3, 0x93FD, 0xC4C4, 0x95E1, 0xC4C5, 0x9730, 0xC4C6, 0x98C4, 0xC4C7, 0x9952, 0xC4C8, 0x9951, + 0xC4C9, 0x99A8, 0xC4CA, 0x9A2B, 0xC4CB, 0x9A30, 0xC4CC, 0x9A37, 0xC4CD, 0x9A35, 0xC4CE, 0x9C13, 0xC4CF, 0x9C0D, 0xC4D0, 0x9E79, + 0xC4D1, 0x9EB5, 0xC4D2, 0x9EE8, 0xC4D3, 0x9F2F, 0xC4D4, 0x9F5F, 0xC4D5, 0x9F63, 0xC4D6, 0x9F61, 0xC4D7, 0x5137, 0xC4D8, 0x5138, + 0xC4D9, 0x56C1, 0xC4DA, 0x56C0, 0xC4DB, 0x56C2, 0xC4DC, 0x5914, 0xC4DD, 0x5C6C, 0xC4DE, 0x5DCD, 0xC4DF, 0x61FC, 0xC4E0, 0x61FE, + 0xC4E1, 0x651D, 0xC4E2, 0x651C, 0xC4E3, 0x6595, 0xC4E4, 0x66E9, 0xC4E5, 0x6AFB, 0xC4E6, 0x6B04, 0xC4E7, 0x6AFA, 0xC4E8, 0x6BB2, + 0xC4E9, 0x704C, 0xC4EA, 0x721B, 0xC4EB, 0x72A7, 0xC4EC, 0x74D6, 0xC4ED, 0x74D4, 0xC4EE, 0x7669, 0xC4EF, 0x77D3, 0xC4F0, 0x7C50, + 0xC4F1, 0x7E8F, 0xC4F2, 0x7E8C, 0xC4F3, 0x7FBC, 0xC4F4, 0x8617, 0xC4F5, 0x862D, 0xC4F6, 0x861A, 0xC4F7, 0x8823, 0xC4F8, 0x8822, + 0xC4F9, 0x8821, 0xC4FA, 0x881F, 0xC4FB, 0x896A, 0xC4FC, 0x896C, 0xC4FD, 0x89BD, 0xC4FE, 0x8B74, 0xC540, 0x8B77, 0xC541, 0x8B7D, + 0xC542, 0x8D13, 0xC543, 0x8E8A, 0xC544, 0x8E8D, 0xC545, 0x8E8B, 0xC546, 0x8F5F, 0xC547, 0x8FAF, 0xC548, 0x91BA, 0xC549, 0x942E, + 0xC54A, 0x9433, 0xC54B, 0x9435, 0xC54C, 0x943A, 0xC54D, 0x9438, 0xC54E, 0x9432, 0xC54F, 0x942B, 0xC550, 0x95E2, 0xC551, 0x9738, + 0xC552, 0x9739, 0xC553, 0x9732, 0xC554, 0x97FF, 0xC555, 0x9867, 0xC556, 0x9865, 0xC557, 0x9957, 0xC558, 0x9A45, 0xC559, 0x9A43, + 0xC55A, 0x9A40, 0xC55B, 0x9A3E, 0xC55C, 0x9ACF, 0xC55D, 0x9B54, 0xC55E, 0x9B51, 0xC55F, 0x9C2D, 0xC560, 0x9C25, 0xC561, 0x9DAF, + 0xC562, 0x9DB4, 0xC563, 0x9DC2, 0xC564, 0x9DB8, 0xC565, 0x9E9D, 0xC566, 0x9EEF, 0xC567, 0x9F19, 0xC568, 0x9F5C, 0xC569, 0x9F66, + 0xC56A, 0x9F67, 0xC56B, 0x513C, 0xC56C, 0x513B, 0xC56D, 0x56C8, 0xC56E, 0x56CA, 0xC56F, 0x56C9, 0xC570, 0x5B7F, 0xC571, 0x5DD4, + 0xC572, 0x5DD2, 0xC573, 0x5F4E, 0xC574, 0x61FF, 0xC575, 0x6524, 0xC576, 0x6B0A, 0xC577, 0x6B61, 0xC578, 0x7051, 0xC579, 0x7058, + 0xC57A, 0x7380, 0xC57B, 0x74E4, 0xC57C, 0x758A, 0xC57D, 0x766E, 0xC57E, 0x766C, 0xC5A1, 0x79B3, 0xC5A2, 0x7C60, 0xC5A3, 0x7C5F, + 0xC5A4, 0x807E, 0xC5A5, 0x807D, 0xC5A6, 0x81DF, 0xC5A7, 0x8972, 0xC5A8, 0x896F, 0xC5A9, 0x89FC, 0xC5AA, 0x8B80, 0xC5AB, 0x8D16, + 0xC5AC, 0x8D17, 0xC5AD, 0x8E91, 0xC5AE, 0x8E93, 0xC5AF, 0x8F61, 0xC5B0, 0x9148, 0xC5B1, 0x9444, 0xC5B2, 0x9451, 0xC5B3, 0x9452, + 0xC5B4, 0x973D, 0xC5B5, 0x973E, 0xC5B6, 0x97C3, 0xC5B7, 0x97C1, 0xC5B8, 0x986B, 0xC5B9, 0x9955, 0xC5BA, 0x9A55, 0xC5BB, 0x9A4D, + 0xC5BC, 0x9AD2, 0xC5BD, 0x9B1A, 0xC5BE, 0x9C49, 0xC5BF, 0x9C31, 0xC5C0, 0x9C3E, 0xC5C1, 0x9C3B, 0xC5C2, 0x9DD3, 0xC5C3, 0x9DD7, + 0xC5C4, 0x9F34, 0xC5C5, 0x9F6C, 0xC5C6, 0x9F6A, 0xC5C7, 0x9F94, 0xC5C8, 0x56CC, 0xC5C9, 0x5DD6, 0xC5CA, 0x6200, 0xC5CB, 0x6523, + 0xC5CC, 0x652B, 0xC5CD, 0x652A, 0xC5CE, 0x66EC, 0xC5CF, 0x6B10, 0xC5D0, 0x74DA, 0xC5D1, 0x7ACA, 0xC5D2, 0x7C64, 0xC5D3, 0x7C63, + 0xC5D4, 0x7C65, 0xC5D5, 0x7E93, 0xC5D6, 0x7E96, 0xC5D7, 0x7E94, 0xC5D8, 0x81E2, 0xC5D9, 0x8638, 0xC5DA, 0x863F, 0xC5DB, 0x8831, + 0xC5DC, 0x8B8A, 0xC5DD, 0x9090, 0xC5DE, 0x908F, 0xC5DF, 0x9463, 0xC5E0, 0x9460, 0xC5E1, 0x9464, 0xC5E2, 0x9768, 0xC5E3, 0x986F, + 0xC5E4, 0x995C, 0xC5E5, 0x9A5A, 0xC5E6, 0x9A5B, 0xC5E7, 0x9A57, 0xC5E8, 0x9AD3, 0xC5E9, 0x9AD4, 0xC5EA, 0x9AD1, 0xC5EB, 0x9C54, + 0xC5EC, 0x9C57, 0xC5ED, 0x9C56, 0xC5EE, 0x9DE5, 0xC5EF, 0x9E9F, 0xC5F0, 0x9EF4, 0xC5F1, 0x56D1, 0xC5F2, 0x58E9, 0xC5F3, 0x652C, + 0xC5F4, 0x705E, 0xC5F5, 0x7671, 0xC5F6, 0x7672, 0xC5F7, 0x77D7, 0xC5F8, 0x7F50, 0xC5F9, 0x7F88, 0xC5FA, 0x8836, 0xC5FB, 0x8839, + 0xC5FC, 0x8862, 0xC5FD, 0x8B93, 0xC5FE, 0x8B92, 0xC640, 0x8B96, 0xC641, 0x8277, 0xC642, 0x8D1B, 0xC643, 0x91C0, 0xC644, 0x946A, + 0xC645, 0x9742, 0xC646, 0x9748, 0xC647, 0x9744, 0xC648, 0x97C6, 0xC649, 0x9870, 0xC64A, 0x9A5F, 0xC64B, 0x9B22, 0xC64C, 0x9B58, + 0xC64D, 0x9C5F, 0xC64E, 0x9DF9, 0xC64F, 0x9DFA, 0xC650, 0x9E7C, 0xC651, 0x9E7D, 0xC652, 0x9F07, 0xC653, 0x9F77, 0xC654, 0x9F72, + 0xC655, 0x5EF3, 0xC656, 0x6B16, 0xC657, 0x7063, 0xC658, 0x7C6C, 0xC659, 0x7C6E, 0xC65A, 0x883B, 0xC65B, 0x89C0, 0xC65C, 0x8EA1, + 0xC65D, 0x91C1, 0xC65E, 0x9472, 0xC65F, 0x9470, 0xC660, 0x9871, 0xC661, 0x995E, 0xC662, 0x9AD6, 0xC663, 0x9B23, 0xC664, 0x9ECC, + 0xC665, 0x7064, 0xC666, 0x77DA, 0xC667, 0x8B9A, 0xC668, 0x9477, 0xC669, 0x97C9, 0xC66A, 0x9A62, 0xC66B, 0x9A65, 0xC66C, 0x7E9C, + 0xC66D, 0x8B9C, 0xC66E, 0x8EAA, 0xC66F, 0x91C5, 0xC670, 0x947D, 0xC671, 0x947E, 0xC672, 0x947C, 0xC673, 0x9C77, 0xC674, 0x9C78, + 0xC675, 0x9EF7, 0xC676, 0x8C54, 0xC677, 0x947F, 0xC678, 0x9E1A, 0xC679, 0x7228, 0xC67A, 0x9A6A, 0xC67B, 0x9B31, 0xC67C, 0x9E1B, + 0xC67D, 0x9E1E, 0xC67E, 0x7C72, 0xC940, 0x4E42, 0xC941, 0x4E5C, 0xC942, 0x51F5, 0xC943, 0x531A, 0xC944, 0x5382, 0xC945, 0x4E07, + 0xC946, 0x4E0C, 0xC947, 0x4E47, 0xC948, 0x4E8D, 0xC949, 0x56D7, 0xC94A, 0xFA0C, 0xC94B, 0x5C6E, 0xC94C, 0x5F73, 0xC94D, 0x4E0F, + 0xC94E, 0x5187, 0xC94F, 0x4E0E, 0xC950, 0x4E2E, 0xC951, 0x4E93, 0xC952, 0x4EC2, 0xC953, 0x4EC9, 0xC954, 0x4EC8, 0xC955, 0x5198, + 0xC956, 0x52FC, 0xC957, 0x536C, 0xC958, 0x53B9, 0xC959, 0x5720, 0xC95A, 0x5903, 0xC95B, 0x592C, 0xC95C, 0x5C10, 0xC95D, 0x5DFF, + 0xC95E, 0x65E1, 0xC95F, 0x6BB3, 0xC960, 0x6BCC, 0xC961, 0x6C14, 0xC962, 0x723F, 0xC963, 0x4E31, 0xC964, 0x4E3C, 0xC965, 0x4EE8, + 0xC966, 0x4EDC, 0xC967, 0x4EE9, 0xC968, 0x4EE1, 0xC969, 0x4EDD, 0xC96A, 0x4EDA, 0xC96B, 0x520C, 0xC96C, 0x531C, 0xC96D, 0x534C, + 0xC96E, 0x5722, 0xC96F, 0x5723, 0xC970, 0x5917, 0xC971, 0x592F, 0xC972, 0x5B81, 0xC973, 0x5B84, 0xC974, 0x5C12, 0xC975, 0x5C3B, + 0xC976, 0x5C74, 0xC977, 0x5C73, 0xC978, 0x5E04, 0xC979, 0x5E80, 0xC97A, 0x5E82, 0xC97B, 0x5FC9, 0xC97C, 0x6209, 0xC97D, 0x6250, + 0xC97E, 0x6C15, 0xC9A1, 0x6C36, 0xC9A2, 0x6C43, 0xC9A3, 0x6C3F, 0xC9A4, 0x6C3B, 0xC9A5, 0x72AE, 0xC9A6, 0x72B0, 0xC9A7, 0x738A, + 0xC9A8, 0x79B8, 0xC9A9, 0x808A, 0xC9AA, 0x961E, 0xC9AB, 0x4F0E, 0xC9AC, 0x4F18, 0xC9AD, 0x4F2C, 0xC9AE, 0x4EF5, 0xC9AF, 0x4F14, + 0xC9B0, 0x4EF1, 0xC9B1, 0x4F00, 0xC9B2, 0x4EF7, 0xC9B3, 0x4F08, 0xC9B4, 0x4F1D, 0xC9B5, 0x4F02, 0xC9B6, 0x4F05, 0xC9B7, 0x4F22, + 0xC9B8, 0x4F13, 0xC9B9, 0x4F04, 0xC9BA, 0x4EF4, 0xC9BB, 0x4F12, 0xC9BC, 0x51B1, 0xC9BD, 0x5213, 0xC9BE, 0x5209, 0xC9BF, 0x5210, + 0xC9C0, 0x52A6, 0xC9C1, 0x5322, 0xC9C2, 0x531F, 0xC9C3, 0x534D, 0xC9C4, 0x538A, 0xC9C5, 0x5407, 0xC9C6, 0x56E1, 0xC9C7, 0x56DF, + 0xC9C8, 0x572E, 0xC9C9, 0x572A, 0xC9CA, 0x5734, 0xC9CB, 0x593C, 0xC9CC, 0x5980, 0xC9CD, 0x597C, 0xC9CE, 0x5985, 0xC9CF, 0x597B, + 0xC9D0, 0x597E, 0xC9D1, 0x5977, 0xC9D2, 0x597F, 0xC9D3, 0x5B56, 0xC9D4, 0x5C15, 0xC9D5, 0x5C25, 0xC9D6, 0x5C7C, 0xC9D7, 0x5C7A, + 0xC9D8, 0x5C7B, 0xC9D9, 0x5C7E, 0xC9DA, 0x5DDF, 0xC9DB, 0x5E75, 0xC9DC, 0x5E84, 0xC9DD, 0x5F02, 0xC9DE, 0x5F1A, 0xC9DF, 0x5F74, + 0xC9E0, 0x5FD5, 0xC9E1, 0x5FD4, 0xC9E2, 0x5FCF, 0xC9E3, 0x625C, 0xC9E4, 0x625E, 0xC9E5, 0x6264, 0xC9E6, 0x6261, 0xC9E7, 0x6266, + 0xC9E8, 0x6262, 0xC9E9, 0x6259, 0xC9EA, 0x6260, 0xC9EB, 0x625A, 0xC9EC, 0x6265, 0xC9ED, 0x65EF, 0xC9EE, 0x65EE, 0xC9EF, 0x673E, + 0xC9F0, 0x6739, 0xC9F1, 0x6738, 0xC9F2, 0x673B, 0xC9F3, 0x673A, 0xC9F4, 0x673F, 0xC9F5, 0x673C, 0xC9F6, 0x6733, 0xC9F7, 0x6C18, + 0xC9F8, 0x6C46, 0xC9F9, 0x6C52, 0xC9FA, 0x6C5C, 0xC9FB, 0x6C4F, 0xC9FC, 0x6C4A, 0xC9FD, 0x6C54, 0xC9FE, 0x6C4B, 0xCA40, 0x6C4C, + 0xCA41, 0x7071, 0xCA42, 0x725E, 0xCA43, 0x72B4, 0xCA44, 0x72B5, 0xCA45, 0x738E, 0xCA46, 0x752A, 0xCA47, 0x767F, 0xCA48, 0x7A75, + 0xCA49, 0x7F51, 0xCA4A, 0x8278, 0xCA4B, 0x827C, 0xCA4C, 0x8280, 0xCA4D, 0x827D, 0xCA4E, 0x827F, 0xCA4F, 0x864D, 0xCA50, 0x897E, + 0xCA51, 0x9099, 0xCA52, 0x9097, 0xCA53, 0x9098, 0xCA54, 0x909B, 0xCA55, 0x9094, 0xCA56, 0x9622, 0xCA57, 0x9624, 0xCA58, 0x9620, + 0xCA59, 0x9623, 0xCA5A, 0x4F56, 0xCA5B, 0x4F3B, 0xCA5C, 0x4F62, 0xCA5D, 0x4F49, 0xCA5E, 0x4F53, 0xCA5F, 0x4F64, 0xCA60, 0x4F3E, + 0xCA61, 0x4F67, 0xCA62, 0x4F52, 0xCA63, 0x4F5F, 0xCA64, 0x4F41, 0xCA65, 0x4F58, 0xCA66, 0x4F2D, 0xCA67, 0x4F33, 0xCA68, 0x4F3F, + 0xCA69, 0x4F61, 0xCA6A, 0x518F, 0xCA6B, 0x51B9, 0xCA6C, 0x521C, 0xCA6D, 0x521E, 0xCA6E, 0x5221, 0xCA6F, 0x52AD, 0xCA70, 0x52AE, + 0xCA71, 0x5309, 0xCA72, 0x5363, 0xCA73, 0x5372, 0xCA74, 0x538E, 0xCA75, 0x538F, 0xCA76, 0x5430, 0xCA77, 0x5437, 0xCA78, 0x542A, + 0xCA79, 0x5454, 0xCA7A, 0x5445, 0xCA7B, 0x5419, 0xCA7C, 0x541C, 0xCA7D, 0x5425, 0xCA7E, 0x5418, 0xCAA1, 0x543D, 0xCAA2, 0x544F, + 0xCAA3, 0x5441, 0xCAA4, 0x5428, 0xCAA5, 0x5424, 0xCAA6, 0x5447, 0xCAA7, 0x56EE, 0xCAA8, 0x56E7, 0xCAA9, 0x56E5, 0xCAAA, 0x5741, + 0xCAAB, 0x5745, 0xCAAC, 0x574C, 0xCAAD, 0x5749, 0xCAAE, 0x574B, 0xCAAF, 0x5752, 0xCAB0, 0x5906, 0xCAB1, 0x5940, 0xCAB2, 0x59A6, + 0xCAB3, 0x5998, 0xCAB4, 0x59A0, 0xCAB5, 0x5997, 0xCAB6, 0x598E, 0xCAB7, 0x59A2, 0xCAB8, 0x5990, 0xCAB9, 0x598F, 0xCABA, 0x59A7, + 0xCABB, 0x59A1, 0xCABC, 0x5B8E, 0xCABD, 0x5B92, 0xCABE, 0x5C28, 0xCABF, 0x5C2A, 0xCAC0, 0x5C8D, 0xCAC1, 0x5C8F, 0xCAC2, 0x5C88, + 0xCAC3, 0x5C8B, 0xCAC4, 0x5C89, 0xCAC5, 0x5C92, 0xCAC6, 0x5C8A, 0xCAC7, 0x5C86, 0xCAC8, 0x5C93, 0xCAC9, 0x5C95, 0xCACA, 0x5DE0, + 0xCACB, 0x5E0A, 0xCACC, 0x5E0E, 0xCACD, 0x5E8B, 0xCACE, 0x5E89, 0xCACF, 0x5E8C, 0xCAD0, 0x5E88, 0xCAD1, 0x5E8D, 0xCAD2, 0x5F05, + 0xCAD3, 0x5F1D, 0xCAD4, 0x5F78, 0xCAD5, 0x5F76, 0xCAD6, 0x5FD2, 0xCAD7, 0x5FD1, 0xCAD8, 0x5FD0, 0xCAD9, 0x5FED, 0xCADA, 0x5FE8, + 0xCADB, 0x5FEE, 0xCADC, 0x5FF3, 0xCADD, 0x5FE1, 0xCADE, 0x5FE4, 0xCADF, 0x5FE3, 0xCAE0, 0x5FFA, 0xCAE1, 0x5FEF, 0xCAE2, 0x5FF7, + 0xCAE3, 0x5FFB, 0xCAE4, 0x6000, 0xCAE5, 0x5FF4, 0xCAE6, 0x623A, 0xCAE7, 0x6283, 0xCAE8, 0x628C, 0xCAE9, 0x628E, 0xCAEA, 0x628F, + 0xCAEB, 0x6294, 0xCAEC, 0x6287, 0xCAED, 0x6271, 0xCAEE, 0x627B, 0xCAEF, 0x627A, 0xCAF0, 0x6270, 0xCAF1, 0x6281, 0xCAF2, 0x6288, + 0xCAF3, 0x6277, 0xCAF4, 0x627D, 0xCAF5, 0x6272, 0xCAF6, 0x6274, 0xCAF7, 0x6537, 0xCAF8, 0x65F0, 0xCAF9, 0x65F4, 0xCAFA, 0x65F3, + 0xCAFB, 0x65F2, 0xCAFC, 0x65F5, 0xCAFD, 0x6745, 0xCAFE, 0x6747, 0xCB40, 0x6759, 0xCB41, 0x6755, 0xCB42, 0x674C, 0xCB43, 0x6748, + 0xCB44, 0x675D, 0xCB45, 0x674D, 0xCB46, 0x675A, 0xCB47, 0x674B, 0xCB48, 0x6BD0, 0xCB49, 0x6C19, 0xCB4A, 0x6C1A, 0xCB4B, 0x6C78, + 0xCB4C, 0x6C67, 0xCB4D, 0x6C6B, 0xCB4E, 0x6C84, 0xCB4F, 0x6C8B, 0xCB50, 0x6C8F, 0xCB51, 0x6C71, 0xCB52, 0x6C6F, 0xCB53, 0x6C69, + 0xCB54, 0x6C9A, 0xCB55, 0x6C6D, 0xCB56, 0x6C87, 0xCB57, 0x6C95, 0xCB58, 0x6C9C, 0xCB59, 0x6C66, 0xCB5A, 0x6C73, 0xCB5B, 0x6C65, + 0xCB5C, 0x6C7B, 0xCB5D, 0x6C8E, 0xCB5E, 0x7074, 0xCB5F, 0x707A, 0xCB60, 0x7263, 0xCB61, 0x72BF, 0xCB62, 0x72BD, 0xCB63, 0x72C3, + 0xCB64, 0x72C6, 0xCB65, 0x72C1, 0xCB66, 0x72BA, 0xCB67, 0x72C5, 0xCB68, 0x7395, 0xCB69, 0x7397, 0xCB6A, 0x7393, 0xCB6B, 0x7394, + 0xCB6C, 0x7392, 0xCB6D, 0x753A, 0xCB6E, 0x7539, 0xCB6F, 0x7594, 0xCB70, 0x7595, 0xCB71, 0x7681, 0xCB72, 0x793D, 0xCB73, 0x8034, + 0xCB74, 0x8095, 0xCB75, 0x8099, 0xCB76, 0x8090, 0xCB77, 0x8092, 0xCB78, 0x809C, 0xCB79, 0x8290, 0xCB7A, 0x828F, 0xCB7B, 0x8285, + 0xCB7C, 0x828E, 0xCB7D, 0x8291, 0xCB7E, 0x8293, 0xCBA1, 0x828A, 0xCBA2, 0x8283, 0xCBA3, 0x8284, 0xCBA4, 0x8C78, 0xCBA5, 0x8FC9, + 0xCBA6, 0x8FBF, 0xCBA7, 0x909F, 0xCBA8, 0x90A1, 0xCBA9, 0x90A5, 0xCBAA, 0x909E, 0xCBAB, 0x90A7, 0xCBAC, 0x90A0, 0xCBAD, 0x9630, + 0xCBAE, 0x9628, 0xCBAF, 0x962F, 0xCBB0, 0x962D, 0xCBB1, 0x4E33, 0xCBB2, 0x4F98, 0xCBB3, 0x4F7C, 0xCBB4, 0x4F85, 0xCBB5, 0x4F7D, + 0xCBB6, 0x4F80, 0xCBB7, 0x4F87, 0xCBB8, 0x4F76, 0xCBB9, 0x4F74, 0xCBBA, 0x4F89, 0xCBBB, 0x4F84, 0xCBBC, 0x4F77, 0xCBBD, 0x4F4C, + 0xCBBE, 0x4F97, 0xCBBF, 0x4F6A, 0xCBC0, 0x4F9A, 0xCBC1, 0x4F79, 0xCBC2, 0x4F81, 0xCBC3, 0x4F78, 0xCBC4, 0x4F90, 0xCBC5, 0x4F9C, + 0xCBC6, 0x4F94, 0xCBC7, 0x4F9E, 0xCBC8, 0x4F92, 0xCBC9, 0x4F82, 0xCBCA, 0x4F95, 0xCBCB, 0x4F6B, 0xCBCC, 0x4F6E, 0xCBCD, 0x519E, + 0xCBCE, 0x51BC, 0xCBCF, 0x51BE, 0xCBD0, 0x5235, 0xCBD1, 0x5232, 0xCBD2, 0x5233, 0xCBD3, 0x5246, 0xCBD4, 0x5231, 0xCBD5, 0x52BC, + 0xCBD6, 0x530A, 0xCBD7, 0x530B, 0xCBD8, 0x533C, 0xCBD9, 0x5392, 0xCBDA, 0x5394, 0xCBDB, 0x5487, 0xCBDC, 0x547F, 0xCBDD, 0x5481, + 0xCBDE, 0x5491, 0xCBDF, 0x5482, 0xCBE0, 0x5488, 0xCBE1, 0x546B, 0xCBE2, 0x547A, 0xCBE3, 0x547E, 0xCBE4, 0x5465, 0xCBE5, 0x546C, + 0xCBE6, 0x5474, 0xCBE7, 0x5466, 0xCBE8, 0x548D, 0xCBE9, 0x546F, 0xCBEA, 0x5461, 0xCBEB, 0x5460, 0xCBEC, 0x5498, 0xCBED, 0x5463, + 0xCBEE, 0x5467, 0xCBEF, 0x5464, 0xCBF0, 0x56F7, 0xCBF1, 0x56F9, 0xCBF2, 0x576F, 0xCBF3, 0x5772, 0xCBF4, 0x576D, 0xCBF5, 0x576B, + 0xCBF6, 0x5771, 0xCBF7, 0x5770, 0xCBF8, 0x5776, 0xCBF9, 0x5780, 0xCBFA, 0x5775, 0xCBFB, 0x577B, 0xCBFC, 0x5773, 0xCBFD, 0x5774, + 0xCBFE, 0x5762, 0xCC40, 0x5768, 0xCC41, 0x577D, 0xCC42, 0x590C, 0xCC43, 0x5945, 0xCC44, 0x59B5, 0xCC45, 0x59BA, 0xCC46, 0x59CF, + 0xCC47, 0x59CE, 0xCC48, 0x59B2, 0xCC49, 0x59CC, 0xCC4A, 0x59C1, 0xCC4B, 0x59B6, 0xCC4C, 0x59BC, 0xCC4D, 0x59C3, 0xCC4E, 0x59D6, + 0xCC4F, 0x59B1, 0xCC50, 0x59BD, 0xCC51, 0x59C0, 0xCC52, 0x59C8, 0xCC53, 0x59B4, 0xCC54, 0x59C7, 0xCC55, 0x5B62, 0xCC56, 0x5B65, + 0xCC57, 0x5B93, 0xCC58, 0x5B95, 0xCC59, 0x5C44, 0xCC5A, 0x5C47, 0xCC5B, 0x5CAE, 0xCC5C, 0x5CA4, 0xCC5D, 0x5CA0, 0xCC5E, 0x5CB5, + 0xCC5F, 0x5CAF, 0xCC60, 0x5CA8, 0xCC61, 0x5CAC, 0xCC62, 0x5C9F, 0xCC63, 0x5CA3, 0xCC64, 0x5CAD, 0xCC65, 0x5CA2, 0xCC66, 0x5CAA, + 0xCC67, 0x5CA7, 0xCC68, 0x5C9D, 0xCC69, 0x5CA5, 0xCC6A, 0x5CB6, 0xCC6B, 0x5CB0, 0xCC6C, 0x5CA6, 0xCC6D, 0x5E17, 0xCC6E, 0x5E14, + 0xCC6F, 0x5E19, 0xCC70, 0x5F28, 0xCC71, 0x5F22, 0xCC72, 0x5F23, 0xCC73, 0x5F24, 0xCC74, 0x5F54, 0xCC75, 0x5F82, 0xCC76, 0x5F7E, + 0xCC77, 0x5F7D, 0xCC78, 0x5FDE, 0xCC79, 0x5FE5, 0xCC7A, 0x602D, 0xCC7B, 0x6026, 0xCC7C, 0x6019, 0xCC7D, 0x6032, 0xCC7E, 0x600B, + 0xCCA1, 0x6034, 0xCCA2, 0x600A, 0xCCA3, 0x6017, 0xCCA4, 0x6033, 0xCCA5, 0x601A, 0xCCA6, 0x601E, 0xCCA7, 0x602C, 0xCCA8, 0x6022, + 0xCCA9, 0x600D, 0xCCAA, 0x6010, 0xCCAB, 0x602E, 0xCCAC, 0x6013, 0xCCAD, 0x6011, 0xCCAE, 0x600C, 0xCCAF, 0x6009, 0xCCB0, 0x601C, + 0xCCB1, 0x6214, 0xCCB2, 0x623D, 0xCCB3, 0x62AD, 0xCCB4, 0x62B4, 0xCCB5, 0x62D1, 0xCCB6, 0x62BE, 0xCCB7, 0x62AA, 0xCCB8, 0x62B6, + 0xCCB9, 0x62CA, 0xCCBA, 0x62AE, 0xCCBB, 0x62B3, 0xCCBC, 0x62AF, 0xCCBD, 0x62BB, 0xCCBE, 0x62A9, 0xCCBF, 0x62B0, 0xCCC0, 0x62B8, + 0xCCC1, 0x653D, 0xCCC2, 0x65A8, 0xCCC3, 0x65BB, 0xCCC4, 0x6609, 0xCCC5, 0x65FC, 0xCCC6, 0x6604, 0xCCC7, 0x6612, 0xCCC8, 0x6608, + 0xCCC9, 0x65FB, 0xCCCA, 0x6603, 0xCCCB, 0x660B, 0xCCCC, 0x660D, 0xCCCD, 0x6605, 0xCCCE, 0x65FD, 0xCCCF, 0x6611, 0xCCD0, 0x6610, + 0xCCD1, 0x66F6, 0xCCD2, 0x670A, 0xCCD3, 0x6785, 0xCCD4, 0x676C, 0xCCD5, 0x678E, 0xCCD6, 0x6792, 0xCCD7, 0x6776, 0xCCD8, 0x677B, + 0xCCD9, 0x6798, 0xCCDA, 0x6786, 0xCCDB, 0x6784, 0xCCDC, 0x6774, 0xCCDD, 0x678D, 0xCCDE, 0x678C, 0xCCDF, 0x677A, 0xCCE0, 0x679F, + 0xCCE1, 0x6791, 0xCCE2, 0x6799, 0xCCE3, 0x6783, 0xCCE4, 0x677D, 0xCCE5, 0x6781, 0xCCE6, 0x6778, 0xCCE7, 0x6779, 0xCCE8, 0x6794, + 0xCCE9, 0x6B25, 0xCCEA, 0x6B80, 0xCCEB, 0x6B7E, 0xCCEC, 0x6BDE, 0xCCED, 0x6C1D, 0xCCEE, 0x6C93, 0xCCEF, 0x6CEC, 0xCCF0, 0x6CEB, + 0xCCF1, 0x6CEE, 0xCCF2, 0x6CD9, 0xCCF3, 0x6CB6, 0xCCF4, 0x6CD4, 0xCCF5, 0x6CAD, 0xCCF6, 0x6CE7, 0xCCF7, 0x6CB7, 0xCCF8, 0x6CD0, + 0xCCF9, 0x6CC2, 0xCCFA, 0x6CBA, 0xCCFB, 0x6CC3, 0xCCFC, 0x6CC6, 0xCCFD, 0x6CED, 0xCCFE, 0x6CF2, 0xCD40, 0x6CD2, 0xCD41, 0x6CDD, + 0xCD42, 0x6CB4, 0xCD43, 0x6C8A, 0xCD44, 0x6C9D, 0xCD45, 0x6C80, 0xCD46, 0x6CDE, 0xCD47, 0x6CC0, 0xCD48, 0x6D30, 0xCD49, 0x6CCD, + 0xCD4A, 0x6CC7, 0xCD4B, 0x6CB0, 0xCD4C, 0x6CF9, 0xCD4D, 0x6CCF, 0xCD4E, 0x6CE9, 0xCD4F, 0x6CD1, 0xCD50, 0x7094, 0xCD51, 0x7098, + 0xCD52, 0x7085, 0xCD53, 0x7093, 0xCD54, 0x7086, 0xCD55, 0x7084, 0xCD56, 0x7091, 0xCD57, 0x7096, 0xCD58, 0x7082, 0xCD59, 0x709A, + 0xCD5A, 0x7083, 0xCD5B, 0x726A, 0xCD5C, 0x72D6, 0xCD5D, 0x72CB, 0xCD5E, 0x72D8, 0xCD5F, 0x72C9, 0xCD60, 0x72DC, 0xCD61, 0x72D2, + 0xCD62, 0x72D4, 0xCD63, 0x72DA, 0xCD64, 0x72CC, 0xCD65, 0x72D1, 0xCD66, 0x73A4, 0xCD67, 0x73A1, 0xCD68, 0x73AD, 0xCD69, 0x73A6, + 0xCD6A, 0x73A2, 0xCD6B, 0x73A0, 0xCD6C, 0x73AC, 0xCD6D, 0x739D, 0xCD6E, 0x74DD, 0xCD6F, 0x74E8, 0xCD70, 0x753F, 0xCD71, 0x7540, + 0xCD72, 0x753E, 0xCD73, 0x758C, 0xCD74, 0x7598, 0xCD75, 0x76AF, 0xCD76, 0x76F3, 0xCD77, 0x76F1, 0xCD78, 0x76F0, 0xCD79, 0x76F5, + 0xCD7A, 0x77F8, 0xCD7B, 0x77FC, 0xCD7C, 0x77F9, 0xCD7D, 0x77FB, 0xCD7E, 0x77FA, 0xCDA1, 0x77F7, 0xCDA2, 0x7942, 0xCDA3, 0x793F, + 0xCDA4, 0x79C5, 0xCDA5, 0x7A78, 0xCDA6, 0x7A7B, 0xCDA7, 0x7AFB, 0xCDA8, 0x7C75, 0xCDA9, 0x7CFD, 0xCDAA, 0x8035, 0xCDAB, 0x808F, + 0xCDAC, 0x80AE, 0xCDAD, 0x80A3, 0xCDAE, 0x80B8, 0xCDAF, 0x80B5, 0xCDB0, 0x80AD, 0xCDB1, 0x8220, 0xCDB2, 0x82A0, 0xCDB3, 0x82C0, + 0xCDB4, 0x82AB, 0xCDB5, 0x829A, 0xCDB6, 0x8298, 0xCDB7, 0x829B, 0xCDB8, 0x82B5, 0xCDB9, 0x82A7, 0xCDBA, 0x82AE, 0xCDBB, 0x82BC, + 0xCDBC, 0x829E, 0xCDBD, 0x82BA, 0xCDBE, 0x82B4, 0xCDBF, 0x82A8, 0xCDC0, 0x82A1, 0xCDC1, 0x82A9, 0xCDC2, 0x82C2, 0xCDC3, 0x82A4, + 0xCDC4, 0x82C3, 0xCDC5, 0x82B6, 0xCDC6, 0x82A2, 0xCDC7, 0x8670, 0xCDC8, 0x866F, 0xCDC9, 0x866D, 0xCDCA, 0x866E, 0xCDCB, 0x8C56, + 0xCDCC, 0x8FD2, 0xCDCD, 0x8FCB, 0xCDCE, 0x8FD3, 0xCDCF, 0x8FCD, 0xCDD0, 0x8FD6, 0xCDD1, 0x8FD5, 0xCDD2, 0x8FD7, 0xCDD3, 0x90B2, + 0xCDD4, 0x90B4, 0xCDD5, 0x90AF, 0xCDD6, 0x90B3, 0xCDD7, 0x90B0, 0xCDD8, 0x9639, 0xCDD9, 0x963D, 0xCDDA, 0x963C, 0xCDDB, 0x963A, + 0xCDDC, 0x9643, 0xCDDD, 0x4FCD, 0xCDDE, 0x4FC5, 0xCDDF, 0x4FD3, 0xCDE0, 0x4FB2, 0xCDE1, 0x4FC9, 0xCDE2, 0x4FCB, 0xCDE3, 0x4FC1, + 0xCDE4, 0x4FD4, 0xCDE5, 0x4FDC, 0xCDE6, 0x4FD9, 0xCDE7, 0x4FBB, 0xCDE8, 0x4FB3, 0xCDE9, 0x4FDB, 0xCDEA, 0x4FC7, 0xCDEB, 0x4FD6, + 0xCDEC, 0x4FBA, 0xCDED, 0x4FC0, 0xCDEE, 0x4FB9, 0xCDEF, 0x4FEC, 0xCDF0, 0x5244, 0xCDF1, 0x5249, 0xCDF2, 0x52C0, 0xCDF3, 0x52C2, + 0xCDF4, 0x533D, 0xCDF5, 0x537C, 0xCDF6, 0x5397, 0xCDF7, 0x5396, 0xCDF8, 0x5399, 0xCDF9, 0x5398, 0xCDFA, 0x54BA, 0xCDFB, 0x54A1, + 0xCDFC, 0x54AD, 0xCDFD, 0x54A5, 0xCDFE, 0x54CF, 0xCE40, 0x54C3, 0xCE41, 0x830D, 0xCE42, 0x54B7, 0xCE43, 0x54AE, 0xCE44, 0x54D6, + 0xCE45, 0x54B6, 0xCE46, 0x54C5, 0xCE47, 0x54C6, 0xCE48, 0x54A0, 0xCE49, 0x5470, 0xCE4A, 0x54BC, 0xCE4B, 0x54A2, 0xCE4C, 0x54BE, + 0xCE4D, 0x5472, 0xCE4E, 0x54DE, 0xCE4F, 0x54B0, 0xCE50, 0x57B5, 0xCE51, 0x579E, 0xCE52, 0x579F, 0xCE53, 0x57A4, 0xCE54, 0x578C, + 0xCE55, 0x5797, 0xCE56, 0x579D, 0xCE57, 0x579B, 0xCE58, 0x5794, 0xCE59, 0x5798, 0xCE5A, 0x578F, 0xCE5B, 0x5799, 0xCE5C, 0x57A5, + 0xCE5D, 0x579A, 0xCE5E, 0x5795, 0xCE5F, 0x58F4, 0xCE60, 0x590D, 0xCE61, 0x5953, 0xCE62, 0x59E1, 0xCE63, 0x59DE, 0xCE64, 0x59EE, + 0xCE65, 0x5A00, 0xCE66, 0x59F1, 0xCE67, 0x59DD, 0xCE68, 0x59FA, 0xCE69, 0x59FD, 0xCE6A, 0x59FC, 0xCE6B, 0x59F6, 0xCE6C, 0x59E4, + 0xCE6D, 0x59F2, 0xCE6E, 0x59F7, 0xCE6F, 0x59DB, 0xCE70, 0x59E9, 0xCE71, 0x59F3, 0xCE72, 0x59F5, 0xCE73, 0x59E0, 0xCE74, 0x59FE, + 0xCE75, 0x59F4, 0xCE76, 0x59ED, 0xCE77, 0x5BA8, 0xCE78, 0x5C4C, 0xCE79, 0x5CD0, 0xCE7A, 0x5CD8, 0xCE7B, 0x5CCC, 0xCE7C, 0x5CD7, + 0xCE7D, 0x5CCB, 0xCE7E, 0x5CDB, 0xCEA1, 0x5CDE, 0xCEA2, 0x5CDA, 0xCEA3, 0x5CC9, 0xCEA4, 0x5CC7, 0xCEA5, 0x5CCA, 0xCEA6, 0x5CD6, + 0xCEA7, 0x5CD3, 0xCEA8, 0x5CD4, 0xCEA9, 0x5CCF, 0xCEAA, 0x5CC8, 0xCEAB, 0x5CC6, 0xCEAC, 0x5CCE, 0xCEAD, 0x5CDF, 0xCEAE, 0x5CF8, + 0xCEAF, 0x5DF9, 0xCEB0, 0x5E21, 0xCEB1, 0x5E22, 0xCEB2, 0x5E23, 0xCEB3, 0x5E20, 0xCEB4, 0x5E24, 0xCEB5, 0x5EB0, 0xCEB6, 0x5EA4, + 0xCEB7, 0x5EA2, 0xCEB8, 0x5E9B, 0xCEB9, 0x5EA3, 0xCEBA, 0x5EA5, 0xCEBB, 0x5F07, 0xCEBC, 0x5F2E, 0xCEBD, 0x5F56, 0xCEBE, 0x5F86, + 0xCEBF, 0x6037, 0xCEC0, 0x6039, 0xCEC1, 0x6054, 0xCEC2, 0x6072, 0xCEC3, 0x605E, 0xCEC4, 0x6045, 0xCEC5, 0x6053, 0xCEC6, 0x6047, + 0xCEC7, 0x6049, 0xCEC8, 0x605B, 0xCEC9, 0x604C, 0xCECA, 0x6040, 0xCECB, 0x6042, 0xCECC, 0x605F, 0xCECD, 0x6024, 0xCECE, 0x6044, + 0xCECF, 0x6058, 0xCED0, 0x6066, 0xCED1, 0x606E, 0xCED2, 0x6242, 0xCED3, 0x6243, 0xCED4, 0x62CF, 0xCED5, 0x630D, 0xCED6, 0x630B, + 0xCED7, 0x62F5, 0xCED8, 0x630E, 0xCED9, 0x6303, 0xCEDA, 0x62EB, 0xCEDB, 0x62F9, 0xCEDC, 0x630F, 0xCEDD, 0x630C, 0xCEDE, 0x62F8, + 0xCEDF, 0x62F6, 0xCEE0, 0x6300, 0xCEE1, 0x6313, 0xCEE2, 0x6314, 0xCEE3, 0x62FA, 0xCEE4, 0x6315, 0xCEE5, 0x62FB, 0xCEE6, 0x62F0, + 0xCEE7, 0x6541, 0xCEE8, 0x6543, 0xCEE9, 0x65AA, 0xCEEA, 0x65BF, 0xCEEB, 0x6636, 0xCEEC, 0x6621, 0xCEED, 0x6632, 0xCEEE, 0x6635, + 0xCEEF, 0x661C, 0xCEF0, 0x6626, 0xCEF1, 0x6622, 0xCEF2, 0x6633, 0xCEF3, 0x662B, 0xCEF4, 0x663A, 0xCEF5, 0x661D, 0xCEF6, 0x6634, + 0xCEF7, 0x6639, 0xCEF8, 0x662E, 0xCEF9, 0x670F, 0xCEFA, 0x6710, 0xCEFB, 0x67C1, 0xCEFC, 0x67F2, 0xCEFD, 0x67C8, 0xCEFE, 0x67BA, + 0xCF40, 0x67DC, 0xCF41, 0x67BB, 0xCF42, 0x67F8, 0xCF43, 0x67D8, 0xCF44, 0x67C0, 0xCF45, 0x67B7, 0xCF46, 0x67C5, 0xCF47, 0x67EB, + 0xCF48, 0x67E4, 0xCF49, 0x67DF, 0xCF4A, 0x67B5, 0xCF4B, 0x67CD, 0xCF4C, 0x67B3, 0xCF4D, 0x67F7, 0xCF4E, 0x67F6, 0xCF4F, 0x67EE, + 0xCF50, 0x67E3, 0xCF51, 0x67C2, 0xCF52, 0x67B9, 0xCF53, 0x67CE, 0xCF54, 0x67E7, 0xCF55, 0x67F0, 0xCF56, 0x67B2, 0xCF57, 0x67FC, + 0xCF58, 0x67C6, 0xCF59, 0x67ED, 0xCF5A, 0x67CC, 0xCF5B, 0x67AE, 0xCF5C, 0x67E6, 0xCF5D, 0x67DB, 0xCF5E, 0x67FA, 0xCF5F, 0x67C9, + 0xCF60, 0x67CA, 0xCF61, 0x67C3, 0xCF62, 0x67EA, 0xCF63, 0x67CB, 0xCF64, 0x6B28, 0xCF65, 0x6B82, 0xCF66, 0x6B84, 0xCF67, 0x6BB6, + 0xCF68, 0x6BD6, 0xCF69, 0x6BD8, 0xCF6A, 0x6BE0, 0xCF6B, 0x6C20, 0xCF6C, 0x6C21, 0xCF6D, 0x6D28, 0xCF6E, 0x6D34, 0xCF6F, 0x6D2D, + 0xCF70, 0x6D1F, 0xCF71, 0x6D3C, 0xCF72, 0x6D3F, 0xCF73, 0x6D12, 0xCF74, 0x6D0A, 0xCF75, 0x6CDA, 0xCF76, 0x6D33, 0xCF77, 0x6D04, + 0xCF78, 0x6D19, 0xCF79, 0x6D3A, 0xCF7A, 0x6D1A, 0xCF7B, 0x6D11, 0xCF7C, 0x6D00, 0xCF7D, 0x6D1D, 0xCF7E, 0x6D42, 0xCFA1, 0x6D01, + 0xCFA2, 0x6D18, 0xCFA3, 0x6D37, 0xCFA4, 0x6D03, 0xCFA5, 0x6D0F, 0xCFA6, 0x6D40, 0xCFA7, 0x6D07, 0xCFA8, 0x6D20, 0xCFA9, 0x6D2C, + 0xCFAA, 0x6D08, 0xCFAB, 0x6D22, 0xCFAC, 0x6D09, 0xCFAD, 0x6D10, 0xCFAE, 0x70B7, 0xCFAF, 0x709F, 0xCFB0, 0x70BE, 0xCFB1, 0x70B1, + 0xCFB2, 0x70B0, 0xCFB3, 0x70A1, 0xCFB4, 0x70B4, 0xCFB5, 0x70B5, 0xCFB6, 0x70A9, 0xCFB7, 0x7241, 0xCFB8, 0x7249, 0xCFB9, 0x724A, + 0xCFBA, 0x726C, 0xCFBB, 0x7270, 0xCFBC, 0x7273, 0xCFBD, 0x726E, 0xCFBE, 0x72CA, 0xCFBF, 0x72E4, 0xCFC0, 0x72E8, 0xCFC1, 0x72EB, + 0xCFC2, 0x72DF, 0xCFC3, 0x72EA, 0xCFC4, 0x72E6, 0xCFC5, 0x72E3, 0xCFC6, 0x7385, 0xCFC7, 0x73CC, 0xCFC8, 0x73C2, 0xCFC9, 0x73C8, + 0xCFCA, 0x73C5, 0xCFCB, 0x73B9, 0xCFCC, 0x73B6, 0xCFCD, 0x73B5, 0xCFCE, 0x73B4, 0xCFCF, 0x73EB, 0xCFD0, 0x73BF, 0xCFD1, 0x73C7, + 0xCFD2, 0x73BE, 0xCFD3, 0x73C3, 0xCFD4, 0x73C6, 0xCFD5, 0x73B8, 0xCFD6, 0x73CB, 0xCFD7, 0x74EC, 0xCFD8, 0x74EE, 0xCFD9, 0x752E, + 0xCFDA, 0x7547, 0xCFDB, 0x7548, 0xCFDC, 0x75A7, 0xCFDD, 0x75AA, 0xCFDE, 0x7679, 0xCFDF, 0x76C4, 0xCFE0, 0x7708, 0xCFE1, 0x7703, + 0xCFE2, 0x7704, 0xCFE3, 0x7705, 0xCFE4, 0x770A, 0xCFE5, 0x76F7, 0xCFE6, 0x76FB, 0xCFE7, 0x76FA, 0xCFE8, 0x77E7, 0xCFE9, 0x77E8, + 0xCFEA, 0x7806, 0xCFEB, 0x7811, 0xCFEC, 0x7812, 0xCFED, 0x7805, 0xCFEE, 0x7810, 0xCFEF, 0x780F, 0xCFF0, 0x780E, 0xCFF1, 0x7809, + 0xCFF2, 0x7803, 0xCFF3, 0x7813, 0xCFF4, 0x794A, 0xCFF5, 0x794C, 0xCFF6, 0x794B, 0xCFF7, 0x7945, 0xCFF8, 0x7944, 0xCFF9, 0x79D5, + 0xCFFA, 0x79CD, 0xCFFB, 0x79CF, 0xCFFC, 0x79D6, 0xCFFD, 0x79CE, 0xCFFE, 0x7A80, 0xD040, 0x7A7E, 0xD041, 0x7AD1, 0xD042, 0x7B00, + 0xD043, 0x7B01, 0xD044, 0x7C7A, 0xD045, 0x7C78, 0xD046, 0x7C79, 0xD047, 0x7C7F, 0xD048, 0x7C80, 0xD049, 0x7C81, 0xD04A, 0x7D03, + 0xD04B, 0x7D08, 0xD04C, 0x7D01, 0xD04D, 0x7F58, 0xD04E, 0x7F91, 0xD04F, 0x7F8D, 0xD050, 0x7FBE, 0xD051, 0x8007, 0xD052, 0x800E, + 0xD053, 0x800F, 0xD054, 0x8014, 0xD055, 0x8037, 0xD056, 0x80D8, 0xD057, 0x80C7, 0xD058, 0x80E0, 0xD059, 0x80D1, 0xD05A, 0x80C8, + 0xD05B, 0x80C2, 0xD05C, 0x80D0, 0xD05D, 0x80C5, 0xD05E, 0x80E3, 0xD05F, 0x80D9, 0xD060, 0x80DC, 0xD061, 0x80CA, 0xD062, 0x80D5, + 0xD063, 0x80C9, 0xD064, 0x80CF, 0xD065, 0x80D7, 0xD066, 0x80E6, 0xD067, 0x80CD, 0xD068, 0x81FF, 0xD069, 0x8221, 0xD06A, 0x8294, + 0xD06B, 0x82D9, 0xD06C, 0x82FE, 0xD06D, 0x82F9, 0xD06E, 0x8307, 0xD06F, 0x82E8, 0xD070, 0x8300, 0xD071, 0x82D5, 0xD072, 0x833A, + 0xD073, 0x82EB, 0xD074, 0x82D6, 0xD075, 0x82F4, 0xD076, 0x82EC, 0xD077, 0x82E1, 0xD078, 0x82F2, 0xD079, 0x82F5, 0xD07A, 0x830C, + 0xD07B, 0x82FB, 0xD07C, 0x82F6, 0xD07D, 0x82F0, 0xD07E, 0x82EA, 0xD0A1, 0x82E4, 0xD0A2, 0x82E0, 0xD0A3, 0x82FA, 0xD0A4, 0x82F3, + 0xD0A5, 0x82ED, 0xD0A6, 0x8677, 0xD0A7, 0x8674, 0xD0A8, 0x867C, 0xD0A9, 0x8673, 0xD0AA, 0x8841, 0xD0AB, 0x884E, 0xD0AC, 0x8867, + 0xD0AD, 0x886A, 0xD0AE, 0x8869, 0xD0AF, 0x89D3, 0xD0B0, 0x8A04, 0xD0B1, 0x8A07, 0xD0B2, 0x8D72, 0xD0B3, 0x8FE3, 0xD0B4, 0x8FE1, + 0xD0B5, 0x8FEE, 0xD0B6, 0x8FE0, 0xD0B7, 0x90F1, 0xD0B8, 0x90BD, 0xD0B9, 0x90BF, 0xD0BA, 0x90D5, 0xD0BB, 0x90C5, 0xD0BC, 0x90BE, + 0xD0BD, 0x90C7, 0xD0BE, 0x90CB, 0xD0BF, 0x90C8, 0xD0C0, 0x91D4, 0xD0C1, 0x91D3, 0xD0C2, 0x9654, 0xD0C3, 0x964F, 0xD0C4, 0x9651, + 0xD0C5, 0x9653, 0xD0C6, 0x964A, 0xD0C7, 0x964E, 0xD0C8, 0x501E, 0xD0C9, 0x5005, 0xD0CA, 0x5007, 0xD0CB, 0x5013, 0xD0CC, 0x5022, + 0xD0CD, 0x5030, 0xD0CE, 0x501B, 0xD0CF, 0x4FF5, 0xD0D0, 0x4FF4, 0xD0D1, 0x5033, 0xD0D2, 0x5037, 0xD0D3, 0x502C, 0xD0D4, 0x4FF6, + 0xD0D5, 0x4FF7, 0xD0D6, 0x5017, 0xD0D7, 0x501C, 0xD0D8, 0x5020, 0xD0D9, 0x5027, 0xD0DA, 0x5035, 0xD0DB, 0x502F, 0xD0DC, 0x5031, + 0xD0DD, 0x500E, 0xD0DE, 0x515A, 0xD0DF, 0x5194, 0xD0E0, 0x5193, 0xD0E1, 0x51CA, 0xD0E2, 0x51C4, 0xD0E3, 0x51C5, 0xD0E4, 0x51C8, + 0xD0E5, 0x51CE, 0xD0E6, 0x5261, 0xD0E7, 0x525A, 0xD0E8, 0x5252, 0xD0E9, 0x525E, 0xD0EA, 0x525F, 0xD0EB, 0x5255, 0xD0EC, 0x5262, + 0xD0ED, 0x52CD, 0xD0EE, 0x530E, 0xD0EF, 0x539E, 0xD0F0, 0x5526, 0xD0F1, 0x54E2, 0xD0F2, 0x5517, 0xD0F3, 0x5512, 0xD0F4, 0x54E7, + 0xD0F5, 0x54F3, 0xD0F6, 0x54E4, 0xD0F7, 0x551A, 0xD0F8, 0x54FF, 0xD0F9, 0x5504, 0xD0FA, 0x5508, 0xD0FB, 0x54EB, 0xD0FC, 0x5511, + 0xD0FD, 0x5505, 0xD0FE, 0x54F1, 0xD140, 0x550A, 0xD141, 0x54FB, 0xD142, 0x54F7, 0xD143, 0x54F8, 0xD144, 0x54E0, 0xD145, 0x550E, + 0xD146, 0x5503, 0xD147, 0x550B, 0xD148, 0x5701, 0xD149, 0x5702, 0xD14A, 0x57CC, 0xD14B, 0x5832, 0xD14C, 0x57D5, 0xD14D, 0x57D2, + 0xD14E, 0x57BA, 0xD14F, 0x57C6, 0xD150, 0x57BD, 0xD151, 0x57BC, 0xD152, 0x57B8, 0xD153, 0x57B6, 0xD154, 0x57BF, 0xD155, 0x57C7, + 0xD156, 0x57D0, 0xD157, 0x57B9, 0xD158, 0x57C1, 0xD159, 0x590E, 0xD15A, 0x594A, 0xD15B, 0x5A19, 0xD15C, 0x5A16, 0xD15D, 0x5A2D, + 0xD15E, 0x5A2E, 0xD15F, 0x5A15, 0xD160, 0x5A0F, 0xD161, 0x5A17, 0xD162, 0x5A0A, 0xD163, 0x5A1E, 0xD164, 0x5A33, 0xD165, 0x5B6C, + 0xD166, 0x5BA7, 0xD167, 0x5BAD, 0xD168, 0x5BAC, 0xD169, 0x5C03, 0xD16A, 0x5C56, 0xD16B, 0x5C54, 0xD16C, 0x5CEC, 0xD16D, 0x5CFF, + 0xD16E, 0x5CEE, 0xD16F, 0x5CF1, 0xD170, 0x5CF7, 0xD171, 0x5D00, 0xD172, 0x5CF9, 0xD173, 0x5E29, 0xD174, 0x5E28, 0xD175, 0x5EA8, + 0xD176, 0x5EAE, 0xD177, 0x5EAA, 0xD178, 0x5EAC, 0xD179, 0x5F33, 0xD17A, 0x5F30, 0xD17B, 0x5F67, 0xD17C, 0x605D, 0xD17D, 0x605A, + 0xD17E, 0x6067, 0xD1A1, 0x6041, 0xD1A2, 0x60A2, 0xD1A3, 0x6088, 0xD1A4, 0x6080, 0xD1A5, 0x6092, 0xD1A6, 0x6081, 0xD1A7, 0x609D, + 0xD1A8, 0x6083, 0xD1A9, 0x6095, 0xD1AA, 0x609B, 0xD1AB, 0x6097, 0xD1AC, 0x6087, 0xD1AD, 0x609C, 0xD1AE, 0x608E, 0xD1AF, 0x6219, + 0xD1B0, 0x6246, 0xD1B1, 0x62F2, 0xD1B2, 0x6310, 0xD1B3, 0x6356, 0xD1B4, 0x632C, 0xD1B5, 0x6344, 0xD1B6, 0x6345, 0xD1B7, 0x6336, + 0xD1B8, 0x6343, 0xD1B9, 0x63E4, 0xD1BA, 0x6339, 0xD1BB, 0x634B, 0xD1BC, 0x634A, 0xD1BD, 0x633C, 0xD1BE, 0x6329, 0xD1BF, 0x6341, + 0xD1C0, 0x6334, 0xD1C1, 0x6358, 0xD1C2, 0x6354, 0xD1C3, 0x6359, 0xD1C4, 0x632D, 0xD1C5, 0x6347, 0xD1C6, 0x6333, 0xD1C7, 0x635A, + 0xD1C8, 0x6351, 0xD1C9, 0x6338, 0xD1CA, 0x6357, 0xD1CB, 0x6340, 0xD1CC, 0x6348, 0xD1CD, 0x654A, 0xD1CE, 0x6546, 0xD1CF, 0x65C6, + 0xD1D0, 0x65C3, 0xD1D1, 0x65C4, 0xD1D2, 0x65C2, 0xD1D3, 0x664A, 0xD1D4, 0x665F, 0xD1D5, 0x6647, 0xD1D6, 0x6651, 0xD1D7, 0x6712, + 0xD1D8, 0x6713, 0xD1D9, 0x681F, 0xD1DA, 0x681A, 0xD1DB, 0x6849, 0xD1DC, 0x6832, 0xD1DD, 0x6833, 0xD1DE, 0x683B, 0xD1DF, 0x684B, + 0xD1E0, 0x684F, 0xD1E1, 0x6816, 0xD1E2, 0x6831, 0xD1E3, 0x681C, 0xD1E4, 0x6835, 0xD1E5, 0x682B, 0xD1E6, 0x682D, 0xD1E7, 0x682F, + 0xD1E8, 0x684E, 0xD1E9, 0x6844, 0xD1EA, 0x6834, 0xD1EB, 0x681D, 0xD1EC, 0x6812, 0xD1ED, 0x6814, 0xD1EE, 0x6826, 0xD1EF, 0x6828, + 0xD1F0, 0x682E, 0xD1F1, 0x684D, 0xD1F2, 0x683A, 0xD1F3, 0x6825, 0xD1F4, 0x6820, 0xD1F5, 0x6B2C, 0xD1F6, 0x6B2F, 0xD1F7, 0x6B2D, + 0xD1F8, 0x6B31, 0xD1F9, 0x6B34, 0xD1FA, 0x6B6D, 0xD1FB, 0x8082, 0xD1FC, 0x6B88, 0xD1FD, 0x6BE6, 0xD1FE, 0x6BE4, 0xD240, 0x6BE8, + 0xD241, 0x6BE3, 0xD242, 0x6BE2, 0xD243, 0x6BE7, 0xD244, 0x6C25, 0xD245, 0x6D7A, 0xD246, 0x6D63, 0xD247, 0x6D64, 0xD248, 0x6D76, + 0xD249, 0x6D0D, 0xD24A, 0x6D61, 0xD24B, 0x6D92, 0xD24C, 0x6D58, 0xD24D, 0x6D62, 0xD24E, 0x6D6D, 0xD24F, 0x6D6F, 0xD250, 0x6D91, + 0xD251, 0x6D8D, 0xD252, 0x6DEF, 0xD253, 0x6D7F, 0xD254, 0x6D86, 0xD255, 0x6D5E, 0xD256, 0x6D67, 0xD257, 0x6D60, 0xD258, 0x6D97, + 0xD259, 0x6D70, 0xD25A, 0x6D7C, 0xD25B, 0x6D5F, 0xD25C, 0x6D82, 0xD25D, 0x6D98, 0xD25E, 0x6D2F, 0xD25F, 0x6D68, 0xD260, 0x6D8B, + 0xD261, 0x6D7E, 0xD262, 0x6D80, 0xD263, 0x6D84, 0xD264, 0x6D16, 0xD265, 0x6D83, 0xD266, 0x6D7B, 0xD267, 0x6D7D, 0xD268, 0x6D75, + 0xD269, 0x6D90, 0xD26A, 0x70DC, 0xD26B, 0x70D3, 0xD26C, 0x70D1, 0xD26D, 0x70DD, 0xD26E, 0x70CB, 0xD26F, 0x7F39, 0xD270, 0x70E2, + 0xD271, 0x70D7, 0xD272, 0x70D2, 0xD273, 0x70DE, 0xD274, 0x70E0, 0xD275, 0x70D4, 0xD276, 0x70CD, 0xD277, 0x70C5, 0xD278, 0x70C6, + 0xD279, 0x70C7, 0xD27A, 0x70DA, 0xD27B, 0x70CE, 0xD27C, 0x70E1, 0xD27D, 0x7242, 0xD27E, 0x7278, 0xD2A1, 0x7277, 0xD2A2, 0x7276, + 0xD2A3, 0x7300, 0xD2A4, 0x72FA, 0xD2A5, 0x72F4, 0xD2A6, 0x72FE, 0xD2A7, 0x72F6, 0xD2A8, 0x72F3, 0xD2A9, 0x72FB, 0xD2AA, 0x7301, + 0xD2AB, 0x73D3, 0xD2AC, 0x73D9, 0xD2AD, 0x73E5, 0xD2AE, 0x73D6, 0xD2AF, 0x73BC, 0xD2B0, 0x73E7, 0xD2B1, 0x73E3, 0xD2B2, 0x73E9, + 0xD2B3, 0x73DC, 0xD2B4, 0x73D2, 0xD2B5, 0x73DB, 0xD2B6, 0x73D4, 0xD2B7, 0x73DD, 0xD2B8, 0x73DA, 0xD2B9, 0x73D7, 0xD2BA, 0x73D8, + 0xD2BB, 0x73E8, 0xD2BC, 0x74DE, 0xD2BD, 0x74DF, 0xD2BE, 0x74F4, 0xD2BF, 0x74F5, 0xD2C0, 0x7521, 0xD2C1, 0x755B, 0xD2C2, 0x755F, + 0xD2C3, 0x75B0, 0xD2C4, 0x75C1, 0xD2C5, 0x75BB, 0xD2C6, 0x75C4, 0xD2C7, 0x75C0, 0xD2C8, 0x75BF, 0xD2C9, 0x75B6, 0xD2CA, 0x75BA, + 0xD2CB, 0x768A, 0xD2CC, 0x76C9, 0xD2CD, 0x771D, 0xD2CE, 0x771B, 0xD2CF, 0x7710, 0xD2D0, 0x7713, 0xD2D1, 0x7712, 0xD2D2, 0x7723, + 0xD2D3, 0x7711, 0xD2D4, 0x7715, 0xD2D5, 0x7719, 0xD2D6, 0x771A, 0xD2D7, 0x7722, 0xD2D8, 0x7727, 0xD2D9, 0x7823, 0xD2DA, 0x782C, + 0xD2DB, 0x7822, 0xD2DC, 0x7835, 0xD2DD, 0x782F, 0xD2DE, 0x7828, 0xD2DF, 0x782E, 0xD2E0, 0x782B, 0xD2E1, 0x7821, 0xD2E2, 0x7829, + 0xD2E3, 0x7833, 0xD2E4, 0x782A, 0xD2E5, 0x7831, 0xD2E6, 0x7954, 0xD2E7, 0x795B, 0xD2E8, 0x794F, 0xD2E9, 0x795C, 0xD2EA, 0x7953, + 0xD2EB, 0x7952, 0xD2EC, 0x7951, 0xD2ED, 0x79EB, 0xD2EE, 0x79EC, 0xD2EF, 0x79E0, 0xD2F0, 0x79EE, 0xD2F1, 0x79ED, 0xD2F2, 0x79EA, + 0xD2F3, 0x79DC, 0xD2F4, 0x79DE, 0xD2F5, 0x79DD, 0xD2F6, 0x7A86, 0xD2F7, 0x7A89, 0xD2F8, 0x7A85, 0xD2F9, 0x7A8B, 0xD2FA, 0x7A8C, + 0xD2FB, 0x7A8A, 0xD2FC, 0x7A87, 0xD2FD, 0x7AD8, 0xD2FE, 0x7B10, 0xD340, 0x7B04, 0xD341, 0x7B13, 0xD342, 0x7B05, 0xD343, 0x7B0F, + 0xD344, 0x7B08, 0xD345, 0x7B0A, 0xD346, 0x7B0E, 0xD347, 0x7B09, 0xD348, 0x7B12, 0xD349, 0x7C84, 0xD34A, 0x7C91, 0xD34B, 0x7C8A, + 0xD34C, 0x7C8C, 0xD34D, 0x7C88, 0xD34E, 0x7C8D, 0xD34F, 0x7C85, 0xD350, 0x7D1E, 0xD351, 0x7D1D, 0xD352, 0x7D11, 0xD353, 0x7D0E, + 0xD354, 0x7D18, 0xD355, 0x7D16, 0xD356, 0x7D13, 0xD357, 0x7D1F, 0xD358, 0x7D12, 0xD359, 0x7D0F, 0xD35A, 0x7D0C, 0xD35B, 0x7F5C, + 0xD35C, 0x7F61, 0xD35D, 0x7F5E, 0xD35E, 0x7F60, 0xD35F, 0x7F5D, 0xD360, 0x7F5B, 0xD361, 0x7F96, 0xD362, 0x7F92, 0xD363, 0x7FC3, + 0xD364, 0x7FC2, 0xD365, 0x7FC0, 0xD366, 0x8016, 0xD367, 0x803E, 0xD368, 0x8039, 0xD369, 0x80FA, 0xD36A, 0x80F2, 0xD36B, 0x80F9, + 0xD36C, 0x80F5, 0xD36D, 0x8101, 0xD36E, 0x80FB, 0xD36F, 0x8100, 0xD370, 0x8201, 0xD371, 0x822F, 0xD372, 0x8225, 0xD373, 0x8333, + 0xD374, 0x832D, 0xD375, 0x8344, 0xD376, 0x8319, 0xD377, 0x8351, 0xD378, 0x8325, 0xD379, 0x8356, 0xD37A, 0x833F, 0xD37B, 0x8341, + 0xD37C, 0x8326, 0xD37D, 0x831C, 0xD37E, 0x8322, 0xD3A1, 0x8342, 0xD3A2, 0x834E, 0xD3A3, 0x831B, 0xD3A4, 0x832A, 0xD3A5, 0x8308, + 0xD3A6, 0x833C, 0xD3A7, 0x834D, 0xD3A8, 0x8316, 0xD3A9, 0x8324, 0xD3AA, 0x8320, 0xD3AB, 0x8337, 0xD3AC, 0x832F, 0xD3AD, 0x8329, + 0xD3AE, 0x8347, 0xD3AF, 0x8345, 0xD3B0, 0x834C, 0xD3B1, 0x8353, 0xD3B2, 0x831E, 0xD3B3, 0x832C, 0xD3B4, 0x834B, 0xD3B5, 0x8327, + 0xD3B6, 0x8348, 0xD3B7, 0x8653, 0xD3B8, 0x8652, 0xD3B9, 0x86A2, 0xD3BA, 0x86A8, 0xD3BB, 0x8696, 0xD3BC, 0x868D, 0xD3BD, 0x8691, + 0xD3BE, 0x869E, 0xD3BF, 0x8687, 0xD3C0, 0x8697, 0xD3C1, 0x8686, 0xD3C2, 0x868B, 0xD3C3, 0x869A, 0xD3C4, 0x8685, 0xD3C5, 0x86A5, + 0xD3C6, 0x8699, 0xD3C7, 0x86A1, 0xD3C8, 0x86A7, 0xD3C9, 0x8695, 0xD3CA, 0x8698, 0xD3CB, 0x868E, 0xD3CC, 0x869D, 0xD3CD, 0x8690, + 0xD3CE, 0x8694, 0xD3CF, 0x8843, 0xD3D0, 0x8844, 0xD3D1, 0x886D, 0xD3D2, 0x8875, 0xD3D3, 0x8876, 0xD3D4, 0x8872, 0xD3D5, 0x8880, + 0xD3D6, 0x8871, 0xD3D7, 0x887F, 0xD3D8, 0x886F, 0xD3D9, 0x8883, 0xD3DA, 0x887E, 0xD3DB, 0x8874, 0xD3DC, 0x887C, 0xD3DD, 0x8A12, + 0xD3DE, 0x8C47, 0xD3DF, 0x8C57, 0xD3E0, 0x8C7B, 0xD3E1, 0x8CA4, 0xD3E2, 0x8CA3, 0xD3E3, 0x8D76, 0xD3E4, 0x8D78, 0xD3E5, 0x8DB5, + 0xD3E6, 0x8DB7, 0xD3E7, 0x8DB6, 0xD3E8, 0x8ED1, 0xD3E9, 0x8ED3, 0xD3EA, 0x8FFE, 0xD3EB, 0x8FF5, 0xD3EC, 0x9002, 0xD3ED, 0x8FFF, + 0xD3EE, 0x8FFB, 0xD3EF, 0x9004, 0xD3F0, 0x8FFC, 0xD3F1, 0x8FF6, 0xD3F2, 0x90D6, 0xD3F3, 0x90E0, 0xD3F4, 0x90D9, 0xD3F5, 0x90DA, + 0xD3F6, 0x90E3, 0xD3F7, 0x90DF, 0xD3F8, 0x90E5, 0xD3F9, 0x90D8, 0xD3FA, 0x90DB, 0xD3FB, 0x90D7, 0xD3FC, 0x90DC, 0xD3FD, 0x90E4, + 0xD3FE, 0x9150, 0xD440, 0x914E, 0xD441, 0x914F, 0xD442, 0x91D5, 0xD443, 0x91E2, 0xD444, 0x91DA, 0xD445, 0x965C, 0xD446, 0x965F, + 0xD447, 0x96BC, 0xD448, 0x98E3, 0xD449, 0x9ADF, 0xD44A, 0x9B2F, 0xD44B, 0x4E7F, 0xD44C, 0x5070, 0xD44D, 0x506A, 0xD44E, 0x5061, + 0xD44F, 0x505E, 0xD450, 0x5060, 0xD451, 0x5053, 0xD452, 0x504B, 0xD453, 0x505D, 0xD454, 0x5072, 0xD455, 0x5048, 0xD456, 0x504D, + 0xD457, 0x5041, 0xD458, 0x505B, 0xD459, 0x504A, 0xD45A, 0x5062, 0xD45B, 0x5015, 0xD45C, 0x5045, 0xD45D, 0x505F, 0xD45E, 0x5069, + 0xD45F, 0x506B, 0xD460, 0x5063, 0xD461, 0x5064, 0xD462, 0x5046, 0xD463, 0x5040, 0xD464, 0x506E, 0xD465, 0x5073, 0xD466, 0x5057, + 0xD467, 0x5051, 0xD468, 0x51D0, 0xD469, 0x526B, 0xD46A, 0x526D, 0xD46B, 0x526C, 0xD46C, 0x526E, 0xD46D, 0x52D6, 0xD46E, 0x52D3, + 0xD46F, 0x532D, 0xD470, 0x539C, 0xD471, 0x5575, 0xD472, 0x5576, 0xD473, 0x553C, 0xD474, 0x554D, 0xD475, 0x5550, 0xD476, 0x5534, + 0xD477, 0x552A, 0xD478, 0x5551, 0xD479, 0x5562, 0xD47A, 0x5536, 0xD47B, 0x5535, 0xD47C, 0x5530, 0xD47D, 0x5552, 0xD47E, 0x5545, + 0xD4A1, 0x550C, 0xD4A2, 0x5532, 0xD4A3, 0x5565, 0xD4A4, 0x554E, 0xD4A5, 0x5539, 0xD4A6, 0x5548, 0xD4A7, 0x552D, 0xD4A8, 0x553B, + 0xD4A9, 0x5540, 0xD4AA, 0x554B, 0xD4AB, 0x570A, 0xD4AC, 0x5707, 0xD4AD, 0x57FB, 0xD4AE, 0x5814, 0xD4AF, 0x57E2, 0xD4B0, 0x57F6, + 0xD4B1, 0x57DC, 0xD4B2, 0x57F4, 0xD4B3, 0x5800, 0xD4B4, 0x57ED, 0xD4B5, 0x57FD, 0xD4B6, 0x5808, 0xD4B7, 0x57F8, 0xD4B8, 0x580B, + 0xD4B9, 0x57F3, 0xD4BA, 0x57CF, 0xD4BB, 0x5807, 0xD4BC, 0x57EE, 0xD4BD, 0x57E3, 0xD4BE, 0x57F2, 0xD4BF, 0x57E5, 0xD4C0, 0x57EC, + 0xD4C1, 0x57E1, 0xD4C2, 0x580E, 0xD4C3, 0x57FC, 0xD4C4, 0x5810, 0xD4C5, 0x57E7, 0xD4C6, 0x5801, 0xD4C7, 0x580C, 0xD4C8, 0x57F1, + 0xD4C9, 0x57E9, 0xD4CA, 0x57F0, 0xD4CB, 0x580D, 0xD4CC, 0x5804, 0xD4CD, 0x595C, 0xD4CE, 0x5A60, 0xD4CF, 0x5A58, 0xD4D0, 0x5A55, + 0xD4D1, 0x5A67, 0xD4D2, 0x5A5E, 0xD4D3, 0x5A38, 0xD4D4, 0x5A35, 0xD4D5, 0x5A6D, 0xD4D6, 0x5A50, 0xD4D7, 0x5A5F, 0xD4D8, 0x5A65, + 0xD4D9, 0x5A6C, 0xD4DA, 0x5A53, 0xD4DB, 0x5A64, 0xD4DC, 0x5A57, 0xD4DD, 0x5A43, 0xD4DE, 0x5A5D, 0xD4DF, 0x5A52, 0xD4E0, 0x5A44, + 0xD4E1, 0x5A5B, 0xD4E2, 0x5A48, 0xD4E3, 0x5A8E, 0xD4E4, 0x5A3E, 0xD4E5, 0x5A4D, 0xD4E6, 0x5A39, 0xD4E7, 0x5A4C, 0xD4E8, 0x5A70, + 0xD4E9, 0x5A69, 0xD4EA, 0x5A47, 0xD4EB, 0x5A51, 0xD4EC, 0x5A56, 0xD4ED, 0x5A42, 0xD4EE, 0x5A5C, 0xD4EF, 0x5B72, 0xD4F0, 0x5B6E, + 0xD4F1, 0x5BC1, 0xD4F2, 0x5BC0, 0xD4F3, 0x5C59, 0xD4F4, 0x5D1E, 0xD4F5, 0x5D0B, 0xD4F6, 0x5D1D, 0xD4F7, 0x5D1A, 0xD4F8, 0x5D20, + 0xD4F9, 0x5D0C, 0xD4FA, 0x5D28, 0xD4FB, 0x5D0D, 0xD4FC, 0x5D26, 0xD4FD, 0x5D25, 0xD4FE, 0x5D0F, 0xD540, 0x5D30, 0xD541, 0x5D12, + 0xD542, 0x5D23, 0xD543, 0x5D1F, 0xD544, 0x5D2E, 0xD545, 0x5E3E, 0xD546, 0x5E34, 0xD547, 0x5EB1, 0xD548, 0x5EB4, 0xD549, 0x5EB9, + 0xD54A, 0x5EB2, 0xD54B, 0x5EB3, 0xD54C, 0x5F36, 0xD54D, 0x5F38, 0xD54E, 0x5F9B, 0xD54F, 0x5F96, 0xD550, 0x5F9F, 0xD551, 0x608A, + 0xD552, 0x6090, 0xD553, 0x6086, 0xD554, 0x60BE, 0xD555, 0x60B0, 0xD556, 0x60BA, 0xD557, 0x60D3, 0xD558, 0x60D4, 0xD559, 0x60CF, + 0xD55A, 0x60E4, 0xD55B, 0x60D9, 0xD55C, 0x60DD, 0xD55D, 0x60C8, 0xD55E, 0x60B1, 0xD55F, 0x60DB, 0xD560, 0x60B7, 0xD561, 0x60CA, + 0xD562, 0x60BF, 0xD563, 0x60C3, 0xD564, 0x60CD, 0xD565, 0x60C0, 0xD566, 0x6332, 0xD567, 0x6365, 0xD568, 0x638A, 0xD569, 0x6382, + 0xD56A, 0x637D, 0xD56B, 0x63BD, 0xD56C, 0x639E, 0xD56D, 0x63AD, 0xD56E, 0x639D, 0xD56F, 0x6397, 0xD570, 0x63AB, 0xD571, 0x638E, + 0xD572, 0x636F, 0xD573, 0x6387, 0xD574, 0x6390, 0xD575, 0x636E, 0xD576, 0x63AF, 0xD577, 0x6375, 0xD578, 0x639C, 0xD579, 0x636D, + 0xD57A, 0x63AE, 0xD57B, 0x637C, 0xD57C, 0x63A4, 0xD57D, 0x633B, 0xD57E, 0x639F, 0xD5A1, 0x6378, 0xD5A2, 0x6385, 0xD5A3, 0x6381, + 0xD5A4, 0x6391, 0xD5A5, 0x638D, 0xD5A6, 0x6370, 0xD5A7, 0x6553, 0xD5A8, 0x65CD, 0xD5A9, 0x6665, 0xD5AA, 0x6661, 0xD5AB, 0x665B, + 0xD5AC, 0x6659, 0xD5AD, 0x665C, 0xD5AE, 0x6662, 0xD5AF, 0x6718, 0xD5B0, 0x6879, 0xD5B1, 0x6887, 0xD5B2, 0x6890, 0xD5B3, 0x689C, + 0xD5B4, 0x686D, 0xD5B5, 0x686E, 0xD5B6, 0x68AE, 0xD5B7, 0x68AB, 0xD5B8, 0x6956, 0xD5B9, 0x686F, 0xD5BA, 0x68A3, 0xD5BB, 0x68AC, + 0xD5BC, 0x68A9, 0xD5BD, 0x6875, 0xD5BE, 0x6874, 0xD5BF, 0x68B2, 0xD5C0, 0x688F, 0xD5C1, 0x6877, 0xD5C2, 0x6892, 0xD5C3, 0x687C, + 0xD5C4, 0x686B, 0xD5C5, 0x6872, 0xD5C6, 0x68AA, 0xD5C7, 0x6880, 0xD5C8, 0x6871, 0xD5C9, 0x687E, 0xD5CA, 0x689B, 0xD5CB, 0x6896, + 0xD5CC, 0x688B, 0xD5CD, 0x68A0, 0xD5CE, 0x6889, 0xD5CF, 0x68A4, 0xD5D0, 0x6878, 0xD5D1, 0x687B, 0xD5D2, 0x6891, 0xD5D3, 0x688C, + 0xD5D4, 0x688A, 0xD5D5, 0x687D, 0xD5D6, 0x6B36, 0xD5D7, 0x6B33, 0xD5D8, 0x6B37, 0xD5D9, 0x6B38, 0xD5DA, 0x6B91, 0xD5DB, 0x6B8F, + 0xD5DC, 0x6B8D, 0xD5DD, 0x6B8E, 0xD5DE, 0x6B8C, 0xD5DF, 0x6C2A, 0xD5E0, 0x6DC0, 0xD5E1, 0x6DAB, 0xD5E2, 0x6DB4, 0xD5E3, 0x6DB3, + 0xD5E4, 0x6E74, 0xD5E5, 0x6DAC, 0xD5E6, 0x6DE9, 0xD5E7, 0x6DE2, 0xD5E8, 0x6DB7, 0xD5E9, 0x6DF6, 0xD5EA, 0x6DD4, 0xD5EB, 0x6E00, + 0xD5EC, 0x6DC8, 0xD5ED, 0x6DE0, 0xD5EE, 0x6DDF, 0xD5EF, 0x6DD6, 0xD5F0, 0x6DBE, 0xD5F1, 0x6DE5, 0xD5F2, 0x6DDC, 0xD5F3, 0x6DDD, + 0xD5F4, 0x6DDB, 0xD5F5, 0x6DF4, 0xD5F6, 0x6DCA, 0xD5F7, 0x6DBD, 0xD5F8, 0x6DED, 0xD5F9, 0x6DF0, 0xD5FA, 0x6DBA, 0xD5FB, 0x6DD5, + 0xD5FC, 0x6DC2, 0xD5FD, 0x6DCF, 0xD5FE, 0x6DC9, 0xD640, 0x6DD0, 0xD641, 0x6DF2, 0xD642, 0x6DD3, 0xD643, 0x6DFD, 0xD644, 0x6DD7, + 0xD645, 0x6DCD, 0xD646, 0x6DE3, 0xD647, 0x6DBB, 0xD648, 0x70FA, 0xD649, 0x710D, 0xD64A, 0x70F7, 0xD64B, 0x7117, 0xD64C, 0x70F4, + 0xD64D, 0x710C, 0xD64E, 0x70F0, 0xD64F, 0x7104, 0xD650, 0x70F3, 0xD651, 0x7110, 0xD652, 0x70FC, 0xD653, 0x70FF, 0xD654, 0x7106, + 0xD655, 0x7113, 0xD656, 0x7100, 0xD657, 0x70F8, 0xD658, 0x70F6, 0xD659, 0x710B, 0xD65A, 0x7102, 0xD65B, 0x710E, 0xD65C, 0x727E, + 0xD65D, 0x727B, 0xD65E, 0x727C, 0xD65F, 0x727F, 0xD660, 0x731D, 0xD661, 0x7317, 0xD662, 0x7307, 0xD663, 0x7311, 0xD664, 0x7318, + 0xD665, 0x730A, 0xD666, 0x7308, 0xD667, 0x72FF, 0xD668, 0x730F, 0xD669, 0x731E, 0xD66A, 0x7388, 0xD66B, 0x73F6, 0xD66C, 0x73F8, + 0xD66D, 0x73F5, 0xD66E, 0x7404, 0xD66F, 0x7401, 0xD670, 0x73FD, 0xD671, 0x7407, 0xD672, 0x7400, 0xD673, 0x73FA, 0xD674, 0x73FC, + 0xD675, 0x73FF, 0xD676, 0x740C, 0xD677, 0x740B, 0xD678, 0x73F4, 0xD679, 0x7408, 0xD67A, 0x7564, 0xD67B, 0x7563, 0xD67C, 0x75CE, + 0xD67D, 0x75D2, 0xD67E, 0x75CF, 0xD6A1, 0x75CB, 0xD6A2, 0x75CC, 0xD6A3, 0x75D1, 0xD6A4, 0x75D0, 0xD6A5, 0x768F, 0xD6A6, 0x7689, + 0xD6A7, 0x76D3, 0xD6A8, 0x7739, 0xD6A9, 0x772F, 0xD6AA, 0x772D, 0xD6AB, 0x7731, 0xD6AC, 0x7732, 0xD6AD, 0x7734, 0xD6AE, 0x7733, + 0xD6AF, 0x773D, 0xD6B0, 0x7725, 0xD6B1, 0x773B, 0xD6B2, 0x7735, 0xD6B3, 0x7848, 0xD6B4, 0x7852, 0xD6B5, 0x7849, 0xD6B6, 0x784D, + 0xD6B7, 0x784A, 0xD6B8, 0x784C, 0xD6B9, 0x7826, 0xD6BA, 0x7845, 0xD6BB, 0x7850, 0xD6BC, 0x7964, 0xD6BD, 0x7967, 0xD6BE, 0x7969, + 0xD6BF, 0x796A, 0xD6C0, 0x7963, 0xD6C1, 0x796B, 0xD6C2, 0x7961, 0xD6C3, 0x79BB, 0xD6C4, 0x79FA, 0xD6C5, 0x79F8, 0xD6C6, 0x79F6, + 0xD6C7, 0x79F7, 0xD6C8, 0x7A8F, 0xD6C9, 0x7A94, 0xD6CA, 0x7A90, 0xD6CB, 0x7B35, 0xD6CC, 0x7B47, 0xD6CD, 0x7B34, 0xD6CE, 0x7B25, + 0xD6CF, 0x7B30, 0xD6D0, 0x7B22, 0xD6D1, 0x7B24, 0xD6D2, 0x7B33, 0xD6D3, 0x7B18, 0xD6D4, 0x7B2A, 0xD6D5, 0x7B1D, 0xD6D6, 0x7B31, + 0xD6D7, 0x7B2B, 0xD6D8, 0x7B2D, 0xD6D9, 0x7B2F, 0xD6DA, 0x7B32, 0xD6DB, 0x7B38, 0xD6DC, 0x7B1A, 0xD6DD, 0x7B23, 0xD6DE, 0x7C94, + 0xD6DF, 0x7C98, 0xD6E0, 0x7C96, 0xD6E1, 0x7CA3, 0xD6E2, 0x7D35, 0xD6E3, 0x7D3D, 0xD6E4, 0x7D38, 0xD6E5, 0x7D36, 0xD6E6, 0x7D3A, + 0xD6E7, 0x7D45, 0xD6E8, 0x7D2C, 0xD6E9, 0x7D29, 0xD6EA, 0x7D41, 0xD6EB, 0x7D47, 0xD6EC, 0x7D3E, 0xD6ED, 0x7D3F, 0xD6EE, 0x7D4A, + 0xD6EF, 0x7D3B, 0xD6F0, 0x7D28, 0xD6F1, 0x7F63, 0xD6F2, 0x7F95, 0xD6F3, 0x7F9C, 0xD6F4, 0x7F9D, 0xD6F5, 0x7F9B, 0xD6F6, 0x7FCA, + 0xD6F7, 0x7FCB, 0xD6F8, 0x7FCD, 0xD6F9, 0x7FD0, 0xD6FA, 0x7FD1, 0xD6FB, 0x7FC7, 0xD6FC, 0x7FCF, 0xD6FD, 0x7FC9, 0xD6FE, 0x801F, + 0xD740, 0x801E, 0xD741, 0x801B, 0xD742, 0x8047, 0xD743, 0x8043, 0xD744, 0x8048, 0xD745, 0x8118, 0xD746, 0x8125, 0xD747, 0x8119, + 0xD748, 0x811B, 0xD749, 0x812D, 0xD74A, 0x811F, 0xD74B, 0x812C, 0xD74C, 0x811E, 0xD74D, 0x8121, 0xD74E, 0x8115, 0xD74F, 0x8127, + 0xD750, 0x811D, 0xD751, 0x8122, 0xD752, 0x8211, 0xD753, 0x8238, 0xD754, 0x8233, 0xD755, 0x823A, 0xD756, 0x8234, 0xD757, 0x8232, + 0xD758, 0x8274, 0xD759, 0x8390, 0xD75A, 0x83A3, 0xD75B, 0x83A8, 0xD75C, 0x838D, 0xD75D, 0x837A, 0xD75E, 0x8373, 0xD75F, 0x83A4, + 0xD760, 0x8374, 0xD761, 0x838F, 0xD762, 0x8381, 0xD763, 0x8395, 0xD764, 0x8399, 0xD765, 0x8375, 0xD766, 0x8394, 0xD767, 0x83A9, + 0xD768, 0x837D, 0xD769, 0x8383, 0xD76A, 0x838C, 0xD76B, 0x839D, 0xD76C, 0x839B, 0xD76D, 0x83AA, 0xD76E, 0x838B, 0xD76F, 0x837E, + 0xD770, 0x83A5, 0xD771, 0x83AF, 0xD772, 0x8388, 0xD773, 0x8397, 0xD774, 0x83B0, 0xD775, 0x837F, 0xD776, 0x83A6, 0xD777, 0x8387, + 0xD778, 0x83AE, 0xD779, 0x8376, 0xD77A, 0x839A, 0xD77B, 0x8659, 0xD77C, 0x8656, 0xD77D, 0x86BF, 0xD77E, 0x86B7, 0xD7A1, 0x86C2, + 0xD7A2, 0x86C1, 0xD7A3, 0x86C5, 0xD7A4, 0x86BA, 0xD7A5, 0x86B0, 0xD7A6, 0x86C8, 0xD7A7, 0x86B9, 0xD7A8, 0x86B3, 0xD7A9, 0x86B8, + 0xD7AA, 0x86CC, 0xD7AB, 0x86B4, 0xD7AC, 0x86BB, 0xD7AD, 0x86BC, 0xD7AE, 0x86C3, 0xD7AF, 0x86BD, 0xD7B0, 0x86BE, 0xD7B1, 0x8852, + 0xD7B2, 0x8889, 0xD7B3, 0x8895, 0xD7B4, 0x88A8, 0xD7B5, 0x88A2, 0xD7B6, 0x88AA, 0xD7B7, 0x889A, 0xD7B8, 0x8891, 0xD7B9, 0x88A1, + 0xD7BA, 0x889F, 0xD7BB, 0x8898, 0xD7BC, 0x88A7, 0xD7BD, 0x8899, 0xD7BE, 0x889B, 0xD7BF, 0x8897, 0xD7C0, 0x88A4, 0xD7C1, 0x88AC, + 0xD7C2, 0x888C, 0xD7C3, 0x8893, 0xD7C4, 0x888E, 0xD7C5, 0x8982, 0xD7C6, 0x89D6, 0xD7C7, 0x89D9, 0xD7C8, 0x89D5, 0xD7C9, 0x8A30, + 0xD7CA, 0x8A27, 0xD7CB, 0x8A2C, 0xD7CC, 0x8A1E, 0xD7CD, 0x8C39, 0xD7CE, 0x8C3B, 0xD7CF, 0x8C5C, 0xD7D0, 0x8C5D, 0xD7D1, 0x8C7D, + 0xD7D2, 0x8CA5, 0xD7D3, 0x8D7D, 0xD7D4, 0x8D7B, 0xD7D5, 0x8D79, 0xD7D6, 0x8DBC, 0xD7D7, 0x8DC2, 0xD7D8, 0x8DB9, 0xD7D9, 0x8DBF, + 0xD7DA, 0x8DC1, 0xD7DB, 0x8ED8, 0xD7DC, 0x8EDE, 0xD7DD, 0x8EDD, 0xD7DE, 0x8EDC, 0xD7DF, 0x8ED7, 0xD7E0, 0x8EE0, 0xD7E1, 0x8EE1, + 0xD7E2, 0x9024, 0xD7E3, 0x900B, 0xD7E4, 0x9011, 0xD7E5, 0x901C, 0xD7E6, 0x900C, 0xD7E7, 0x9021, 0xD7E8, 0x90EF, 0xD7E9, 0x90EA, + 0xD7EA, 0x90F0, 0xD7EB, 0x90F4, 0xD7EC, 0x90F2, 0xD7ED, 0x90F3, 0xD7EE, 0x90D4, 0xD7EF, 0x90EB, 0xD7F0, 0x90EC, 0xD7F1, 0x90E9, + 0xD7F2, 0x9156, 0xD7F3, 0x9158, 0xD7F4, 0x915A, 0xD7F5, 0x9153, 0xD7F6, 0x9155, 0xD7F7, 0x91EC, 0xD7F8, 0x91F4, 0xD7F9, 0x91F1, + 0xD7FA, 0x91F3, 0xD7FB, 0x91F8, 0xD7FC, 0x91E4, 0xD7FD, 0x91F9, 0xD7FE, 0x91EA, 0xD840, 0x91EB, 0xD841, 0x91F7, 0xD842, 0x91E8, + 0xD843, 0x91EE, 0xD844, 0x957A, 0xD845, 0x9586, 0xD846, 0x9588, 0xD847, 0x967C, 0xD848, 0x966D, 0xD849, 0x966B, 0xD84A, 0x9671, + 0xD84B, 0x966F, 0xD84C, 0x96BF, 0xD84D, 0x976A, 0xD84E, 0x9804, 0xD84F, 0x98E5, 0xD850, 0x9997, 0xD851, 0x509B, 0xD852, 0x5095, + 0xD853, 0x5094, 0xD854, 0x509E, 0xD855, 0x508B, 0xD856, 0x50A3, 0xD857, 0x5083, 0xD858, 0x508C, 0xD859, 0x508E, 0xD85A, 0x509D, + 0xD85B, 0x5068, 0xD85C, 0x509C, 0xD85D, 0x5092, 0xD85E, 0x5082, 0xD85F, 0x5087, 0xD860, 0x515F, 0xD861, 0x51D4, 0xD862, 0x5312, + 0xD863, 0x5311, 0xD864, 0x53A4, 0xD865, 0x53A7, 0xD866, 0x5591, 0xD867, 0x55A8, 0xD868, 0x55A5, 0xD869, 0x55AD, 0xD86A, 0x5577, + 0xD86B, 0x5645, 0xD86C, 0x55A2, 0xD86D, 0x5593, 0xD86E, 0x5588, 0xD86F, 0x558F, 0xD870, 0x55B5, 0xD871, 0x5581, 0xD872, 0x55A3, + 0xD873, 0x5592, 0xD874, 0x55A4, 0xD875, 0x557D, 0xD876, 0x558C, 0xD877, 0x55A6, 0xD878, 0x557F, 0xD879, 0x5595, 0xD87A, 0x55A1, + 0xD87B, 0x558E, 0xD87C, 0x570C, 0xD87D, 0x5829, 0xD87E, 0x5837, 0xD8A1, 0x5819, 0xD8A2, 0x581E, 0xD8A3, 0x5827, 0xD8A4, 0x5823, + 0xD8A5, 0x5828, 0xD8A6, 0x57F5, 0xD8A7, 0x5848, 0xD8A8, 0x5825, 0xD8A9, 0x581C, 0xD8AA, 0x581B, 0xD8AB, 0x5833, 0xD8AC, 0x583F, + 0xD8AD, 0x5836, 0xD8AE, 0x582E, 0xD8AF, 0x5839, 0xD8B0, 0x5838, 0xD8B1, 0x582D, 0xD8B2, 0x582C, 0xD8B3, 0x583B, 0xD8B4, 0x5961, + 0xD8B5, 0x5AAF, 0xD8B6, 0x5A94, 0xD8B7, 0x5A9F, 0xD8B8, 0x5A7A, 0xD8B9, 0x5AA2, 0xD8BA, 0x5A9E, 0xD8BB, 0x5A78, 0xD8BC, 0x5AA6, + 0xD8BD, 0x5A7C, 0xD8BE, 0x5AA5, 0xD8BF, 0x5AAC, 0xD8C0, 0x5A95, 0xD8C1, 0x5AAE, 0xD8C2, 0x5A37, 0xD8C3, 0x5A84, 0xD8C4, 0x5A8A, + 0xD8C5, 0x5A97, 0xD8C6, 0x5A83, 0xD8C7, 0x5A8B, 0xD8C8, 0x5AA9, 0xD8C9, 0x5A7B, 0xD8CA, 0x5A7D, 0xD8CB, 0x5A8C, 0xD8CC, 0x5A9C, + 0xD8CD, 0x5A8F, 0xD8CE, 0x5A93, 0xD8CF, 0x5A9D, 0xD8D0, 0x5BEA, 0xD8D1, 0x5BCD, 0xD8D2, 0x5BCB, 0xD8D3, 0x5BD4, 0xD8D4, 0x5BD1, + 0xD8D5, 0x5BCA, 0xD8D6, 0x5BCE, 0xD8D7, 0x5C0C, 0xD8D8, 0x5C30, 0xD8D9, 0x5D37, 0xD8DA, 0x5D43, 0xD8DB, 0x5D6B, 0xD8DC, 0x5D41, + 0xD8DD, 0x5D4B, 0xD8DE, 0x5D3F, 0xD8DF, 0x5D35, 0xD8E0, 0x5D51, 0xD8E1, 0x5D4E, 0xD8E2, 0x5D55, 0xD8E3, 0x5D33, 0xD8E4, 0x5D3A, + 0xD8E5, 0x5D52, 0xD8E6, 0x5D3D, 0xD8E7, 0x5D31, 0xD8E8, 0x5D59, 0xD8E9, 0x5D42, 0xD8EA, 0x5D39, 0xD8EB, 0x5D49, 0xD8EC, 0x5D38, + 0xD8ED, 0x5D3C, 0xD8EE, 0x5D32, 0xD8EF, 0x5D36, 0xD8F0, 0x5D40, 0xD8F1, 0x5D45, 0xD8F2, 0x5E44, 0xD8F3, 0x5E41, 0xD8F4, 0x5F58, + 0xD8F5, 0x5FA6, 0xD8F6, 0x5FA5, 0xD8F7, 0x5FAB, 0xD8F8, 0x60C9, 0xD8F9, 0x60B9, 0xD8FA, 0x60CC, 0xD8FB, 0x60E2, 0xD8FC, 0x60CE, + 0xD8FD, 0x60C4, 0xD8FE, 0x6114, 0xD940, 0x60F2, 0xD941, 0x610A, 0xD942, 0x6116, 0xD943, 0x6105, 0xD944, 0x60F5, 0xD945, 0x6113, + 0xD946, 0x60F8, 0xD947, 0x60FC, 0xD948, 0x60FE, 0xD949, 0x60C1, 0xD94A, 0x6103, 0xD94B, 0x6118, 0xD94C, 0x611D, 0xD94D, 0x6110, + 0xD94E, 0x60FF, 0xD94F, 0x6104, 0xD950, 0x610B, 0xD951, 0x624A, 0xD952, 0x6394, 0xD953, 0x63B1, 0xD954, 0x63B0, 0xD955, 0x63CE, + 0xD956, 0x63E5, 0xD957, 0x63E8, 0xD958, 0x63EF, 0xD959, 0x63C3, 0xD95A, 0x649D, 0xD95B, 0x63F3, 0xD95C, 0x63CA, 0xD95D, 0x63E0, + 0xD95E, 0x63F6, 0xD95F, 0x63D5, 0xD960, 0x63F2, 0xD961, 0x63F5, 0xD962, 0x6461, 0xD963, 0x63DF, 0xD964, 0x63BE, 0xD965, 0x63DD, + 0xD966, 0x63DC, 0xD967, 0x63C4, 0xD968, 0x63D8, 0xD969, 0x63D3, 0xD96A, 0x63C2, 0xD96B, 0x63C7, 0xD96C, 0x63CC, 0xD96D, 0x63CB, + 0xD96E, 0x63C8, 0xD96F, 0x63F0, 0xD970, 0x63D7, 0xD971, 0x63D9, 0xD972, 0x6532, 0xD973, 0x6567, 0xD974, 0x656A, 0xD975, 0x6564, + 0xD976, 0x655C, 0xD977, 0x6568, 0xD978, 0x6565, 0xD979, 0x658C, 0xD97A, 0x659D, 0xD97B, 0x659E, 0xD97C, 0x65AE, 0xD97D, 0x65D0, + 0xD97E, 0x65D2, 0xD9A1, 0x667C, 0xD9A2, 0x666C, 0xD9A3, 0x667B, 0xD9A4, 0x6680, 0xD9A5, 0x6671, 0xD9A6, 0x6679, 0xD9A7, 0x666A, + 0xD9A8, 0x6672, 0xD9A9, 0x6701, 0xD9AA, 0x690C, 0xD9AB, 0x68D3, 0xD9AC, 0x6904, 0xD9AD, 0x68DC, 0xD9AE, 0x692A, 0xD9AF, 0x68EC, + 0xD9B0, 0x68EA, 0xD9B1, 0x68F1, 0xD9B2, 0x690F, 0xD9B3, 0x68D6, 0xD9B4, 0x68F7, 0xD9B5, 0x68EB, 0xD9B6, 0x68E4, 0xD9B7, 0x68F6, + 0xD9B8, 0x6913, 0xD9B9, 0x6910, 0xD9BA, 0x68F3, 0xD9BB, 0x68E1, 0xD9BC, 0x6907, 0xD9BD, 0x68CC, 0xD9BE, 0x6908, 0xD9BF, 0x6970, + 0xD9C0, 0x68B4, 0xD9C1, 0x6911, 0xD9C2, 0x68EF, 0xD9C3, 0x68C6, 0xD9C4, 0x6914, 0xD9C5, 0x68F8, 0xD9C6, 0x68D0, 0xD9C7, 0x68FD, + 0xD9C8, 0x68FC, 0xD9C9, 0x68E8, 0xD9CA, 0x690B, 0xD9CB, 0x690A, 0xD9CC, 0x6917, 0xD9CD, 0x68CE, 0xD9CE, 0x68C8, 0xD9CF, 0x68DD, + 0xD9D0, 0x68DE, 0xD9D1, 0x68E6, 0xD9D2, 0x68F4, 0xD9D3, 0x68D1, 0xD9D4, 0x6906, 0xD9D5, 0x68D4, 0xD9D6, 0x68E9, 0xD9D7, 0x6915, + 0xD9D8, 0x6925, 0xD9D9, 0x68C7, 0xD9DA, 0x6B39, 0xD9DB, 0x6B3B, 0xD9DC, 0x6B3F, 0xD9DD, 0x6B3C, 0xD9DE, 0x6B94, 0xD9DF, 0x6B97, + 0xD9E0, 0x6B99, 0xD9E1, 0x6B95, 0xD9E2, 0x6BBD, 0xD9E3, 0x6BF0, 0xD9E4, 0x6BF2, 0xD9E5, 0x6BF3, 0xD9E6, 0x6C30, 0xD9E7, 0x6DFC, + 0xD9E8, 0x6E46, 0xD9E9, 0x6E47, 0xD9EA, 0x6E1F, 0xD9EB, 0x6E49, 0xD9EC, 0x6E88, 0xD9ED, 0x6E3C, 0xD9EE, 0x6E3D, 0xD9EF, 0x6E45, + 0xD9F0, 0x6E62, 0xD9F1, 0x6E2B, 0xD9F2, 0x6E3F, 0xD9F3, 0x6E41, 0xD9F4, 0x6E5D, 0xD9F5, 0x6E73, 0xD9F6, 0x6E1C, 0xD9F7, 0x6E33, + 0xD9F8, 0x6E4B, 0xD9F9, 0x6E40, 0xD9FA, 0x6E51, 0xD9FB, 0x6E3B, 0xD9FC, 0x6E03, 0xD9FD, 0x6E2E, 0xD9FE, 0x6E5E, 0xDA40, 0x6E68, + 0xDA41, 0x6E5C, 0xDA42, 0x6E61, 0xDA43, 0x6E31, 0xDA44, 0x6E28, 0xDA45, 0x6E60, 0xDA46, 0x6E71, 0xDA47, 0x6E6B, 0xDA48, 0x6E39, + 0xDA49, 0x6E22, 0xDA4A, 0x6E30, 0xDA4B, 0x6E53, 0xDA4C, 0x6E65, 0xDA4D, 0x6E27, 0xDA4E, 0x6E78, 0xDA4F, 0x6E64, 0xDA50, 0x6E77, + 0xDA51, 0x6E55, 0xDA52, 0x6E79, 0xDA53, 0x6E52, 0xDA54, 0x6E66, 0xDA55, 0x6E35, 0xDA56, 0x6E36, 0xDA57, 0x6E5A, 0xDA58, 0x7120, + 0xDA59, 0x711E, 0xDA5A, 0x712F, 0xDA5B, 0x70FB, 0xDA5C, 0x712E, 0xDA5D, 0x7131, 0xDA5E, 0x7123, 0xDA5F, 0x7125, 0xDA60, 0x7122, + 0xDA61, 0x7132, 0xDA62, 0x711F, 0xDA63, 0x7128, 0xDA64, 0x713A, 0xDA65, 0x711B, 0xDA66, 0x724B, 0xDA67, 0x725A, 0xDA68, 0x7288, + 0xDA69, 0x7289, 0xDA6A, 0x7286, 0xDA6B, 0x7285, 0xDA6C, 0x728B, 0xDA6D, 0x7312, 0xDA6E, 0x730B, 0xDA6F, 0x7330, 0xDA70, 0x7322, + 0xDA71, 0x7331, 0xDA72, 0x7333, 0xDA73, 0x7327, 0xDA74, 0x7332, 0xDA75, 0x732D, 0xDA76, 0x7326, 0xDA77, 0x7323, 0xDA78, 0x7335, + 0xDA79, 0x730C, 0xDA7A, 0x742E, 0xDA7B, 0x742C, 0xDA7C, 0x7430, 0xDA7D, 0x742B, 0xDA7E, 0x7416, 0xDAA1, 0x741A, 0xDAA2, 0x7421, + 0xDAA3, 0x742D, 0xDAA4, 0x7431, 0xDAA5, 0x7424, 0xDAA6, 0x7423, 0xDAA7, 0x741D, 0xDAA8, 0x7429, 0xDAA9, 0x7420, 0xDAAA, 0x7432, + 0xDAAB, 0x74FB, 0xDAAC, 0x752F, 0xDAAD, 0x756F, 0xDAAE, 0x756C, 0xDAAF, 0x75E7, 0xDAB0, 0x75DA, 0xDAB1, 0x75E1, 0xDAB2, 0x75E6, + 0xDAB3, 0x75DD, 0xDAB4, 0x75DF, 0xDAB5, 0x75E4, 0xDAB6, 0x75D7, 0xDAB7, 0x7695, 0xDAB8, 0x7692, 0xDAB9, 0x76DA, 0xDABA, 0x7746, + 0xDABB, 0x7747, 0xDABC, 0x7744, 0xDABD, 0x774D, 0xDABE, 0x7745, 0xDABF, 0x774A, 0xDAC0, 0x774E, 0xDAC1, 0x774B, 0xDAC2, 0x774C, + 0xDAC3, 0x77DE, 0xDAC4, 0x77EC, 0xDAC5, 0x7860, 0xDAC6, 0x7864, 0xDAC7, 0x7865, 0xDAC8, 0x785C, 0xDAC9, 0x786D, 0xDACA, 0x7871, + 0xDACB, 0x786A, 0xDACC, 0x786E, 0xDACD, 0x7870, 0xDACE, 0x7869, 0xDACF, 0x7868, 0xDAD0, 0x785E, 0xDAD1, 0x7862, 0xDAD2, 0x7974, + 0xDAD3, 0x7973, 0xDAD4, 0x7972, 0xDAD5, 0x7970, 0xDAD6, 0x7A02, 0xDAD7, 0x7A0A, 0xDAD8, 0x7A03, 0xDAD9, 0x7A0C, 0xDADA, 0x7A04, + 0xDADB, 0x7A99, 0xDADC, 0x7AE6, 0xDADD, 0x7AE4, 0xDADE, 0x7B4A, 0xDADF, 0x7B3B, 0xDAE0, 0x7B44, 0xDAE1, 0x7B48, 0xDAE2, 0x7B4C, + 0xDAE3, 0x7B4E, 0xDAE4, 0x7B40, 0xDAE5, 0x7B58, 0xDAE6, 0x7B45, 0xDAE7, 0x7CA2, 0xDAE8, 0x7C9E, 0xDAE9, 0x7CA8, 0xDAEA, 0x7CA1, + 0xDAEB, 0x7D58, 0xDAEC, 0x7D6F, 0xDAED, 0x7D63, 0xDAEE, 0x7D53, 0xDAEF, 0x7D56, 0xDAF0, 0x7D67, 0xDAF1, 0x7D6A, 0xDAF2, 0x7D4F, + 0xDAF3, 0x7D6D, 0xDAF4, 0x7D5C, 0xDAF5, 0x7D6B, 0xDAF6, 0x7D52, 0xDAF7, 0x7D54, 0xDAF8, 0x7D69, 0xDAF9, 0x7D51, 0xDAFA, 0x7D5F, + 0xDAFB, 0x7D4E, 0xDAFC, 0x7F3E, 0xDAFD, 0x7F3F, 0xDAFE, 0x7F65, 0xDB40, 0x7F66, 0xDB41, 0x7FA2, 0xDB42, 0x7FA0, 0xDB43, 0x7FA1, + 0xDB44, 0x7FD7, 0xDB45, 0x8051, 0xDB46, 0x804F, 0xDB47, 0x8050, 0xDB48, 0x80FE, 0xDB49, 0x80D4, 0xDB4A, 0x8143, 0xDB4B, 0x814A, + 0xDB4C, 0x8152, 0xDB4D, 0x814F, 0xDB4E, 0x8147, 0xDB4F, 0x813D, 0xDB50, 0x814D, 0xDB51, 0x813A, 0xDB52, 0x81E6, 0xDB53, 0x81EE, + 0xDB54, 0x81F7, 0xDB55, 0x81F8, 0xDB56, 0x81F9, 0xDB57, 0x8204, 0xDB58, 0x823C, 0xDB59, 0x823D, 0xDB5A, 0x823F, 0xDB5B, 0x8275, + 0xDB5C, 0x833B, 0xDB5D, 0x83CF, 0xDB5E, 0x83F9, 0xDB5F, 0x8423, 0xDB60, 0x83C0, 0xDB61, 0x83E8, 0xDB62, 0x8412, 0xDB63, 0x83E7, + 0xDB64, 0x83E4, 0xDB65, 0x83FC, 0xDB66, 0x83F6, 0xDB67, 0x8410, 0xDB68, 0x83C6, 0xDB69, 0x83C8, 0xDB6A, 0x83EB, 0xDB6B, 0x83E3, + 0xDB6C, 0x83BF, 0xDB6D, 0x8401, 0xDB6E, 0x83DD, 0xDB6F, 0x83E5, 0xDB70, 0x83D8, 0xDB71, 0x83FF, 0xDB72, 0x83E1, 0xDB73, 0x83CB, + 0xDB74, 0x83CE, 0xDB75, 0x83D6, 0xDB76, 0x83F5, 0xDB77, 0x83C9, 0xDB78, 0x8409, 0xDB79, 0x840F, 0xDB7A, 0x83DE, 0xDB7B, 0x8411, + 0xDB7C, 0x8406, 0xDB7D, 0x83C2, 0xDB7E, 0x83F3, 0xDBA1, 0x83D5, 0xDBA2, 0x83FA, 0xDBA3, 0x83C7, 0xDBA4, 0x83D1, 0xDBA5, 0x83EA, + 0xDBA6, 0x8413, 0xDBA7, 0x83C3, 0xDBA8, 0x83EC, 0xDBA9, 0x83EE, 0xDBAA, 0x83C4, 0xDBAB, 0x83FB, 0xDBAC, 0x83D7, 0xDBAD, 0x83E2, + 0xDBAE, 0x841B, 0xDBAF, 0x83DB, 0xDBB0, 0x83FE, 0xDBB1, 0x86D8, 0xDBB2, 0x86E2, 0xDBB3, 0x86E6, 0xDBB4, 0x86D3, 0xDBB5, 0x86E3, + 0xDBB6, 0x86DA, 0xDBB7, 0x86EA, 0xDBB8, 0x86DD, 0xDBB9, 0x86EB, 0xDBBA, 0x86DC, 0xDBBB, 0x86EC, 0xDBBC, 0x86E9, 0xDBBD, 0x86D7, + 0xDBBE, 0x86E8, 0xDBBF, 0x86D1, 0xDBC0, 0x8848, 0xDBC1, 0x8856, 0xDBC2, 0x8855, 0xDBC3, 0x88BA, 0xDBC4, 0x88D7, 0xDBC5, 0x88B9, + 0xDBC6, 0x88B8, 0xDBC7, 0x88C0, 0xDBC8, 0x88BE, 0xDBC9, 0x88B6, 0xDBCA, 0x88BC, 0xDBCB, 0x88B7, 0xDBCC, 0x88BD, 0xDBCD, 0x88B2, + 0xDBCE, 0x8901, 0xDBCF, 0x88C9, 0xDBD0, 0x8995, 0xDBD1, 0x8998, 0xDBD2, 0x8997, 0xDBD3, 0x89DD, 0xDBD4, 0x89DA, 0xDBD5, 0x89DB, + 0xDBD6, 0x8A4E, 0xDBD7, 0x8A4D, 0xDBD8, 0x8A39, 0xDBD9, 0x8A59, 0xDBDA, 0x8A40, 0xDBDB, 0x8A57, 0xDBDC, 0x8A58, 0xDBDD, 0x8A44, + 0xDBDE, 0x8A45, 0xDBDF, 0x8A52, 0xDBE0, 0x8A48, 0xDBE1, 0x8A51, 0xDBE2, 0x8A4A, 0xDBE3, 0x8A4C, 0xDBE4, 0x8A4F, 0xDBE5, 0x8C5F, + 0xDBE6, 0x8C81, 0xDBE7, 0x8C80, 0xDBE8, 0x8CBA, 0xDBE9, 0x8CBE, 0xDBEA, 0x8CB0, 0xDBEB, 0x8CB9, 0xDBEC, 0x8CB5, 0xDBED, 0x8D84, + 0xDBEE, 0x8D80, 0xDBEF, 0x8D89, 0xDBF0, 0x8DD8, 0xDBF1, 0x8DD3, 0xDBF2, 0x8DCD, 0xDBF3, 0x8DC7, 0xDBF4, 0x8DD6, 0xDBF5, 0x8DDC, + 0xDBF6, 0x8DCF, 0xDBF7, 0x8DD5, 0xDBF8, 0x8DD9, 0xDBF9, 0x8DC8, 0xDBFA, 0x8DD7, 0xDBFB, 0x8DC5, 0xDBFC, 0x8EEF, 0xDBFD, 0x8EF7, + 0xDBFE, 0x8EFA, 0xDC40, 0x8EF9, 0xDC41, 0x8EE6, 0xDC42, 0x8EEE, 0xDC43, 0x8EE5, 0xDC44, 0x8EF5, 0xDC45, 0x8EE7, 0xDC46, 0x8EE8, + 0xDC47, 0x8EF6, 0xDC48, 0x8EEB, 0xDC49, 0x8EF1, 0xDC4A, 0x8EEC, 0xDC4B, 0x8EF4, 0xDC4C, 0x8EE9, 0xDC4D, 0x902D, 0xDC4E, 0x9034, + 0xDC4F, 0x902F, 0xDC50, 0x9106, 0xDC51, 0x912C, 0xDC52, 0x9104, 0xDC53, 0x90FF, 0xDC54, 0x90FC, 0xDC55, 0x9108, 0xDC56, 0x90F9, + 0xDC57, 0x90FB, 0xDC58, 0x9101, 0xDC59, 0x9100, 0xDC5A, 0x9107, 0xDC5B, 0x9105, 0xDC5C, 0x9103, 0xDC5D, 0x9161, 0xDC5E, 0x9164, + 0xDC5F, 0x915F, 0xDC60, 0x9162, 0xDC61, 0x9160, 0xDC62, 0x9201, 0xDC63, 0x920A, 0xDC64, 0x9225, 0xDC65, 0x9203, 0xDC66, 0x921A, + 0xDC67, 0x9226, 0xDC68, 0x920F, 0xDC69, 0x920C, 0xDC6A, 0x9200, 0xDC6B, 0x9212, 0xDC6C, 0x91FF, 0xDC6D, 0x91FD, 0xDC6E, 0x9206, + 0xDC6F, 0x9204, 0xDC70, 0x9227, 0xDC71, 0x9202, 0xDC72, 0x921C, 0xDC73, 0x9224, 0xDC74, 0x9219, 0xDC75, 0x9217, 0xDC76, 0x9205, + 0xDC77, 0x9216, 0xDC78, 0x957B, 0xDC79, 0x958D, 0xDC7A, 0x958C, 0xDC7B, 0x9590, 0xDC7C, 0x9687, 0xDC7D, 0x967E, 0xDC7E, 0x9688, + 0xDCA1, 0x9689, 0xDCA2, 0x9683, 0xDCA3, 0x9680, 0xDCA4, 0x96C2, 0xDCA5, 0x96C8, 0xDCA6, 0x96C3, 0xDCA7, 0x96F1, 0xDCA8, 0x96F0, + 0xDCA9, 0x976C, 0xDCAA, 0x9770, 0xDCAB, 0x976E, 0xDCAC, 0x9807, 0xDCAD, 0x98A9, 0xDCAE, 0x98EB, 0xDCAF, 0x9CE6, 0xDCB0, 0x9EF9, + 0xDCB1, 0x4E83, 0xDCB2, 0x4E84, 0xDCB3, 0x4EB6, 0xDCB4, 0x50BD, 0xDCB5, 0x50BF, 0xDCB6, 0x50C6, 0xDCB7, 0x50AE, 0xDCB8, 0x50C4, + 0xDCB9, 0x50CA, 0xDCBA, 0x50B4, 0xDCBB, 0x50C8, 0xDCBC, 0x50C2, 0xDCBD, 0x50B0, 0xDCBE, 0x50C1, 0xDCBF, 0x50BA, 0xDCC0, 0x50B1, + 0xDCC1, 0x50CB, 0xDCC2, 0x50C9, 0xDCC3, 0x50B6, 0xDCC4, 0x50B8, 0xDCC5, 0x51D7, 0xDCC6, 0x527A, 0xDCC7, 0x5278, 0xDCC8, 0x527B, + 0xDCC9, 0x527C, 0xDCCA, 0x55C3, 0xDCCB, 0x55DB, 0xDCCC, 0x55CC, 0xDCCD, 0x55D0, 0xDCCE, 0x55CB, 0xDCCF, 0x55CA, 0xDCD0, 0x55DD, + 0xDCD1, 0x55C0, 0xDCD2, 0x55D4, 0xDCD3, 0x55C4, 0xDCD4, 0x55E9, 0xDCD5, 0x55BF, 0xDCD6, 0x55D2, 0xDCD7, 0x558D, 0xDCD8, 0x55CF, + 0xDCD9, 0x55D5, 0xDCDA, 0x55E2, 0xDCDB, 0x55D6, 0xDCDC, 0x55C8, 0xDCDD, 0x55F2, 0xDCDE, 0x55CD, 0xDCDF, 0x55D9, 0xDCE0, 0x55C2, + 0xDCE1, 0x5714, 0xDCE2, 0x5853, 0xDCE3, 0x5868, 0xDCE4, 0x5864, 0xDCE5, 0x584F, 0xDCE6, 0x584D, 0xDCE7, 0x5849, 0xDCE8, 0x586F, + 0xDCE9, 0x5855, 0xDCEA, 0x584E, 0xDCEB, 0x585D, 0xDCEC, 0x5859, 0xDCED, 0x5865, 0xDCEE, 0x585B, 0xDCEF, 0x583D, 0xDCF0, 0x5863, + 0xDCF1, 0x5871, 0xDCF2, 0x58FC, 0xDCF3, 0x5AC7, 0xDCF4, 0x5AC4, 0xDCF5, 0x5ACB, 0xDCF6, 0x5ABA, 0xDCF7, 0x5AB8, 0xDCF8, 0x5AB1, + 0xDCF9, 0x5AB5, 0xDCFA, 0x5AB0, 0xDCFB, 0x5ABF, 0xDCFC, 0x5AC8, 0xDCFD, 0x5ABB, 0xDCFE, 0x5AC6, 0xDD40, 0x5AB7, 0xDD41, 0x5AC0, + 0xDD42, 0x5ACA, 0xDD43, 0x5AB4, 0xDD44, 0x5AB6, 0xDD45, 0x5ACD, 0xDD46, 0x5AB9, 0xDD47, 0x5A90, 0xDD48, 0x5BD6, 0xDD49, 0x5BD8, + 0xDD4A, 0x5BD9, 0xDD4B, 0x5C1F, 0xDD4C, 0x5C33, 0xDD4D, 0x5D71, 0xDD4E, 0x5D63, 0xDD4F, 0x5D4A, 0xDD50, 0x5D65, 0xDD51, 0x5D72, + 0xDD52, 0x5D6C, 0xDD53, 0x5D5E, 0xDD54, 0x5D68, 0xDD55, 0x5D67, 0xDD56, 0x5D62, 0xDD57, 0x5DF0, 0xDD58, 0x5E4F, 0xDD59, 0x5E4E, + 0xDD5A, 0x5E4A, 0xDD5B, 0x5E4D, 0xDD5C, 0x5E4B, 0xDD5D, 0x5EC5, 0xDD5E, 0x5ECC, 0xDD5F, 0x5EC6, 0xDD60, 0x5ECB, 0xDD61, 0x5EC7, + 0xDD62, 0x5F40, 0xDD63, 0x5FAF, 0xDD64, 0x5FAD, 0xDD65, 0x60F7, 0xDD66, 0x6149, 0xDD67, 0x614A, 0xDD68, 0x612B, 0xDD69, 0x6145, + 0xDD6A, 0x6136, 0xDD6B, 0x6132, 0xDD6C, 0x612E, 0xDD6D, 0x6146, 0xDD6E, 0x612F, 0xDD6F, 0x614F, 0xDD70, 0x6129, 0xDD71, 0x6140, + 0xDD72, 0x6220, 0xDD73, 0x9168, 0xDD74, 0x6223, 0xDD75, 0x6225, 0xDD76, 0x6224, 0xDD77, 0x63C5, 0xDD78, 0x63F1, 0xDD79, 0x63EB, + 0xDD7A, 0x6410, 0xDD7B, 0x6412, 0xDD7C, 0x6409, 0xDD7D, 0x6420, 0xDD7E, 0x6424, 0xDDA1, 0x6433, 0xDDA2, 0x6443, 0xDDA3, 0x641F, + 0xDDA4, 0x6415, 0xDDA5, 0x6418, 0xDDA6, 0x6439, 0xDDA7, 0x6437, 0xDDA8, 0x6422, 0xDDA9, 0x6423, 0xDDAA, 0x640C, 0xDDAB, 0x6426, + 0xDDAC, 0x6430, 0xDDAD, 0x6428, 0xDDAE, 0x6441, 0xDDAF, 0x6435, 0xDDB0, 0x642F, 0xDDB1, 0x640A, 0xDDB2, 0x641A, 0xDDB3, 0x6440, + 0xDDB4, 0x6425, 0xDDB5, 0x6427, 0xDDB6, 0x640B, 0xDDB7, 0x63E7, 0xDDB8, 0x641B, 0xDDB9, 0x642E, 0xDDBA, 0x6421, 0xDDBB, 0x640E, + 0xDDBC, 0x656F, 0xDDBD, 0x6592, 0xDDBE, 0x65D3, 0xDDBF, 0x6686, 0xDDC0, 0x668C, 0xDDC1, 0x6695, 0xDDC2, 0x6690, 0xDDC3, 0x668B, + 0xDDC4, 0x668A, 0xDDC5, 0x6699, 0xDDC6, 0x6694, 0xDDC7, 0x6678, 0xDDC8, 0x6720, 0xDDC9, 0x6966, 0xDDCA, 0x695F, 0xDDCB, 0x6938, + 0xDDCC, 0x694E, 0xDDCD, 0x6962, 0xDDCE, 0x6971, 0xDDCF, 0x693F, 0xDDD0, 0x6945, 0xDDD1, 0x696A, 0xDDD2, 0x6939, 0xDDD3, 0x6942, + 0xDDD4, 0x6957, 0xDDD5, 0x6959, 0xDDD6, 0x697A, 0xDDD7, 0x6948, 0xDDD8, 0x6949, 0xDDD9, 0x6935, 0xDDDA, 0x696C, 0xDDDB, 0x6933, + 0xDDDC, 0x693D, 0xDDDD, 0x6965, 0xDDDE, 0x68F0, 0xDDDF, 0x6978, 0xDDE0, 0x6934, 0xDDE1, 0x6969, 0xDDE2, 0x6940, 0xDDE3, 0x696F, + 0xDDE4, 0x6944, 0xDDE5, 0x6976, 0xDDE6, 0x6958, 0xDDE7, 0x6941, 0xDDE8, 0x6974, 0xDDE9, 0x694C, 0xDDEA, 0x693B, 0xDDEB, 0x694B, + 0xDDEC, 0x6937, 0xDDED, 0x695C, 0xDDEE, 0x694F, 0xDDEF, 0x6951, 0xDDF0, 0x6932, 0xDDF1, 0x6952, 0xDDF2, 0x692F, 0xDDF3, 0x697B, + 0xDDF4, 0x693C, 0xDDF5, 0x6B46, 0xDDF6, 0x6B45, 0xDDF7, 0x6B43, 0xDDF8, 0x6B42, 0xDDF9, 0x6B48, 0xDDFA, 0x6B41, 0xDDFB, 0x6B9B, + 0xDDFC, 0xFA0D, 0xDDFD, 0x6BFB, 0xDDFE, 0x6BFC, 0xDE40, 0x6BF9, 0xDE41, 0x6BF7, 0xDE42, 0x6BF8, 0xDE43, 0x6E9B, 0xDE44, 0x6ED6, + 0xDE45, 0x6EC8, 0xDE46, 0x6E8F, 0xDE47, 0x6EC0, 0xDE48, 0x6E9F, 0xDE49, 0x6E93, 0xDE4A, 0x6E94, 0xDE4B, 0x6EA0, 0xDE4C, 0x6EB1, + 0xDE4D, 0x6EB9, 0xDE4E, 0x6EC6, 0xDE4F, 0x6ED2, 0xDE50, 0x6EBD, 0xDE51, 0x6EC1, 0xDE52, 0x6E9E, 0xDE53, 0x6EC9, 0xDE54, 0x6EB7, + 0xDE55, 0x6EB0, 0xDE56, 0x6ECD, 0xDE57, 0x6EA6, 0xDE58, 0x6ECF, 0xDE59, 0x6EB2, 0xDE5A, 0x6EBE, 0xDE5B, 0x6EC3, 0xDE5C, 0x6EDC, + 0xDE5D, 0x6ED8, 0xDE5E, 0x6E99, 0xDE5F, 0x6E92, 0xDE60, 0x6E8E, 0xDE61, 0x6E8D, 0xDE62, 0x6EA4, 0xDE63, 0x6EA1, 0xDE64, 0x6EBF, + 0xDE65, 0x6EB3, 0xDE66, 0x6ED0, 0xDE67, 0x6ECA, 0xDE68, 0x6E97, 0xDE69, 0x6EAE, 0xDE6A, 0x6EA3, 0xDE6B, 0x7147, 0xDE6C, 0x7154, + 0xDE6D, 0x7152, 0xDE6E, 0x7163, 0xDE6F, 0x7160, 0xDE70, 0x7141, 0xDE71, 0x715D, 0xDE72, 0x7162, 0xDE73, 0x7172, 0xDE74, 0x7178, + 0xDE75, 0x716A, 0xDE76, 0x7161, 0xDE77, 0x7142, 0xDE78, 0x7158, 0xDE79, 0x7143, 0xDE7A, 0x714B, 0xDE7B, 0x7170, 0xDE7C, 0x715F, + 0xDE7D, 0x7150, 0xDE7E, 0x7153, 0xDEA1, 0x7144, 0xDEA2, 0x714D, 0xDEA3, 0x715A, 0xDEA4, 0x724F, 0xDEA5, 0x728D, 0xDEA6, 0x728C, + 0xDEA7, 0x7291, 0xDEA8, 0x7290, 0xDEA9, 0x728E, 0xDEAA, 0x733C, 0xDEAB, 0x7342, 0xDEAC, 0x733B, 0xDEAD, 0x733A, 0xDEAE, 0x7340, + 0xDEAF, 0x734A, 0xDEB0, 0x7349, 0xDEB1, 0x7444, 0xDEB2, 0x744A, 0xDEB3, 0x744B, 0xDEB4, 0x7452, 0xDEB5, 0x7451, 0xDEB6, 0x7457, + 0xDEB7, 0x7440, 0xDEB8, 0x744F, 0xDEB9, 0x7450, 0xDEBA, 0x744E, 0xDEBB, 0x7442, 0xDEBC, 0x7446, 0xDEBD, 0x744D, 0xDEBE, 0x7454, + 0xDEBF, 0x74E1, 0xDEC0, 0x74FF, 0xDEC1, 0x74FE, 0xDEC2, 0x74FD, 0xDEC3, 0x751D, 0xDEC4, 0x7579, 0xDEC5, 0x7577, 0xDEC6, 0x6983, + 0xDEC7, 0x75EF, 0xDEC8, 0x760F, 0xDEC9, 0x7603, 0xDECA, 0x75F7, 0xDECB, 0x75FE, 0xDECC, 0x75FC, 0xDECD, 0x75F9, 0xDECE, 0x75F8, + 0xDECF, 0x7610, 0xDED0, 0x75FB, 0xDED1, 0x75F6, 0xDED2, 0x75ED, 0xDED3, 0x75F5, 0xDED4, 0x75FD, 0xDED5, 0x7699, 0xDED6, 0x76B5, + 0xDED7, 0x76DD, 0xDED8, 0x7755, 0xDED9, 0x775F, 0xDEDA, 0x7760, 0xDEDB, 0x7752, 0xDEDC, 0x7756, 0xDEDD, 0x775A, 0xDEDE, 0x7769, + 0xDEDF, 0x7767, 0xDEE0, 0x7754, 0xDEE1, 0x7759, 0xDEE2, 0x776D, 0xDEE3, 0x77E0, 0xDEE4, 0x7887, 0xDEE5, 0x789A, 0xDEE6, 0x7894, + 0xDEE7, 0x788F, 0xDEE8, 0x7884, 0xDEE9, 0x7895, 0xDEEA, 0x7885, 0xDEEB, 0x7886, 0xDEEC, 0x78A1, 0xDEED, 0x7883, 0xDEEE, 0x7879, + 0xDEEF, 0x7899, 0xDEF0, 0x7880, 0xDEF1, 0x7896, 0xDEF2, 0x787B, 0xDEF3, 0x797C, 0xDEF4, 0x7982, 0xDEF5, 0x797D, 0xDEF6, 0x7979, + 0xDEF7, 0x7A11, 0xDEF8, 0x7A18, 0xDEF9, 0x7A19, 0xDEFA, 0x7A12, 0xDEFB, 0x7A17, 0xDEFC, 0x7A15, 0xDEFD, 0x7A22, 0xDEFE, 0x7A13, + 0xDF40, 0x7A1B, 0xDF41, 0x7A10, 0xDF42, 0x7AA3, 0xDF43, 0x7AA2, 0xDF44, 0x7A9E, 0xDF45, 0x7AEB, 0xDF46, 0x7B66, 0xDF47, 0x7B64, + 0xDF48, 0x7B6D, 0xDF49, 0x7B74, 0xDF4A, 0x7B69, 0xDF4B, 0x7B72, 0xDF4C, 0x7B65, 0xDF4D, 0x7B73, 0xDF4E, 0x7B71, 0xDF4F, 0x7B70, + 0xDF50, 0x7B61, 0xDF51, 0x7B78, 0xDF52, 0x7B76, 0xDF53, 0x7B63, 0xDF54, 0x7CB2, 0xDF55, 0x7CB4, 0xDF56, 0x7CAF, 0xDF57, 0x7D88, + 0xDF58, 0x7D86, 0xDF59, 0x7D80, 0xDF5A, 0x7D8D, 0xDF5B, 0x7D7F, 0xDF5C, 0x7D85, 0xDF5D, 0x7D7A, 0xDF5E, 0x7D8E, 0xDF5F, 0x7D7B, + 0xDF60, 0x7D83, 0xDF61, 0x7D7C, 0xDF62, 0x7D8C, 0xDF63, 0x7D94, 0xDF64, 0x7D84, 0xDF65, 0x7D7D, 0xDF66, 0x7D92, 0xDF67, 0x7F6D, + 0xDF68, 0x7F6B, 0xDF69, 0x7F67, 0xDF6A, 0x7F68, 0xDF6B, 0x7F6C, 0xDF6C, 0x7FA6, 0xDF6D, 0x7FA5, 0xDF6E, 0x7FA7, 0xDF6F, 0x7FDB, + 0xDF70, 0x7FDC, 0xDF71, 0x8021, 0xDF72, 0x8164, 0xDF73, 0x8160, 0xDF74, 0x8177, 0xDF75, 0x815C, 0xDF76, 0x8169, 0xDF77, 0x815B, + 0xDF78, 0x8162, 0xDF79, 0x8172, 0xDF7A, 0x6721, 0xDF7B, 0x815E, 0xDF7C, 0x8176, 0xDF7D, 0x8167, 0xDF7E, 0x816F, 0xDFA1, 0x8144, + 0xDFA2, 0x8161, 0xDFA3, 0x821D, 0xDFA4, 0x8249, 0xDFA5, 0x8244, 0xDFA6, 0x8240, 0xDFA7, 0x8242, 0xDFA8, 0x8245, 0xDFA9, 0x84F1, + 0xDFAA, 0x843F, 0xDFAB, 0x8456, 0xDFAC, 0x8476, 0xDFAD, 0x8479, 0xDFAE, 0x848F, 0xDFAF, 0x848D, 0xDFB0, 0x8465, 0xDFB1, 0x8451, + 0xDFB2, 0x8440, 0xDFB3, 0x8486, 0xDFB4, 0x8467, 0xDFB5, 0x8430, 0xDFB6, 0x844D, 0xDFB7, 0x847D, 0xDFB8, 0x845A, 0xDFB9, 0x8459, + 0xDFBA, 0x8474, 0xDFBB, 0x8473, 0xDFBC, 0x845D, 0xDFBD, 0x8507, 0xDFBE, 0x845E, 0xDFBF, 0x8437, 0xDFC0, 0x843A, 0xDFC1, 0x8434, + 0xDFC2, 0x847A, 0xDFC3, 0x8443, 0xDFC4, 0x8478, 0xDFC5, 0x8432, 0xDFC6, 0x8445, 0xDFC7, 0x8429, 0xDFC8, 0x83D9, 0xDFC9, 0x844B, + 0xDFCA, 0x842F, 0xDFCB, 0x8442, 0xDFCC, 0x842D, 0xDFCD, 0x845F, 0xDFCE, 0x8470, 0xDFCF, 0x8439, 0xDFD0, 0x844E, 0xDFD1, 0x844C, + 0xDFD2, 0x8452, 0xDFD3, 0x846F, 0xDFD4, 0x84C5, 0xDFD5, 0x848E, 0xDFD6, 0x843B, 0xDFD7, 0x8447, 0xDFD8, 0x8436, 0xDFD9, 0x8433, + 0xDFDA, 0x8468, 0xDFDB, 0x847E, 0xDFDC, 0x8444, 0xDFDD, 0x842B, 0xDFDE, 0x8460, 0xDFDF, 0x8454, 0xDFE0, 0x846E, 0xDFE1, 0x8450, + 0xDFE2, 0x870B, 0xDFE3, 0x8704, 0xDFE4, 0x86F7, 0xDFE5, 0x870C, 0xDFE6, 0x86FA, 0xDFE7, 0x86D6, 0xDFE8, 0x86F5, 0xDFE9, 0x874D, + 0xDFEA, 0x86F8, 0xDFEB, 0x870E, 0xDFEC, 0x8709, 0xDFED, 0x8701, 0xDFEE, 0x86F6, 0xDFEF, 0x870D, 0xDFF0, 0x8705, 0xDFF1, 0x88D6, + 0xDFF2, 0x88CB, 0xDFF3, 0x88CD, 0xDFF4, 0x88CE, 0xDFF5, 0x88DE, 0xDFF6, 0x88DB, 0xDFF7, 0x88DA, 0xDFF8, 0x88CC, 0xDFF9, 0x88D0, + 0xDFFA, 0x8985, 0xDFFB, 0x899B, 0xDFFC, 0x89DF, 0xDFFD, 0x89E5, 0xDFFE, 0x89E4, 0xE040, 0x89E1, 0xE041, 0x89E0, 0xE042, 0x89E2, + 0xE043, 0x89DC, 0xE044, 0x89E6, 0xE045, 0x8A76, 0xE046, 0x8A86, 0xE047, 0x8A7F, 0xE048, 0x8A61, 0xE049, 0x8A3F, 0xE04A, 0x8A77, + 0xE04B, 0x8A82, 0xE04C, 0x8A84, 0xE04D, 0x8A75, 0xE04E, 0x8A83, 0xE04F, 0x8A81, 0xE050, 0x8A74, 0xE051, 0x8A7A, 0xE052, 0x8C3C, + 0xE053, 0x8C4B, 0xE054, 0x8C4A, 0xE055, 0x8C65, 0xE056, 0x8C64, 0xE057, 0x8C66, 0xE058, 0x8C86, 0xE059, 0x8C84, 0xE05A, 0x8C85, + 0xE05B, 0x8CCC, 0xE05C, 0x8D68, 0xE05D, 0x8D69, 0xE05E, 0x8D91, 0xE05F, 0x8D8C, 0xE060, 0x8D8E, 0xE061, 0x8D8F, 0xE062, 0x8D8D, + 0xE063, 0x8D93, 0xE064, 0x8D94, 0xE065, 0x8D90, 0xE066, 0x8D92, 0xE067, 0x8DF0, 0xE068, 0x8DE0, 0xE069, 0x8DEC, 0xE06A, 0x8DF1, + 0xE06B, 0x8DEE, 0xE06C, 0x8DD0, 0xE06D, 0x8DE9, 0xE06E, 0x8DE3, 0xE06F, 0x8DE2, 0xE070, 0x8DE7, 0xE071, 0x8DF2, 0xE072, 0x8DEB, + 0xE073, 0x8DF4, 0xE074, 0x8F06, 0xE075, 0x8EFF, 0xE076, 0x8F01, 0xE077, 0x8F00, 0xE078, 0x8F05, 0xE079, 0x8F07, 0xE07A, 0x8F08, + 0xE07B, 0x8F02, 0xE07C, 0x8F0B, 0xE07D, 0x9052, 0xE07E, 0x903F, 0xE0A1, 0x9044, 0xE0A2, 0x9049, 0xE0A3, 0x903D, 0xE0A4, 0x9110, + 0xE0A5, 0x910D, 0xE0A6, 0x910F, 0xE0A7, 0x9111, 0xE0A8, 0x9116, 0xE0A9, 0x9114, 0xE0AA, 0x910B, 0xE0AB, 0x910E, 0xE0AC, 0x916E, + 0xE0AD, 0x916F, 0xE0AE, 0x9248, 0xE0AF, 0x9252, 0xE0B0, 0x9230, 0xE0B1, 0x923A, 0xE0B2, 0x9266, 0xE0B3, 0x9233, 0xE0B4, 0x9265, + 0xE0B5, 0x925E, 0xE0B6, 0x9283, 0xE0B7, 0x922E, 0xE0B8, 0x924A, 0xE0B9, 0x9246, 0xE0BA, 0x926D, 0xE0BB, 0x926C, 0xE0BC, 0x924F, + 0xE0BD, 0x9260, 0xE0BE, 0x9267, 0xE0BF, 0x926F, 0xE0C0, 0x9236, 0xE0C1, 0x9261, 0xE0C2, 0x9270, 0xE0C3, 0x9231, 0xE0C4, 0x9254, + 0xE0C5, 0x9263, 0xE0C6, 0x9250, 0xE0C7, 0x9272, 0xE0C8, 0x924E, 0xE0C9, 0x9253, 0xE0CA, 0x924C, 0xE0CB, 0x9256, 0xE0CC, 0x9232, + 0xE0CD, 0x959F, 0xE0CE, 0x959C, 0xE0CF, 0x959E, 0xE0D0, 0x959B, 0xE0D1, 0x9692, 0xE0D2, 0x9693, 0xE0D3, 0x9691, 0xE0D4, 0x9697, + 0xE0D5, 0x96CE, 0xE0D6, 0x96FA, 0xE0D7, 0x96FD, 0xE0D8, 0x96F8, 0xE0D9, 0x96F5, 0xE0DA, 0x9773, 0xE0DB, 0x9777, 0xE0DC, 0x9778, + 0xE0DD, 0x9772, 0xE0DE, 0x980F, 0xE0DF, 0x980D, 0xE0E0, 0x980E, 0xE0E1, 0x98AC, 0xE0E2, 0x98F6, 0xE0E3, 0x98F9, 0xE0E4, 0x99AF, + 0xE0E5, 0x99B2, 0xE0E6, 0x99B0, 0xE0E7, 0x99B5, 0xE0E8, 0x9AAD, 0xE0E9, 0x9AAB, 0xE0EA, 0x9B5B, 0xE0EB, 0x9CEA, 0xE0EC, 0x9CED, + 0xE0ED, 0x9CE7, 0xE0EE, 0x9E80, 0xE0EF, 0x9EFD, 0xE0F0, 0x50E6, 0xE0F1, 0x50D4, 0xE0F2, 0x50D7, 0xE0F3, 0x50E8, 0xE0F4, 0x50F3, + 0xE0F5, 0x50DB, 0xE0F6, 0x50EA, 0xE0F7, 0x50DD, 0xE0F8, 0x50E4, 0xE0F9, 0x50D3, 0xE0FA, 0x50EC, 0xE0FB, 0x50F0, 0xE0FC, 0x50EF, + 0xE0FD, 0x50E3, 0xE0FE, 0x50E0, 0xE140, 0x51D8, 0xE141, 0x5280, 0xE142, 0x5281, 0xE143, 0x52E9, 0xE144, 0x52EB, 0xE145, 0x5330, + 0xE146, 0x53AC, 0xE147, 0x5627, 0xE148, 0x5615, 0xE149, 0x560C, 0xE14A, 0x5612, 0xE14B, 0x55FC, 0xE14C, 0x560F, 0xE14D, 0x561C, + 0xE14E, 0x5601, 0xE14F, 0x5613, 0xE150, 0x5602, 0xE151, 0x55FA, 0xE152, 0x561D, 0xE153, 0x5604, 0xE154, 0x55FF, 0xE155, 0x55F9, + 0xE156, 0x5889, 0xE157, 0x587C, 0xE158, 0x5890, 0xE159, 0x5898, 0xE15A, 0x5886, 0xE15B, 0x5881, 0xE15C, 0x587F, 0xE15D, 0x5874, + 0xE15E, 0x588B, 0xE15F, 0x587A, 0xE160, 0x5887, 0xE161, 0x5891, 0xE162, 0x588E, 0xE163, 0x5876, 0xE164, 0x5882, 0xE165, 0x5888, + 0xE166, 0x587B, 0xE167, 0x5894, 0xE168, 0x588F, 0xE169, 0x58FE, 0xE16A, 0x596B, 0xE16B, 0x5ADC, 0xE16C, 0x5AEE, 0xE16D, 0x5AE5, + 0xE16E, 0x5AD5, 0xE16F, 0x5AEA, 0xE170, 0x5ADA, 0xE171, 0x5AED, 0xE172, 0x5AEB, 0xE173, 0x5AF3, 0xE174, 0x5AE2, 0xE175, 0x5AE0, + 0xE176, 0x5ADB, 0xE177, 0x5AEC, 0xE178, 0x5ADE, 0xE179, 0x5ADD, 0xE17A, 0x5AD9, 0xE17B, 0x5AE8, 0xE17C, 0x5ADF, 0xE17D, 0x5B77, + 0xE17E, 0x5BE0, 0xE1A1, 0x5BE3, 0xE1A2, 0x5C63, 0xE1A3, 0x5D82, 0xE1A4, 0x5D80, 0xE1A5, 0x5D7D, 0xE1A6, 0x5D86, 0xE1A7, 0x5D7A, + 0xE1A8, 0x5D81, 0xE1A9, 0x5D77, 0xE1AA, 0x5D8A, 0xE1AB, 0x5D89, 0xE1AC, 0x5D88, 0xE1AD, 0x5D7E, 0xE1AE, 0x5D7C, 0xE1AF, 0x5D8D, + 0xE1B0, 0x5D79, 0xE1B1, 0x5D7F, 0xE1B2, 0x5E58, 0xE1B3, 0x5E59, 0xE1B4, 0x5E53, 0xE1B5, 0x5ED8, 0xE1B6, 0x5ED1, 0xE1B7, 0x5ED7, + 0xE1B8, 0x5ECE, 0xE1B9, 0x5EDC, 0xE1BA, 0x5ED5, 0xE1BB, 0x5ED9, 0xE1BC, 0x5ED2, 0xE1BD, 0x5ED4, 0xE1BE, 0x5F44, 0xE1BF, 0x5F43, + 0xE1C0, 0x5F6F, 0xE1C1, 0x5FB6, 0xE1C2, 0x612C, 0xE1C3, 0x6128, 0xE1C4, 0x6141, 0xE1C5, 0x615E, 0xE1C6, 0x6171, 0xE1C7, 0x6173, + 0xE1C8, 0x6152, 0xE1C9, 0x6153, 0xE1CA, 0x6172, 0xE1CB, 0x616C, 0xE1CC, 0x6180, 0xE1CD, 0x6174, 0xE1CE, 0x6154, 0xE1CF, 0x617A, + 0xE1D0, 0x615B, 0xE1D1, 0x6165, 0xE1D2, 0x613B, 0xE1D3, 0x616A, 0xE1D4, 0x6161, 0xE1D5, 0x6156, 0xE1D6, 0x6229, 0xE1D7, 0x6227, + 0xE1D8, 0x622B, 0xE1D9, 0x642B, 0xE1DA, 0x644D, 0xE1DB, 0x645B, 0xE1DC, 0x645D, 0xE1DD, 0x6474, 0xE1DE, 0x6476, 0xE1DF, 0x6472, + 0xE1E0, 0x6473, 0xE1E1, 0x647D, 0xE1E2, 0x6475, 0xE1E3, 0x6466, 0xE1E4, 0x64A6, 0xE1E5, 0x644E, 0xE1E6, 0x6482, 0xE1E7, 0x645E, + 0xE1E8, 0x645C, 0xE1E9, 0x644B, 0xE1EA, 0x6453, 0xE1EB, 0x6460, 0xE1EC, 0x6450, 0xE1ED, 0x647F, 0xE1EE, 0x643F, 0xE1EF, 0x646C, + 0xE1F0, 0x646B, 0xE1F1, 0x6459, 0xE1F2, 0x6465, 0xE1F3, 0x6477, 0xE1F4, 0x6573, 0xE1F5, 0x65A0, 0xE1F6, 0x66A1, 0xE1F7, 0x66A0, + 0xE1F8, 0x669F, 0xE1F9, 0x6705, 0xE1FA, 0x6704, 0xE1FB, 0x6722, 0xE1FC, 0x69B1, 0xE1FD, 0x69B6, 0xE1FE, 0x69C9, 0xE240, 0x69A0, + 0xE241, 0x69CE, 0xE242, 0x6996, 0xE243, 0x69B0, 0xE244, 0x69AC, 0xE245, 0x69BC, 0xE246, 0x6991, 0xE247, 0x6999, 0xE248, 0x698E, + 0xE249, 0x69A7, 0xE24A, 0x698D, 0xE24B, 0x69A9, 0xE24C, 0x69BE, 0xE24D, 0x69AF, 0xE24E, 0x69BF, 0xE24F, 0x69C4, 0xE250, 0x69BD, + 0xE251, 0x69A4, 0xE252, 0x69D4, 0xE253, 0x69B9, 0xE254, 0x69CA, 0xE255, 0x699A, 0xE256, 0x69CF, 0xE257, 0x69B3, 0xE258, 0x6993, + 0xE259, 0x69AA, 0xE25A, 0x69A1, 0xE25B, 0x699E, 0xE25C, 0x69D9, 0xE25D, 0x6997, 0xE25E, 0x6990, 0xE25F, 0x69C2, 0xE260, 0x69B5, + 0xE261, 0x69A5, 0xE262, 0x69C6, 0xE263, 0x6B4A, 0xE264, 0x6B4D, 0xE265, 0x6B4B, 0xE266, 0x6B9E, 0xE267, 0x6B9F, 0xE268, 0x6BA0, + 0xE269, 0x6BC3, 0xE26A, 0x6BC4, 0xE26B, 0x6BFE, 0xE26C, 0x6ECE, 0xE26D, 0x6EF5, 0xE26E, 0x6EF1, 0xE26F, 0x6F03, 0xE270, 0x6F25, + 0xE271, 0x6EF8, 0xE272, 0x6F37, 0xE273, 0x6EFB, 0xE274, 0x6F2E, 0xE275, 0x6F09, 0xE276, 0x6F4E, 0xE277, 0x6F19, 0xE278, 0x6F1A, + 0xE279, 0x6F27, 0xE27A, 0x6F18, 0xE27B, 0x6F3B, 0xE27C, 0x6F12, 0xE27D, 0x6EED, 0xE27E, 0x6F0A, 0xE2A1, 0x6F36, 0xE2A2, 0x6F73, + 0xE2A3, 0x6EF9, 0xE2A4, 0x6EEE, 0xE2A5, 0x6F2D, 0xE2A6, 0x6F40, 0xE2A7, 0x6F30, 0xE2A8, 0x6F3C, 0xE2A9, 0x6F35, 0xE2AA, 0x6EEB, + 0xE2AB, 0x6F07, 0xE2AC, 0x6F0E, 0xE2AD, 0x6F43, 0xE2AE, 0x6F05, 0xE2AF, 0x6EFD, 0xE2B0, 0x6EF6, 0xE2B1, 0x6F39, 0xE2B2, 0x6F1C, + 0xE2B3, 0x6EFC, 0xE2B4, 0x6F3A, 0xE2B5, 0x6F1F, 0xE2B6, 0x6F0D, 0xE2B7, 0x6F1E, 0xE2B8, 0x6F08, 0xE2B9, 0x6F21, 0xE2BA, 0x7187, + 0xE2BB, 0x7190, 0xE2BC, 0x7189, 0xE2BD, 0x7180, 0xE2BE, 0x7185, 0xE2BF, 0x7182, 0xE2C0, 0x718F, 0xE2C1, 0x717B, 0xE2C2, 0x7186, + 0xE2C3, 0x7181, 0xE2C4, 0x7197, 0xE2C5, 0x7244, 0xE2C6, 0x7253, 0xE2C7, 0x7297, 0xE2C8, 0x7295, 0xE2C9, 0x7293, 0xE2CA, 0x7343, + 0xE2CB, 0x734D, 0xE2CC, 0x7351, 0xE2CD, 0x734C, 0xE2CE, 0x7462, 0xE2CF, 0x7473, 0xE2D0, 0x7471, 0xE2D1, 0x7475, 0xE2D2, 0x7472, + 0xE2D3, 0x7467, 0xE2D4, 0x746E, 0xE2D5, 0x7500, 0xE2D6, 0x7502, 0xE2D7, 0x7503, 0xE2D8, 0x757D, 0xE2D9, 0x7590, 0xE2DA, 0x7616, + 0xE2DB, 0x7608, 0xE2DC, 0x760C, 0xE2DD, 0x7615, 0xE2DE, 0x7611, 0xE2DF, 0x760A, 0xE2E0, 0x7614, 0xE2E1, 0x76B8, 0xE2E2, 0x7781, + 0xE2E3, 0x777C, 0xE2E4, 0x7785, 0xE2E5, 0x7782, 0xE2E6, 0x776E, 0xE2E7, 0x7780, 0xE2E8, 0x776F, 0xE2E9, 0x777E, 0xE2EA, 0x7783, + 0xE2EB, 0x78B2, 0xE2EC, 0x78AA, 0xE2ED, 0x78B4, 0xE2EE, 0x78AD, 0xE2EF, 0x78A8, 0xE2F0, 0x787E, 0xE2F1, 0x78AB, 0xE2F2, 0x789E, + 0xE2F3, 0x78A5, 0xE2F4, 0x78A0, 0xE2F5, 0x78AC, 0xE2F6, 0x78A2, 0xE2F7, 0x78A4, 0xE2F8, 0x7998, 0xE2F9, 0x798A, 0xE2FA, 0x798B, + 0xE2FB, 0x7996, 0xE2FC, 0x7995, 0xE2FD, 0x7994, 0xE2FE, 0x7993, 0xE340, 0x7997, 0xE341, 0x7988, 0xE342, 0x7992, 0xE343, 0x7990, + 0xE344, 0x7A2B, 0xE345, 0x7A4A, 0xE346, 0x7A30, 0xE347, 0x7A2F, 0xE348, 0x7A28, 0xE349, 0x7A26, 0xE34A, 0x7AA8, 0xE34B, 0x7AAB, + 0xE34C, 0x7AAC, 0xE34D, 0x7AEE, 0xE34E, 0x7B88, 0xE34F, 0x7B9C, 0xE350, 0x7B8A, 0xE351, 0x7B91, 0xE352, 0x7B90, 0xE353, 0x7B96, + 0xE354, 0x7B8D, 0xE355, 0x7B8C, 0xE356, 0x7B9B, 0xE357, 0x7B8E, 0xE358, 0x7B85, 0xE359, 0x7B98, 0xE35A, 0x5284, 0xE35B, 0x7B99, + 0xE35C, 0x7BA4, 0xE35D, 0x7B82, 0xE35E, 0x7CBB, 0xE35F, 0x7CBF, 0xE360, 0x7CBC, 0xE361, 0x7CBA, 0xE362, 0x7DA7, 0xE363, 0x7DB7, + 0xE364, 0x7DC2, 0xE365, 0x7DA3, 0xE366, 0x7DAA, 0xE367, 0x7DC1, 0xE368, 0x7DC0, 0xE369, 0x7DC5, 0xE36A, 0x7D9D, 0xE36B, 0x7DCE, + 0xE36C, 0x7DC4, 0xE36D, 0x7DC6, 0xE36E, 0x7DCB, 0xE36F, 0x7DCC, 0xE370, 0x7DAF, 0xE371, 0x7DB9, 0xE372, 0x7D96, 0xE373, 0x7DBC, + 0xE374, 0x7D9F, 0xE375, 0x7DA6, 0xE376, 0x7DAE, 0xE377, 0x7DA9, 0xE378, 0x7DA1, 0xE379, 0x7DC9, 0xE37A, 0x7F73, 0xE37B, 0x7FE2, + 0xE37C, 0x7FE3, 0xE37D, 0x7FE5, 0xE37E, 0x7FDE, 0xE3A1, 0x8024, 0xE3A2, 0x805D, 0xE3A3, 0x805C, 0xE3A4, 0x8189, 0xE3A5, 0x8186, + 0xE3A6, 0x8183, 0xE3A7, 0x8187, 0xE3A8, 0x818D, 0xE3A9, 0x818C, 0xE3AA, 0x818B, 0xE3AB, 0x8215, 0xE3AC, 0x8497, 0xE3AD, 0x84A4, + 0xE3AE, 0x84A1, 0xE3AF, 0x849F, 0xE3B0, 0x84BA, 0xE3B1, 0x84CE, 0xE3B2, 0x84C2, 0xE3B3, 0x84AC, 0xE3B4, 0x84AE, 0xE3B5, 0x84AB, + 0xE3B6, 0x84B9, 0xE3B7, 0x84B4, 0xE3B8, 0x84C1, 0xE3B9, 0x84CD, 0xE3BA, 0x84AA, 0xE3BB, 0x849A, 0xE3BC, 0x84B1, 0xE3BD, 0x84D0, + 0xE3BE, 0x849D, 0xE3BF, 0x84A7, 0xE3C0, 0x84BB, 0xE3C1, 0x84A2, 0xE3C2, 0x8494, 0xE3C3, 0x84C7, 0xE3C4, 0x84CC, 0xE3C5, 0x849B, + 0xE3C6, 0x84A9, 0xE3C7, 0x84AF, 0xE3C8, 0x84A8, 0xE3C9, 0x84D6, 0xE3CA, 0x8498, 0xE3CB, 0x84B6, 0xE3CC, 0x84CF, 0xE3CD, 0x84A0, + 0xE3CE, 0x84D7, 0xE3CF, 0x84D4, 0xE3D0, 0x84D2, 0xE3D1, 0x84DB, 0xE3D2, 0x84B0, 0xE3D3, 0x8491, 0xE3D4, 0x8661, 0xE3D5, 0x8733, + 0xE3D6, 0x8723, 0xE3D7, 0x8728, 0xE3D8, 0x876B, 0xE3D9, 0x8740, 0xE3DA, 0x872E, 0xE3DB, 0x871E, 0xE3DC, 0x8721, 0xE3DD, 0x8719, + 0xE3DE, 0x871B, 0xE3DF, 0x8743, 0xE3E0, 0x872C, 0xE3E1, 0x8741, 0xE3E2, 0x873E, 0xE3E3, 0x8746, 0xE3E4, 0x8720, 0xE3E5, 0x8732, + 0xE3E6, 0x872A, 0xE3E7, 0x872D, 0xE3E8, 0x873C, 0xE3E9, 0x8712, 0xE3EA, 0x873A, 0xE3EB, 0x8731, 0xE3EC, 0x8735, 0xE3ED, 0x8742, + 0xE3EE, 0x8726, 0xE3EF, 0x8727, 0xE3F0, 0x8738, 0xE3F1, 0x8724, 0xE3F2, 0x871A, 0xE3F3, 0x8730, 0xE3F4, 0x8711, 0xE3F5, 0x88F7, + 0xE3F6, 0x88E7, 0xE3F7, 0x88F1, 0xE3F8, 0x88F2, 0xE3F9, 0x88FA, 0xE3FA, 0x88FE, 0xE3FB, 0x88EE, 0xE3FC, 0x88FC, 0xE3FD, 0x88F6, + 0xE3FE, 0x88FB, 0xE440, 0x88F0, 0xE441, 0x88EC, 0xE442, 0x88EB, 0xE443, 0x899D, 0xE444, 0x89A1, 0xE445, 0x899F, 0xE446, 0x899E, + 0xE447, 0x89E9, 0xE448, 0x89EB, 0xE449, 0x89E8, 0xE44A, 0x8AAB, 0xE44B, 0x8A99, 0xE44C, 0x8A8B, 0xE44D, 0x8A92, 0xE44E, 0x8A8F, + 0xE44F, 0x8A96, 0xE450, 0x8C3D, 0xE451, 0x8C68, 0xE452, 0x8C69, 0xE453, 0x8CD5, 0xE454, 0x8CCF, 0xE455, 0x8CD7, 0xE456, 0x8D96, + 0xE457, 0x8E09, 0xE458, 0x8E02, 0xE459, 0x8DFF, 0xE45A, 0x8E0D, 0xE45B, 0x8DFD, 0xE45C, 0x8E0A, 0xE45D, 0x8E03, 0xE45E, 0x8E07, + 0xE45F, 0x8E06, 0xE460, 0x8E05, 0xE461, 0x8DFE, 0xE462, 0x8E00, 0xE463, 0x8E04, 0xE464, 0x8F10, 0xE465, 0x8F11, 0xE466, 0x8F0E, + 0xE467, 0x8F0D, 0xE468, 0x9123, 0xE469, 0x911C, 0xE46A, 0x9120, 0xE46B, 0x9122, 0xE46C, 0x911F, 0xE46D, 0x911D, 0xE46E, 0x911A, + 0xE46F, 0x9124, 0xE470, 0x9121, 0xE471, 0x911B, 0xE472, 0x917A, 0xE473, 0x9172, 0xE474, 0x9179, 0xE475, 0x9173, 0xE476, 0x92A5, + 0xE477, 0x92A4, 0xE478, 0x9276, 0xE479, 0x929B, 0xE47A, 0x927A, 0xE47B, 0x92A0, 0xE47C, 0x9294, 0xE47D, 0x92AA, 0xE47E, 0x928D, + 0xE4A1, 0x92A6, 0xE4A2, 0x929A, 0xE4A3, 0x92AB, 0xE4A4, 0x9279, 0xE4A5, 0x9297, 0xE4A6, 0x927F, 0xE4A7, 0x92A3, 0xE4A8, 0x92EE, + 0xE4A9, 0x928E, 0xE4AA, 0x9282, 0xE4AB, 0x9295, 0xE4AC, 0x92A2, 0xE4AD, 0x927D, 0xE4AE, 0x9288, 0xE4AF, 0x92A1, 0xE4B0, 0x928A, + 0xE4B1, 0x9286, 0xE4B2, 0x928C, 0xE4B3, 0x9299, 0xE4B4, 0x92A7, 0xE4B5, 0x927E, 0xE4B6, 0x9287, 0xE4B7, 0x92A9, 0xE4B8, 0x929D, + 0xE4B9, 0x928B, 0xE4BA, 0x922D, 0xE4BB, 0x969E, 0xE4BC, 0x96A1, 0xE4BD, 0x96FF, 0xE4BE, 0x9758, 0xE4BF, 0x977D, 0xE4C0, 0x977A, + 0xE4C1, 0x977E, 0xE4C2, 0x9783, 0xE4C3, 0x9780, 0xE4C4, 0x9782, 0xE4C5, 0x977B, 0xE4C6, 0x9784, 0xE4C7, 0x9781, 0xE4C8, 0x977F, + 0xE4C9, 0x97CE, 0xE4CA, 0x97CD, 0xE4CB, 0x9816, 0xE4CC, 0x98AD, 0xE4CD, 0x98AE, 0xE4CE, 0x9902, 0xE4CF, 0x9900, 0xE4D0, 0x9907, + 0xE4D1, 0x999D, 0xE4D2, 0x999C, 0xE4D3, 0x99C3, 0xE4D4, 0x99B9, 0xE4D5, 0x99BB, 0xE4D6, 0x99BA, 0xE4D7, 0x99C2, 0xE4D8, 0x99BD, + 0xE4D9, 0x99C7, 0xE4DA, 0x9AB1, 0xE4DB, 0x9AE3, 0xE4DC, 0x9AE7, 0xE4DD, 0x9B3E, 0xE4DE, 0x9B3F, 0xE4DF, 0x9B60, 0xE4E0, 0x9B61, + 0xE4E1, 0x9B5F, 0xE4E2, 0x9CF1, 0xE4E3, 0x9CF2, 0xE4E4, 0x9CF5, 0xE4E5, 0x9EA7, 0xE4E6, 0x50FF, 0xE4E7, 0x5103, 0xE4E8, 0x5130, + 0xE4E9, 0x50F8, 0xE4EA, 0x5106, 0xE4EB, 0x5107, 0xE4EC, 0x50F6, 0xE4ED, 0x50FE, 0xE4EE, 0x510B, 0xE4EF, 0x510C, 0xE4F0, 0x50FD, + 0xE4F1, 0x510A, 0xE4F2, 0x528B, 0xE4F3, 0x528C, 0xE4F4, 0x52F1, 0xE4F5, 0x52EF, 0xE4F6, 0x5648, 0xE4F7, 0x5642, 0xE4F8, 0x564C, + 0xE4F9, 0x5635, 0xE4FA, 0x5641, 0xE4FB, 0x564A, 0xE4FC, 0x5649, 0xE4FD, 0x5646, 0xE4FE, 0x5658, 0xE540, 0x565A, 0xE541, 0x5640, + 0xE542, 0x5633, 0xE543, 0x563D, 0xE544, 0x562C, 0xE545, 0x563E, 0xE546, 0x5638, 0xE547, 0x562A, 0xE548, 0x563A, 0xE549, 0x571A, + 0xE54A, 0x58AB, 0xE54B, 0x589D, 0xE54C, 0x58B1, 0xE54D, 0x58A0, 0xE54E, 0x58A3, 0xE54F, 0x58AF, 0xE550, 0x58AC, 0xE551, 0x58A5, + 0xE552, 0x58A1, 0xE553, 0x58FF, 0xE554, 0x5AFF, 0xE555, 0x5AF4, 0xE556, 0x5AFD, 0xE557, 0x5AF7, 0xE558, 0x5AF6, 0xE559, 0x5B03, + 0xE55A, 0x5AF8, 0xE55B, 0x5B02, 0xE55C, 0x5AF9, 0xE55D, 0x5B01, 0xE55E, 0x5B07, 0xE55F, 0x5B05, 0xE560, 0x5B0F, 0xE561, 0x5C67, + 0xE562, 0x5D99, 0xE563, 0x5D97, 0xE564, 0x5D9F, 0xE565, 0x5D92, 0xE566, 0x5DA2, 0xE567, 0x5D93, 0xE568, 0x5D95, 0xE569, 0x5DA0, + 0xE56A, 0x5D9C, 0xE56B, 0x5DA1, 0xE56C, 0x5D9A, 0xE56D, 0x5D9E, 0xE56E, 0x5E69, 0xE56F, 0x5E5D, 0xE570, 0x5E60, 0xE571, 0x5E5C, + 0xE572, 0x7DF3, 0xE573, 0x5EDB, 0xE574, 0x5EDE, 0xE575, 0x5EE1, 0xE576, 0x5F49, 0xE577, 0x5FB2, 0xE578, 0x618B, 0xE579, 0x6183, + 0xE57A, 0x6179, 0xE57B, 0x61B1, 0xE57C, 0x61B0, 0xE57D, 0x61A2, 0xE57E, 0x6189, 0xE5A1, 0x619B, 0xE5A2, 0x6193, 0xE5A3, 0x61AF, + 0xE5A4, 0x61AD, 0xE5A5, 0x619F, 0xE5A6, 0x6192, 0xE5A7, 0x61AA, 0xE5A8, 0x61A1, 0xE5A9, 0x618D, 0xE5AA, 0x6166, 0xE5AB, 0x61B3, + 0xE5AC, 0x622D, 0xE5AD, 0x646E, 0xE5AE, 0x6470, 0xE5AF, 0x6496, 0xE5B0, 0x64A0, 0xE5B1, 0x6485, 0xE5B2, 0x6497, 0xE5B3, 0x649C, + 0xE5B4, 0x648F, 0xE5B5, 0x648B, 0xE5B6, 0x648A, 0xE5B7, 0x648C, 0xE5B8, 0x64A3, 0xE5B9, 0x649F, 0xE5BA, 0x6468, 0xE5BB, 0x64B1, + 0xE5BC, 0x6498, 0xE5BD, 0x6576, 0xE5BE, 0x657A, 0xE5BF, 0x6579, 0xE5C0, 0x657B, 0xE5C1, 0x65B2, 0xE5C2, 0x65B3, 0xE5C3, 0x66B5, + 0xE5C4, 0x66B0, 0xE5C5, 0x66A9, 0xE5C6, 0x66B2, 0xE5C7, 0x66B7, 0xE5C8, 0x66AA, 0xE5C9, 0x66AF, 0xE5CA, 0x6A00, 0xE5CB, 0x6A06, + 0xE5CC, 0x6A17, 0xE5CD, 0x69E5, 0xE5CE, 0x69F8, 0xE5CF, 0x6A15, 0xE5D0, 0x69F1, 0xE5D1, 0x69E4, 0xE5D2, 0x6A20, 0xE5D3, 0x69FF, + 0xE5D4, 0x69EC, 0xE5D5, 0x69E2, 0xE5D6, 0x6A1B, 0xE5D7, 0x6A1D, 0xE5D8, 0x69FE, 0xE5D9, 0x6A27, 0xE5DA, 0x69F2, 0xE5DB, 0x69EE, + 0xE5DC, 0x6A14, 0xE5DD, 0x69F7, 0xE5DE, 0x69E7, 0xE5DF, 0x6A40, 0xE5E0, 0x6A08, 0xE5E1, 0x69E6, 0xE5E2, 0x69FB, 0xE5E3, 0x6A0D, + 0xE5E4, 0x69FC, 0xE5E5, 0x69EB, 0xE5E6, 0x6A09, 0xE5E7, 0x6A04, 0xE5E8, 0x6A18, 0xE5E9, 0x6A25, 0xE5EA, 0x6A0F, 0xE5EB, 0x69F6, + 0xE5EC, 0x6A26, 0xE5ED, 0x6A07, 0xE5EE, 0x69F4, 0xE5EF, 0x6A16, 0xE5F0, 0x6B51, 0xE5F1, 0x6BA5, 0xE5F2, 0x6BA3, 0xE5F3, 0x6BA2, + 0xE5F4, 0x6BA6, 0xE5F5, 0x6C01, 0xE5F6, 0x6C00, 0xE5F7, 0x6BFF, 0xE5F8, 0x6C02, 0xE5F9, 0x6F41, 0xE5FA, 0x6F26, 0xE5FB, 0x6F7E, + 0xE5FC, 0x6F87, 0xE5FD, 0x6FC6, 0xE5FE, 0x6F92, 0xE640, 0x6F8D, 0xE641, 0x6F89, 0xE642, 0x6F8C, 0xE643, 0x6F62, 0xE644, 0x6F4F, + 0xE645, 0x6F85, 0xE646, 0x6F5A, 0xE647, 0x6F96, 0xE648, 0x6F76, 0xE649, 0x6F6C, 0xE64A, 0x6F82, 0xE64B, 0x6F55, 0xE64C, 0x6F72, + 0xE64D, 0x6F52, 0xE64E, 0x6F50, 0xE64F, 0x6F57, 0xE650, 0x6F94, 0xE651, 0x6F93, 0xE652, 0x6F5D, 0xE653, 0x6F00, 0xE654, 0x6F61, + 0xE655, 0x6F6B, 0xE656, 0x6F7D, 0xE657, 0x6F67, 0xE658, 0x6F90, 0xE659, 0x6F53, 0xE65A, 0x6F8B, 0xE65B, 0x6F69, 0xE65C, 0x6F7F, + 0xE65D, 0x6F95, 0xE65E, 0x6F63, 0xE65F, 0x6F77, 0xE660, 0x6F6A, 0xE661, 0x6F7B, 0xE662, 0x71B2, 0xE663, 0x71AF, 0xE664, 0x719B, + 0xE665, 0x71B0, 0xE666, 0x71A0, 0xE667, 0x719A, 0xE668, 0x71A9, 0xE669, 0x71B5, 0xE66A, 0x719D, 0xE66B, 0x71A5, 0xE66C, 0x719E, + 0xE66D, 0x71A4, 0xE66E, 0x71A1, 0xE66F, 0x71AA, 0xE670, 0x719C, 0xE671, 0x71A7, 0xE672, 0x71B3, 0xE673, 0x7298, 0xE674, 0x729A, + 0xE675, 0x7358, 0xE676, 0x7352, 0xE677, 0x735E, 0xE678, 0x735F, 0xE679, 0x7360, 0xE67A, 0x735D, 0xE67B, 0x735B, 0xE67C, 0x7361, + 0xE67D, 0x735A, 0xE67E, 0x7359, 0xE6A1, 0x7362, 0xE6A2, 0x7487, 0xE6A3, 0x7489, 0xE6A4, 0x748A, 0xE6A5, 0x7486, 0xE6A6, 0x7481, + 0xE6A7, 0x747D, 0xE6A8, 0x7485, 0xE6A9, 0x7488, 0xE6AA, 0x747C, 0xE6AB, 0x7479, 0xE6AC, 0x7508, 0xE6AD, 0x7507, 0xE6AE, 0x757E, + 0xE6AF, 0x7625, 0xE6B0, 0x761E, 0xE6B1, 0x7619, 0xE6B2, 0x761D, 0xE6B3, 0x761C, 0xE6B4, 0x7623, 0xE6B5, 0x761A, 0xE6B6, 0x7628, + 0xE6B7, 0x761B, 0xE6B8, 0x769C, 0xE6B9, 0x769D, 0xE6BA, 0x769E, 0xE6BB, 0x769B, 0xE6BC, 0x778D, 0xE6BD, 0x778F, 0xE6BE, 0x7789, + 0xE6BF, 0x7788, 0xE6C0, 0x78CD, 0xE6C1, 0x78BB, 0xE6C2, 0x78CF, 0xE6C3, 0x78CC, 0xE6C4, 0x78D1, 0xE6C5, 0x78CE, 0xE6C6, 0x78D4, + 0xE6C7, 0x78C8, 0xE6C8, 0x78C3, 0xE6C9, 0x78C4, 0xE6CA, 0x78C9, 0xE6CB, 0x799A, 0xE6CC, 0x79A1, 0xE6CD, 0x79A0, 0xE6CE, 0x799C, + 0xE6CF, 0x79A2, 0xE6D0, 0x799B, 0xE6D1, 0x6B76, 0xE6D2, 0x7A39, 0xE6D3, 0x7AB2, 0xE6D4, 0x7AB4, 0xE6D5, 0x7AB3, 0xE6D6, 0x7BB7, + 0xE6D7, 0x7BCB, 0xE6D8, 0x7BBE, 0xE6D9, 0x7BAC, 0xE6DA, 0x7BCE, 0xE6DB, 0x7BAF, 0xE6DC, 0x7BB9, 0xE6DD, 0x7BCA, 0xE6DE, 0x7BB5, + 0xE6DF, 0x7CC5, 0xE6E0, 0x7CC8, 0xE6E1, 0x7CCC, 0xE6E2, 0x7CCB, 0xE6E3, 0x7DF7, 0xE6E4, 0x7DDB, 0xE6E5, 0x7DEA, 0xE6E6, 0x7DE7, + 0xE6E7, 0x7DD7, 0xE6E8, 0x7DE1, 0xE6E9, 0x7E03, 0xE6EA, 0x7DFA, 0xE6EB, 0x7DE6, 0xE6EC, 0x7DF6, 0xE6ED, 0x7DF1, 0xE6EE, 0x7DF0, + 0xE6EF, 0x7DEE, 0xE6F0, 0x7DDF, 0xE6F1, 0x7F76, 0xE6F2, 0x7FAC, 0xE6F3, 0x7FB0, 0xE6F4, 0x7FAD, 0xE6F5, 0x7FED, 0xE6F6, 0x7FEB, + 0xE6F7, 0x7FEA, 0xE6F8, 0x7FEC, 0xE6F9, 0x7FE6, 0xE6FA, 0x7FE8, 0xE6FB, 0x8064, 0xE6FC, 0x8067, 0xE6FD, 0x81A3, 0xE6FE, 0x819F, + 0xE740, 0x819E, 0xE741, 0x8195, 0xE742, 0x81A2, 0xE743, 0x8199, 0xE744, 0x8197, 0xE745, 0x8216, 0xE746, 0x824F, 0xE747, 0x8253, + 0xE748, 0x8252, 0xE749, 0x8250, 0xE74A, 0x824E, 0xE74B, 0x8251, 0xE74C, 0x8524, 0xE74D, 0x853B, 0xE74E, 0x850F, 0xE74F, 0x8500, + 0xE750, 0x8529, 0xE751, 0x850E, 0xE752, 0x8509, 0xE753, 0x850D, 0xE754, 0x851F, 0xE755, 0x850A, 0xE756, 0x8527, 0xE757, 0x851C, + 0xE758, 0x84FB, 0xE759, 0x852B, 0xE75A, 0x84FA, 0xE75B, 0x8508, 0xE75C, 0x850C, 0xE75D, 0x84F4, 0xE75E, 0x852A, 0xE75F, 0x84F2, + 0xE760, 0x8515, 0xE761, 0x84F7, 0xE762, 0x84EB, 0xE763, 0x84F3, 0xE764, 0x84FC, 0xE765, 0x8512, 0xE766, 0x84EA, 0xE767, 0x84E9, + 0xE768, 0x8516, 0xE769, 0x84FE, 0xE76A, 0x8528, 0xE76B, 0x851D, 0xE76C, 0x852E, 0xE76D, 0x8502, 0xE76E, 0x84FD, 0xE76F, 0x851E, + 0xE770, 0x84F6, 0xE771, 0x8531, 0xE772, 0x8526, 0xE773, 0x84E7, 0xE774, 0x84E8, 0xE775, 0x84F0, 0xE776, 0x84EF, 0xE777, 0x84F9, + 0xE778, 0x8518, 0xE779, 0x8520, 0xE77A, 0x8530, 0xE77B, 0x850B, 0xE77C, 0x8519, 0xE77D, 0x852F, 0xE77E, 0x8662, 0xE7A1, 0x8756, + 0xE7A2, 0x8763, 0xE7A3, 0x8764, 0xE7A4, 0x8777, 0xE7A5, 0x87E1, 0xE7A6, 0x8773, 0xE7A7, 0x8758, 0xE7A8, 0x8754, 0xE7A9, 0x875B, + 0xE7AA, 0x8752, 0xE7AB, 0x8761, 0xE7AC, 0x875A, 0xE7AD, 0x8751, 0xE7AE, 0x875E, 0xE7AF, 0x876D, 0xE7B0, 0x876A, 0xE7B1, 0x8750, + 0xE7B2, 0x874E, 0xE7B3, 0x875F, 0xE7B4, 0x875D, 0xE7B5, 0x876F, 0xE7B6, 0x876C, 0xE7B7, 0x877A, 0xE7B8, 0x876E, 0xE7B9, 0x875C, + 0xE7BA, 0x8765, 0xE7BB, 0x874F, 0xE7BC, 0x877B, 0xE7BD, 0x8775, 0xE7BE, 0x8762, 0xE7BF, 0x8767, 0xE7C0, 0x8769, 0xE7C1, 0x885A, + 0xE7C2, 0x8905, 0xE7C3, 0x890C, 0xE7C4, 0x8914, 0xE7C5, 0x890B, 0xE7C6, 0x8917, 0xE7C7, 0x8918, 0xE7C8, 0x8919, 0xE7C9, 0x8906, + 0xE7CA, 0x8916, 0xE7CB, 0x8911, 0xE7CC, 0x890E, 0xE7CD, 0x8909, 0xE7CE, 0x89A2, 0xE7CF, 0x89A4, 0xE7D0, 0x89A3, 0xE7D1, 0x89ED, + 0xE7D2, 0x89F0, 0xE7D3, 0x89EC, 0xE7D4, 0x8ACF, 0xE7D5, 0x8AC6, 0xE7D6, 0x8AB8, 0xE7D7, 0x8AD3, 0xE7D8, 0x8AD1, 0xE7D9, 0x8AD4, + 0xE7DA, 0x8AD5, 0xE7DB, 0x8ABB, 0xE7DC, 0x8AD7, 0xE7DD, 0x8ABE, 0xE7DE, 0x8AC0, 0xE7DF, 0x8AC5, 0xE7E0, 0x8AD8, 0xE7E1, 0x8AC3, + 0xE7E2, 0x8ABA, 0xE7E3, 0x8ABD, 0xE7E4, 0x8AD9, 0xE7E5, 0x8C3E, 0xE7E6, 0x8C4D, 0xE7E7, 0x8C8F, 0xE7E8, 0x8CE5, 0xE7E9, 0x8CDF, + 0xE7EA, 0x8CD9, 0xE7EB, 0x8CE8, 0xE7EC, 0x8CDA, 0xE7ED, 0x8CDD, 0xE7EE, 0x8CE7, 0xE7EF, 0x8DA0, 0xE7F0, 0x8D9C, 0xE7F1, 0x8DA1, + 0xE7F2, 0x8D9B, 0xE7F3, 0x8E20, 0xE7F4, 0x8E23, 0xE7F5, 0x8E25, 0xE7F6, 0x8E24, 0xE7F7, 0x8E2E, 0xE7F8, 0x8E15, 0xE7F9, 0x8E1B, + 0xE7FA, 0x8E16, 0xE7FB, 0x8E11, 0xE7FC, 0x8E19, 0xE7FD, 0x8E26, 0xE7FE, 0x8E27, 0xE840, 0x8E14, 0xE841, 0x8E12, 0xE842, 0x8E18, + 0xE843, 0x8E13, 0xE844, 0x8E1C, 0xE845, 0x8E17, 0xE846, 0x8E1A, 0xE847, 0x8F2C, 0xE848, 0x8F24, 0xE849, 0x8F18, 0xE84A, 0x8F1A, + 0xE84B, 0x8F20, 0xE84C, 0x8F23, 0xE84D, 0x8F16, 0xE84E, 0x8F17, 0xE84F, 0x9073, 0xE850, 0x9070, 0xE851, 0x906F, 0xE852, 0x9067, + 0xE853, 0x906B, 0xE854, 0x912F, 0xE855, 0x912B, 0xE856, 0x9129, 0xE857, 0x912A, 0xE858, 0x9132, 0xE859, 0x9126, 0xE85A, 0x912E, + 0xE85B, 0x9185, 0xE85C, 0x9186, 0xE85D, 0x918A, 0xE85E, 0x9181, 0xE85F, 0x9182, 0xE860, 0x9184, 0xE861, 0x9180, 0xE862, 0x92D0, + 0xE863, 0x92C3, 0xE864, 0x92C4, 0xE865, 0x92C0, 0xE866, 0x92D9, 0xE867, 0x92B6, 0xE868, 0x92CF, 0xE869, 0x92F1, 0xE86A, 0x92DF, + 0xE86B, 0x92D8, 0xE86C, 0x92E9, 0xE86D, 0x92D7, 0xE86E, 0x92DD, 0xE86F, 0x92CC, 0xE870, 0x92EF, 0xE871, 0x92C2, 0xE872, 0x92E8, + 0xE873, 0x92CA, 0xE874, 0x92C8, 0xE875, 0x92CE, 0xE876, 0x92E6, 0xE877, 0x92CD, 0xE878, 0x92D5, 0xE879, 0x92C9, 0xE87A, 0x92E0, + 0xE87B, 0x92DE, 0xE87C, 0x92E7, 0xE87D, 0x92D1, 0xE87E, 0x92D3, 0xE8A1, 0x92B5, 0xE8A2, 0x92E1, 0xE8A3, 0x92C6, 0xE8A4, 0x92B4, + 0xE8A5, 0x957C, 0xE8A6, 0x95AC, 0xE8A7, 0x95AB, 0xE8A8, 0x95AE, 0xE8A9, 0x95B0, 0xE8AA, 0x96A4, 0xE8AB, 0x96A2, 0xE8AC, 0x96D3, + 0xE8AD, 0x9705, 0xE8AE, 0x9708, 0xE8AF, 0x9702, 0xE8B0, 0x975A, 0xE8B1, 0x978A, 0xE8B2, 0x978E, 0xE8B3, 0x9788, 0xE8B4, 0x97D0, + 0xE8B5, 0x97CF, 0xE8B6, 0x981E, 0xE8B7, 0x981D, 0xE8B8, 0x9826, 0xE8B9, 0x9829, 0xE8BA, 0x9828, 0xE8BB, 0x9820, 0xE8BC, 0x981B, + 0xE8BD, 0x9827, 0xE8BE, 0x98B2, 0xE8BF, 0x9908, 0xE8C0, 0x98FA, 0xE8C1, 0x9911, 0xE8C2, 0x9914, 0xE8C3, 0x9916, 0xE8C4, 0x9917, + 0xE8C5, 0x9915, 0xE8C6, 0x99DC, 0xE8C7, 0x99CD, 0xE8C8, 0x99CF, 0xE8C9, 0x99D3, 0xE8CA, 0x99D4, 0xE8CB, 0x99CE, 0xE8CC, 0x99C9, + 0xE8CD, 0x99D6, 0xE8CE, 0x99D8, 0xE8CF, 0x99CB, 0xE8D0, 0x99D7, 0xE8D1, 0x99CC, 0xE8D2, 0x9AB3, 0xE8D3, 0x9AEC, 0xE8D4, 0x9AEB, + 0xE8D5, 0x9AF3, 0xE8D6, 0x9AF2, 0xE8D7, 0x9AF1, 0xE8D8, 0x9B46, 0xE8D9, 0x9B43, 0xE8DA, 0x9B67, 0xE8DB, 0x9B74, 0xE8DC, 0x9B71, + 0xE8DD, 0x9B66, 0xE8DE, 0x9B76, 0xE8DF, 0x9B75, 0xE8E0, 0x9B70, 0xE8E1, 0x9B68, 0xE8E2, 0x9B64, 0xE8E3, 0x9B6C, 0xE8E4, 0x9CFC, + 0xE8E5, 0x9CFA, 0xE8E6, 0x9CFD, 0xE8E7, 0x9CFF, 0xE8E8, 0x9CF7, 0xE8E9, 0x9D07, 0xE8EA, 0x9D00, 0xE8EB, 0x9CF9, 0xE8EC, 0x9CFB, + 0xE8ED, 0x9D08, 0xE8EE, 0x9D05, 0xE8EF, 0x9D04, 0xE8F0, 0x9E83, 0xE8F1, 0x9ED3, 0xE8F2, 0x9F0F, 0xE8F3, 0x9F10, 0xE8F4, 0x511C, + 0xE8F5, 0x5113, 0xE8F6, 0x5117, 0xE8F7, 0x511A, 0xE8F8, 0x5111, 0xE8F9, 0x51DE, 0xE8FA, 0x5334, 0xE8FB, 0x53E1, 0xE8FC, 0x5670, + 0xE8FD, 0x5660, 0xE8FE, 0x566E, 0xE940, 0x5673, 0xE941, 0x5666, 0xE942, 0x5663, 0xE943, 0x566D, 0xE944, 0x5672, 0xE945, 0x565E, + 0xE946, 0x5677, 0xE947, 0x571C, 0xE948, 0x571B, 0xE949, 0x58C8, 0xE94A, 0x58BD, 0xE94B, 0x58C9, 0xE94C, 0x58BF, 0xE94D, 0x58BA, + 0xE94E, 0x58C2, 0xE94F, 0x58BC, 0xE950, 0x58C6, 0xE951, 0x5B17, 0xE952, 0x5B19, 0xE953, 0x5B1B, 0xE954, 0x5B21, 0xE955, 0x5B14, + 0xE956, 0x5B13, 0xE957, 0x5B10, 0xE958, 0x5B16, 0xE959, 0x5B28, 0xE95A, 0x5B1A, 0xE95B, 0x5B20, 0xE95C, 0x5B1E, 0xE95D, 0x5BEF, + 0xE95E, 0x5DAC, 0xE95F, 0x5DB1, 0xE960, 0x5DA9, 0xE961, 0x5DA7, 0xE962, 0x5DB5, 0xE963, 0x5DB0, 0xE964, 0x5DAE, 0xE965, 0x5DAA, + 0xE966, 0x5DA8, 0xE967, 0x5DB2, 0xE968, 0x5DAD, 0xE969, 0x5DAF, 0xE96A, 0x5DB4, 0xE96B, 0x5E67, 0xE96C, 0x5E68, 0xE96D, 0x5E66, + 0xE96E, 0x5E6F, 0xE96F, 0x5EE9, 0xE970, 0x5EE7, 0xE971, 0x5EE6, 0xE972, 0x5EE8, 0xE973, 0x5EE5, 0xE974, 0x5F4B, 0xE975, 0x5FBC, + 0xE976, 0x619D, 0xE977, 0x61A8, 0xE978, 0x6196, 0xE979, 0x61C5, 0xE97A, 0x61B4, 0xE97B, 0x61C6, 0xE97C, 0x61C1, 0xE97D, 0x61CC, + 0xE97E, 0x61BA, 0xE9A1, 0x61BF, 0xE9A2, 0x61B8, 0xE9A3, 0x618C, 0xE9A4, 0x64D7, 0xE9A5, 0x64D6, 0xE9A6, 0x64D0, 0xE9A7, 0x64CF, + 0xE9A8, 0x64C9, 0xE9A9, 0x64BD, 0xE9AA, 0x6489, 0xE9AB, 0x64C3, 0xE9AC, 0x64DB, 0xE9AD, 0x64F3, 0xE9AE, 0x64D9, 0xE9AF, 0x6533, + 0xE9B0, 0x657F, 0xE9B1, 0x657C, 0xE9B2, 0x65A2, 0xE9B3, 0x66C8, 0xE9B4, 0x66BE, 0xE9B5, 0x66C0, 0xE9B6, 0x66CA, 0xE9B7, 0x66CB, + 0xE9B8, 0x66CF, 0xE9B9, 0x66BD, 0xE9BA, 0x66BB, 0xE9BB, 0x66BA, 0xE9BC, 0x66CC, 0xE9BD, 0x6723, 0xE9BE, 0x6A34, 0xE9BF, 0x6A66, + 0xE9C0, 0x6A49, 0xE9C1, 0x6A67, 0xE9C2, 0x6A32, 0xE9C3, 0x6A68, 0xE9C4, 0x6A3E, 0xE9C5, 0x6A5D, 0xE9C6, 0x6A6D, 0xE9C7, 0x6A76, + 0xE9C8, 0x6A5B, 0xE9C9, 0x6A51, 0xE9CA, 0x6A28, 0xE9CB, 0x6A5A, 0xE9CC, 0x6A3B, 0xE9CD, 0x6A3F, 0xE9CE, 0x6A41, 0xE9CF, 0x6A6A, + 0xE9D0, 0x6A64, 0xE9D1, 0x6A50, 0xE9D2, 0x6A4F, 0xE9D3, 0x6A54, 0xE9D4, 0x6A6F, 0xE9D5, 0x6A69, 0xE9D6, 0x6A60, 0xE9D7, 0x6A3C, + 0xE9D8, 0x6A5E, 0xE9D9, 0x6A56, 0xE9DA, 0x6A55, 0xE9DB, 0x6A4D, 0xE9DC, 0x6A4E, 0xE9DD, 0x6A46, 0xE9DE, 0x6B55, 0xE9DF, 0x6B54, + 0xE9E0, 0x6B56, 0xE9E1, 0x6BA7, 0xE9E2, 0x6BAA, 0xE9E3, 0x6BAB, 0xE9E4, 0x6BC8, 0xE9E5, 0x6BC7, 0xE9E6, 0x6C04, 0xE9E7, 0x6C03, + 0xE9E8, 0x6C06, 0xE9E9, 0x6FAD, 0xE9EA, 0x6FCB, 0xE9EB, 0x6FA3, 0xE9EC, 0x6FC7, 0xE9ED, 0x6FBC, 0xE9EE, 0x6FCE, 0xE9EF, 0x6FC8, + 0xE9F0, 0x6F5E, 0xE9F1, 0x6FC4, 0xE9F2, 0x6FBD, 0xE9F3, 0x6F9E, 0xE9F4, 0x6FCA, 0xE9F5, 0x6FA8, 0xE9F6, 0x7004, 0xE9F7, 0x6FA5, + 0xE9F8, 0x6FAE, 0xE9F9, 0x6FBA, 0xE9FA, 0x6FAC, 0xE9FB, 0x6FAA, 0xE9FC, 0x6FCF, 0xE9FD, 0x6FBF, 0xE9FE, 0x6FB8, 0xEA40, 0x6FA2, + 0xEA41, 0x6FC9, 0xEA42, 0x6FAB, 0xEA43, 0x6FCD, 0xEA44, 0x6FAF, 0xEA45, 0x6FB2, 0xEA46, 0x6FB0, 0xEA47, 0x71C5, 0xEA48, 0x71C2, + 0xEA49, 0x71BF, 0xEA4A, 0x71B8, 0xEA4B, 0x71D6, 0xEA4C, 0x71C0, 0xEA4D, 0x71C1, 0xEA4E, 0x71CB, 0xEA4F, 0x71D4, 0xEA50, 0x71CA, + 0xEA51, 0x71C7, 0xEA52, 0x71CF, 0xEA53, 0x71BD, 0xEA54, 0x71D8, 0xEA55, 0x71BC, 0xEA56, 0x71C6, 0xEA57, 0x71DA, 0xEA58, 0x71DB, + 0xEA59, 0x729D, 0xEA5A, 0x729E, 0xEA5B, 0x7369, 0xEA5C, 0x7366, 0xEA5D, 0x7367, 0xEA5E, 0x736C, 0xEA5F, 0x7365, 0xEA60, 0x736B, + 0xEA61, 0x736A, 0xEA62, 0x747F, 0xEA63, 0x749A, 0xEA64, 0x74A0, 0xEA65, 0x7494, 0xEA66, 0x7492, 0xEA67, 0x7495, 0xEA68, 0x74A1, + 0xEA69, 0x750B, 0xEA6A, 0x7580, 0xEA6B, 0x762F, 0xEA6C, 0x762D, 0xEA6D, 0x7631, 0xEA6E, 0x763D, 0xEA6F, 0x7633, 0xEA70, 0x763C, + 0xEA71, 0x7635, 0xEA72, 0x7632, 0xEA73, 0x7630, 0xEA74, 0x76BB, 0xEA75, 0x76E6, 0xEA76, 0x779A, 0xEA77, 0x779D, 0xEA78, 0x77A1, + 0xEA79, 0x779C, 0xEA7A, 0x779B, 0xEA7B, 0x77A2, 0xEA7C, 0x77A3, 0xEA7D, 0x7795, 0xEA7E, 0x7799, 0xEAA1, 0x7797, 0xEAA2, 0x78DD, + 0xEAA3, 0x78E9, 0xEAA4, 0x78E5, 0xEAA5, 0x78EA, 0xEAA6, 0x78DE, 0xEAA7, 0x78E3, 0xEAA8, 0x78DB, 0xEAA9, 0x78E1, 0xEAAA, 0x78E2, + 0xEAAB, 0x78ED, 0xEAAC, 0x78DF, 0xEAAD, 0x78E0, 0xEAAE, 0x79A4, 0xEAAF, 0x7A44, 0xEAB0, 0x7A48, 0xEAB1, 0x7A47, 0xEAB2, 0x7AB6, + 0xEAB3, 0x7AB8, 0xEAB4, 0x7AB5, 0xEAB5, 0x7AB1, 0xEAB6, 0x7AB7, 0xEAB7, 0x7BDE, 0xEAB8, 0x7BE3, 0xEAB9, 0x7BE7, 0xEABA, 0x7BDD, + 0xEABB, 0x7BD5, 0xEABC, 0x7BE5, 0xEABD, 0x7BDA, 0xEABE, 0x7BE8, 0xEABF, 0x7BF9, 0xEAC0, 0x7BD4, 0xEAC1, 0x7BEA, 0xEAC2, 0x7BE2, + 0xEAC3, 0x7BDC, 0xEAC4, 0x7BEB, 0xEAC5, 0x7BD8, 0xEAC6, 0x7BDF, 0xEAC7, 0x7CD2, 0xEAC8, 0x7CD4, 0xEAC9, 0x7CD7, 0xEACA, 0x7CD0, + 0xEACB, 0x7CD1, 0xEACC, 0x7E12, 0xEACD, 0x7E21, 0xEACE, 0x7E17, 0xEACF, 0x7E0C, 0xEAD0, 0x7E1F, 0xEAD1, 0x7E20, 0xEAD2, 0x7E13, + 0xEAD3, 0x7E0E, 0xEAD4, 0x7E1C, 0xEAD5, 0x7E15, 0xEAD6, 0x7E1A, 0xEAD7, 0x7E22, 0xEAD8, 0x7E0B, 0xEAD9, 0x7E0F, 0xEADA, 0x7E16, + 0xEADB, 0x7E0D, 0xEADC, 0x7E14, 0xEADD, 0x7E25, 0xEADE, 0x7E24, 0xEADF, 0x7F43, 0xEAE0, 0x7F7B, 0xEAE1, 0x7F7C, 0xEAE2, 0x7F7A, + 0xEAE3, 0x7FB1, 0xEAE4, 0x7FEF, 0xEAE5, 0x802A, 0xEAE6, 0x8029, 0xEAE7, 0x806C, 0xEAE8, 0x81B1, 0xEAE9, 0x81A6, 0xEAEA, 0x81AE, + 0xEAEB, 0x81B9, 0xEAEC, 0x81B5, 0xEAED, 0x81AB, 0xEAEE, 0x81B0, 0xEAEF, 0x81AC, 0xEAF0, 0x81B4, 0xEAF1, 0x81B2, 0xEAF2, 0x81B7, + 0xEAF3, 0x81A7, 0xEAF4, 0x81F2, 0xEAF5, 0x8255, 0xEAF6, 0x8256, 0xEAF7, 0x8257, 0xEAF8, 0x8556, 0xEAF9, 0x8545, 0xEAFA, 0x856B, + 0xEAFB, 0x854D, 0xEAFC, 0x8553, 0xEAFD, 0x8561, 0xEAFE, 0x8558, 0xEB40, 0x8540, 0xEB41, 0x8546, 0xEB42, 0x8564, 0xEB43, 0x8541, + 0xEB44, 0x8562, 0xEB45, 0x8544, 0xEB46, 0x8551, 0xEB47, 0x8547, 0xEB48, 0x8563, 0xEB49, 0x853E, 0xEB4A, 0x855B, 0xEB4B, 0x8571, + 0xEB4C, 0x854E, 0xEB4D, 0x856E, 0xEB4E, 0x8575, 0xEB4F, 0x8555, 0xEB50, 0x8567, 0xEB51, 0x8560, 0xEB52, 0x858C, 0xEB53, 0x8566, + 0xEB54, 0x855D, 0xEB55, 0x8554, 0xEB56, 0x8565, 0xEB57, 0x856C, 0xEB58, 0x8663, 0xEB59, 0x8665, 0xEB5A, 0x8664, 0xEB5B, 0x879B, + 0xEB5C, 0x878F, 0xEB5D, 0x8797, 0xEB5E, 0x8793, 0xEB5F, 0x8792, 0xEB60, 0x8788, 0xEB61, 0x8781, 0xEB62, 0x8796, 0xEB63, 0x8798, + 0xEB64, 0x8779, 0xEB65, 0x8787, 0xEB66, 0x87A3, 0xEB67, 0x8785, 0xEB68, 0x8790, 0xEB69, 0x8791, 0xEB6A, 0x879D, 0xEB6B, 0x8784, + 0xEB6C, 0x8794, 0xEB6D, 0x879C, 0xEB6E, 0x879A, 0xEB6F, 0x8789, 0xEB70, 0x891E, 0xEB71, 0x8926, 0xEB72, 0x8930, 0xEB73, 0x892D, + 0xEB74, 0x892E, 0xEB75, 0x8927, 0xEB76, 0x8931, 0xEB77, 0x8922, 0xEB78, 0x8929, 0xEB79, 0x8923, 0xEB7A, 0x892F, 0xEB7B, 0x892C, + 0xEB7C, 0x891F, 0xEB7D, 0x89F1, 0xEB7E, 0x8AE0, 0xEBA1, 0x8AE2, 0xEBA2, 0x8AF2, 0xEBA3, 0x8AF4, 0xEBA4, 0x8AF5, 0xEBA5, 0x8ADD, + 0xEBA6, 0x8B14, 0xEBA7, 0x8AE4, 0xEBA8, 0x8ADF, 0xEBA9, 0x8AF0, 0xEBAA, 0x8AC8, 0xEBAB, 0x8ADE, 0xEBAC, 0x8AE1, 0xEBAD, 0x8AE8, + 0xEBAE, 0x8AFF, 0xEBAF, 0x8AEF, 0xEBB0, 0x8AFB, 0xEBB1, 0x8C91, 0xEBB2, 0x8C92, 0xEBB3, 0x8C90, 0xEBB4, 0x8CF5, 0xEBB5, 0x8CEE, + 0xEBB6, 0x8CF1, 0xEBB7, 0x8CF0, 0xEBB8, 0x8CF3, 0xEBB9, 0x8D6C, 0xEBBA, 0x8D6E, 0xEBBB, 0x8DA5, 0xEBBC, 0x8DA7, 0xEBBD, 0x8E33, + 0xEBBE, 0x8E3E, 0xEBBF, 0x8E38, 0xEBC0, 0x8E40, 0xEBC1, 0x8E45, 0xEBC2, 0x8E36, 0xEBC3, 0x8E3C, 0xEBC4, 0x8E3D, 0xEBC5, 0x8E41, + 0xEBC6, 0x8E30, 0xEBC7, 0x8E3F, 0xEBC8, 0x8EBD, 0xEBC9, 0x8F36, 0xEBCA, 0x8F2E, 0xEBCB, 0x8F35, 0xEBCC, 0x8F32, 0xEBCD, 0x8F39, + 0xEBCE, 0x8F37, 0xEBCF, 0x8F34, 0xEBD0, 0x9076, 0xEBD1, 0x9079, 0xEBD2, 0x907B, 0xEBD3, 0x9086, 0xEBD4, 0x90FA, 0xEBD5, 0x9133, + 0xEBD6, 0x9135, 0xEBD7, 0x9136, 0xEBD8, 0x9193, 0xEBD9, 0x9190, 0xEBDA, 0x9191, 0xEBDB, 0x918D, 0xEBDC, 0x918F, 0xEBDD, 0x9327, + 0xEBDE, 0x931E, 0xEBDF, 0x9308, 0xEBE0, 0x931F, 0xEBE1, 0x9306, 0xEBE2, 0x930F, 0xEBE3, 0x937A, 0xEBE4, 0x9338, 0xEBE5, 0x933C, + 0xEBE6, 0x931B, 0xEBE7, 0x9323, 0xEBE8, 0x9312, 0xEBE9, 0x9301, 0xEBEA, 0x9346, 0xEBEB, 0x932D, 0xEBEC, 0x930E, 0xEBED, 0x930D, + 0xEBEE, 0x92CB, 0xEBEF, 0x931D, 0xEBF0, 0x92FA, 0xEBF1, 0x9325, 0xEBF2, 0x9313, 0xEBF3, 0x92F9, 0xEBF4, 0x92F7, 0xEBF5, 0x9334, + 0xEBF6, 0x9302, 0xEBF7, 0x9324, 0xEBF8, 0x92FF, 0xEBF9, 0x9329, 0xEBFA, 0x9339, 0xEBFB, 0x9335, 0xEBFC, 0x932A, 0xEBFD, 0x9314, + 0xEBFE, 0x930C, 0xEC40, 0x930B, 0xEC41, 0x92FE, 0xEC42, 0x9309, 0xEC43, 0x9300, 0xEC44, 0x92FB, 0xEC45, 0x9316, 0xEC46, 0x95BC, + 0xEC47, 0x95CD, 0xEC48, 0x95BE, 0xEC49, 0x95B9, 0xEC4A, 0x95BA, 0xEC4B, 0x95B6, 0xEC4C, 0x95BF, 0xEC4D, 0x95B5, 0xEC4E, 0x95BD, + 0xEC4F, 0x96A9, 0xEC50, 0x96D4, 0xEC51, 0x970B, 0xEC52, 0x9712, 0xEC53, 0x9710, 0xEC54, 0x9799, 0xEC55, 0x9797, 0xEC56, 0x9794, + 0xEC57, 0x97F0, 0xEC58, 0x97F8, 0xEC59, 0x9835, 0xEC5A, 0x982F, 0xEC5B, 0x9832, 0xEC5C, 0x9924, 0xEC5D, 0x991F, 0xEC5E, 0x9927, + 0xEC5F, 0x9929, 0xEC60, 0x999E, 0xEC61, 0x99EE, 0xEC62, 0x99EC, 0xEC63, 0x99E5, 0xEC64, 0x99E4, 0xEC65, 0x99F0, 0xEC66, 0x99E3, + 0xEC67, 0x99EA, 0xEC68, 0x99E9, 0xEC69, 0x99E7, 0xEC6A, 0x9AB9, 0xEC6B, 0x9ABF, 0xEC6C, 0x9AB4, 0xEC6D, 0x9ABB, 0xEC6E, 0x9AF6, + 0xEC6F, 0x9AFA, 0xEC70, 0x9AF9, 0xEC71, 0x9AF7, 0xEC72, 0x9B33, 0xEC73, 0x9B80, 0xEC74, 0x9B85, 0xEC75, 0x9B87, 0xEC76, 0x9B7C, + 0xEC77, 0x9B7E, 0xEC78, 0x9B7B, 0xEC79, 0x9B82, 0xEC7A, 0x9B93, 0xEC7B, 0x9B92, 0xEC7C, 0x9B90, 0xEC7D, 0x9B7A, 0xEC7E, 0x9B95, + 0xECA1, 0x9B7D, 0xECA2, 0x9B88, 0xECA3, 0x9D25, 0xECA4, 0x9D17, 0xECA5, 0x9D20, 0xECA6, 0x9D1E, 0xECA7, 0x9D14, 0xECA8, 0x9D29, + 0xECA9, 0x9D1D, 0xECAA, 0x9D18, 0xECAB, 0x9D22, 0xECAC, 0x9D10, 0xECAD, 0x9D19, 0xECAE, 0x9D1F, 0xECAF, 0x9E88, 0xECB0, 0x9E86, + 0xECB1, 0x9E87, 0xECB2, 0x9EAE, 0xECB3, 0x9EAD, 0xECB4, 0x9ED5, 0xECB5, 0x9ED6, 0xECB6, 0x9EFA, 0xECB7, 0x9F12, 0xECB8, 0x9F3D, + 0xECB9, 0x5126, 0xECBA, 0x5125, 0xECBB, 0x5122, 0xECBC, 0x5124, 0xECBD, 0x5120, 0xECBE, 0x5129, 0xECBF, 0x52F4, 0xECC0, 0x5693, + 0xECC1, 0x568C, 0xECC2, 0x568D, 0xECC3, 0x5686, 0xECC4, 0x5684, 0xECC5, 0x5683, 0xECC6, 0x567E, 0xECC7, 0x5682, 0xECC8, 0x567F, + 0xECC9, 0x5681, 0xECCA, 0x58D6, 0xECCB, 0x58D4, 0xECCC, 0x58CF, 0xECCD, 0x58D2, 0xECCE, 0x5B2D, 0xECCF, 0x5B25, 0xECD0, 0x5B32, + 0xECD1, 0x5B23, 0xECD2, 0x5B2C, 0xECD3, 0x5B27, 0xECD4, 0x5B26, 0xECD5, 0x5B2F, 0xECD6, 0x5B2E, 0xECD7, 0x5B7B, 0xECD8, 0x5BF1, + 0xECD9, 0x5BF2, 0xECDA, 0x5DB7, 0xECDB, 0x5E6C, 0xECDC, 0x5E6A, 0xECDD, 0x5FBE, 0xECDE, 0x5FBB, 0xECDF, 0x61C3, 0xECE0, 0x61B5, + 0xECE1, 0x61BC, 0xECE2, 0x61E7, 0xECE3, 0x61E0, 0xECE4, 0x61E5, 0xECE5, 0x61E4, 0xECE6, 0x61E8, 0xECE7, 0x61DE, 0xECE8, 0x64EF, + 0xECE9, 0x64E9, 0xECEA, 0x64E3, 0xECEB, 0x64EB, 0xECEC, 0x64E4, 0xECED, 0x64E8, 0xECEE, 0x6581, 0xECEF, 0x6580, 0xECF0, 0x65B6, + 0xECF1, 0x65DA, 0xECF2, 0x66D2, 0xECF3, 0x6A8D, 0xECF4, 0x6A96, 0xECF5, 0x6A81, 0xECF6, 0x6AA5, 0xECF7, 0x6A89, 0xECF8, 0x6A9F, + 0xECF9, 0x6A9B, 0xECFA, 0x6AA1, 0xECFB, 0x6A9E, 0xECFC, 0x6A87, 0xECFD, 0x6A93, 0xECFE, 0x6A8E, 0xED40, 0x6A95, 0xED41, 0x6A83, + 0xED42, 0x6AA8, 0xED43, 0x6AA4, 0xED44, 0x6A91, 0xED45, 0x6A7F, 0xED46, 0x6AA6, 0xED47, 0x6A9A, 0xED48, 0x6A85, 0xED49, 0x6A8C, + 0xED4A, 0x6A92, 0xED4B, 0x6B5B, 0xED4C, 0x6BAD, 0xED4D, 0x6C09, 0xED4E, 0x6FCC, 0xED4F, 0x6FA9, 0xED50, 0x6FF4, 0xED51, 0x6FD4, + 0xED52, 0x6FE3, 0xED53, 0x6FDC, 0xED54, 0x6FED, 0xED55, 0x6FE7, 0xED56, 0x6FE6, 0xED57, 0x6FDE, 0xED58, 0x6FF2, 0xED59, 0x6FDD, + 0xED5A, 0x6FE2, 0xED5B, 0x6FE8, 0xED5C, 0x71E1, 0xED5D, 0x71F1, 0xED5E, 0x71E8, 0xED5F, 0x71F2, 0xED60, 0x71E4, 0xED61, 0x71F0, + 0xED62, 0x71E2, 0xED63, 0x7373, 0xED64, 0x736E, 0xED65, 0x736F, 0xED66, 0x7497, 0xED67, 0x74B2, 0xED68, 0x74AB, 0xED69, 0x7490, + 0xED6A, 0x74AA, 0xED6B, 0x74AD, 0xED6C, 0x74B1, 0xED6D, 0x74A5, 0xED6E, 0x74AF, 0xED6F, 0x7510, 0xED70, 0x7511, 0xED71, 0x7512, + 0xED72, 0x750F, 0xED73, 0x7584, 0xED74, 0x7643, 0xED75, 0x7648, 0xED76, 0x7649, 0xED77, 0x7647, 0xED78, 0x76A4, 0xED79, 0x76E9, + 0xED7A, 0x77B5, 0xED7B, 0x77AB, 0xED7C, 0x77B2, 0xED7D, 0x77B7, 0xED7E, 0x77B6, 0xEDA1, 0x77B4, 0xEDA2, 0x77B1, 0xEDA3, 0x77A8, + 0xEDA4, 0x77F0, 0xEDA5, 0x78F3, 0xEDA6, 0x78FD, 0xEDA7, 0x7902, 0xEDA8, 0x78FB, 0xEDA9, 0x78FC, 0xEDAA, 0x78F2, 0xEDAB, 0x7905, + 0xEDAC, 0x78F9, 0xEDAD, 0x78FE, 0xEDAE, 0x7904, 0xEDAF, 0x79AB, 0xEDB0, 0x79A8, 0xEDB1, 0x7A5C, 0xEDB2, 0x7A5B, 0xEDB3, 0x7A56, + 0xEDB4, 0x7A58, 0xEDB5, 0x7A54, 0xEDB6, 0x7A5A, 0xEDB7, 0x7ABE, 0xEDB8, 0x7AC0, 0xEDB9, 0x7AC1, 0xEDBA, 0x7C05, 0xEDBB, 0x7C0F, + 0xEDBC, 0x7BF2, 0xEDBD, 0x7C00, 0xEDBE, 0x7BFF, 0xEDBF, 0x7BFB, 0xEDC0, 0x7C0E, 0xEDC1, 0x7BF4, 0xEDC2, 0x7C0B, 0xEDC3, 0x7BF3, + 0xEDC4, 0x7C02, 0xEDC5, 0x7C09, 0xEDC6, 0x7C03, 0xEDC7, 0x7C01, 0xEDC8, 0x7BF8, 0xEDC9, 0x7BFD, 0xEDCA, 0x7C06, 0xEDCB, 0x7BF0, + 0xEDCC, 0x7BF1, 0xEDCD, 0x7C10, 0xEDCE, 0x7C0A, 0xEDCF, 0x7CE8, 0xEDD0, 0x7E2D, 0xEDD1, 0x7E3C, 0xEDD2, 0x7E42, 0xEDD3, 0x7E33, + 0xEDD4, 0x9848, 0xEDD5, 0x7E38, 0xEDD6, 0x7E2A, 0xEDD7, 0x7E49, 0xEDD8, 0x7E40, 0xEDD9, 0x7E47, 0xEDDA, 0x7E29, 0xEDDB, 0x7E4C, + 0xEDDC, 0x7E30, 0xEDDD, 0x7E3B, 0xEDDE, 0x7E36, 0xEDDF, 0x7E44, 0xEDE0, 0x7E3A, 0xEDE1, 0x7F45, 0xEDE2, 0x7F7F, 0xEDE3, 0x7F7E, + 0xEDE4, 0x7F7D, 0xEDE5, 0x7FF4, 0xEDE6, 0x7FF2, 0xEDE7, 0x802C, 0xEDE8, 0x81BB, 0xEDE9, 0x81C4, 0xEDEA, 0x81CC, 0xEDEB, 0x81CA, + 0xEDEC, 0x81C5, 0xEDED, 0x81C7, 0xEDEE, 0x81BC, 0xEDEF, 0x81E9, 0xEDF0, 0x825B, 0xEDF1, 0x825A, 0xEDF2, 0x825C, 0xEDF3, 0x8583, + 0xEDF4, 0x8580, 0xEDF5, 0x858F, 0xEDF6, 0x85A7, 0xEDF7, 0x8595, 0xEDF8, 0x85A0, 0xEDF9, 0x858B, 0xEDFA, 0x85A3, 0xEDFB, 0x857B, + 0xEDFC, 0x85A4, 0xEDFD, 0x859A, 0xEDFE, 0x859E, 0xEE40, 0x8577, 0xEE41, 0x857C, 0xEE42, 0x8589, 0xEE43, 0x85A1, 0xEE44, 0x857A, + 0xEE45, 0x8578, 0xEE46, 0x8557, 0xEE47, 0x858E, 0xEE48, 0x8596, 0xEE49, 0x8586, 0xEE4A, 0x858D, 0xEE4B, 0x8599, 0xEE4C, 0x859D, + 0xEE4D, 0x8581, 0xEE4E, 0x85A2, 0xEE4F, 0x8582, 0xEE50, 0x8588, 0xEE51, 0x8585, 0xEE52, 0x8579, 0xEE53, 0x8576, 0xEE54, 0x8598, + 0xEE55, 0x8590, 0xEE56, 0x859F, 0xEE57, 0x8668, 0xEE58, 0x87BE, 0xEE59, 0x87AA, 0xEE5A, 0x87AD, 0xEE5B, 0x87C5, 0xEE5C, 0x87B0, + 0xEE5D, 0x87AC, 0xEE5E, 0x87B9, 0xEE5F, 0x87B5, 0xEE60, 0x87BC, 0xEE61, 0x87AE, 0xEE62, 0x87C9, 0xEE63, 0x87C3, 0xEE64, 0x87C2, + 0xEE65, 0x87CC, 0xEE66, 0x87B7, 0xEE67, 0x87AF, 0xEE68, 0x87C4, 0xEE69, 0x87CA, 0xEE6A, 0x87B4, 0xEE6B, 0x87B6, 0xEE6C, 0x87BF, + 0xEE6D, 0x87B8, 0xEE6E, 0x87BD, 0xEE6F, 0x87DE, 0xEE70, 0x87B2, 0xEE71, 0x8935, 0xEE72, 0x8933, 0xEE73, 0x893C, 0xEE74, 0x893E, + 0xEE75, 0x8941, 0xEE76, 0x8952, 0xEE77, 0x8937, 0xEE78, 0x8942, 0xEE79, 0x89AD, 0xEE7A, 0x89AF, 0xEE7B, 0x89AE, 0xEE7C, 0x89F2, + 0xEE7D, 0x89F3, 0xEE7E, 0x8B1E, 0xEEA1, 0x8B18, 0xEEA2, 0x8B16, 0xEEA3, 0x8B11, 0xEEA4, 0x8B05, 0xEEA5, 0x8B0B, 0xEEA6, 0x8B22, + 0xEEA7, 0x8B0F, 0xEEA8, 0x8B12, 0xEEA9, 0x8B15, 0xEEAA, 0x8B07, 0xEEAB, 0x8B0D, 0xEEAC, 0x8B08, 0xEEAD, 0x8B06, 0xEEAE, 0x8B1C, + 0xEEAF, 0x8B13, 0xEEB0, 0x8B1A, 0xEEB1, 0x8C4F, 0xEEB2, 0x8C70, 0xEEB3, 0x8C72, 0xEEB4, 0x8C71, 0xEEB5, 0x8C6F, 0xEEB6, 0x8C95, + 0xEEB7, 0x8C94, 0xEEB8, 0x8CF9, 0xEEB9, 0x8D6F, 0xEEBA, 0x8E4E, 0xEEBB, 0x8E4D, 0xEEBC, 0x8E53, 0xEEBD, 0x8E50, 0xEEBE, 0x8E4C, + 0xEEBF, 0x8E47, 0xEEC0, 0x8F43, 0xEEC1, 0x8F40, 0xEEC2, 0x9085, 0xEEC3, 0x907E, 0xEEC4, 0x9138, 0xEEC5, 0x919A, 0xEEC6, 0x91A2, + 0xEEC7, 0x919B, 0xEEC8, 0x9199, 0xEEC9, 0x919F, 0xEECA, 0x91A1, 0xEECB, 0x919D, 0xEECC, 0x91A0, 0xEECD, 0x93A1, 0xEECE, 0x9383, + 0xEECF, 0x93AF, 0xEED0, 0x9364, 0xEED1, 0x9356, 0xEED2, 0x9347, 0xEED3, 0x937C, 0xEED4, 0x9358, 0xEED5, 0x935C, 0xEED6, 0x9376, + 0xEED7, 0x9349, 0xEED8, 0x9350, 0xEED9, 0x9351, 0xEEDA, 0x9360, 0xEEDB, 0x936D, 0xEEDC, 0x938F, 0xEEDD, 0x934C, 0xEEDE, 0x936A, + 0xEEDF, 0x9379, 0xEEE0, 0x9357, 0xEEE1, 0x9355, 0xEEE2, 0x9352, 0xEEE3, 0x934F, 0xEEE4, 0x9371, 0xEEE5, 0x9377, 0xEEE6, 0x937B, + 0xEEE7, 0x9361, 0xEEE8, 0x935E, 0xEEE9, 0x9363, 0xEEEA, 0x9367, 0xEEEB, 0x9380, 0xEEEC, 0x934E, 0xEEED, 0x9359, 0xEEEE, 0x95C7, + 0xEEEF, 0x95C0, 0xEEF0, 0x95C9, 0xEEF1, 0x95C3, 0xEEF2, 0x95C5, 0xEEF3, 0x95B7, 0xEEF4, 0x96AE, 0xEEF5, 0x96B0, 0xEEF6, 0x96AC, + 0xEEF7, 0x9720, 0xEEF8, 0x971F, 0xEEF9, 0x9718, 0xEEFA, 0x971D, 0xEEFB, 0x9719, 0xEEFC, 0x979A, 0xEEFD, 0x97A1, 0xEEFE, 0x979C, + 0xEF40, 0x979E, 0xEF41, 0x979D, 0xEF42, 0x97D5, 0xEF43, 0x97D4, 0xEF44, 0x97F1, 0xEF45, 0x9841, 0xEF46, 0x9844, 0xEF47, 0x984A, + 0xEF48, 0x9849, 0xEF49, 0x9845, 0xEF4A, 0x9843, 0xEF4B, 0x9925, 0xEF4C, 0x992B, 0xEF4D, 0x992C, 0xEF4E, 0x992A, 0xEF4F, 0x9933, + 0xEF50, 0x9932, 0xEF51, 0x992F, 0xEF52, 0x992D, 0xEF53, 0x9931, 0xEF54, 0x9930, 0xEF55, 0x9998, 0xEF56, 0x99A3, 0xEF57, 0x99A1, + 0xEF58, 0x9A02, 0xEF59, 0x99FA, 0xEF5A, 0x99F4, 0xEF5B, 0x99F7, 0xEF5C, 0x99F9, 0xEF5D, 0x99F8, 0xEF5E, 0x99F6, 0xEF5F, 0x99FB, + 0xEF60, 0x99FD, 0xEF61, 0x99FE, 0xEF62, 0x99FC, 0xEF63, 0x9A03, 0xEF64, 0x9ABE, 0xEF65, 0x9AFE, 0xEF66, 0x9AFD, 0xEF67, 0x9B01, + 0xEF68, 0x9AFC, 0xEF69, 0x9B48, 0xEF6A, 0x9B9A, 0xEF6B, 0x9BA8, 0xEF6C, 0x9B9E, 0xEF6D, 0x9B9B, 0xEF6E, 0x9BA6, 0xEF6F, 0x9BA1, + 0xEF70, 0x9BA5, 0xEF71, 0x9BA4, 0xEF72, 0x9B86, 0xEF73, 0x9BA2, 0xEF74, 0x9BA0, 0xEF75, 0x9BAF, 0xEF76, 0x9D33, 0xEF77, 0x9D41, + 0xEF78, 0x9D67, 0xEF79, 0x9D36, 0xEF7A, 0x9D2E, 0xEF7B, 0x9D2F, 0xEF7C, 0x9D31, 0xEF7D, 0x9D38, 0xEF7E, 0x9D30, 0xEFA1, 0x9D45, + 0xEFA2, 0x9D42, 0xEFA3, 0x9D43, 0xEFA4, 0x9D3E, 0xEFA5, 0x9D37, 0xEFA6, 0x9D40, 0xEFA7, 0x9D3D, 0xEFA8, 0x7FF5, 0xEFA9, 0x9D2D, + 0xEFAA, 0x9E8A, 0xEFAB, 0x9E89, 0xEFAC, 0x9E8D, 0xEFAD, 0x9EB0, 0xEFAE, 0x9EC8, 0xEFAF, 0x9EDA, 0xEFB0, 0x9EFB, 0xEFB1, 0x9EFF, + 0xEFB2, 0x9F24, 0xEFB3, 0x9F23, 0xEFB4, 0x9F22, 0xEFB5, 0x9F54, 0xEFB6, 0x9FA0, 0xEFB7, 0x5131, 0xEFB8, 0x512D, 0xEFB9, 0x512E, + 0xEFBA, 0x5698, 0xEFBB, 0x569C, 0xEFBC, 0x5697, 0xEFBD, 0x569A, 0xEFBE, 0x569D, 0xEFBF, 0x5699, 0xEFC0, 0x5970, 0xEFC1, 0x5B3C, + 0xEFC2, 0x5C69, 0xEFC3, 0x5C6A, 0xEFC4, 0x5DC0, 0xEFC5, 0x5E6D, 0xEFC6, 0x5E6E, 0xEFC7, 0x61D8, 0xEFC8, 0x61DF, 0xEFC9, 0x61ED, + 0xEFCA, 0x61EE, 0xEFCB, 0x61F1, 0xEFCC, 0x61EA, 0xEFCD, 0x61F0, 0xEFCE, 0x61EB, 0xEFCF, 0x61D6, 0xEFD0, 0x61E9, 0xEFD1, 0x64FF, + 0xEFD2, 0x6504, 0xEFD3, 0x64FD, 0xEFD4, 0x64F8, 0xEFD5, 0x6501, 0xEFD6, 0x6503, 0xEFD7, 0x64FC, 0xEFD8, 0x6594, 0xEFD9, 0x65DB, + 0xEFDA, 0x66DA, 0xEFDB, 0x66DB, 0xEFDC, 0x66D8, 0xEFDD, 0x6AC5, 0xEFDE, 0x6AB9, 0xEFDF, 0x6ABD, 0xEFE0, 0x6AE1, 0xEFE1, 0x6AC6, + 0xEFE2, 0x6ABA, 0xEFE3, 0x6AB6, 0xEFE4, 0x6AB7, 0xEFE5, 0x6AC7, 0xEFE6, 0x6AB4, 0xEFE7, 0x6AAD, 0xEFE8, 0x6B5E, 0xEFE9, 0x6BC9, + 0xEFEA, 0x6C0B, 0xEFEB, 0x7007, 0xEFEC, 0x700C, 0xEFED, 0x700D, 0xEFEE, 0x7001, 0xEFEF, 0x7005, 0xEFF0, 0x7014, 0xEFF1, 0x700E, + 0xEFF2, 0x6FFF, 0xEFF3, 0x7000, 0xEFF4, 0x6FFB, 0xEFF5, 0x7026, 0xEFF6, 0x6FFC, 0xEFF7, 0x6FF7, 0xEFF8, 0x700A, 0xEFF9, 0x7201, + 0xEFFA, 0x71FF, 0xEFFB, 0x71F9, 0xEFFC, 0x7203, 0xEFFD, 0x71FD, 0xEFFE, 0x7376, 0xF040, 0x74B8, 0xF041, 0x74C0, 0xF042, 0x74B5, + 0xF043, 0x74C1, 0xF044, 0x74BE, 0xF045, 0x74B6, 0xF046, 0x74BB, 0xF047, 0x74C2, 0xF048, 0x7514, 0xF049, 0x7513, 0xF04A, 0x765C, + 0xF04B, 0x7664, 0xF04C, 0x7659, 0xF04D, 0x7650, 0xF04E, 0x7653, 0xF04F, 0x7657, 0xF050, 0x765A, 0xF051, 0x76A6, 0xF052, 0x76BD, + 0xF053, 0x76EC, 0xF054, 0x77C2, 0xF055, 0x77BA, 0xF056, 0x78FF, 0xF057, 0x790C, 0xF058, 0x7913, 0xF059, 0x7914, 0xF05A, 0x7909, + 0xF05B, 0x7910, 0xF05C, 0x7912, 0xF05D, 0x7911, 0xF05E, 0x79AD, 0xF05F, 0x79AC, 0xF060, 0x7A5F, 0xF061, 0x7C1C, 0xF062, 0x7C29, + 0xF063, 0x7C19, 0xF064, 0x7C20, 0xF065, 0x7C1F, 0xF066, 0x7C2D, 0xF067, 0x7C1D, 0xF068, 0x7C26, 0xF069, 0x7C28, 0xF06A, 0x7C22, + 0xF06B, 0x7C25, 0xF06C, 0x7C30, 0xF06D, 0x7E5C, 0xF06E, 0x7E50, 0xF06F, 0x7E56, 0xF070, 0x7E63, 0xF071, 0x7E58, 0xF072, 0x7E62, + 0xF073, 0x7E5F, 0xF074, 0x7E51, 0xF075, 0x7E60, 0xF076, 0x7E57, 0xF077, 0x7E53, 0xF078, 0x7FB5, 0xF079, 0x7FB3, 0xF07A, 0x7FF7, + 0xF07B, 0x7FF8, 0xF07C, 0x8075, 0xF07D, 0x81D1, 0xF07E, 0x81D2, 0xF0A1, 0x81D0, 0xF0A2, 0x825F, 0xF0A3, 0x825E, 0xF0A4, 0x85B4, + 0xF0A5, 0x85C6, 0xF0A6, 0x85C0, 0xF0A7, 0x85C3, 0xF0A8, 0x85C2, 0xF0A9, 0x85B3, 0xF0AA, 0x85B5, 0xF0AB, 0x85BD, 0xF0AC, 0x85C7, + 0xF0AD, 0x85C4, 0xF0AE, 0x85BF, 0xF0AF, 0x85CB, 0xF0B0, 0x85CE, 0xF0B1, 0x85C8, 0xF0B2, 0x85C5, 0xF0B3, 0x85B1, 0xF0B4, 0x85B6, + 0xF0B5, 0x85D2, 0xF0B6, 0x8624, 0xF0B7, 0x85B8, 0xF0B8, 0x85B7, 0xF0B9, 0x85BE, 0xF0BA, 0x8669, 0xF0BB, 0x87E7, 0xF0BC, 0x87E6, + 0xF0BD, 0x87E2, 0xF0BE, 0x87DB, 0xF0BF, 0x87EB, 0xF0C0, 0x87EA, 0xF0C1, 0x87E5, 0xF0C2, 0x87DF, 0xF0C3, 0x87F3, 0xF0C4, 0x87E4, + 0xF0C5, 0x87D4, 0xF0C6, 0x87DC, 0xF0C7, 0x87D3, 0xF0C8, 0x87ED, 0xF0C9, 0x87D8, 0xF0CA, 0x87E3, 0xF0CB, 0x87A4, 0xF0CC, 0x87D7, + 0xF0CD, 0x87D9, 0xF0CE, 0x8801, 0xF0CF, 0x87F4, 0xF0D0, 0x87E8, 0xF0D1, 0x87DD, 0xF0D2, 0x8953, 0xF0D3, 0x894B, 0xF0D4, 0x894F, + 0xF0D5, 0x894C, 0xF0D6, 0x8946, 0xF0D7, 0x8950, 0xF0D8, 0x8951, 0xF0D9, 0x8949, 0xF0DA, 0x8B2A, 0xF0DB, 0x8B27, 0xF0DC, 0x8B23, + 0xF0DD, 0x8B33, 0xF0DE, 0x8B30, 0xF0DF, 0x8B35, 0xF0E0, 0x8B47, 0xF0E1, 0x8B2F, 0xF0E2, 0x8B3C, 0xF0E3, 0x8B3E, 0xF0E4, 0x8B31, + 0xF0E5, 0x8B25, 0xF0E6, 0x8B37, 0xF0E7, 0x8B26, 0xF0E8, 0x8B36, 0xF0E9, 0x8B2E, 0xF0EA, 0x8B24, 0xF0EB, 0x8B3B, 0xF0EC, 0x8B3D, + 0xF0ED, 0x8B3A, 0xF0EE, 0x8C42, 0xF0EF, 0x8C75, 0xF0F0, 0x8C99, 0xF0F1, 0x8C98, 0xF0F2, 0x8C97, 0xF0F3, 0x8CFE, 0xF0F4, 0x8D04, + 0xF0F5, 0x8D02, 0xF0F6, 0x8D00, 0xF0F7, 0x8E5C, 0xF0F8, 0x8E62, 0xF0F9, 0x8E60, 0xF0FA, 0x8E57, 0xF0FB, 0x8E56, 0xF0FC, 0x8E5E, + 0xF0FD, 0x8E65, 0xF0FE, 0x8E67, 0xF140, 0x8E5B, 0xF141, 0x8E5A, 0xF142, 0x8E61, 0xF143, 0x8E5D, 0xF144, 0x8E69, 0xF145, 0x8E54, + 0xF146, 0x8F46, 0xF147, 0x8F47, 0xF148, 0x8F48, 0xF149, 0x8F4B, 0xF14A, 0x9128, 0xF14B, 0x913A, 0xF14C, 0x913B, 0xF14D, 0x913E, + 0xF14E, 0x91A8, 0xF14F, 0x91A5, 0xF150, 0x91A7, 0xF151, 0x91AF, 0xF152, 0x91AA, 0xF153, 0x93B5, 0xF154, 0x938C, 0xF155, 0x9392, + 0xF156, 0x93B7, 0xF157, 0x939B, 0xF158, 0x939D, 0xF159, 0x9389, 0xF15A, 0x93A7, 0xF15B, 0x938E, 0xF15C, 0x93AA, 0xF15D, 0x939E, + 0xF15E, 0x93A6, 0xF15F, 0x9395, 0xF160, 0x9388, 0xF161, 0x9399, 0xF162, 0x939F, 0xF163, 0x938D, 0xF164, 0x93B1, 0xF165, 0x9391, + 0xF166, 0x93B2, 0xF167, 0x93A4, 0xF168, 0x93A8, 0xF169, 0x93B4, 0xF16A, 0x93A3, 0xF16B, 0x93A5, 0xF16C, 0x95D2, 0xF16D, 0x95D3, + 0xF16E, 0x95D1, 0xF16F, 0x96B3, 0xF170, 0x96D7, 0xF171, 0x96DA, 0xF172, 0x5DC2, 0xF173, 0x96DF, 0xF174, 0x96D8, 0xF175, 0x96DD, + 0xF176, 0x9723, 0xF177, 0x9722, 0xF178, 0x9725, 0xF179, 0x97AC, 0xF17A, 0x97AE, 0xF17B, 0x97A8, 0xF17C, 0x97AB, 0xF17D, 0x97A4, + 0xF17E, 0x97AA, 0xF1A1, 0x97A2, 0xF1A2, 0x97A5, 0xF1A3, 0x97D7, 0xF1A4, 0x97D9, 0xF1A5, 0x97D6, 0xF1A6, 0x97D8, 0xF1A7, 0x97FA, + 0xF1A8, 0x9850, 0xF1A9, 0x9851, 0xF1AA, 0x9852, 0xF1AB, 0x98B8, 0xF1AC, 0x9941, 0xF1AD, 0x993C, 0xF1AE, 0x993A, 0xF1AF, 0x9A0F, + 0xF1B0, 0x9A0B, 0xF1B1, 0x9A09, 0xF1B2, 0x9A0D, 0xF1B3, 0x9A04, 0xF1B4, 0x9A11, 0xF1B5, 0x9A0A, 0xF1B6, 0x9A05, 0xF1B7, 0x9A07, + 0xF1B8, 0x9A06, 0xF1B9, 0x9AC0, 0xF1BA, 0x9ADC, 0xF1BB, 0x9B08, 0xF1BC, 0x9B04, 0xF1BD, 0x9B05, 0xF1BE, 0x9B29, 0xF1BF, 0x9B35, + 0xF1C0, 0x9B4A, 0xF1C1, 0x9B4C, 0xF1C2, 0x9B4B, 0xF1C3, 0x9BC7, 0xF1C4, 0x9BC6, 0xF1C5, 0x9BC3, 0xF1C6, 0x9BBF, 0xF1C7, 0x9BC1, + 0xF1C8, 0x9BB5, 0xF1C9, 0x9BB8, 0xF1CA, 0x9BD3, 0xF1CB, 0x9BB6, 0xF1CC, 0x9BC4, 0xF1CD, 0x9BB9, 0xF1CE, 0x9BBD, 0xF1CF, 0x9D5C, + 0xF1D0, 0x9D53, 0xF1D1, 0x9D4F, 0xF1D2, 0x9D4A, 0xF1D3, 0x9D5B, 0xF1D4, 0x9D4B, 0xF1D5, 0x9D59, 0xF1D6, 0x9D56, 0xF1D7, 0x9D4C, + 0xF1D8, 0x9D57, 0xF1D9, 0x9D52, 0xF1DA, 0x9D54, 0xF1DB, 0x9D5F, 0xF1DC, 0x9D58, 0xF1DD, 0x9D5A, 0xF1DE, 0x9E8E, 0xF1DF, 0x9E8C, + 0xF1E0, 0x9EDF, 0xF1E1, 0x9F01, 0xF1E2, 0x9F00, 0xF1E3, 0x9F16, 0xF1E4, 0x9F25, 0xF1E5, 0x9F2B, 0xF1E6, 0x9F2A, 0xF1E7, 0x9F29, + 0xF1E8, 0x9F28, 0xF1E9, 0x9F4C, 0xF1EA, 0x9F55, 0xF1EB, 0x5134, 0xF1EC, 0x5135, 0xF1ED, 0x5296, 0xF1EE, 0x52F7, 0xF1EF, 0x53B4, + 0xF1F0, 0x56AB, 0xF1F1, 0x56AD, 0xF1F2, 0x56A6, 0xF1F3, 0x56A7, 0xF1F4, 0x56AA, 0xF1F5, 0x56AC, 0xF1F6, 0x58DA, 0xF1F7, 0x58DD, + 0xF1F8, 0x58DB, 0xF1F9, 0x5912, 0xF1FA, 0x5B3D, 0xF1FB, 0x5B3E, 0xF1FC, 0x5B3F, 0xF1FD, 0x5DC3, 0xF1FE, 0x5E70, 0xF240, 0x5FBF, + 0xF241, 0x61FB, 0xF242, 0x6507, 0xF243, 0x6510, 0xF244, 0x650D, 0xF245, 0x6509, 0xF246, 0x650C, 0xF247, 0x650E, 0xF248, 0x6584, + 0xF249, 0x65DE, 0xF24A, 0x65DD, 0xF24B, 0x66DE, 0xF24C, 0x6AE7, 0xF24D, 0x6AE0, 0xF24E, 0x6ACC, 0xF24F, 0x6AD1, 0xF250, 0x6AD9, + 0xF251, 0x6ACB, 0xF252, 0x6ADF, 0xF253, 0x6ADC, 0xF254, 0x6AD0, 0xF255, 0x6AEB, 0xF256, 0x6ACF, 0xF257, 0x6ACD, 0xF258, 0x6ADE, + 0xF259, 0x6B60, 0xF25A, 0x6BB0, 0xF25B, 0x6C0C, 0xF25C, 0x7019, 0xF25D, 0x7027, 0xF25E, 0x7020, 0xF25F, 0x7016, 0xF260, 0x702B, + 0xF261, 0x7021, 0xF262, 0x7022, 0xF263, 0x7023, 0xF264, 0x7029, 0xF265, 0x7017, 0xF266, 0x7024, 0xF267, 0x701C, 0xF268, 0x702A, + 0xF269, 0x720C, 0xF26A, 0x720A, 0xF26B, 0x7207, 0xF26C, 0x7202, 0xF26D, 0x7205, 0xF26E, 0x72A5, 0xF26F, 0x72A6, 0xF270, 0x72A4, + 0xF271, 0x72A3, 0xF272, 0x72A1, 0xF273, 0x74CB, 0xF274, 0x74C5, 0xF275, 0x74B7, 0xF276, 0x74C3, 0xF277, 0x7516, 0xF278, 0x7660, + 0xF279, 0x77C9, 0xF27A, 0x77CA, 0xF27B, 0x77C4, 0xF27C, 0x77F1, 0xF27D, 0x791D, 0xF27E, 0x791B, 0xF2A1, 0x7921, 0xF2A2, 0x791C, + 0xF2A3, 0x7917, 0xF2A4, 0x791E, 0xF2A5, 0x79B0, 0xF2A6, 0x7A67, 0xF2A7, 0x7A68, 0xF2A8, 0x7C33, 0xF2A9, 0x7C3C, 0xF2AA, 0x7C39, + 0xF2AB, 0x7C2C, 0xF2AC, 0x7C3B, 0xF2AD, 0x7CEC, 0xF2AE, 0x7CEA, 0xF2AF, 0x7E76, 0xF2B0, 0x7E75, 0xF2B1, 0x7E78, 0xF2B2, 0x7E70, + 0xF2B3, 0x7E77, 0xF2B4, 0x7E6F, 0xF2B5, 0x7E7A, 0xF2B6, 0x7E72, 0xF2B7, 0x7E74, 0xF2B8, 0x7E68, 0xF2B9, 0x7F4B, 0xF2BA, 0x7F4A, + 0xF2BB, 0x7F83, 0xF2BC, 0x7F86, 0xF2BD, 0x7FB7, 0xF2BE, 0x7FFD, 0xF2BF, 0x7FFE, 0xF2C0, 0x8078, 0xF2C1, 0x81D7, 0xF2C2, 0x81D5, + 0xF2C3, 0x8264, 0xF2C4, 0x8261, 0xF2C5, 0x8263, 0xF2C6, 0x85EB, 0xF2C7, 0x85F1, 0xF2C8, 0x85ED, 0xF2C9, 0x85D9, 0xF2CA, 0x85E1, + 0xF2CB, 0x85E8, 0xF2CC, 0x85DA, 0xF2CD, 0x85D7, 0xF2CE, 0x85EC, 0xF2CF, 0x85F2, 0xF2D0, 0x85F8, 0xF2D1, 0x85D8, 0xF2D2, 0x85DF, + 0xF2D3, 0x85E3, 0xF2D4, 0x85DC, 0xF2D5, 0x85D1, 0xF2D6, 0x85F0, 0xF2D7, 0x85E6, 0xF2D8, 0x85EF, 0xF2D9, 0x85DE, 0xF2DA, 0x85E2, + 0xF2DB, 0x8800, 0xF2DC, 0x87FA, 0xF2DD, 0x8803, 0xF2DE, 0x87F6, 0xF2DF, 0x87F7, 0xF2E0, 0x8809, 0xF2E1, 0x880C, 0xF2E2, 0x880B, + 0xF2E3, 0x8806, 0xF2E4, 0x87FC, 0xF2E5, 0x8808, 0xF2E6, 0x87FF, 0xF2E7, 0x880A, 0xF2E8, 0x8802, 0xF2E9, 0x8962, 0xF2EA, 0x895A, + 0xF2EB, 0x895B, 0xF2EC, 0x8957, 0xF2ED, 0x8961, 0xF2EE, 0x895C, 0xF2EF, 0x8958, 0xF2F0, 0x895D, 0xF2F1, 0x8959, 0xF2F2, 0x8988, + 0xF2F3, 0x89B7, 0xF2F4, 0x89B6, 0xF2F5, 0x89F6, 0xF2F6, 0x8B50, 0xF2F7, 0x8B48, 0xF2F8, 0x8B4A, 0xF2F9, 0x8B40, 0xF2FA, 0x8B53, + 0xF2FB, 0x8B56, 0xF2FC, 0x8B54, 0xF2FD, 0x8B4B, 0xF2FE, 0x8B55, 0xF340, 0x8B51, 0xF341, 0x8B42, 0xF342, 0x8B52, 0xF343, 0x8B57, + 0xF344, 0x8C43, 0xF345, 0x8C77, 0xF346, 0x8C76, 0xF347, 0x8C9A, 0xF348, 0x8D06, 0xF349, 0x8D07, 0xF34A, 0x8D09, 0xF34B, 0x8DAC, + 0xF34C, 0x8DAA, 0xF34D, 0x8DAD, 0xF34E, 0x8DAB, 0xF34F, 0x8E6D, 0xF350, 0x8E78, 0xF351, 0x8E73, 0xF352, 0x8E6A, 0xF353, 0x8E6F, + 0xF354, 0x8E7B, 0xF355, 0x8EC2, 0xF356, 0x8F52, 0xF357, 0x8F51, 0xF358, 0x8F4F, 0xF359, 0x8F50, 0xF35A, 0x8F53, 0xF35B, 0x8FB4, + 0xF35C, 0x9140, 0xF35D, 0x913F, 0xF35E, 0x91B0, 0xF35F, 0x91AD, 0xF360, 0x93DE, 0xF361, 0x93C7, 0xF362, 0x93CF, 0xF363, 0x93C2, + 0xF364, 0x93DA, 0xF365, 0x93D0, 0xF366, 0x93F9, 0xF367, 0x93EC, 0xF368, 0x93CC, 0xF369, 0x93D9, 0xF36A, 0x93A9, 0xF36B, 0x93E6, + 0xF36C, 0x93CA, 0xF36D, 0x93D4, 0xF36E, 0x93EE, 0xF36F, 0x93E3, 0xF370, 0x93D5, 0xF371, 0x93C4, 0xF372, 0x93CE, 0xF373, 0x93C0, + 0xF374, 0x93D2, 0xF375, 0x93E7, 0xF376, 0x957D, 0xF377, 0x95DA, 0xF378, 0x95DB, 0xF379, 0x96E1, 0xF37A, 0x9729, 0xF37B, 0x972B, + 0xF37C, 0x972C, 0xF37D, 0x9728, 0xF37E, 0x9726, 0xF3A1, 0x97B3, 0xF3A2, 0x97B7, 0xF3A3, 0x97B6, 0xF3A4, 0x97DD, 0xF3A5, 0x97DE, + 0xF3A6, 0x97DF, 0xF3A7, 0x985C, 0xF3A8, 0x9859, 0xF3A9, 0x985D, 0xF3AA, 0x9857, 0xF3AB, 0x98BF, 0xF3AC, 0x98BD, 0xF3AD, 0x98BB, + 0xF3AE, 0x98BE, 0xF3AF, 0x9948, 0xF3B0, 0x9947, 0xF3B1, 0x9943, 0xF3B2, 0x99A6, 0xF3B3, 0x99A7, 0xF3B4, 0x9A1A, 0xF3B5, 0x9A15, + 0xF3B6, 0x9A25, 0xF3B7, 0x9A1D, 0xF3B8, 0x9A24, 0xF3B9, 0x9A1B, 0xF3BA, 0x9A22, 0xF3BB, 0x9A20, 0xF3BC, 0x9A27, 0xF3BD, 0x9A23, + 0xF3BE, 0x9A1E, 0xF3BF, 0x9A1C, 0xF3C0, 0x9A14, 0xF3C1, 0x9AC2, 0xF3C2, 0x9B0B, 0xF3C3, 0x9B0A, 0xF3C4, 0x9B0E, 0xF3C5, 0x9B0C, + 0xF3C6, 0x9B37, 0xF3C7, 0x9BEA, 0xF3C8, 0x9BEB, 0xF3C9, 0x9BE0, 0xF3CA, 0x9BDE, 0xF3CB, 0x9BE4, 0xF3CC, 0x9BE6, 0xF3CD, 0x9BE2, + 0xF3CE, 0x9BF0, 0xF3CF, 0x9BD4, 0xF3D0, 0x9BD7, 0xF3D1, 0x9BEC, 0xF3D2, 0x9BDC, 0xF3D3, 0x9BD9, 0xF3D4, 0x9BE5, 0xF3D5, 0x9BD5, + 0xF3D6, 0x9BE1, 0xF3D7, 0x9BDA, 0xF3D8, 0x9D77, 0xF3D9, 0x9D81, 0xF3DA, 0x9D8A, 0xF3DB, 0x9D84, 0xF3DC, 0x9D88, 0xF3DD, 0x9D71, + 0xF3DE, 0x9D80, 0xF3DF, 0x9D78, 0xF3E0, 0x9D86, 0xF3E1, 0x9D8B, 0xF3E2, 0x9D8C, 0xF3E3, 0x9D7D, 0xF3E4, 0x9D6B, 0xF3E5, 0x9D74, + 0xF3E6, 0x9D75, 0xF3E7, 0x9D70, 0xF3E8, 0x9D69, 0xF3E9, 0x9D85, 0xF3EA, 0x9D73, 0xF3EB, 0x9D7B, 0xF3EC, 0x9D82, 0xF3ED, 0x9D6F, + 0xF3EE, 0x9D79, 0xF3EF, 0x9D7F, 0xF3F0, 0x9D87, 0xF3F1, 0x9D68, 0xF3F2, 0x9E94, 0xF3F3, 0x9E91, 0xF3F4, 0x9EC0, 0xF3F5, 0x9EFC, + 0xF3F6, 0x9F2D, 0xF3F7, 0x9F40, 0xF3F8, 0x9F41, 0xF3F9, 0x9F4D, 0xF3FA, 0x9F56, 0xF3FB, 0x9F57, 0xF3FC, 0x9F58, 0xF3FD, 0x5337, + 0xF3FE, 0x56B2, 0xF440, 0x56B5, 0xF441, 0x56B3, 0xF442, 0x58E3, 0xF443, 0x5B45, 0xF444, 0x5DC6, 0xF445, 0x5DC7, 0xF446, 0x5EEE, + 0xF447, 0x5EEF, 0xF448, 0x5FC0, 0xF449, 0x5FC1, 0xF44A, 0x61F9, 0xF44B, 0x6517, 0xF44C, 0x6516, 0xF44D, 0x6515, 0xF44E, 0x6513, + 0xF44F, 0x65DF, 0xF450, 0x66E8, 0xF451, 0x66E3, 0xF452, 0x66E4, 0xF453, 0x6AF3, 0xF454, 0x6AF0, 0xF455, 0x6AEA, 0xF456, 0x6AE8, + 0xF457, 0x6AF9, 0xF458, 0x6AF1, 0xF459, 0x6AEE, 0xF45A, 0x6AEF, 0xF45B, 0x703C, 0xF45C, 0x7035, 0xF45D, 0x702F, 0xF45E, 0x7037, + 0xF45F, 0x7034, 0xF460, 0x7031, 0xF461, 0x7042, 0xF462, 0x7038, 0xF463, 0x703F, 0xF464, 0x703A, 0xF465, 0x7039, 0xF466, 0x7040, + 0xF467, 0x703B, 0xF468, 0x7033, 0xF469, 0x7041, 0xF46A, 0x7213, 0xF46B, 0x7214, 0xF46C, 0x72A8, 0xF46D, 0x737D, 0xF46E, 0x737C, + 0xF46F, 0x74BA, 0xF470, 0x76AB, 0xF471, 0x76AA, 0xF472, 0x76BE, 0xF473, 0x76ED, 0xF474, 0x77CC, 0xF475, 0x77CE, 0xF476, 0x77CF, + 0xF477, 0x77CD, 0xF478, 0x77F2, 0xF479, 0x7925, 0xF47A, 0x7923, 0xF47B, 0x7927, 0xF47C, 0x7928, 0xF47D, 0x7924, 0xF47E, 0x7929, + 0xF4A1, 0x79B2, 0xF4A2, 0x7A6E, 0xF4A3, 0x7A6C, 0xF4A4, 0x7A6D, 0xF4A5, 0x7AF7, 0xF4A6, 0x7C49, 0xF4A7, 0x7C48, 0xF4A8, 0x7C4A, + 0xF4A9, 0x7C47, 0xF4AA, 0x7C45, 0xF4AB, 0x7CEE, 0xF4AC, 0x7E7B, 0xF4AD, 0x7E7E, 0xF4AE, 0x7E81, 0xF4AF, 0x7E80, 0xF4B0, 0x7FBA, + 0xF4B1, 0x7FFF, 0xF4B2, 0x8079, 0xF4B3, 0x81DB, 0xF4B4, 0x81D9, 0xF4B5, 0x820B, 0xF4B6, 0x8268, 0xF4B7, 0x8269, 0xF4B8, 0x8622, + 0xF4B9, 0x85FF, 0xF4BA, 0x8601, 0xF4BB, 0x85FE, 0xF4BC, 0x861B, 0xF4BD, 0x8600, 0xF4BE, 0x85F6, 0xF4BF, 0x8604, 0xF4C0, 0x8609, + 0xF4C1, 0x8605, 0xF4C2, 0x860C, 0xF4C3, 0x85FD, 0xF4C4, 0x8819, 0xF4C5, 0x8810, 0xF4C6, 0x8811, 0xF4C7, 0x8817, 0xF4C8, 0x8813, + 0xF4C9, 0x8816, 0xF4CA, 0x8963, 0xF4CB, 0x8966, 0xF4CC, 0x89B9, 0xF4CD, 0x89F7, 0xF4CE, 0x8B60, 0xF4CF, 0x8B6A, 0xF4D0, 0x8B5D, + 0xF4D1, 0x8B68, 0xF4D2, 0x8B63, 0xF4D3, 0x8B65, 0xF4D4, 0x8B67, 0xF4D5, 0x8B6D, 0xF4D6, 0x8DAE, 0xF4D7, 0x8E86, 0xF4D8, 0x8E88, + 0xF4D9, 0x8E84, 0xF4DA, 0x8F59, 0xF4DB, 0x8F56, 0xF4DC, 0x8F57, 0xF4DD, 0x8F55, 0xF4DE, 0x8F58, 0xF4DF, 0x8F5A, 0xF4E0, 0x908D, + 0xF4E1, 0x9143, 0xF4E2, 0x9141, 0xF4E3, 0x91B7, 0xF4E4, 0x91B5, 0xF4E5, 0x91B2, 0xF4E6, 0x91B3, 0xF4E7, 0x940B, 0xF4E8, 0x9413, + 0xF4E9, 0x93FB, 0xF4EA, 0x9420, 0xF4EB, 0x940F, 0xF4EC, 0x9414, 0xF4ED, 0x93FE, 0xF4EE, 0x9415, 0xF4EF, 0x9410, 0xF4F0, 0x9428, + 0xF4F1, 0x9419, 0xF4F2, 0x940D, 0xF4F3, 0x93F5, 0xF4F4, 0x9400, 0xF4F5, 0x93F7, 0xF4F6, 0x9407, 0xF4F7, 0x940E, 0xF4F8, 0x9416, + 0xF4F9, 0x9412, 0xF4FA, 0x93FA, 0xF4FB, 0x9409, 0xF4FC, 0x93F8, 0xF4FD, 0x940A, 0xF4FE, 0x93FF, 0xF540, 0x93FC, 0xF541, 0x940C, + 0xF542, 0x93F6, 0xF543, 0x9411, 0xF544, 0x9406, 0xF545, 0x95DE, 0xF546, 0x95E0, 0xF547, 0x95DF, 0xF548, 0x972E, 0xF549, 0x972F, + 0xF54A, 0x97B9, 0xF54B, 0x97BB, 0xF54C, 0x97FD, 0xF54D, 0x97FE, 0xF54E, 0x9860, 0xF54F, 0x9862, 0xF550, 0x9863, 0xF551, 0x985F, + 0xF552, 0x98C1, 0xF553, 0x98C2, 0xF554, 0x9950, 0xF555, 0x994E, 0xF556, 0x9959, 0xF557, 0x994C, 0xF558, 0x994B, 0xF559, 0x9953, + 0xF55A, 0x9A32, 0xF55B, 0x9A34, 0xF55C, 0x9A31, 0xF55D, 0x9A2C, 0xF55E, 0x9A2A, 0xF55F, 0x9A36, 0xF560, 0x9A29, 0xF561, 0x9A2E, + 0xF562, 0x9A38, 0xF563, 0x9A2D, 0xF564, 0x9AC7, 0xF565, 0x9ACA, 0xF566, 0x9AC6, 0xF567, 0x9B10, 0xF568, 0x9B12, 0xF569, 0x9B11, + 0xF56A, 0x9C0B, 0xF56B, 0x9C08, 0xF56C, 0x9BF7, 0xF56D, 0x9C05, 0xF56E, 0x9C12, 0xF56F, 0x9BF8, 0xF570, 0x9C40, 0xF571, 0x9C07, + 0xF572, 0x9C0E, 0xF573, 0x9C06, 0xF574, 0x9C17, 0xF575, 0x9C14, 0xF576, 0x9C09, 0xF577, 0x9D9F, 0xF578, 0x9D99, 0xF579, 0x9DA4, + 0xF57A, 0x9D9D, 0xF57B, 0x9D92, 0xF57C, 0x9D98, 0xF57D, 0x9D90, 0xF57E, 0x9D9B, 0xF5A1, 0x9DA0, 0xF5A2, 0x9D94, 0xF5A3, 0x9D9C, + 0xF5A4, 0x9DAA, 0xF5A5, 0x9D97, 0xF5A6, 0x9DA1, 0xF5A7, 0x9D9A, 0xF5A8, 0x9DA2, 0xF5A9, 0x9DA8, 0xF5AA, 0x9D9E, 0xF5AB, 0x9DA3, + 0xF5AC, 0x9DBF, 0xF5AD, 0x9DA9, 0xF5AE, 0x9D96, 0xF5AF, 0x9DA6, 0xF5B0, 0x9DA7, 0xF5B1, 0x9E99, 0xF5B2, 0x9E9B, 0xF5B3, 0x9E9A, + 0xF5B4, 0x9EE5, 0xF5B5, 0x9EE4, 0xF5B6, 0x9EE7, 0xF5B7, 0x9EE6, 0xF5B8, 0x9F30, 0xF5B9, 0x9F2E, 0xF5BA, 0x9F5B, 0xF5BB, 0x9F60, + 0xF5BC, 0x9F5E, 0xF5BD, 0x9F5D, 0xF5BE, 0x9F59, 0xF5BF, 0x9F91, 0xF5C0, 0x513A, 0xF5C1, 0x5139, 0xF5C2, 0x5298, 0xF5C3, 0x5297, + 0xF5C4, 0x56C3, 0xF5C5, 0x56BD, 0xF5C6, 0x56BE, 0xF5C7, 0x5B48, 0xF5C8, 0x5B47, 0xF5C9, 0x5DCB, 0xF5CA, 0x5DCF, 0xF5CB, 0x5EF1, + 0xF5CC, 0x61FD, 0xF5CD, 0x651B, 0xF5CE, 0x6B02, 0xF5CF, 0x6AFC, 0xF5D0, 0x6B03, 0xF5D1, 0x6AF8, 0xF5D2, 0x6B00, 0xF5D3, 0x7043, + 0xF5D4, 0x7044, 0xF5D5, 0x704A, 0xF5D6, 0x7048, 0xF5D7, 0x7049, 0xF5D8, 0x7045, 0xF5D9, 0x7046, 0xF5DA, 0x721D, 0xF5DB, 0x721A, + 0xF5DC, 0x7219, 0xF5DD, 0x737E, 0xF5DE, 0x7517, 0xF5DF, 0x766A, 0xF5E0, 0x77D0, 0xF5E1, 0x792D, 0xF5E2, 0x7931, 0xF5E3, 0x792F, + 0xF5E4, 0x7C54, 0xF5E5, 0x7C53, 0xF5E6, 0x7CF2, 0xF5E7, 0x7E8A, 0xF5E8, 0x7E87, 0xF5E9, 0x7E88, 0xF5EA, 0x7E8B, 0xF5EB, 0x7E86, + 0xF5EC, 0x7E8D, 0xF5ED, 0x7F4D, 0xF5EE, 0x7FBB, 0xF5EF, 0x8030, 0xF5F0, 0x81DD, 0xF5F1, 0x8618, 0xF5F2, 0x862A, 0xF5F3, 0x8626, + 0xF5F4, 0x861F, 0xF5F5, 0x8623, 0xF5F6, 0x861C, 0xF5F7, 0x8619, 0xF5F8, 0x8627, 0xF5F9, 0x862E, 0xF5FA, 0x8621, 0xF5FB, 0x8620, + 0xF5FC, 0x8629, 0xF5FD, 0x861E, 0xF5FE, 0x8625, 0xF640, 0x8829, 0xF641, 0x881D, 0xF642, 0x881B, 0xF643, 0x8820, 0xF644, 0x8824, + 0xF645, 0x881C, 0xF646, 0x882B, 0xF647, 0x884A, 0xF648, 0x896D, 0xF649, 0x8969, 0xF64A, 0x896E, 0xF64B, 0x896B, 0xF64C, 0x89FA, + 0xF64D, 0x8B79, 0xF64E, 0x8B78, 0xF64F, 0x8B45, 0xF650, 0x8B7A, 0xF651, 0x8B7B, 0xF652, 0x8D10, 0xF653, 0x8D14, 0xF654, 0x8DAF, + 0xF655, 0x8E8E, 0xF656, 0x8E8C, 0xF657, 0x8F5E, 0xF658, 0x8F5B, 0xF659, 0x8F5D, 0xF65A, 0x9146, 0xF65B, 0x9144, 0xF65C, 0x9145, + 0xF65D, 0x91B9, 0xF65E, 0x943F, 0xF65F, 0x943B, 0xF660, 0x9436, 0xF661, 0x9429, 0xF662, 0x943D, 0xF663, 0x943C, 0xF664, 0x9430, + 0xF665, 0x9439, 0xF666, 0x942A, 0xF667, 0x9437, 0xF668, 0x942C, 0xF669, 0x9440, 0xF66A, 0x9431, 0xF66B, 0x95E5, 0xF66C, 0x95E4, + 0xF66D, 0x95E3, 0xF66E, 0x9735, 0xF66F, 0x973A, 0xF670, 0x97BF, 0xF671, 0x97E1, 0xF672, 0x9864, 0xF673, 0x98C9, 0xF674, 0x98C6, + 0xF675, 0x98C0, 0xF676, 0x9958, 0xF677, 0x9956, 0xF678, 0x9A39, 0xF679, 0x9A3D, 0xF67A, 0x9A46, 0xF67B, 0x9A44, 0xF67C, 0x9A42, + 0xF67D, 0x9A41, 0xF67E, 0x9A3A, 0xF6A1, 0x9A3F, 0xF6A2, 0x9ACD, 0xF6A3, 0x9B15, 0xF6A4, 0x9B17, 0xF6A5, 0x9B18, 0xF6A6, 0x9B16, + 0xF6A7, 0x9B3A, 0xF6A8, 0x9B52, 0xF6A9, 0x9C2B, 0xF6AA, 0x9C1D, 0xF6AB, 0x9C1C, 0xF6AC, 0x9C2C, 0xF6AD, 0x9C23, 0xF6AE, 0x9C28, + 0xF6AF, 0x9C29, 0xF6B0, 0x9C24, 0xF6B1, 0x9C21, 0xF6B2, 0x9DB7, 0xF6B3, 0x9DB6, 0xF6B4, 0x9DBC, 0xF6B5, 0x9DC1, 0xF6B6, 0x9DC7, + 0xF6B7, 0x9DCA, 0xF6B8, 0x9DCF, 0xF6B9, 0x9DBE, 0xF6BA, 0x9DC5, 0xF6BB, 0x9DC3, 0xF6BC, 0x9DBB, 0xF6BD, 0x9DB5, 0xF6BE, 0x9DCE, + 0xF6BF, 0x9DB9, 0xF6C0, 0x9DBA, 0xF6C1, 0x9DAC, 0xF6C2, 0x9DC8, 0xF6C3, 0x9DB1, 0xF6C4, 0x9DAD, 0xF6C5, 0x9DCC, 0xF6C6, 0x9DB3, + 0xF6C7, 0x9DCD, 0xF6C8, 0x9DB2, 0xF6C9, 0x9E7A, 0xF6CA, 0x9E9C, 0xF6CB, 0x9EEB, 0xF6CC, 0x9EEE, 0xF6CD, 0x9EED, 0xF6CE, 0x9F1B, + 0xF6CF, 0x9F18, 0xF6D0, 0x9F1A, 0xF6D1, 0x9F31, 0xF6D2, 0x9F4E, 0xF6D3, 0x9F65, 0xF6D4, 0x9F64, 0xF6D5, 0x9F92, 0xF6D6, 0x4EB9, + 0xF6D7, 0x56C6, 0xF6D8, 0x56C5, 0xF6D9, 0x56CB, 0xF6DA, 0x5971, 0xF6DB, 0x5B4B, 0xF6DC, 0x5B4C, 0xF6DD, 0x5DD5, 0xF6DE, 0x5DD1, + 0xF6DF, 0x5EF2, 0xF6E0, 0x6521, 0xF6E1, 0x6520, 0xF6E2, 0x6526, 0xF6E3, 0x6522, 0xF6E4, 0x6B0B, 0xF6E5, 0x6B08, 0xF6E6, 0x6B09, + 0xF6E7, 0x6C0D, 0xF6E8, 0x7055, 0xF6E9, 0x7056, 0xF6EA, 0x7057, 0xF6EB, 0x7052, 0xF6EC, 0x721E, 0xF6ED, 0x721F, 0xF6EE, 0x72A9, + 0xF6EF, 0x737F, 0xF6F0, 0x74D8, 0xF6F1, 0x74D5, 0xF6F2, 0x74D9, 0xF6F3, 0x74D7, 0xF6F4, 0x766D, 0xF6F5, 0x76AD, 0xF6F6, 0x7935, + 0xF6F7, 0x79B4, 0xF6F8, 0x7A70, 0xF6F9, 0x7A71, 0xF6FA, 0x7C57, 0xF6FB, 0x7C5C, 0xF6FC, 0x7C59, 0xF6FD, 0x7C5B, 0xF6FE, 0x7C5A, + 0xF740, 0x7CF4, 0xF741, 0x7CF1, 0xF742, 0x7E91, 0xF743, 0x7F4F, 0xF744, 0x7F87, 0xF745, 0x81DE, 0xF746, 0x826B, 0xF747, 0x8634, + 0xF748, 0x8635, 0xF749, 0x8633, 0xF74A, 0x862C, 0xF74B, 0x8632, 0xF74C, 0x8636, 0xF74D, 0x882C, 0xF74E, 0x8828, 0xF74F, 0x8826, + 0xF750, 0x882A, 0xF751, 0x8825, 0xF752, 0x8971, 0xF753, 0x89BF, 0xF754, 0x89BE, 0xF755, 0x89FB, 0xF756, 0x8B7E, 0xF757, 0x8B84, + 0xF758, 0x8B82, 0xF759, 0x8B86, 0xF75A, 0x8B85, 0xF75B, 0x8B7F, 0xF75C, 0x8D15, 0xF75D, 0x8E95, 0xF75E, 0x8E94, 0xF75F, 0x8E9A, + 0xF760, 0x8E92, 0xF761, 0x8E90, 0xF762, 0x8E96, 0xF763, 0x8E97, 0xF764, 0x8F60, 0xF765, 0x8F62, 0xF766, 0x9147, 0xF767, 0x944C, + 0xF768, 0x9450, 0xF769, 0x944A, 0xF76A, 0x944B, 0xF76B, 0x944F, 0xF76C, 0x9447, 0xF76D, 0x9445, 0xF76E, 0x9448, 0xF76F, 0x9449, + 0xF770, 0x9446, 0xF771, 0x973F, 0xF772, 0x97E3, 0xF773, 0x986A, 0xF774, 0x9869, 0xF775, 0x98CB, 0xF776, 0x9954, 0xF777, 0x995B, + 0xF778, 0x9A4E, 0xF779, 0x9A53, 0xF77A, 0x9A54, 0xF77B, 0x9A4C, 0xF77C, 0x9A4F, 0xF77D, 0x9A48, 0xF77E, 0x9A4A, 0xF7A1, 0x9A49, + 0xF7A2, 0x9A52, 0xF7A3, 0x9A50, 0xF7A4, 0x9AD0, 0xF7A5, 0x9B19, 0xF7A6, 0x9B2B, 0xF7A7, 0x9B3B, 0xF7A8, 0x9B56, 0xF7A9, 0x9B55, + 0xF7AA, 0x9C46, 0xF7AB, 0x9C48, 0xF7AC, 0x9C3F, 0xF7AD, 0x9C44, 0xF7AE, 0x9C39, 0xF7AF, 0x9C33, 0xF7B0, 0x9C41, 0xF7B1, 0x9C3C, + 0xF7B2, 0x9C37, 0xF7B3, 0x9C34, 0xF7B4, 0x9C32, 0xF7B5, 0x9C3D, 0xF7B6, 0x9C36, 0xF7B7, 0x9DDB, 0xF7B8, 0x9DD2, 0xF7B9, 0x9DDE, + 0xF7BA, 0x9DDA, 0xF7BB, 0x9DCB, 0xF7BC, 0x9DD0, 0xF7BD, 0x9DDC, 0xF7BE, 0x9DD1, 0xF7BF, 0x9DDF, 0xF7C0, 0x9DE9, 0xF7C1, 0x9DD9, + 0xF7C2, 0x9DD8, 0xF7C3, 0x9DD6, 0xF7C4, 0x9DF5, 0xF7C5, 0x9DD5, 0xF7C6, 0x9DDD, 0xF7C7, 0x9EB6, 0xF7C8, 0x9EF0, 0xF7C9, 0x9F35, + 0xF7CA, 0x9F33, 0xF7CB, 0x9F32, 0xF7CC, 0x9F42, 0xF7CD, 0x9F6B, 0xF7CE, 0x9F95, 0xF7CF, 0x9FA2, 0xF7D0, 0x513D, 0xF7D1, 0x5299, + 0xF7D2, 0x58E8, 0xF7D3, 0x58E7, 0xF7D4, 0x5972, 0xF7D5, 0x5B4D, 0xF7D6, 0x5DD8, 0xF7D7, 0x882F, 0xF7D8, 0x5F4F, 0xF7D9, 0x6201, + 0xF7DA, 0x6203, 0xF7DB, 0x6204, 0xF7DC, 0x6529, 0xF7DD, 0x6525, 0xF7DE, 0x6596, 0xF7DF, 0x66EB, 0xF7E0, 0x6B11, 0xF7E1, 0x6B12, + 0xF7E2, 0x6B0F, 0xF7E3, 0x6BCA, 0xF7E4, 0x705B, 0xF7E5, 0x705A, 0xF7E6, 0x7222, 0xF7E7, 0x7382, 0xF7E8, 0x7381, 0xF7E9, 0x7383, + 0xF7EA, 0x7670, 0xF7EB, 0x77D4, 0xF7EC, 0x7C67, 0xF7ED, 0x7C66, 0xF7EE, 0x7E95, 0xF7EF, 0x826C, 0xF7F0, 0x863A, 0xF7F1, 0x8640, + 0xF7F2, 0x8639, 0xF7F3, 0x863C, 0xF7F4, 0x8631, 0xF7F5, 0x863B, 0xF7F6, 0x863E, 0xF7F7, 0x8830, 0xF7F8, 0x8832, 0xF7F9, 0x882E, + 0xF7FA, 0x8833, 0xF7FB, 0x8976, 0xF7FC, 0x8974, 0xF7FD, 0x8973, 0xF7FE, 0x89FE, 0xF840, 0x8B8C, 0xF841, 0x8B8E, 0xF842, 0x8B8B, + 0xF843, 0x8B88, 0xF844, 0x8C45, 0xF845, 0x8D19, 0xF846, 0x8E98, 0xF847, 0x8F64, 0xF848, 0x8F63, 0xF849, 0x91BC, 0xF84A, 0x9462, + 0xF84B, 0x9455, 0xF84C, 0x945D, 0xF84D, 0x9457, 0xF84E, 0x945E, 0xF84F, 0x97C4, 0xF850, 0x97C5, 0xF851, 0x9800, 0xF852, 0x9A56, + 0xF853, 0x9A59, 0xF854, 0x9B1E, 0xF855, 0x9B1F, 0xF856, 0x9B20, 0xF857, 0x9C52, 0xF858, 0x9C58, 0xF859, 0x9C50, 0xF85A, 0x9C4A, + 0xF85B, 0x9C4D, 0xF85C, 0x9C4B, 0xF85D, 0x9C55, 0xF85E, 0x9C59, 0xF85F, 0x9C4C, 0xF860, 0x9C4E, 0xF861, 0x9DFB, 0xF862, 0x9DF7, + 0xF863, 0x9DEF, 0xF864, 0x9DE3, 0xF865, 0x9DEB, 0xF866, 0x9DF8, 0xF867, 0x9DE4, 0xF868, 0x9DF6, 0xF869, 0x9DE1, 0xF86A, 0x9DEE, + 0xF86B, 0x9DE6, 0xF86C, 0x9DF2, 0xF86D, 0x9DF0, 0xF86E, 0x9DE2, 0xF86F, 0x9DEC, 0xF870, 0x9DF4, 0xF871, 0x9DF3, 0xF872, 0x9DE8, + 0xF873, 0x9DED, 0xF874, 0x9EC2, 0xF875, 0x9ED0, 0xF876, 0x9EF2, 0xF877, 0x9EF3, 0xF878, 0x9F06, 0xF879, 0x9F1C, 0xF87A, 0x9F38, + 0xF87B, 0x9F37, 0xF87C, 0x9F36, 0xF87D, 0x9F43, 0xF87E, 0x9F4F, 0xF8A1, 0x9F71, 0xF8A2, 0x9F70, 0xF8A3, 0x9F6E, 0xF8A4, 0x9F6F, + 0xF8A5, 0x56D3, 0xF8A6, 0x56CD, 0xF8A7, 0x5B4E, 0xF8A8, 0x5C6D, 0xF8A9, 0x652D, 0xF8AA, 0x66ED, 0xF8AB, 0x66EE, 0xF8AC, 0x6B13, + 0xF8AD, 0x705F, 0xF8AE, 0x7061, 0xF8AF, 0x705D, 0xF8B0, 0x7060, 0xF8B1, 0x7223, 0xF8B2, 0x74DB, 0xF8B3, 0x74E5, 0xF8B4, 0x77D5, + 0xF8B5, 0x7938, 0xF8B6, 0x79B7, 0xF8B7, 0x79B6, 0xF8B8, 0x7C6A, 0xF8B9, 0x7E97, 0xF8BA, 0x7F89, 0xF8BB, 0x826D, 0xF8BC, 0x8643, + 0xF8BD, 0x8838, 0xF8BE, 0x8837, 0xF8BF, 0x8835, 0xF8C0, 0x884B, 0xF8C1, 0x8B94, 0xF8C2, 0x8B95, 0xF8C3, 0x8E9E, 0xF8C4, 0x8E9F, + 0xF8C5, 0x8EA0, 0xF8C6, 0x8E9D, 0xF8C7, 0x91BE, 0xF8C8, 0x91BD, 0xF8C9, 0x91C2, 0xF8CA, 0x946B, 0xF8CB, 0x9468, 0xF8CC, 0x9469, + 0xF8CD, 0x96E5, 0xF8CE, 0x9746, 0xF8CF, 0x9743, 0xF8D0, 0x9747, 0xF8D1, 0x97C7, 0xF8D2, 0x97E5, 0xF8D3, 0x9A5E, 0xF8D4, 0x9AD5, + 0xF8D5, 0x9B59, 0xF8D6, 0x9C63, 0xF8D7, 0x9C67, 0xF8D8, 0x9C66, 0xF8D9, 0x9C62, 0xF8DA, 0x9C5E, 0xF8DB, 0x9C60, 0xF8DC, 0x9E02, + 0xF8DD, 0x9DFE, 0xF8DE, 0x9E07, 0xF8DF, 0x9E03, 0xF8E0, 0x9E06, 0xF8E1, 0x9E05, 0xF8E2, 0x9E00, 0xF8E3, 0x9E01, 0xF8E4, 0x9E09, + 0xF8E5, 0x9DFF, 0xF8E6, 0x9DFD, 0xF8E7, 0x9E04, 0xF8E8, 0x9EA0, 0xF8E9, 0x9F1E, 0xF8EA, 0x9F46, 0xF8EB, 0x9F74, 0xF8EC, 0x9F75, + 0xF8ED, 0x9F76, 0xF8EE, 0x56D4, 0xF8EF, 0x652E, 0xF8F0, 0x65B8, 0xF8F1, 0x6B18, 0xF8F2, 0x6B19, 0xF8F3, 0x6B17, 0xF8F4, 0x6B1A, + 0xF8F5, 0x7062, 0xF8F6, 0x7226, 0xF8F7, 0x72AA, 0xF8F8, 0x77D8, 0xF8F9, 0x77D9, 0xF8FA, 0x7939, 0xF8FB, 0x7C69, 0xF8FC, 0x7C6B, + 0xF8FD, 0x7CF6, 0xF8FE, 0x7E9A, 0xF940, 0x7E98, 0xF941, 0x7E9B, 0xF942, 0x7E99, 0xF943, 0x81E0, 0xF944, 0x81E1, 0xF945, 0x8646, + 0xF946, 0x8647, 0xF947, 0x8648, 0xF948, 0x8979, 0xF949, 0x897A, 0xF94A, 0x897C, 0xF94B, 0x897B, 0xF94C, 0x89FF, 0xF94D, 0x8B98, + 0xF94E, 0x8B99, 0xF94F, 0x8EA5, 0xF950, 0x8EA4, 0xF951, 0x8EA3, 0xF952, 0x946E, 0xF953, 0x946D, 0xF954, 0x946F, 0xF955, 0x9471, + 0xF956, 0x9473, 0xF957, 0x9749, 0xF958, 0x9872, 0xF959, 0x995F, 0xF95A, 0x9C68, 0xF95B, 0x9C6E, 0xF95C, 0x9C6D, 0xF95D, 0x9E0B, + 0xF95E, 0x9E0D, 0xF95F, 0x9E10, 0xF960, 0x9E0F, 0xF961, 0x9E12, 0xF962, 0x9E11, 0xF963, 0x9EA1, 0xF964, 0x9EF5, 0xF965, 0x9F09, + 0xF966, 0x9F47, 0xF967, 0x9F78, 0xF968, 0x9F7B, 0xF969, 0x9F7A, 0xF96A, 0x9F79, 0xF96B, 0x571E, 0xF96C, 0x7066, 0xF96D, 0x7C6F, + 0xF96E, 0x883C, 0xF96F, 0x8DB2, 0xF970, 0x8EA6, 0xF971, 0x91C3, 0xF972, 0x9474, 0xF973, 0x9478, 0xF974, 0x9476, 0xF975, 0x9475, + 0xF976, 0x9A60, 0xF977, 0x9C74, 0xF978, 0x9C73, 0xF979, 0x9C71, 0xF97A, 0x9C75, 0xF97B, 0x9E14, 0xF97C, 0x9E13, 0xF97D, 0x9EF6, + 0xF97E, 0x9F0A, 0xF9A1, 0x9FA4, 0xF9A2, 0x7068, 0xF9A3, 0x7065, 0xF9A4, 0x7CF7, 0xF9A5, 0x866A, 0xF9A6, 0x883E, 0xF9A7, 0x883D, + 0xF9A8, 0x883F, 0xF9A9, 0x8B9E, 0xF9AA, 0x8C9C, 0xF9AB, 0x8EA9, 0xF9AC, 0x8EC9, 0xF9AD, 0x974B, 0xF9AE, 0x9873, 0xF9AF, 0x9874, + 0xF9B0, 0x98CC, 0xF9B1, 0x9961, 0xF9B2, 0x99AB, 0xF9B3, 0x9A64, 0xF9B4, 0x9A66, 0xF9B5, 0x9A67, 0xF9B6, 0x9B24, 0xF9B7, 0x9E15, + 0xF9B8, 0x9E17, 0xF9B9, 0x9F48, 0xF9BA, 0x6207, 0xF9BB, 0x6B1E, 0xF9BC, 0x7227, 0xF9BD, 0x864C, 0xF9BE, 0x8EA8, 0xF9BF, 0x9482, + 0xF9C0, 0x9480, 0xF9C1, 0x9481, 0xF9C2, 0x9A69, 0xF9C3, 0x9A68, 0xF9C4, 0x9B2E, 0xF9C5, 0x9E19, 0xF9C6, 0x7229, 0xF9C7, 0x864B, + 0xF9C8, 0x8B9F, 0xF9C9, 0x9483, 0xF9CA, 0x9C79, 0xF9CB, 0x9EB7, 0xF9CC, 0x7675, 0xF9CD, 0x9A6B, 0xF9CE, 0x9C7A, 0xF9CF, 0x9E1D, + 0xF9D0, 0x7069, 0xF9D1, 0x706A, 0xF9D2, 0x9EA4, 0xF9D3, 0x9F7E, 0xF9D4, 0x9F49, 0xF9D5, 0x9F98, 0xF9D6, 0x7881, 0xF9D7, 0x92B9, + 0xF9D8, 0x88CF, 0xF9D9, 0x58BB, 0xF9DA, 0x6052, 0xF9DB, 0x7CA7, 0xF9DC, 0x5AFA, 0xF9DD, 0x2554, 0xF9DE, 0x2566, 0xF9DF, 0x2557, + 0xF9E0, 0x2560, 0xF9E1, 0x256C, 0xF9E2, 0x2563, 0xF9E3, 0x255A, 0xF9E4, 0x2569, 0xF9E5, 0x255D, 0xF9E6, 0x2552, 0xF9E7, 0x2564, + 0xF9E8, 0x2555, 0xF9E9, 0x255E, 0xF9EA, 0x256A, 0xF9EB, 0x2561, 0xF9EC, 0x2558, 0xF9ED, 0x2567, 0xF9EE, 0x255B, 0xF9EF, 0x2553, + 0xF9F0, 0x2565, 0xF9F1, 0x2556, 0xF9F2, 0x255F, 0xF9F3, 0x256B, 0xF9F4, 0x2562, 0xF9F5, 0x2559, 0xF9F6, 0x2568, 0xF9F7, 0x255C, + 0xF9F8, 0x2551, 0xF9F9, 0x2550, 0xF9FA, 0x256D, 0xF9FB, 0x256E, 0xF9FC, 0x2570, 0xF9FD, 0x256F, 0xF9FE, 0x2593, 0, 0 +}; +#endif + +#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 +static const WCHAR uc437[] = { /* CP437(U.S.) 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 +}; +#endif +#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 +static const WCHAR uc720[] = { /* CP720(Arabic) 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 +}; +#endif +#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 +static const WCHAR uc737[] = { /* CP737(Greek) 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 +}; +#endif +#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 +static const WCHAR uc771[] = { /* CP771(KBL) 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 +}; +#endif +#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 +static const WCHAR uc775[] = { /* CP775(Baltic) 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 +}; +#endif +#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 +static const WCHAR uc850[] = { /* CP850(Latin 1) 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 +}; +#endif +#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 +static const WCHAR uc852[] = { /* CP852(Latin 2) 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 +}; +#endif +#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 +static const WCHAR uc855[] = { /* CP855(Cyrillic) 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 +}; +#endif +#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 +static const WCHAR uc857[] = { /* CP857(Turkish) 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 +}; +#endif +#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 +static const WCHAR uc860[] = { /* CP860(Portuguese) 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 +}; +#endif +#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 +static const WCHAR uc861[] = { /* CP861(Icelandic) 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 +}; +#endif +#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 +static const WCHAR uc862[] = { /* CP862(Hebrew) 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 +}; +#endif +#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 +static const WCHAR uc863[] = { /* CP863(Canadian French) 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 +}; +#endif +#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 +static const WCHAR uc864[] = { /* CP864(Arabic) 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 +}; +#endif +#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 +static const WCHAR uc865[] = { /* CP865(Nordic) 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 +}; +#endif +#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 +static const WCHAR uc866[] = { /* CP866(Russian) 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 +}; +#endif +#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 +static const WCHAR uc869[] = { /* CP869(Greek 2) 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 + + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* SBCS Fixed Code Page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + WCHAR c = 0; + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + for (c = 0; c < 0x80 && uni != p[c]; c++) ; + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + WCHAR c = 0; + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } + + return c; +} + +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* DBCS Fixed Code Page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE >= 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR* p; + WCHAR c = 0, uc; + UINT i = 0, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + uc = (WCHAR)uni; + p = CVTBL(uni2oem, FF_CODE_PAGE); + hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR* p; + WCHAR c = 0; + UINT i = 0, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ + p = CVTBL(oem2uni, FF_CODE_PAGE); + hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 0 + +static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; +static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; + + +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR* p; + WCHAR c = 0, uc; + UINT i, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WCHAR)uni; + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ + p = cp_table[i]; + if (p) { /* Is it valid code page ? */ + for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ + c = (c + 0x80) & 0xFF; + } + } else { /* DBCS */ + switch (cp) { /* Get conversion table */ + case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; + case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; + case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; + case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; + } + if (p) { /* Is it valid code page? */ + li = 0; + for (n = 16; n; n--) { /* Find OEM code */ + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ + WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR* p; + WCHAR c = 0; + UINT i, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + p = cp_table[i]; + if (p) { /* Is it a valid CP ? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } else { /* DBCS */ + switch (cp) { + case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; + case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; + case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; + case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; + } + if (p) { + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* Unicode Up-case Conversion */ +/*------------------------------------------------------------------------*/ + +DWORD ff_wtoupper ( /* Returns up-converted code point */ + DWORD uni /* Unicode code point to be up-converted */ +) +{ + const WORD* p; + WORD uc, bc, nc, cmd; + static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, + 0x00F8,0x0307, + 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, + 0x0132,0x0106, + 0x0139,0x0110, + 0x014A,0x012E, + 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, + 0x01DD,0x0001,0x018E, + 0x01DE,0x0112, + 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, + 0x01F8,0x0128, + 0x0222,0x0112, + 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, + 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, + 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, + 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, + 0x03C4,0x0308, + 0x03CC,0x0003,0x038C,0x038E,0x038F, + 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, + 0x0450,0x0710, + 0x0460,0x0122, + 0x048A,0x0136, + 0x04C1,0x010E, + 0x04CF,0x0001,0x04C0, + 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 /* EOT */ + }; + static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, + 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, + 0x1F10,0x0606, + 0x1F20,0x0608, + 0x1F30,0x0608, + 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, + 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, + 0x1F90,0x0608, + 0x1FA0,0x0608, + 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, + 0x1FD0,0x0602, + 0x1FE0,0x0602, + 0x1FE5,0x0001,0x1FEC, + 0x1FF3,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, + 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, + 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, + 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 /* EOT */ + }; + + + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WORD)uni; + p = uc < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get the block base */ + if (bc == 0 || uc < bc) break; /* Not matched? */ + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (uc < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: uc = p[uc - bc]; break; /* Table conversion */ + case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ + case 2: uc -= 16; break; /* Shift -16 */ + case 3: uc -= 32; break; /* Shift -32 */ + case 4: uc -= 48; break; /* Shift -48 */ + case 5: uc -= 26; break; /* Shift -26 */ + case 6: uc += 8; break; /* Shift +8 */ + case 7: uc -= 80; break; /* Shift -80 */ + case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (cmd == 0) p += nc; /* Skip table if needed */ + } + uni = uc; + } + + return uni; +} + + +#endif /* #if FF_USE_LFN != 0 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.c new file mode 100644 index 0000000..b7be07b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.c @@ -0,0 +1,664 @@ +/*------------------------------------------------------------------------/ +/ Universal String Handler for Console Input and Output +/-------------------------------------------------------------------------/ +/ +/ Copyright (C) 2021, ChaN, all right reserved. +/ +/ xprintf module is an open source software. Redistribution and use of +/ xprintf module in source and binary forms, with or without modification, +/ are permitted provided that the following condition is met: +/ +/ 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 "xprintf.h" +#include "bsp.h" +#define SZB_OUTPUT 32 + + +#if XF_USE_OUTPUT +#include +#include +void (*xfunc_output)(int); /* Pointer to the default output device */ +static char *strptr; /* Pointer to the output memory (used by xsprintf) */ + + +#if XF_USE_FP +/*----------------------------------------------*/ +/* Floating point output */ +/*----------------------------------------------*/ +#include + + +static int ilog10 (double n) /* Calculate log10(n) in integer output */ +{ + int rv = 0; + + while (n >= 10) { /* Decimate digit in right shift */ + if (n >= 100000) { + n /= 100000; rv += 5; + } else { + n /= 10; rv++; + } + } + while (n < 1) { /* Decimate digit in left shift */ + if (n < 0.00001) { + n *= 100000; rv -= 5; + } else { + n *= 10; rv--; + } + } + return rv; +} + + +static double i10x (int n) /* Calculate 10^n */ +{ + double rv = 1; + + while (n > 0) { /* Left shift */ + if (n >= 5) { + rv *= 100000; n -= 5; + } else { + rv *= 10; n--; + } + } + while (n < 0) { /* Right shift */ + if (n <= -5) { + rv /= 100000; n += 5; + } else { + rv /= 10; n++; + } + } + return rv; +} + + +static void ftoa ( + char* buf, /* Buffer to output the generated string */ + double val, /* Real number to output */ + int prec, /* Number of fractinal digits */ + char fmt /* Notation */ +) +{ + int d; + int e = 0, m = 0; + char sign = 0; + double w; + const char *er = 0; + + + if (isnan(val)) { /* Not a number? */ + er = "NaN"; + } else { + if (prec < 0) prec = 6; /* Default precision (6 fractional digits) */ + if (val < 0) { /* Nagative value? */ + val = -val; sign = '-'; + } else { + sign = '+'; + } + if (isinf(val)) { /* Infinite? */ + er = "INF"; + } else { + if (fmt == 'f') { /* Decimal notation? */ + val += i10x(-prec) / 2; /* Round (nearest) */ + m = ilog10(val); + if (m < 0) m = 0; + if (m + prec + 3 >= SZB_OUTPUT) er = "OV"; /* Buffer overflow? */ + } else { /* E notation */ + if (val != 0) { /* Not a true zero? */ + val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */ + e = ilog10(val); + if (e > 99 || prec + 6 >= SZB_OUTPUT) { /* Buffer overflow or E > +99? */ + er = "OV"; + } else { + if (e < -99) e = -99; + val /= i10x(e); /* Normalize */ + } + } + } + } + if (!er) { /* Not error condition */ + if (sign == '-') *buf++ = sign; /* Add a - if negative value */ + do { /* Put decimal number */ + w = i10x(m); /* Snip the highest digit d */ + d = val / w; val -= d * w; + if (m == -1) *buf++ = XF_DPC; /* Insert a decimal separarot if get into fractional part */ + *buf++ = '0' + d; /* Put the digit */ + } while (--m >= -prec); /* Output all digits specified by prec */ + if (fmt != 'f') { /* Put exponent if needed */ + *buf++ = fmt; + if (e < 0) { + e = -e; *buf++ = '-'; + } else { + *buf++ = '+'; + } + *buf++ = '0' + e / 10; + *buf++ = '0' + e % 10; + } + } + } + if (er) { /* Error condition? */ + if (sign) *buf++ = sign; /* Add sign if needed */ + do *buf++ = *er++; while (*er); /* Put error symbol */ + } + *buf = 0; /* Term */ +} +#endif /* XF_USE_FLOAT */ + + +/*----------------------------------------------*/ +/* Put a character */ +/*----------------------------------------------*/ + +void xputc ( + int chr /* Character to be output */ +) +{ + xfputc(xfunc_output, chr); /* Output it to the default output device */ +} + + +void xfputc ( /* Put a character to the specified device */ + void(*func)(int), /* Pointer to the output function (null:strptr) */ + int chr /* Character to be output */ +) +{ + if (XF_CRLF && chr == '\n') xfputc(func, '\r'); /* CR -> CRLF */ + + if (func) { + func(chr); /* Write a character to the output device */ + } else if (strptr) { + *strptr++ = chr; /* Write a character to the memory */ + } +} + + + +/*----------------------------------------------*/ +/* Put a null-terminated string */ +/*----------------------------------------------*/ + +void xputs ( /* Put a string to the default device */ + const char* str /* Pointer to the string */ +) +{ + xfputs(xfunc_output, str); +} + + +void xfputs ( /* Put a string to the specified device */ + void(*func)(int), /* Pointer to the output function */ + const char* str /* Pointer to the string */ +) +{ + while (*str) { /* Put the string */ + xfputc(func, *str++); + } +} + + + +/*----------------------------------------------*/ +/* Formatted string output */ +/*----------------------------------------------*/ +/* xprintf("%d", 1234); "1234" + xprintf("%6d,%3d%%", -200, 5); " -200, 5%" + xprintf("%-6u", 100); "100 " + xprintf("%ld", 12345678); "12345678" + xprintf("%llu", 0x100000000); "4294967296" + xprintf("%lld", -1LL); "-1" + xprintf("%04x", 0xA3); "00a3" + xprintf("%08lX", 0x123ABC); "00123ABC" + xprintf("%016b", 0x550F); "0101010100001111" + xprintf("%*d", 6, 100); " 100" + xprintf("%s", "String"); "String" + xprintf("%5s", "abc"); " abc" + xprintf("%-5s", "abc"); "abc " + xprintf("%-5s", "abcdefg"); "abcdefg" + xprintf("%-5.5s", "abcdefg"); "abcde" + xprintf("%-.5s", "abcdefg"); "abcde" + xprintf("%-5.5s", "abc"); "abc " + xprintf("%c", 'a'); "a" + xprintf("%12f", 10.0); " 10.000000" + xprintf("%.4E", 123.45678); "1.2346E+02" +*/ + +static void xvfprintf ( + void(*func)(int), /* Pointer to the output function */ + const char* fmt, /* Pointer to the format string */ + va_list arp /* Pointer to arguments */ +) +{ + unsigned int r, i, j, w, f; + int n, prec; + char str[SZB_OUTPUT], c, d, *p, pad; +#if XF_USE_LLI + long long v; + unsigned long long uv; +#else + long v; + unsigned long uv; +#endif + + for (;;) { + c = *fmt++; /* Get a format character */ + if (!c) break; /* End of format? */ + if (c != '%') { /* Pass it through if not a % sequense */ + xfputc(func, c); continue; + } + f = w = 0; /* Clear parms */ + pad = ' '; prec = -1; + c = *fmt++; /* Get first char of the sequense */ + if (c == '0') { /* Flag: left '0' padded */ + pad = '0'; c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *fmt++; + } + } + if (c == '*') { /* Minimum width from an argument */ + n = va_arg(arp, int); + if (n < 0) { /* Flag: left justified */ + n = 0 - n; f = 2; + } + w = n; c = *fmt++; + } else { + while (c >= '0' && c <= '9') { /* Minimum width */ + w = w * 10 + c - '0'; + c = *fmt++; + } + } + if (c == '.') { /* Precision */ + c = *fmt++; + if (c == '*') { /* Precision from an argument */ + prec = va_arg(arp, int); + c = *fmt++; + } else { + prec = 0; + while (c >= '0' && c <= '9') { + prec = prec * 10 + c - '0'; + c = *fmt++; + } + } + } + if (c == 'l') { /* Prefix: Size is long */ + f |= 4; c = *fmt++; +#if XF_USE_LLI + if (c == 'l') { /* Prefix: Size is long long */ + f |= 8; c = *fmt++; + } +#endif + } + if (!c) break; /* End of format? */ + switch (c) { /* Type is... */ + case 'b': /* Unsigned binary */ + r = 2; break; + case 'o': /* Unsigned octal */ + r = 8; break; + case 'd': /* Signed decimal */ + case 'u': /* Unsigned decimal */ + r = 10; break; + case 'x': /* Hexdecimal (lower case) */ + case 'X': /* Hexdecimal (upper case) */ + r = 16; break; + case 'c': /* A character */ + xfputc(func, (char)va_arg(arp, int)); continue; + case 's': /* String */ + p = va_arg(arp, char*); /* Get a pointer argument */ + if (!p) p = ""; /* Null ptr generates a null string */ + j = strlen(p); + if (prec >= 0 && j > (unsigned int)prec) j = prec; /* Limited length of string body */ + for ( ; !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */ + while (*p && prec--) xfputc(func, *p++);/* String body */ + while (j++ < w) xfputc(func, ' '); /* Right pads */ + continue; +#if XF_USE_FP + case 'f': /* Float (decimal) */ + case 'e': /* Float (e) */ + case 'E': /* Float (E) */ + ftoa(p = str, va_arg(arp, double), prec, c); /* Make fp string */ + for (j = strlen(p); !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */ + while (*p) xfputc(func, *p++); /* Value */ + while (j++ < w) xfputc(func, ' '); /* Right pads */ + continue; +#endif + default: /* Unknown type (passthrough) */ + xfputc(func, c); continue; + } + + /* Get an integer argument and put it in numeral */ +#if XF_USE_LLI + if (f & 8) { /* long long argument? */ + v = (long long)va_arg(arp, long long); + } else { + if (f & 4) { /* long argument? */ + v = (c == 'd') ? (long long)va_arg(arp, long) : (long long)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (c == 'd') ? (long long)va_arg(arp, int) : (long long)va_arg(arp, unsigned int); + } + } +#else + if (f & 4) { /* long argument? */ + v = (long)va_arg(arp, long); + } else { /* int/short/char argument */ + v = (c == 'd') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int); + } +#endif + if (c == 'd' && v < 0) { /* Negative value? */ + v = 0 - v; f |= 1; + } + i = 0; uv = v; + do { /* Make an integer number string */ + d = (char)(uv % r); uv /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + str[i++] = d + '0'; + } while (uv != 0 && i < sizeof str); + if (f & 1) str[i++] = '-'; /* Sign */ + for (j = i; !(f & 2) && j < w; j++) xfputc(func, pad); /* Left pads */ + do xfputc(func, str[--i]); while (i != 0); /* Value */ + while (j++ < w) xfputc(func, ' '); /* Right pads */ + } +} + + +void xprintf ( /* Put a formatted string to the default device */ + const char* fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + + + va_start(arp, fmt); + xvfprintf(xfunc_output, fmt, arp); + va_end(arp); +} + + +void xfprintf ( /* Put a formatted string to the specified device */ + void(*func)(int), /* Pointer to the output function */ + const char* fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + + + va_start(arp, fmt); + xvfprintf(func, fmt, arp); + va_end(arp); +} + + +void xsprintf ( /* Put a formatted string to the memory */ + char* buff, /* Pointer to the output buffer */ + const char* fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + + + strptr = buff; /* Enable destination for memory */ + va_start(arp, fmt); + xvfprintf(0, fmt, arp); + va_end(arp); + *strptr = 0; /* Terminate output string */ + strptr = 0; /* Disable destination for memory */ +} + + + +#if XF_USE_DUMP +/*----------------------------------------------*/ +/* Dump a line of binary dump */ +/*----------------------------------------------*/ + +void put_dump ( + const void* buff, /* Pointer to the array to be dumped */ + unsigned long addr, /* Heading address value */ + int len, /* Number of items to be dumped */ + int width /* Size of buff[0] (1, 2, 4) */ +) +{ + int i; + const unsigned char *bp; + const unsigned short *sp; + const unsigned long *lp; + + + xprintf("%08lX ", addr); /* address */ + + switch (width) { + case 1: + bp = buff; + for (i = 0; i < len; i++) { /* Hexdecimal dump */ + xprintf(" %02X", bp[i]); + } + xputs(" "); + for (i = 0; i < len; i++) { /* ASCII dump */ + xputc((unsigned char)((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.')); + } + break; + case 2: + sp = buff; + do { /* Hexdecimal dump */ + xprintf(" %04X", *sp++); + } while (--len); + break; + case 4: + lp = buff; + do { /* Hexdecimal dump */ + xprintf(" %08LX", *lp++); + } while (--len); + break; + } + + xputc('\n'); +} +#endif /* XF_USE_DUMP */ + +#endif /* XF_USE_OUTPUT */ + + +static int bsp_read(void){ + int dat = 0; + while(!uart_readOccupancy(BSP_UART_TERMINAL)); // wait while rx fifo is empty + if(uart_readOccupancy(BSP_UART_TERMINAL)){ + dat=uart_read(BSP_UART_TERMINAL); + } + return dat; +} + + +#if XF_USE_INPUT +//int (*xfunc_input)(void); /* Pointer to the default input stream */ +//xfunc_input = bsp_read; +/*----------------------------------------------*/ +/* Get a line from the input */ +/*----------------------------------------------*/ + + +int xgets ( /* 0:End of stream, 1:A line arrived */ + char* buff, /* Pointer to the buffer */ + int len /* Buffer length */ +) +{ + int c, i; + + +// if (!xfunc_input) return 0; /* No input function is specified */ + + i = 0; + for (;;) { + c = bsp_read(); //xfunc_input(); /* Get a char from the incoming stream */ + if (c < 0 || c == '\r') break; /* End of stream or CR? */ + if (c == '\b' && i) { /* BS? */ + i--; + if (XF_INPUT_ECHO) xputc(c); + continue; + } + if (c >= ' ' && i < len - 1) { /* Visible chars? */ + buff[i++] = c; + if (XF_INPUT_ECHO) xputc(c); + } + } + if (XF_INPUT_ECHO) { + xputc('\r'); + xputc('\n'); + } + buff[i] = 0; /* Terminate with a \0 */ + return (int)(c == '\r'); +} + + +/*----------------------------------------------*/ +/* Get a value of integer string */ +/*----------------------------------------------*/ +/* "123 -5 0x3ff 0b1111 0377 w " + ^ 1st call returns 123 and next ptr + ^ 2nd call returns -5 and next ptr + ^ 3rd call returns 1023 and next ptr + ^ 4th call returns 15 and next ptr + ^ 5th call returns 255 and next ptr + ^ 6th call fails and returns 0 +*/ + +int xatoi ( /* 0:Failed, 1:Successful */ + char **str, /* Pointer to pointer to the string */ + long *res /* Pointer to the valiable to store the value */ +) +{ + unsigned long val; + unsigned char c, r, s = 0; + + + *res = 0; + + while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */ + + if (c == '-') { /* negative? */ + s = 1; + c = *(++(*str)); + } + + if (c == '0') { + c = *(++(*str)); + switch (c) { + case 'x': /* hexdecimal */ + r = 16; c = *(++(*str)); + break; + case 'b': /* binary */ + r = 2; c = *(++(*str)); + break; + default: + if (c <= ' ') return 1; /* single zero */ + if (c < '0' || c > '9') return 0; /* invalid char */ + r = 8; /* octal */ + } + } else { + if (c < '0' || c > '9') return 0; /* EOL or invalid char */ + r = 10; /* decimal */ + } + + val = 0; + while (c > ' ') { + if (c >= 'a') c -= 0x20; + c -= '0'; + if (c >= 17) { + c -= 7; + if (c <= 9) return 0; /* invalid char */ + } + if (c >= r) return 0; /* invalid char for current radix */ + val = val * r + c; + c = *(++(*str)); + } + if (s) val = 0 - val; /* apply sign if needed */ + + *res = val; + return 1; +} + + +#if XF_USE_FP +/*----------------------------------------------*/ +/* Get a value of the real number string */ +/*----------------------------------------------*/ +/* Float version of xatoi +*/ + +int xatof ( /* 0:Failed, 1:Successful */ + char **str, /* Pointer to pointer to the string */ + double *res /* Pointer to the valiable to store the value */ +) +{ + double val; + int s, f, e; + unsigned char c; + + + *res = 0; + s = f = 0; + + while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */ + if (c == '-') { /* Negative? */ + c = *(++(*str)); s = 1; + } else if (c == '+') { /* Positive? */ + c = *(++(*str)); + } + if (c == XF_DPC) { /* Leading dp? */ + f = -1; /* Start at fractional part */ + c = *(++(*str)); + } + if (c <= ' ') return 0; /* Wrong termination? */ + val = 0; + while (c > ' ') { /* Get a value of decimal */ + if (c == XF_DPC) { /* Embedded dp? */ + if (f < 0) return 0; /* Wrong dp? */ + f = -1; /* Enter fractional part */ + } else { + if (c < '0' || c > '9') break; /* End of decimal? */ + c -= '0'; + if (f == 0) { /* In integer part */ + val = val * 10 + c; + } else { /* In fractional part */ + val += i10x(f--) * c; + } + } + c = *(++(*str)); + } + if (c > ' ') { /* It may be an exponent */ + if (c != 'e' && c != 'E') return 0; /* Wrong character? */ + c = *(++(*str)); + if (c == '-') { + c = *(++(*str)); s |= 2; /* Negative exponent */ + } else if (c == '+') { + c = *(++(*str)); /* Positive exponent */ + } + if (c <= ' ') return 0; /* Wrong termination? */ + e = 0; + while (c > ' ') { /* Get value of exponent */ + c -= '0'; + if (c > 9) return 0; /* Not a numeral? */ + e = e * 10 + c; + c = *(++(*str)); + } + val *= i10x((s & 2) ? -e : e); /* Apply exponent */ + } + + if (s & 1) val = -val; /* Negate sign if needed */ + + *res = val; + return 1; +} +#endif /* XF_USE_FP */ + +#endif /* XF_USE_INPUT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.h new file mode 100644 index 0000000..7ba6258 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/fatfs/xprintf.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------*/ +/* Universal string handler for user console interface (C)ChaN, 2021 */ +/*------------------------------------------------------------------------*/ + +#ifndef XPRINTF_DEF +#define XPRINTF_DEF + +#ifdef __cplusplus +extern "C" { +#endif + +#define XF_USE_OUTPUT 1 /* 1: Enable output functions */ +#define XF_CRLF 1 /* 1: Convert \n ==> \r\n in the output char */ +#define XF_USE_DUMP 1 /* 1: Enable put_dump function */ +#define XF_USE_LLI 1 /* 1: Enable long long integer in size prefix ll */ +#define XF_USE_FP 0 /* 1: Enable support for floating point in type e and f */ +#define XF_DPC '.' /* Decimal separator for floating point */ +#define XF_USE_INPUT 1 /* 1: Enable input functions */ +#define XF_INPUT_ECHO 1 /* 1: Echo back input chars in xgets function */ + +#if defined(__GNUC__) && __GNUC__ >= 10 +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#if XF_USE_OUTPUT +#define xdev_out(func) xfunc_output = (void(*)(int))(func) +extern void (*xfunc_output)(int); +void xputc (int chr); +void xfputc (void (*func)(int), int chr); +void xputs (const char* str); +void xfputs (void (*func)(int), const char* str); +void xprintf (const char* fmt, ...); +void xsprintf (char* buff, const char* fmt, ...); +void xfprintf (void (*func)(int), const char* fmt, ...); +void put_dump (const void* buff, unsigned long addr, int len, int width); +#endif + +#if XF_USE_INPUT +//#define xdev_in(func) xfunc_input = (int(*)(void))(func) +//extern int (*xfunc_input)(void); +//#define xfunc_input bsp_read +int xgets (char* buff, int len); +int xatoi (char** str, long* res); +int xatof (char** str, double* res); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_lib.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_lib.c new file mode 100644 index 0000000..ffa14d6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_lib.c @@ -0,0 +1,1367 @@ +/** + * @file + * Sequential API External module + * + * @defgroup netconn Netconn API + * @ingroup sequential_api + * Thread-safe, to be called from non-TCPIP threads only. + * TX/RX handling based on @ref netbuf (containing @ref pbuf) + * to avoid copying data around. + * + * @defgroup netconn_common Common functions + * @ingroup netconn + * For use with TCP and UDP + * + * @defgroup netconn_tcp TCP only + * @ingroup netconn + * TCP only functions + * + * @defgroup netconn_udp UDP only + * @ingroup netconn + * UDP only functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +/* This is the part of the API that is linked with + the application */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api.h" +#include "lwip/memp.h" + +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/api_msg.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#include + +#define API_MSG_VAR_REF(name) API_VAR_REF(name) +#define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) +#define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) +#define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) +#define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) + +#if TCP_LISTEN_BACKLOG +/* need to allocate API message for accept so empty message pool does not result in event loss + * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ +#define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg) +#define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg) +#else /* TCP_LISTEN_BACKLOG */ +#define API_MSG_VAR_ALLOC_ACCEPT(msg) +#define API_MSG_VAR_FREE_ACCEPT(msg) +#endif /* TCP_LISTEN_BACKLOG */ + +#if LWIP_NETCONN_FULLDUPLEX +#define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0)) +#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0)) +#define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1) +#define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1) +#else /* LWIP_NETCONN_FULLDUPLEX */ +#define NETCONN_RECVMBOX_WAITABLE(conn) sys_mbox_valid(&(conn)->recvmbox) +#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0)) +#define NETCONN_MBOX_WAITING_INC(conn) +#define NETCONN_MBOX_WAITING_DEC(conn) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); + +/** + * Call the lower part of a netconn_* function + * This function is then running in the thread context + * of tcpip_thread and has exclusive access to lwIP core code. + * + * @param fn function to call + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK if the function was called, another err_t if not + */ +static err_t +netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) +{ + err_t err; + +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->err = ERR_VAL; +#endif /* LWIP_DEBUG */ + +#if LWIP_NETCONN_SEM_PER_THREAD + apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); + if (err == ERR_OK) { + return apimsg->err; + } + return err; +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is also created. + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn * +netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) +{ + struct netconn *conn; + API_MSG_VAR_DECLARE(msg); + API_MSG_VAR_ALLOC_RETURN_NULL(msg); + + conn = netconn_alloc(t, callback); + if (conn != NULL) { + err_t err; + + API_MSG_VAR_REF(msg).msg.n.proto = proto; + API_MSG_VAR_REF(msg).conn = conn; + err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); + if (err != ERR_OK) { + LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); + LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ +#if !LWIP_NETCONN_SEM_PER_THREAD + LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); + sys_sem_free(&conn->op_completed); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ + sys_mbox_free(&conn->recvmbox); + memp_free(MEMP_NETCONN, conn); + API_MSG_VAR_FREE(msg); + return NULL; + } + } + API_MSG_VAR_FREE(msg); + return conn; +} + +/** + * @ingroup netconn_common + * Close a netconn 'connection' and free all its resources but not the netconn itself. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_prepare_delete(struct netconn *conn) +{ + err_t err; + API_MSG_VAR_DECLARE(msg); + + /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ + if (conn == NULL) { + return ERR_OK; + } + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if LWIP_TCP +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + API_MSG_VAR_REF(msg).msg.sd.polls_left = + ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ +#endif /* LWIP_TCP */ + err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + if (err != ERR_OK) { + return err; + } + return ERR_OK; +} + +/** + * @ingroup netconn_common + * Close a netconn 'connection' and free its resources. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_delete(struct netconn *conn) +{ + err_t err; + + /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ + if (conn == NULL) { + return ERR_OK; + } + +#if LWIP_NETCONN_FULLDUPLEX + if (conn->flags & NETCONN_FLAG_MBOXINVALID) { + /* Already called netconn_prepare_delete() before */ + err = ERR_OK; + } else +#endif /* LWIP_NETCONN_FULLDUPLEX */ + { + err = netconn_prepare_delete(conn); + } + if (err == ERR_OK) { + netconn_free(conn); + } + return err; +} + +/** + * Get the local or remote IP address and port of a netconn. + * For RAW netconns, this returns the protocol instead of a port! + * + * @param conn the netconn to query + * @param addr a pointer to which to save the IP address + * @param port a pointer to which to save the port (or protocol for RAW) + * @param local 1 to get the local IP address, 0 to get the remote one + * @return ERR_CONN for invalid connections + * ERR_OK if the information was retrieved + */ +err_t +netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.ad.local = local; +#if LWIP_MPU_COMPATIBLE + err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); + *addr = msg->msg.ad.ipaddr; + *port = msg->msg.ad.port; +#else /* LWIP_MPU_COMPATIBLE */ + msg.msg.ad.ipaddr = addr; + msg.msg.ad.port = port; + err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); +#endif /* LWIP_MPU_COMPATIBLE */ + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_common + * Bind a netconn to a specific local IP address and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param addr the local IP address to bind the netconn to + * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) + * @param port the local port to bind the netconn to (not used for RAW) + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (addr == NULL) { + addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV4 && LWIP_IPV6 + /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, + * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind + */ + if ((netconn_get_ipv6only(conn) == 0) && + ip_addr_cmp(addr, IP6_ADDR_ANY)) { + addr = IP_ANY_TYPE; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_common + * Bind a netconn to a specific interface and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param if_idx the local interface index to bind the netconn to + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind_if(struct netconn *conn, u8_t if_idx) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx; + err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_common + * Connect a netconn to a specific remote IP address and port. + * + * @param conn the netconn to connect + * @param addr the remote IP address to connect to + * @param port the remote port to connect to (no used for RAW) + * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise + */ +err_t +netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (addr == NULL) { + addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_udp + * Disconnect a netconn from its current peer (only valid for UDP netconns). + * + * @param conn the netconn to disconnect + * @return See @ref err_t + */ +err_t +netconn_disconnect(struct netconn *conn) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Set a TCP netconn into listen mode + * + * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 + * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns + * don't return any error (yet?)) + */ +err_t +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) +{ +#if LWIP_TCP + API_MSG_VAR_DECLARE(msg); + err_t err; + + /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ + LWIP_UNUSED_ARG(backlog); + + LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ + err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(backlog); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * @ingroup netconn_tcp + * Accept a new connection on a TCP listening netconn. + * + * @param conn the TCP listen netconn + * @param new_conn pointer where the new connection is stored + * @return ERR_OK if a new connection has been received or an error + * code otherwise + */ +err_t +netconn_accept(struct netconn *conn, struct netconn **new_conn) +{ +#if LWIP_TCP + err_t err; + void *accept_ptr; + struct netconn *newconn; +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_DECLARE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + + LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); + *new_conn = NULL; + LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); + + /* NOTE: Although the opengroup spec says a pending error shall be returned to + send/recv/getsockopt(SO_ERROR) only, we return it for listening + connections also, to handle embedded-system errors */ + err = netconn_err(conn); + if (err != ERR_OK) { + /* return pending error */ + return err; + } + if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) { + /* don't accept if closed: this might block the application task + waiting on acceptmbox forever! */ + return ERR_CLSD; + } + + API_MSG_VAR_ALLOC_ACCEPT(msg); + + NETCONN_MBOX_WAITING_INC(conn); + if (netconn_is_nonblocking(conn)) { + if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_MBOX_EMPTY) { + API_MSG_VAR_FREE_ACCEPT(msg); + NETCONN_MBOX_WAITING_DEC(conn); + return ERR_WOULDBLOCK; + } + } else { +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + API_MSG_VAR_FREE_ACCEPT(msg); + NETCONN_MBOX_WAITING_DEC(conn); + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + } + NETCONN_MBOX_WAITING_DEC(conn); +#if LWIP_NETCONN_FULLDUPLEX + if (conn->flags & NETCONN_FLAG_MBOXINVALID) { + if (lwip_netconn_is_deallocated_msg(accept_ptr)) { + /* the netconn has been closed from another thread */ + API_MSG_VAR_FREE_ACCEPT(msg); + return ERR_CONN; + } + } +#endif + + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + + if (lwip_netconn_is_err_msg(accept_ptr, &err)) { + /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */ + API_MSG_VAR_FREE_ACCEPT(msg); + return err; + } + if (accept_ptr == NULL) { + /* connection has been aborted */ + API_MSG_VAR_FREE_ACCEPT(msg); + return ERR_CLSD; + } + newconn = (struct netconn *)accept_ptr; +#if TCP_LISTEN_BACKLOG + /* Let the stack know that we have accepted the connection. */ + API_MSG_VAR_REF(msg).conn = newconn; + /* don't care for the return value of lwip_netconn_do_recv */ + netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + + *new_conn = newconn; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(new_conn); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * @ingroup netconn_common + * Receive data: actual implementation that doesn't care whether pbuf or netbuf + * is received (this is internal, it's just here for describing common errors) + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf/netbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_CONN if not connected + * ERR_CLSD if TCP connection has been closed + * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data + * ERR_TIMEOUT if the netconn has a receive timeout and no data was received + */ +static err_t +netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) +{ + void *buf = NULL; + u16_t len; + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + + if (!NETCONN_RECVMBOX_WAITABLE(conn)) { + err_t err = netconn_err(conn); + if (err != ERR_OK) { + /* return pending error */ + return err; + } + return ERR_CONN; + } + + NETCONN_MBOX_WAITING_INC(conn); + if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) || + (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) { + if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_MBOX_EMPTY) { + err_t err; + NETCONN_MBOX_WAITING_DEC(conn); + err = netconn_err(conn); + if (err != ERR_OK) { + /* return pending error */ + return err; + } + if (conn->flags & NETCONN_FLAG_MBOXCLOSED) { + return ERR_CONN; + } + return ERR_WOULDBLOCK; + } + } else { +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + NETCONN_MBOX_WAITING_DEC(conn); + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + } + NETCONN_MBOX_WAITING_DEC(conn); +#if LWIP_NETCONN_FULLDUPLEX + if (conn->flags & NETCONN_FLAG_MBOXINVALID) { + if (lwip_netconn_is_deallocated_msg(buf)) { + /* the netconn has been closed from another thread */ + API_MSG_VAR_FREE_ACCEPT(msg); + return ERR_CONN; + } + } +#endif + +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + err_t err; + /* Check if this is an error message or a pbuf */ + if (lwip_netconn_is_err_msg(buf, &err)) { + /* new_buf has been zeroed above already */ + if (err == ERR_CLSD) { + /* connection closed translates to ERR_OK with *new_buf == NULL */ + return ERR_OK; + } + return err; + } + len = ((struct pbuf *)buf)->tot_len; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ +#if (LWIP_UDP || LWIP_RAW) + { + LWIP_ASSERT("buf != NULL", buf != NULL); + len = netbuf_len((struct netbuf *)buf); + } +#endif /* (LWIP_UDP || LWIP_RAW) */ + +#if LWIP_SO_RCVBUF + SYS_ARCH_DEC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); + + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +} + +#if LWIP_TCP +static err_t +netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg) +{ + LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + msg->conn = conn; + msg->msg.r.len = len; + + return netconn_apimsg(lwip_netconn_do_recv, msg); +} + +err_t +netconn_tcp_recvd(struct netconn *conn, size_t len) +{ + err_t err; + API_MSG_VAR_DECLARE(msg); + LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + return err; +} + +static err_t +netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) +{ + err_t err; + struct pbuf *buf; + API_MSG_VAR_DECLARE(msg); +#if LWIP_MPU_COMPATIBLE + msg = NULL; +#endif + + if (!NETCONN_RECVMBOX_WAITABLE(conn)) { + /* This only happens when calling this function more than once *after* receiving FIN */ + return ERR_CONN; + } + if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) { + netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING); + goto handle_fin; + } + + if (!(apiflags & NETCONN_NOAUTORCVD)) { + /* need to allocate API message here so empty message pool does not result in event loss + * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ + API_MSG_VAR_ALLOC(msg); + } + + err = netconn_recv_data(conn, (void **)new_buf, apiflags); + if (err != ERR_OK) { + if (!(apiflags & NETCONN_NOAUTORCVD)) { + API_MSG_VAR_FREE(msg); + } + return err; + } + buf = *new_buf; + if (!(apiflags & NETCONN_NOAUTORCVD)) { + /* Let the stack know that we have taken the data. */ + u16_t len = buf ? buf->tot_len : 1; + /* don't care for the return value of lwip_netconn_do_recv */ + /* @todo: this should really be fixed, e.g. by retrying in poll on error */ + netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + } + + /* If we are closed, we indicate that we no longer wish to use the socket */ + if (buf == NULL) { + if (apiflags & NETCONN_NOFIN) { + /* received a FIN but the caller cannot handle it right now: + re-enqueue it and return "no data" */ + netconn_set_flags(conn, NETCONN_FIN_RX_PENDING); + return ERR_WOULDBLOCK; + } else { +handle_fin: + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + if (conn->pcb.ip == NULL) { + /* race condition: RST during recv */ + err = netconn_err(conn); + if (err != ERR_OK) { + return err; + } + return ERR_RST; + } + /* RX side is closed, so deallocate the recvmbox */ + netconn_close_shutdown(conn, NETCONN_SHUT_RD); + /* Don' store ERR_CLSD as conn->err since we are only half-closed */ + return ERR_CLSD; + } + } + return err; +} + +/** + * @ingroup netconn_tcp + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error, @see netconn_recv_data) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) +{ + LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data_tcp(conn, new_buf, 0); +} + +/** + * @ingroup netconn_tcp + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error, @see netconn_recv_data) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) +{ + LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data_tcp(conn, new_buf, apiflags); +} +#endif /* LWIP_TCP */ + +/** + * Receive data (in form of a netbuf) from a UDP or RAW netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a UDP/RAW netconn + */ +err_t +netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) +{ + LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf, 0); +} + +/** + * Receive data (in form of a netbuf) from a UDP or RAW netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a UDP/RAW netconn + */ +err_t +netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags) +{ + LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf, apiflags); +} + +/** + * @ingroup netconn_common + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +err_t +netconn_recv(struct netconn *conn, struct netbuf **new_buf) +{ +#if LWIP_TCP + struct netbuf *buf = NULL; + err_t err; +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + struct pbuf *p = NULL; + /* This is not a listening netconn, since recvmbox is set */ + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + return ERR_MEM; + } + + err = netconn_recv_data_tcp(conn, &p, 0); + if (err != ERR_OK) { + memp_free(MEMP_NETBUF, buf); + return err; + } + LWIP_ASSERT("p != NULL", p != NULL); + + buf->p = p; + buf->ptr = p; + buf->port = 0; + ip_addr_set_zero(&buf->addr); + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ + { +#if (LWIP_UDP || LWIP_RAW) + return netconn_recv_data(conn, (void **)new_buf, 0); +#endif /* (LWIP_UDP || LWIP_RAW) */ + } +} + +/** + * @ingroup netconn_udp + * Send data (in form of a netbuf) to a specific remote IP address and port. + * Only to be used for UDP and RAW netconns (not TCP). + * + * @param conn the netconn over which to send data + * @param buf a netbuf containing the data to send + * @param addr the remote IP address to which to send the data + * @param port the remote port to which to send the data + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) +{ + if (buf != NULL) { + ip_addr_set(&buf->addr, addr); + buf->port = port; + return netconn_send(conn, buf); + } + return ERR_VAL; +} + +/** + * @ingroup netconn_udp + * Send data over a UDP or RAW netconn (that is already connected). + * + * @param conn the UDP or RAW netconn over which to send data + * @param buf a netbuf containing the data to send + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_send(struct netconn *conn, struct netbuf *buf) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.b = buf; + err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Send data over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param dataptr pointer to the application buffer that contains the data to send + * @param size size of the application data to send + * @param apiflags combination of following flags : + * - NETCONN_COPY: data will be copied into memory belonging to the stack + * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_DONTBLOCK: only write the data if all data can be written at once + * @param bytes_written pointer to a location that receives the number of written bytes + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written) +{ + struct netvector vector; + vector.ptr = dataptr; + vector.len = size; + return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written); +} + +/** + * Send vectorized data atomically over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param vectors array of vectors containing data to send + * @param vectorcnt number of vectors in the array + * @param apiflags combination of following flags : + * - NETCONN_COPY: data will be copied into memory belonging to the stack + * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_DONTBLOCK: only write the data if all data can be written at once + * @param bytes_written pointer to a location that receives the number of written bytes + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, + u8_t apiflags, size_t *bytes_written) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + u8_t dontblock; + size_t size; + int i; + + LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;); + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout != 0) { + dontblock = 1; + } +#endif /* LWIP_SO_SNDTIMEO */ + if (dontblock && !bytes_written) { + /* This implies netconn_write() cannot be used for non-blocking send, since + it has no way to return the number of bytes written. */ + return ERR_VAL; + } + + /* sum up the total size */ + size = 0; + for (i = 0; i < vectorcnt; i++) { + size += vectors[i].len; + if (size < vectors[i].len) { + /* overflow */ + return ERR_VAL; + } + } + if (size == 0) { + return ERR_OK; + } else if (size > SSIZE_MAX) { + ssize_t limited; + /* this is required by the socket layer (cannot send full size_t range) */ + if (!bytes_written) { + return ERR_VAL; + } + /* limit the amount of data to send */ + limited = SSIZE_MAX; + size = (size_t)limited; + } + + API_MSG_VAR_ALLOC(msg); + /* non-blocking write sends as much */ + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.w.vector = vectors; + API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt; + API_MSG_VAR_REF(msg).msg.w.vector_off = 0; + API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; + API_MSG_VAR_REF(msg).msg.w.len = size; + API_MSG_VAR_REF(msg).msg.w.offset = 0; +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout != 0) { + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); + } else { + API_MSG_VAR_REF(msg).msg.w.time_started = 0; + } +#endif /* LWIP_SO_SNDTIMEO */ + + /* For locking the core: this _can_ be delayed on low memory/low send buffer, + but if it is, this is done inside api_msg.c:do_write(), so we can use the + non-blocking version here. */ + err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); + if (err == ERR_OK) { + if (bytes_written != NULL) { + *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset; + } + /* for blocking, check all requested bytes were written, NOTE: send_timeout is + treated as dontblock (see dontblock assignment above) */ + if (!dontblock) { + LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size); + } + } + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Close or shutdown a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close or shutdown + * @param how fully close or only shutdown one side? + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +static err_t +netconn_close_shutdown(struct netconn *conn, u8_t how) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + LWIP_UNUSED_ARG(how); + + LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if LWIP_TCP + /* shutting down both ends is the same as closing */ + API_MSG_VAR_REF(msg).msg.sd.shut = how; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + API_MSG_VAR_REF(msg).msg.sd.polls_left = + ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ +#endif /* LWIP_TCP */ + err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ + /* shutting down both ends is the same as closing */ + return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); +} + +/** + * @ingroup netconn_common + * Get and reset pending error on a netconn + * + * @param conn the netconn to get the error from + * @return and pending error or ERR_OK if no error was pending + */ +err_t +netconn_err(struct netconn *conn) +{ + err_t err; + SYS_ARCH_DECL_PROTECT(lev); + if (conn == NULL) { + return ERR_OK; + } + SYS_ARCH_PROTECT(lev); + err = conn->pending_err; + conn->pending_err = ERR_OK; + SYS_ARCH_UNPROTECT(lev); + return err; +} + +/** + * @ingroup netconn_tcp + * Shut down one or both sides of a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to shut down + * @param shut_rx shut down the RX side (no more read possible after this) + * @param shut_tx shut down the TX side (no more write possible after this) + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) +{ + return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0))); +} + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * @ingroup netconn_udp + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param netif_addr the IP address of the network interface on which to send + * the igmp message + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group(struct netconn *conn, + const ip_addr_t *multiaddr, + const ip_addr_t *netif_addr, + enum netconn_igmp join_or_leave) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (multiaddr == NULL) { + multiaddr = IP4_ADDR_ANY; + } + if (netif_addr == NULL) { + netif_addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); + API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); + API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; + err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} +/** + * @ingroup netconn_udp + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param if_idx the index of the netif + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group_netif(struct netconn *conn, + const ip_addr_t *multiaddr, + u8_t if_idx, + enum netconn_igmp join_or_leave) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (multiaddr == NULL) { + multiaddr = IP4_ADDR_ANY; + } + if (if_idx == NETIF_NO_INDEX) { + return ERR_IF; + } +#endif /* LWIP_IPV4 */ + + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); + API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx; + API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; + err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/** + * @ingroup netconn_common + * Execute a DNS query, only one IP address is returned + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated ip_addr_t where to store the resolved IP address + * @param dns_addrtype IP address type (IPv4 / IPv6) + * @return ERR_OK: resolving succeeded + * ERR_MEM: memory error, try again later + * ERR_ARG: dns client not initialized or invalid hostname + * ERR_VAL: dns server response was invalid + */ +#if LWIP_IPV4 && LWIP_IPV6 +err_t +netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) +#else +err_t +netconn_gethostbyname(const char *name, ip_addr_t *addr) +#endif +{ + API_VAR_DECLARE(struct dns_api_msg, msg); +#if !LWIP_MPU_COMPATIBLE + sys_sem_t sem; +#endif /* LWIP_MPU_COMPATIBLE */ + err_t err; + err_t cberr; + + LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); +#if LWIP_MPU_COMPATIBLE + if (strlen(name) >= DNS_MAX_NAME_LENGTH) { + return ERR_ARG; + } +#endif + +#ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE +#if LWIP_IPV4 && LWIP_IPV6 + if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) { +#else + if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) { +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return err; + } +#endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */ + + API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); +#if LWIP_MPU_COMPATIBLE + strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1); + API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0; +#else /* LWIP_MPU_COMPATIBLE */ + msg.err = &err; + msg.sem = &sem; + API_VAR_REF(msg).addr = API_VAR_REF(addr); + API_VAR_REF(msg).name = name; +#endif /* LWIP_MPU_COMPATIBLE */ +#if LWIP_IPV4 && LWIP_IPV6 + API_VAR_REF(msg).dns_addrtype = dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_NETCONN_SEM_PER_THREAD + API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD*/ + err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); + if (err != ERR_OK) { + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return err; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem)); +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ + if (cberr != ERR_OK) { + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return cberr; + } + +#if LWIP_MPU_COMPATIBLE + *addr = msg->addr; + err = msg->err; +#endif /* LWIP_MPU_COMPATIBLE */ + + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return err; +} +#endif /* LWIP_DNS*/ + +#if LWIP_NETCONN_SEM_PER_THREAD +void +netconn_thread_init(void) +{ + sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); + if (!sys_sem_valid(sem)) { + /* call alloc only once */ + LWIP_NETCONN_THREAD_SEM_ALLOC(); + LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); + } +} + +void +netconn_thread_cleanup(void) +{ + sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); + if (sys_sem_valid(sem)) { + /* call free only once */ + LWIP_NETCONN_THREAD_SEM_FREE(); + } +} +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#endif /* LWIP_NETCONN */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_msg.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_msg.c new file mode 100644 index 0000000..3f08e03 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/api_msg.c @@ -0,0 +1,2176 @@ +/** + * @file + * Sequential API Internal module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/api_msg.h" + +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" + +#include "lwip/memp.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/mld6.h" +#include "lwip/priv/tcpip_priv.h" + +#include + +/* netconns are polled once per second (e.g. continue write on memory error) */ +#define NETCONN_TCP_POLL_INTERVAL 2 + +#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ + netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \ +} else { \ + netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0) +#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT) + +#if LWIP_NETCONN_FULLDUPLEX +#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0)) +#else +#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox) +#endif + +/* forward declarations */ +#if LWIP_TCP +#if LWIP_TCPIP_CORE_LOCKING +#define WRITE_DELAYED , 1 +#define WRITE_DELAYED_PARAM , u8_t delayed +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define WRITE_DELAYED +#define WRITE_DELAYED_PARAM +#endif /* LWIP_TCPIP_CORE_LOCKING */ +static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); +static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); +#endif + +static void netconn_drain(struct netconn *conn); + +#if LWIP_TCPIP_CORE_LOCKING +#define TCPIP_APIMSG_ACK(m) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_NETCONN_FULLDUPLEX +const u8_t netconn_deleted = 0; + +int +lwip_netconn_is_deallocated_msg(void *msg) +{ + if (msg == &netconn_deleted) { + return 1; + } + return 0; +} +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +#if LWIP_TCP +const u8_t netconn_aborted = 0; +const u8_t netconn_reset = 0; +const u8_t netconn_closed = 0; + +/** Translate an error to a unique void* passed via an mbox */ +static void * +lwip_netconn_err_to_msg(err_t err) +{ + switch (err) { + case ERR_ABRT: + return LWIP_CONST_CAST(void *, &netconn_aborted); + case ERR_RST: + return LWIP_CONST_CAST(void *, &netconn_reset); + case ERR_CLSD: + return LWIP_CONST_CAST(void *, &netconn_closed); + default: + LWIP_ASSERT("unhandled error", err == ERR_OK); + return NULL; + } +} + +int +lwip_netconn_is_err_msg(void *msg, err_t *err) +{ + LWIP_ASSERT("err != NULL", err != NULL); + + if (msg == &netconn_aborted) { + *err = ERR_ABRT; + return 1; + } else if (msg == &netconn_reset) { + *err = ERR_RST; + return 1; + } else if (msg == &netconn_closed) { + *err = ERR_CLSD; + return 1; + } + return 0; +} +#endif /* LWIP_TCP */ + + +#if LWIP_RAW +/** + * Receive callback function for RAW netconns. + * Doesn't 'eat' the packet, only copies it and sends it to + * conn->recvmbox + * + * @see raw.h (struct raw_pcb.recv) for parameters and return value + */ +static u8_t +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr) +{ + struct pbuf *q; + struct netbuf *buf; + struct netconn *conn; + + LWIP_UNUSED_ARG(addr); + conn = (struct netconn *)arg; + + if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { +#if LWIP_SO_RCVBUF + int recv_avail; + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { + return 0; + } +#endif /* LWIP_SO_RCVBUF */ + /* copy the whole packet into new pbufs */ + q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); + if (q != NULL) { + u16_t len; + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(q); + return 0; + } + + buf->p = q; + buf->ptr = q; + ip_addr_copy(buf->addr, *ip_current_src_addr()); + buf->port = pcb->protocol; + + len = q->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return 0; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + } + } + + return 0; /* do not eat the packet */ +} +#endif /* LWIP_RAW*/ + +#if LWIP_UDP +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ +static void +recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port) +{ + struct netbuf *buf; + struct netconn *conn; + u16_t len; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ + LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_udp must have an argument", arg != NULL); + conn = (struct netconn *)arg; + + if (conn == NULL) { + pbuf_free(p); + return; + } + + LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); + +#if LWIP_SO_RCVBUF + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) || + ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { +#else /* LWIP_SO_RCVBUF */ + if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { +#endif /* LWIP_SO_RCVBUF */ + pbuf_free(p); + return; + } + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(p); + return; + } else { + buf->p = p; + buf->ptr = p; + ip_addr_set(&buf->addr, addr); + buf->port = port; +#if LWIP_NETBUF_RECVINFO + if (conn->flags & NETCONN_FLAG_PKTINFO) { + /* get the UDP header - always in the first pbuf, ensured by udp_input */ + const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr(); + buf->flags = NETBUF_FLAG_DESTADDR; + ip_addr_set(&buf->toaddr, ip_current_dest_addr()); + buf->toport_chksum = udphdr->dest; + } +#endif /* LWIP_NETBUF_RECVINFO */ + } + + len = p->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } +} +#endif /* LWIP_UDP */ + +#if LWIP_TCP +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct netconn *conn; + u16_t len; + void *msg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); + LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK); + LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ + conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); + + if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { + /* recvmbox already deleted */ + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } + return ERR_OK; + } + /* Unlike for UDP or RAW pcbs, don't check for available space + using recv_avail since that could break the connection + (data is already ACKed) */ + + if (p != NULL) { + msg = p; + len = p->tot_len; + } else { + msg = LWIP_CONST_CAST(void *, &netconn_closed); + len = 0; + } + + if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) { + /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ + return ERR_MEM; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + + return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn->state == NETCONN_WRITE) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } else if (conn->state == NETCONN_CLOSE) { +#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER + if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { + conn->current_msg->msg.sd.polls_left--; + } +#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ + lwip_netconn_do_close_internal(conn WRITE_DELAYED); + } + /* @todo: implement connect timeout here? */ + + /* Did a nonblocking write fail before? Then check available write-space. */ + if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } + + return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +static err_t +sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn) { + if (conn->state == NETCONN_WRITE) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } else if (conn->state == NETCONN_CLOSE) { + lwip_netconn_do_close_internal(conn WRITE_DELAYED); + } + + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); + } + } + + return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +static void +err_tcp(void *arg, err_t err) +{ + struct netconn *conn; + enum netconn_state old_state; + void *mbox_msg; + SYS_ARCH_DECL_PROTECT(lev); + + conn = (struct netconn *)arg; + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + SYS_ARCH_PROTECT(lev); + + /* when err is called, the pcb is deallocated, so delete the reference */ + conn->pcb.tcp = NULL; + /* store pending error */ + conn->pending_err = err; + /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */ + conn->flags |= NETCONN_FLAG_MBOXCLOSED; + + /* reset conn->state now before waking up other threads */ + old_state = conn->state; + conn->state = NETCONN_NONE; + + SYS_ARCH_UNPROTECT(lev); + + /* Notify the user layer about a connection error. Used to signal select. */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + /* Try to release selects pending on 'read' or 'write', too. + They will get an error if they actually try to read or write. */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + mbox_msg = lwip_netconn_err_to_msg(err); + /* pass error message to recvmbox to wake up pending recv */ + if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { + /* use trypost to prevent deadlock */ + sys_mbox_trypost(&conn->recvmbox, mbox_msg); + } + /* pass error message to acceptmbox to wake up pending accept */ + if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { + /* use trypost to preven deadlock */ + sys_mbox_trypost(&conn->acceptmbox, mbox_msg); + } + + if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || + (old_state == NETCONN_CONNECT)) { + /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary + since the pcb has already been deleted! */ + int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + + if (!was_nonblocking_connect) { + sys_sem_t *op_completed_sem; + /* set error return code */ + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + if (old_state == NETCONN_CLOSE) { + /* let close succeed: the connection is closed after all... */ + conn->current_msg->err = ERR_OK; + } else { + /* Write and connect fail */ + conn->current_msg->err = err; + } + op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); + conn->current_msg = NULL; + /* wake up the waiting task */ + sys_sem_signal(op_completed_sem); + } else { + /* @todo: test what happens for error on nonblocking connect */ + } + } else { + LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); + } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +static void +setup_tcp(struct netconn *conn) +{ + struct tcp_pcb *pcb; + + pcb = conn->pcb.tcp; + tcp_arg(pcb, conn); + tcp_recv(pcb, recv_tcp); + tcp_sent(pcb, sent_tcp); + tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); + tcp_err(pcb, err_tcp); +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +static err_t +accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + struct netconn *newconn; + struct netconn *conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); + return ERR_VAL; + } + + if (newpcb == NULL) { + /* out-of-pcbs during connect: pass on this error to the application */ + if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + return ERR_VAL; + } + LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK); + LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ + + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state))); + + /* We have to set the callback here even though + * the new socket is unknown. newconn->socket is marked as -1. */ + newconn = netconn_alloc(conn->type, conn->callback); + if (newconn == NULL) { + /* outof netconns: pass on this error to the application */ + if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + return ERR_MEM; + } + newconn->pcb.tcp = newpcb; + setup_tcp(newconn); + + /* handle backlog counter */ + tcp_backlog_delayed(newpcb); + + if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { + /* When returning != ERR_OK, the pcb is aborted in tcp_process(), + so do nothing here! */ + /* remove all references to this netconn from the pcb */ + struct tcp_pcb *pcb = newconn->pcb.tcp; + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_poll(pcb, NULL, 0); + tcp_err(pcb, NULL); + /* remove reference from to the pcb from this netconn */ + newconn->pcb.tcp = NULL; + /* no need to drain since we know the recvmbox is empty. */ + sys_mbox_free(&newconn->recvmbox); + sys_mbox_set_invalid(&newconn->recvmbox); + netconn_free(newconn); + return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from lwip_netconn_do_newconn(). + * + * @param msg the api_msg describing the connection type + */ +static void +pcb_new(struct api_msg *msg) +{ + enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; + + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + +#if LWIP_IPV6 && LWIP_IPV4 + /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ + if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { + iptype = IPADDR_TYPE_ANY; + } +#endif + + /* Allocate a PCB for this connection */ + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); + if (msg->conn->pcb.raw != NULL) { +#if LWIP_IPV6 + /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ + if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { + msg->conn->pcb.raw->chksum_reqd = 1; + msg->conn->pcb.raw->chksum_offset = 2; + } +#endif /* LWIP_IPV6 */ + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new_ip_type(iptype); + if (msg->conn->pcb.udp != NULL) { +#if LWIP_UDPLITE + if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } +#endif /* LWIP_UDPLITE */ + if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new_ip_type(iptype); + if (msg->conn->pcb.tcp != NULL) { + setup_tcp(msg->conn); + } + break; +#endif /* LWIP_TCP */ + default: + /* Unsupported netconn type, e.g. protocol disabled */ + msg->err = ERR_VAL; + return; + } + if (msg->conn->pcb.ip == NULL) { + msg->err = ERR_MEM; + } +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param m the api_msg describing the connection type + */ +void +lwip_netconn_do_newconn(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp == NULL) { + pcb_new(msg); + } + /* Else? This "new" connection already has a PCB allocated. */ + /* Is this an error condition? Should it be deleted? */ + /* We currently just are happy and return. */ + + TCPIP_APIMSG_ACK(msg); +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is NOT created! + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn * +netconn_alloc(enum netconn_type t, netconn_callback callback) +{ + struct netconn *conn; + int size; + u8_t init_flags = 0; + + conn = (struct netconn *)memp_malloc(MEMP_NETCONN); + if (conn == NULL) { + return NULL; + } + + conn->pending_err = ERR_OK; + conn->type = t; + conn->pcb.tcp = NULL; +#if LWIP_NETCONN_FULLDUPLEX + conn->mbox_threads_waiting = 0; +#endif + + /* If all sizes are the same, every compiler should optimize this switch to nothing */ + switch (NETCONNTYPE_GROUP(t)) { +#if LWIP_RAW + case NETCONN_RAW: + size = DEFAULT_RAW_RECVMBOX_SIZE; + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + size = DEFAULT_UDP_RECVMBOX_SIZE; +#if LWIP_NETBUF_RECVINFO + init_flags |= NETCONN_FLAG_PKTINFO; +#endif /* LWIP_NETBUF_RECVINFO */ + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + size = DEFAULT_TCP_RECVMBOX_SIZE; + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); + goto free_and_return; + } + + if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { + goto free_and_return; + } +#if !LWIP_NETCONN_SEM_PER_THREAD + if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { + sys_mbox_free(&conn->recvmbox); + goto free_and_return; + } +#endif + +#if LWIP_TCP + sys_mbox_set_invalid(&conn->acceptmbox); +#endif + conn->state = NETCONN_NONE; +#if LWIP_SOCKET + /* initialize socket to -1 since 0 is a valid socket */ + conn->socket = -1; +#endif /* LWIP_SOCKET */ + conn->callback = callback; +#if LWIP_TCP + conn->current_msg = NULL; +#endif /* LWIP_TCP */ +#if LWIP_SO_SNDTIMEO + conn->send_timeout = 0; +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + conn->recv_timeout = 0; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; + conn->recv_avail = 0; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + conn->linger = -1; +#endif /* LWIP_SO_LINGER */ + conn->flags = init_flags; + return conn; +free_and_return: + memp_free(MEMP_NETCONN, conn); + return NULL; +} + +/** + * Delete a netconn and all its resources. + * The pcb is NOT freed (since we might not be in the right thread context do this). + * + * @param conn the netconn to free + */ +void +netconn_free(struct netconn *conn) +{ + LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + +#if LWIP_NETCONN_FULLDUPLEX + /* in fullduplex, netconn is drained here */ + netconn_drain(conn); +#endif /* LWIP_NETCONN_FULLDUPLEX */ + + LWIP_ASSERT("recvmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("acceptmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(&conn->op_completed); + sys_sem_set_invalid(&conn->op_completed); +#endif + + memp_free(MEMP_NETCONN, conn); +} + +/** + * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in + * these mboxes + * + * @param conn the netconn to free + * @bytes_drained bytes drained from recvmbox + * @accepts_drained pending connections drained from acceptmbox + */ +static void +netconn_drain(struct netconn *conn) +{ + void *mem; + + /* This runs when mbox and netconn are marked as closed, + so we don't need to lock against rx packets */ +#if LWIP_NETCONN_FULLDUPLEX + LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID); +#endif /* LWIP_NETCONN_FULLDUPLEX */ + + /* Delete and drain the recvmbox. */ + if (sys_mbox_valid(&conn->recvmbox)) { + while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +#if LWIP_NETCONN_FULLDUPLEX + if (!lwip_netconn_is_deallocated_msg(mem)) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + { +#if LWIP_TCP + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { + err_t err; + if (!lwip_netconn_is_err_msg(mem, &err)) { + pbuf_free((struct pbuf *)mem); + } + } else +#endif /* LWIP_TCP */ + { + netbuf_delete((struct netbuf *)mem); + } + } + } + sys_mbox_free(&conn->recvmbox); + sys_mbox_set_invalid(&conn->recvmbox); + } + + /* Delete and drain the acceptmbox. */ +#if LWIP_TCP + if (sys_mbox_valid(&conn->acceptmbox)) { + while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { +#if LWIP_NETCONN_FULLDUPLEX + if (!lwip_netconn_is_deallocated_msg(mem)) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + { + err_t err; + if (!lwip_netconn_is_err_msg(mem, &err)) { + struct netconn *newconn = (struct netconn *)mem; + /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ + /* pcb might be set to NULL already by err_tcp() */ + /* drain recvmbox */ + netconn_drain(newconn); + if (newconn->pcb.tcp != NULL) { + tcp_abort(newconn->pcb.tcp); + newconn->pcb.tcp = NULL; + } + netconn_free(newconn); + } + } + } + sys_mbox_free(&conn->acceptmbox); + sys_mbox_set_invalid(&conn->acceptmbox); + } +#endif /* LWIP_TCP */ +} + +#if LWIP_NETCONN_FULLDUPLEX +static void +netconn_mark_mbox_invalid(struct netconn *conn) +{ + int i, num_waiting; + void *msg = LWIP_CONST_CAST(void *, &netconn_deleted); + + /* Prevent new calls/threads from reading from the mbox */ + conn->flags |= NETCONN_FLAG_MBOXINVALID; + + SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting); + for (i = 0; i < num_waiting; i++) { + if (sys_mbox_valid_val(conn->recvmbox)) { + sys_mbox_trypost(&conn->recvmbox, msg); + } else { + sys_mbox_trypost(&conn->acceptmbox, msg); + } + } +} +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +#if LWIP_TCP +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +static err_t +lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) +{ + err_t err; + u8_t shut, shut_rx, shut_tx, shut_close; + u8_t close_finished = 0; + struct tcp_pcb *tpcb; +#if LWIP_SO_LINGER + u8_t linger_wait_required = 0; +#endif /* LWIP_SO_LINGER */ + + LWIP_ASSERT("invalid conn", (conn != NULL)); + LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); + LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); + LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + + tpcb = conn->pcb.tcp; + shut = conn->current_msg->msg.sd.shut; + shut_rx = shut & NETCONN_SHUT_RD; + shut_tx = shut & NETCONN_SHUT_WR; + /* shutting down both ends is the same as closing + (also if RD or WR side was shut down before already) */ + if (shut == NETCONN_SHUT_RDWR) { + shut_close = 1; + } else if (shut_rx && + ((tpcb->state == FIN_WAIT_1) || + (tpcb->state == FIN_WAIT_2) || + (tpcb->state == CLOSING))) { + shut_close = 1; + } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { + shut_close = 1; + } else { + shut_close = 0; + } + + /* Set back some callback pointers */ + if (shut_close) { + tcp_arg(tpcb, NULL); + } + if (tpcb->state == LISTEN) { + tcp_accept(tpcb, NULL); + } else { + /* some callbacks have to be reset if tcp_close is not successful */ + if (shut_rx) { + tcp_recv(tpcb, NULL); + tcp_accept(tpcb, NULL); + } + if (shut_tx) { + tcp_sent(tpcb, NULL); + } + if (shut_close) { + tcp_poll(tpcb, NULL, 0); + tcp_err(tpcb, NULL); + } + } + /* Try to close the connection */ + if (shut_close) { +#if LWIP_SO_LINGER + /* check linger possibilites before calling tcp_close */ + err = ERR_OK; + /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ + if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { + if ((conn->linger == 0)) { + /* data left but linger prevents waiting */ + tcp_abort(tpcb); + tpcb = NULL; + } else if (conn->linger > 0) { + /* data left and linger says we should wait */ + if (netconn_is_nonblocking(conn)) { + /* data left on a nonblocking netconn -> cannot linger */ + err = ERR_WOULDBLOCK; + } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= + (conn->linger * 1000)) { + /* data left but linger timeout has expired (this happens on further + calls to this function through poll_tcp */ + tcp_abort(tpcb); + tpcb = NULL; + } else { + /* data left -> need to wait for ACK after successful close */ + linger_wait_required = 1; + } + } + } + if ((err == ERR_OK) && (tpcb != NULL)) +#endif /* LWIP_SO_LINGER */ + { + err = tcp_close(tpcb); + } + } else { + err = tcp_shutdown(tpcb, shut_rx, shut_tx); + } + if (err == ERR_OK) { + close_finished = 1; +#if LWIP_SO_LINGER + if (linger_wait_required) { + /* wait for ACK of all unsent/unacked data by just getting called again */ + close_finished = 0; + err = ERR_INPROGRESS; + } +#endif /* LWIP_SO_LINGER */ + } else { + if (err == ERR_MEM) { + /* Closing failed because of memory shortage, try again later. Even for + nonblocking netconns, we have to wait since no standard socket application + is prepared for close failing because of resource shortage. + Check the timeout: this is kind of an lwip addition to the standard sockets: + we wait for some time when failing to allocate a segment for the FIN */ +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout > 0) { + close_timeout = conn->send_timeout; + } +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_LINGER + if (conn->linger >= 0) { + /* use linger timeout (seconds) */ + close_timeout = conn->linger * 1000U; + } +#endif + if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + if (conn->current_msg->msg.sd.polls_left == 0) { +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + close_finished = 1; + if (shut_close) { + /* in this case, we want to RST the connection */ + tcp_abort(tpcb); + err = ERR_OK; + } + } + } else { + /* Closing failed for a non-memory error: give up */ + close_finished = 1; + } + } + if (close_finished) { + /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ + sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + conn->current_msg->err = err; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + if (err == ERR_OK) { + if (shut_close) { + /* Set back some callback pointers as conn is going away */ + conn->pcb.tcp = NULL; + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + } + if (shut_rx) { + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + if (shut_tx) { + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } +#if LWIP_TCPIP_CORE_LOCKING + if (delayed) +#endif + { + /* wake up the application task */ + sys_sem_signal(op_completed_sem); + } + return ERR_OK; + } + if (!close_finished) { + /* Closing failed and we want to wait: restore some of the callbacks */ + /* Closing of listen pcb will never fail! */ + LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); + if (shut_tx) { + tcp_sent(tpcb, sent_tcp); + } + /* when waiting for close, set up poll interval to 500ms */ + tcp_poll(tpcb, poll_tcp, 1); + tcp_err(tpcb, err_tcp); + tcp_arg(tpcb, conn); + /* don't restore recv callback: we don't want to receive any more data */ + } + /* If closing didn't succeed, we get called again either + from poll_tcp or from sent_tcp */ + LWIP_ASSERT("err != ERR_OK", err != ERR_OK); + return err; +} +#endif /* LWIP_TCP */ + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_delconn(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + enum netconn_state state = msg->conn->state; + LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ + (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); +#if LWIP_NETCONN_FULLDUPLEX + /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ + if (state != NETCONN_NONE) { + if ((state == NETCONN_WRITE) || + ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { + /* close requested, abort running write/connect */ + sys_sem_t *op_completed_sem; + LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); + op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); + msg->conn->current_msg->err = ERR_CLSD; + msg->conn->current_msg = NULL; + msg->conn->state = NETCONN_NONE; + sys_sem_signal(op_completed_sem); + } + } +#else /* LWIP_NETCONN_FULLDUPLEX */ + if (((state != NETCONN_NONE) && + (state != NETCONN_LISTEN) && + (state != NETCONN_CONNECT)) || + ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { + /* This means either a blocking write or blocking connect is running + (nonblocking write returns and sets state to NONE) */ + msg->err = ERR_INPROGRESS; + } else +#endif /* LWIP_NETCONN_FULLDUPLEX */ + { + LWIP_ASSERT("blocking connect in progress", + (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); + msg->err = ERR_OK; +#if LWIP_NETCONN_FULLDUPLEX + /* Mark mboxes invalid */ + netconn_mark_mbox_invalid(msg->conn); +#else /* LWIP_NETCONN_FULLDUPLEX */ + netconn_drain(msg->conn); +#endif /* LWIP_NETCONN_FULLDUPLEX */ + + if (msg->conn->pcb.tcp != NULL) { + + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp->recv_arg = NULL; + udp_remove(msg->conn->pcb.udp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); + msg->conn->state = NETCONN_CLOSE; + msg->msg.sd.shut = NETCONN_SHUT_RDWR; + msg->conn->current_msg = msg; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_close_internal(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing + the application thread, so we can return at this point! */ + return; +#endif /* LWIP_TCP */ + default: + break; + } + msg->conn->pcb.tcp = NULL; + } + /* tcp netconns don't come here! */ + + /* @todo: this lets select make the socket readable and writable, + which is wrong! errfd instead? */ + API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + } + if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { + TCPIP_APIMSG_ACK(msg); + } +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param m the api_msg pointing to the connection and containing + * the IP address and port to bind to + */ +void +lwip_netconn_do_bind(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + err_t err; + + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_TCP */ + default: + err = ERR_VAL; + break; + } + } else { + err = ERR_VAL; + } + msg->err = err; + TCPIP_APIMSG_ACK(msg); +} +/** + * Bind a pcb contained in a netconn to an interface + * Called from netconn_bind_if. + * + * @param m the api_msg pointing to the connection and containing + * the IP address and port to bind to + */ +void +lwip_netconn_do_bind_if(void *m) +{ + struct netif *netif; + struct api_msg *msg = (struct api_msg *)m; + err_t err; + + netif = netif_get_by_index(msg->msg.bc.if_idx); + + if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { + err = ERR_OK; + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + raw_bind_netif(msg->conn->pcb.raw, netif); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + udp_bind_netif(msg->conn->pcb.udp, netif); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + tcp_bind_netif(msg->conn->pcb.tcp, netif); + break; +#endif /* LWIP_TCP */ + default: + err = ERR_VAL; + break; + } + } else { + err = ERR_VAL; + } + msg->err = err; + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t +lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct netconn *conn; + int was_blocking; + sys_sem_t *op_completed_sem = NULL; + + LWIP_UNUSED_ARG(pcb); + + conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + + LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); + LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", + (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); + + if (conn->current_msg != NULL) { + conn->current_msg->err = err; + op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + } + if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { + setup_tcp(conn); + } + was_blocking = !IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + LWIP_ASSERT("blocking connect state error", + (was_blocking && op_completed_sem != NULL) || + (!was_blocking && op_completed_sem == NULL)); + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + if (was_blocking) { + sys_sem_signal(op_completed_sem); + } + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param m the api_msg pointing to the connection and containing + * the IP address and port to connect to + */ +void +lwip_netconn_do_connect(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + err_t err; + + if (msg->conn->pcb.tcp == NULL) { + /* This may happen when calling netconn_connect() a second time */ + err = ERR_CLSD; + } else { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + /* Prevent connect while doing any other action. */ + if (msg->conn->state == NETCONN_CONNECT) { + err = ERR_ALREADY; + } else if (msg->conn->state != NETCONN_NONE) { + err = ERR_ISCONN; + } else { + setup_tcp(msg->conn); + err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), + msg->msg.bc.port, lwip_netconn_do_connected); + if (err == ERR_OK) { + u8_t non_blocking = netconn_is_nonblocking(msg->conn); + msg->conn->state = NETCONN_CONNECT; + SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); + if (non_blocking) { + err = ERR_INPROGRESS; + } else { + msg->conn->current_msg = msg; + /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), + when the connection is established! */ +#if LWIP_TCPIP_CORE_LOCKING + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + return; + } + } + } + break; +#endif /* LWIP_TCP */ + default: + LWIP_ERROR("Invalid netconn type", 0, do { + err = ERR_VAL; + } while (0)); + break; + } + } + msg->err = err; + /* For all other protocols, netconn_connect() calls netconn_apimsg(), + so use TCPIP_APIMSG_ACK() here. */ + TCPIP_APIMSG_ACK(msg); +} + +/** + * Disconnect a pcb contained inside a netconn + * Only used for UDP netconns. + * Called from netconn_disconnect. + * + * @param m the api_msg pointing to the connection to disconnect + */ +void +lwip_netconn_do_disconnect(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + +#if LWIP_UDP + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { + udp_disconnect(msg->conn->pcb.udp); + msg->err = ERR_OK; + } else +#endif /* LWIP_UDP */ + { + msg->err = ERR_VAL; + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_listen(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + err_t err; + + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + if (msg->conn->state == NETCONN_NONE) { + struct tcp_pcb *lpcb; + if (msg->conn->pcb.tcp->state != CLOSED) { + /* connection is not closed, cannot listen */ + err = ERR_VAL; + } else { + u8_t backlog; +#if TCP_LISTEN_BACKLOG + backlog = msg->msg.lb.backlog; +#else /* TCP_LISTEN_BACKLOG */ + backlog = TCP_DEFAULT_LISTEN_BACKLOG; +#endif /* TCP_LISTEN_BACKLOG */ +#if LWIP_IPV4 && LWIP_IPV6 + /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, + * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen + */ + if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && + (netconn_get_ipv6only(msg->conn) == 0)) { + /* change PCB type to IPADDR_TYPE_ANY */ + IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); + IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); + + if (lpcb == NULL) { + /* in this case, the old pcb is still allocated */ + } else { + /* delete the recvmbox and allocate the acceptmbox */ + if (sys_mbox_valid(&msg->conn->recvmbox)) { + /** @todo: should we drain the recvmbox here? */ + sys_mbox_free(&msg->conn->recvmbox); + sys_mbox_set_invalid(&msg->conn->recvmbox); + } + err = ERR_OK; + if (!sys_mbox_valid(&msg->conn->acceptmbox)) { + err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); + } + if (err == ERR_OK) { + msg->conn->state = NETCONN_LISTEN; + msg->conn->pcb.tcp = lpcb; + tcp_arg(msg->conn->pcb.tcp, msg->conn); + tcp_accept(msg->conn->pcb.tcp, accept_function); + } else { + /* since the old pcb is already deallocated, free lpcb now */ + tcp_close(lpcb); + msg->conn->pcb.tcp = NULL; + } + } + } + } else if (msg->conn->state == NETCONN_LISTEN) { + /* already listening, allow updating of the backlog */ + err = ERR_OK; + tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); + } else { + err = ERR_CONN; + } + } else { + err = ERR_ARG; + } + } else { + err = ERR_CONN; + } + msg->err = err; + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_send(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + err_t err = netconn_err(msg->conn); + if (err == ERR_OK) { + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); + } else { + err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); + } + break; +#endif +#if LWIP_UDP + case NETCONN_UDP: +#if LWIP_CHECKSUM_ON_COPY + if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } else { + err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, + &msg->msg.b->addr, msg->msg.b->port, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } +#else /* LWIP_CHECKSUM_ON_COPY */ + if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); + } else { + err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + break; +#endif /* LWIP_UDP */ + default: + err = ERR_CONN; + break; + } + } else { + err = ERR_CONN; + } + } + msg->err = err; + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_recv(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + size_t remaining = msg->msg.r.len; + do { + u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining); + tcp_recved(msg->conn->pcb.tcp, recved); + remaining -= recved; + } while (remaining != 0); + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if TCP_LISTEN_BACKLOG +/** Indicate that a TCP pcb has been accepted + * Called from netconn_accept + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_accepted(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + tcp_backlog_accepted(msg->conn->pcb.tcp); + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* TCP_LISTEN_BACKLOG */ + +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from lwip_netconn_do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +static err_t +lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) +{ + err_t err; + const void *dataptr; + u16_t len, available; + u8_t write_finished = 0; + size_t diff; + u8_t dontblock; + u8_t apiflags; + u8_t write_more; + + LWIP_ASSERT("conn != NULL", conn != NULL); + LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); + LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len", + conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len); + LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0); + + apiflags = conn->current_msg->msg.w.apiflags; + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); + +#if LWIP_SO_SNDTIMEO + if ((conn->send_timeout != 0) && + ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { + write_finished = 1; + if (conn->current_msg->msg.w.offset == 0) { + /* nothing has been written */ + err = ERR_WOULDBLOCK; + } else { + /* partial write */ + err = ERR_OK; + } + } else +#endif /* LWIP_SO_SNDTIMEO */ + { + do { + dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off; + diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off; + if (diff > 0xffffUL) { /* max_u16_t */ + len = 0xffff; + apiflags |= TCP_WRITE_FLAG_MORE; + } else { + len = (u16_t)diff; + } + available = tcp_sndbuf(conn->pcb.tcp); + if (available < len) { + /* don't try to write more than sendbuf */ + len = available; + if (dontblock) { + if (!len) { + /* set error according to partial write or not */ + err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; + goto err_mem; + } + } else { + apiflags |= TCP_WRITE_FLAG_MORE; + } + } + LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", + ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len)); + /* we should loop around for more sending in the following cases: + 1) We couldn't finish the current vector because of 16-bit size limitations. + tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes + 2) We are sending the remainder of the current vector and have more */ + if ((len == 0xffff && diff > 0xffffUL) || + (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) { + write_more = 1; + apiflags |= TCP_WRITE_FLAG_MORE; + } else { + write_more = 0; + } + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + if (err == ERR_OK) { + conn->current_msg->msg.w.offset += len; + conn->current_msg->msg.w.vector_off += len; + /* check if current vector is finished */ + if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) { + conn->current_msg->msg.w.vector_cnt--; + /* if we have additional vectors, move on to them */ + if (conn->current_msg->msg.w.vector_cnt > 0) { + conn->current_msg->msg.w.vector++; + conn->current_msg->msg.w.vector_off = 0; + } + } + } + } while (write_more && err == ERR_OK); + /* if OK or memory error, check available space */ + if ((err == ERR_OK) || (err == ERR_MEM)) { +err_mem: + if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) { + /* non-blocking write did not write everything: mark the pcb non-writable + and let poll_tcp check writable space to mark the pcb writable again */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); + } + } + + if (err == ERR_OK) { + err_t out_err; + if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) { + /* return sent length (caller reads length from msg.w.offset) */ + write_finished = 1; + } + out_err = tcp_output(conn->pcb.tcp); + if (out_err == ERR_RTE) { + /* If tcp_output fails because no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + } + } else if (err == ERR_MEM) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. + For blocking sockets, we do NOT return to the application + thread, since ERR_MEM is only a temporary error! Non-blocking + will remain non-writable until sent_tcp/poll_tcp is called */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + err_t out_err = tcp_output(conn->pcb.tcp); + if (out_err == ERR_RTE) { + /* If tcp_output fails because no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + } else if (dontblock) { + /* non-blocking write is done on ERR_MEM, set error according + to partial write or not */ + err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; + write_finished = 1; + } + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + } + } + if (write_finished) { + /* everything was written: set back connection state + and back to application task */ + sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + conn->current_msg->err = err; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; +#if LWIP_TCPIP_CORE_LOCKING + if (delayed) +#endif + { + sys_sem_signal(op_completed_sem); + } + } +#if LWIP_TCPIP_CORE_LOCKING + else { + return ERR_MEM; + } +#endif + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_write(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + err_t err = netconn_err(msg->conn); + if (err == ERR_OK) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { +#if LWIP_TCP + if (msg->conn->state != NETCONN_NONE) { + /* netconn is connecting, closing or in blocking write */ + err = ERR_INPROGRESS; + } else if (msg->conn->pcb.tcp != NULL) { + msg->conn->state = NETCONN_WRITE; + /* set all the variables used by lwip_netconn_do_writemore */ + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); + LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); + msg->conn->current_msg = msg; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_writemore(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG + since lwip_netconn_do_writemore ACKs it! */ + return; + } else { + err = ERR_CONN; + } +#else /* LWIP_TCP */ + err = ERR_VAL; +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) + } else { + err = ERR_VAL; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + } + msg->err = err; + TCPIP_APIMSG_ACK(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_getaddr(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + if (msg->conn->pcb.ip != NULL) { + if (msg->msg.ad.local) { + ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->local_ip); + } else { + ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->remote_ip); + } + + msg->err = ERR_OK; + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (msg->msg.ad.local) { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; + } else { + /* return an error as connecting is only a helper for upper layers */ + msg->err = ERR_CONN; + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + if (msg->msg.ad.local) { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; + } else { + if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { + msg->err = ERR_CONN; + } else { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; + } + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + if ((msg->msg.ad.local == 0) && + ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { + /* pcb is not connected and remote name is requested */ + msg->err = ERR_CONN; + } else { + API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); + } + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("invalid netconn_type", 0); + break; + } + } else { + msg->err = ERR_CONN; + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * Close or half-shutdown a TCP pcb contained in a netconn + * Called from netconn_close + * In contrast to closing sockets, the netconn is not deallocated. + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_close(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + +#if LWIP_TCP + enum netconn_state state = msg->conn->state; + /* First check if this is a TCP netconn and if it is in a correct state + (LISTEN doesn't support half shutdown) */ + if ((msg->conn->pcb.tcp != NULL) && + (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && + ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { + /* Check if we are in a connected state */ + if (state == NETCONN_CONNECT) { + /* TCP connect in progress: cannot shutdown */ + msg->err = ERR_CONN; + } else if (state == NETCONN_WRITE) { +#if LWIP_NETCONN_FULLDUPLEX + if (msg->msg.sd.shut & NETCONN_SHUT_WR) { + /* close requested, abort running write */ + sys_sem_t *write_completed_sem; + LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); + write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); + msg->conn->current_msg->err = ERR_CLSD; + msg->conn->current_msg = NULL; + msg->conn->state = NETCONN_NONE; + state = NETCONN_NONE; + sys_sem_signal(write_completed_sem); + } else { + LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); + /* In this case, let the write continue and do not interfere with + conn->current_msg or conn->state! */ + msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); + } + } + if (state == NETCONN_NONE) { +#else /* LWIP_NETCONN_FULLDUPLEX */ + msg->err = ERR_INPROGRESS; + } else { +#endif /* LWIP_NETCONN_FULLDUPLEX */ + if (msg->msg.sd.shut & NETCONN_SHUT_RD) { +#if LWIP_NETCONN_FULLDUPLEX + /* Mark mboxes invalid */ + netconn_mark_mbox_invalid(msg->conn); +#else /* LWIP_NETCONN_FULLDUPLEX */ + netconn_drain(msg->conn); +#endif /* LWIP_NETCONN_FULLDUPLEX */ + } + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); + msg->conn->state = NETCONN_CLOSE; + msg->conn->current_msg = msg; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_close_internal(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ + return; + } + } else +#endif /* LWIP_TCP */ + { + msg->err = ERR_CONN; + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_join_leave_group(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP +#if LWIP_IPV6 && LWIP_IPV6_MLD + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } + } else +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + { +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } +#endif /* LWIP_IGMP */ + } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ + } + } + TCPIP_APIMSG_ACK(msg); +} +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group_netif + * + * @param m the api_msg pointing to the connection + */ +void +lwip_netconn_do_join_leave_group_netif(void *m) +{ + struct api_msg *msg = (struct api_msg *)m; + struct netif *netif; + + netif = netif_get_by_index(msg->msg.jl.if_idx); + if (netif == NULL) { + msg->err = ERR_IF; + goto done; + } + + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP +#if LWIP_IPV6 && LWIP_IPV6_MLD + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mld6_joingroup_netif(netif, + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = mld6_leavegroup_netif(netif, + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } + } else +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + { +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = igmp_joingroup_netif(netif, + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = igmp_leavegroup_netif(netif, + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } +#endif /* LWIP_IGMP */ + } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ + } + } + +done: + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/** + * Callback function that is called when DNS name is resolved + * (or on timeout). A waiting application thread is waked up by + * signaling the semaphore. + */ +static void +lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg *)arg; + + /* we trust the internal implementation to be correct :-) */ + LWIP_UNUSED_ARG(name); + + if (ipaddr == NULL) { + /* timeout or memory error */ + API_EXPR_DEREF(msg->err) = ERR_VAL; + } else { + /* address was resolved */ + API_EXPR_DEREF(msg->err) = ERR_OK; + API_EXPR_DEREF(msg->addr) = *ipaddr; + } + /* wake up the application task waiting in netconn_gethostbyname */ + sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); +} + +/** + * Execute a DNS query + * Called from netconn_gethostbyname + * + * @param arg the dns_api_msg pointing to the query + */ +void +lwip_netconn_do_gethostbyname(void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg *)arg; + u8_t addrtype = +#if LWIP_IPV4 && LWIP_IPV6 + msg->dns_addrtype; +#else + LWIP_DNS_ADDRTYPE_DEFAULT; +#endif + + API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, + API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); +#if LWIP_TCPIP_CORE_LOCKING + /* For core locking, only block if we need to wait for answer/timeout */ + if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) { + UNLOCK_TCPIP_CORE(); + sys_sem_wait(API_EXPR_REF_SEM(msg->sem)); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { + /* on error or immediate success, wake up the application + * task waiting in netconn_gethostbyname */ + sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); + } +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} +#endif /* LWIP_DNS */ + +#endif /* LWIP_NETCONN */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/err.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/err.c new file mode 100644 index 0000000..dd2b62d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/err.c @@ -0,0 +1,115 @@ +/** + * @file + * Error Management module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/err.h" +#include "lwip/def.h" +#include "lwip/sys.h" + +#include "lwip/errno.h" + +#if !NO_SYS +/** Table to quickly map an lwIP error (err_t) to a socket error + * by using -err as an index */ +static const int err_to_errno_table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + ENOMEM, /* ERR_MEM -1 Out of memory error. */ + ENOBUFS, /* ERR_BUF -2 Buffer error. */ + EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + EINVAL, /* ERR_VAL -6 Illegal value. */ + EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + EADDRINUSE, /* ERR_USE -8 Address in use. */ + EALREADY, /* ERR_ALREADY -9 Already connecting. */ + EISCONN, /* ERR_ISCONN -10 Conn already established.*/ + ENOTCONN, /* ERR_CONN -11 Not connected. */ + -1, /* ERR_IF -12 Low-level netif error */ + ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */ + ECONNRESET, /* ERR_RST -14 Connection reset. */ + ENOTCONN, /* ERR_CLSD -15 Connection closed. */ + EIO /* ERR_ARG -16 Illegal argument. */ +}; + +int +err_to_errno(err_t err) +{ + if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) { + return EIO; + } + return err_to_errno_table[-err]; +} +#endif /* !NO_SYS */ + +#ifdef LWIP_DEBUG + +static const char *err_strerr[] = { + "Ok.", /* ERR_OK 0 */ + "Out of memory error.", /* ERR_MEM -1 */ + "Buffer error.", /* ERR_BUF -2 */ + "Timeout.", /* ERR_TIMEOUT -3 */ + "Routing problem.", /* ERR_RTE -4 */ + "Operation in progress.", /* ERR_INPROGRESS -5 */ + "Illegal value.", /* ERR_VAL -6 */ + "Operation would block.", /* ERR_WOULDBLOCK -7 */ + "Address in use.", /* ERR_USE -8 */ + "Already connecting.", /* ERR_ALREADY -9 */ + "Already connected.", /* ERR_ISCONN -10 */ + "Not connected.", /* ERR_CONN -11 */ + "Low-level netif error.", /* ERR_IF -12 */ + "Connection aborted.", /* ERR_ABRT -13 */ + "Connection reset.", /* ERR_RST -14 */ + "Connection closed.", /* ERR_CLSD -15 */ + "Illegal argument." /* ERR_ARG -16 */ +}; + +/** + * Convert an lwip internal error to a string representation. + * + * @param err an lwip internal err_t + * @return a string representation for err + */ +const char * +lwip_strerr(err_t err) +{ + if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) { + return "Unknown error."; + } + return err_strerr[-err]; +} + +#endif /* LWIP_DEBUG */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/if_api.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/if_api.c new file mode 100644 index 0000000..8e094d0 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/if_api.c @@ -0,0 +1,102 @@ +/** + * @file + * Interface Identification APIs from: + * RFC 3493: Basic Socket Interface Extensions for IPv6 + * Section 4: Interface Identification + * + * @defgroup if_api Interface Identification API + * @ingroup socket + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Joel Cunningham + * + */ +#include "lwip/opt.h" + +#if LWIP_SOCKET + +#include "lwip/errno.h" +#include "lwip/if_api.h" +#include "lwip/netifapi.h" +#include "lwip/priv/sockets_priv.h" + +/** + * @ingroup if_api + * Maps an interface index to its corresponding name. + * @param ifindex interface index + * @param ifname shall point to a buffer of at least {IF_NAMESIZE} bytes + * @return If ifindex is an interface index, then the function shall return the + * value supplied in ifname, which points to a buffer now containing the interface name. + * Otherwise, the function shall return a NULL pointer. + */ +char * +lwip_if_indextoname(unsigned int ifindex, char *ifname) +{ +#if LWIP_NETIF_API + if (ifindex <= 0xff) { + err_t err = netifapi_netif_index_to_name((u8_t)ifindex, ifname); + if (!err && ifname[0] != '\0') { + return ifname; + } + } +#else /* LWIP_NETIF_API */ + LWIP_UNUSED_ARG(ifindex); + LWIP_UNUSED_ARG(ifname); +#endif /* LWIP_NETIF_API */ + set_errno(ENXIO); + return NULL; +} + +/** + * @ingroup if_api + * Returs the interface index corresponding to name ifname. + * @param ifname Interface name + * @return The corresponding index if ifname is the name of an interface; + * otherwise, zero. + */ +unsigned int +lwip_if_nametoindex(const char *ifname) +{ +#if LWIP_NETIF_API + err_t err; + u8_t idx; + + err = netifapi_netif_name_to_index(ifname, &idx); + if (!err) { + return idx; + } +#else /* LWIP_NETIF_API */ + LWIP_UNUSED_ARG(ifname); +#endif /* LWIP_NETIF_API */ + return 0; /* invalid index */ +} + +#endif /* LWIP_SOCKET */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netbuf.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netbuf.c new file mode 100644 index 0000000..3b910de --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netbuf.c @@ -0,0 +1,250 @@ +/** + * @file + * Network buffer management + * + * @defgroup netbuf Network buffers + * @ingroup netconn + * Network buffer descriptor for @ref netconn. Based on @ref pbuf internally + * to avoid copying data around.\n + * Buffers must not be shared accross multiple threads, all functions except + * netbuf_new() and netbuf_delete() are not thread-safe. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netbuf.h" +#include "lwip/memp.h" + +#include + +/** + * @ingroup netbuf + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * + * @return a pointer to a new netbuf + * NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ + struct netbuf *buf; + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf != NULL) { + memset(buf, 0, sizeof(struct netbuf)); + } + return buf; +} + +/** + * @ingroup netbuf + * Deallocate a netbuf allocated by netbuf_new(). + * + * @param buf pointer to a netbuf allocated by netbuf_new() + */ +void +netbuf_delete(struct netbuf *buf) +{ + if (buf != NULL) { + if (buf->p != NULL) { + pbuf_free(buf->p); + buf->p = buf->ptr = NULL; + } + memp_free(MEMP_NETBUF, buf); + } +} + +/** + * @ingroup netbuf + * Allocate memory for a packet buffer for a given netbuf. + * + * @param buf the netbuf for which to allocate a packet buffer + * @param size the size of the packet buffer to allocate + * @return pointer to the allocated memory + * NULL if no memory could be allocated + */ +void * +netbuf_alloc(struct netbuf *buf, u16_t size) +{ + LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); + + /* Deallocate any previously allocated memory. */ + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (buf->p == NULL) { + return NULL; + } + LWIP_ASSERT("check that first pbuf can hold size", + (buf->p->len >= size)); + buf->ptr = buf->p; + return buf->p->payload; +} + +/** + * @ingroup netbuf + * Free the packet buffer included in a netbuf + * + * @param buf pointer to the netbuf which contains the packet buffer to free + */ +void +netbuf_free(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = buf->ptr = NULL; +#if LWIP_CHECKSUM_ON_COPY + buf->flags = 0; + buf->toport_chksum = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ +} + +/** + * @ingroup netbuf + * Let a netbuf reference existing (non-volatile) data. + * + * @param buf netbuf which should reference the data + * @param dataptr pointer to the data to reference + * @param size size of the data + * @return ERR_OK if data is referenced + * ERR_MEM if data couldn't be referenced due to lack of memory + */ +err_t +netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) +{ + LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + if (buf->p == NULL) { + buf->ptr = NULL; + return ERR_MEM; + } + ((struct pbuf_rom *)buf->p)->payload = dataptr; + buf->p->len = buf->p->tot_len = size; + buf->ptr = buf->p; + return ERR_OK; +} + +/** + * @ingroup netbuf + * Chain one netbuf to another (@see pbuf_chain) + * + * @param head the first netbuf + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning + */ +void +netbuf_chain(struct netbuf *head, struct netbuf *tail) +{ + LWIP_ERROR("netbuf_chain: invalid head", (head != NULL), return;); + LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); + pbuf_cat(head->p, tail->p); + head->ptr = head->p; + memp_free(MEMP_NETBUF, tail); +} + +/** + * @ingroup netbuf + * Get the data pointer and length of the data inside a netbuf. + * + * @param buf netbuf to get the data from + * @param dataptr pointer to a void pointer where to store the data pointer + * @param len pointer to an u16_t where the length of the data is stored + * @return ERR_OK if the information was retrieved, + * ERR_BUF on error. + */ +err_t +netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) +{ + LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); + + if (buf->ptr == NULL) { + return ERR_BUF; + } + *dataptr = buf->ptr->payload; + *len = buf->ptr->len; + return ERR_OK; +} + +/** + * @ingroup netbuf + * Move the current data pointer of a packet buffer contained in a netbuf + * to the next part. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + * @return -1 if there is no next part + * 1 if moved to the next part but now there is no next part + * 0 if moved to the next part and there are still more parts + */ +s8_t +netbuf_next(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_next: invalid buf", (buf != NULL), return -1;); + if (buf->ptr->next == NULL) { + return -1; + } + buf->ptr = buf->ptr->next; + if (buf->ptr->next == NULL) { + return 1; + } + return 0; +} + +/** + * @ingroup netbuf + * Move the current data pointer of a packet buffer contained in a netbuf + * to the beginning of the packet. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + */ +void +netbuf_first(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_first: invalid buf", (buf != NULL), return;); + buf->ptr = buf->p; +} + +#endif /* LWIP_NETCONN */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netdb.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netdb.c new file mode 100644 index 0000000..ee78297 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netdb.c @@ -0,0 +1,417 @@ +/** + * @file + * API functions for name resolving + * + * @defgroup netdbapi NETDB API + * @ingroup socket + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/netdb.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/err.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/api.h" +#include "lwip/dns.h" + +#include /* memset */ +#include /* atoi */ + +/** helper struct for gethostbyname_r to access the char* buffer */ +struct gethostbyname_r_helper { + ip_addr_t *addr_list[2]; + ip_addr_t addr; + char *aliases; +}; + +/** h_errno is exported in netdb.h for access by applications. */ +#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + +/** define "hostent" variables storage: 0 if we use a static (but unprotected) + * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +#ifndef LWIP_DNS_API_HOSTENT_STORAGE +#define LWIP_DNS_API_HOSTENT_STORAGE 0 +#endif + +/** define "hostent" variables storage */ +#if LWIP_DNS_API_HOSTENT_STORAGE +#define HOSTENT_STORAGE +#else +#define HOSTENT_STORAGE static +#endif /* LWIP_DNS_API_STATIC_HOSTENT */ + +/** + * Returns an entry containing addresses of address family AF_INET + * for the host with name name. + * Due to dns_gethostbyname limitations, only one address is returned. + * + * @param name the hostname to resolve + * @return an entry containing addresses of address family AF_INET + * for the host with name name + */ +struct hostent * +lwip_gethostbyname(const char *name) +{ + err_t err; + ip_addr_t addr; + + /* buffer variables for lwip_gethostbyname() */ + HOSTENT_STORAGE struct hostent s_hostent; + HOSTENT_STORAGE char *s_aliases; + HOSTENT_STORAGE ip_addr_t s_hostent_addr; + HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; + HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; + + /* query host IP address */ + err = netconn_gethostbyname(name, &addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + h_errno = HOST_NOT_FOUND; + return NULL; + } + + /* fill hostent */ + s_hostent_addr = addr; + s_phostent_addr[0] = &s_hostent_addr; + s_phostent_addr[1] = NULL; + strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH); + s_hostname[DNS_MAX_NAME_LENGTH] = 0; + s_hostent.h_name = s_hostname; + s_aliases = NULL; + s_hostent.h_aliases = &s_aliases; + s_hostent.h_addrtype = AF_INET; + s_hostent.h_length = sizeof(ip_addr_t); + s_hostent.h_addr_list = (char **)&s_phostent_addr; + +#if DNS_DEBUG + /* dump hostent */ + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void *)s_hostent.h_aliases)); + /* h_aliases are always empty */ + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void *)s_hostent.h_addr_list)); + if (s_hostent.h_addr_list != NULL) { + u8_t idx; + for (idx = 0; s_hostent.h_addr_list[idx]; idx++) { + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa(s_phostent_addr[idx]))); + } + } +#endif /* DNS_DEBUG */ + +#if LWIP_DNS_API_HOSTENT_STORAGE + /* this function should return the "per-thread" hostent after copy from s_hostent */ + return sys_thread_hostent(&s_hostent); +#else + return &s_hostent; +#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ +} + +/** + * Thread-safe variant of lwip_gethostbyname: instead of using a static + * buffer, this function takes buffer and errno pointers as arguments + * and uses these for the result. + * + * @param name the hostname to resolve + * @param ret pre-allocated struct where to store the result + * @param buf pre-allocated buffer where to store additional data + * @param buflen the size of buf + * @param result pointer to a hostent pointer that is set to ret on success + * and set to zero on error + * @param h_errnop pointer to an int where to store errors (instead of modifying + * the global h_errno) + * @return 0 on success, non-zero on error, additional error information + * is stored in *h_errnop instead of h_errno to be thread-safe + */ +int +lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop) +{ + err_t err; + struct gethostbyname_r_helper *h; + char *hostname; + size_t namelen; + int lh_errno; + + if (h_errnop == NULL) { + /* ensure h_errnop is never NULL */ + h_errnop = &lh_errno; + } + + if (result == NULL) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + /* first thing to do: set *result to nothing */ + *result = NULL; + if ((name == NULL) || (ret == NULL) || (buf == NULL)) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + + namelen = strlen(name); + if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) { + /* buf can't hold the data needed + a copy of name */ + *h_errnop = ERANGE; + return -1; + } + + h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf); + hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper); + + /* query host IP address */ + err = netconn_gethostbyname(name, &h->addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + *h_errnop = HOST_NOT_FOUND; + return -1; + } + + /* copy the hostname into buf */ + MEMCPY(hostname, name, namelen); + hostname[namelen] = 0; + + /* fill hostent */ + h->addr_list[0] = &h->addr; + h->addr_list[1] = NULL; + h->aliases = NULL; + ret->h_name = hostname; + ret->h_aliases = &h->aliases; + ret->h_addrtype = AF_INET; + ret->h_length = sizeof(ip_addr_t); + ret->h_addr_list = (char **)&h->addr_list; + + /* set result != NULL */ + *result = ret; + + /* return success */ + return 0; +} + +/** + * Frees one or more addrinfo structures returned by getaddrinfo(), along with + * any additional storage associated with those structures. If the ai_next field + * of the structure is not null, the entire list of structures is freed. + * + * @param ai struct addrinfo to free + */ +void +lwip_freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + while (ai != NULL) { + next = ai->ai_next; + memp_free(MEMP_NETDB, ai); + ai = next; + } +} + +/** + * Translates the name of a service location (for example, a host name) and/or + * a service name and returns a set of socket addresses and associated + * information to be used in creating a socket with which to address the + * specified service. + * Memory for the result is allocated internally and must be freed by calling + * lwip_freeaddrinfo()! + * + * Due to a limitation in dns_gethostbyname, only the first address of a + * host is returned. + * Also, service names are not supported (only port numbers)! + * + * @param nodename descriptive name or address string of the host + * (may be NULL -> local address) + * @param servname port number as string of NULL + * @param hints structure containing input values that set socktype and protocol + * @param res pointer to a pointer where to store the result (set to NULL on failure) + * @return 0 on success, non-zero on failure + * + * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG + */ +int +lwip_getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + err_t err; + ip_addr_t addr; + struct addrinfo *ai; + struct sockaddr_storage *sa = NULL; + int port_nr = 0; + size_t total_size; + size_t namelen = 0; + int ai_family; + + if (res == NULL) { + return EAI_FAIL; + } + *res = NULL; + if ((nodename == NULL) && (servname == NULL)) { + return EAI_NONAME; + } + + if (hints != NULL) { + ai_family = hints->ai_family; + if ((ai_family != AF_UNSPEC) +#if LWIP_IPV4 + && (ai_family != AF_INET) +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + && (ai_family != AF_INET6) +#endif /* LWIP_IPV6 */ + ) { + return EAI_FAMILY; + } + } else { + ai_family = AF_UNSPEC; + } + + if (servname != NULL) { + /* service name specified: convert to port number + * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ + port_nr = atoi(servname); + if (port_nr == 0 && (servname[0] != '0')) { + /* atoi failed - service was not numeric */ + return EAI_SERVICE; + } + if ((port_nr < 0) || (port_nr > 0xffff)) { + return EAI_SERVICE; + } + } + + if (nodename != NULL) { + /* service location specified, try to resolve */ + if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { + /* no DNS lookup, just parse for an address string */ + if (!ipaddr_aton(nodename, &addr)) { + return EAI_NONAME; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || + (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { + return EAI_NONAME; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + } else { +#if LWIP_IPV4 && LWIP_IPV6 + /* AF_UNSPEC: prefer IPv4 */ + u8_t type = NETCONN_DNS_IPV4_IPV6; + if (ai_family == AF_INET) { + type = NETCONN_DNS_IPV4; + } else if (ai_family == AF_INET6) { + type = NETCONN_DNS_IPV6; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + err = netconn_gethostbyname_addrtype(nodename, &addr, type); + if (err != ERR_OK) { + return EAI_FAIL; + } + } + } else { + /* service location specified, use loopback address */ + if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { + ip_addr_set_any_val(ai_family == AF_INET6, addr); + } else { + ip_addr_set_loopback_val(ai_family == AF_INET6, addr); + } + } + + total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); + if (nodename != NULL) { + namelen = strlen(nodename); + if (namelen > DNS_MAX_NAME_LENGTH) { + /* invalid name length */ + return EAI_FAIL; + } + LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); + total_size += namelen + 1; + } + /* If this fails, please report to lwip-devel! :-) */ + LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", + total_size <= NETDB_ELEM_SIZE); + ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); + if (ai == NULL) { + return EAI_MEMORY; + } + memset(ai, 0, total_size); + /* cast through void* to get rid of alignment warnings */ + sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo)); + if (IP_IS_V6_VAL(addr)) { +#if LWIP_IPV6 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + /* set up sockaddr */ + inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); + sa6->sin6_family = AF_INET6; + sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_port = lwip_htons((u16_t)port_nr); + sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); + ai->ai_family = AF_INET6; +#endif /* LWIP_IPV6 */ + } else { +#if LWIP_IPV4 + struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; + /* set up sockaddr */ + inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); + sa4->sin_family = AF_INET; + sa4->sin_len = sizeof(struct sockaddr_in); + sa4->sin_port = lwip_htons((u16_t)port_nr); + ai->ai_family = AF_INET; +#endif /* LWIP_IPV4 */ + } + + /* set up addrinfo */ + if (hints != NULL) { + /* copy socktype & protocol from hints if specified */ + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + } + if (nodename != NULL) { + /* copy nodename to canonname if specified */ + ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + MEMCPY(ai->ai_canonname, nodename, namelen); + ai->ai_canonname[namelen] = 0; + } + ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr *)sa; + + *res = ai; + + return 0; +} + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netifapi.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netifapi.c new file mode 100644 index 0000000..25957cd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/netifapi.c @@ -0,0 +1,380 @@ +/** + * @file + * Network Interface Sequential API module + * + * @defgroup netifapi NETIF API + * @ingroup sequential_api + * Thread-safe functions to be called from non-TCPIP threads + * + * @defgroup netifapi_netif NETIF related + * @ingroup netifapi + * To be called from non-TCPIP threads + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/etharp.h" +#include "lwip/netifapi.h" +#include "lwip/memp.h" +#include "lwip/priv/tcpip_priv.h" + +#include /* strncpy */ + +#define NETIFAPI_VAR_REF(name) API_VAR_REF(name) +#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name) +#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM) +#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name) + +/** + * Call netif_add() inside the tcpip_thread context. + */ +static err_t +netifapi_do_netif_add(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + + if (!netif_add( msg->netif, +#if LWIP_IPV4 + API_EXPR_REF(msg->msg.add.ipaddr), + API_EXPR_REF(msg->msg.add.netmask), + API_EXPR_REF(msg->msg.add.gw), +#endif /* LWIP_IPV4 */ + msg->msg.add.state, + msg->msg.add.init, + msg->msg.add.input)) { + return ERR_IF; + } else { + return ERR_OK; + } +} + +#if LWIP_IPV4 +/** + * Call netif_set_addr() inside the tcpip_thread context. + */ +static err_t +netifapi_do_netif_set_addr(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + + netif_set_addr( msg->netif, + API_EXPR_REF(msg->msg.add.ipaddr), + API_EXPR_REF(msg->msg.add.netmask), + API_EXPR_REF(msg->msg.add.gw)); + return ERR_OK; +} +#endif /* LWIP_IPV4 */ + +/** +* Call netif_name_to_index() inside the tcpip_thread context. +*/ +static err_t +netifapi_do_name_to_index(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + + msg->msg.ifs.index = netif_name_to_index(msg->msg.ifs.name); + return ERR_OK; +} + +/** +* Call netif_index_to_name() inside the tcpip_thread context. +*/ +static err_t +netifapi_do_index_to_name(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + + if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) { + /* return failure via empty name */ + msg->msg.ifs.name[0] = '\0'; + } + return ERR_OK; +} + +/** + * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the + * tcpip_thread context. + */ +static err_t +netifapi_do_netif_common(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m; + + if (msg->msg.common.errtfunc != NULL) { + return msg->msg.common.errtfunc(msg->netif); + } else { + msg->msg.common.voidfunc(msg->netif); + return ERR_OK; + } +} + +#if LWIP_ARP && LWIP_IPV4 +/** + * @ingroup netifapi_arp + * Add or update an entry in the ARP cache. + * For an update, ipaddr is used to find the cache entry. + * + * @param ipaddr IPv4 address of cache entry + * @param ethaddr hardware address mapped to ipaddr + * @param type type of ARP cache entry + * @return ERR_OK: entry added/updated, else error from err_t + */ +err_t +netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type) +{ + err_t err; + + /* We only support permanent entries currently */ + LWIP_UNUSED_ARG(type); + +#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); + err = etharp_add_static_entry(ipaddr, ethaddr); + UNLOCK_TCPIP_CORE(); +#else + /* @todo add new vars to struct netifapi_msg and create a 'do' func */ + LWIP_UNUSED_ARG(ipaddr); + LWIP_UNUSED_ARG(ethaddr); + err = ERR_VAL; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */ + + return err; +} + +/** + * @ingroup netifapi_arp + * Remove an entry in the ARP cache identified by ipaddr + * + * @param ipaddr IPv4 address of cache entry + * @param type type of ARP cache entry + * @return ERR_OK: entry removed, else error from err_t + */ +err_t +netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type) +{ + err_t err; + + /* We only support permanent entries currently */ + LWIP_UNUSED_ARG(type); + +#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); + err = etharp_remove_static_entry(ipaddr); + UNLOCK_TCPIP_CORE(); +#else + /* @todo add new vars to struct netifapi_msg and create a 'do' func */ + LWIP_UNUSED_ARG(ipaddr); + err = ERR_VAL; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */ + + return err; +} +#endif /* LWIP_ARP && LWIP_IPV4 */ + +/** + * @ingroup netifapi_netif + * Call netif_add() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_add() + */ +err_t +netifapi_netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + +#if LWIP_IPV4 + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } +#endif /* LWIP_IPV4 */ + + NETIFAPI_VAR_REF(msg).netif = netif; +#if LWIP_IPV4 + NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); + NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); + NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); +#endif /* LWIP_IPV4 */ + NETIFAPI_VAR_REF(msg).msg.add.state = state; + NETIFAPI_VAR_REF(msg).msg.add.init = init; + NETIFAPI_VAR_REF(msg).msg.add.input = input; + err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} + +#if LWIP_IPV4 +/** + * @ingroup netifapi_netif + * Call netif_set_addr() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_set_addr() + */ +err_t +netifapi_netif_set_addr(struct netif *netif, + const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } + + NETIFAPI_VAR_REF(msg).netif = netif; + NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); + NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); + NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); + err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} +#endif /* LWIP_IPV4 */ + +/** + * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe + * way by running that function inside the tcpip_thread context. + * + * @note use only for functions where there is only "netif" parameter. + */ +err_t +netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + NETIFAPI_VAR_REF(msg).netif = netif; + NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc; + NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc; + err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} + +/** +* @ingroup netifapi_netif +* Call netif_name_to_index() in a thread-safe way by running that function inside the +* tcpip_thread context. +* +* @param name the interface name of the netif +* @param idx output index of the found netif +*/ +err_t +netifapi_netif_name_to_index(const char *name, u8_t *idx) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + *idx = 0; + +#if LWIP_MPU_COMPATIBLE + strncpy(NETIFAPI_VAR_REF(msg).msg.ifs.name, name, NETIF_NAMESIZE - 1); + NETIFAPI_VAR_REF(msg).msg.ifs.name[NETIF_NAMESIZE - 1] = '\0'; +#else + NETIFAPI_VAR_REF(msg).msg.ifs.name = LWIP_CONST_CAST(char *, name); +#endif /* LWIP_MPU_COMPATIBLE */ + err = tcpip_api_call(netifapi_do_name_to_index, &API_VAR_REF(msg).call); + if (!err) { + *idx = NETIFAPI_VAR_REF(msg).msg.ifs.index; + } + NETIFAPI_VAR_FREE(msg); + return err; +} + +/** +* @ingroup netifapi_netif +* Call netif_index_to_name() in a thread-safe way by running that function inside the +* tcpip_thread context. +* +* @param idx the interface index of the netif +* @param name output name of the found netif, empty '\0' string if netif not found. +* name should be of at least NETIF_NAMESIZE bytes +*/ +err_t +netifapi_netif_index_to_name(u8_t idx, char *name) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + NETIFAPI_VAR_REF(msg).msg.ifs.index = idx; +#if !LWIP_MPU_COMPATIBLE + NETIFAPI_VAR_REF(msg).msg.ifs.name = name; +#endif /* LWIP_MPU_COMPATIBLE */ + err = tcpip_api_call(netifapi_do_index_to_name, &API_VAR_REF(msg).call); +#if LWIP_MPU_COMPATIBLE + if (!err) { + strncpy(name, NETIFAPI_VAR_REF(msg).msg.ifs.name, NETIF_NAMESIZE - 1); + name[NETIF_NAMESIZE - 1] = '\0'; + } +#endif /* LWIP_MPU_COMPATIBLE */ + NETIFAPI_VAR_FREE(msg); + return err; +} + +#endif /* LWIP_NETIF_API */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/sockets.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/sockets.c new file mode 100644 index 0000000..7852635 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/sockets.c @@ -0,0 +1,4166 @@ +/** + * @file + * Sockets BSD-Like API module + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * Improved by Marc Boucher and David Haas + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sockets.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/api.h" +#include "lwip/igmp.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/mld6.h" +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES +#include +#endif + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/* If the netconn API is not required publicly, then we include the necessary + files here to get the implementation */ +#if !LWIP_NETCONN +#undef LWIP_NETCONN +#define LWIP_NETCONN 1 +#include "api_msg.c" +#include "api_lib.c" +#include "netbuf.c" +#undef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +#define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name) +#define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name) +#define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) +#define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) + +#if LWIP_IPV4 +#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ + (sin)->sin_len = sizeof(struct sockaddr_in); \ + (sin)->sin_family = AF_INET; \ + (sin)->sin_port = lwip_htons((port)); \ + inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ + memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) +#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ + inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ + (port) = lwip_ntohs((sin)->sin_port); }while(0) +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ + (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ + (sin6)->sin6_family = AF_INET6; \ + (sin6)->sin6_port = lwip_htons((port)); \ + (sin6)->sin6_flowinfo = 0; \ + inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ + (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) +#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ + inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ + if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ + ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \ + } \ + (port) = lwip_ntohs((sin6)->sin6_port); }while(0) +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 && LWIP_IPV6 +static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port); + +#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ + ((namelen) == sizeof(struct sockaddr_in6))) +#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ + ((name)->sa_family == AF_INET6)) +#define SOCK_ADDR_TYPE_MATCH(name, sock) \ + ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ + (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ + if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ + } else { \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ + } } while(0) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) +#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ + (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ +#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) +#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) +#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ + SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) +#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ +#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) +#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) +#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ + SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) +#endif /* LWIP_IPV6 */ + +#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ + IS_SOCK_ADDR_TYPE_VALID(name)) +#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ + SOCK_ADDR_TYPE_MATCH(name, sock)) +#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) + + +#define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ + if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ + if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ + if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0) + + +#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) +#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) +#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) +#if LWIP_MPU_COMPATIBLE +#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ + name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ + if (name == NULL) { \ + sock_set_errno(sock, ENOMEM); \ + done_socket(sock); \ + return -1; \ + } }while(0) +#else /* LWIP_MPU_COMPATIBLE */ +#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) +#endif /* LWIP_MPU_COMPATIBLE */ + +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD +#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int +#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) +#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval)) +#else +#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval +#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ + u32_t loc = (val); \ + ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \ + ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0) +#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000)) +#endif + + +/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ + * sockaddr_in6 if instantiated. + */ +union sockaddr_aligned { + struct sockaddr sa; +#if LWIP_IPV6 + struct sockaddr_in6 sin6; +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + struct sockaddr_in sin; +#endif /* LWIP_IPV4 */ +}; + +/* Define the number of IPv4 multicast memberships, default is one per socket */ +#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS +#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS +#endif + +#if LWIP_IGMP +/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when + a socket is closed */ +struct lwip_socket_multicast_pair { + /** the socket */ + struct lwip_sock *sock; + /** the interface address */ + ip4_addr_t if_addr; + /** the group address */ + ip4_addr_t multi_addr; +}; + +static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; + +static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); +static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); +static void lwip_socket_drop_registered_memberships(int s); +#endif /* LWIP_IGMP */ + +#if LWIP_IPV6_MLD +/* This is to keep track of IP_JOIN_GROUP calls to drop the membership when + a socket is closed */ +struct lwip_socket_multicast_mld6_pair { + /** the socket */ + struct lwip_sock *sock; + /** the interface index */ + u8_t if_idx; + /** the group address */ + ip6_addr_t multi_addr; +}; + +static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; + +static int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); +static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); +static void lwip_socket_drop_registered_mld6_memberships(int s); +#endif /* LWIP_IPV6_MLD */ + +/** The global array of available sockets */ +static struct lwip_sock sockets[NUM_SOCKETS]; + +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +#if LWIP_TCPIP_CORE_LOCKING +/* protect the select_cb_list using core lock */ +#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) +#define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE() +#define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE() +#else /* LWIP_TCPIP_CORE_LOCKING */ +/* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */ +#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) +#define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev) +#define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) +/** This counter is increased from lwip_select when the list is changed + and checked in select_check_waiters to see if it has changed. */ +static volatile int select_cb_ctr; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +/** The global list of tasks waiting for select */ +static struct lwip_select_cb *select_cb_list; +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + +#define sock_set_errno(sk, e) do { \ + const int sockerr = (e); \ + set_errno(sockerr); \ +} while (0) + +/* Forward declaration of some functions */ +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +#define DEFAULT_SOCKET_EVENTCB event_callback +static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); +#else +#define DEFAULT_SOCKET_EVENTCB NULL +#endif +#if !LWIP_TCPIP_CORE_LOCKING +static void lwip_getsockopt_callback(void *arg); +static void lwip_setsockopt_callback(void *arg); +#endif +static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); +static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); +static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, + union lwip_sock_lastdata *lastdata); +static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata); + +#if LWIP_IPV4 && LWIP_IPV6 +static void +sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port) +{ + if ((sockaddr->sa_family) == AF_INET6) { + SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port); + ipaddr->type = IPADDR_TYPE_V6; + } else { + SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port); + ipaddr->type = IPADDR_TYPE_V4; + } +} +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void +lwip_socket_thread_init(void) +{ + netconn_thread_init(); +} + +/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ +void +lwip_socket_thread_cleanup(void) +{ + netconn_thread_cleanup(); +} + +#if LWIP_NETCONN_FULLDUPLEX +/* Thread-safe increment of sock->fd_used, with overflow check */ +static int +sock_inc_used(struct lwip_sock *sock) +{ + int ret; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_ASSERT("sock != NULL", sock != NULL); + + SYS_ARCH_PROTECT(lev); + if (sock->fd_free_pending) { + /* prevent new usage of this socket if free is pending */ + ret = 0; + } else { + ++sock->fd_used; + ret = 1; + LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); + } + SYS_ARCH_UNPROTECT(lev); + return ret; +} + +/* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */ +static int +sock_inc_used_locked(struct lwip_sock *sock) +{ + LWIP_ASSERT("sock != NULL", sock != NULL); + + if (sock->fd_free_pending) { + LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); + return 0; + } + + ++sock->fd_used; + LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); + return 1; +} + +/* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being + * released (and possibly reused) when used from more than one thread + * (e.g. read-while-write or close-while-write, etc) + * This function is called at the end of functions using (try)get_socket*(). + */ +static void +done_socket(struct lwip_sock *sock) +{ + int freed = 0; + int is_tcp = 0; + struct netconn *conn = NULL; + union lwip_sock_lastdata lastdata; + SYS_ARCH_DECL_PROTECT(lev); + LWIP_ASSERT("sock != NULL", sock != NULL); + + SYS_ARCH_PROTECT(lev); + LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); + if (--sock->fd_used == 0) { + if (sock->fd_free_pending) { + /* free the socket */ + sock->fd_used = 1; + is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP; + freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); + } + } + SYS_ARCH_UNPROTECT(lev); + + if (freed) { + free_socket_free_elements(is_tcp, conn, &lastdata); + } +} + +#else /* LWIP_NETCONN_FULLDUPLEX */ +#define sock_inc_used(sock) 1 +#define sock_inc_used_locked(sock) 1 +#define done_socket(sock) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ +static struct lwip_sock * +tryget_socket_unconn_nouse(int fd) +{ + int s = fd - LWIP_SOCKET_OFFSET; + if ((s < 0) || (s >= NUM_SOCKETS)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); + return NULL; + } + return &sockets[s]; +} + +struct lwip_sock * +lwip_socket_dbg_get_socket(int fd) +{ + return tryget_socket_unconn_nouse(fd); +} + +/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ +static struct lwip_sock * +tryget_socket_unconn(int fd) +{ + struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); + if (ret != NULL) { + if (!sock_inc_used(ret)) { + return NULL; + } + } + return ret; +} + +/* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */ +static struct lwip_sock * +tryget_socket_unconn_locked(int fd) +{ + struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); + if (ret != NULL) { + if (!sock_inc_used_locked(ret)) { + return NULL; + } + } + return ret; +} + +/** + * Same as get_socket but doesn't set errno + * + * @param fd externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +tryget_socket(int fd) +{ + struct lwip_sock *sock = tryget_socket_unconn(fd); + if (sock != NULL) { + if (sock->conn) { + return sock; + } + done_socket(sock); + } + return NULL; +} + +/** + * Map a externally used socket index to the internal socket representation. + * + * @param fd externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +get_socket(int fd) +{ + struct lwip_sock *sock = tryget_socket(fd); + if (!sock) { + if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); + } + set_errno(EBADF); + return NULL; + } + return sock; +} + +/** + * Allocate a new socket for a given netconn. + * + * @param newconn the netconn for which to allocate a socket + * @param accepted 1 if socket has been created by accept(), + * 0 if socket has been created by socket() + * @return the index of the new socket; -1 on error + */ +static int +alloc_socket(struct netconn *newconn, int accepted) +{ + int i; + SYS_ARCH_DECL_PROTECT(lev); + LWIP_UNUSED_ARG(accepted); + + /* allocate a new socket identifier */ + for (i = 0; i < NUM_SOCKETS; ++i) { + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + if (!sockets[i].conn) { +#if LWIP_NETCONN_FULLDUPLEX + if (sockets[i].fd_used) { + SYS_ARCH_UNPROTECT(lev); + continue; + } + sockets[i].fd_used = 1; + sockets[i].fd_free_pending = 0; +#endif + sockets[i].conn = newconn; + /* The socket is not yet known to anyone, so no need to protect + after having marked it as used. */ + SYS_ARCH_UNPROTECT(lev); + sockets[i].lastdata.pbuf = NULL; +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0); + sockets[i].rcvevent = 0; + /* TCP sendbuf is empty, but the socket is not yet writable until connected + * (unless it has been created by accept()). */ + sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); + sockets[i].errevent = 0; +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + return i + LWIP_SOCKET_OFFSET; + } + SYS_ARCH_UNPROTECT(lev); + } + return -1; +} + +/** Free a socket (under lock) + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + * @param conn the socekt's netconn is stored here, must be freed externally + * @param lastdata lastdata is stored here, must be freed externally + */ +static int +free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, + union lwip_sock_lastdata *lastdata) +{ +#if LWIP_NETCONN_FULLDUPLEX + LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); + sock->fd_used--; + if (sock->fd_used > 0) { + sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0); + return 0; + } +#else /* LWIP_NETCONN_FULLDUPLEX */ + LWIP_UNUSED_ARG(is_tcp); +#endif /* LWIP_NETCONN_FULLDUPLEX */ + + *lastdata = sock->lastdata; + sock->lastdata.pbuf = NULL; + *conn = sock->conn; + sock->conn = NULL; + return 1; +} + +/** Free a socket's leftover members. + */ +static void +free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata) +{ + if (lastdata->pbuf != NULL) { + if (is_tcp) { + pbuf_free(lastdata->pbuf); + } else { + netbuf_delete(lastdata->netbuf); + } + } + if (conn != NULL) { + /* netconn_prepare_delete() has already been called, here we only free the conn */ + netconn_delete(conn); + } +} + +/** Free a socket. The socket's netconn must have been + * delete before! + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + */ +static void +free_socket(struct lwip_sock *sock, int is_tcp) +{ + int freed; + struct netconn *conn; + union lwip_sock_lastdata lastdata; + SYS_ARCH_DECL_PROTECT(lev); + + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + + freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); + SYS_ARCH_UNPROTECT(lev); + /* don't use 'sock' after this line, as another task might have allocated it */ + + if (freed) { + free_socket_free_elements(is_tcp, conn, &lastdata); + } +} + +/* Below this, the well-known socket functions are implemented. + * Use google.com or opengroup.org to get a good description :-) + * + * Exceptions are documented! + */ + +int +lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + struct lwip_sock *sock, *nsock; + struct netconn *newconn; + ip_addr_t naddr; + u16_t port = 0; + int newsock; + err_t err; + int recvevent; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + } else if (err == ERR_CLSD) { + sock_set_errno(sock, EINVAL); + } else { + sock_set_errno(sock, err_to_errno(err)); + } + done_socket(sock); + return -1; + } + LWIP_ASSERT("newconn != NULL", newconn != NULL); + + newsock = alloc_socket(newconn, 1); + if (newsock == -1) { + netconn_delete(newconn); + sock_set_errno(sock, ENFILE); + done_socket(sock); + return -1; + } + LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); + nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; + + /* See event_callback: If data comes in right away after an accept, even + * though the server task might not have created a new socket yet. + * In that case, newconn->socket is counted down (newconn->socket--), + * so nsock->rcvevent is >= 1 here! + */ + SYS_ARCH_PROTECT(lev); + recvevent = (s16_t)(-1 - newconn->socket); + newconn->socket = newsock; + SYS_ARCH_UNPROTECT(lev); + + if (newconn->callback) { + LOCK_TCPIP_CORE(); + while (recvevent > 0) { + recvevent--; + newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); + } + UNLOCK_TCPIP_CORE(); + } + + /* Note that POSIX only requires us to check addr is non-NULL. addrlen must + * not be NULL if addr is valid. + */ + if ((addr != NULL) && (addrlen != NULL)) { + union sockaddr_aligned tempaddr; + /* get the IP address and port of the remote host */ + err = netconn_peer(newconn, &naddr, &port); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); + free_socket(nsock, 1); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + + IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); + if (*addrlen > tempaddr.sa.sa_len) { + *addrlen = tempaddr.sa.sa_len; + } + MEMCPY(addr, &tempaddr, *addrlen); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); + ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); + } else { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); + } + + sock_set_errno(sock, 0); + done_socket(sock); + done_socket(nsock); + return newsock; +} + +int +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + ip_addr_t local_addr; + u16_t local_port; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + done_socket(sock); + return -1; + } + + /* check size, family and alignment of 'name' */ + LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + LWIP_UNUSED_ARG(namelen); + + SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); + IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + err = netconn_bind(sock->conn, &local_addr, local_port); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + done_socket(sock); + return 0; +} + +int +lwip_close(int s) +{ + struct lwip_sock *sock; + int is_tcp = 0; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; + } else { + LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL); + } + +#if LWIP_IGMP + /* drop all possibly joined IGMP memberships */ + lwip_socket_drop_registered_memberships(s); +#endif /* LWIP_IGMP */ +#if LWIP_IPV6_MLD + /* drop all possibly joined MLD6 memberships */ + lwip_socket_drop_registered_mld6_memberships(s); +#endif /* LWIP_IPV6_MLD */ + + err = netconn_prepare_delete(sock->conn); + if (err != ERR_OK) { + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + + free_socket(sock, is_tcp); + set_errno(0); + return 0; +} + +int +lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + done_socket(sock); + return -1; + } + + LWIP_UNUSED_ARG(namelen); + if (name->sa_family == AF_UNSPEC) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); + err = netconn_disconnect(sock->conn); + } else { + ip_addr_t remote_addr; + u16_t remote_port; + + /* check size, family and alignment of 'name' */ + LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + + SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); + IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + err = netconn_connect(sock->conn, &remote_addr, remote_port); + } + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + done_socket(sock); + return 0; +} + +/** + * Set a socket into listen mode. + * The socket may not have been used for another connection previously. + * + * @param s the socket to set to listening mode + * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) + * @return 0 on success, non-zero on failure + */ +int +lwip_listen(int s, int backlog) +{ + struct lwip_sock *sock; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* limit the "backlog" parameter to fit in an u8_t */ + backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); + + err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + } else { + sock_set_errno(sock, err_to_errno(err)); + } + done_socket(sock); + return -1; + } + + sock_set_errno(sock, 0); + done_socket(sock); + return 0; +} + +#if LWIP_TCP +/* Helper function to loop over receiving pbufs from netconn + * until "len" bytes are received or we're otherwise done. + * Keeps sock->lastdata for peeking or partly copying. + */ +static ssize_t +lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) +{ + u8_t apiflags = NETCONN_NOAUTORCVD; + ssize_t recvd = 0; + ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; + + LWIP_ASSERT("no socket given", sock != NULL); + LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); + + if (flags & MSG_DONTWAIT) { + apiflags |= NETCONN_DONTBLOCK; + } + + do { + struct pbuf *p; + err_t err; + u16_t copylen; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf)); + /* Check if there is data left from the last recv operation. */ + if (sock->lastdata.pbuf) { + p = sock->lastdata.pbuf; + } else { + /* No data was left from the previous operation, so we try to get + some from the network. */ + err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n", + err, (void *)p)); + + if (err != ERR_OK) { + if (recvd > 0) { + /* already received data, return that (this trusts in getting the same error from + netconn layer again next time netconn_recv is called) */ + goto lwip_recv_tcp_done; + } + /* We should really do some error checking here. */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", + lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + if (err == ERR_CLSD) { + return 0; + } else { + return -1; + } + } + LWIP_ASSERT("p != NULL", p != NULL); + sock->lastdata.pbuf = p; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n", + p->tot_len, (int)recv_left, (int)recvd)); + + if (recv_left > p->tot_len) { + copylen = p->tot_len; + } else { + copylen = (u16_t)recv_left; + } + if (recvd + copylen < recvd) { + /* overflow */ + copylen = (u16_t)(SSIZE_MAX - recvd); + } + + /* copy the contents of the received buffer into + the supplied memory pointer mem */ + pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0); + + recvd += copylen; + + /* TCP combines multiple pbufs for one recv */ + LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen); + recv_left -= copylen; + + /* Unless we peek the incoming message... */ + if ((flags & MSG_PEEK) == 0) { + /* ... check if there is data left in the pbuf */ + LWIP_ASSERT("invalid copylen", p->tot_len >= copylen); + if (p->tot_len - copylen > 0) { + /* If so, it should be saved in the sock structure for the next recv call. + We store the pbuf but hide/free the consumed data: */ + sock->lastdata.pbuf = pbuf_free_header(p, copylen); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf)); + } else { + sock->lastdata.pbuf = NULL; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p)); + pbuf_free(p); + } + } + /* once we have some data to return, only add more if we don't need to wait */ + apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; + /* @todo: do we need to support peeking more than one pbuf? */ + } while ((recv_left > 0) && !(flags & MSG_PEEK)); +lwip_recv_tcp_done: + if ((recvd > 0) && !(flags & MSG_PEEK)) { + /* ensure window update after copying all data */ + netconn_tcp_recvd(sock->conn, (size_t)recvd); + } + sock_set_errno(sock, 0); + return recvd; +} +#endif + +/* Convert a netbuf's address data to struct sockaddr */ +static int +lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, + struct sockaddr *from, socklen_t *fromlen) +{ + int truncated = 0; + union sockaddr_aligned saddr; + + LWIP_UNUSED_ARG(conn); + + LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL); + LWIP_ASSERT("from != NULL", from != NULL); + LWIP_ASSERT("fromlen != NULL", fromlen != NULL); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ + if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); + IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); + if (*fromlen < saddr.sa.sa_len) { + truncated = 1; + } else if (*fromlen > saddr.sa.sa_len) { + *fromlen = saddr.sa.sa_len; + } + MEMCPY(from, &saddr, *fromlen); + return truncated; +} + +#if LWIP_TCP +/* Helper function to get a tcp socket's remote address info */ +static int +lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret) +{ + if (sock == NULL) { + return 0; + } + LWIP_UNUSED_ARG(dbg_fn); + LWIP_UNUSED_ARG(dbg_s); + LWIP_UNUSED_ARG(dbg_ret); + +#if !SOCKETS_DEBUG + if (from && fromlen) +#endif /* !SOCKETS_DEBUG */ + { + /* get remote addr/port from tcp_pcb */ + u16_t port; + ip_addr_t tmpaddr; + netconn_getaddr(sock->conn, &tmpaddr, &port, 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); + if (from && fromlen) { + return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); + } + } + return 0; +} +#endif + +/* Helper function to receive a netbuf from a udp or raw netconn. + * Keeps sock->lastdata for peeking. + */ +static err_t +lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s) +{ + struct netbuf *buf; + u8_t apiflags; + err_t err; + u16_t buflen, copylen, copied; + int i; + + LWIP_UNUSED_ARG(dbg_s); + LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); + + if (flags & MSG_DONTWAIT) { + apiflags = NETCONN_DONTBLOCK; + } else { + apiflags = 0; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); + /* Check if there is data left from the last recv operation. */ + buf = sock->lastdata.netbuf; + if (buf == NULL) { + /* No data was left from the previous operation, so we try to get + some from the network. */ + err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n", + err, (void *)buf)); + + if (err != ERR_OK) { + return err; + } + LWIP_ASSERT("buf != NULL", buf != NULL); + sock->lastdata.netbuf = buf; + } + buflen = buf->p->tot_len; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen)); + + copied = 0; + /* copy the pbuf payload into the iovs */ + for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) { + u16_t len_left = (u16_t)(buflen - copied); + if (msg->msg_iov[i].iov_len > len_left) { + copylen = len_left; + } else { + copylen = (u16_t)msg->msg_iov[i].iov_len; + } + + /* copy the contents of the received buffer into + the supplied memory buffer */ + pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied); + copied = (u16_t)(copied + copylen); + } + + /* Check to see from where the data was.*/ +#if !SOCKETS_DEBUG + if (msg->msg_name && msg->msg_namelen) +#endif /* !SOCKETS_DEBUG */ + { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); + if (msg->msg_name && msg->msg_namelen) { + lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), + (struct sockaddr *)msg->msg_name, &msg->msg_namelen); + } + } + + /* Initialize flag output */ + msg->msg_flags = 0; + + if (msg->msg_control) { + u8_t wrote_msg = 0; +#if LWIP_NETBUF_RECVINFO + /* Check if packet info was recorded */ + if (buf->flags & NETBUF_FLAG_DESTADDR) { + if (IP_IS_V4(&buf->toaddr)) { +#if LWIP_IPV4 + if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) { + struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ + struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr); + chdr->cmsg_level = IPPROTO_IP; + chdr->cmsg_type = IP_PKTINFO; + chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + pkti->ipi_ifindex = buf->p->if_idx; + inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf))); + msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + wrote_msg = 1; + } else { + msg->msg_flags |= MSG_CTRUNC; + } +#endif /* LWIP_IPV4 */ + } + } +#endif /* LWIP_NETBUF_RECVINFO */ + + if (!wrote_msg) { + msg->msg_controllen = 0; + } + } + + /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ + if ((flags & MSG_PEEK) == 0) { + sock->lastdata.netbuf = NULL; + netbuf_delete(buf); + } + if (datagram_len) { + *datagram_len = buflen; + } + return ERR_OK; +} + +ssize_t +lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + struct lwip_sock *sock; + ssize_t ret; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); + sock = get_socket(s); + if (!sock) { + return -1; + } +#if LWIP_TCP + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + ret = lwip_recv_tcp(sock, mem, len, flags); + lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); + done_socket(sock); + return ret; + } else +#endif + { + u16_t datagram_len = 0; + struct iovec vec; + struct msghdr msg; + err_t err; + vec.iov_base = mem; + vec.iov_len = len; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_name = from; + msg.msg_namelen = (fromlen ? *fromlen : 0); + err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", + s, lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); + if (fromlen) { + *fromlen = msg.msg_namelen; + } + } + + sock_set_errno(sock, 0); + done_socket(sock); + return ret; +} + +ssize_t +lwip_read(int s, void *mem, size_t len) +{ + return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +ssize_t +lwip_readv(int s, const struct iovec *iov, int iovcnt) +{ + struct msghdr msg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Hack: we have to cast via number to cast from 'const' pointer to non-const. + Blame the opengroup standard for this inconsistency. */ + msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); + msg.msg_iovlen = iovcnt; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + return lwip_recvmsg(s, &msg, 0); +} + +ssize_t +lwip_recv(int s, void *mem, size_t len, int flags) +{ + return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +ssize_t +lwip_recvmsg(int s, struct msghdr *message, int flags) +{ + struct lwip_sock *sock; + int i; + ssize_t buflen; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); + LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); + LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, + set_errno(EOPNOTSUPP); return -1;); + + if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { + set_errno(EMSGSIZE); + return -1; + } + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* check for valid vectors */ + buflen = 0; + for (i = 0; i < message->msg_iovlen; i++) { + if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || + ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || + ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { + sock_set_errno(sock, err_to_errno(ERR_VAL)); + done_socket(sock); + return -1; + } + buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len); + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + int recv_flags = flags; + message->msg_flags = 0; + /* recv the data */ + buflen = 0; + for (i = 0; i < message->msg_iovlen; i++) { + /* try to receive into this vector's buffer */ + ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); + if (recvd_local > 0) { + /* sum up received bytes */ + buflen += recvd_local; + } + if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) || + (flags & MSG_PEEK)) { + /* returned prematurely (or peeking, which might actually be limitated to the first iov) */ + if (buflen <= 0) { + /* nothing received at all, propagate the error */ + buflen = recvd_local; + } + break; + } + /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */ + recv_flags |= MSG_DONTWAIT; + } + if (buflen > 0) { + /* reset socket error since we have received something */ + sock_set_errno(sock, 0); + } + /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ + done_socket(sock); + return buflen; +#else /* LWIP_TCP */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_TCP */ + } + /* else, UDP and RAW NETCONNs */ +#if LWIP_UDP || LWIP_RAW + { + u16_t datagram_len = 0; + err_t err; + err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", + s, lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + if (datagram_len > buflen) { + message->msg_flags |= MSG_TRUNC; + } + + sock_set_errno(sock, 0); + done_socket(sock); + return (int)datagram_len; + } +#else /* LWIP_UDP || LWIP_RAW */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_UDP || LWIP_RAW */ +} + +ssize_t +lwip_send(int s, const void *data, size_t size, int flags) +{ + struct lwip_sock *sock; + err_t err; + u8_t write_flags; + size_t written; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", + s, data, size, flags)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) + done_socket(sock); + return lwip_sendto(s, data, size, flags, NULL, 0); +#else /* (LWIP_UDP || LWIP_RAW) */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + + write_flags = (u8_t)(NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); + written = 0; + err = netconn_write_partly(sock->conn, data, size, write_flags, &written); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ + return (err == ERR_OK ? (ssize_t)written : -1); +} + +ssize_t +lwip_sendmsg(int s, const struct msghdr *msg, int flags) +{ + struct lwip_sock *sock; +#if LWIP_TCP + u8_t write_flags; + size_t written; +#endif + err_t err = ERR_OK; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), + sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); + LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, + sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); + + LWIP_UNUSED_ARG(msg->msg_control); + LWIP_UNUSED_ARG(msg->msg_controllen); + LWIP_UNUSED_ARG(msg->msg_flags); + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + write_flags = (u8_t)(NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); + + written = 0; + err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ + return (err == ERR_OK ? (ssize_t)written : -1); +#else /* LWIP_TCP */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_TCP */ + } + /* else, UDP and RAW NETCONNs */ +#if LWIP_UDP || LWIP_RAW + { + struct netbuf chain_buf; + int i; + ssize_t size = 0; + + LWIP_UNUSED_ARG(flags); + LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || + IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + + /* initialize chain buffer with destination */ + memset(&chain_buf, 0, sizeof(struct netbuf)); + if (msg->msg_name) { + u16_t remote_port; + SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port); + netbuf_fromport(&chain_buf) = remote_port; + } +#if LWIP_NETIF_TX_SINGLE_PBUF + for (i = 0; i < msg->msg_iovlen; i++) { + size += msg->msg_iov[i].iov_len; + if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) { + /* overflow */ + goto sendmsg_emsgsize; + } + } + if (size > 0xFFFF) { + /* overflow */ + goto sendmsg_emsgsize; + } + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) { + err = ERR_MEM; + } else { + /* flatten the IO vectors */ + size_t offset = 0; + for (i = 0; i < msg->msg_iovlen; i++) { + MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); + offset += msg->msg_iov[i].iov_len; + } +#if LWIP_CHECKSUM_ON_COPY + { + /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ + u16_t chksum = ~inet_chksum_pbuf(chain_buf.p); + netbuf_set_chksum(&chain_buf, chksum); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + err = ERR_OK; + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain + manually to avoid having to allocate, chain, and delete a netbuf for each iov */ + for (i = 0; i < msg->msg_iovlen; i++) { + struct pbuf *p; + if (msg->msg_iov[i].iov_len > 0xFFFF) { + /* overflow */ + goto sendmsg_emsgsize; + } + p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + if (p == NULL) { + err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ + break; + } + p->payload = msg->msg_iov[i].iov_base; + p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; + /* netbuf empty, add new pbuf */ + if (chain_buf.p == NULL) { + chain_buf.p = chain_buf.ptr = p; + /* add pbuf to existing pbuf chain */ + } else { + if (chain_buf.p->tot_len + p->len > 0xffff) { + /* overflow */ + pbuf_free(p); + goto sendmsg_emsgsize; + } + pbuf_cat(chain_buf.p, p); + } + } + /* save size of total chain */ + if (err == ERR_OK) { + size = netbuf_len(&chain_buf); + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + if (err == ERR_OK) { +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr)); + IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* send the data */ + err = netconn_send(sock->conn, &chain_buf); + } + + /* deallocated the buffer */ + netbuf_free(&chain_buf); + + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return (err == ERR_OK ? size : -1); +sendmsg_emsgsize: + sock_set_errno(sock, EMSGSIZE); + netbuf_free(&chain_buf); + done_socket(sock); + return -1; + } +#else /* LWIP_UDP || LWIP_RAW */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_UDP || LWIP_RAW */ +} + +ssize_t +lwip_sendto(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + struct lwip_sock *sock; + err_t err; + u16_t short_size; + u16_t remote_port; + struct netbuf buf; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + done_socket(sock); + return lwip_send(s, data, size, flags); +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(flags); + sock_set_errno(sock, err_to_errno(ERR_ARG)); + done_socket(sock); + return -1; +#endif /* LWIP_TCP */ + } + + if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { + /* cannot fit into one datagram (at least for us) */ + sock_set_errno(sock, EMSGSIZE); + done_socket(sock); + return -1; + } + short_size = (u16_t)size; + LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || + (IS_SOCK_ADDR_LEN_VALID(tolen) && + ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); + LWIP_UNUSED_ARG(tolen); + + /* initialize a buffer */ + buf.p = buf.ptr = NULL; +#if LWIP_CHECKSUM_ON_COPY + buf.flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ + if (to) { + SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); + } else { + remote_port = 0; + ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); + } + netbuf_fromport(&buf) = remote_port; + + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", + s, data, short_size, flags)); + ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + + /* make the buffer point to the data that should be sent */ +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(&buf, short_size) == NULL) { + err = ERR_MEM; + } else { +#if LWIP_CHECKSUM_ON_COPY + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { + u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); + netbuf_set_chksum(&buf, chksum); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + MEMCPY(buf.p->payload, data, short_size); + } + err = ERR_OK; + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (err == ERR_OK) { +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); + IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* send the data */ + err = netconn_send(sock->conn, &buf); + } + + /* deallocated the buffer */ + netbuf_free(&buf); + + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return (err == ERR_OK ? short_size : -1); +} + +int +lwip_socket(int domain, int type, int protocol) +{ + struct netconn *conn; + int i; + + LWIP_UNUSED_ARG(domain); /* @todo: check this */ + + /* create a netconn */ + switch (type) { + case SOCK_RAW: + conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), + (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_DGRAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), + DEFAULT_SOCKET_EVENTCB); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +#if LWIP_NETBUF_RECVINFO + if (conn) { + /* netconn layer enables pktinfo by default, sockets default to off */ + conn->flags &= ~NETCONN_FLAG_PKTINFO; + } +#endif /* LWIP_NETBUF_RECVINFO */ + break; + case SOCK_STREAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", + domain, type, protocol)); + set_errno(EINVAL); + return -1; + } + + if (!conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); + set_errno(ENOBUFS); + return -1; + } + + i = alloc_socket(conn, 0); + + if (i == -1) { + netconn_delete(conn); + set_errno(ENFILE); + return -1; + } + conn->socket = i; + done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); + LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); + set_errno(0); + return i; +} + +ssize_t +lwip_write(int s, const void *data, size_t size) +{ + return lwip_send(s, data, size, 0); +} + +ssize_t +lwip_writev(int s, const struct iovec *iov, int iovcnt) +{ + struct msghdr msg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Hack: we have to cast via number to cast from 'const' pointer to non-const. + Blame the opengroup standard for this inconsistency. */ + msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); + msg.msg_iovlen = iovcnt; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + return lwip_sendmsg(s, &msg, 0); +} + +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +/* Add select_cb to select_cb_list. */ +static void +lwip_link_select_cb(struct lwip_select_cb *select_cb) +{ + LWIP_SOCKET_SELECT_DECL_PROTECT(lev); + + /* Protect the select_cb_list */ + LWIP_SOCKET_SELECT_PROTECT(lev); + + /* Put this select_cb on top of list */ + select_cb->next = select_cb_list; + if (select_cb_list != NULL) { + select_cb_list->prev = select_cb; + } + select_cb_list = select_cb; +#if !LWIP_TCPIP_CORE_LOCKING + /* Increasing this counter tells select_check_waiters that the list has changed. */ + select_cb_ctr++; +#endif + + /* Now we can safely unprotect */ + LWIP_SOCKET_SELECT_UNPROTECT(lev); +} + +/* Remove select_cb from select_cb_list. */ +static void +lwip_unlink_select_cb(struct lwip_select_cb *select_cb) +{ + LWIP_SOCKET_SELECT_DECL_PROTECT(lev); + + /* Take us off the list */ + LWIP_SOCKET_SELECT_PROTECT(lev); + if (select_cb->next != NULL) { + select_cb->next->prev = select_cb->prev; + } + if (select_cb_list == select_cb) { + LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); + select_cb_list = select_cb->next; + } else { + LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); + select_cb->prev->next = select_cb->next; + } +#if !LWIP_TCPIP_CORE_LOCKING + /* Increasing this counter tells select_check_waiters that the list has changed. */ + select_cb_ctr++; +#endif + LWIP_SOCKET_SELECT_UNPROTECT(lev); +} +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + +#if LWIP_SOCKET_SELECT +/** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have + * the sockets enabled that had events. + * + * @param maxfdp1 the highest socket index in the sets + * @param readset_in set of sockets to check for read events + * @param writeset_in set of sockets to check for write events + * @param exceptset_in set of sockets to check for error events + * @param readset_out set of sockets that had read events + * @param writeset_out set of sockets that had write events + * @param exceptset_out set os sockets that had error events + * @return number of sockets that had events (read/write/exception) (>= 0) + */ +static int +lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, + fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) +{ + int i, nready = 0; + fd_set lreadset, lwriteset, lexceptset; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + FD_ZERO(&lreadset); + FD_ZERO(&lwriteset); + FD_ZERO(&lexceptset); + + /* Go through each socket in each list to count number of sockets which + currently match */ + for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { + /* if this FD is not in the set, continue */ + if (!(readset_in && FD_ISSET(i, readset_in)) && + !(writeset_in && FD_ISSET(i, writeset_in)) && + !(exceptset_in && FD_ISSET(i, exceptset_in))) { + continue; + } + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn_locked(i); + if (sock != NULL) { + void *lastdata = sock->lastdata.pbuf; + s16_t rcvevent = sock->rcvevent; + u16_t sendevent = sock->sendevent; + u16_t errevent = sock->errevent; + SYS_ARCH_UNPROTECT(lev); + + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { + FD_SET(i, &lreadset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); + nready++; + } + /* See if netconn of this socket is ready for write */ + if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { + FD_SET(i, &lwriteset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); + nready++; + } + /* See if netconn of this socket had an error */ + if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; + } + done_socket(sock); + } else { + SYS_ARCH_UNPROTECT(lev); + /* no a valid open socket */ + return -1; + } + } + /* copy local sets to the ones provided as arguments */ + *readset_out = lreadset; + *writeset_out = lwriteset; + *exceptset_out = lexceptset; + + LWIP_ASSERT("nready >= 0", nready >= 0); + return nready; +} + +#if LWIP_NETCONN_FULLDUPLEX +/* Mark all of the set sockets in one of the three fdsets passed to select as used. + * All sockets are marked (and later unmarked), whether they are open or not. + * This is OK as lwip_selscan aborts select when non-open sockets are found. + */ +static void +lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets) +{ + SYS_ARCH_DECL_PROTECT(lev); + if (fdset) { + int i; + for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { + /* if this FD is in the set, lock it (unless already done) */ + if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) { + struct lwip_sock *sock; + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn_locked(i); + if (sock != NULL) { + /* leave the socket used until released by lwip_select_dec_sockets_used */ + FD_SET(i, used_sockets); + } + SYS_ARCH_UNPROTECT(lev); + } + } + } +} + +/* Mark all sockets passed to select as used to prevent them from being freed + * from other threads while select is running. + * Marked sockets are added to 'used_sockets' to mark them only once an be able + * to unmark them correctly. + */ +static void +lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets) +{ + FD_ZERO(used_sockets); + lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets); + lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets); + lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets); +} + +/* Let go all sockets that were marked as used when starting select */ +static void +lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets) +{ + int i; + for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { + /* if this FD is not in the set, continue */ + if (FD_ISSET(i, used_sockets)) { + struct lwip_sock *sock = tryget_socket_unconn_nouse(i); + LWIP_ASSERT("socket gone at the end of select", sock != NULL); + if (sock != NULL) { + done_socket(sock); + } + } + } +} +#else /* LWIP_NETCONN_FULLDUPLEX */ +#define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets) +#define lwip_select_dec_sockets_used(maxfdp1, used_sockets) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +int +lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout) +{ + u32_t waitres = 0; + int nready; + fd_set lreadset, lwriteset, lexceptset; + u32_t msectimeout; + int i; + int maxfdp2; +#if LWIP_NETCONN_SEM_PER_THREAD + int waited = 0; +#endif +#if LWIP_NETCONN_FULLDUPLEX + fd_set used_sockets; +#endif + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", + maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, + timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, + timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); + + if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { + set_errno(EINVAL); + return -1; + } + + lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); + + /* Go through each socket in each list to count number of sockets which + currently match */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + + if (nready < 0) { + /* one of the sockets in one of the fd_sets was invalid */ + set_errno(EBADF); + lwip_select_dec_sockets_used(maxfdp1, &used_sockets); + return -1; + } else if (nready > 0) { + /* one or more sockets are set, no need to wait */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); + } else { + /* If we don't have any current events, then suspend if we are supposed to */ + if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + } else { + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables (unless we're running in MPU compatible + mode). */ + API_SELECT_CB_VAR_DECLARE(select_cb); + API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); + memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); + + API_SELECT_CB_VAR_REF(select_cb).readset = readset; + API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; + API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; +#if LWIP_NETCONN_SEM_PER_THREAD + API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { + /* failed to create semaphore */ + set_errno(ENOMEM); + lwip_select_dec_sockets_used(maxfdp1, &used_sockets); + API_SELECT_CB_VAR_FREE(select_cb); + return -1; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + + /* Increase select_waiting for each socket we are interested in */ + maxfdp2 = maxfdp1; + for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock; + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn_locked(i); + if (sock != NULL) { + sock->select_waiting++; + if (sock->select_waiting == 0) { + /* overflow - too many threads waiting */ + sock->select_waiting--; + nready = -1; + maxfdp2 = i; + SYS_ARCH_UNPROTECT(lev); + done_socket(sock); + set_errno(EBUSY); + break; + } + SYS_ARCH_UNPROTECT(lev); + done_socket(sock); + } else { + /* Not a valid socket */ + nready = -1; + maxfdp2 = i; + SYS_ARCH_UNPROTECT(lev); + set_errno(EBADF); + break; + } + } + } + + if (nready >= 0) { + /* Call lwip_selscan again: there could have been events between + the last scan (without us on the list) and putting us on the list! */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + if (nready < 0) { + set_errno(EBADF); + } else if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout == 0) { + /* Wait forever */ + msectimeout = 0; + } else { + long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000)); + if (msecs_long <= 0) { + /* Wait 1ms at least (0 means wait forever) */ + msectimeout = 1; + } else { + msectimeout = (u32_t)msecs_long; + } + } + + waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); +#if LWIP_NETCONN_SEM_PER_THREAD + waited = 1; +#endif + } + } + + /* Decrease select_waiting for each socket we are interested in */ + for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock; + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn_nouse(i); + LWIP_ASSERT("socket gone at the end of select", sock != NULL); + if (sock != NULL) { + /* for now, handle select_waiting==0... */ + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + if (sock->select_waiting > 0) { + sock->select_waiting--; + } + SYS_ARCH_UNPROTECT(lev); + } else { + SYS_ARCH_UNPROTECT(lev); + /* Not a valid socket */ + nready = -1; + set_errno(EBADF); + } + } + } + + lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + +#if LWIP_NETCONN_SEM_PER_THREAD + if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { + /* don't leave the thread-local semaphore signalled */ + sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); + } +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + API_SELECT_CB_VAR_FREE(select_cb); + + if (nready < 0) { + /* This happens when a socket got closed while waiting */ + lwip_select_dec_sockets_used(maxfdp1, &used_sockets); + return -1; + } + + if (waitres == SYS_ARCH_TIMEOUT) { + /* Timeout */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + } else { + /* See what's set now after waiting */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); + if (nready < 0) { + set_errno(EBADF); + lwip_select_dec_sockets_used(maxfdp1, &used_sockets); + return -1; + } + } + } + } + + lwip_select_dec_sockets_used(maxfdp1, &used_sockets); + set_errno(0); + if (readset) { + *readset = lreadset; + } + if (writeset) { + *writeset = lwriteset; + } + if (exceptset) { + *exceptset = lexceptset; + } + return nready; +} +#endif /* LWIP_SOCKET_SELECT */ + +#if LWIP_SOCKET_POLL +/** Options for the lwip_pollscan function. */ +enum lwip_pollscan_opts +{ + /** Clear revents in each struct pollfd. */ + LWIP_POLLSCAN_CLEAR = 1, + + /** Increment select_waiting in each struct lwip_sock. */ + LWIP_POLLSCAN_INC_WAIT = 2, + + /** Decrement select_waiting in each struct lwip_sock. */ + LWIP_POLLSCAN_DEC_WAIT = 4 +}; + +/** + * Update revents in each struct pollfd. + * Optionally update select_waiting in struct lwip_sock. + * + * @param fds array of structures to update + * @param nfds number of structures in fds + * @param opts what to update and how + * @return number of structures that have revents != 0 + */ +static int +lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) +{ + int nready = 0; + nfds_t fdi; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { + fds[fdi].revents = 0; + } + + /* Negative fd means the caller wants us to ignore this struct. + POLLNVAL means we already detected that the fd is invalid; + if another thread has since opened a new socket with that fd, + we must not use that socket. */ + if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn_locked(fds[fdi].fd); + if (sock != NULL) { + void* lastdata = sock->lastdata.pbuf; + s16_t rcvevent = sock->rcvevent; + u16_t sendevent = sock->sendevent; + u16_t errevent = sock->errevent; + + if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { + sock->select_waiting++; + if (sock->select_waiting == 0) { + /* overflow - too many threads waiting */ + sock->select_waiting--; + nready = -1; + SYS_ARCH_UNPROTECT(lev); + done_socket(sock); + break; + } + } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { + /* for now, handle select_waiting==0... */ + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + if (sock->select_waiting > 0) { + sock->select_waiting--; + } + } + SYS_ARCH_UNPROTECT(lev); + done_socket(sock); + + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { + fds[fdi].revents |= POLLIN; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); + } + /* See if netconn of this socket is ready for write */ + if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { + fds[fdi].revents |= POLLOUT; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); + } + /* See if netconn of this socket had an error */ + if (errevent != 0) { + /* POLLERR is output only. */ + fds[fdi].revents |= POLLERR; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); + } + } else { + /* Not a valid socket */ + SYS_ARCH_UNPROTECT(lev); + /* POLLNVAL is output only. */ + fds[fdi].revents |= POLLNVAL; + return -1; + } + } + + /* Will return the number of structures that have events, + not the number of events. */ + if (fds[fdi].revents != 0) { + nready++; + } + } + + LWIP_ASSERT("nready >= 0", nready >= 0); + return nready; +} + +#if LWIP_NETCONN_FULLDUPLEX +/* Mark all sockets as used. + * + * All sockets are marked (and later unmarked), whether they are open or not. + * This is OK as lwip_pollscan aborts select when non-open sockets are found. + */ +static void +lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) +{ + nfds_t fdi; + + if(fds) { + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + /* Increase the reference counter */ + tryget_socket_unconn(fds[fdi].fd); + } + } +} + +/* Let go all sockets that were marked as used when starting poll */ +static void +lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) +{ + nfds_t fdi; + + if(fds) { + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd); + if (sock != NULL) { + done_socket(sock); + } + } + } +} +#else /* LWIP_NETCONN_FULLDUPLEX */ +#define lwip_poll_inc_sockets_used(fds, nfds) +#define lwip_poll_dec_sockets_used(fds, nfds) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +int +lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + u32_t waitres = 0; + int nready; + u32_t msectimeout; +#if LWIP_NETCONN_SEM_PER_THREAD + int waited = 0; +#endif + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", + (void*)fds, (int)nfds, timeout)); + LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)), + set_errno(EINVAL); return -1;); + + lwip_poll_inc_sockets_used(fds, nfds); + + /* Go through each struct pollfd to count number of structures + which currently match */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); + + if (nready < 0) { + lwip_poll_dec_sockets_used(fds, nfds); + return -1; + } + + /* If we don't have any current events, then suspend if we are supposed to */ + if (!nready) { + API_SELECT_CB_VAR_DECLARE(select_cb); + + if (timeout == 0) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); + goto return_success; + } + API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); + memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); + + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables. */ + + API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; + API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; +#if LWIP_NETCONN_SEM_PER_THREAD + API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { + /* failed to create semaphore */ + set_errno(EAGAIN); + lwip_poll_dec_sockets_used(fds, nfds); + API_SELECT_CB_VAR_FREE(select_cb); + return -1; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + + /* Increase select_waiting for each socket we are interested in. + Also, check for events again: there could have been events between + the last scan (without us on the list) and putting us on the list! */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); + + if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout < 0) { + /* Wait forever */ + msectimeout = 0; + } else { + /* timeout == 0 would have been handled earlier. */ + LWIP_ASSERT("timeout > 0", timeout > 0); + msectimeout = timeout; + } + waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); +#if LWIP_NETCONN_SEM_PER_THREAD + waited = 1; +#endif + } + + /* Decrease select_waiting for each socket we are interested in, + and check which events occurred while we waited. */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); + + lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + +#if LWIP_NETCONN_SEM_PER_THREAD + if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { + /* don't leave the thread-local semaphore signalled */ + sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); + } +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + API_SELECT_CB_VAR_FREE(select_cb); + + if (nready < 0) { + /* This happens when a socket got closed while waiting */ + lwip_poll_dec_sockets_used(fds, nfds); + return -1; + } + + if (waitres == SYS_ARCH_TIMEOUT) { + /* Timeout */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); + goto return_success; + } + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); +return_success: + lwip_poll_dec_sockets_used(fds, nfds); + set_errno(0); + return nready; +} + +/** + * Check whether event_callback should wake up a thread waiting in + * lwip_poll. + */ +static int +lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent) +{ + nfds_t fdi; + for (fdi = 0; fdi < scb->poll_nfds; fdi++) { + const struct pollfd *pollfd = &scb->poll_fds[fdi]; + if (pollfd->fd == fd) { + /* Do not update pollfd->revents right here; + that would be a data race because lwip_pollscan + accesses revents without protecting. */ + if (has_recvevent && (pollfd->events & POLLIN) != 0) { + return 1; + } + if (has_sendevent && (pollfd->events & POLLOUT) != 0) { + return 1; + } + if (has_errevent) { + /* POLLERR is output only. */ + return 1; + } + } + } + return 0; +} +#endif /* LWIP_SOCKET_POLL */ + +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +/** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. + * + * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function + * must have the core lock held when signaling the following events + * as they might cause select_list_cb to be checked: + * NETCONN_EVT_RCVPLUS + * NETCONN_EVT_SENDPLUS + * NETCONN_EVT_ERROR + * This requirement will be asserted in select_check_waiters() + */ +static void +event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) +{ + int s, check_waiters; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_UNUSED_ARG(len); + + /* Get socket */ + if (conn) { + s = conn->socket; + if (s < 0) { + /* Data comes in right away after an accept, even though + * the server task might not have created a new socket yet. + * Just count down (or up) if that's the case and we + * will use the data later. Note that only receive events + * can happen before the new socket is set up. */ + SYS_ARCH_PROTECT(lev); + if (conn->socket < 0) { + if (evt == NETCONN_EVT_RCVPLUS) { + /* conn->socket is -1 on initialization + lwip_accept adjusts sock->recvevent if conn->socket < -1 */ + conn->socket--; + } + SYS_ARCH_UNPROTECT(lev); + return; + } + s = conn->socket; + SYS_ARCH_UNPROTECT(lev); + } + + sock = get_socket(s); + if (!sock) { + return; + } + } else { + return; + } + + check_waiters = 1; + SYS_ARCH_PROTECT(lev); + /* Set event as required */ + switch (evt) { + case NETCONN_EVT_RCVPLUS: + sock->rcvevent++; + if (sock->rcvevent > 1) { + check_waiters = 0; + } + break; + case NETCONN_EVT_RCVMINUS: + sock->rcvevent--; + check_waiters = 0; + break; + case NETCONN_EVT_SENDPLUS: + if (sock->sendevent) { + check_waiters = 0; + } + sock->sendevent = 1; + break; + case NETCONN_EVT_SENDMINUS: + sock->sendevent = 0; + check_waiters = 0; + break; + case NETCONN_EVT_ERROR: + sock->errevent = 1; + break; + default: + LWIP_ASSERT("unknown event", 0); + break; + } + + if (sock->select_waiting && check_waiters) { + /* Save which events are active */ + int has_recvevent, has_sendevent, has_errevent; + has_recvevent = sock->rcvevent > 0; + has_sendevent = sock->sendevent != 0; + has_errevent = sock->errevent != 0; + SYS_ARCH_UNPROTECT(lev); + /* Check any select calls waiting on this socket */ + select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); + } else { + SYS_ARCH_UNPROTECT(lev); + } + done_socket(sock); +} + +/** + * Check if any select waiters are waiting on this socket and its events + * + * @note on synchronization of select_cb_list: + * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding + * the core lock. We do a single pass through the list and signal any waiters. + * Core lock should already be held when calling here!!!! + + * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration + * of the loop, thus creating a possibility where a thread could modify the + * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to + * detect this change and restart the list walk. The list is expected to be small + */ +static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) +{ + struct lwip_select_cb *scb; +#if !LWIP_TCPIP_CORE_LOCKING + int last_select_cb_ctr; + SYS_ARCH_DECL_PROTECT(lev); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + + LWIP_ASSERT_CORE_LOCKED(); + +#if !LWIP_TCPIP_CORE_LOCKING + SYS_ARCH_PROTECT(lev); +again: + /* remember the state of select_cb_list to detect changes */ + last_select_cb_ctr = select_cb_ctr; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + for (scb = select_cb_list; scb != NULL; scb = scb->next) { + if (scb->sem_signalled == 0) { + /* semaphore not signalled yet */ + int do_signal = 0; +#if LWIP_SOCKET_POLL + if (scb->poll_fds != NULL) { + do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent); + } +#endif /* LWIP_SOCKET_POLL */ +#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL + else +#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ +#if LWIP_SOCKET_SELECT + { + /* Test this select call for our socket */ + if (has_recvevent) { + if (scb->readset && FD_ISSET(s, scb->readset)) { + do_signal = 1; + } + } + if (has_sendevent) { + if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { + do_signal = 1; + } + } + if (has_errevent) { + if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { + do_signal = 1; + } + } + } +#endif /* LWIP_SOCKET_SELECT */ + if (do_signal) { + scb->sem_signalled = 1; + /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling + the semaphore, as this might lead to the select thread taking itself off the list, + invalidating the semaphore. */ + sys_sem_signal(SELECT_SEM_PTR(scb->sem)); + } + } +#if LWIP_TCPIP_CORE_LOCKING + } +#else + /* unlock interrupts with each step */ + SYS_ARCH_UNPROTECT(lev); + /* this makes sure interrupt protection time is short */ + SYS_ARCH_PROTECT(lev); + if (last_select_cb_ctr != select_cb_ctr) { + /* someone has changed select_cb_list, restart at the beginning */ + goto again; + } + /* remember the state of select_cb_list to detect changes */ + last_select_cb_ctr = select_cb_ctr; + } + SYS_ARCH_UNPROTECT(lev); +#endif +} +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + +/** + * Close one end of a full-duplex connection. + */ +int +lwip_shutdown(int s, int how) +{ + struct lwip_sock *sock; + err_t err; + u8_t shut_rx = 0, shut_tx = 0; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + done_socket(sock); + return -1; + } + } else { + sock_set_errno(sock, ENOTCONN); + done_socket(sock); + return -1; + } + + if (how == SHUT_RD) { + shut_rx = 1; + } else if (how == SHUT_WR) { + shut_tx = 1; + } else if (how == SHUT_RDWR) { + shut_rx = 1; + shut_tx = 1; + } else { + sock_set_errno(sock, EINVAL); + done_socket(sock); + return -1; + } + err = netconn_shutdown(sock->conn, shut_rx, shut_tx); + + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return (err == ERR_OK ? 0 : -1); +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ + struct lwip_sock *sock; + union sockaddr_aligned saddr; + ip_addr_t naddr; + u16_t port; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* get the IP address and port */ + err = netconn_getaddr(sock->conn, &naddr, &port, local); + if (err != ERR_OK) { + sock_set_errno(sock, err_to_errno(err)); + done_socket(sock); + return -1; + } + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ + if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && + IP_IS_V4_VAL(naddr)) { + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); + IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); + + if (*namelen > saddr.sa.sa_len) { + *namelen = saddr.sa.sa_len; + } + MEMCPY(name, &saddr, *namelen); + + sock_set_errno(sock, 0); + done_socket(sock); + return 0; +} + +int +lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 0); +} + +int +lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 1); +} + +int +lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + int err; + struct lwip_sock *sock = get_socket(s); +#if !LWIP_TCPIP_CORE_LOCKING + err_t cberr; + LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + + if (!sock) { + return -1; + } + + if ((NULL == optval) || (NULL == optlen)) { + sock_set_errno(sock, EFAULT); + done_socket(sock); + return -1; + } + +#if LWIP_TCPIP_CORE_LOCKING + /* core-locking can just call the -impl function */ + LOCK_TCPIP_CORE(); + err = lwip_getsockopt_impl(s, level, optname, optval, optlen); + UNLOCK_TCPIP_CORE(); + +#else /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_MPU_COMPATIBLE + /* MPU_COMPATIBLE copies the optval data, so check for max size here */ + if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { + sock_set_errno(sock, ENOBUFS); + done_socket(sock); + return -1; + } +#endif /* LWIP_MPU_COMPATIBLE */ + + LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; +#if !LWIP_MPU_COMPATIBLE + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; +#endif /* !LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; +#if LWIP_NETCONN_SEM_PER_THREAD + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; +#endif + cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); + if (cberr != ERR_OK) { + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); + sock_set_errno(sock, err_to_errno(cberr)); + done_socket(sock); + return -1; + } + sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); + + /* write back optlen and optval */ + *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; +#if LWIP_MPU_COMPATIBLE + MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); +#endif /* LWIP_MPU_COMPATIBLE */ + + /* maybe lwip_getsockopt_internal has changed err */ + err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sock_set_errno(sock, err); + done_socket(sock); + return err ? -1 : 0; +} + +#if !LWIP_TCPIP_CORE_LOCKING +/** lwip_getsockopt_callback: only used without CORE_LOCKING + * to get into the tcpip_thread + */ +static void +lwip_getsockopt_callback(void *arg) +{ + struct lwip_setgetsockopt_data *data; + LWIP_ASSERT("arg != NULL", arg != NULL); + data = (struct lwip_setgetsockopt_data *)arg; + + data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, +#if LWIP_MPU_COMPATIBLE + data->optval, +#else /* LWIP_MPU_COMPATIBLE */ + data->optval.p, +#endif /* LWIP_MPU_COMPATIBLE */ + &data->optlen); + + sys_sem_signal((sys_sem_t *)(data->completed_sem)); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +static int +lwip_sockopt_to_ipopt(int optname) +{ + /* Map SO_* values to our internal SOF_* values + * We should not rely on #defines in socket.h + * being in sync with ip.h. + */ + switch (optname) { + case SO_BROADCAST: + return SOF_BROADCAST; + case SO_KEEPALIVE: + return SOF_KEEPALIVE; + case SO_REUSEADDR: + return SOF_REUSEADDR; + default: + LWIP_ASSERT("Unknown socket option", 0); + return 0; + } +} + +/** lwip_getsockopt_impl: the actual implementation of getsockopt: + * same argument as lwip_getsockopt, either called directly or through callback + */ +static int +lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + int err = 0; + struct lwip_sock *sock = tryget_socket(s); + if (!sock) { + return EBADF; + } + +#ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT + if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { + return err; + } +#endif + + switch (level) { + + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + +#if LWIP_TCP + case SO_ACCEPTCONN: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { + done_socket(sock); + return ENOPROTOOPT; + } + if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { + *(int *)optval = 1; + } else { + *(int *)optval = 0; + } + break; +#endif /* LWIP_TCP */ + + /* The option flags */ + case SO_BROADCAST: + case SO_KEEPALIVE: +#if SO_REUSE + case SO_REUSEADDR: +#endif /* SO_REUSE */ + if ((optname == SO_BROADCAST) && + (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { + done_socket(sock); + return ENOPROTOOPT; + } + + optname = lwip_sockopt_to_ipopt(optname); + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", + s, optname, (*(int *)optval ? "on" : "off"))); + break; + + case SO_TYPE: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { + case NETCONN_RAW: + *(int *)optval = SOCK_RAW; + break; + case NETCONN_TCP: + *(int *)optval = SOCK_STREAM; + break; + case NETCONN_UDP: + *(int *)optval = SOCK_DGRAM; + break; + default: /* unrecognized socket type */ + *(int *)optval = netconn_type(sock->conn); + LWIP_DEBUGF(SOCKETS_DEBUG, + ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", + s, *(int *)optval)); + } /* switch (netconn_type(sock->conn)) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", + s, *(int *)optval)); + break; + + case SO_ERROR: + LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int); + *(int *)optval = err_to_errno(netconn_err(sock->conn)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); + break; +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); + break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + *(int *)optval = netconn_get_recvbufsize(sock->conn); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + case SO_LINGER: { + s16_t conn_linger; + struct linger *linger = (struct linger *)optval; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); + conn_linger = sock->conn->linger; + if (conn_linger >= 0) { + linger->l_onoff = 1; + linger->l_linger = (int)conn_linger; + } else { + linger->l_onoff = 0; + linger->l_linger = 0; + } + } + break; +#endif /* LWIP_SO_LINGER */ +#if LWIP_UDP + case SO_NO_CHECK: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); +#if LWIP_UDPLITE + if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { + /* this flag is only available for UDP, not for UDP lite */ + done_socket(sock); + return EAFNOSUPPORT; + } +#endif /* LWIP_UDPLITE */ + *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0; + break; +#endif /* LWIP_UDP*/ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int *)optval = sock->conn->pcb.ip->ttl; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_TOS: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int *)optval = sock->conn->pcb.ip->tos; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", + s, *(int *)optval)); + break; +#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP + case IP_MULTICAST_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + done_socket(sock); + return ENOPROTOOPT; + } + *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_MULTICAST_IF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + done_socket(sock); + return ENOPROTOOPT; + } + inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", + s, *(u32_t *)optval)); + break; + case IP_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t *)optval = 1; + } else { + *(u8_t *)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + /* Special case: all IPPROTO_TCP option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); + if (sock->conn->pcb.tcp->state == LISTEN) { + done_socket(sock); + return EINVAL; + } + switch (optname) { + case TCP_NODELAY: + *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", + s, (*(int *)optval) ? "on" : "off") ); + break; + case TCP_KEEPALIVE: + *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPINTVL: + *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPCNT: + *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ + +#if LWIP_IPV6 + /* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", + s, *(int *)optval)); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + /* Special case: all IPPROTO_UDPLITE option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + /* If this is no UDP lite socket, ignore any options. */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { + done_socket(sock); + return ENOPROTOOPT; + } + switch (optname) { + case UDPLITE_SEND_CSCOV: + *(int *)optval = sock->conn->pcb.udp->chksum_len_tx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", + s, (*(int *)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + *(int *)optval = sock->conn->pcb.udp->chksum_len_rx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", + s, (*(int *)optval)) ); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + /* Level: IPPROTO_RAW */ + case IPPROTO_RAW: + switch (optname) { +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); + if (sock->conn->pcb.raw->chksum_reqd == 0) { + *(int *)optval = -1; + } else { + *(int *)optval = sock->conn->pcb.raw->chksum_offset; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", + s, (*(int *)optval)) ); + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + break; + } /* switch (level) */ + + done_socket(sock); + return err; +} + +int +lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + int err = 0; + struct lwip_sock *sock = get_socket(s); +#if !LWIP_TCPIP_CORE_LOCKING + err_t cberr; + LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + + if (!sock) { + return -1; + } + + if (NULL == optval) { + sock_set_errno(sock, EFAULT); + done_socket(sock); + return -1; + } + +#if LWIP_TCPIP_CORE_LOCKING + /* core-locking can just call the -impl function */ + LOCK_TCPIP_CORE(); + err = lwip_setsockopt_impl(s, level, optname, optval, optlen); + UNLOCK_TCPIP_CORE(); + +#else /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_MPU_COMPATIBLE + /* MPU_COMPATIBLE copies the optval data, so check for max size here */ + if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { + sock_set_errno(sock, ENOBUFS); + done_socket(sock); + return -1; + } +#endif /* LWIP_MPU_COMPATIBLE */ + + LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; +#if LWIP_MPU_COMPATIBLE + MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); +#else /* LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval; +#endif /* LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; +#if LWIP_NETCONN_SEM_PER_THREAD + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; +#endif + cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); + if (cberr != ERR_OK) { + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); + sock_set_errno(sock, err_to_errno(cberr)); + done_socket(sock); + return -1; + } + sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); + + /* maybe lwip_getsockopt_internal has changed err */ + err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sock_set_errno(sock, err); + done_socket(sock); + return err ? -1 : 0; +} + +#if !LWIP_TCPIP_CORE_LOCKING +/** lwip_setsockopt_callback: only used without CORE_LOCKING + * to get into the tcpip_thread + */ +static void +lwip_setsockopt_callback(void *arg) +{ + struct lwip_setgetsockopt_data *data; + LWIP_ASSERT("arg != NULL", arg != NULL); + data = (struct lwip_setgetsockopt_data *)arg; + + data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, +#if LWIP_MPU_COMPATIBLE + data->optval, +#else /* LWIP_MPU_COMPATIBLE */ + data->optval.pc, +#endif /* LWIP_MPU_COMPATIBLE */ + data->optlen); + + sys_sem_signal((sys_sem_t *)(data->completed_sem)); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** lwip_setsockopt_impl: the actual implementation of setsockopt: + * same argument as lwip_setsockopt, either called directly or through callback + */ +static int +lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + int err = 0; + struct lwip_sock *sock = tryget_socket(s); + if (!sock) { + return EBADF; + } + +#ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT + if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { + return err; + } +#endif + + switch (level) { + + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + /* SO_ACCEPTCONN is get-only */ + + /* The option flags */ + case SO_BROADCAST: + case SO_KEEPALIVE: +#if SO_REUSE + case SO_REUSEADDR: +#endif /* SO_REUSE */ + if ((optname == SO_BROADCAST) && + (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { + done_socket(sock); + return ENOPROTOOPT; + } + + optname = lwip_sockopt_to_ipopt(optname); + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + if (*(const int *)optval) { + ip_set_option(sock->conn->pcb.ip, optname); + } else { + ip_reset_option(sock->conn->pcb.ip, optname); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", + s, optname, (*(const int *)optval ? "on" : "off"))); + break; + + /* SO_TYPE is get-only */ + /* SO_ERROR is get-only */ + +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: { + long ms_long; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); + if (ms_long < 0) { + done_socket(sock); + return EINVAL; + } + netconn_set_sendtimeout(sock->conn, ms_long); + break; + } +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: { + long ms_long; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); + if (ms_long < 0) { + done_socket(sock); + return EINVAL; + } + netconn_set_recvtimeout(sock->conn, (u32_t)ms_long); + break; + } +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); + netconn_set_recvbufsize(sock->conn, *(const int *)optval); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + case SO_LINGER: { + const struct linger *linger = (const struct linger *)optval; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); + if (linger->l_onoff) { + int lingersec = linger->l_linger; + if (lingersec < 0) { + done_socket(sock); + return EINVAL; + } + if (lingersec > 0xFFFF) { + lingersec = 0xFFFF; + } + sock->conn->linger = (s16_t)lingersec; + } else { + sock->conn->linger = -1; + } + } + break; +#endif /* LWIP_SO_LINGER */ +#if LWIP_UDP + case SO_NO_CHECK: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); +#if LWIP_UDPLITE + if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { + /* this flag is only available for UDP, not for UDP lite */ + done_socket(sock); + return EAFNOSUPPORT; + } +#endif /* LWIP_UDPLITE */ + if (*(const int *)optval) { + udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } else { + udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + break; +#endif /* LWIP_UDP */ + case SO_BINDTODEVICE: { + const struct ifreq *iface; + struct netif *n = NULL; + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq); + + iface = (const struct ifreq *)optval; + if (iface->ifr_name[0] != 0) { + n = netif_find(iface->ifr_name); + if (n == NULL) { + done_socket(sock); + return ENODEV; + } + } + + switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { +#if LWIP_TCP + case NETCONN_TCP: + tcp_bind_netif(sock->conn->pcb.tcp, n); + break; +#endif +#if LWIP_UDP + case NETCONN_UDP: + udp_bind_netif(sock->conn->pcb.udp, n); + break; +#endif +#if LWIP_RAW + case NETCONN_RAW: + raw_bind_netif(sock->conn->pcb.raw, n); + break; +#endif + default: + LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0); + break; + } + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", + s, sock->conn->pcb.ip->ttl)); + break; + case IP_TOS: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", + s, sock->conn->pcb.ip->tos)); + break; +#if LWIP_NETBUF_RECVINFO + case IP_PKTINFO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); + if (*(const int *)optval) { + sock->conn->flags |= NETCONN_FLAG_PKTINFO; + } else { + sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; + } + break; +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP + case IP_MULTICAST_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval)); + break; + case IP_MULTICAST_IF: { + ip4_addr_t if_addr; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); + inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval); + udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); + } + break; + case IP_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + if (*(const u8_t *)optval) { + udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); + } + break; +#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ +#if LWIP_IGMP + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: { + /* If this is a TCP or a RAW socket, ignore these options. */ + err_t igmp_err; + const struct ip_mreq *imr = (const struct ip_mreq *)optval; + ip4_addr_t if_addr; + ip4_addr_t multi_addr; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); + inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); + inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); + if (optname == IP_ADD_MEMBERSHIP) { + if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + igmp_err = ERR_OK; + } else { + igmp_err = igmp_joingroup(&if_addr, &multi_addr); + } + } else { + igmp_err = igmp_leavegroup(&if_addr, &multi_addr); + lwip_socket_unregister_membership(s, &if_addr, &multi_addr); + } + if (igmp_err != ERR_OK) { + err = EADDRNOTAVAIL; + } + } + break; +#endif /* LWIP_IGMP */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + /* Special case: all IPPROTO_TCP option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); + if (sock->conn->pcb.tcp->state == LISTEN) { + done_socket(sock); + return EINVAL; + } + switch (optname) { + case TCP_NODELAY: + if (*(const int *)optval) { + tcp_nagle_disable(sock->conn->pcb.tcp); + } else { + tcp_nagle_enable(sock->conn->pcb.tcp); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", + s, (*(const int *)optval) ? "on" : "off") ); + break; + case TCP_KEEPALIVE: + sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + case TCP_KEEPINTVL: + sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_intvl)); + break; + case TCP_KEEPCNT: + sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_cnt)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP*/ + +#if LWIP_IPV6 + /* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + if (*(const int *)optval) { + netconn_set_ipv6only(sock->conn, 1); + } else { + netconn_set_ipv6only(sock->conn, 0); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", + s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); + break; +#if LWIP_IPV6_MLD + case IPV6_JOIN_GROUP: + case IPV6_LEAVE_GROUP: { + /* If this is a TCP or a RAW socket, ignore these options. */ + err_t mld6_err; + struct netif *netif; + ip6_addr_t multi_addr; + const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); + inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); + LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); + netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); + if (netif == NULL) { + err = EADDRNOTAVAIL; + break; + } + + if (optname == IPV6_JOIN_GROUP) { + if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + mld6_err = ERR_OK; + } else { + mld6_err = mld6_joingroup_netif(netif, &multi_addr); + } + } else { + mld6_err = mld6_leavegroup_netif(netif, &multi_addr); + lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr); + } + if (mld6_err != ERR_OK) { + err = EADDRNOTAVAIL; + } + } + break; +#endif /* LWIP_IPV6_MLD */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + /* Special case: all IPPROTO_UDPLITE option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + /* If this is no UDP lite socket, ignore any options. */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { + done_socket(sock); + return ENOPROTOOPT; + } + switch (optname) { + case UDPLITE_SEND_CSCOV: + if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_tx = 8; + } else { + sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", + s, (*(const int *)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_rx = 8; + } else { + sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", + s, (*(const int *)optval)) ); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + /* Level: IPPROTO_RAW */ + case IPPROTO_RAW: + switch (optname) { +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + /* It should not be possible to disable the checksum generation with ICMPv6 + * as per RFC 3542 chapter 3.1 */ + if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { + done_socket(sock); + return EINVAL; + } + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); + if (*(const int *)optval < 0) { + sock->conn->pcb.raw->chksum_reqd = 0; + } else if (*(const int *)optval & 1) { + /* Per RFC3542, odd offsets are not allowed */ + done_socket(sock); + return EINVAL; + } else { + sock->conn->pcb.raw->chksum_reqd = 1; + sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", + s, sock->conn->pcb.raw->chksum_reqd)); + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + break; + } /* switch (level) */ + + done_socket(sock); + return err; +} + +int +lwip_ioctl(int s, long cmd, void *argp) +{ + struct lwip_sock *sock = get_socket(s); + u8_t val; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + if (!sock) { + return -1; + } + + switch (cmd) { +#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE + case FIONREAD: + if (!argp) { + sock_set_errno(sock, EINVAL); + done_socket(sock); + return -1; + } +#if LWIP_FIONREAD_LINUXMODE + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + struct netbuf *nb; + if (sock->lastdata.netbuf) { + nb = sock->lastdata.netbuf; + *((int *)argp) = nb->p->tot_len; + } else { + struct netbuf *rxbuf; + err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); + if (err != ERR_OK) { + *((int *)argp) = 0; + } else { + sock->lastdata.netbuf = rxbuf; + *((int *)argp) = rxbuf->p->tot_len; + } + } + done_socket(sock); + return 0; + } +#endif /* LWIP_FIONREAD_LINUXMODE */ + +#if LWIP_SO_RCVBUF + /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ + SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); + if (recv_avail < 0) { + recv_avail = 0; + } + + /* Check if there is data left from the last recv operation. /maq 041215 */ + if (sock->lastdata.netbuf) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + recv_avail += sock->lastdata.pbuf->tot_len; + } else { + recv_avail += sock->lastdata.netbuf->p->tot_len; + } + } + *((int *)argp) = recv_avail; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); + sock_set_errno(sock, 0); + done_socket(sock); + return 0; +#else /* LWIP_SO_RCVBUF */ + break; +#endif /* LWIP_SO_RCVBUF */ +#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ + + case (long)FIONBIO: + val = 0; + if (argp && *(int *)argp) { + val = 1; + } + netconn_set_nonblocking(sock->conn, val); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); + sock_set_errno(sock, 0); + done_socket(sock); + return 0; + + default: + break; + } /* switch (cmd) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + done_socket(sock); + return -1; +} + +/** A minimal implementation of fcntl. + * Currently only the commands F_GETFL and F_SETFL are implemented. + * The flag O_NONBLOCK and access modes are supported for F_GETFL, only + * the flag O_NONBLOCK is implemented for F_SETFL. + */ +int +lwip_fcntl(int s, int cmd, int val) +{ + struct lwip_sock *sock = get_socket(s); + int ret = -1; + int op_mode = 0; + + if (!sock) { + return -1; + } + + switch (cmd) { + case F_GETFL: + ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; + sock_set_errno(sock, 0); + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); +#else + SYS_ARCH_DECL_PROTECT(lev); + /* the proper thing to do here would be to get into the tcpip_thread, + but locking should be OK as well since we only *read* some flags */ + SYS_ARCH_PROTECT(lev); +#endif +#if LWIP_TCP + if (sock->conn->pcb.tcp) { + if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { + op_mode |= O_RDONLY; + } + if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { + op_mode |= O_WRONLY; + } + } +#endif +#if LWIP_TCPIP_CORE_LOCKING + UNLOCK_TCPIP_CORE(); +#else + SYS_ARCH_UNPROTECT(lev); +#endif + } else { + op_mode |= O_RDWR; + } + + /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ + ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; + + break; + case F_SETFL: + /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ + val &= ~(O_RDONLY | O_WRONLY | O_RDWR); + if ((val & ~O_NONBLOCK) == 0) { + /* only O_NONBLOCK, all other bits are zero */ + netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); + ret = 0; + sock_set_errno(sock, 0); + } else { + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + break; + } + done_socket(sock); + return ret; +} + +#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES +int +fcntl(int s, int cmd, ...) +{ + va_list ap; + int val; + + va_start(ap, cmd); + val = va_arg(ap, int); + va_end(ap); + return lwip_fcntl(s, cmd, val); +} +#endif + +const char * +lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ + const char *ret = NULL; + int size_int = (int)size; + if (size_int < 0) { + set_errno(ENOSPC); + return NULL; + } + switch (af) { +#if LWIP_IPV4 + case AF_INET: + ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); + if (ret == NULL) { + set_errno(ENOSPC); + } + break; +#endif +#if LWIP_IPV6 + case AF_INET6: + ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); + if (ret == NULL) { + set_errno(ENOSPC); + } + break; +#endif + default: + set_errno(EAFNOSUPPORT); + break; + } + return ret; +} + +int +lwip_inet_pton(int af, const char *src, void *dst) +{ + int err; + switch (af) { +#if LWIP_IPV4 + case AF_INET: + err = ip4addr_aton(src, (ip4_addr_t *)dst); + break; +#endif +#if LWIP_IPV6 + case AF_INET6: { + /* convert into temporary variable since ip6_addr_t might be larger + than in6_addr when scopes are enabled */ + ip6_addr_t addr; + err = ip6addr_aton(src, &addr); + if (err) { + memcpy(dst, &addr.addr, sizeof(addr.addr)); + } + break; + } +#endif + default: + err = -1; + set_errno(EAFNOSUPPORT); + break; + } + return err; +} + +#if LWIP_IGMP +/** Register a new IGMP membership. On socket close, the membership is dropped automatically. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + * + * @return 1 on success, 0 on failure + */ +static int +lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return 0; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv4_multicast_memberships[i].sock == NULL) { + socket_ipv4_multicast_memberships[i].sock = sock; + ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); + ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); + done_socket(sock); + return 1; + } + } + done_socket(sock); + return 0; +} + +/** Unregister a previously registered membership. This prevents dropping the membership + * on socket close. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if ((socket_ipv4_multicast_memberships[i].sock == sock) && + ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && + ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { + socket_ipv4_multicast_memberships[i].sock = NULL; + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); + break; + } + } + done_socket(sock); +} + +/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. + * + * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_drop_registered_memberships(int s) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv4_multicast_memberships[i].sock == sock) { + ip_addr_t multi_addr, if_addr; + ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); + ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); + socket_ipv4_multicast_memberships[i].sock = NULL; + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); + + netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); + } + } + done_socket(sock); +} +#endif /* LWIP_IGMP */ + +#if LWIP_IPV6_MLD +/** Register a new MLD6 membership. On socket close, the membership is dropped automatically. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + * + * @return 1 on success, 0 on failure + */ +static int +lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return 0; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv6_multicast_memberships[i].sock == NULL) { + socket_ipv6_multicast_memberships[i].sock = sock; + socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; + ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr); + done_socket(sock); + return 1; + } + } + done_socket(sock); + return 0; +} + +/** Unregister a previously registered MLD6 membership. This prevents dropping the membership + * on socket close. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if ((socket_ipv6_multicast_memberships[i].sock == sock) && + (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && + ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { + socket_ipv6_multicast_memberships[i].sock = NULL; + socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; + ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); + break; + } + } + done_socket(sock); +} + +/** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt. + * + * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_drop_registered_mld6_memberships(int s) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv6_multicast_memberships[i].sock == sock) { + ip_addr_t multi_addr; + u8_t if_idx; + + ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr); + if_idx = socket_ipv6_multicast_memberships[i].if_idx; + + socket_ipv6_multicast_memberships[i].sock = NULL; + socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; + ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); + + netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); + } + } + done_socket(sock); +} +#endif /* LWIP_IPV6_MLD */ + +#endif /* LWIP_SOCKET */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/tcpip.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/tcpip.c new file mode 100644 index 0000000..a7e312a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/api/tcpip.c @@ -0,0 +1,658 @@ +/** + * @file + * Sequential API Main thread module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcpip_priv.h" +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/mem.h" +#include "lwip/init.h" +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/etharp.h" +#include "netif/ethernet.h" + +#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) +#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) +#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) +#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) + +/* global variables */ +static tcpip_init_done_fn tcpip_init_done; +static void *tcpip_init_done_arg; +static sys_mbox_t tcpip_mbox; + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +sys_mutex_t lock_tcpip_core; +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +static void tcpip_thread_handle_msg(struct tcpip_msg *msg); + +#if !LWIP_TIMERS +/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ +#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) +#else /* !LWIP_TIMERS */ +/* wait for a message, timeouts are processed while waiting */ +#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg) +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +static void +tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +{ + u32_t sleeptime, res; + +again: + LWIP_ASSERT_CORE_LOCKED(); + + sleeptime = sys_timeouts_sleeptime(); + if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { + UNLOCK_TCPIP_CORE(); + sys_arch_mbox_fetch(mbox, msg, 0); + LOCK_TCPIP_CORE(); + return; + } else if (sleeptime == 0) { + sys_check_timeouts(); + /* We try again to fetch a message from the mbox. */ + goto again; + } + + UNLOCK_TCPIP_CORE(); + res = sys_arch_mbox_fetch(mbox, msg, sleeptime); + LOCK_TCPIP_CORE(); + if (res == SYS_ARCH_TIMEOUT) { + /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred + before a message could be fetched. */ + sys_check_timeouts(); + /* We try again to fetch a message from the mbox. */ + goto again; + } +} +#endif /* !LWIP_TIMERS */ + +/** + * The main lwIP thread. This thread has exclusive access to lwIP core functions + * (unless access to them is not locked). Other threads communicate with this + * thread using message boxes. + * + * It also starts all the timers to make sure they are running in the right + * thread context. + * + * @param arg unused argument + */ +static void +tcpip_thread(void *arg) +{ + struct tcpip_msg *msg; + LWIP_UNUSED_ARG(arg); + + LWIP_MARK_TCPIP_THREAD(); + + LOCK_TCPIP_CORE(); + if (tcpip_init_done != NULL) { + tcpip_init_done(tcpip_init_done_arg); + } + + while (1) { /* MAIN Loop */ + LWIP_TCPIP_THREAD_ALIVE(); + /* wait for a message, timeouts are processed while waiting */ + TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); + if (msg == NULL) { + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + continue; + } + tcpip_thread_handle_msg(msg); + } +} + +/* Handle a single tcpip_msg + * This is in its own function for access by tests only. + */ +static void +tcpip_thread_handle_msg(struct tcpip_msg *msg) +{ + switch (msg->type) { +#if !LWIP_TCPIP_CORE_LOCKING + case TCPIP_MSG_API: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); + msg->msg.api_msg.function(msg->msg.api_msg.msg); + break; + case TCPIP_MSG_API_CALL: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); + msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); + sys_sem_signal(msg->msg.api_call.sem); + break; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + +#if !LWIP_TCPIP_CORE_LOCKING_INPUT + case TCPIP_MSG_INPKT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); + if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) { + pbuf_free(msg->msg.inp.p); + } + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + break; +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + case TCPIP_MSG_TIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); + sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + case TCPIP_MSG_UNTIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); + sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + + case TCPIP_MSG_CALLBACK: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + + case TCPIP_MSG_CALLBACK_STATIC: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + break; + + default: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + break; + } +} + +#ifdef TCPIP_THREAD_TEST +/** Work on queued items in single-threaded test mode */ +int +tcpip_thread_poll_one(void) +{ + int ret = 0; + struct tcpip_msg *msg; + + if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_MBOX_EMPTY) { + LOCK_TCPIP_CORE(); + if (msg != NULL) { + tcpip_thread_handle_msg(msg); + ret = 1; + } + UNLOCK_TCPIP_CORE(); + } + return ret; +} +#endif + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet + * @param inp the network interface on which the packet was received + * @param input_fn input function to call + */ +err_t +tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) +{ +#if LWIP_TCPIP_CORE_LOCKING_INPUT + err_t ret; + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); + LOCK_TCPIP_CORE(); + ret = input_fn(p, inp); + UNLOCK_TCPIP_CORE(); + return ret; +#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_INPKT; + msg->msg.inp.p = p; + msg->msg.inp.netif = inp; + msg->msg.inp.input_fn = input_fn; + if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + return ERR_MEM; + } + return ERR_OK; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ +} + +/** + * @ingroup lwip_os + * Pass a received packet to tcpip_thread for input processing with + * ethernet_input or ip_input. Don't call directly, pass to netif_add() + * and call netif->input(). + * + * @param p the received packet, p->payload pointing to the Ethernet header or + * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or + * NETIF_FLAG_ETHERNET flags) + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + return tcpip_inpkt(p, inp, ethernet_input); + } else +#endif /* LWIP_ETHERNET */ + return tcpip_inpkt(p, inp, ip_input); +} + +/** + * @ingroup lwip_os + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * Blocks until the request is posted. + * Must not be called from interrupt context! + * + * @param function the function to call + * @param ctx parameter passed to f + * @return ERR_OK if the function was called, another err_t if not + * + * @see tcpip_try_callback + */ +err_t +tcpip_callback(tcpip_callback_fn function, void *ctx) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_CALLBACK; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + + sys_mbox_post(&tcpip_mbox, msg); + return ERR_OK; +} + +/** + * @ingroup lwip_os + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * Does NOT block when the request cannot be posted because the + * tcpip_mbox is full, but returns ERR_MEM instead. + * Can be called from interrupt context. + * + * @param function the function to call + * @param ctx parameter passed to f + * @return ERR_OK if the function was called, another err_t if not + * + * @see tcpip_callback + */ +err_t +tcpip_try_callback(tcpip_callback_fn function, void *ctx) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_CALLBACK; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + + if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_API, msg); + return ERR_MEM; + } + return ERR_OK; +} + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS +/** + * call sys_timeout in tcpip_thread + * + * @param msecs time in milliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_TIMEOUT; + msg->msg.tmo.msecs = msecs; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&tcpip_mbox, msg); + return ERR_OK; +} + +/** + * call sys_untimeout in tcpip_thread + * + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_UNTIMEOUT; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&tcpip_mbox, msg); + return ERR_OK; +} +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + + +/** + * Sends a message to TCPIP thread to call a function. Caller thread blocks on + * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, + * this has to be done by the user. + * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way + * with least runtime overhead. + * + * @param fn function to be called from TCPIP thread + * @param apimsg argument to API function + * @param sem semaphore to wait on + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) +{ +#if LWIP_TCPIP_CORE_LOCKING + LWIP_UNUSED_ARG(sem); + LOCK_TCPIP_CORE(); + fn(apimsg); + UNLOCK_TCPIP_CORE(); + return ERR_OK; +#else /* LWIP_TCPIP_CORE_LOCKING */ + TCPIP_MSG_VAR_DECLARE(msg); + + LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + TCPIP_MSG_VAR_ALLOC(msg); + TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; + TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; + TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; + sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); + sys_arch_sem_wait(sem, 0); + TCPIP_MSG_VAR_FREE(msg); + return ERR_OK; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} + +/** + * Synchronously calls function in TCPIP thread and waits for its completion. + * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or + * LWIP_NETCONN_SEM_PER_THREAD. + * If not, a semaphore is created and destroyed on every call which is usually + * an expensive/slow operation. + * @param fn Function to call + * @param call Call parameters + * @return Return value from tcpip_api_call_fn + */ +err_t +tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) +{ +#if LWIP_TCPIP_CORE_LOCKING + err_t err; + LOCK_TCPIP_CORE(); + err = fn(call); + UNLOCK_TCPIP_CORE(); + return err; +#else /* LWIP_TCPIP_CORE_LOCKING */ + TCPIP_MSG_VAR_DECLARE(msg); + +#if !LWIP_NETCONN_SEM_PER_THREAD + err_t err = sys_sem_new(&call->sem, 0); + if (err != ERR_OK) { + return err; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + + TCPIP_MSG_VAR_ALLOC(msg); + TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; + TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; + TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; +#if LWIP_NETCONN_SEM_PER_THREAD + TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); + sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); + TCPIP_MSG_VAR_FREE(msg); + +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(&call->sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + return call->err; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} + +/** + * @ingroup lwip_os + * Allocate a structure for a static callback message and initialize it. + * The message has a special type such that lwIP never frees it. + * This is intended to be used to send "static" messages from interrupt context, + * e.g. the message is allocated once and posted several times from an IRQ + * using tcpip_callbackmsg_trycallback(). + * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context. + * + * @param function the function to call + * @param ctx parameter passed to function + * @return a struct pointer to pass to tcpip_callbackmsg_trycallback(). + * + * @see tcpip_callbackmsg_trycallback() + * @see tcpip_callbackmsg_delete() + */ +struct tcpip_callback_msg * +tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) +{ + struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return NULL; + } + msg->type = TCPIP_MSG_CALLBACK_STATIC; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + return (struct tcpip_callback_msg *)msg; +} + +/** + * @ingroup lwip_os + * Free a callback message allocated by tcpip_callbackmsg_new(). + * + * @param msg the message to free + * + * @see tcpip_callbackmsg_new() + */ +void +tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg) +{ + memp_free(MEMP_TCPIP_MSG_API, msg); +} + +/** + * @ingroup lwip_os + * Try to post a callback-message to the tcpip_thread tcpip_mbox. + * + * @param msg pointer to the message to post + * @return sys_mbox_trypost() return code + * + * @see tcpip_callbackmsg_new() + */ +err_t +tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg) +{ + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + return sys_mbox_trypost(&tcpip_mbox, msg); +} + +/** + * @ingroup lwip_os + * Try to post a callback-message to the tcpip_thread mbox. + * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(), + * mainly to help FreeRTOS, where calls differ between task level and ISR level. + * + * @param msg pointer to the message to post + * @return sys_mbox_trypost_fromisr() return code (without change, so this + * knowledge can be used to e.g. propagate "bool needs_scheduling") + * + * @see tcpip_callbackmsg_new() + */ +err_t +tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg) +{ + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); + return sys_mbox_trypost_fromisr(&tcpip_mbox, msg); +} + +/** + * @ingroup lwip_os + * Initialize this module: + * - initialize all sub modules + * - start the tcpip_thread + * + * @param initfunc a function to call when tcpip_thread is running and finished initializing + * @param arg argument to pass to initfunc + */ +void +tcpip_init(tcpip_init_done_fn initfunc, void *arg) +{ + lwip_init(); + + tcpip_init_done = initfunc; + tcpip_init_done_arg = arg; + if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) { + LWIP_ASSERT("failed to create tcpip_thread mbox", 0); + } +#if LWIP_TCPIP_CORE_LOCKING + if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { + LWIP_ASSERT("failed to create lock_tcpip_core", 0); + } +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); +} + +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ + struct pbuf *q = (struct pbuf *)p; + pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ + return tcpip_try_callback(pbuf_free_int, p); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ + return tcpip_try_callback(mem_free, m); +} + +#endif /* !NO_SYS */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp.c new file mode 100644 index 0000000..4abef7c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp.c @@ -0,0 +1,717 @@ +/** + * @file + * @defgroup altcp Application layered TCP Functions + * @ingroup altcp_api + * + * This file contains the common functions for altcp to work. + * For more details see @ref altcp_api. + */ + +/** + * @defgroup altcp_api Application layered TCP Introduction + * @ingroup callbackstyle_api + * + * Overview + * -------- + * altcp (application layered TCP connection API; to be used from TCPIP thread) + * is an abstraction layer that prevents applications linking hard against the + * @ref tcp.h functions while providing the same functionality. It is used to + * e.g. add SSL/TLS (see LWIP_ALTCP_TLS) or proxy-connect support to an application + * written for the tcp callback API without that application knowing the + * protocol details. + * + * * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * * This is achieved by simply including "lwip/altcp.h" instead of "lwip/tcp.h", + * replacing "struct tcp_pcb" with "struct altcp_pcb" and prefixing all functions + * with "altcp_" instead of "tcp_". + * + * With altcp support disabled (LWIP_ALTCP==0), applications written against the + * altcp API can still be compiled but are directly linked against the tcp.h + * callback API and then cannot use layered protocols. To minimize code changes + * in this case, the use of altcp_allocators is strongly suggested. + * + * Usage + * ----- + * To make use of this API from an existing tcp raw API application: + * * Include "lwip/altcp.h" instead of "lwip/tcp.h" + * * Replace "struct tcp_pcb" with "struct altcp_pcb" + * * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link + * against the altcp functions + * * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take + * an @ref altcp_allocator_t as an argument, whereas the original tcp API + * functions take no arguments. + * * An @ref altcp_allocator_t allocator is an object that holds a pointer to an + * allocator object and a corresponding state (e.g. for TLS, the corresponding + * state may hold certificates or keys). This way, the application does not + * even need to know if it uses TLS or pure TCP, this is handled at runtime + * by passing a specific allocator. + * * An application can alternatively bind hard to the altcp_tls API by calling + * @ref altcp_tls_new or @ref altcp_tls_wrap. + * * The TLS layer is not directly implemented by lwIP, but a port to mbedTLS is + * provided. + * * Another altcp layer is proxy-connect to use TLS behind a HTTP proxy (see + * @ref altcp_proxyconnect.h) + * + * altcp_allocator_t + * ----------------- + * An altcp allocator is created by the application by combining an allocator + * callback function and a corresponding state, e.g.:\code{.c} + * static const unsigned char cert[] = {0x2D, ... (see mbedTLS doc for how to create this)}; + * struct altcp_tls_config * conf = altcp_tls_create_config_client(cert, sizeof(cert)); + * altcp_allocator_t tls_allocator = { + * altcp_tls_alloc, conf + * }; + * \endcode + * + * + * struct altcp_tls_config + * ----------------------- + * The struct altcp_tls_config holds state that is needed to create new TLS client + * or server connections (e.g. certificates and private keys). + * + * It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS + * adaption). However, the parameters used to create it are defined in @ref + * altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers + * and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth + * for clients). + * + * For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and + * private keys can be parsed by 'mbedtls_pk_parse_key()'. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/altcp_tcp.h" +#include "lwip/tcp.h" +#include "lwip/mem.h" + +#include + +extern const struct altcp_functions altcp_tcp_functions; + +/** + * For altcp layer implementations only: allocate a new struct altcp_pcb from the pool + * and zero the memory + */ +struct altcp_pcb * +altcp_alloc(void) +{ + struct altcp_pcb *ret = (struct altcp_pcb *)memp_malloc(MEMP_ALTCP_PCB); + if (ret != NULL) { + memset(ret, 0, sizeof(struct altcp_pcb)); + } + return ret; +} + +/** + * For altcp layer implementations only: return a struct altcp_pcb to the pool + */ +void +altcp_free(struct altcp_pcb *conn) +{ + if (conn) { + if (conn->fns && conn->fns->dealloc) { + conn->fns->dealloc(conn); + } + memp_free(MEMP_ALTCP_PCB, conn); + } +} + +/** + * @ingroup altcp + * altcp_new_ip6: @ref altcp_new for IPv6 + */ +struct altcp_pcb * +altcp_new_ip6(altcp_allocator_t *allocator) +{ + return altcp_new_ip_type(allocator, IPADDR_TYPE_V6); +} + +/** + * @ingroup altcp + * altcp_new: @ref altcp_new for IPv4 + */ +struct altcp_pcb * +altcp_new(altcp_allocator_t *allocator) +{ + return altcp_new_ip_type(allocator, IPADDR_TYPE_V4); +} + +/** + * @ingroup altcp + * altcp_new_ip_type: called by applications to allocate a new pcb with the help of an + * allocator function. + * + * @param allocator allocator function and argument + * @param ip_type IP version of the pcb (@ref lwip_ip_addr_type) + * @return a new altcp_pcb or NULL on error + */ +struct altcp_pcb * +altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type) +{ + struct altcp_pcb *conn; + if (allocator == NULL) { + /* no allocator given, create a simple TCP connection */ + return altcp_tcp_new_ip_type(ip_type); + } + if (allocator->alloc == NULL) { + /* illegal allocator */ + return NULL; + } + conn = allocator->alloc(allocator->arg, ip_type); + if (conn == NULL) { + /* allocation failed */ + return NULL; + } + return conn; +} + +/** + * @ingroup altcp + * @see tcp_arg() + */ +void +altcp_arg(struct altcp_pcb *conn, void *arg) +{ + if (conn) { + conn->arg = arg; + } +} + +/** + * @ingroup altcp + * @see tcp_accept() + */ +void +altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept) +{ + if (conn != NULL) { + conn->accept = accept; + } +} + +/** + * @ingroup altcp + * @see tcp_recv() + */ +void +altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv) +{ + if (conn) { + conn->recv = recv; + } +} + +/** + * @ingroup altcp + * @see tcp_sent() + */ +void +altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent) +{ + if (conn) { + conn->sent = sent; + } +} + +/** + * @ingroup altcp + * @see tcp_poll() + */ +void +altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval) +{ + if (conn) { + conn->poll = poll; + conn->pollinterval = interval; + if (conn->fns && conn->fns->set_poll) { + conn->fns->set_poll(conn, interval); + } + } +} + +/** + * @ingroup altcp + * @see tcp_err() + */ +void +altcp_err(struct altcp_pcb *conn, altcp_err_fn err) +{ + if (conn) { + conn->err = err; + } +} + +/* Generic functions calling the "virtual" ones */ + +/** + * @ingroup altcp + * @see tcp_recved() + */ +void +altcp_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn && conn->fns && conn->fns->recved) { + conn->fns->recved(conn, len); + } +} + +/** + * @ingroup altcp + * @see tcp_bind() + */ +err_t +altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + if (conn && conn->fns && conn->fns->bind) { + return conn->fns->bind(conn, ipaddr, port); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_connect() + */ +err_t +altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + if (conn && conn->fns && conn->fns->connect) { + return conn->fns->connect(conn, ipaddr, port, connected); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_listen_with_backlog_and_err() + */ +struct altcp_pcb * +altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + if (conn && conn->fns && conn->fns->listen) { + return conn->fns->listen(conn, backlog, err); + } + return NULL; +} + +/** + * @ingroup altcp + * @see tcp_abort() + */ +void +altcp_abort(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->abort) { + conn->fns->abort(conn); + } +} + +/** + * @ingroup altcp + * @see tcp_close() + */ +err_t +altcp_close(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->close) { + return conn->fns->close(conn); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_shutdown() + */ +err_t +altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + if (conn && conn->fns && conn->fns->shutdown) { + return conn->fns->shutdown(conn, shut_rx, shut_tx); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_write() + */ +err_t +altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + if (conn && conn->fns && conn->fns->write) { + return conn->fns->write(conn, dataptr, len, apiflags); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_output() + */ +err_t +altcp_output(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->output) { + return conn->fns->output(conn); + } + return ERR_VAL; +} + +/** + * @ingroup altcp + * @see tcp_mss() + */ +u16_t +altcp_mss(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->mss) { + return conn->fns->mss(conn); + } + return 0; +} + +/** + * @ingroup altcp + * @see tcp_sndbuf() + */ +u16_t +altcp_sndbuf(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->sndbuf) { + return conn->fns->sndbuf(conn); + } + return 0; +} + +/** + * @ingroup altcp + * @see tcp_sndqueuelen() + */ +u16_t +altcp_sndqueuelen(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->sndqueuelen) { + return conn->fns->sndqueuelen(conn); + } + return 0; +} + +void +altcp_nagle_disable(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->nagle_disable) { + conn->fns->nagle_disable(conn); + } +} + +void +altcp_nagle_enable(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->nagle_enable) { + conn->fns->nagle_enable(conn); + } +} + +int +altcp_nagle_disabled(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->nagle_disabled) { + return conn->fns->nagle_disabled(conn); + } + return 0; +} + +/** + * @ingroup altcp + * @see tcp_setprio() + */ +void +altcp_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn && conn->fns && conn->fns->setprio) { + conn->fns->setprio(conn, prio); + } +} + +err_t +altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) +{ + if (conn && conn->fns && conn->fns->addrinfo) { + return conn->fns->addrinfo(conn, local, addr, port); + } + return ERR_VAL; +} + +ip_addr_t * +altcp_get_ip(struct altcp_pcb *conn, int local) +{ + if (conn && conn->fns && conn->fns->getip) { + return conn->fns->getip(conn, local); + } + return NULL; +} + +u16_t +altcp_get_port(struct altcp_pcb *conn, int local) +{ + if (conn && conn->fns && conn->fns->getport) { + return conn->fns->getport(conn, local); + } + return 0; +} + +#if LWIP_TCP_KEEPALIVE +void +altcp_keepalive_disable(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->keepalive_disable) { + conn->fns->keepalive_disable(conn); + } +} + +void +altcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count) +{ + if (conn && conn->fns && conn->fns->keepalive_enable) { + conn->fns->keepalive_enable(conn, idle, intvl, count); + } +} +#endif + +#ifdef LWIP_DEBUG +enum tcp_state +altcp_dbg_get_tcp_state(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->dbg_get_tcp_state) { + return conn->fns->dbg_get_tcp_state(conn); + } + return CLOSED; +} +#endif + +/* Default implementations for the "virtual" functions */ + +void +altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval) +{ + if (conn && conn->inner_conn) { + altcp_poll(conn->inner_conn, conn->poll, interval); + } +} + +void +altcp_default_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn && conn->inner_conn) { + altcp_recved(conn->inner_conn, len); + } +} + +err_t +altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + if (conn && conn->inner_conn) { + return altcp_bind(conn->inner_conn, ipaddr, port); + } + return ERR_VAL; +} + +err_t +altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + if (conn) { + if (shut_rx && shut_tx && conn->fns && conn->fns->close) { + /* default shutdown for both sides is close */ + return conn->fns->close(conn); + } + if (conn->inner_conn) { + return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx); + } + } + return ERR_VAL; +} + +err_t +altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + if (conn && conn->inner_conn) { + return altcp_write(conn->inner_conn, dataptr, len, apiflags); + } + return ERR_VAL; +} + +err_t +altcp_default_output(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_output(conn->inner_conn); + } + return ERR_VAL; +} + +u16_t +altcp_default_mss(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_mss(conn->inner_conn); + } + return 0; +} + +u16_t +altcp_default_sndbuf(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_sndbuf(conn->inner_conn); + } + return 0; +} + +u16_t +altcp_default_sndqueuelen(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_sndqueuelen(conn->inner_conn); + } + return 0; +} + +void +altcp_default_nagle_disable(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + altcp_nagle_disable(conn->inner_conn); + } +} + +void +altcp_default_nagle_enable(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + altcp_nagle_enable(conn->inner_conn); + } +} + +int +altcp_default_nagle_disabled(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_nagle_disabled(conn->inner_conn); + } + return 0; +} + +void +altcp_default_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn && conn->inner_conn) { + altcp_setprio(conn->inner_conn, prio); + } +} + +void +altcp_default_dealloc(struct altcp_pcb *conn) +{ + LWIP_UNUSED_ARG(conn); + /* nothing to do */ +} + +err_t +altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) +{ + if (conn && conn->inner_conn) { + return altcp_get_tcp_addrinfo(conn->inner_conn, local, addr, port); + } + return ERR_VAL; +} + +ip_addr_t * +altcp_default_get_ip(struct altcp_pcb *conn, int local) +{ + if (conn && conn->inner_conn) { + return altcp_get_ip(conn->inner_conn, local); + } + return NULL; +} + +u16_t +altcp_default_get_port(struct altcp_pcb *conn, int local) +{ + if (conn && conn->inner_conn) { + return altcp_get_port(conn->inner_conn, local); + } + return 0; +} + +#if LWIP_TCP_KEEPALIVE +void +altcp_default_keepalive_disable(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + altcp_keepalive_disable(conn->inner_conn); + } +} + +void +altcp_default_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count) +{ + if (conn && conn->inner_conn) { + altcp_keepalive_enable(conn->inner_conn, idle, intvl, count); + } +} +#endif + +#ifdef LWIP_DEBUG +enum tcp_state +altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn) +{ + if (conn && conn->inner_conn) { + return altcp_dbg_get_tcp_state(conn->inner_conn); + } + return CLOSED; +} +#endif + + +#endif /* LWIP_ALTCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_alloc.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_alloc.c new file mode 100644 index 0000000..cd619bc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_alloc.c @@ -0,0 +1,87 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains allocation implementation that combine several layers. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/altcp_tcp.h" +#include "lwip/altcp_tls.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/mem.h" + +#include + +#if LWIP_ALTCP_TLS + +/** This standard allocator function creates an altcp pcb for + * TLS over TCP */ +struct altcp_pcb * +altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type) +{ + struct altcp_pcb *inner_conn, *ret; + LWIP_UNUSED_ARG(ip_type); + + inner_conn = altcp_tcp_new_ip_type(ip_type); + if (inner_conn == NULL) { + return NULL; + } + ret = altcp_tls_wrap(config, inner_conn); + if (ret == NULL) { + altcp_close(inner_conn); + } + return ret; +} + +/** This standard allocator function creates an altcp pcb for + * TLS over TCP */ +struct altcp_pcb * +altcp_tls_alloc(void *arg, u8_t ip_type) +{ + return altcp_tls_new((struct altcp_tls_config *)arg, ip_type); +} + +#endif /* LWIP_ALTCP_TLS */ + +#endif /* LWIP_ALTCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_tcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_tcp.c new file mode 100644 index 0000000..1869e2a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/altcp_tcp.c @@ -0,0 +1,577 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the base implementation calling into tcp. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/altcp_tcp.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/mem.h" + +#include + +#define ALTCP_TCP_ASSERT_CONN(conn) do { \ + LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \ + LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0) +#define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \ + LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \ + LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \ + ALTCP_TCP_ASSERT_CONN(conn); } while(0) + + +/* Variable prototype, the actual declaration is at the end of this file + since it contains pointers to static functions declared here */ +extern const struct altcp_functions altcp_tcp_functions; + +static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb); + +/* callback functions for TCP */ +static err_t +altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err) +{ + struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; + if (listen_conn && listen_conn->accept) { + /* create a new altcp_conn to pass to the next 'accept' callback */ + struct altcp_pcb *new_conn = altcp_alloc(); + if (new_conn == NULL) { + return ERR_MEM; + } + altcp_tcp_setup(new_conn, new_tpcb); + return listen_conn->accept(listen_conn->arg, new_conn, err); + } + return ERR_ARG; +} + +static err_t +altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); + if (conn->connected) { + return conn->connected(conn->arg, conn, err); + } + } + return ERR_OK; +} + +static err_t +altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); + if (conn->recv) { + return conn->recv(conn->arg, conn, p, err); + } + } + if (p != NULL) { + /* prevent memory leaks */ + pbuf_free(p); + } + return ERR_OK; +} + +static err_t +altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); + if (conn->sent) { + return conn->sent(conn->arg, conn, len); + } + } + return ERR_OK; +} + +static err_t +altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); + if (conn->poll) { + return conn->poll(conn->arg, conn); + } + } + return ERR_OK; +} + +static void +altcp_tcp_err(void *arg, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + conn->state = NULL; /* already freed */ + if (conn->err) { + conn->err(conn->arg, err); + } + altcp_free(conn); + } +} + +/* setup functions */ + +static void +altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb) +{ + tcp_arg(tpcb, NULL); + if (tpcb->state != LISTEN) { + tcp_recv(tpcb, NULL); + tcp_sent(tpcb, NULL); + tcp_err(tpcb, NULL); + tcp_poll(tpcb, NULL, tpcb->pollinterval); + } +} + +static void +altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb) +{ + tcp_arg(tpcb, conn); + /* this might be called for LISTN when close fails... */ + if (tpcb->state != LISTEN) { + tcp_recv(tpcb, altcp_tcp_recv); + tcp_sent(tpcb, altcp_tcp_sent); + tcp_err(tpcb, altcp_tcp_err); + /* tcp_poll is set when interval is set by application */ + } +} + +static void +altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb) +{ + altcp_tcp_setup_callbacks(conn, tpcb); + conn->state = tpcb; + conn->fns = &altcp_tcp_functions; +} + +struct altcp_pcb * +altcp_tcp_new_ip_type(u8_t ip_type) +{ + /* Allocate the tcp pcb first to invoke the priority handling code + if we're out of pcbs */ + struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type); + if (tpcb != NULL) { + struct altcp_pcb *ret = altcp_alloc(); + if (ret != NULL) { + altcp_tcp_setup(ret, tpcb); + return ret; + } else { + /* altcp_pcb allocation failed -> free the tcp_pcb too */ + tcp_close(tpcb); + } + } + return NULL; +} + +/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new. +* +* arg pointer is not used for TCP. +*/ +struct altcp_pcb * +altcp_tcp_alloc(void *arg, u8_t ip_type) +{ + LWIP_UNUSED_ARG(arg); + return altcp_tcp_new_ip_type(ip_type); +} + +struct altcp_pcb * +altcp_tcp_wrap(struct tcp_pcb *tpcb) +{ + if (tpcb != NULL) { + struct altcp_pcb *ret = altcp_alloc(); + if (ret != NULL) { + altcp_tcp_setup(ret, tpcb); + return ret; + } + } + return NULL; +} + + +/* "virtual" functions calling into tcp */ +static void +altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + tcp_poll(pcb, altcp_tcp_poll, interval); + } +} + +static void +altcp_tcp_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + tcp_recved(pcb, len); + } +} + +static err_t +altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_bind(pcb, ipaddr, port); +} + +static err_t +altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + conn->connected = connected; + pcb = (struct tcp_pcb *)conn->state; + return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected); +} + +static struct altcp_pcb * +altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + struct tcp_pcb *pcb; + struct tcp_pcb *lpcb; + if (conn == NULL) { + return NULL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err); + if (lpcb != NULL) { + conn->state = lpcb; + tcp_accept(lpcb, altcp_tcp_accept); + return conn; + } + return NULL; +} + +static void +altcp_tcp_abort(struct altcp_pcb *conn) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + if (pcb) { + tcp_abort(pcb); + } + } +} + +static err_t +altcp_tcp_close(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + if (pcb) { + err_t err; + tcp_poll_fn oldpoll = pcb->poll; + altcp_tcp_remove_callbacks(pcb); + err = tcp_close(pcb); + if (err != ERR_OK) { + /* not closed, set up all callbacks again */ + altcp_tcp_setup_callbacks(conn, pcb); + /* poll callback is not included in the above */ + tcp_poll(pcb, oldpoll, pcb->pollinterval); + return err; + } + conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */ + } + altcp_free(conn); + return ERR_OK; +} + +static err_t +altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_shutdown(pcb, shut_rx, shut_tx); +} + +static err_t +altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_write(pcb, dataptr, len, apiflags); +} + +static err_t +altcp_tcp_output(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_output(pcb); +} + +static u16_t +altcp_tcp_mss(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_mss(pcb); +} + +static u16_t +altcp_tcp_sndbuf(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_sndbuf(pcb); +} + +static u16_t +altcp_tcp_sndqueuelen(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + ALTCP_TCP_ASSERT_CONN(conn); + pcb = (struct tcp_pcb *)conn->state; + return tcp_sndqueuelen(pcb); +} + +static void +altcp_tcp_nagle_disable(struct altcp_pcb *conn) +{ + if (conn && conn->state) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + tcp_nagle_disable(pcb); + } +} + +static void +altcp_tcp_nagle_enable(struct altcp_pcb *conn) +{ + if (conn && conn->state) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + tcp_nagle_enable(pcb); + } +} + +static int +altcp_tcp_nagle_disabled(struct altcp_pcb *conn) +{ + if (conn && conn->state) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + return tcp_nagle_disabled(pcb); + } + return 0; +} + +static void +altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + tcp_setprio(pcb, prio); + } +} + +#if LWIP_TCP_KEEPALIVE +static void +altcp_tcp_keepalive_disable(struct altcp_pcb *conn) +{ + if (conn && conn->state) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + ip_reset_option(pcb, SOF_KEEPALIVE); + } +} + +static void +altcp_tcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t cnt) +{ + if (conn && conn->state) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + ip_set_option(pcb, SOF_KEEPALIVE); + pcb->keep_idle = idle ? idle : TCP_KEEPIDLE_DEFAULT; + pcb->keep_intvl = intvl ? intvl : TCP_KEEPINTVL_DEFAULT; + pcb->keep_cnt = cnt ? cnt : TCP_KEEPCNT_DEFAULT; + } +} +#endif + +static void +altcp_tcp_dealloc(struct altcp_pcb *conn) +{ + LWIP_UNUSED_ARG(conn); + ALTCP_TCP_ASSERT_CONN(conn); + /* no private state to clean up */ +} + +static err_t +altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) +{ + if (conn) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port); + } + return ERR_VAL; +} + +static ip_addr_t * +altcp_tcp_get_ip(struct altcp_pcb *conn, int local) +{ + if (conn) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + if (pcb) { + if (local) { + return &pcb->local_ip; + } else { + return &pcb->remote_ip; + } + } + } + return NULL; +} + +static u16_t +altcp_tcp_get_port(struct altcp_pcb *conn, int local) +{ + if (conn) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + if (pcb) { + if (local) { + return pcb->local_port; + } else { + return pcb->remote_port; + } + } + } + return 0; +} + +#ifdef LWIP_DEBUG +static enum tcp_state +altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn) +{ + if (conn) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; + ALTCP_TCP_ASSERT_CONN(conn); + if (pcb) { + return pcb->state; + } + } + return CLOSED; +} +#endif +const struct altcp_functions altcp_tcp_functions = { + altcp_tcp_set_poll, + altcp_tcp_recved, + altcp_tcp_bind, + altcp_tcp_connect, + altcp_tcp_listen, + altcp_tcp_abort, + altcp_tcp_close, + altcp_tcp_shutdown, + altcp_tcp_write, + altcp_tcp_output, + altcp_tcp_mss, + altcp_tcp_sndbuf, + altcp_tcp_sndqueuelen, + altcp_tcp_nagle_disable, + altcp_tcp_nagle_enable, + altcp_tcp_nagle_disabled, + altcp_tcp_setprio, + altcp_tcp_dealloc, + altcp_tcp_get_tcp_addrinfo, + altcp_tcp_get_ip, + altcp_tcp_get_port +#if LWIP_TCP_KEEPALIVE + , altcp_tcp_keepalive_disable + , altcp_tcp_keepalive_enable +#endif +#ifdef LWIP_DEBUG + , altcp_tcp_dbg_get_tcp_state +#endif +}; + +#endif /* LWIP_ALTCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/def.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/def.c new file mode 100644 index 0000000..9da36fe --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/def.c @@ -0,0 +1,240 @@ +/** + * @file + * Common functions used throughout the stack. + * + * These are reference implementations of the byte swapping functions. + * Again with the aim of being simple, correct and fully portable. + * Byte swapping is the second thing you would want to optimize. You will + * need to port it to your architecture and in your cc.h: + * + * \#define lwip_htons(x) your_htons + * \#define lwip_htonl(x) your_htonl + * + * Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts. + * + * If you \#define them to htons() and htonl(), you should + * \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from + * defining htonx/ntohx compatibility macros. + + * @defgroup sys_nonstandard Non-standard functions + * @ingroup sys_layer + * lwIP provides default implementations for non-standard functions. + * These can be mapped to OS functions to reduce code footprint if desired. + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/cc.h! + * These options cannot be \#defined in lwipopts.h since they are not options + * of lwIP itself, but options of the lwIP port to your system. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include + +#if BYTE_ORDER == LITTLE_ENDIAN + +#if !defined(lwip_htons) +/** + * Convert an u16_t from host- to network byte order. + * + * @param n u16_t in host byte order + * @return n in network byte order + */ +u16_t +lwip_htons(u16_t n) +{ + return PP_HTONS(n); +} +#endif /* lwip_htons */ + +#if !defined(lwip_htonl) +/** + * Convert an u32_t from host- to network byte order. + * + * @param n u32_t in host byte order + * @return n in network byte order + */ +u32_t +lwip_htonl(u32_t n) +{ + return PP_HTONL(n); +} +#endif /* lwip_htonl */ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#ifndef lwip_strnstr +/** + * @ingroup sys_nonstandard + * lwIP default implementation for strnstr() non-standard function. + * This can be \#defined to strnstr() depending on your platform port. + */ +char * +lwip_strnstr(const char *buffer, const char *token, size_t n) +{ + const char *p; + size_t tokenlen = strlen(token); + if (tokenlen == 0) { + return LWIP_CONST_CAST(char *, buffer); + } + for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { + if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { + return LWIP_CONST_CAST(char *, p); + } + } + return NULL; +} +#endif + +#ifndef lwip_stricmp +/** + * @ingroup sys_nonstandard + * lwIP default implementation for stricmp() non-standard function. + * This can be \#defined to stricmp() depending on your platform port. + */ +int +lwip_stricmp(const char *str1, const char *str2) +{ + char c1, c2; + + do { + c1 = *str1++; + c2 = *str2++; + if (c1 != c2) { + char c1_upc = c1 | 0x20; + if ((c1_upc >= 'a') && (c1_upc <= 'z')) { + /* characters are not equal an one is in the alphabet range: + downcase both chars and check again */ + char c2_upc = c2 | 0x20; + if (c1_upc != c2_upc) { + /* still not equal */ + /* don't care for < or > */ + return 1; + } + } else { + /* characters are not equal but none is in the alphabet range */ + return 1; + } + } + } while (c1 != 0); + return 0; +} +#endif + +#ifndef lwip_strnicmp +/** + * @ingroup sys_nonstandard + * lwIP default implementation for strnicmp() non-standard function. + * This can be \#defined to strnicmp() depending on your platform port. + */ +int +lwip_strnicmp(const char *str1, const char *str2, size_t len) +{ + char c1, c2; + + do { + c1 = *str1++; + c2 = *str2++; + if (c1 != c2) { + char c1_upc = c1 | 0x20; + if ((c1_upc >= 'a') && (c1_upc <= 'z')) { + /* characters are not equal an one is in the alphabet range: + downcase both chars and check again */ + char c2_upc = c2 | 0x20; + if (c1_upc != c2_upc) { + /* still not equal */ + /* don't care for < or > */ + return 1; + } + } else { + /* characters are not equal but none is in the alphabet range */ + return 1; + } + } + len--; + } while ((len != 0) && (c1 != 0)); + return 0; +} +#endif + +#ifndef lwip_itoa +/** + * @ingroup sys_nonstandard + * lwIP default implementation for itoa() non-standard function. + * This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port. + */ +void +lwip_itoa(char *result, size_t bufsize, int number) +{ + char *res = result; + char *tmp = result + bufsize - 1; + int n = (number >= 0) ? number : -number; + + /* handle invalid bufsize */ + if (bufsize < 2) { + if (bufsize == 1) { + *result = 0; + } + return; + } + + /* First, add sign */ + if (number < 0) { + *res++ = '-'; + } + /* Then create the string from the end and stop if buffer full, + and ensure output string is zero terminated */ + *tmp = 0; + while ((n != 0) && (tmp > res)) { + char val = (char)('0' + (n % 10)); + tmp--; + *tmp = val; + n = n / 10; + } + if (n) { + /* buffer is too small */ + *result = 0; + return; + } + if (*tmp == 0) { + /* Nothing added? */ + *res++ = '0'; + *res++ = 0; + return; + } + /* move from temporary buffer to output buffer (sign is not moved) */ + memmove(res, tmp, (size_t)((result + bufsize) - tmp)); +} +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/dns.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/dns.c new file mode 100644 index 0000000..9d2f61e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/dns.c @@ -0,0 +1,1631 @@ +/** + * @file + * DNS - host name to IP address resolver. + * + * @defgroup dns DNS + * @ingroup callbackstyle_api + * + * Implements a DNS host name to IP address resolver. + * + * The lwIP DNS resolver functions are used to lookup a host name and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the dns_lookup() function. + * New hostnames can be resolved using the dns_query() function. + * + * The lwIP version of the resolver also adds a non-blocking version of + * gethostbyname() that will work with a raw API application. This function + * checks for an IP address string first and converts it if it is valid. + * gethostbyname() then does a dns_lookup() to see if the name is + * already in the table. If so, the IP is returned. If not, a query is + * issued and the function returns with a ERR_INPROGRESS status. The app + * using the dns client must then go into a waiting state. + * + * Once a hostname has been resolved (or found to be non-existent), + * the resolver code calls a specified callback function (which + * must be implemented by the module that uses the resolver). + * + * Multicast DNS queries are supported for names ending on ".local". + * However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762 + * chapter 5.1), this is not a fully compliant implementation of continuous + * mDNS querying! + * + * All functions must be called from TCPIP thread. + * + * @see DNS_MAX_SERVERS + * @see LWIP_DHCP_MAX_DNS_SERVERS + * @see @ref netconn_common for thread-safe access. + */ + +/* + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + * + * security fixes and more by Simon Goldschmidt + * + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/*----------------------------------------------------------------------------- + * RFC 1035 - Domain names - implementation and specification + * RFC 2181 - Clarifications to the DNS Specification + *----------------------------------------------------------------------------*/ + +/** @todo: define good default values (rfc compliance) */ +/** @todo: improve answer parsing, more checkings... */ +/** @todo: check RFC1035 - 7.3. Processing responses */ +/** @todo: one-shot mDNS: dual-stack fallback to another IP version */ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/dns.h" +#include "lwip/prot/dns.h" + +#include + +/** Random generator function to create random TXIDs and source ports for queries */ +#ifndef DNS_RAND_TXID +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) +#define DNS_RAND_TXID LWIP_RAND +#else +static u16_t dns_txid; +#define DNS_RAND_TXID() (++dns_txid) +#endif +#endif + +/** Limits the source port to be >= 1024 by default */ +#ifndef DNS_PORT_ALLOWED +#define DNS_PORT_ALLOWED(port) ((port) >= 1024) +#endif + +/** DNS resource record max. TTL (one week as default) */ +#ifndef DNS_MAX_TTL +#define DNS_MAX_TTL 604800 +#elif DNS_MAX_TTL > 0x7FFFFFFF +#error DNS_MAX_TTL must be a positive 32-bit value +#endif + +#if DNS_TABLE_SIZE > 255 +#error DNS_TABLE_SIZE must fit into an u8_t +#endif +#if DNS_MAX_SERVERS > 255 +#error DNS_MAX_SERVERS must fit into an u8_t +#endif + +/* The number of parallel requests (i.e. calls to dns_gethostbyname + * that cannot be answered from the DNS table. + * This is set to the table size by default. + */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) +#ifndef DNS_MAX_REQUESTS +#define DNS_MAX_REQUESTS DNS_TABLE_SIZE +#else +#if DNS_MAX_REQUESTS > 255 +#error DNS_MAX_REQUESTS must fit into an u8_t +#endif +#endif +#else +/* In this configuration, both arrays have to have the same size and are used + * like one entry (used/free) */ +#define DNS_MAX_REQUESTS DNS_TABLE_SIZE +#endif + +/* The number of UDP source ports used in parallel */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +#ifndef DNS_MAX_SOURCE_PORTS +#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS +#else +#if DNS_MAX_SOURCE_PORTS > 255 +#error DNS_MAX_SOURCE_PORTS must fit into an u8_t +#endif +#endif +#else +#ifdef DNS_MAX_SOURCE_PORTS +#undef DNS_MAX_SOURCE_PORTS +#endif +#define DNS_MAX_SOURCE_PORTS 1 +#endif + +#if LWIP_IPV4 && LWIP_IPV6 +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6)) +#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t))) +#define LWIP_DNS_ADDRTYPE_ARG(x) , x +#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x +#define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0) +#else +#if LWIP_IPV6 +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1 +#else +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0 +#endif +#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1 +#define LWIP_DNS_ADDRTYPE_ARG(x) +#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0 +#define LWIP_DNS_SET_ADDRTYPE(x, y) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES +#define LWIP_DNS_ISMDNS_ARG(x) , x +#else +#define LWIP_DNS_ISMDNS_ARG(x) +#endif + +/** DNS query message structure. + No packing needed: only used locally on the stack. */ +struct dns_query { + /* DNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; +}; +#define SIZEOF_DNS_QUERY 4 + +/** DNS answer message structure. + No packing needed: only used locally on the stack. */ +struct dns_answer { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; + u32_t ttl; + u16_t len; +}; +#define SIZEOF_DNS_ANSWER 10 +/* maximum allowed size for the struct due to non-packed */ +#define SIZEOF_DNS_ANSWER_ASSERT 12 + +/* DNS table entry states */ +typedef enum { + DNS_STATE_UNUSED = 0, + DNS_STATE_NEW = 1, + DNS_STATE_ASKING = 2, + DNS_STATE_DONE = 3 +} dns_state_enum_t; + +/** DNS table entry */ +struct dns_table_entry { + u32_t ttl; + ip_addr_t ipaddr; + u16_t txid; + u8_t state; + u8_t server_idx; + u8_t tmr; + u8_t retries; + u8_t seqno; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + u8_t pcb_idx; +#endif + char name[DNS_MAX_NAME_LENGTH]; +#if LWIP_IPV4 && LWIP_IPV6 + u8_t reqaddrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + u8_t is_mdns; +#endif +}; + +/** DNS request table entry: used when dns_gehostbyname cannot answer the + * request from the DNS table */ +struct dns_req_entry { + /* pointer to callback on DNS query done */ + dns_found_callback found; + /* argument passed to the callback function */ + void *arg; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + u8_t dns_table_idx; +#endif +#if LWIP_IPV4 && LWIP_IPV6 + u8_t reqaddrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +}; + +#if DNS_LOCAL_HOSTLIST + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Local host-list. For hostnames in this list, no + * external name resolution is performed */ +static struct local_hostlist_entry *local_hostlist_dynamic; +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE +#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST +#define DNS_LOCAL_HOSTLIST_STORAGE_POST +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ +DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] + DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; + +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +static void dns_init_local(void); +static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); +#endif /* DNS_LOCAL_HOSTLIST */ + + +/* forward declarations */ +static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +static void dns_check_entries(void); +static void dns_call_found(u8_t idx, ip_addr_t *addr); + +/*----------------------------------------------------------------------------- + * Globals + *----------------------------------------------------------------------------*/ + +/* DNS variables */ +static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +static u8_t dns_last_pcb_idx; +#endif +static u8_t dns_seqno; +static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; +static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; +static ip_addr_t dns_servers[DNS_MAX_SERVERS]; + +#if LWIP_IPV4 +const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT; +#endif /* LWIP_IPV6 */ + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (if DNS_SERVER_ADDRESS is set). + */ +void +dns_init(void) +{ +#ifdef DNS_SERVER_ADDRESS + /* initialize default DNS server address */ + ip_addr_t dnsserver; + DNS_SERVER_ADDRESS(&dnsserver); + dns_setserver(0, &dnsserver); +#endif /* DNS_SERVER_ADDRESS */ + + LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", + sizeof(struct dns_query) == SIZEOF_DNS_QUERY); + LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER", + sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT); + + LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); + + /* if dns client not yet initialized... */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) + if (dns_pcbs[0] == NULL) { + dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL); + + /* initialize DNS table not needed (initialized to zero since it is a + * global variable) */ + LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", + DNS_STATE_UNUSED == 0); + + /* initialize DNS client */ + udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0); + udp_recv(dns_pcbs[0], dns_recv, NULL); + } +#endif + +#if DNS_LOCAL_HOSTLIST + dns_init_local(); +#endif +} + +/** + * @ingroup dns + * Initialize one of the DNS servers. + * + * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS + * @param dnsserver IP address of the DNS server to set + */ +void +dns_setserver(u8_t numdns, const ip_addr_t *dnsserver) +{ + if (numdns < DNS_MAX_SERVERS) { + if (dnsserver != NULL) { + dns_servers[numdns] = (*dnsserver); + } else { + dns_servers[numdns] = *IP_ADDR_ANY; + } + } +} + +/** + * @ingroup dns + * Obtain one of the currently configured DNS server. + * + * @param numdns the index of the DNS server + * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS + * server has not been configured. + */ +const ip_addr_t * +dns_getserver(u8_t numdns) +{ + if (numdns < DNS_MAX_SERVERS) { + return &dns_servers[numdns]; + } else { + return IP_ADDR_ANY; + } +} + +/** + * The DNS resolver client timer - handle retries and timeouts and should + * be called every DNS_TMR_INTERVAL milliseconds (every second by default). + */ +void +dns_tmr(void) +{ + LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); + dns_check_entries(); +} + +#if DNS_LOCAL_HOSTLIST +static void +dns_init_local(void) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) + size_t i; + struct local_hostlist_entry *entry; + /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ + struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; + size_t namelen; + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) { + struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; + LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); + namelen = strlen(init_entry->name); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); + if (entry != NULL) { + char *entry_name = (char *)entry + sizeof(struct local_hostlist_entry); + MEMCPY(entry_name, init_entry->name, namelen); + entry_name[namelen] = 0; + entry->name = entry_name; + entry->addr = init_entry->addr; + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ +} + +/** + * @ingroup dns + * Iterate the local host-list for a hostname. + * + * @param iterator_fn a function that is called for every entry in the local host-list + * @param iterator_arg 3rd argument passed to iterator_fn + * @return the number of entries in the local host-list + */ +size_t +dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) +{ + size_t i; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + i = 0; + while (entry != NULL) { + if (iterator_fn != NULL) { + iterator_fn(entry->name, &entry->addr, iterator_arg); + } + i++; + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { + if (iterator_fn != NULL) { + iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg); + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return i; +} + +/** + * @ingroup dns + * Scans the local host-list for a hostname. + * + * @param hostname Hostname to look for in the local host-list + * @param addr the first IP address for the hostname in the local host-list or + * IPADDR_NONE if not found. + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!) + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!) + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + * @return ERR_OK if found, ERR_ARG if not found + */ +err_t +dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) +{ + LWIP_UNUSED_ARG(dns_addrtype); + return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); +} + +/* Internal implementation for dns_local_lookup and dns_lookup */ +static err_t +dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + while (entry != NULL) { + if ((lwip_stricmp(entry->name, hostname) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { + if (addr) { + ip_addr_copy(*addr, entry->addr); + } + return ERR_OK; + } + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + size_t i; + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { + if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { + if (addr) { + ip_addr_copy(*addr, local_hostlist_static[i].addr); + } + return ERR_OK; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return ERR_ARG; +} + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** + * @ingroup dns + * Remove all entries from the local host-list for a specific hostname + * and/or IP address + * + * @param hostname hostname for which entries shall be removed from the local + * host-list + * @param addr address for which entries shall be removed from the local host-list + * @return the number of removed entries + */ +int +dns_local_removehost(const char *hostname, const ip_addr_t *addr) +{ + int removed = 0; + struct local_hostlist_entry *entry = local_hostlist_dynamic; + struct local_hostlist_entry *last_entry = NULL; + while (entry != NULL) { + if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && + ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { + struct local_hostlist_entry *free_entry; + if (last_entry != NULL) { + last_entry->next = entry->next; + } else { + local_hostlist_dynamic = entry->next; + } + free_entry = entry; + entry = entry->next; + memp_free(MEMP_LOCALHOSTLIST, free_entry); + removed++; + } else { + last_entry = entry; + entry = entry->next; + } + } + return removed; +} + +/** + * @ingroup dns + * Add a hostname/IP address pair to the local host-list. + * Duplicates are not checked. + * + * @param hostname hostname of the new entry + * @param addr IP address of the new entry + * @return ERR_OK if succeeded or ERR_MEM on memory error + */ +err_t +dns_local_addhost(const char *hostname, const ip_addr_t *addr) +{ + struct local_hostlist_entry *entry; + size_t namelen; + char *entry_name; + LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); + namelen = strlen(hostname); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + if (entry == NULL) { + return ERR_MEM; + } + entry_name = (char *)entry + sizeof(struct local_hostlist_entry); + MEMCPY(entry_name, hostname, namelen); + entry_name[namelen] = 0; + entry->name = entry_name; + ip_addr_copy(entry->addr, *addr); + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + return ERR_OK; +} +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** + * @ingroup dns + * Look up a hostname in the array of known hostnames. + * + * @note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function dns_enqueue() can be used to send a query + * for a hostname. + * + * @param name the hostname to look up + * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to + * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname + * was not found in the cached dns_table. + * @return ERR_OK if found, ERR_ARG if not found + */ +static err_t +dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +{ + u8_t i; +#if DNS_LOCAL_HOSTLIST + if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN + if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#endif /* DNS_LOOKUP_LOCAL_EXTERN */ + + /* Walk through name list, return entry if found. If not, return NULL. */ + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + if ((dns_table[i].state == DNS_STATE_DONE) && + (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); + ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + if (addr) { + ip_addr_copy(*addr, dns_table[i].ipaddr); + } + return ERR_OK; + } + } + + return ERR_ARG; +} + +/** + * Compare the "dotted" name "query" with the encoded name "response" + * to make sure an answer from the DNS server matches the current dns_table + * entry (otherwise, answers might arrive late for hostname not on the list + * any more). + * + * For now, this function compares case-insensitive to cope with all kinds of + * servers. This also means that "dns 0x20 bit encoding" must be checked + * externally, if we want to implement it. + * Currently, the request is sent exactly as passed in by he user request. + * + * @param query hostname (not encoded) from the dns_table + * @param p pbuf containing the encoded hostname in the DNS response + * @param start_offset offset into p where the name starts + * @return 0xFFFF: names differ, other: names equal -> offset behind name + */ +static u16_t +dns_compare_name(const char *query, struct pbuf *p, u16_t start_offset) +{ + int n; + u16_t response_offset = start_offset; + + do { + n = pbuf_try_get_at(p, response_offset); + if ((n < 0) || (response_offset == 0xFFFF)) { + /* error or overflow */ + return 0xFFFF; + } + response_offset++; + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name: cannot be equal since we don't send them */ + return 0xFFFF; + } else { + /* Not compressed name */ + while (n > 0) { + int c = pbuf_try_get_at(p, response_offset); + if (c < 0) { + return 0xFFFF; + } + if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) { + return 0xFFFF; + } + if (response_offset == 0xFFFF) { + /* would overflow */ + return 0xFFFF; + } + response_offset++; + ++query; + --n; + } + ++query; + } + n = pbuf_try_get_at(p, response_offset); + if (n < 0) { + return 0xFFFF; + } + } while (n != 0); + + if (response_offset == 0xFFFF) { + /* would overflow */ + return 0xFFFF; + } + return (u16_t)(response_offset + 1); +} + +/** + * Walk through a compact encoded DNS name and return the end of the name. + * + * @param p pbuf containing the name + * @param query_idx start index into p pointing to encoded DNS name in the DNS server response + * @return index to end of the name + */ +static u16_t +dns_skip_name(struct pbuf *p, u16_t query_idx) +{ + int n; + u16_t offset = query_idx; + + do { + n = pbuf_try_get_at(p, offset++); + if ((n < 0) || (offset == 0)) { + return 0xFFFF; + } + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name: since we only want to skip it (not check it), stop here */ + break; + } else { + /* Not compressed name */ + if (offset + n >= p->tot_len) { + return 0xFFFF; + } + offset = (u16_t)(offset + n); + } + n = pbuf_try_get_at(p, offset); + if (n < 0) { + return 0xFFFF; + } + } while (n != 0); + + if (offset == 0xFFFF) { + return 0xFFFF; + } + return (u16_t)(offset + 1); +} + +/** + * Send a DNS query packet. + * + * @param idx the DNS table entry index for which to send a request + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t +dns_send(u8_t idx) +{ + err_t err; + struct dns_hdr hdr; + struct dns_query qry; + struct pbuf *p; + u16_t query_idx, copy_len; + const char *hostname, *hostname_part; + u8_t n; + u8_t pcb_idx; + struct dns_table_entry *entry = &dns_table[idx]; + + LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", + (u16_t)(entry->server_idx), entry->name)); + LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); + if (ip_addr_isany_val(dns_servers[entry->server_idx]) +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + && !entry->is_mdns +#endif + ) { + /* DNS server not valid anymore, e.g. PPP netif has been shut down */ + /* call specified callback function if provided */ + dns_call_found(idx, NULL); + /* flush this entry */ + entry->state = DNS_STATE_UNUSED; + return ERR_OK; + } + + /* if here, we have either a new query or a retry on a previous query to process */ + p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + + SIZEOF_DNS_QUERY), PBUF_RAM); + if (p != NULL) { + const ip_addr_t *dst; + u16_t dst_port; + /* fill dns header */ + memset(&hdr, 0, SIZEOF_DNS_HDR); + hdr.id = lwip_htons(entry->txid); + hdr.flags1 = DNS_FLAG1_RD; + hdr.numquestions = PP_HTONS(1); + pbuf_take(p, &hdr, SIZEOF_DNS_HDR); + hostname = entry->name; + --hostname; + + /* convert hostname into suitable query format. */ + query_idx = SIZEOF_DNS_HDR; + do { + ++hostname; + hostname_part = hostname; + for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { + ++n; + } + copy_len = (u16_t)(hostname - hostname_part); + if (query_idx + n + 1 > 0xFFFF) { + /* u16_t overflow */ + goto overflow_return; + } + pbuf_put_at(p, query_idx, n); + pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1)); + query_idx = (u16_t)(query_idx + n + 1); + } while (*hostname != 0); + pbuf_put_at(p, query_idx, 0); + query_idx++; + + /* fill dns query */ + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { + qry.type = PP_HTONS(DNS_RRTYPE_AAAA); + } else { + qry.type = PP_HTONS(DNS_RRTYPE_A); + } + qry.cls = PP_HTONS(DNS_RRCLASS_IN); + pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + pcb_idx = entry->pcb_idx; +#else + pcb_idx = 0; +#endif + /* send dns packet */ + LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", + entry->txid, entry->name, entry->server_idx)); +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (entry->is_mdns) { + dst_port = DNS_MQUERY_PORT; +#if LWIP_IPV6 + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { + dst = &dns_mquery_v6group; + } +#endif +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif +#if LWIP_IPV4 + { + dst = &dns_mquery_v4group; + } +#endif + } else +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + dst_port = DNS_SERVER_PORT; + dst = &dns_servers[entry->server_idx]; + } + err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); + + /* free pbuf */ + pbuf_free(p); + } else { + err = ERR_MEM; + } + + return err; +overflow_return: + pbuf_free(p); + return ERR_VAL; +} + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +static struct udp_pcb * +dns_alloc_random_port(void) +{ + err_t err; + struct udp_pcb *pcb; + + pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (pcb == NULL) { + /* out of memory, have to reuse an existing pcb */ + return NULL; + } + do { + u16_t port = (u16_t)DNS_RAND_TXID(); + if (DNS_PORT_ALLOWED(port)) { + err = udp_bind(pcb, IP_ANY_TYPE, port); + } else { + /* this port is not allowed, try again */ + err = ERR_USE; + } + } while (err == ERR_USE); + if (err != ERR_OK) { + udp_remove(pcb); + return NULL; + } + udp_recv(pcb, dns_recv, NULL); + return pcb; +} + +/** + * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used + * for sending a request + * + * @return an index into dns_pcbs + */ +static u8_t +dns_alloc_pcb(void) +{ + u8_t i; + u8_t idx; + + for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { + if (dns_pcbs[i] == NULL) { + break; + } + } + if (i < DNS_MAX_SOURCE_PORTS) { + dns_pcbs[i] = dns_alloc_random_port(); + if (dns_pcbs[i] != NULL) { + /* succeeded */ + dns_last_pcb_idx = i; + return i; + } + } + /* if we come here, creating a new UDP pcb failed, so we have to use + an already existing one (so overflow is no issue) */ + for (i = 0, idx = (u8_t)(dns_last_pcb_idx + 1); i < DNS_MAX_SOURCE_PORTS; i++, idx++) { + if (idx >= DNS_MAX_SOURCE_PORTS) { + idx = 0; + } + if (dns_pcbs[idx] != NULL) { + dns_last_pcb_idx = idx; + return idx; + } + } + return DNS_MAX_SOURCE_PORTS; +} +#endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ + +/** + * dns_call_found() - call the found callback and check if there are duplicate + * entries for the given hostname. If there are any, their found callback will + * be called and they will be removed. + * + * @param idx dns table index of the entry that is resolved or removed + * @param addr IP address for the hostname (or NULL on error or memory shortage) + */ +static void +dns_call_found(u8_t idx, ip_addr_t *addr) +{ +#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) + u8_t i; +#endif + +#if LWIP_IPV4 && LWIP_IPV6 + if (addr != NULL) { + /* check that address type matches the request and adapt the table entry */ + if (IP_IS_V6_VAL(*addr)) { + LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); + dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; + } else { + LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); + dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; + } + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + for (i = 0; i < DNS_MAX_REQUESTS; i++) { + if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { + (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); + /* flush this entry */ + dns_requests[i].found = NULL; + } + } +#else + if (dns_requests[idx].found) { + (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); + } + dns_requests[idx].found = NULL; +#endif +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + /* close the pcb used unless other request are using it */ + for (i = 0; i < DNS_MAX_REQUESTS; i++) { + if (i == idx) { + continue; /* only check other requests */ + } + if (dns_table[i].state == DNS_STATE_ASKING) { + if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { + /* another request is still using the same pcb */ + dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; + break; + } + } + } + if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { + /* if we come here, the pcb is not used any more and can be removed */ + udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); + dns_pcbs[dns_table[idx].pcb_idx] = NULL; + dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; + } +#endif +} + +/* Create a query transmission ID that is unique for all outstanding queries */ +static u16_t +dns_create_txid(void) +{ + u16_t txid; + u8_t i; + +again: + txid = (u16_t)DNS_RAND_TXID(); + + /* check whether the ID is unique */ + for (i = 0; i < DNS_TABLE_SIZE; i++) { + if ((dns_table[i].state == DNS_STATE_ASKING) && + (dns_table[i].txid == txid)) { + /* ID already used by another pending query */ + goto again; + } + } + + return txid; +} + +/** + * Check whether there are other backup DNS servers available to try + */ +static u8_t +dns_backupserver_available(struct dns_table_entry *pentry) +{ + u8_t ret = 0; + + if (pentry) { + if ((pentry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[pentry->server_idx + 1])) { + ret = 1; + } + } + + return ret; +} + +/** + * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. + * Check an entry in the dns_table: + * - send out query for new entries + * - retry old pending entries on timeout (also with different servers) + * - remove completed entries from the table if their TTL has expired + * + * @param i index of the dns_table entry to check + */ +static void +dns_check_entry(u8_t i) +{ + err_t err; + struct dns_table_entry *entry = &dns_table[i]; + + LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); + + switch (entry->state) { + case DNS_STATE_NEW: + /* initialize new entry */ + entry->txid = dns_create_txid(); + entry->state = DNS_STATE_ASKING; + entry->server_idx = 0; + entry->tmr = 1; + entry->retries = 0; + + /* send DNS packet for this entry */ + err = dns_send(i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + break; + case DNS_STATE_ASKING: + if (--entry->tmr == 0) { + if (++entry->retries == DNS_MAX_RETRIES) { + if (dns_backupserver_available(entry) +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + && !entry->is_mdns +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + ) { + /* change of server */ + entry->server_idx++; + entry->tmr = 1; + entry->retries = 0; + } else { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); + /* call specified callback function if provided */ + dns_call_found(i, NULL); + /* flush this entry */ + entry->state = DNS_STATE_UNUSED; + break; + } + } else { + /* wait longer for the next retry */ + entry->tmr = entry->retries; + } + + /* send DNS packet for this entry */ + err = dns_send(i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + } + break; + case DNS_STATE_DONE: + /* if the time to live is nul */ + if ((entry->ttl == 0) || (--entry->ttl == 0)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); + /* flush this entry, there cannot be any related pending entries in this state */ + entry->state = DNS_STATE_UNUSED; + } + break; + case DNS_STATE_UNUSED: + /* nothing to do */ + break; + default: + LWIP_ASSERT("unknown dns_table entry state:", 0); + break; + } +} + +/** + * Call dns_check_entry for each entry in dns_table - check all entries. + */ +static void +dns_check_entries(void) +{ + u8_t i; + + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + dns_check_entry(i); + } +} + +/** + * Save TTL and call dns_call_found for correct response. + */ +static void +dns_correct_response(u8_t idx, u32_t ttl) +{ + struct dns_table_entry *entry = &dns_table[idx]; + + entry->state = DNS_STATE_DONE; + + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); + ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + + /* read the answer resource record's TTL, and maximize it if needed */ + entry->ttl = ttl; + if (entry->ttl > DNS_MAX_TTL) { + entry->ttl = DNS_MAX_TTL; + } + dns_call_found(idx, &entry->ipaddr); + + if (entry->ttl == 0) { + /* RFC 883, page 29: "Zero values are + interpreted to mean that the RR can only be used for the + transaction in progress, and should not be cached." + -> flush this entry now */ + /* entry reused during callback? */ + if (entry->state == DNS_STATE_DONE) { + entry->state = DNS_STATE_UNUSED; + } + } +} + +/** + * Receive input function for DNS response packets arriving for the dns UDP pcb. + */ +static void +dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + u8_t i; + u16_t txid; + u16_t res_idx; + struct dns_hdr hdr; + struct dns_answer ans; + struct dns_query qry; + u16_t nquestions, nanswers; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(port); + + /* is the dns message big enough ? */ + if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); + /* free pbuf and return */ + goto ignore_packet; + } + + /* copy dns payload inside static buffer for processing */ + if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { + /* Match the ID in the DNS header with the name table. */ + txid = lwip_htons(hdr.id); + for (i = 0; i < DNS_TABLE_SIZE; i++) { + struct dns_table_entry *entry = &dns_table[i]; + if ((entry->state == DNS_STATE_ASKING) && + (entry->txid == txid)) { + + /* We only care about the question(s) and the answers. The authrr + and the extrarr are simply discarded. */ + nquestions = lwip_htons(hdr.numquestions); + nanswers = lwip_htons(hdr.numanswers); + + /* Check for correct response. */ + if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); + goto ignore_packet; /* ignore this packet */ + } + if (nquestions != 1) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto ignore_packet; /* ignore this packet */ + } + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (!entry->is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* Check whether response comes from the same network address to which the + question was sent. (RFC 5452) */ + if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { + goto ignore_packet; /* ignore this packet */ + } + } + + /* Check if the name in the "question" part match with the name in the entry and + skip it if equal. */ + res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); + if (res_idx == 0xFFFF) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto ignore_packet; /* ignore this packet */ + } + + /* check if "question" part matches the request */ + if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { + goto ignore_packet; /* ignore this packet */ + } + if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || + (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || + (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto ignore_packet; /* ignore this packet */ + } + /* skip the rest of the "question" part */ + if (res_idx + SIZEOF_DNS_QUERY > 0xFFFF) { + goto ignore_packet; + } + res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY); + + /* Check for error. If so, call callback to inform. */ + if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); + + /* if there is another backup DNS server to try + * then don't stop the DNS request + */ + if (dns_backupserver_available(entry)) { + /* avoid retrying the same server */ + entry->retries = DNS_MAX_RETRIES-1; + entry->tmr = 1; + + /* contact next available server for this entry */ + dns_check_entry(i); + + goto ignore_packet; + } + } else { + while ((nanswers > 0) && (res_idx < p->tot_len)) { + /* skip answer resource record's host name */ + res_idx = dns_skip_name(p, res_idx); + if (res_idx == 0xFFFF) { + goto ignore_packet; /* ignore this packet */ + } + + /* Check for IP address type and Internet class. Others are discarded. */ + if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { + goto ignore_packet; /* ignore this packet */ + } + if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) { + goto ignore_packet; + } + res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER); + + if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { +#if LWIP_IPV4 + if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { +#if LWIP_IPV4 && LWIP_IPV6 + if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + ip4_addr_t ip4addr; + /* read the IP address after answer resource record's header */ + if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { + goto ignore_packet; /* ignore this packet */ + } + ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); + pbuf_free(p); + /* handle correct response */ + dns_correct_response(i, lwip_ntohl(ans.ttl)); + return; + } + } +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_p_t)))) { +#if LWIP_IPV4 && LWIP_IPV6 + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + ip6_addr_p_t ip6addr; + /* read the IP address after answer resource record's header */ + if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_p_t), res_idx) != sizeof(ip6_addr_p_t)) { + goto ignore_packet; /* ignore this packet */ + } + /* @todo: scope ip6addr? Might be required for link-local addresses at least? */ + ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr); + pbuf_free(p); + /* handle correct response */ + dns_correct_response(i, lwip_ntohl(ans.ttl)); + return; + } + } +#endif /* LWIP_IPV6 */ + } + /* skip this answer */ + if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { + goto ignore_packet; /* ignore this packet */ + } + res_idx = (u16_t)(res_idx + lwip_htons(ans.len)); + --nanswers; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || + (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { + if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { + /* IPv4 failed, try IPv6 */ + dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; + } else { + /* IPv6 failed, try IPv4 */ + dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; + } + pbuf_free(p); + dns_table[i].state = DNS_STATE_NEW; + dns_check_entry(i); + return; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); + } + /* call callback to indicate error, clean up memory and return */ + pbuf_free(p); + dns_call_found(i, NULL); + dns_table[i].state = DNS_STATE_UNUSED; + return; + } + } + } + +ignore_packet: + /* deallocate memory and return */ + pbuf_free(p); + return; +} + +/** + * Queues a new hostname to resolve and sends out a DNS query for that hostname + * + * @param name the hostname that is to be queried + * @param hostnamelen length of the hostname + * @param found a callback function to be called on success, failure or timeout + * @param callback_arg argument to pass to the callback function + * @return err_t return code. + */ +static err_t +dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, + void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) +{ + u8_t i; + u8_t lseq, lseqi; + struct dns_table_entry *entry = NULL; + size_t namelen; + struct dns_req_entry *req; + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + u8_t r; + /* check for duplicate entries */ + for (i = 0; i < DNS_TABLE_SIZE; i++) { + if ((dns_table[i].state == DNS_STATE_ASKING) && + (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { +#if LWIP_IPV4 && LWIP_IPV6 + if (dns_table[i].reqaddrtype != dns_addrtype) { + /* requested address types don't match + this can lead to 2 concurrent requests, but mixing the address types + for the same host should not be that common */ + continue; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + /* this is a duplicate entry, find a free request entry */ + for (r = 0; r < DNS_MAX_REQUESTS; r++) { + if (dns_requests[r].found == 0) { + dns_requests[r].found = found; + dns_requests[r].arg = callback_arg; + dns_requests[r].dns_table_idx = i; + LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); + return ERR_INPROGRESS; + } + } + } + } + /* no duplicate entries found */ +#endif + + /* search an unused entry, or the oldest one */ + lseq = 0; + lseqi = DNS_TABLE_SIZE; + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + entry = &dns_table[i]; + /* is it an unused entry ? */ + if (entry->state == DNS_STATE_UNUSED) { + break; + } + /* check if this is the oldest completed entry */ + if (entry->state == DNS_STATE_DONE) { + u8_t age = (u8_t)(dns_seqno - entry->seqno); + if (age > lseq) { + lseq = age; + lseqi = i; + } + } + } + + /* if we don't have found an unused entry, use the oldest completed one */ + if (i == DNS_TABLE_SIZE) { + if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { + /* no entry can be used now, table is full */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); + return ERR_MEM; + } else { + /* use the oldest completed one */ + i = lseqi; + entry = &dns_table[i]; + } + } + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + /* find a free request entry */ + req = NULL; + for (r = 0; r < DNS_MAX_REQUESTS; r++) { + if (dns_requests[r].found == NULL) { + req = &dns_requests[r]; + break; + } + } + if (req == NULL) { + /* no request entry can be used now, table is full */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); + return ERR_MEM; + } + req->dns_table_idx = i; +#else + /* in this configuration, the entry index is the same as the request index */ + req = &dns_requests[i]; +#endif + + /* use this entry */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); + + /* fill the entry */ + entry->state = DNS_STATE_NEW; + entry->seqno = dns_seqno; + LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); + LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); + req->found = found; + req->arg = callback_arg; + namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); + MEMCPY(entry->name, name, namelen); + entry->name[namelen] = 0; + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + entry->pcb_idx = dns_alloc_pcb(); + if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { + /* failed to get a UDP pcb */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); + entry->state = DNS_STATE_UNUSED; + req->found = NULL; + return ERR_MEM; + } + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); +#endif + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + entry->is_mdns = is_mdns; +#endif + + dns_seqno++; + + /* force to send query without waiting timer */ + dns_check_entry(i); + + /* dns query is enqueued */ + return ERR_INPROGRESS; +} + +/** + * @ingroup dns + * Resolve a hostname (string) into an IP address. + * NON-BLOCKING callback version for use with raw API!!! + * + * Returns immediately with one of err_t return codes: + * - ERR_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ERR_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ERR_ARG: dns client not initialized or invalid hostname + * + * @param hostname the hostname that is to be queried + * @param addr pointer to a ip_addr_t where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @return a err_t return code. + */ +err_t +dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg) +{ + return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); +} + +/** + * @ingroup dns + * Like dns_gethostbyname, but returned address type can be controlled: + * @param hostname the hostname that is to be queried + * @param addr pointer to a ip_addr_t where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + */ +err_t +dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg, u8_t dns_addrtype) +{ + size_t hostnamelen; +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + u8_t is_mdns; +#endif + /* not initialized or no valid server yet, or invalid addr pointer + * or invalid hostname or invalid hostname length */ + if ((addr == NULL) || + (!hostname) || (!hostname[0])) { + return ERR_ARG; + } +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) + if (dns_pcbs[0] == NULL) { + return ERR_ARG; + } +#endif + hostnamelen = strlen(hostname); + if (hostnamelen >= DNS_MAX_NAME_LENGTH) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); + return ERR_ARG; + } + + +#if LWIP_HAVE_LOOPIF + if (strcmp(hostname, "localhost") == 0) { + ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); + return ERR_OK; + } +#endif /* LWIP_HAVE_LOOPIF */ + + /* host name already in octet notation? set ip addr and return ERR_OK */ + if (ipaddr_aton(hostname, addr)) { +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || + (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + return ERR_OK; + } + } + /* already have this address cached? */ + if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { + /* fallback to 2nd IP type and try again to lookup */ + u8_t fallback; + if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { + fallback = LWIP_DNS_ADDRTYPE_IPV6; + } else { + fallback = LWIP_DNS_ADDRTYPE_IPV4; + } + if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { + return ERR_OK; + } + } +#else /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_UNUSED_ARG(dns_addrtype); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { + is_mdns = 1; + } else { + is_mdns = 0; + } + + if (!is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* prevent calling found callback if no server is set, return error instead */ + if (ip_addr_isany_val(dns_servers[0])) { + return ERR_VAL; + } + } + + /* queue query with specified callback */ + return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) + LWIP_DNS_ISMDNS_ARG(is_mdns)); +} + +#endif /* LWIP_DNS */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/inet_chksum.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/inet_chksum.c new file mode 100644 index 0000000..818c68f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/inet_chksum.c @@ -0,0 +1,608 @@ +/** + * @file + * Internet checksum functions.\n + * + * These are some reference implementations of the checksum algorithm, with the + * aim of being simple, correct and fully portable. Checksumming is the + * first thing you would want to optimize for your platform. If you create + * your own version, link it in and in your cc.h put: + * + * \#define LWIP_CHKSUM your_checksum_routine + * + * Or you can select from the implementations below by defining + * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet_chksum.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + +#include + +#ifndef LWIP_CHKSUM +# define LWIP_CHKSUM lwip_standard_chksum +# ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 2 +# endif +u16_t lwip_standard_chksum(const void *dataptr, int len); +#endif +/* If none set: */ +#ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 0 +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ +/** + * lwip checksum + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * @note accumulator size limits summable length to 64k + * @note host endianess is irrelevant (p3 RFC1071) + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + u32_t acc; + u16_t src; + const u8_t *octetptr; + + acc = 0; + /* dataptr may be at odd or even addresses */ + octetptr = (const u8_t *)dataptr; + while (len > 1) { + /* declare first octet as most significant + thus assume network order, ignoring host order */ + src = (*octetptr) << 8; + octetptr++; + /* declare second octet as least significant */ + src |= (*octetptr); + octetptr++; + acc += src; + len -= 2; + } + if (len > 0) { + /* accumulate remaining octet */ + src = (*octetptr) << 8; + acc += src; + } + /* add deferred carry bits */ + acc = (acc >> 16) + (acc & 0x0000ffffUL); + if ((acc & 0xffff0000UL) != 0) { + acc = (acc >> 16) + (acc & 0x0000ffffUL); + } + /* This maybe a little confusing: reorder sum using lwip_htons() + instead of lwip_ntohs() since it has a little less call overhead. + The caller must invert bits for Internet sum ! */ + return lwip_htons((u16_t)acc); +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ +/* + * Curt McDowell + * Broadcom Corp. + * csm@broadcom.com + * + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + const u8_t *pb = (const u8_t *)dataptr; + const u16_t *ps; + u16_t t = 0; + u32_t sum = 0; + int odd = ((mem_ptr_t)pb & 1); + + /* Get aligned to u16_t */ + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + /* Add the bulk of the data */ + ps = (const u16_t *)(const void *)pb; + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* Consume left-over byte, if any */ + if (len > 0) { + ((u8_t *)&t)[0] = *(const u8_t *)ps; + } + + /* Add end bytes */ + sum += t; + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + /* Swap if alignment was odd */ + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time. + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + const u8_t *pb = (const u8_t *)dataptr; + const u16_t *ps; + u16_t t = 0; + const u32_t *pl; + u32_t sum = 0, tmp; + /* starts at odd byte address? */ + int odd = ((mem_ptr_t)pb & 1); + + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + ps = (const u16_t *)(const void *)pb; + + if (((mem_ptr_t)ps & 3) && len > 1) { + sum += *ps++; + len -= 2; + } + + pl = (const u32_t *)(const void *)ps; + + while (len > 7) { + tmp = sum + *pl++; /* ping */ + if (tmp < sum) { + tmp++; /* add back carry */ + } + + sum = tmp + *pl++; /* pong */ + if (sum < tmp) { + sum++; /* add back carry */ + } + + len -= 8; + } + + /* make room in upper bits */ + sum = FOLD_U32T(sum); + + ps = (const u16_t *)pl; + + /* 16-bit aligned word remaining? */ + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* dangling tail byte remaining? */ + if (len > 0) { /* include odd byte */ + ((u8_t *)&t)[0] = *(const u8_t *)ps; + } + + sum += t; /* add end bytes */ + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) +{ + struct pbuf *q; + int swapped = 0; + + /* iterate through all pbuf in chain */ + for (q = p; q != NULL; q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + acc += LWIP_CHKSUM(q->payload, q->len); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* just executing this next line is probably faster that the if statement needed + to check whether we really need to execute it, and does no harm */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = !swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)lwip_htons((u16_t)proto); + acc += (u32_t)lwip_htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +#if LWIP_IPV4 +/* inet_chksum_pseudo: + * + * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip4_addr_t *src, const ip4_addr_t *dest) +{ + u32_t acc; + u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + addr = ip4_addr_get_u32(dest); + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dest destination ipv6 address (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip6_addr_t *src, const ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + addr = dest->addr[addr_part]; + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#endif /* LWIP_IPV6 */ + +/* ip_chksum_pseudo: + * + * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip_addr_t *src, const ip_addr_t *dest) +{ +#if LWIP_IPV6 + if (IP_IS_V6(dest)) { + return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest)); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest)); + } +#endif /* LWIP_IPV4 */ +} + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, u32_t acc) +{ + struct pbuf *q; + int swapped = 0; + u16_t chklen; + + /* iterate through all pbuf in chain */ + for (q = p; (q != NULL) && (chksum_len > 0); q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + chklen = q->len; + if (chklen > chksum_len) { + chklen = chksum_len; + } + acc += LWIP_CHKSUM(q->payload, chklen); + chksum_len = (u16_t)(chksum_len - chklen); + LWIP_ASSERT("delete me", chksum_len < 0x7fff); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* fold the upper bit down */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = !swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)lwip_htons((u16_t)proto); + acc += (u32_t)lwip_htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +#if LWIP_IPV4 +/* inet_chksum_pseudo_partial: + * + * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest) +{ + u32_t acc; + u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + addr = ip4_addr_get_u32(dest); + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. Will only compute for a + * portion of the payload. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param chksum_len number of payload bytes used to compute chksum + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dest destination ipv6 address (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + addr = dest->addr[addr_part]; + acc = (u32_t)(acc + (addr & 0xffffUL)); + acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); + } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} +#endif /* LWIP_IPV6 */ + +/* ip_chksum_pseudo_partial: + * + * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest) +{ +#if LWIP_IPV6 + if (IP_IS_V6(dest)) { + return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest)); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest)); + } +#endif /* LWIP_IPV4 */ +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarily for IP + * and ICMP. + * + * @param dataptr start of the buffer to calculate the checksum (no alignment needed) + * @param len length of the buffer to calculate the checksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ + +u16_t +inet_chksum(const void *dataptr, u16_t len) +{ + return (u16_t)~(unsigned int)LWIP_CHKSUM(dataptr, len); +} + +/** + * Calculate a checksum over a chain of pbufs (without pseudo-header, much like + * inet_chksum only pbufs are used). + * + * @param p pbuf chain over that the checksum should be calculated + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ + u32_t acc; + struct pbuf *q; + int swapped = 0; + + acc = 0; + for (q = p; q != NULL; q = q->next) { + acc += LWIP_CHKSUM(q->payload, q->len); + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = !swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + return (u16_t)~(acc & 0xffffUL); +} + +/* These are some implementations for LWIP_CHKSUM_COPY, which copies data + * like MEMCPY but generates a checksum at the same time. Since this is a + * performance-sensitive function, you might want to create your own version + * in assembly targeted at your hardware by defining it in lwipopts.h: + * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) + */ + +#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ +/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. + * For architectures with big caches, data might still be in cache when + * generating the checksum after copying. + */ +u16_t +lwip_chksum_copy(void *dst, const void *src, u16_t len) +{ + MEMCPY(dst, src, len); + return LWIP_CHKSUM(dst, len); +} +#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/init.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/init.c new file mode 100644 index 0000000..3620e1d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/init.c @@ -0,0 +1,381 @@ +/** + * @file + * Modules initialization + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#include "lwip/opt.h" + +#include "lwip/init.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/sockets.h" +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/timeouts.h" +#include "lwip/etharp.h" +#include "lwip/ip6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/api.h" + +#include "netif/ppp/ppp_opts.h" +#include "netif/ppp/ppp_impl.h" + +#ifndef LWIP_SKIP_PACKING_CHECK + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct packed_struct_test { + PACK_STRUCT_FLD_8(u8_t dummy1); + PACK_STRUCT_FIELD(u32_t dummy2); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5 + +#endif + +/* Compile-time sanity checks for configuration errors. + * These can be done independently of LWIP_DEBUG, without penalty. + */ +#ifndef BYTE_ORDER +#error "BYTE_ORDER is not defined, you have to define it in your cc.h" +#endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) +#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_UDPLITE) +#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DHCP) +#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && !LWIP_RAW && LWIP_MULTICAST_TX_OPTIONS) +#error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 and/or LWIP_RAW=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DNS) +#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ +#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) +#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" +#endif +#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) +#error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) +#error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) +#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) +#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS) +#error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && !LWIP_IPV4) +#error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" +#endif +#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) +#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" +#endif +/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < LWIP_NUM_SYS_TIMEOUT_INTERNAL) +#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#endif +#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) +#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" +#endif +#endif /* !MEMP_MEM_MALLOC */ +#if LWIP_WND_SCALE +#if (LWIP_TCP && (TCP_WND > 0xffffffff)) +#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_RCV_SCALE > 14)) +#error "The maximum valid window scale value is 14!" +#endif +#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) +#error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" +#endif +#if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0)) +#error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" +#endif +#else /* LWIP_WND_SCALE */ +#if (LWIP_TCP && (TCP_WND > 0xffff)) +#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" +#endif +#endif /* LWIP_WND_SCALE */ +#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) +#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) +#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" +#endif +#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) +#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" +#endif +#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))) +#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" +#endif +#if (LWIP_TCP && LWIP_TCP_SACK_OUT && !TCP_QUEUE_OOSEQ) +#error "To use LWIP_TCP_SACK_OUT, TCP_QUEUE_OOSEQ needs to be enabled" +#endif +#if (LWIP_TCP && LWIP_TCP_SACK_OUT && (LWIP_TCP_MAX_SACK_NUM < 1)) +#error "LWIP_TCP_MAX_SACK_NUM must be greater than 0" +#endif +#if (LWIP_NETIF_API && (NO_SYS==1)) +#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) +#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if (LWIP_PPP_API && (NO_SYS==1)) +#error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if (LWIP_PPP_API && (PPP_SUPPORT==0)) +#error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) +#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) +#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && LWIP_AUTOIP) +#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) +#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" +#endif +#if (LWIP_ALTCP && LWIP_EVENT_API) +#error "The application layered tcp API does not work with LWIP_EVENT_API" +#endif +#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) +#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" +#endif +#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) +#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" +#endif +#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) +#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" +#endif +#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) +#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" +#endif +#if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT && !PPPOL2TP_SUPPORT +#error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on" +#endif +#if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT +#error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on" +#endif +#if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4 +#error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on" +#endif +#if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6 +#error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" +#endif +#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) +#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" +#endif +#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING +#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" +#endif +#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE +#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" +#endif +#if LWIP_NETCONN && LWIP_TCP +#if NETCONN_COPY != TCP_WRITE_FLAG_COPY +#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" +#endif +#if NETCONN_MORE != TCP_WRITE_FLAG_MORE +#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" +#endif +#endif /* LWIP_NETCONN && LWIP_TCP */ +#if LWIP_NETCONN_FULLDUPLEX && !LWIP_NETCONN_SEM_PER_THREAD +#error "For LWIP_NETCONN_FULLDUPLEX to work, LWIP_NETCONN_SEM_PER_THREAD is required" +#endif + + +/* Compile-time checks for deprecated options. + */ +#ifdef MEMP_NUM_TCPIP_MSG +#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef TCP_REXMIT_DEBUG +#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef RAW_STATS +#error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_QUEUE_FIRST +#error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_ALWAYS_INSERT +#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." +#endif +#if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED) +#error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)" +#endif + +#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS +#define LWIP_DISABLE_TCP_SANITY_CHECKS 0 +#endif +#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 +#endif + +/* MEMP sanity checks */ +#if MEMP_MEM_MALLOC +#if !LWIP_DISABLE_MEMP_SANITY_CHECKS +#if LWIP_NETCONN || LWIP_SOCKET +#if !MEMP_NUM_NETCONN && LWIP_SOCKET +#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!" +#endif +#else /* MEMP_MEM_MALLOC */ +#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) +#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." +#endif +#endif /* LWIP_NETCONN || LWIP_SOCKET */ +#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ +#if MEM_USE_POOLS +#error "MEMP_MEM_MALLOC and MEM_USE_POOLS cannot be enabled at the same time" +#endif +#ifdef LWIP_HOOK_MEMP_AVAILABLE +#error "LWIP_HOOK_MEMP_AVAILABLE doesn't make sense with MEMP_MEM_MALLOC" +#endif +#endif /* MEMP_MEM_MALLOC */ + +/* TCP sanity checks */ +#if !LWIP_DISABLE_TCP_SANITY_CHECKS +#if LWIP_TCP +#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) +#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_BUF < (2 * TCP_MSS) +#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) +#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDLOWAT >= TCP_SND_BUF +#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) +#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" +#endif +#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN +#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) +#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) +#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_WND < TCP_MSS +#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#endif /* LWIP_TCP */ +#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ + +/** + * @ingroup lwip_nosys + * Initialize all modules. + * Use this in NO_SYS mode. Use tcpip_init() otherwise. + */ +void +lwip_init(void) +{ +#ifndef LWIP_SKIP_CONST_CHECK + int a = 0; + LWIP_UNUSED_ARG(a); + LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void *, &a) == &a); +#endif +#ifndef LWIP_SKIP_PACKING_CHECK + LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE); +#endif + + /* Modules initialization */ + stats_init(); +#if !NO_SYS + sys_init(); +#endif /* !NO_SYS */ + mem_init(); + memp_init(); + pbuf_init(); + netif_init(); +#if LWIP_IPV4 + ip_init(); +#if LWIP_ARP + etharp_init(); +#endif /* LWIP_ARP */ +#endif /* LWIP_IPV4 */ +#if LWIP_RAW + raw_init(); +#endif /* LWIP_RAW */ +#if LWIP_UDP + udp_init(); +#endif /* LWIP_UDP */ +#if LWIP_TCP + tcp_init(); +#endif /* LWIP_TCP */ +#if LWIP_IGMP + igmp_init(); +#endif /* LWIP_IGMP */ +#if LWIP_DNS + dns_init(); +#endif /* LWIP_DNS */ +#if PPP_SUPPORT + ppp_init(); +#endif + +#if LWIP_TIMERS + sys_timeouts_init(); +#endif /* LWIP_TIMERS */ +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ip.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ip.c new file mode 100644 index 0000000..18514cf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ip.c @@ -0,0 +1,167 @@ +/** + * @file + * Common IPv4 and IPv6 code + * + * @defgroup ip IP + * @ingroup callbackstyle_api + * + * @defgroup ip4 IPv4 + * @ingroup ip + * + * @defgroup ip6 IPv6 + * @ingroup ip + * + * @defgroup ipaddr IP address handling + * @ingroup infrastructure + * + * @defgroup ip4addr IPv4 only + * @ingroup ipaddr + * + * @defgroup ip6addr IPv6 only + * @ingroup ipaddr + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 || LWIP_IPV6 + +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +/** Global data for both IPv4 and IPv6 */ +struct ip_globals ip_data; + +#if LWIP_IPV4 && LWIP_IPV6 + +const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT; + +/** + * @ingroup ipaddr + * Convert numeric IP address (both versions) into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char *ipaddr_ntoa(const ip_addr_t *addr) +{ + if (addr == NULL) { + return NULL; + } + if (IP_IS_V6(addr)) { + return ip6addr_ntoa(ip_2_ip6(addr)); + } else { + return ip4addr_ntoa(ip_2_ip4(addr)); + } +} + +/** + * @ingroup ipaddr + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) +{ + if (addr == NULL) { + return NULL; + } + if (IP_IS_V6(addr)) { + return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen); + } else { + return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen); + } +} + +/** + * @ingroup ipaddr + * Convert IP address string (both versions) to numeric. + * The version is auto-detected from the string. + * + * @param cp IP address string to convert + * @param addr conversion result is stored here + * @return 1 on success, 0 on error + */ +int +ipaddr_aton(const char *cp, ip_addr_t *addr) +{ + if (cp != NULL) { + const char *c; + for (c = cp; *c != 0; c++) { + if (*c == ':') { + /* contains a colon: IPv6 address */ + if (addr) { + IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); + } + return ip6addr_aton(cp, ip_2_ip6(addr)); + } else if (*c == '.') { + /* contains a dot: IPv4 address */ + break; + } + } + /* call ip4addr_aton as fallback or if IPv4 was found */ + if (addr) { + IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); + } + return ip4addr_aton(cp, ip_2_ip4(addr)); + } + return 0; +} + +/** + * @ingroup lwip_nosys + * If both IP versions are enabled, this function can dispatch packets to the correct one. + * Don't call directly, pass to netif_add() and call netif->input(). + */ +err_t +ip_input(struct pbuf *p, struct netif *inp) +{ + if (p != NULL) { + if (IP_HDR_GET_VERSION(p->payload) == 6) { + return ip6_input(p, inp); + } + return ip4_input(p, inp); + } + return ERR_VAL; +} + +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/autoip.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/autoip.c new file mode 100644 index 0000000..9f7139b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/autoip.c @@ -0,0 +1,527 @@ +/** + * @file + * AutoIP Automatic LinkLocal IP Configuration + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * @defgroup autoip AUTOIP + * @ingroup ip4 + * AUTOIP related functions + * USAGE: + * + * define @ref LWIP_AUTOIP 1 in your lwipopts.h + * Options: + * AUTOIP_TMR_INTERVAL msecs, + * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. + * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + * + * Without DHCP: + * - Call autoip_start() after netif_add(). + * + * With DHCP: + * - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. + * - Configure your DHCP Client. + * + * @see netifapi_autoip + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Dominik Spies + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +/* #include "lwip/udp.h" */ +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/autoip.h" +#include "lwip/etharp.h" +#include "lwip/prot/autoip.h" + +#include + +/** Pseudo random macro based on netif informations. + * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ +#ifndef LWIP_AUTOIP_RAND +#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ + ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ + ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ + ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ + (netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0)) +#endif /* LWIP_AUTOIP_RAND */ + +/** + * Macro that generates the initial IP address to be tried by AUTOIP. + * If you want to override this, define it to something else in lwipopts.h. + */ +#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR +#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ + lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ + ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) +#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ + +/* static functions */ +static err_t autoip_arp_announce(struct netif *netif); +static void autoip_start_probing(struct netif *netif); + +/** + * @ingroup autoip + * Set a statically allocated struct autoip to work with. + * Using this prevents autoip_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct autoip + * @param autoip (uninitialised) autoip struct allocated by the application + */ +void +autoip_set_struct(struct netif *netif, struct autoip *autoip) +{ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("autoip != NULL", autoip != NULL); + LWIP_ASSERT("netif already has a struct autoip set", + netif_autoip_data(netif) == NULL); + + /* clear data structure */ + memset(autoip, 0, sizeof(struct autoip)); + /* autoip->state = AUTOIP_STATE_OFF; */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); +} + +/** Restart AutoIP client and check the next address (conflict detected) + * + * @param netif The netif under AutoIP control + */ +static void +autoip_restart(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + autoip->tried_llipaddr++; + autoip_start(netif); +} + +/** + * Handle a IP address conflict after an ARP conflict detection + */ +static void +autoip_handle_arp_conflict(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + + /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where + a) means retreat on the first conflict and + b) allows to keep an already configured address when having only one + conflict in 10 seconds + We use option b) since it helps to improve the chance that one of the two + conflicting hosts may be able to retain its address. */ + + if (autoip->lastconflict > 0) { + /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + + /* Active TCP sessions are aborted when removing the ip addresss */ + autoip_restart(netif); + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); + autoip_arp_announce(netif); + autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } +} + +/** + * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * + * @param netif network interface on which create the IP-Address + * @param ipaddr ip address to initialize + */ +static void +autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr) +{ + struct autoip *autoip = netif_autoip_data(netif); + + /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * compliant to RFC 3927 Section 2.1 + * We have 254 * 256 possibilities */ + + u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); + addr += autoip->tried_llipaddr; + addr = AUTOIP_NET | (addr & 0xffff); + /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ + + if (addr < AUTOIP_RANGE_START) { + addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + if (addr > AUTOIP_RANGE_END) { + addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && + (addr <= AUTOIP_RANGE_END)); + ip4_addr_set_u32(ipaddr, lwip_htonl(addr)); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), + ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); +} + +/** + * Sends an ARP probe from a network interface + * + * @param netif network interface used to send the probe + */ +static err_t +autoip_arp_probe(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + /* this works because netif->ip_addr is ANY */ + return etharp_request(netif, &autoip->llipaddr); +} + +/** + * Sends an ARP announce from a network interface + * + * @param netif network interface used to send the announce + */ +static err_t +autoip_arp_announce(struct netif *netif) +{ + return etharp_gratuitous(netif); +} + +/** + * Configure interface for use with current LL IP-Address + * + * @param netif network interface to configure with current LL IP-Address + */ +static err_t +autoip_bind(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + ip4_addr_t sn_mask, gw_addr; + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num, + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + + IP4_ADDR(&sn_mask, 255, 255, 0, 0); + IP4_ADDR(&gw_addr, 0, 0, 0, 0); + + netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr); + /* interface is used by routing now that an address is set */ + + return ERR_OK; +} + +/** + * @ingroup autoip + * Start AutoIP client + * + * @param netif network interface on which start the AutoIP client + */ +err_t +autoip_start(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + err_t result = ERR_OK; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); + + /* Set IP-Address, Netmask and Gateway to 0 to make sure that + * ARP Packets are formed correctly + */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + if (autoip == NULL) { + /* no AutoIP client attached yet? */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): starting new AUTOIP client\n")); + autoip = (struct autoip *)mem_calloc(1, sizeof(struct autoip)); + if (autoip == NULL) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): could not allocate autoip\n")); + return ERR_MEM; + } + /* store this AutoIP client in the netif */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); + } else { + autoip->state = AUTOIP_STATE_OFF; + autoip->ttw = 0; + autoip->sent_num = 0; + ip4_addr_set_zero(&autoip->llipaddr); + autoip->lastconflict = 0; + } + + autoip_create_addr(netif, &(autoip->llipaddr)); + autoip_start_probing(netif); + + return result; +} + +static void +autoip_start_probing(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + + autoip->state = AUTOIP_STATE_PROBING; + autoip->sent_num = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + + /* time to wait to first probe, this is randomly + * chosen out of 0 to PROBE_WAIT seconds. + * compliant to RFC 3927 Section 2.2.1 + */ + autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); + + /* + * if we tried more then MAX_CONFLICTS we must limit our rate for + * acquiring and probing address + * compliant to RFC 3927 Section 2.2.1 + */ + if (autoip->tried_llipaddr > MAX_CONFLICTS) { + autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } +} + +/** + * Handle a possible change in the network configuration. + * + * If there is an AutoIP address configured, take the interface down + * and begin probing with the same address. + */ +void +autoip_network_changed(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + + if (autoip && (autoip->state != AUTOIP_STATE_OFF)) { + autoip_start_probing(netif); + } +} + +/** + * @ingroup autoip + * Stop AutoIP client + * + * @param netif network interface on which stop the AutoIP client + */ +err_t +autoip_stop(struct netif *netif) +{ + struct autoip *autoip = netif_autoip_data(netif); + + LWIP_ASSERT_CORE_LOCKED(); + if (autoip != NULL) { + autoip->state = AUTOIP_STATE_OFF; + if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + } + } + return ERR_OK; +} + +/** + * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds + */ +void +autoip_tmr(void) +{ + struct netif *netif; + /* loop through netif's */ + NETIF_FOREACH(netif) { + struct autoip *autoip = netif_autoip_data(netif); + /* only act on AutoIP configured interfaces */ + if (autoip != NULL) { + if (autoip->lastconflict > 0) { + autoip->lastconflict--; + } + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", + (u16_t)(autoip->state), autoip->ttw)); + + if (autoip->ttw > 0) { + autoip->ttw--; + } + + switch (autoip->state) { + case AUTOIP_STATE_PROBING: + if (autoip->ttw == 0) { + if (autoip->sent_num >= PROBE_NUM) { + /* Switch to ANNOUNCING: now we can bind to an IP address and use it */ + autoip->state = AUTOIP_STATE_ANNOUNCING; + autoip_bind(netif); + /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP + which counts as an announcement */ + autoip->sent_num = 1; + autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + } else { + autoip_arp_probe(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); + autoip->sent_num++; + if (autoip->sent_num == PROBE_NUM) { + /* calculate time to wait to for announce */ + autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + } else { + /* calculate time to wait to next probe */ + autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % + ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + + PROBE_MIN * AUTOIP_TICKS_PER_SECOND); + } + } + } + break; + + case AUTOIP_STATE_ANNOUNCING: + if (autoip->ttw == 0) { + autoip_arp_announce(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); + autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; + autoip->sent_num++; + + if (autoip->sent_num >= ANNOUNCE_NUM) { + autoip->state = AUTOIP_STATE_BOUND; + autoip->sent_num = 0; + autoip->ttw = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + } + } + break; + + default: + /* nothing to do in other states */ + break; + } + } + } +} + +/** + * Handles every incoming ARP Packet, called by etharp_input(). + * + * @param netif network interface to use for autoip processing + * @param hdr Incoming ARP packet + */ +void +autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + struct autoip *autoip = netif_autoip_data(netif); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); + if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) { + /* when ip.src == llipaddr && hw.src != netif->hwaddr + * + * when probing ip.dst == llipaddr && hw.src != netif->hwaddr + * we have a conflict and must solve it + */ + ip4_addr_t sipaddr, dipaddr; + struct eth_addr netifaddr; + SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN); + + /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). + */ + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); + + if (autoip->state == AUTOIP_STATE_PROBING) { + /* RFC 3927 Section 2.2.1: + * from beginning to after ANNOUNCE_WAIT + * seconds we have a conflict if + * ip.src == llipaddr OR + * ip.dst == llipaddr && hw.src != own hwaddr + */ + if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) || + (ip4_addr_isany_val(sipaddr) && + ip4_addr_cmp(&dipaddr, &autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Probe Conflict detected\n")); + autoip_restart(netif); + } + } else { + /* RFC 3927 Section 2.5: + * in any state we have a conflict if + * ip.src == llipaddr && hw.src != own hwaddr + */ + if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); + autoip_handle_arp_conflict(netif); + } + } + } +} + +/** check if AutoIP supplied netif->ip_addr + * + * @param netif the netif to check + * @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING), + * 0 otherwise + */ +u8_t +autoip_supplied_address(const struct netif *netif) +{ + if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) { + struct autoip *autoip = netif_autoip_data(netif); + return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING); + } + return 0; +} + +u8_t +autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr) +{ + struct autoip *autoip = netif_autoip_data(netif); + return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr)); +} + +#endif /* LWIP_IPV4 && LWIP_AUTOIP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/dhcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/dhcp.c new file mode 100644 index 0000000..76b9f68 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/dhcp.c @@ -0,0 +1,1991 @@ +/** + * @file + * Dynamic Host Configuration Protocol client + * + * @defgroup dhcp4 DHCPv4 + * @ingroup ip4 + * DHCP (IPv4) related functions + * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform + * with RFC 2131 and RFC 2132. + * + * @todo: + * - Support for interfaces other than Ethernet (SLIP, PPP, ...) + * + * Options: + * @ref DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) + * @ref DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) + * + * dhcp_start() starts a DHCP client instance which + * configures the interface by obtaining an IP address lease and maintaining it. + * + * Use dhcp_release() to end the lease and use dhcp_stop() + * to remove the DHCP client. + * + * @see LWIP_HOOK_DHCP_APPEND_OPTIONS + * @see LWIP_HOOK_DHCP_PARSE_OPTION + * + * @see netifapi_dhcp4 + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. + * + * Author: Leon Woestenberg + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/dns.h" +#include "lwip/etharp.h" +#include "lwip/prot/dhcp.h" +#include "lwip/prot/iana.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif +#ifndef LWIP_HOOK_DHCP_APPEND_OPTIONS +#define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) +#endif +#ifndef LWIP_HOOK_DHCP_PARSE_OPTION +#define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) +#endif + +/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using + * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) + */ +#ifndef DHCP_CREATE_RAND_XID +#define DHCP_CREATE_RAND_XID 1 +#endif + +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + * \#define DHCP_GLOBAL_XID_HEADER "stdlib.h" + * \#define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * MTU is checked to be big enough in dhcp_start */ +#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) +#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 +/** Minimum length for reply before packet is parsed */ +#define DHCP_MIN_REPLY_LEN 44 + +#define REBOOT_TRIES 2 + +#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS +#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS +#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS +#endif +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 +#endif + +#ifndef LWIP_DHCP_INPUT_ERROR +#define LWIP_DHCP_INPUT_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;} } while(0) +#endif + +/** Option handling: options are parsed in dhcp_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +enum dhcp_option_idx { + DHCP_OPTION_IDX_OVERLOAD = 0, + DHCP_OPTION_IDX_MSG_TYPE, + DHCP_OPTION_IDX_SERVER_ID, + DHCP_OPTION_IDX_LEASE_TIME, + DHCP_OPTION_IDX_T1, + DHCP_OPTION_IDX_T2, + DHCP_OPTION_IDX_SUBNET_MASK, + DHCP_OPTION_IDX_ROUTER, +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + DHCP_OPTION_IDX_DNS_SERVER, + DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP_GET_NTP_SRV + DHCP_OPTION_IDX_NTP_SERVER, + DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, +#endif /* LWIP_DHCP_GET_NTP_SRV */ + DHCP_OPTION_IDX_MAX +}; + +/** Holds the decoded option values, only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; +/** Holds a flag which option was received and is contained in dhcp_rx_options_val, + only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; + +static u8_t dhcp_discover_request_options[] = { + DHCP_OPTION_SUBNET_MASK, + DHCP_OPTION_ROUTER, + DHCP_OPTION_BROADCAST +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + , DHCP_OPTION_DNS_SERVER +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP_GET_NTP_SRV + , DHCP_OPTION_NTP +#endif /* LWIP_DHCP_GET_NTP_SRV */ +}; + +#ifdef DHCP_GLOBAL_XID +static u32_t xid; +static u8_t xid_initialised; +#endif /* DHCP_GLOBAL_XID */ + +#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) + +static struct udp_pcb *dhcp_pcb; +static u8_t dhcp_pcb_refcount; + +/* DHCP client state machine functions */ +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_bind(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +static err_t dhcp_decline(struct netif *netif); +#endif /* DHCP_DOES_ARP_CHECK */ +static err_t dhcp_rebind(struct netif *netif); +static err_t dhcp_reboot(struct netif *netif); +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); + +/* receive, unfold, parse and free incoming messages */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + +/* set the DHCP timers */ +static void dhcp_timeout(struct netif *netif); +static void dhcp_t1_timeout(struct netif *netif); +static void dhcp_t2_timeout(struct netif *netif); + +/* build outgoing messages */ +/* create a DHCP message, fill in common headers */ +static struct pbuf *dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len); +/* add a DHCP option (type, then length in bytes) */ +static u16_t dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len); +/* add option values */ +static u16_t dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value); +static u16_t dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value); +static u16_t dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value); +#if LWIP_NETIF_HOSTNAME +static u16_t dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif); +#endif /* LWIP_NETIF_HOSTNAME */ +/* always add the DHCP options trailer to end and pad */ +static void dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out); + +/** Ensure DHCP PCB is allocated and bound */ +static err_t +dhcp_inc_pcb_refcount(void) +{ + if (dhcp_pcb_refcount == 0) { + LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL); + + /* allocate UDP PCB */ + dhcp_pcb = udp_new(); + + if (dhcp_pcb == NULL) { + return ERR_MEM; + } + + ip_set_option(dhcp_pcb, SOF_BROADCAST); + + /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ + udp_bind(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT); + udp_connect(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER); + udp_recv(dhcp_pcb, dhcp_recv, NULL); + } + + dhcp_pcb_refcount++; + + return ERR_OK; +} + +/** Free DHCP PCB if the last netif stops using it */ +static void +dhcp_dec_pcb_refcount(void) +{ + LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0)); + dhcp_pcb_refcount--; + + if (dhcp_pcb_refcount == 0) { + udp_remove(dhcp_pcb); + dhcp_pcb = NULL; + } +} + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We clear any existing set IP address and restart DHCP negotiation + * afresh (as per RFC2131 3.2.3). + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_nak(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", + (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* Change to a defined state - set this before assigning the address + to ensure the callback can use dhcp_supplied_address() */ + dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + /* remove IP address from interface (must no longer be used, as per RFC2131) */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + /* We can immediately restart discovery */ + dhcp_discover(netif); +} + +#if DHCP_DOES_ARP_CHECK +/** + * Checks if the offered IP address is already in use. + * + * It does so by sending an ARP request for the offered address and + * entering CHECKING state. If no ARP reply is received within a small + * interval, the address is assumed to be free for use by us. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_check(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], + (s16_t)netif->name[1])); + dhcp_set_state(dhcp, DHCP_STATE_CHECKING); + /* create an ARP query for the offered IP address, expecting that no host + responds, as the IP address should not be in use. */ + result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); + if (result != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = 500; + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); +} +#endif /* DHCP_DOES_ARP_CHECK */ + +/** + * Remember the configuration offered by a DHCP server. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_offer(struct netif *netif, struct dhcp_msg *msg_in) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", + (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* obtain the server address */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { + dhcp->request_timeout = 0; /* stop timer */ + + ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", + ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); + /* remember offered address */ + ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void *)netif)); + } +} + +/** + * Select a DHCP server offer out of all offers. + * + * Simply select the first offer received. + * + * @param netif the netif under DHCP control + * @return lwIP specific error (see error.h) + */ +static err_t +dhcp_select(struct netif *netif) +{ + struct dhcp *dhcp; + err_t result; + u16_t msecs; + u8_t i; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_ERROR("dhcp_select: netif != NULL", (netif != NULL), return ERR_ARG;); + dhcp = netif_dhcp_data(netif); + LWIP_ERROR("dhcp_select: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + dhcp_set_state(dhcp, DHCP_STATE_REQUESTING); + + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); + + /* MUST request the offered IP address */ + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); + options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); + options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REQUESTING, msg_out, DHCP_REQUEST, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + /* send broadcast to any DHCP server */ + result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); + result = ERR_MEM; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * The DHCP timer that checks for lease renewal/rebind timeouts. + * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS). + */ +void +dhcp_coarse_tmr(void) +{ + struct netif *netif; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); + /* iterate through all network interfaces */ + NETIF_FOREACH(netif) { + /* only act on DHCP configured interfaces */ + struct dhcp *dhcp = netif_dhcp_data(netif); + if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { + /* compare lease time to expire timeout */ + if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n")); + /* this clients' lease time has expired */ + dhcp_release_and_stop(netif); + dhcp_start(netif); + /* timer is active (non zero), and triggers (zeroes) now? */ + } else if (dhcp->t2_rebind_time && (dhcp->t2_rebind_time-- == 1)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); + /* this clients' rebind timeout triggered */ + dhcp_t2_timeout(netif); + /* timer is active (non zero), and triggers (zeroes) now */ + } else if (dhcp->t1_renew_time && (dhcp->t1_renew_time-- == 1)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); + /* this clients' renewal timeout triggered */ + dhcp_t1_timeout(netif); + } + } + } +} + +/** + * DHCP transaction timeout handling (this function must be called every 500ms, + * see @ref DHCP_FINE_TIMER_MSECS). + * + * A DHCP server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCP request is timed out. + */ +void +dhcp_fine_tmr(void) +{ + struct netif *netif; + /* loop through netif's */ + NETIF_FOREACH(netif) { + struct dhcp *dhcp = netif_dhcp_data(netif); + /* only act on DHCP configured interfaces */ + if (dhcp != NULL) { + /* timer is active (non zero), and is about to trigger now */ + if (dhcp->request_timeout > 1) { + dhcp->request_timeout--; + } else if (dhcp->request_timeout == 1) { + dhcp->request_timeout--; + /* { dhcp->request_timeout == 0 } */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); + /* this client's request timeout triggered */ + dhcp_timeout(netif); + } + } + } +} + +/** + * A DHCP negotiation transaction, or ARP request, has timed out. + * + * The timer that was started with the DHCP or ARP request has + * timed out, indicating no response was received in time. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); + /* back-off period has passed, or server selection timed out */ + if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); + dhcp_discover(netif); + /* receiving the requested lease timed out */ + } else if (dhcp->state == DHCP_STATE_REQUESTING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); + if (dhcp->tries <= 5) { + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); + dhcp_release_and_stop(netif); + dhcp_start(netif); + } +#if DHCP_DOES_ARP_CHECK + /* received no ARP reply for the offered address (which is good) */ + } else if (dhcp->state == DHCP_STATE_CHECKING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); + if (dhcp->tries <= 1) { + dhcp_check(netif); + /* no ARP replies on the offered address, + looks like the IP address is indeed free */ + } else { + /* bind the interface to the offered address */ + dhcp_bind(netif); + } +#endif /* DHCP_DOES_ARP_CHECK */ + } else if (dhcp->state == DHCP_STATE_REBOOTING) { + if (dhcp->tries < REBOOT_TRIES) { + dhcp_reboot(netif); + } else { + dhcp_discover(netif); + } + } +} + +/** + * The renewal period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t1_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); + if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || + (dhcp->state == DHCP_STATE_RENEWING)) { + /* just retry to renew - note that the rebind timer (t2) will + * eventually time-out if renew tries fail. */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t1_timeout(): must renew\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ + dhcp_renew(netif); + /* Calculate next timeout */ + if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { + dhcp->t1_renew_time = (u16_t)((dhcp->t2_timeout - dhcp->lease_used) / 2); + } + } +} + +/** + * The rebind period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t2_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); + if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || + (dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) { + /* just retry to rebind */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t2_timeout(): must rebind\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */ + dhcp_rebind(netif); + /* Calculate next timeout */ + if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { + dhcp->t2_rebind_time = (u16_t)((dhcp->t0_timeout - dhcp->lease_used) / 2); + } + } +} + +/** + * Handle a DHCP ACK packet + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + +#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV + u8_t n; +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */ +#if LWIP_DHCP_GET_NTP_SRV + ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; +#endif + + /* clear options we might not get from the ACK */ + ip4_addr_set_zero(&dhcp->offered_sn_mask); + ip4_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* lease time given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { + /* remember offered lease time */ + dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); + } + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { + /* remember given renewal period */ + dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); + } else { + /* calculate safe periods for renewal */ + dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; + } + + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { + /* remember given rebind period */ + dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); + } else { + /* calculate safe periods for rebinding (offered_t0_lease * 0.875 -> 87.5%)*/ + dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U; + } + + /* (y)our internet address */ + ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr); + +#if LWIP_DHCP_BOOTP_FILE + /* copy boot server address, + boot file name copied in dhcp_parse_reply if not overloaded */ + ip4_addr_copy(dhcp->offered_si_addr, msg_in->siaddr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* subnet mask given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { + /* remember given subnet mask */ + ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); + dhcp->subnet_mask_given = 1; + } else { + dhcp->subnet_mask_given = 0; + } + + /* gateway router */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { + ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); + } + +#if LWIP_DHCP_GET_NTP_SRV + /* NTP servers */ + for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) { + ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n))); + } + dhcp_set_ntp_servers(n, ntp_server_addrs); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + /* DNS servers */ + for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { + ip_addr_t dns_addr; + ip_addr_set_ip4_u32_val(dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); + dns_setserver(n, &dns_addr); + } +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +} + +/** + * @ingroup dhcp4 + * Set a statically allocated struct dhcp to work with. + * Using this prevents dhcp_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct dhcp + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void +dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) +{ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp != NULL", dhcp != NULL); + LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL); + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); +} + +/** + * @ingroup dhcp4 + * Removes a struct dhcp from a netif. + * + * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the + * struct dhcp since the memory is passed back to the heap. + * + * @param netif the netif from which to remove the struct dhcp + */ +void dhcp_cleanup(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + + if (netif_dhcp_data(netif) != NULL) { + mem_free(netif_dhcp_data(netif)); + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL); + } +} + +/** + * @ingroup dhcp4 + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + */ +err_t +dhcp_start(struct netif *netif) +{ + struct dhcp *dhcp; + err_t result; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); + LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); + dhcp = netif_dhcp_data(netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* check MTU of the netif */ + if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); + return ERR_MEM; + } + + /* no DHCP client attached yet? */ + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new DHCP client\n")); + dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); + return ERR_MEM; + } + + /* store this dhcp client in the netif */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); + /* already has DHCP client attached */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); + + if (dhcp->pcb_allocated != 0) { + dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ + } + /* dhcp is cleared below, no need to reset flag*/ + } + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); + + if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ + return ERR_MEM; + } + dhcp->pcb_allocated = 1; + + if (!netif_is_link_up(netif)) { + /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */ + dhcp_set_state(dhcp, DHCP_STATE_INIT); + return ERR_OK; + } + + /* (re)start the DHCP negotiation */ + result = dhcp_discover(netif); + if (result != ERR_OK) { + /* free resources allocated above */ + dhcp_release_and_stop(netif); + return ERR_MEM; + } + return result; +} + +/** + * @ingroup dhcp4 + * Inform a DHCP server of our manual configuration. + * + * This informs DHCP servers of our fixed IP address configuration + * by sending an INFORM message. It does not involve DHCP address + * configuration, it is just here to be nice to the network. + * + * @param netif The lwIP network interface + */ +void +dhcp_inform(struct netif *netif) +{ + struct dhcp dhcp; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ + return; + } + + memset(&dhcp, 0, sizeof(struct dhcp)); + dhcp_set_state(&dhcp, DHCP_STATE_INFORMING); + + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, &dhcp, DHCP_INFORM, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, &dhcp, DHCP_STATE_INFORMING, msg_out, DHCP_INFORM, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); + + udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); + + pbuf_free(p_out); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); + } + + dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */ +} + +/** Handle a possible change in the network configuration. + * + * This enters the REBOOTING state to verify that the currently bound + * address is still valid. + */ +void +dhcp_network_changed(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + if (!dhcp) { + return; + } + switch (dhcp->state) { + case DHCP_STATE_REBINDING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_BOUND: + case DHCP_STATE_REBOOTING: + dhcp->tries = 0; + dhcp_reboot(netif); + break; + case DHCP_STATE_OFF: + /* stay off */ + break; + default: + LWIP_ASSERT("invalid dhcp->state", dhcp->state <= DHCP_STATE_BACKING_OFF); + /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the + state changes, SELECTING: continue with current 'rid' as we stay in the + same state */ +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + /* ensure we start with short timeouts, even if already discovering */ + dhcp->tries = 0; + dhcp_discover(netif); + break; + } +} + +#if DHCP_DOES_ARP_CHECK +/** + * Match an ARP reply with the offered IP address: + * check whether the offered IP address is not in use using ARP + * + * @param netif the network interface on which the reply was received + * @param addr The IP address we received a reply from + */ +void +dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) +{ + struct dhcp *dhcp; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + dhcp = netif_dhcp_data(netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); + /* is a DHCP client doing an ARP check? */ + if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", + ip4_addr_get_u32(addr))); + /* did a host respond with the address we + were offered by the DHCP server? */ + if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) { + /* we will not accept the offered address */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); + dhcp_decline(netif); + } + } +} + +/** + * Decline an offered lease. + * + * Tell the DHCP server we do not accept the offered address. + * One reason to decline the lease is when we find out the address + * is already in use by another host (through ARP). + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_decline(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); + dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); + options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_BACKING_OFF, msg_out, DHCP_DECLINE, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + /* per section 4.4.4, broadcast DECLINE messages */ + result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_decline: could not allocate DHCP request\n")); + result = ERR_MEM; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = 10 * 1000; + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} +#endif /* DHCP_DOES_ARP_CHECK */ + + +/** + * Start the DHCP process, discover a DHCP server. + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_discover(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result = ERR_OK; + u16_t msecs; + u8_t i; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); + + ip4_addr_set_any(&dhcp->offered_ip_addr); + dhcp_set_state(dhcp, DHCP_STATE_SELECTING); + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); + } + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_SELECTING, msg_out, DHCP_DISCOVER, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n")); + udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; + autoip_start(netif); + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * Bind the interface to the offered IP address. + * + * @param netif network interface to bind to the offered address + */ +static void +dhcp_bind(struct netif *netif) +{ + u32_t timeout; + struct dhcp *dhcp; + ip4_addr_t sn_mask, gw_addr; + LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); + dhcp = netif_dhcp_data(netif); + LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* reset time used of lease */ + dhcp->lease_used = 0; + + if (dhcp->offered_t0_lease != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); + timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t0_timeout = (u16_t)timeout; + if (dhcp->t0_timeout == 0) { + dhcp->t0_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000)); + } + + /* temporary DHCP lease? */ + if (dhcp->offered_t1_renew != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); + timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t1_timeout = (u16_t)timeout; + if (dhcp->t1_timeout == 0) { + dhcp->t1_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew * 1000)); + dhcp->t1_renew_time = dhcp->t1_timeout; + } + /* set renewal period timer */ + if (dhcp->offered_t2_rebind != 0xffffffffUL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); + timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t2_timeout = (u16_t)timeout; + if (dhcp->t2_timeout == 0) { + dhcp->t2_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind * 1000)); + dhcp->t2_rebind_time = dhcp->t2_timeout; + } + + /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ + if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { + dhcp->t1_timeout = 0; + } + + if (dhcp->subnet_mask_given) { + /* copy offered network mask */ + ip4_addr_copy(sn_mask, dhcp->offered_sn_mask); + } else { + /* subnet mask not given, choose a safe subnet mask given the network class */ + u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); + if (first_octet <= 127) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); + } else if (first_octet >= 192) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); + } else { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); + } + } + + ip4_addr_copy(gw_addr, dhcp->offered_gw_addr); + +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr))); + /* netif is now bound to DHCP leased address - set this before assigning the address + to ensure the callback can use dhcp_supplied_address() */ + dhcp_set_state(dhcp, DHCP_STATE_BOUND); + + netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr); + /* interface is used by routing now that an address is set */ +} + +/** + * @ingroup dhcp4 + * Renew an existing DHCP lease at the involved DHCP server. + * + * @param netif network interface which must renew its lease + */ +err_t +dhcp_renew(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); + dhcp_set_state(dhcp, DHCP_STATE_RENEWING); + + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_RENEWING, msg_out, DHCP_REQUEST, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + result = udp_sendto_if(dhcp_pcb, p_out, &dhcp->server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); + pbuf_free(p_out); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); + result = ERR_MEM; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + /* back-off on retries, but to a maximum of 20 seconds */ + msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000); + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Rebind with a DHCP server for an existing DHCP lease. + * + * @param netif network interface which must rebind with a DHCP server + */ +static err_t +dhcp_rebind(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); + dhcp_set_state(dhcp, DHCP_STATE_REBINDING); + + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBINDING, msg_out, DHCP_DISCOVER, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + /* broadcast to server */ + result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); + result = ERR_MEM; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Enter REBOOTING state to verify an existing lease + * + * @param netif network interface which must reboot + */ +static err_t +dhcp_reboot(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + struct pbuf *p_out; + u16_t options_out_len; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); + dhcp_set_state(dhcp, DHCP_STATE_REBOOTING); + + /* create and initialize the DHCP message header */ + p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN_MIN_REQUIRED); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); + options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBOOTING, msg_out, DHCP_REQUEST, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + /* broadcast to server */ + result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); + result = ERR_MEM; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); + dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * @ingroup dhcp4 + * Release a DHCP lease and stop DHCP statemachine (and AUTOIP if LWIP_DHCP_AUTOIP_COOP). + * + * @param netif network interface + */ +void +dhcp_release_and_stop(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + ip_addr_t server_ip_addr; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release_and_stop()\n")); + if (dhcp == NULL) { + return; + } + + /* already off? -> nothing to do */ + if (dhcp->state == DHCP_STATE_OFF) { + return; + } + + ip_addr_copy(server_ip_addr, dhcp->server_ip_addr); + + /* clean old DHCP offer */ + ip_addr_set_zero_ip4(&dhcp->server_ip_addr); + ip4_addr_set_zero(&dhcp->offered_ip_addr); + ip4_addr_set_zero(&dhcp->offered_sn_mask); + ip4_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; + dhcp->t1_renew_time = dhcp->t2_rebind_time = dhcp->lease_used = dhcp->t0_timeout = 0; + + /* send release message when current IP was assigned via DHCP */ + if (dhcp_supplied_address(netif)) { + /* create and initialize the DHCP message header */ + struct pbuf *p_out; + u16_t options_out_len; + dhcp_set_state(dhcp, DHCP_STATE_OFF); + p_out = dhcp_create_msg(netif, dhcp, DHCP_RELEASE, &options_out_len); + if (p_out != NULL) { + struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); + options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr)))); + + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, dhcp->state, msg_out, DHCP_RELEASE, &options_out_len); + dhcp_option_trailer(options_out_len, msg_out->options, p_out); + + udp_sendto_if(dhcp_pcb, p_out, &server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n")); + } else { + /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); + } + + /* remove IP address from interface (prevents routing from selecting this interface) */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + } else { + dhcp_set_state(dhcp, DHCP_STATE_OFF); + } + +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + if (dhcp->pcb_allocated != 0) { + dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ + dhcp->pcb_allocated = 0; + } +} + +/** + * @ingroup dhcp4 + * This function calls dhcp_release_and_stop() internally. + * @deprecated Use dhcp_release_and_stop() instead. + */ +err_t +dhcp_release(struct netif *netif) +{ + dhcp_release_and_stop(netif); + return ERR_OK; +} + +/** + * @ingroup dhcp4 + * This function calls dhcp_release_and_stop() internally. + * @deprecated Use dhcp_release_and_stop() instead. + */ +void +dhcp_stop(struct netif *netif) +{ + dhcp_release_and_stop(netif); +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + */ +static void +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ + if (new_state != dhcp->state) { + dhcp->state = new_state; + dhcp->tries = 0; + dhcp->request_timeout = 0; + } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static u16_t +dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len) +{ + LWIP_ASSERT("dhcp_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); + options[options_out_len++] = option_type; + options[options_out_len++] = option_len; + return options_out_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static u16_t +dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value) +{ + LWIP_ASSERT("dhcp_option_byte: options_out_len < DHCP_OPTIONS_LEN", options_out_len < DHCP_OPTIONS_LEN); + options[options_out_len++] = value; + return options_out_len; +} + +static u16_t +dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value) +{ + LWIP_ASSERT("dhcp_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN", options_out_len + 2U <= DHCP_OPTIONS_LEN); + options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8); + options[options_out_len++] = (u8_t) (value & 0x00ffU); + return options_out_len; +} + +static u16_t +dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value) +{ + LWIP_ASSERT("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN", options_out_len + 4U <= DHCP_OPTIONS_LEN); + options[options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); + options[options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); + options[options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); + options[options_out_len++] = (u8_t)((value & 0x000000ffUL)); + return options_out_len; +} + +#if LWIP_NETIF_HOSTNAME +static u16_t +dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif) +{ + if (netif->hostname != NULL) { + size_t namelen = strlen(netif->hostname); + if (namelen > 0) { + size_t len; + const char *p = netif->hostname; + /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME + and 1 byte for trailer) */ + size_t available = DHCP_OPTIONS_LEN - options_out_len - 3; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); + len = LWIP_MIN(namelen, available); + LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF); + options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_HOSTNAME, (u8_t)len); + while (len--) { + options_out_len = dhcp_option_byte(options_out_len, options, *p++); + } + } + } + return options_out_len; +} +#endif /* LWIP_NETIF_HOSTNAME */ + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a contiguous piece of memory, and + * use that further on. + * + */ +static err_t +dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) +{ + u8_t *options; + u16_t offset; + u16_t offset_max; + u16_t options_offset; + u16_t options_idx; + u16_t options_idx_max; + struct pbuf *q; + int parse_file_as_options = 0; + int parse_sname_as_options = 0; + struct dhcp_msg *msg_in; +#if LWIP_DHCP_BOOTP_FILE + int file_overloaded = 0; +#endif + + LWIP_UNUSED_ARG(dhcp); + + /* clear received options */ + dhcp_clear_all_options(dhcp); + /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ + if (p->len < DHCP_SNAME_OFS) { + return ERR_BUF; + } + msg_in = (struct dhcp_msg *)p->payload; +#if LWIP_DHCP_BOOTP_FILE + /* clear boot file name */ + dhcp->boot_file_name[0] = 0; +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* parse options */ + + /* start with options field */ + options_idx = DHCP_OPTIONS_OFS; + /* parse options to the end of the received packet */ + options_idx_max = p->tot_len; +again: + q = p; + options_offset = options_idx; + while ((q != NULL) && (options_idx >= q->len)) { + options_idx = (u16_t)(options_idx - q->len); + options_idx_max = (u16_t)(options_idx_max - q->len); + q = q->next; + } + if (q == NULL) { + return ERR_BUF; + } + offset = options_idx; + offset_max = options_idx_max; + options = (u8_t *)q->payload; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while ((q != NULL) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) { + u8_t op = options[offset]; + u8_t len; + u8_t decode_len = 0; + int decode_idx = -1; + u16_t val_offset = (u16_t)(offset + 2); + if (val_offset < offset) { + /* overflow */ + return ERR_BUF; + } + /* len byte might be in the next pbuf */ + if ((offset + 1) < q->len) { + len = options[offset + 1]; + } else { + len = (q->next != NULL ? ((u8_t *)q->next->payload)[0] : 0); + } + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + decode_len = len; + switch (op) { + /* case(DHCP_OPTION_END): handled above */ + case (DHCP_OPTION_PAD): + /* special option: no len encoded */ + decode_len = len = 0; + /* will be increased below */ + break; + case (DHCP_OPTION_SUBNET_MASK): + LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; + break; + case (DHCP_OPTION_ROUTER): + decode_len = 4; /* only copy the first given router */ + LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_ROUTER; + break; +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + case (DHCP_OPTION_DNS_SERVER): + /* special case: there might be more than one server */ + LWIP_DHCP_INPUT_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); + /* limit number of DNS servers */ + decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_DNS_SERVER; + break; +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ + case (DHCP_OPTION_LEASE_TIME): + LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_LEASE_TIME; + break; +#if LWIP_DHCP_GET_NTP_SRV + case (DHCP_OPTION_NTP): + /* special case: there might be more than one server */ + LWIP_DHCP_INPUT_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); + /* limit number of NTP servers */ + decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS); + LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_NTP_SERVER; + break; +#endif /* LWIP_DHCP_GET_NTP_SRV*/ + case (DHCP_OPTION_OVERLOAD): + LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL;); + /* decode overload only in options, not in file/sname: invalid packet */ + LWIP_DHCP_INPUT_ERROR("overload in file/sname", options_offset == DHCP_OPTIONS_OFS, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_OVERLOAD; + break; + case (DHCP_OPTION_MESSAGE_TYPE): + LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_MSG_TYPE; + break; + case (DHCP_OPTION_SERVER_ID): + LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SERVER_ID; + break; + case (DHCP_OPTION_T1): + LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T1; + break; + case (DHCP_OPTION_T2): + LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T2; + break; + default: + decode_len = 0; + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); + LWIP_HOOK_DHCP_PARSE_OPTION(ip_current_netif(), dhcp, dhcp->state, msg_in, + dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) ? (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) : 0, + op, len, q, val_offset); + break; + } + if (op == DHCP_OPTION_PAD) { + offset++; + } else { + if (offset + len + 2 > 0xFFFF) { + /* overflow */ + return ERR_BUF; + } + offset = (u16_t)(offset + len + 2); + if (decode_len > 0) { + u32_t value = 0; + u16_t copy_len; +decode_next: + LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); + if (!dhcp_option_given(dhcp, decode_idx)) { + copy_len = LWIP_MIN(decode_len, 4); + if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) { + return ERR_BUF; + } + if (decode_len > 4) { + /* decode more than one u32_t */ + u16_t next_val_offset; + LWIP_DHCP_INPUT_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); + decode_len = (u8_t)(decode_len - 4); + next_val_offset = (u16_t)(val_offset + 4); + if (next_val_offset < val_offset) { + /* overflow */ + return ERR_BUF; + } + val_offset = next_val_offset; + decode_idx++; + goto decode_next; + } else if (decode_len == 4) { + value = lwip_ntohl(value); + } else { + LWIP_DHCP_INPUT_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); + value = ((u8_t *)&value)[0]; + } + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, value); + } + } + } + if (offset >= q->len) { + offset = (u16_t)(offset - q->len); + offset_max = (u16_t)(offset_max - q->len); + if (offset < offset_max) { + q = q->next; + LWIP_DHCP_INPUT_ERROR("next pbuf was null", q != NULL, return ERR_VAL;); + options = (u8_t *)q->payload; + } else { + /* We've run out of bytes, probably no end marker. Don't proceed. */ + return ERR_BUF; + } + } + } + /* is this an overloaded message? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { + u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); + dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); + if (overload == DHCP_OVERLOAD_FILE) { + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME) { + parse_sname_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { + parse_sname_as_options = 1; + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); + } + } + if (parse_file_as_options) { + /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ + parse_file_as_options = 0; + options_idx = DHCP_FILE_OFS; + options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; +#if LWIP_DHCP_BOOTP_FILE + file_overloaded = 1; +#endif + goto again; + } else if (parse_sname_as_options) { + parse_sname_as_options = 0; + options_idx = DHCP_SNAME_OFS; + options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; + goto again; + } +#if LWIP_DHCP_BOOTP_FILE + if (!file_overloaded) { + /* only do this for ACK messages */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && + (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) + /* copy bootp file name, don't care for sname (server hostname) */ + if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS) != (DHCP_FILE_LEN-1)) { + return ERR_BUF; + } + /* make sure the string is really NULL-terminated */ + dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; + } +#endif /* LWIP_DHCP_BOOTP_FILE */ + return ERR_OK; +} + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void +dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + struct netif *netif = ip_current_input_netif(); + struct dhcp *dhcp = netif_dhcp_data(netif); + struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; + u8_t msg_type; + u8_t i; + struct dhcp_msg *msg_in; + + LWIP_UNUSED_ARG(arg); + + /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */ + if ((dhcp == NULL) || (dhcp->pcb_allocated == 0)) { + goto free_pbuf_and_return; + } + + LWIP_ASSERT("invalid server address type", IP_IS_V4(addr)); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void *)p, + ip4_addr1_16(ip_2_ip4(addr)), ip4_addr2_16(ip_2_ip4(addr)), ip4_addr3_16(ip_2_ip4(addr)), ip4_addr4_16(ip_2_ip4(addr)), port)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); + /* prevent warnings about unused arguments */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + if (p->len < DHCP_MIN_REPLY_LEN) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); + goto free_pbuf_and_return; + } + + if (reply_msg->op != DHCP_BOOTREPLY) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); + goto free_pbuf_and_return; + } + /* iterate through hardware address and match against DHCP message */ + for (i = 0; i < netif->hwaddr_len && i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) { + if (netif->hwaddr[i] != reply_msg->chaddr[i]) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", + (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); + goto free_pbuf_and_return; + } + } + /* match transaction ID against what we expected */ + if (lwip_ntohl(reply_msg->xid) != dhcp->xid) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n", lwip_ntohl(reply_msg->xid), dhcp->xid)); + goto free_pbuf_and_return; + } + /* option fields could be unfold? */ + if (dhcp_parse_reply(p, dhcp) != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("problem unfolding DHCP message - too short on memory?\n")); + goto free_pbuf_and_return; + } + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); + /* obtain pointer to DHCP message type */ + if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); + goto free_pbuf_and_return; + } + + msg_in = (struct dhcp_msg *)p->payload; + /* read DHCP message type */ + msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); + /* message type is DHCP ACK? */ + if (msg_type == DHCP_ACK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); + /* in requesting state? */ + if (dhcp->state == DHCP_STATE_REQUESTING) { + dhcp_handle_ack(netif, msg_in); +#if DHCP_DOES_ARP_CHECK + if ((netif->flags & NETIF_FLAG_ETHARP) != 0) { + /* check if the acknowledged lease address is already in use */ + dhcp_check(netif); + } else { + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); + } +#else + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); +#endif + } + /* already bound to the given lease address? */ + else if ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) || + (dhcp->state == DHCP_STATE_RENEWING)) { + dhcp_handle_ack(netif, msg_in); + dhcp_bind(netif); + } + } + /* received a DHCP_NAK in appropriate state? */ + else if ((msg_type == DHCP_NAK) && + ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REQUESTING) || + (dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING ))) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); + dhcp_handle_nak(netif); + } + /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */ + else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_STATE_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n")); + /* remember offered lease */ + dhcp_handle_offer(netif, msg_in); + } + +free_pbuf_and_return: + pbuf_free(p); +} + +/** + * Create a DHCP request, fill in common headers + * + * @param netif the netif under DHCP control + * @param dhcp dhcp control struct + * @param message_type message type of the request + */ +static struct pbuf * +dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len) +{ + u16_t i; + struct pbuf *p_out; + struct dhcp_msg *msg_out; + u16_t options_out_len_loc; + +#ifndef DHCP_GLOBAL_XID + /** default global transaction identifier starting value (easy to match + * with a packet analyser). We simply increment for each new request. + * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one + * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + static u32_t xid; +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + static u32_t xid = 0xABCD0000; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ +#else + if (!xid_initialised) { + xid = DHCP_GLOBAL_XID; + xid_initialised = !xid_initialised; + } +#endif + LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return NULL;); + LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return NULL;); + p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); + if (p_out == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_create_msg(): could not allocate pbuf\n")); + return NULL; + } + LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", + (p_out->len >= sizeof(struct dhcp_msg))); + + /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ + if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) { + /* reuse transaction identifier in retransmissions */ + if (dhcp->tries == 0) { +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + xid = LWIP_RAND(); +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + xid++; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + } + dhcp->xid = xid; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, + ("transaction id xid(%"X32_F")\n", xid)); + + msg_out = (struct dhcp_msg *)p_out->payload; + memset(msg_out, 0, sizeof(struct dhcp_msg)); + + msg_out->op = DHCP_BOOTREQUEST; + /* @todo: make link layer independent */ + msg_out->htype = LWIP_IANA_HWTYPE_ETHERNET; + msg_out->hlen = netif->hwaddr_len; + msg_out->xid = lwip_htonl(dhcp->xid); + /* we don't need the broadcast flag since we can receive unicast traffic + before being fully configured! */ + /* set ciaddr to netif->ip_addr based on message_type and state */ + if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_RELEASE) || + ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */ + ((dhcp->state == DHCP_STATE_RENEWING) || dhcp->state == DHCP_STATE_REBINDING))) { + ip4_addr_copy(msg_out->ciaddr, *netif_ip4_addr(netif)); + } + for (i = 0; i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) { + /* copy netif hardware address (padded with zeroes through memset already) */ + msg_out->chaddr[i] = netif->hwaddr[i]; + } + msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); + /* Add option MESSAGE_TYPE */ + options_out_len_loc = dhcp_option(0, msg_out->options, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + options_out_len_loc = dhcp_option_byte(options_out_len_loc, msg_out->options, message_type); + if (options_out_len) { + *options_out_len = options_out_len_loc; + } + return p_out; +} + +/** + * Add a DHCP message trailer + * + * Adds the END option to the DHCP message, and if + * necessary, up to three padding bytes. + */ +static void +dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out) +{ + options[options_out_len++] = DHCP_OPTION_END; + /* packet is too small, or not 4 byte aligned? */ + while (((options_out_len < DHCP_MIN_OPTIONS_LEN) || (options_out_len & 3)) && + (options_out_len < DHCP_OPTIONS_LEN)) { + /* add a fill/padding byte */ + options[options_out_len++] = 0; + } + /* shrink the pbuf to the actual content length */ + pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + options_out_len)); +} + +/** check if DHCP supplied netif->ip_addr + * + * @param netif the netif to check + * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING), + * 0 otherwise + */ +u8_t +dhcp_supplied_address(const struct netif *netif) +{ + if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) { + struct dhcp *dhcp = netif_dhcp_data(netif); + return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING) || + (dhcp->state == DHCP_STATE_REBINDING); + } + return 0; +} + +#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/etharp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/etharp.c new file mode 100644 index 0000000..c3a5a10 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/etharp.c @@ -0,0 +1,1212 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_gratuitous(our_netif) upon address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/etharp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/prot/iana.h" +#include "netif/ethernet.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Re-request a used ARP entry 1 minute before it would expire to prevent + * breaking a steadily used connection because the ARP entry timed out. */ +#define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30) +#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15) + +/** the time an ARP entry stays pending after first request, + * for ARP_TMR_INTERVAL = 1000, this is + * 10 seconds. + * + * @internal Keep this number at least 2, otherwise it might + * run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 5 + +/** ARP states */ +enum etharp_state { + ETHARP_STATE_EMPTY = 0, + ETHARP_STATE_PENDING, + ETHARP_STATE_STABLE, + ETHARP_STATE_STABLE_REREQUESTING_1, + ETHARP_STATE_STABLE_REREQUESTING_2 +#if ETHARP_SUPPORT_STATIC_ENTRIES + , ETHARP_STATE_STATIC +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +}; + +struct etharp_entry { +#if ARP_QUEUEING + /** Pointer to queue of pending outgoing packets on this ARP entry. */ + struct etharp_q_entry *q; +#else /* ARP_QUEUEING */ + /** Pointer to a single pending outgoing packet on this ARP entry. */ + struct pbuf *q; +#endif /* ARP_QUEUEING */ + ip4_addr_t ipaddr; + struct netif *netif; + struct eth_addr ethaddr; + u16_t ctime; + u8_t state; +}; + +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; + +#if !LWIP_NETIF_HWADDRHINT +static netif_addr_idx_t etharp_cached_entry; +#endif /* !LWIP_NETIF_HWADDRHINT */ + +/** Try hard to create a new entry - we want the IP address to appear in + the cache (even if this means removing an active entry or so). */ +#define ETHARP_FLAG_TRY_HARD 1 +#define ETHARP_FLAG_FIND_ONLY 2 +#if ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_FLAG_STATIC_ENTRY 4 +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#if LWIP_NETIF_HWADDRHINT +#define ETHARP_SET_ADDRHINT(netif, addrhint) do { if (((netif) != NULL) && ((netif)->hints != NULL)) { \ + (netif)->hints->addr_hint = (addrhint); }} while(0) +#else /* LWIP_NETIF_HWADDRHINT */ +#define ETHARP_SET_ADDRHINT(netif, addrhint) (etharp_cached_entry = (addrhint)) +#endif /* LWIP_NETIF_HWADDRHINT */ + + +/* Check for maximum ARP_TABLE_SIZE */ +#if (ARP_TABLE_SIZE > NETIF_ADDR_IDX_MAX) +#error "ARP_TABLE_SIZE must fit in an s16_t, you have to reduce it in your lwipopts.h" +#endif + + +static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr); +static err_t etharp_raw(struct netif *netif, + const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, + const u16_t opcode); + +#if ARP_QUEUEING +/** + * Free a complete queue of etharp entries + * + * @param q a qeueue of etharp_q_entry's to free + */ +static void +free_etharp_q(struct etharp_q_entry *q) +{ + struct etharp_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ARP_QUEUE, r); + } +} +#else /* ARP_QUEUEING */ + +/** Compatibility define: free the queued pbuf */ +#define free_etharp_q(q) pbuf_free(q) + +#endif /* ARP_QUEUEING */ + +/** Clean up ARP table entries */ +static void +etharp_free_entry(int i) +{ + /* remove from SNMP ARP index tree */ + mib2_remove_arp_entry(arp_table[i].netif, &arp_table[i].ipaddr); + /* and empty packet queue */ + if (arp_table[i].q != NULL) { + /* remove all queued packets */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + free_etharp_q(arp_table[i].q); + arp_table[i].q = NULL; + } + /* recycle entry for re-use */ + arp_table[i].state = ETHARP_STATE_EMPTY; +#ifdef LWIP_DEBUG + /* for debugging, clean out the complete entry */ + arp_table[i].ctime = 0; + arp_table[i].netif = NULL; + ip4_addr_set_zero(&arp_table[i].ipaddr); + arp_table[i].ethaddr = ethzero; +#endif /* LWIP_DEBUG */ +} + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ARP_TMR_INTERVAL milliseconds (1 second), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ + int i; + + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); + /* remove expired entries from the ARP table */ + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if (state != ETHARP_STATE_EMPTY +#if ETHARP_SUPPORT_STATIC_ENTRIES + && (state != ETHARP_STATE_STATIC) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + ) { + arp_table[i].ctime++; + if ((arp_table[i].ctime >= ARP_MAXAGE) || + ((arp_table[i].state == ETHARP_STATE_PENDING) && + (arp_table[i].ctime >= ARP_MAXPENDING))) { + /* pending or stable entry has become old! */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %d.\n", + arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", i)); + /* clean up entries that have just been expired */ + etharp_free_entry(i); + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) { + /* Don't send more than one request every 2 seconds. */ + arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2; + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) { + /* Reset state to stable, so that the next transmitted packet will + re-send an ARP request. */ + arp_table[i].state = ETHARP_STATE_STABLE; + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* still pending, resend an ARP query */ + etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); + } + } + } +} + +/** + * Search the ARP table for a matching or new entry. + * + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + * + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + * + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags See @ref etharp_state + * @param netif netif related to this address (used for NETIF_HWADDRHINT) + * + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s16_t +etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif *netif) +{ + s16_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; + s16_t empty = ARP_TABLE_SIZE; + s16_t i = 0; + /* oldest entry with packets on queue */ + s16_t old_queue = ARP_TABLE_SIZE; + /* its age */ + u16_t age_queue = 0, age_pending = 0, age_stable = 0; + + LWIP_UNUSED_ARG(netif); + + /** + * a) do a search through the cache, remember candidates + * b) select candidate entry + * c) create new entry + */ + + /* a) in a single search sweep, do all of this + * 1) remember the first empty entry (if any) + * 2) remember the oldest stable entry (if any) + * 3) remember the oldest pending entry without queued packets (if any) + * 4) remember the oldest pending entry with queued packets (if any) + * 5) search for a matching IP entry, either pending or stable + * until 5 matches, or all entries are searched for. + */ + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + /* no empty entry found yet and now we do find one? */ + if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %d\n", (int)i)); + /* remember first empty entry */ + empty = i; + } else if (state != ETHARP_STATE_EMPTY) { + LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", + state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); + /* if given, does IP address match IP address in ARP entry? */ + if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) +#if ETHARP_TABLE_MATCH_NETIF + && ((netif == NULL) || (netif == arp_table[i].netif)) +#endif /* ETHARP_TABLE_MATCH_NETIF */ + ) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %d\n", (int)i)); + /* found exact IP address match, simply bail out */ + return i; + } + /* pending entry? */ + if (state == ETHARP_STATE_PENDING) { + /* pending with queued packets? */ + if (arp_table[i].q != NULL) { + if (arp_table[i].ctime >= age_queue) { + old_queue = i; + age_queue = arp_table[i].ctime; + } + } else + /* pending without queued packets? */ + { + if (arp_table[i].ctime >= age_pending) { + old_pending = i; + age_pending = arp_table[i].ctime; + } + } + /* stable entry? */ + } else if (state >= ETHARP_STATE_STABLE) { +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* don't record old_stable for static entries since they never expire */ + if (state < ETHARP_STATE_STATIC) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* remember entry with oldest stable entry in oldest, its age in maxtime */ + if (arp_table[i].ctime >= age_stable) { + old_stable = i; + age_stable = arp_table[i].ctime; + } + } + } + } + } + /* { we have no match } => try to create a new entry */ + + /* don't create new entry, only search? */ + if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || + /* or no empty entry found and not allowed to recycle? */ + ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); + return (s16_t)ERR_MEM; + } + + /* b) choose the least destructive entry to recycle: + * 1) empty entry + * 2) oldest stable entry + * 3) oldest pending entry without queued packets + * 4) oldest pending entry with queued packets + * + * { ETHARP_FLAG_TRY_HARD is set at this point } + */ + + /* 1) empty entry available? */ + if (empty < ARP_TABLE_SIZE) { + i = empty; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %d\n", (int)i)); + } else { + /* 2) found recyclable stable entry? */ + if (old_stable < ARP_TABLE_SIZE) { + /* recycle oldest stable*/ + i = old_stable; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %d\n", (int)i)); + /* no queued packets should exist on stable entries */ + LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); + /* 3) found recyclable pending entry without queued packets? */ + } else if (old_pending < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_pending; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %d (without queue)\n", (int)i)); + /* 4) found recyclable pending entry with queued packets? */ + } else if (old_queue < ARP_TABLE_SIZE) { + /* recycle oldest pending (queued packets are free in etharp_free_entry) */ + i = old_queue; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", (int)i, (void *)(arp_table[i].q))); + /* no empty or recyclable entries found */ + } else { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); + return (s16_t)ERR_MEM; + } + + /* { empty or recyclable entry found } */ + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + etharp_free_entry(i); + } + + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", + arp_table[i].state == ETHARP_STATE_EMPTY); + + /* IP address given? */ + if (ipaddr != NULL) { + /* set IP address */ + ip4_addr_copy(arp_table[i].ipaddr, *ipaddr); + } + arp_table[i].ctime = 0; +#if ETHARP_TABLE_MATCH_NETIF + arp_table[i].netif = netif; +#endif /* ETHARP_TABLE_MATCH_NETIF */ + return (s16_t)i; +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + * + * @param netif netif related to this entry (used for NETIF_ADDRHINT) + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags See @ref etharp_state + * + * @return + * - ERR_OK Successfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t +etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ + s16_t i; + LWIP_ASSERT("netif->hwaddr_len == ETH_HWADDR_LEN", netif->hwaddr_len == ETH_HWADDR_LEN); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], + (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); + /* non-unicast address? */ + if (ip4_addr_isany(ipaddr) || + ip4_addr_isbroadcast(ipaddr, netif) || + ip4_addr_ismulticast(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + /* find or create ARP entry */ + i = etharp_find_entry(ipaddr, flags, netif); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + +#if ETHARP_SUPPORT_STATIC_ENTRIES + if (flags & ETHARP_FLAG_STATIC_ENTRY) { + /* record static type */ + arp_table[i].state = ETHARP_STATE_STATIC; + } else if (arp_table[i].state == ETHARP_STATE_STATIC) { + /* found entry is a static type, don't overwrite it */ + return ERR_VAL; + } else +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* mark it stable */ + arp_table[i].state = ETHARP_STATE_STABLE; + } + + /* record network interface */ + arp_table[i].netif = netif; + /* insert in SNMP ARP index tree */ + mib2_add_arp_entry(netif, &arp_table[i].ipaddr); + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", i)); + /* update address */ + SMEMCPY(&arp_table[i].ethaddr, ethaddr, ETH_HWADDR_LEN); + /* reset time stamp */ + arp_table[i].ctime = 0; + /* this is where we will send out queued packets! */ +#if ARP_QUEUEING + while (arp_table[i].q != NULL) { + struct pbuf *p; + /* remember remainder of queue */ + struct etharp_q_entry *q = arp_table[i].q; + /* pop first item off the queue */ + arp_table[i].q = q->next; + /* get the packet pointer */ + p = q->p; + /* now queue entry can be freed */ + memp_free(MEMP_ARP_QUEUE, q); +#else /* ARP_QUEUEING */ + if (arp_table[i].q != NULL) { + struct pbuf *p = arp_table[i].q; + arp_table[i].q = NULL; +#endif /* ARP_QUEUEING */ + /* send the queued IP packet */ + ethernet_output(netif, p, (struct eth_addr *)(netif->hwaddr), ethaddr, ETHTYPE_IP); + /* free the queued IP packet */ + pbuf_free(p); + } + return ERR_OK; +} + +#if ETHARP_SUPPORT_STATIC_ENTRIES +/** Add a new static entry to the ARP table. If an entry exists for the + * specified IP address, this entry is overwritten. + * If packets are queued for the specified IP address, they are sent out. + * + * @param ipaddr IP address for the new static entry + * @param ethaddr ethernet address for the new static entry + * @return See return values of etharp_add_static_entry + */ +err_t +etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) +{ + struct netif *netif; + LWIP_ASSERT_CORE_LOCKED(); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], + (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); + + netif = ip4_route(ipaddr); + if (netif == NULL) { + return ERR_RTE; + } + + return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); +} + +/** Remove a static entry from the ARP table previously added with a call to + * etharp_add_static_entry. + * + * @param ipaddr IP address of the static entry to remove + * @return ERR_OK: entry removed + * ERR_MEM: entry wasn't found + * ERR_ARG: entry wasn't a static entry but a dynamic one + */ +err_t +etharp_remove_static_entry(const ip4_addr_t *ipaddr) +{ + s16_t i; + LWIP_ASSERT_CORE_LOCKED(); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); + + /* find or create ARP entry */ + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + + if (arp_table[i].state != ETHARP_STATE_STATIC) { + /* entry wasn't a static entry, cannot remove it */ + return ERR_ARG; + } + /* entry found, free it */ + etharp_free_entry(i); + return ERR_OK; +} +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +/** + * Remove all ARP table entries of the specified netif. + * + * @param netif points to a network interface + */ +void +etharp_cleanup_netif(struct netif *netif) +{ + int i; + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { + etharp_free_entry(i); + } + } +} + +/** + * Finds (stable) ethernet/IP address pair from ARP table + * using interface and IP address index. + * @note the addresses in the ARP table are in network order! + * + * @param netif points to interface index + * @param ipaddr points to the (network order) IP address index + * @param eth_ret points to return pointer + * @param ip_ret points to return pointer + * @return table index if found, -1 otherwise + */ +ssize_t +etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, + struct eth_addr **eth_ret, const ip4_addr_t **ip_ret) +{ + s16_t i; + + LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", + eth_ret != NULL && ip_ret != NULL); + + LWIP_UNUSED_ARG(netif); + + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif); + if ((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { + *eth_ret = &arp_table[i].ethaddr; + *ip_ret = &arp_table[i].ipaddr; + return i; + } + return -1; +} + +/** + * Possibility to iterate over stable ARP table entries + * + * @param i entry number, 0 to ARP_TABLE_SIZE + * @param ipaddr return value: IP address + * @param netif return value: points to interface + * @param eth_ret return value: ETH address + * @return 1 on valid index, 0 otherwise + */ +int +etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret) +{ + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("eth_ret != NULL", eth_ret != NULL); + + if ((i < ARP_TABLE_SIZE) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { + *ipaddr = &arp_table[i].ipaddr; + *netif = arp_table[i].netif; + *eth_ret = &arp_table[i].ethaddr; + return 1; + } else { + return 0; + } +} + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param p The ARP packet that arrived on netif. Is freed by this function. + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * + * @see pbuf_free() + */ +void +etharp_input(struct pbuf *p, struct netif *netif) +{ + struct etharp_hdr *hdr; + /* these are aligned properly, whereas the ARP header fields might not be */ + ip4_addr_t sipaddr, dipaddr; + u8_t for_us; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + hdr = (struct etharp_hdr *)p->payload; + + /* RFC 826 "Packet Reception": */ + if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) || + (hdr->hwlen != ETH_HWADDR_LEN) || + (hdr->protolen != sizeof(ip4_addr_t)) || + (hdr->proto != PP_HTONS(ETHTYPE_IP))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", + hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen)); + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + pbuf_free(p); + return; + } + ETHARP_STATS_INC(etharp.recv); + +#if LWIP_AUTOIP + /* We have to check if a host already has configured our random + * created link local address and continuously check if there is + * a host with this IP-address so we can detect collisions */ + autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + + /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). */ + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); + + /* this interface is not configured? */ + if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { + for_us = 0; + } else { + /* ARP packet directed to us? */ + for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); + } + + /* ARP message directed to us? + -> add IP address in ARP cache; assume requester wants to talk to us, + can result in directly sending the queued packets for this host. + ARP message not directed to us? + -> update the source IP address in the cache, if present */ + etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), + for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); + + /* now act on the message itself */ + switch (hdr->opcode) { + /* ARP request? */ + case PP_HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + * reply. In any case, we time-stamp any existing ARP entry, + * and possibly send out an IP packet that was queued on it. */ + + LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n")); + /* ARP request for our address? */ + if (for_us) { + /* send ARP response */ + etharp_raw(netif, + (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, + (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), + &hdr->shwaddr, &sipaddr, + ARP_REPLY); + /* we are not configured? */ + } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* { for_us == 0 and netif->ip_addr.addr == 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n")); + /* request was not directed to us */ + } else { + /* { for_us == 0 and netif->ip_addr.addr != 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n")); + } + break; + case PP_HTONS(ARP_REPLY): + /* ARP reply. We already updated the ARP cache earlier. */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) + /* DHCP wants to know about ARP replies from any host with an + * IP address also offered to us by the DHCP server. We do not + * want to take a duplicate IP address on a single network. + * @todo How should we handle redundant (fail-over) interfaces? */ + dhcp_arp_reply(netif, &sipaddr); +#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ + break; + default: + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode))); + ETHARP_STATS_INC(etharp.err); + break; + } + /* free ARP packet */ + pbuf_free(p); +} + +/** Just a small helper function that sends a pbuf to an ethernet address + * in the arp_table specified by the index 'arp_idx'. + */ +static err_t +etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, netif_addr_idx_t arp_idx) +{ + LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", + arp_table[arp_idx].state >= ETHARP_STATE_STABLE); + /* if arp table entry is about to expire: re-request it, + but only if its state is ETHARP_STATE_STABLE to prevent flooding the + network with ARP requests if this address is used frequently. */ + if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) { + if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) { + /* issue a standard request using broadcast */ + if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } + } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) { + /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */ + if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } + } + } + + return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or ethernet_output(). + */ +err_t +etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) +{ + const struct eth_addr *dest; + struct eth_addr mcastaddr; + const ip4_addr_t *dst_addr = ipaddr; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); + + /* Determine on destination hardware address. Broadcasts and multicasts + * are special, other IP addresses are looked up in the ARP table. */ + + /* broadcast destination IP address? */ + if (ip4_addr_isbroadcast(ipaddr, netif)) { + /* broadcast on Ethernet also */ + dest = (const struct eth_addr *)ðbroadcast; + /* multicast destination IP address? */ + } else if (ip4_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address.*/ + mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0; + mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1; + mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + /* destination Ethernet address is multicast */ + dest = &mcastaddr; + /* unicast destination IP address? */ + } else { + netif_addr_idx_t i; + /* outside local network? if so, this can neither be a global broadcast nor + a subnet broadcast. */ + if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && + !ip4_addr_islinklocal(ipaddr)) { +#if LWIP_AUTOIP + struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr *, q->payload); + /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with + a link-local source address must always be "directly to its destination + on the same physical link. The host MUST NOT send the packet to any + router for forwarding". */ + if (!ip4_addr_islinklocal(&iphdr->src)) +#endif /* LWIP_AUTOIP */ + { +#ifdef LWIP_HOOK_ETHARP_GET_GW + /* For advanced routing, a single default gateway might not be enough, so get + the IP address of the gateway to handle the current destination address. */ + dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); + if (dst_addr == NULL) +#endif /* LWIP_HOOK_ETHARP_GET_GW */ + { + /* interface has default gateway? */ + if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) { + /* send to hardware address of default gateway IP address */ + dst_addr = netif_ip4_gw(netif); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + } + } +#if LWIP_NETIF_HWADDRHINT + if (netif->hints != NULL) { + /* per-pcb cached entry was given */ + netif_addr_idx_t etharp_cached_entry = netif->hints->addr_hint; + if (etharp_cached_entry < ARP_TABLE_SIZE) { +#endif /* LWIP_NETIF_HWADDRHINT */ + if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && +#if ETHARP_TABLE_MATCH_NETIF + (arp_table[etharp_cached_entry].netif == netif) && +#endif + (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { + /* the per-pcb-cached entry is stable and the right one! */ + ETHARP_STATS_INC(etharp.cachehit); + return etharp_output_to_arp_index(netif, q, etharp_cached_entry); + } +#if LWIP_NETIF_HWADDRHINT + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* find stable entry: do this here since this is a critical path for + throughput and etharp_find_entry() is kind of slow */ + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if ((arp_table[i].state >= ETHARP_STATE_STABLE) && +#if ETHARP_TABLE_MATCH_NETIF + (arp_table[i].netif == netif) && +#endif + (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { + /* found an existing, stable entry */ + ETHARP_SET_ADDRHINT(netif, i); + return etharp_output_to_arp_index(netif, q, i); + } + } + /* no stable entry found, use the (slower) query function: + queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, dst_addr, q); + } + + /* continuation for multicast/broadcast destinations */ + /* obtain source Ethernet address of the given interface */ + /* send packet directly on the link */ + return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), dest, ETHTYPE_IP); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out. + * + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + * + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + * to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) +{ + struct eth_addr *srcaddr = (struct eth_addr *)netif->hwaddr; + err_t result = ERR_MEM; + int is_new_entry = 0; + s16_t i_err; + netif_addr_idx_t i; + + /* non-unicast address? */ + if (ip4_addr_isbroadcast(ipaddr, netif) || + ip4_addr_ismulticast(ipaddr) || + ip4_addr_isany(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + + /* find entry in ARP cache, ask to create entry if queueing packet */ + i_err = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif); + + /* could not find or create entry? */ + if (i_err < 0) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); + if (q) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); + ETHARP_STATS_INC(etharp.memerr); + } + return (err_t)i_err; + } + LWIP_ASSERT("type overflow", (size_t)i_err < NETIF_ADDR_IDX_MAX); + i = (netif_addr_idx_t)i_err; + + /* mark a fresh entry as pending (we just sent a request) */ + if (arp_table[i].state == ETHARP_STATE_EMPTY) { + is_new_entry = 1; + arp_table[i].state = ETHARP_STATE_PENDING; + /* record network interface for re-sending arp request in etharp_tmr */ + arp_table[i].netif = netif; + } + + /* { i is either a STABLE or (new or existing) PENDING entry } */ + LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", + ((arp_table[i].state == ETHARP_STATE_PENDING) || + (arp_table[i].state >= ETHARP_STATE_STABLE))); + + /* do we have a new entry? or an implicit query request? */ + if (is_new_entry || (q == NULL)) { + /* try to resolve it; send out ARP request */ + result = etharp_request(netif, ipaddr); + if (result != ERR_OK) { + /* ARP request couldn't be sent */ + /* We don't re-send arp request in etharp_tmr, but we still queue packets, + since this failure could be temporary, and the next packet calling + etharp_query again could lead to sending the queued packets. */ + } else { + /* ARP request successfully sent */ + if ((arp_table[i].state == ETHARP_STATE_PENDING) && !is_new_entry) { + /* A new ARP request has been sent for a pending entry. Reset the ctime to + not let it expire too fast. */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: reset ctime for entry %"S16_F"\n", (s16_t)i)); + arp_table[i].ctime = 0; + } + } + if (q == NULL) { + return result; + } + } + + /* packet given? */ + LWIP_ASSERT("q != NULL", q != NULL); + /* stable entry? */ + if (arp_table[i].state >= ETHARP_STATE_STABLE) { + /* we have a valid IP->Ethernet address mapping */ + ETHARP_SET_ADDRHINT(netif, i); + /* send the packet */ + result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* entry is still pending, queue the given packet 'q' */ + struct pbuf *p; + int copy_needed = 0; + /* IF q includes a pbuf that must be copied, copy the whole chain into a + * new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ + p = q; + while (p) { + LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); + if (PBUF_NEEDS_COPY(p)) { + copy_needed = 1; + break; + } + p = p->next; + } + if (copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet could be taken over? */ + if (p != NULL) { + /* queue packet ... */ +#if ARP_QUEUEING + struct etharp_q_entry *new_entry; + /* allocate a new arp queue entry */ + new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); + if (new_entry != NULL) { + unsigned int qlen = 0; + new_entry->next = 0; + new_entry->p = p; + if (arp_table[i].q != NULL) { + /* queue was already existent, append the new entry to the end */ + struct etharp_q_entry *r; + r = arp_table[i].q; + qlen++; + while (r->next != NULL) { + r = r->next; + qlen++; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + arp_table[i].q = new_entry; + } +#if ARP_QUEUE_LEN + if (qlen >= ARP_QUEUE_LEN) { + struct etharp_q_entry *old; + old = arp_table[i].q; + arp_table[i].q = arp_table[i].q->next; + pbuf_free(old->p); + memp_free(MEMP_ARP_QUEUE, old); + } +#endif + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"U16_F"\n", (void *)q, i)); + result = ERR_OK; + } else { + /* the pool MEMP_ARP_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } +#else /* ARP_QUEUEING */ + /* always queue one packet per ARP request only, freeing a previously queued packet */ + if (arp_table[i].q != NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"U16_F"\n", (void *)q, (u16_t)i)); + pbuf_free(arp_table[i].q); + } + arp_table[i].q = p; + result = ERR_OK; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"U16_F"\n", (void *)q, (u16_t)i)); +#endif /* ARP_QUEUEING */ + } else { + ETHARP_STATS_INC(etharp.memerr); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } + } + return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +static err_t +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, + const u16_t opcode) +{ + struct pbuf *p; + err_t result = ERR_OK; + struct etharp_hdr *hdr; + + LWIP_ASSERT("netif != NULL", netif != NULL); + + /* allocate a pbuf for the outgoing ARP request packet */ + p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM); + /* could allocate a pbuf for an ARP request? */ + if (p == NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_raw: could not allocate pbuf for ARP request.\n")); + ETHARP_STATS_INC(etharp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", + (p->len >= SIZEOF_ETHARP_HDR)); + + hdr = (struct etharp_hdr *)p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); + hdr->opcode = lwip_htons(opcode); + + LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", + (netif->hwaddr_len == ETH_HWADDR_LEN)); + + /* Write the ARP MAC-Addresses */ + SMEMCPY(&hdr->shwaddr, hwsrc_addr, ETH_HWADDR_LEN); + SMEMCPY(&hdr->dhwaddr, hwdst_addr, ETH_HWADDR_LEN); + /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without + * structure packing. */ + IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->sipaddr, ipsrc_addr); + IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->dipaddr, ipdst_addr); + + hdr->hwtype = PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET); + hdr->proto = PP_HTONS(ETHTYPE_IP); + /* set hwlen and protolen */ + hdr->hwlen = ETH_HWADDR_LEN; + hdr->protolen = sizeof(ip4_addr_t); + + /* send ARP query */ +#if LWIP_AUTOIP + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + if (ip4_addr_islinklocal(ipsrc_addr)) { + ethernet_output(netif, p, ethsrc_addr, ðbroadcast, ETHTYPE_ARP); + } else +#endif /* LWIP_AUTOIP */ + { + ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP); + } + + ETHARP_STATS_INC(etharp.xmit); + /* free ARP query packet */ + pbuf_free(p); + p = NULL; + /* could not allocate pbuf for ARP request */ + + return result; +} + +/** + * Send an ARP request packet asking for ipaddr to a specific eth address. + * Used to send unicast request to refresh the ARP table just before an entry + * times out + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @param hw_dst_addr the ethernet address to send this packet to + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +static err_t +etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr, + (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), ðzero, + ipaddr, ARP_REQUEST); +} + +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, const ip4_addr_t *ipaddr) +{ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); + return etharp_request_dst(netif, ipaddr, ðbroadcast); +} + +#endif /* LWIP_IPV4 && LWIP_ARP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/icmp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/icmp.c new file mode 100644 index 0000000..59b493a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/icmp.c @@ -0,0 +1,410 @@ +/** + * @file + * ICMP - Internet Control Message Protocol + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/stats.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be + * used to modify and send a response packet (and to 1 if this is not the case, + * e.g. when link header is stripped off when receiving) */ +#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + +/* The maximum amount of data from the original packet to return in a dest-unreachable */ +#define ICMP_DEST_UNREACH_DATASIZE 8 + +static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); + +/** + * Processes ICMP input packets, called from ip_input(). + * + * Currently only processes icmp echo requests and sends + * out the echo response. + * + * @param p the icmp echo request packet, p->payload pointing to the icmp header + * @param inp the netif on which this packet was received + */ +void +icmp_input(struct pbuf *p, struct netif *inp) +{ + u8_t type; +#ifdef LWIP_DEBUG + u8_t code; +#endif /* LWIP_DEBUG */ + struct icmp_echo_hdr *iecho; + const struct ip_hdr *iphdr_in; + u16_t hlen; + const ip4_addr_t *src; + + ICMP_STATS_INC(icmp.recv); + MIB2_STATS_INC(mib2.icmpinmsgs); + + iphdr_in = ip4_current_header(); + hlen = IPH_HL_BYTES(iphdr_in); + if (hlen < IP_HLEN) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen)); + goto lenerr; + } + if (p->len < sizeof(u16_t) * 2) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); + goto lenerr; + } + + type = *((u8_t *)p->payload); +#ifdef LWIP_DEBUG + code = *(((u8_t *)p->payload) + 1); + /* if debug is enabled but debug statement below is somehow disabled: */ + LWIP_UNUSED_ARG(code); +#endif /* LWIP_DEBUG */ + switch (type) { + case ICMP_ER: + /* This is OK, echo reply might have been parsed by a raw PCB + (as obviously, an echo request has been sent, too). */ + MIB2_STATS_INC(mib2.icmpinechoreps); + break; + case ICMP_ECHO: + MIB2_STATS_INC(mib2.icmpinechos); + src = ip4_current_dest_addr(); + /* multicast destination address? */ + if (ip4_addr_ismulticast(ip4_current_dest_addr())) { +#if LWIP_MULTICAST_PING + /* For multicast, use address of receiving interface as source address */ + src = netif_ip4_addr(inp); +#else /* LWIP_MULTICAST_PING */ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n")); + goto icmperr; +#endif /* LWIP_MULTICAST_PING */ + } + /* broadcast destination address? */ + if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) { +#if LWIP_BROADCAST_PING + /* For broadcast, use address of receiving interface as source address */ + src = netif_ip4_addr(inp); +#else /* LWIP_BROADCAST_PING */ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n")); + goto icmperr; +#endif /* LWIP_BROADCAST_PING */ + } + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + if (p->tot_len < sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + goto lenerr; + } +#if CHECKSUM_CHECK_ICMP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) { + if (inet_chksum_pbuf(p) != 0) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.chkerr); + MIB2_STATS_INC(mib2.icmpinerrors); + return; + } + } +#endif +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + if (pbuf_add_header(p, hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN)) { + /* p is not big enough to contain link headers + * allocate a new one and copy p into it + */ + struct pbuf *r; + u16_t alloc_len = (u16_t)(p->tot_len + hlen); + if (alloc_len < p->tot_len) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed (tot_len overflow)\n")); + goto icmperr; + } + /* allocate new packet buffer with space for link headers */ + r = pbuf_alloc(PBUF_LINK, alloc_len, PBUF_RAM); + if (r == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); + goto icmperr; + } + if (r->len < hlen + sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header")); + pbuf_free(r); + goto icmperr; + } + /* copy the ip header */ + MEMCPY(r->payload, iphdr_in, hlen); + /* switch r->payload back to icmp header (cannot fail) */ + if (pbuf_remove_header(r, hlen)) { + LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0); + pbuf_free(r); + goto icmperr; + } + /* copy the rest of the packet without ip header */ + if (pbuf_copy(r, p) != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed")); + pbuf_free(r); + goto icmperr; + } + /* free the original p */ + pbuf_free(p); + /* we now have an identical copy of p that has room for link headers */ + p = r; + } else { + /* restore p->payload to point to icmp header (cannot fail) */ + if (pbuf_remove_header(p, hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN)) { + LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); + goto icmperr; + } + } +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + /* At this point, all checks are OK. */ + /* We generate an answer by switching the dest and src ip addresses, + * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ + iecho = (struct icmp_echo_hdr *)p->payload; + if (pbuf_add_header(p, hlen)) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet")); + } else { + err_t ret; + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + ip4_addr_copy(iphdr->src, *src); + ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); + ICMPH_TYPE_SET(iecho, ICMP_ER); +#if CHECKSUM_GEN_ICMP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { + /* adjust the checksum */ + if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { + iecho->chksum = (u16_t)(iecho->chksum + PP_HTONS((u16_t)(ICMP_ECHO << 8)) + 1); + } else { + iecho->chksum = (u16_t)(iecho->chksum + PP_HTONS(ICMP_ECHO << 8)); + } + } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + iecho->chksum = 0; + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#else /* CHECKSUM_GEN_ICMP */ + iecho->chksum = 0; +#endif /* CHECKSUM_GEN_ICMP */ + + /* Set the correct TTL and recalculate the header checksum. */ + IPH_TTL_SET(iphdr, ICMP_TTL); + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); + } +#endif /* CHECKSUM_GEN_IP */ + + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + MIB2_STATS_INC(mib2.icmpoutmsgs); + /* increase number of echo replies attempted to send */ + MIB2_STATS_INC(mib2.icmpoutechoreps); + + /* send an ICMP packet */ + ret = ip4_output_if(p, src, LWIP_IP_HDRINCL, + ICMP_TTL, 0, IP_PROTO_ICMP, inp); + if (ret != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret))); + } + } + break; + default: + if (type == ICMP_DUR) { + MIB2_STATS_INC(mib2.icmpindestunreachs); + } else if (type == ICMP_TE) { + MIB2_STATS_INC(mib2.icmpintimeexcds); + } else if (type == ICMP_PP) { + MIB2_STATS_INC(mib2.icmpinparmprobs); + } else if (type == ICMP_SQ) { + MIB2_STATS_INC(mib2.icmpinsrcquenchs); + } else if (type == ICMP_RD) { + MIB2_STATS_INC(mib2.icmpinredirects); + } else if (type == ICMP_TS) { + MIB2_STATS_INC(mib2.icmpintimestamps); + } else if (type == ICMP_TSR) { + MIB2_STATS_INC(mib2.icmpintimestampreps); + } else if (type == ICMP_AM) { + MIB2_STATS_INC(mib2.icmpinaddrmasks); + } else if (type == ICMP_AMR) { + MIB2_STATS_INC(mib2.icmpinaddrmaskreps); + } + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", + (s16_t)type, (s16_t)code)); + ICMP_STATS_INC(icmp.proterr); + ICMP_STATS_INC(icmp.drop); + } + pbuf_free(p); + return; +lenerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + MIB2_STATS_INC(mib2.icmpinerrors); + return; +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING +icmperr: + pbuf_free(p); + ICMP_STATS_INC(icmp.err); + MIB2_STATS_INC(mib2.icmpinerrors); + return; +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ +} + +/** + * Send an icmp 'destination unreachable' packet, called from ip_input() if + * the transport layer protocol is unknown and from udp_input() if the local + * port is not bound. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'unreachable' packet + */ +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ + MIB2_STATS_INC(mib2.icmpoutdestunreachs); + icmp_send_response(p, ICMP_DUR, t); +} + +#if IP_FORWARD || IP_REASSEMBLY +/** + * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. + * + * @param p the input packet for which the 'time exceeded' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'time exceeded' packet + */ +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ + MIB2_STATS_INC(mib2.icmpouttimeexcds); + icmp_send_response(p, ICMP_TE, t); +} + +#endif /* IP_FORWARD || IP_REASSEMBLY */ + +/** + * Send an icmp packet in response to an incoming packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param type Type of the ICMP header + * @param code Code of the ICMP header + */ +static void +icmp_send_response(struct pbuf *p, u8_t type, u8_t code) +{ + struct pbuf *q; + struct ip_hdr *iphdr; + /* we can use the echo header here */ + struct icmp_echo_hdr *icmphdr; + ip4_addr_t iphdr_src; + struct netif *netif; + u16_t response_pkt_len; + + /* increase number of messages attempted to send */ + MIB2_STATS_INC(mib2.icmpoutmsgs); + + /* Keep IP header + up to 8 bytes */ + response_pkt_len = IP_HLEN + ICMP_DEST_UNREACH_DATASIZE; + if (p->tot_len < response_pkt_len) { + response_pkt_len = p->tot_len; + } + + /* ICMP header + part of original packet */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + response_pkt_len, PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); + MIB2_STATS_INC(mib2.icmpouterrors); + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp message", + (q->len >= (sizeof(struct icmp_echo_hdr) + response_pkt_len))); + + iphdr = (struct ip_hdr *)p->payload; + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src); + LWIP_DEBUGF(ICMP_DEBUG, (" to ")); + ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest); + LWIP_DEBUGF(ICMP_DEBUG, ("\n")); + + icmphdr = (struct icmp_echo_hdr *)q->payload; + icmphdr->type = type; + icmphdr->code = code; + icmphdr->id = 0; + icmphdr->seqno = 0; + + /* copy fields from original packet */ + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, + response_pkt_len); + + ip4_addr_copy(iphdr_src, iphdr->src); +#ifdef LWIP_HOOK_IP4_ROUTE_SRC + { + ip4_addr_t iphdr_dst; + ip4_addr_copy(iphdr_dst, iphdr->dest); + netif = ip4_route_src(&iphdr_dst, &iphdr_src); + } +#else + netif = ip4_route(&iphdr_src); +#endif + if (netif != NULL) { + /* calculate checksum */ + icmphdr->chksum = 0; +#if CHECKSUM_GEN_ICMP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { + icmphdr->chksum = inet_chksum(icmphdr, q->len); + } +#endif + ICMP_STATS_INC(icmp.xmit); + ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); + } + pbuf_free(q); +} + +#endif /* LWIP_IPV4 && LWIP_ICMP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/igmp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/igmp.c new file mode 100644 index 0000000..b655aa3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/igmp.c @@ -0,0 +1,801 @@ +/** + * @file + * IGMP - Internet Group Management Protocol + * + * @defgroup igmp IGMP + * @ingroup ip4 + * To be called from TCPIP thread + */ + +/* + * Copyright (c) 2002 CITEL Technologies 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of CITEL Technologies Ltd 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 CITEL TECHNOLOGIES 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 CITEL TECHNOLOGIES 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. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +/*------------------------------------------------------------- +Note 1) +Although the rfc requires V1 AND V2 capability +we will only support v2 since now V1 is very old (August 1989) +V1 can be added if required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 2) +A query for a specific group address (as opposed to ALLHOSTS) +has now been implemented as I am unsure if it is required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 3) +The router alert rfc 2113 is implemented in outgoing packets +but not checked rigorously incoming +------------------------------------------------------------- +Steve Reynolds +------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * RFC 988 - Host extensions for IP multicasting - V0 + * RFC 1054 - Host extensions for IP multicasting - + * RFC 1112 - Host extensions for IP multicasting - V1 + * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) + * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 + * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ + * RFC 2113 - IP Router Alert Option - + *----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/igmp.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/stats.h" +#include "lwip/prot/igmp.h" + +#include + +static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr); +static err_t igmp_remove_group(struct netif *netif, struct igmp_group *group); +static void igmp_timeout(struct netif *netif, struct igmp_group *group); +static void igmp_start_timer(struct igmp_group *group, u8_t max_time); +static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); +static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif); +static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type); + +static ip4_addr_t allsystems; +static ip4_addr_t allrouters; + +/** + * Initialize the IGMP module + */ +void +igmp_init(void) +{ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); + + IP4_ADDR(&allsystems, 224, 0, 0, 1); + IP4_ADDR(&allrouters, 224, 0, 0, 2); +} + +/** + * Start IGMP processing on interface + * + * @param netif network interface on which start IGMP processing + */ +err_t +igmp_start(struct netif *netif) +{ + struct igmp_group *group; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", (void *)netif)); + + group = igmp_lookup_group(netif, &allsystems); + + if (group != NULL) { + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->use++; + + /* Allow the igmp messages at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); + ip4_addr_debug_print_val(IGMP_DEBUG, allsystems); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); + netif->igmp_mac_filter(netif, &allsystems, NETIF_ADD_MAC_FILTER); + } + + return ERR_OK; + } + + return ERR_MEM; +} + +/** + * Stop IGMP processing on interface + * + * @param netif network interface on which stop IGMP processing + */ +err_t +igmp_stop(struct netif *netif) +{ + struct igmp_group *group = netif_igmp_data(netif); + + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL); + + while (group != NULL) { + struct igmp_group *next = group->next; /* avoid use-after-free below */ + + /* disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); + ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); + netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); + } + + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report IGMP memberships for this interface + * + * @param netif network interface on which report IGMP memberships + */ +void +igmp_report_groups(struct netif *netif) +{ + struct igmp_group *group = netif_igmp_data(netif); + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void *)netif)); + + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + if (group != NULL) { + group = group->next; + } + + while (group != NULL) { + igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + group = group->next; + } +} + +/** + * Search for a group in the netif's igmp group list + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search for + * @return a struct igmp_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct igmp_group * +igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr) +{ + struct igmp_group *group = netif_igmp_data(ifp); + + while (group != NULL) { + if (ip4_addr_cmp(&(group->group_address), addr)) { + return group; + } + group = group->next; + } + + /* to be clearer, we return NULL here instead of + * 'group' (which is also NULL at this point). + */ + return NULL; +} + +/** + * Search for a specific igmp group and create a new one if not found- + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search + * @return a struct igmp_group*, + * NULL on memory error. + */ +static struct igmp_group * +igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) +{ + struct igmp_group *group; + struct igmp_group *list_head = netif_igmp_data(ifp); + + /* Search if the group already exists */ + group = igmp_lookfor_group(ifp, addr); + if (group != NULL) { + /* Group already exists. */ + return group; + } + + /* Group doesn't exist yet, create a new one */ + group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); + if (group != NULL) { + ip4_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = IGMP_GROUP_NON_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + + /* Ensure allsystems group is always first in list */ + if (list_head == NULL) { + /* this is the first entry in linked list */ + LWIP_ASSERT("igmp_lookup_group: first group must be allsystems", + (ip4_addr_cmp(addr, &allsystems) != 0)); + group->next = NULL; + netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); + } else { + /* append _after_ first entry */ + LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems", + (ip4_addr_cmp(addr, &allsystems) == 0)); + group->next = list_head->next; + list_head->next = group; + } + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group ? "" : "impossible to "))); + ip4_addr_debug_print(IGMP_DEBUG, addr); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)ifp)); + + return group; +} + +/** + * Remove a group from netif's igmp group list, but don't free it yet + * + * @param group the group to remove from the netif's igmp group list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +igmp_remove_group(struct netif *netif, struct igmp_group *group) +{ + err_t err = ERR_OK; + struct igmp_group *tmp_group; + + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) { + if (tmp_group->next == group) { + tmp_group->next = group->next; + break; + } + } + /* Group not found in netif's igmp group list */ + if (tmp_group == NULL) { + err = ERR_ARG; + } + + return err; +} + +/** + * Called from ip_input() if a new IGMP packet is received. + * + * @param p received igmp packet, p->payload pointing to the igmp header + * @param inp network interface on which the packet was received + * @param dest destination ip address of the igmp packet + */ +void +igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest) +{ + struct igmp_msg *igmp; + struct igmp_group *group; + struct igmp_group *groupref; + + IGMP_STATS_INC(igmp.recv); + + /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ + if (p->len < IGMP_MINLEN) { + pbuf_free(p); + IGMP_STATS_INC(igmp.lenerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); + return; + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); + ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->src); + LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); + ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->dest); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)inp)); + + /* Now calculate and check the checksum */ + igmp = (struct igmp_msg *)p->payload; + if (inet_chksum(igmp, p->len)) { + pbuf_free(p); + IGMP_STATS_INC(igmp.chkerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); + return; + } + + /* Packet is ok so find an existing group */ + group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ + + /* If group can be found or create... */ + if (!group) { + pbuf_free(p); + IGMP_STATS_INC(igmp.drop); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); + return; + } + + /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ + switch (igmp->igmp_msgtype) { + case IGMP_MEMB_QUERY: + /* IGMP_MEMB_QUERY to the "all systems" address ? */ + if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) { + /* THIS IS THE GENERAL QUERY */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + + if (igmp->igmp_maxresp == 0) { + IGMP_STATS_INC(igmp.rx_v1); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); + igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; + } else { + IGMP_STATS_INC(igmp.rx_general); + } + + groupref = netif_igmp_data(inp); + + /* Do not send messages on the all systems group address! */ + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + if (groupref != NULL) { + groupref = groupref->next; + } + + while (groupref) { + igmp_delaying_member(groupref, igmp->igmp_maxresp); + groupref = groupref->next; + } + } else { + /* IGMP_MEMB_QUERY to a specific group ? */ + if (!ip4_addr_isany(&igmp->igmp_group_address)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); + ip4_addr_debug_print_val(IGMP_DEBUG, igmp->igmp_group_address); + if (ip4_addr_cmp(dest, &allsystems)) { + ip4_addr_t groupaddr; + LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + /* we first need to re-look for the group since we used dest last time */ + ip4_addr_copy(groupaddr, igmp->igmp_group_address); + group = igmp_lookfor_group(inp, &groupaddr); + } else { + LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + } + + if (group != NULL) { + IGMP_STATS_INC(igmp.rx_group); + igmp_delaying_member(group, igmp->igmp_maxresp); + } else { + IGMP_STATS_INC(igmp.drop); + } + } else { + IGMP_STATS_INC(igmp.proterr); + } + } + break; + case IGMP_V2_MEMB_REPORT: + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); + IGMP_STATS_INC(igmp.rx_report); + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { + /* This is on a specific group we have already looked up */ + group->timer = 0; /* stopped */ + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + break; + default: + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", + igmp->igmp_msgtype, group->group_state, (void *)&group, (void *)inp)); + IGMP_STATS_INC(igmp.proterr); + break; + } + + pbuf_free(p); + return; +} + +/** + * @ingroup igmp + * Join a group on one network interface. + * + * @param ifaddr ip address of the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + NETIF_FOREACH(netif) { + /* Should we join this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + err = igmp_joingroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Return an error even if some network interfaces are joined */ + /** @todo undo any other netif already joined */ + return err; + } + } + } + + return err; +} + +/** + * @ingroup igmp + * Join a group on one network interface. + * + * @param netif the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif, an err_t otherwise + */ +err_t +igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) +{ + struct igmp_group *group; + + LWIP_ASSERT_CORE_LOCKED(); + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* make sure it is an igmp-enabled netif */ + LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); + + /* find group or create a new one if not found */ + group = igmp_lookup_group(netif, groupaddr); + + if (group != NULL) { + /* This should create a new group, check the state to make sure */ + if (group->group_state != IGMP_GROUP_NON_MEMBER) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n")); + } else { + /* OK - it was new group */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If first use of the group, allow the group at the MAC level */ + if ((group->use == 0) && (netif->igmp_mac_filter != NULL)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); + netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); + } + + IGMP_STATS_INC(igmp.tx_join); + igmp_send(netif, group, IGMP_V2_MEMB_REPORT); + + igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + + /* Need to work out where this timer comes from */ + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } + /* Increment group use */ + group->use++; + /* Join on this interface */ + return ERR_OK; + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n")); + return ERR_MEM; + } +} + +/** + * @ingroup igmp + * Leave a group on one network interface. + * + * @param ifaddr ip address of the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + NETIF_FOREACH(netif) { + /* Should we leave this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + err_t res = igmp_leavegroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Store this result if we have not yet gotten a success */ + err = res; + } + } + } + + return err; +} + +/** + * @ingroup igmp + * Leave a group on one network interface. + * + * @param netif the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif, an err_t otherwise + */ +err_t +igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) +{ + struct igmp_group *group; + + LWIP_ASSERT_CORE_LOCKED(); + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* make sure it is an igmp-enabled netif */ + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); + + /* find group */ + group = igmp_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Only send a leave if the flag is set according to the state diagram */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: Leaving group: ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If there is no other use of the group */ + if (group->use <= 1) { + /* Remove the group from the list */ + igmp_remove_group(netif, group); + + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n")); + IGMP_STATS_INC(igmp.tx_leave); + igmp_send(netif, group, IGMP_LEAVE_GROUP); + } + + /* Disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); + netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); + } + + /* Free group struct */ + memp_free(MEMP_IGMP_GROUP, group); + } else { + /* Decrement group use */ + group->use--; + } + return ERR_OK; + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n")); + return ERR_VAL; + } +} + +/** + * The igmp timer function (both for NO_SYS=1 and =0) + * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). + */ +void +igmp_tmr(void) +{ + struct netif *netif; + + NETIF_FOREACH(netif) { + struct igmp_group *group = netif_igmp_data(netif); + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + igmp_timeout(netif, group); + } + } + group = group->next; + } + } +} + +/** + * Called if a timeout for one group is reached. + * Sends a report for this group. + * + * @param group an igmp_group for which a timeout is reached + */ +static void +igmp_timeout(struct netif *netif, struct igmp_group *group) +{ + /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group + (unless it is the allsystems group) */ + if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); + ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)netif)); + + group->group_state = IGMP_GROUP_IDLE_MEMBER; + + IGMP_STATS_INC(igmp.tx_report); + igmp_send(netif, group, IGMP_V2_MEMB_REPORT); + } +} + +/** + * Start a timer for an igmp group + * + * @param group the igmp_group for which to start a timer + * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with + * every call to igmp_tmr()) + */ +static void +igmp_start_timer(struct igmp_group *group, u8_t max_time) +{ +#ifdef LWIP_RAND + group->timer = (u16_t)(max_time > 2 ? (LWIP_RAND() % max_time) : 1); +#else /* LWIP_RAND */ + /* ATTENTION: use this only if absolutely necessary! */ + group->timer = max_time / 2; +#endif /* LWIP_RAND */ + + if (group->timer == 0) { + group->timer = 1; + } +} + +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +static void +igmp_delaying_member(struct igmp_group *group, u8_t maxresp) +{ + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + igmp_start_timer(group, maxresp); + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } +} + + +/** + * Sends an IP packet on a network interface. This function constructs the IP header + * and calculates the IP header checksum. If the source IP address is NULL, + * the IP address of the outgoing network interface is filled in as source address. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + */ +static err_t +igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif) +{ + /* This is the "router alert" option */ + u16_t ra[2]; + ra[0] = PP_HTONS(ROUTER_ALERT); + ra[1] = 0x0000; /* Router shall examine packet */ + IGMP_STATS_INC(igmp.xmit); + return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); +} + +/** + * Send an igmp packet to a specific group. + * + * @param group the group to which to send the packet + * @param type the type of igmp packet to send + */ +static void +igmp_send(struct netif *netif, struct igmp_group *group, u8_t type) +{ + struct pbuf *p = NULL; + struct igmp_msg *igmp = NULL; + ip4_addr_t src = *IP4_ADDR_ANY4; + ip4_addr_t *dest = NULL; + + /* IP header + "router alert" option + IGMP header */ + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); + + if (p) { + igmp = (struct igmp_msg *)p->payload; + LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", + (p->len >= sizeof(struct igmp_msg))); + ip4_addr_copy(src, *netif_ip4_addr(netif)); + + if (type == IGMP_V2_MEMB_REPORT) { + dest = &(group->group_address); + ip4_addr_copy(igmp->igmp_group_address, group->group_address); + group->last_reporter_flag = 1; /* Remember we were the last to report */ + } else { + if (type == IGMP_LEAVE_GROUP) { + dest = &allrouters; + ip4_addr_copy(igmp->igmp_group_address, group->group_address); + } + } + + if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { + igmp->igmp_msgtype = type; + igmp->igmp_maxresp = 0; + igmp->igmp_checksum = 0; + igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); + + igmp_ip_output_if(p, &src, dest, netif); + } + + pbuf_free(p); + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); + IGMP_STATS_INC(igmp.memerr); + } +} + +#endif /* LWIP_IPV4 && LWIP_IGMP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4.c new file mode 100644 index 0000000..26c26a9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4.c @@ -0,0 +1,1132 @@ +/** + * @file + * This is the IPv4 layer implementation for incoming and outgoing IP traffic. + * + * @see ip_frag.c + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip4_frag.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/igmp.h" +#include "lwip/priv/raw_priv.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/autoip.h" +#include "lwip/stats.h" +#include "lwip/prot/iana.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Set this to 0 in the rare case of wanting to call an extra function to + * generate the IP checksum (in contrast to calculating it on-the-fly). */ +#ifndef LWIP_INLINE_IP_CHKSUM +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define LWIP_INLINE_IP_CHKSUM 0 +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define LWIP_INLINE_IP_CHKSUM 1 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#endif + +#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP_INLINE 1 +#else +#define CHECKSUM_GEN_IP_INLINE 0 +#endif + +#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 + +/** Some defines for DHCP to let link-layer-addressed packets through while the + * netif is down. + * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT(port) + * to return 1 if the port is accepted and 0 if the port is not accepted. + */ +#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) +/* accept DHCP client port and custom port */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(LWIP_IANA_PORT_DHCP_CLIENT)) \ + || (LWIP_IP_ACCEPT_UDP_PORT(port))) +#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept custom port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) +#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept DHCP client port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(LWIP_IANA_PORT_DHCP_CLIENT)) +#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ + +#else /* LWIP_DHCP */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 +#endif /* LWIP_DHCP */ + +/** The IP header ID of the next outgoing IP packet */ +static u16_t ip_id; + +#if LWIP_MULTICAST_TX_OPTIONS +/** The default netif used for multicast */ +static struct netif *ip4_default_multicast_netif; + +/** + * @ingroup ip4 + * Set a default netif for IPv4 multicast. */ +void +ip4_set_default_multicast_netif(struct netif *default_multicast_netif) +{ + ip4_default_multicast_netif = default_multicast_netif; +} +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +/** + * Source based IPv4 routing must be fully implemented in + * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides the parameters. + */ +struct netif * +ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) +{ + if (src != NULL) { + /* when src==NULL, the hook is called from ip4_route(dest) */ + struct netif *netif = LWIP_HOOK_IP4_ROUTE_SRC(src, dest); + if (netif != NULL) { + return netif; + } + } + return ip4_route(dest); +} +#endif /* LWIP_HOOK_IP4_ROUTE_SRC */ + +/** + * Finds the appropriate network interface for a given IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + * + * @param dest the destination IP address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip4_route(const ip4_addr_t *dest) +{ +#if !LWIP_SINGLE_NETIF + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_MULTICAST_TX_OPTIONS + /* Use administratively selected interface for multicast by default */ + if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) { + return ip4_default_multicast_netif; + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + /* bug #54569: in case LWIP_SINGLE_NETIF=1 and LWIP_DEBUGF() disabled, the following loop is optimized away */ + LWIP_UNUSED_ARG(dest); + + /* iterate through netifs */ + NETIF_FOREACH(netif) { + /* is the netif up, does it have a link and a valid address? */ + if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* network mask matches? */ + if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { + /* return netif on which to forward IP packet */ + return netif; + } + /* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */ + if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + } + +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + /* loopif is disabled, looopback traffic is passed through any netif */ + if (ip4_addr_isloopback(dest)) { + /* don't check for link on loopback traffic */ + if (netif_default != NULL && netif_is_up(netif_default)) { + return netif_default; + } + /* default netif is not up, just use any netif for loopback traffic */ + NETIF_FOREACH(netif) { + if (netif_is_up(netif)) { + return netif; + } + } + return NULL; + } +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC + netif = LWIP_HOOK_IP4_ROUTE_SRC(NULL, dest); + if (netif != NULL) { + return netif; + } +#elif defined(LWIP_HOOK_IP4_ROUTE) + netif = LWIP_HOOK_IP4_ROUTE(dest); + if (netif != NULL) { + return netif; + } +#endif +#endif /* !LWIP_SINGLE_NETIF */ + + if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || + ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) { + /* No matching netif found and default netif is not usable. + If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + MIB2_STATS_INC(mib2.ipoutnoroutes); + return NULL; + } + + return netif_default; +} + +#if IP_FORWARD +/** + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + * @param p the packet to forward + * @return 1: can forward 0: discard + */ +static int +ip4_canforward(struct pbuf *p) +{ + u32_t addr = lwip_htonl(ip4_addr_get_u32(ip4_current_dest_addr())); + +#ifdef LWIP_HOOK_IP4_CANFORWARD + int ret = LWIP_HOOK_IP4_CANFORWARD(p, addr); + if (ret >= 0) { + return ret; + } +#endif /* LWIP_HOOK_IP4_CANFORWARD */ + + if (p->flags & PBUF_FLAG_LLBCAST) { + /* don't route link-layer broadcasts */ + return 0; + } + if ((p->flags & PBUF_FLAG_LLMCAST) || IP_MULTICAST(addr)) { + /* don't route link-layer multicasts (use LWIP_HOOK_IP4_CANFORWARD instead) */ + return 0; + } + if (IP_EXPERIMENTAL(addr)) { + return 0; + } + if (IP_CLASSA(addr)) { + u32_t net = addr & IP_CLASSA_NET; + if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { + /* don't route loopback packets */ + return 0; + } + } + return 1; +} + +/** + * Forwards an IP packet. It finds an appropriate route for the + * packet, decrements the TTL value of the packet, adjusts the + * checksum and outputs the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IP header of the input packet + * @param inp the netif on which this packet was received + */ +static void +ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + PERF_START; + LWIP_UNUSED_ARG(inp); + + if (!ip4_canforward(p)) { + goto return_noroute; + } + + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip4_addr_islinklocal(ip4_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + goto return_noroute; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip4_route_src(ip4_current_src_addr(), ip4_current_dest_addr()); + if (netif == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + /* @todo: send ICMP_DUR_NET? */ + goto return_noroute; + } +#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not bouncing packets back on incoming interface.\n")); + goto return_noroute; + } +#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ + + /* decrement TTL */ + IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); + /* send ICMP if TTL == 0 */ + if (IPH_TTL(iphdr) == 0) { + MIB2_STATS_INC(mib2.ipinhdrerrors); +#if LWIP_ICMP + /* Don't send ICMP messages in response to ICMP messages */ + if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { + icmp_time_exceeded(p, ICMP_TE_TTL); + } +#endif /* LWIP_ICMP */ + return; + } + + /* Incrementally update the IP checksum. */ + if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) { + IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1)); + } else { + IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100))); + } + + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + + IP_STATS_INC(ip.fw); + MIB2_STATS_INC(mib2.ipforwdatagrams); + IP_STATS_INC(ip.xmit); + + PERF_STOP("ip4_forward"); + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) { + if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { +#if IP_FRAG + ip4_frag(p, netif, ip4_current_dest_addr()); +#else /* IP_FRAG */ + /* @todo: send ICMP Destination Unreachable code 13 "Communication administratively prohibited"? */ +#endif /* IP_FRAG */ + } else { +#if LWIP_ICMP + /* send ICMP Destination Unreachable code 4: "Fragmentation Needed and DF Set" */ + icmp_dest_unreach(p, ICMP_DUR_FRAG); +#endif /* LWIP_ICMP */ + } + return; + } + /* transmit pbuf on chosen interface */ + netif->output(netif, p, ip4_current_dest_addr()); + return; +return_noroute: + MIB2_STATS_INC(mib2.ipoutnoroutes); +} +#endif /* IP_FORWARD */ + +/** Return true if the current input packet should be accepted on this netif */ +static int +ip4_input_accept(struct netif *netif) +{ + LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", + ip4_addr_get_u32(ip4_current_dest_addr()), ip4_addr_get_u32(netif_ip4_addr(netif)), + ip4_addr_get_u32(ip4_current_dest_addr()) & ip4_addr_get_u32(netif_ip4_netmask(netif)), + ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)), + ip4_addr_get_u32(ip4_current_dest_addr()) & ~ip4_addr_get_u32(netif_ip4_netmask(netif)))); + + /* interface is up and configured? */ + if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) { + /* unicast to this interface address? */ + if (ip4_addr_cmp(ip4_current_dest_addr(), netif_ip4_addr(netif)) || + /* or broadcast on this interface network address? */ + ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + || (ip4_addr_get_u32(ip4_current_dest_addr()) == PP_HTONL(IPADDR_LOOPBACK)) +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ + ) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* accept on this netif */ + return 1; + } +#if LWIP_AUTOIP + /* connections to link-local addresses must persist after changing + the netif's address (RFC3927 ch. 1.9) */ + if (autoip_accept_packet(netif, ip4_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* accept on this netif */ + return 1; + } +#endif /* LWIP_AUTOIP */ + } + return 0; +} + +/** + * This function is called by the network interface device driver when + * an IP packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * @param p the received IP packet (p->payload points to IP header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + * processed, but currently always returns ERR_OK) + */ +err_t +ip4_input(struct pbuf *p, struct netif *inp) +{ + const struct ip_hdr *iphdr; + struct netif *netif; + u16_t iphdr_hlen; + u16_t iphdr_len; +#if IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP + int check_ip_src = 1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP */ +#if LWIP_RAW + raw_input_state_t raw_status; +#endif /* LWIP_RAW */ + + LWIP_ASSERT_CORE_LOCKED(); + + IP_STATS_INC(ip.recv); + MIB2_STATS_INC(mib2.ipinreceives); + + /* identify the IP header */ + iphdr = (struct ip_hdr *)p->payload; + if (IPH_V(iphdr) != 4) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", (u16_t)IPH_V(iphdr))); + ip4_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.err); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinhdrerrors); + return ERR_OK; + } + +#ifdef LWIP_HOOK_IP4_INPUT + if (LWIP_HOOK_IP4_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + + /* obtain IP header length in bytes */ + iphdr_hlen = IPH_HL_BYTES(iphdr); + /* obtain ip length in bytes */ + iphdr_len = lwip_ntohs(IPH_LEN(iphdr)); + + /* Trim pbuf. This is especially required for packets < 60 bytes. */ + if (iphdr_len < p->tot_len) { + pbuf_realloc(p, iphdr_len); + } + + /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ + if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len) || (iphdr_hlen < IP_HLEN)) { + if (iphdr_hlen < IP_HLEN) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("ip4_input: short IP header (%"U16_F" bytes) received, IP packet dropped\n", iphdr_hlen)); + } + if (iphdr_hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_hlen, p->len)); + } + if (iphdr_len > p->tot_len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_len, p->tot_len)); + } + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.lenerr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipindiscards); + return ERR_OK; + } + + /* verify checksum */ +#if CHECKSUM_CHECK_IP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) { + if (inet_chksum(iphdr, iphdr_hlen) != 0) { + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); + ip4_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.chkerr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinhdrerrors); + return ERR_OK; + } + } +#endif + + /* copy IP addresses to aligned ip_addr_t */ + ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest); + ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src); + + /* match packet against an interface, i.e. is this packet for us? */ + if (ip4_addr_ismulticast(ip4_current_dest_addr())) { +#if LWIP_IGMP + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip4_current_dest_addr()))) { + /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */ + ip4_addr_t allsystems; + IP4_ADDR(&allsystems, 224, 0, 0, 1); + if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) && + ip4_addr_isany(ip4_current_src_addr())) { + check_ip_src = 0; + } + netif = inp; + } else { + netif = NULL; + } +#else /* LWIP_IGMP */ + if ((netif_is_up(inp)) && (!ip4_addr_isany_val(*netif_ip4_addr(inp)))) { + netif = inp; + } else { + netif = NULL; + } +#endif /* LWIP_IGMP */ + } else { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. */ + if (ip4_input_accept(inp)) { + netif = inp; + } else { + netif = NULL; +#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF + /* Packets sent to the loopback address must not be accepted on an + * interface that does not have the loopback address assigned to it, + * unless a non-loopback interface is used for loopback traffic. */ + if (!ip4_addr_isloopback(ip4_current_dest_addr())) +#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ + { +#if !LWIP_SINGLE_NETIF + NETIF_FOREACH(netif) { + if (netif == inp) { + /* we checked that before already */ + continue; + } + if (ip4_input_accept(netif)) { + break; + } + } +#endif /* !LWIP_SINGLE_NETIF */ + } + } + } + +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed + * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. + * According to RFC 1542 section 3.1.1, referred by RFC 2131). + * + * If you want to accept private broadcast communication while a netif is down, + * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: + * + * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) + */ + if (netif == NULL) { + /* remote port is DHCP server? */ + if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + const struct udp_hdr *udphdr = (const struct udp_hdr *)((const u8_t *)iphdr + iphdr_hlen); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n", + lwip_ntohs(udphdr->dest))); + if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n")); + netif = inp; + check_ip_src = 0; + } + } + } +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + + /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ +#if LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING + if (check_ip_src +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ + && !ip4_addr_isany_val(*ip4_current_src_addr()) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + ) +#endif /* LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { + if ((ip4_addr_isbroadcast(ip4_current_src_addr(), inp)) || + (ip4_addr_ismulticast(ip4_current_src_addr()))) { + /* packet source is not valid */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip4_input: packet source is not valid.\n")); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinaddrerrors); + MIB2_STATS_INC(mib2.ipindiscards); + return ERR_OK; + } + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: packet not for us.\n")); +#if IP_FORWARD + /* non-broadcast packet? */ + if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), inp)) { + /* try to forward IP packet on (other) interfaces */ + ip4_forward(p, (struct ip_hdr *)p->payload, inp); + } else +#endif /* IP_FORWARD */ + { + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinaddrerrors); + MIB2_STATS_INC(mib2.ipindiscards); + } + pbuf_free(p); + return ERR_OK; + } + /* packet consists of multiple fragments? */ + if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { +#if IP_REASSEMBLY /* packet fragment reassembly code present? */ + LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip4_reass()\n", + lwip_ntohs(IPH_ID(iphdr)), p->tot_len, lwip_ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) * 8))); + /* reassemble the packet*/ + p = ip4_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + return ERR_OK; + } + iphdr = (const struct ip_hdr *)p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ + pbuf_free(p); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", + lwip_ntohs(IPH_OFFSET(iphdr)))); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + MIB2_STATS_INC(mib2.ipinunknownprotos); + return ERR_OK; +#endif /* IP_REASSEMBLY */ + } + +#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ + +#if LWIP_IGMP + /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ + if ((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { +#else + if (iphdr_hlen > IP_HLEN) { +#endif /* LWIP_IGMP */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); + pbuf_free(p); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + MIB2_STATS_INC(mib2.ipinunknownprotos); + return ERR_OK; + } +#endif /* IP_OPTIONS_ALLOWED == 0 */ + + /* send to upper layers */ + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: \n")); + ip4_debug_print(p); + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + + ip_data.current_netif = netif; + ip_data.current_input_netif = inp; + ip_data.current_ip4_header = iphdr; + ip_data.current_ip_header_tot_len = IPH_HL_BYTES(iphdr); + +#if LWIP_RAW + /* raw input did not eat the packet? */ + raw_status = raw_input(p, inp); + if (raw_status != RAW_INPUT_EATEN) +#endif /* LWIP_RAW */ + { + pbuf_remove_header(p, iphdr_hlen); /* Move to payload, no check necessary. */ + + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP + case IP_PROTO_UDP: +#if LWIP_UDPLITE + case IP_PROTO_UDPLITE: +#endif /* LWIP_UDPLITE */ + MIB2_STATS_INC(mib2.ipindelivers); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP_PROTO_TCP: + MIB2_STATS_INC(mib2.ipindelivers); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP + case IP_PROTO_ICMP: + MIB2_STATS_INC(mib2.ipindelivers); + icmp_input(p, inp); + break; +#endif /* LWIP_ICMP */ +#if LWIP_IGMP + case IP_PROTO_IGMP: + igmp_input(p, inp, ip4_current_dest_addr()); + break; +#endif /* LWIP_IGMP */ + default: +#if LWIP_RAW + if (raw_status == RAW_INPUT_DELIVERED) { + MIB2_STATS_INC(mib2.ipindelivers); + } else +#endif /* LWIP_RAW */ + { +#if LWIP_ICMP + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) && + !ip4_addr_ismulticast(ip4_current_dest_addr())) { + pbuf_header_force(p, (s16_t)iphdr_hlen); /* Move to ip header, no check necessary. */ + icmp_dest_unreach(p, ICMP_DUR_PROTO); + } +#endif /* LWIP_ICMP */ + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", (u16_t)IPH_PROTO(iphdr))); + + IP_STATS_INC(ip.proterr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinunknownprotos); + } + pbuf_free(p); + break; + } + } + + /* @todo: this is not really necessary... */ + ip_data.current_netif = NULL; + ip_data.current_input_netif = NULL; + ip_data.current_ip4_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip4_addr_set_any(ip4_current_src_addr()); + ip4_addr_set_any(ip4_current_dest_addr()); + + return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + * If the destination IP address is LWIP_IP_HDRINCL, p is assumed to already + * include an IP header and p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + * + * @note ip_id: RFC791 "some host may be able to simply use + * unique identifiers independent of destination" + */ +err_t +ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip4_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +err_t +ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ + const ip4_addr_t *src_used = src; + if (dest != LWIP_IP_HDRINCL) { + if (ip4_addr_isany(src)) { + src_used = netif_ip4_addr(netif); + } + } + +#if IP_OPTIONS_SEND + return ip4_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif, + ip_options, optlen); +#else /* IP_OPTIONS_SEND */ + return ip4_output_if_src(p, src_used, dest, ttl, tos, proto, netif); +#endif /* IP_OPTIONS_SEND */ +} + +/** + * Same as ip_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip4_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if_opt() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ + struct ip_hdr *iphdr; + ip4_addr_t dest_addr; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum = 0; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + MIB2_STATS_INC(mib2.ipoutrequests); + + /* Should the IP header be generated or is it already included in p? */ + if (dest != LWIP_IP_HDRINCL) { + u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND + u16_t optlen_aligned = 0; + if (optlen != 0) { +#if CHECKSUM_GEN_IP_INLINE + int i; +#endif /* CHECKSUM_GEN_IP_INLINE */ + if (optlen > (IP_HLEN_MAX - IP_HLEN)) { + /* optlen too long */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: optlen too long\n")); + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_VAL; + } + /* round up to a multiple of 4 */ + optlen_aligned = (u16_t)((optlen + 3) & ~3); + ip_hlen = (u16_t)(ip_hlen + optlen_aligned); + /* First write in the IP options */ + if (pbuf_add_header(p, optlen_aligned)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: not enough room for IP options in pbuf\n")); + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_BUF; + } + MEMCPY(p->payload, ip_options, optlen); + if (optlen < optlen_aligned) { + /* zero the remaining bytes */ + memset(((char *)p->payload) + optlen, 0, (size_t)(optlen_aligned - optlen)); + } +#if CHECKSUM_GEN_IP_INLINE + for (i = 0; i < optlen_aligned / 2; i++) { + chk_sum += ((u16_t *)p->payload)[i]; + } +#endif /* CHECKSUM_GEN_IP_INLINE */ + } +#endif /* IP_OPTIONS_SEND */ + /* generate IP header */ + if (pbuf_add_header(p, IP_HLEN)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: not enough room for IP header in pbuf\n")); + + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_BUF; + } + + iphdr = (struct ip_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", + (p->len >= sizeof(struct ip_hdr))); + + IPH_TTL_SET(iphdr, ttl); + IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += PP_NTOHS(proto | (ttl << 8)); +#endif /* CHECKSUM_GEN_IP_INLINE */ + + /* dest cannot be NULL here */ + ip4_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + IPH_VHL_SET(iphdr, 4, ip_hlen / 4); + IPH_TOS_SET(iphdr, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8)); +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_LEN_SET(iphdr, lwip_htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_OFFSET_SET(iphdr, 0); + IPH_ID_SET(iphdr, lwip_htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ + ++ip_id; + + if (src == NULL) { + ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4); + } else { + /* src cannot be NULL here */ + ip4_addr_copy(iphdr->src, *src); + } + +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; + chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); + chk_sum = (chk_sum >> 16) + chk_sum; + chk_sum = ~chk_sum; + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + iphdr->_chksum = (u16_t)chk_sum; /* network order */ + } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + IPH_CHKSUM_SET(iphdr, 0); + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ +#else /* CHECKSUM_GEN_IP_INLINE */ + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); + } +#endif /* CHECKSUM_GEN_IP */ +#endif /* CHECKSUM_GEN_IP_INLINE */ + } else { + /* IP header already included in p */ + if (p->len < IP_HLEN) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: LWIP_IP_HDRINCL but pbuf is too short\n")); + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_BUF; + } + iphdr = (struct ip_hdr *)p->payload; + ip4_addr_copy(dest_addr, iphdr->dest); + dest = &dest_addr; + } + + IP_STATS_INC(ip.xmit); + + LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); + ip4_debug_print(p); + +#if ENABLE_LOOPBACK + if (ip4_addr_cmp(dest, netif_ip4_addr(netif)) +#if !LWIP_HAVE_LOOPIF + || ip4_addr_isloopback(dest) +#endif /* !LWIP_HAVE_LOOPIF */ + ) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); + return netif_loop_output(netif, p); + } +#if LWIP_MULTICAST_TX_OPTIONS + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p); + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#endif /* ENABLE_LOOPBACK */ +#if IP_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) { + return ip4_frag(p, netif, dest); + } +#endif /* IP_FRAG */ + + LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n")); + return netif->output(netif, p, dest); +} + +/** + * Simple interface to ip_output_if. It finds the outgoing network + * interface and calls upon ip_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto) +{ + struct netif *netif; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if ((netif = ip4_route_src(src, dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + return ip4_output_if(p, src, dest, ttl, tos, proto, netif); +} + +#if LWIP_NETIF_USE_HINTS +/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif_hint netif output hint pointer set to netif->hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif_hint *netif_hint) +{ + struct netif *netif; + err_t err; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if ((netif = ip4_route_src(src, dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + NETIF_SET_HINTS(netif, netif_hint); + err = ip4_output_if(p, src, dest, ttl, tos, proto, netif); + NETIF_RESET_HINTS(netif); + + return err; +} +#endif /* LWIP_NETIF_USE_HINTS*/ + +#if IP_DEBUG +/* Print an IP header by using LWIP_DEBUGF + * @param p an IP packet, p->payload pointing to the IP header + */ +void +ip4_debug_print(struct pbuf *p) +{ + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + + LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", + (u16_t)IPH_V(iphdr), + (u16_t)IPH_HL(iphdr), + (u16_t)IPH_TOS(iphdr), + lwip_ntohs(IPH_LEN(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", + lwip_ntohs(IPH_ID(iphdr)), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 15 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 14 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 13 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", + (u16_t)IPH_TTL(iphdr), + (u16_t)IPH_PROTO(iphdr), + lwip_ntohs(IPH_CHKSUM(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", + ip4_addr1_16_val(iphdr->src), + ip4_addr2_16_val(iphdr->src), + ip4_addr3_16_val(iphdr->src), + ip4_addr4_16_val(iphdr->src))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", + ip4_addr1_16_val(iphdr->dest), + ip4_addr2_16_val(iphdr->dest), + ip4_addr3_16_val(iphdr->dest), + ip4_addr4_16_val(iphdr->dest))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ + +#endif /* LWIP_IPV4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_addr.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_addr.c new file mode 100644 index 0000000..f99d8dd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_addr.c @@ -0,0 +1,323 @@ +/** + * @file + * This is the IPv4 address tools implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); +const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); + +/** + * Determine if an address is a broadcast address on a network interface + * + * @param addr address to be checked + * @param netif the network interface against which the address is checked + * @return returns non-zero if the address is a broadcast address + */ +u8_t +ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif) +{ + ip4_addr_t ipaddr; + ip4_addr_set_u32(&ipaddr, addr); + + /* all ones (broadcast) or all zeroes (old skool broadcast) */ + if ((~addr == IPADDR_ANY) || + (addr == IPADDR_ANY)) { + return 1; + /* no broadcast support on this network interface? */ + } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { + /* the given address cannot be a broadcast address + * nor can we check against any broadcast addresses */ + return 0; + /* address matches network interface address exactly? => no broadcast */ + } else if (addr == ip4_addr_get_u32(netif_ip4_addr(netif))) { + return 0; + /* on the same (sub) network... */ + } else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) + /* ...and host identifier bits are all ones? =>... */ + && ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) == + (IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) { + /* => network broadcast address */ + return 1; + } else { + return 0; + } +} + +/** Checks if a netmask is valid (starting with ones, then only zeros) + * + * @param netmask the IPv4 netmask to check (in network byte order!) + * @return 1 if the netmask is valid, 0 if it is not + */ +u8_t +ip4_addr_netmask_valid(u32_t netmask) +{ + u32_t mask; + u32_t nm_hostorder = lwip_htonl(netmask); + + /* first, check for the first zero */ + for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) == 0) { + break; + } + } + /* then check that there is no one */ + for (; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) != 0) { + /* there is a one after the first zero -> invalid */ + return 0; + } + } + /* no one after the first zero -> valid */ + return 1; +} + +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @return ip address in network order + */ +u32_t +ipaddr_addr(const char *cp) +{ + ip4_addr_t val; + + if (ip4addr_aton(cp, &val)) { + return ip4_addr_get_u32(&val); + } + return (IPADDR_NONE); +} + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip4addr_aton(const char *cp, ip4_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!lwip_isdigit(c)) { + return 0; + } + val = 0; + base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') { + base = 16; + c = *++cp; + } else { + base = 8; + } + } + for (;;) { + if (lwip_isdigit(c)) { + if((base == 8) && ((u32_t)(c - '0') >= 8)) + break; + val = (val * base) + (u32_t)(c - '0'); + c = *++cp; + } else if (base == 16 && lwip_isxdigit(c)) { + val = (val << 4) | (u32_t)(c + 10 - (lwip_islower(c) ? 'a' : 'A')); + c = *++cp; + } else { + break; + } + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) { + return 0; + } + *pp++ = val; + c = *++cp; + } else { + break; + } + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !lwip_isspace(c)) { + return 0; + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + + case 0: + return 0; /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) { + return 0; + } + if (parts[0] > 0xff) { + return 0; + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff)) { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + LWIP_ASSERT("unhandled", 0); + break; + } + if (addr) { + ip4_addr_set_u32(addr, lwip_htonl(val)); + } + return 1; +} + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char * +ip4addr_ntoa(const ip4_addr_t *addr) +{ + static char str[IP4ADDR_STRLEN_MAX]; + return ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX); +} + +/** + * Same as ip4addr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen) +{ + u32_t s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + int len = 0; + + s_addr = ip4_addr_get_u32(addr); + + rp = buf; + ap = (u8_t *)&s_addr; + for (n = 0; n < 4; n++) { + i = 0; + do { + rem = *ap % (u8_t)10; + *ap /= (u8_t)10; + inv[i++] = (char)('0' + rem); + } while (*ap); + while (i--) { + if (len++ >= buflen) { + return NULL; + } + *rp++ = inv[i]; + } + if (len++ >= buflen) { + return NULL; + } + *rp++ = '.'; + ap++; + } + *--rp = 0; + return buf; +} + +#endif /* LWIP_IPV4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_frag.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_frag.c new file mode 100644 index 0000000..a445530 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv4/ip4_frag.c @@ -0,0 +1,894 @@ +/** + * @file + * This is the IPv4 packet segmentation and reassembly implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * Simon Goldschmidt + * original reassembly code by Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip4_frag.h" +#include "lwip/def.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/stats.h" +#include "lwip/icmp.h" + +#include + +#if IP_REASSEMBLY +/** + * The IP reassembly code currently has the following limitations: + * - IP header options are not supported + * - fragments must not overlap (e.g. due to different routes), + * currently, overlapping or duplicate fragments are thrown away + * if IP_REASS_CHECK_OVERLAP=1 (the default)! + * + * @todo: work with IP header options + */ + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +#define IP_REASS_VALIDATE_TELEGRAM_FINISHED 1 +#define IP_REASS_VALIDATE_PBUF_QUEUED 0 +#define IP_REASS_VALIDATE_PBUF_DROPPED -1 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IP header, since it replaces + * the IP header in memory in incoming fragments (after copying it) to keep + * track of the various fragments. (-> If the IP header doesn't need packing, + * this struct doesn't need packing, too.) + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ + (ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ + ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ + IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 + +/* global variables */ +static struct ip_reassdata *reassdatagrams; +static u16_t ip_reass_pbufcount; + +/* function prototypes */ +static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); +static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). + */ +void +ip_reass_tmr(void) +{ + struct ip_reassdata *r, *prev = NULL; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n", (u16_t)r->timer)); + prev = r; + r = r->next; + } else { + /* reassembly timed out */ + struct ip_reassdata *tmp; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip_reass_free_complete_datagram(tmp, prev); + } + } +} + +/** + * Free a datagram (struct ip_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip_reass_pbufcount), + * SNMP counters and sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + * @param prev the previous datagram in the linked list + * @return the number of pbufs freed + */ +static int +ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + u16_t pbufs_freed = 0; + u16_t clen; + struct pbuf *p; + struct ip_reass_helper *iprh; + + LWIP_ASSERT("prev != ipr", prev != ipr); + if (prev != NULL) { + LWIP_ASSERT("prev->next == ipr", prev->next == ipr); + } + + MIB2_STATS_INC(mib2.ipreasmfails); +#if LWIP_ICMP + iprh = (struct ip_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, copy the original header into it. */ + SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); + icmp_time_exceeded(p, ICMP_TE_FRAG); + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed = (u16_t)(pbufs_freed + clen); + pbuf_free(p); + } +#endif /* LWIP_ICMP */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed = (u16_t)(pbufs_freed + clen); + pbuf_free(pcur); + } + /* Then, unchain the struct ip_reassdata from the list and free it. */ + ip_reass_dequeue_datagram(ipr, prev); + LWIP_ASSERT("ip_reass_pbufcount >= pbufs_freed", ip_reass_pbufcount >= pbufs_freed); + ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount - pbufs_freed); + + return pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram 'fraghdr' belongs to is not freed! + * + * @param fraghdr IP header of the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + * @return the number of pbufs freed + */ +static int +ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) +{ + /* @todo Can't we simply remove the last datagram in the + * linked list behind reassdatagrams? + */ + struct ip_reassdata *r, *oldest, *prev, *oldest_prev; + int pbufs_freed = 0, pbufs_freed_current; + int other_datagrams; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the datagram that 'fraghdr' belongs to! */ + do { + oldest = NULL; + prev = NULL; + oldest_prev = NULL; + other_datagrams = 0; + r = reassdatagrams; + while (r != NULL) { + if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { + /* Not the same datagram as fraghdr */ + other_datagrams++; + if (oldest == NULL) { + oldest = r; + oldest_prev = prev; + } else if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + oldest_prev = prev; + } + } + if (r->next != NULL) { + prev = r; + } + r = r->next; + } + if (oldest != NULL) { + pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev); + pbufs_freed += pbufs_freed_current; + } + } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); + return pbufs_freed; +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Enqueues a new fragment into the fragment queue + * @param fraghdr points to the new fragments IP hdr + * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) + * @return A pointer to the queue location into which the fragment was enqueued + */ +static struct ip_reassdata * +ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) +{ + struct ip_reassdata *ipr; +#if ! IP_REASS_FREE_OLDEST + LWIP_UNUSED_ARG(clen); +#endif + + /* No matching previous fragment found, allocate a new reassdata struct */ + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + } + if (ipr == NULL) +#endif /* IP_REASS_FREE_OLDEST */ + { + IPFRAG_STATS_INC(ip_frag.memerr); + LWIP_DEBUGF(IP_REASS_DEBUG, ("Failed to alloc reassdata struct\n")); + return NULL; + } + } + memset(ipr, 0, sizeof(struct ip_reassdata)); + ipr->timer = IP_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + /* copy the ip header for later tests and input */ + /* @todo: no ip options supported? */ + SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); + return ipr; +} + +/** + * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. + * @param ipr points to the queue entry to dequeue + */ +static void +ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + /* dequeue the reass struct */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", prev != NULL); + prev->next = ipr->next; + } + + /* now we can free the ip_reassdata struct */ + memp_free(MEMP_REASSDATA, ipr); +} + +/** + * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list + * will grow over time as new pbufs are rx. + * Also checks that the datagram passes basic continuity checks (if the last + * fragment was received at least once). + * @param ipr points to the reassembly state + * @param new_p points to the pbuf for the current fragment + * @param is_last is 1 if this pbuf has MF==0 (ipr->flags not updated yet) + * @return see IP_REASS_VALIDATE_* defines + */ +static int +ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p, int is_last) +{ + struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev = NULL; + struct pbuf *q; + u16_t offset, len; + u8_t hlen; + struct ip_hdr *fraghdr; + int valid = 1; + + /* Extract length and fragment offset from current fragment */ + fraghdr = (struct ip_hdr *)new_p->payload; + len = lwip_ntohs(IPH_LEN(fraghdr)); + hlen = IPH_HL_BYTES(fraghdr); + if (hlen > len) { + /* invalid datagram */ + return IP_REASS_VALIDATE_PBUF_DROPPED; + } + len = (u16_t)(len - hlen); + offset = IPH_OFFSET_BYTES(fraghdr); + + /* overwrite the fragment's ip header from the pbuf with our helper struct, + * and setup the embedded helper structure. */ + /* make sure the struct ip_reass_helper fits into the IP header */ + LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", + sizeof(struct ip_reass_helper) <= IP_HLEN); + iprh = (struct ip_reass_helper *)new_p->payload; + iprh->next_pbuf = NULL; + iprh->start = offset; + iprh->end = (u16_t)(offset + len); + if (iprh->end < offset) { + /* u16_t overflow, cannot handle this */ + return IP_REASS_VALIDATE_PBUF_DROPPED; + } + + /* Iterate through until we either get to the end of the list (append), + * or we find one with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip_reass_helper *)q->payload; + if (iprh->start < iprh_tmp->start) { + /* the new pbuf should be inserted before this */ + iprh->next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ +#if IP_REASS_CHECK_OVERLAP + if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { + /* fragment overlaps with previous or following, throw away */ + return IP_REASS_VALIDATE_PBUF_DROPPED; + } +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + if (iprh_prev->end != iprh->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + if (iprh->end > iprh_tmp->start) { + /* fragment overlaps with following, throw away */ + return IP_REASS_VALIDATE_PBUF_DROPPED; + } +#endif /* IP_REASS_CHECK_OVERLAP */ + /* fragment with the lowest offset */ + ipr->p = new_p; + } + break; + } else if (iprh->start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + return IP_REASS_VALIDATE_PBUF_DROPPED; +#if IP_REASS_CHECK_OVERLAP + } else if (iprh->start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + return IP_REASS_VALIDATE_PBUF_DROPPED; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no holes. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + if (iprh_prev->end != iprh->start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = new_p; + } + } + + /* At this point, the validation part begins: */ + /* If we already received the last fragment */ + if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) { + /* and had no holes so far */ + if (valid) { + /* then check if the rest of the fragments is here */ + /* Check if the queue starts with the first datagram */ + if ((ipr->p == NULL) || (((struct ip_reass_helper *)ipr->p->payload)->start != 0)) { + valid = 0; + } else { + /* and check that there are no holes after this datagram */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while (q != NULL) { + iprh = (struct ip_reass_helper *)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + /* if still valid, all fragments are received + * (because to the MF==0 already arrived */ + if (valid) { + LWIP_ASSERT("sanity check", ipr->p != NULL); + LWIP_ASSERT("sanity check", + ((struct ip_reass_helper *)ipr->p->payload) != iprh); + LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", + iprh->next_pbuf == NULL); + } + } + } + /* If valid is 0 here, there are some fragments missing in the middle + * (since MF == 0 has already arrived). Such datagrams simply time out if + * no more fragments are received... */ + return valid ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : IP_REASS_VALIDATE_PBUF_QUEUED; + } + /* If we come here, not all fragments were received, yet! */ + return IP_REASS_VALIDATE_PBUF_QUEUED; /* not yet valid! */ +} + +/** + * Reassembles incoming IP fragments into an IP datagram. + * + * @param p points to a pbuf chain of the fragment + * @return NULL if reassembly is incomplete, ? otherwise + */ +struct pbuf * +ip4_reass(struct pbuf *p) +{ + struct pbuf *r; + struct ip_hdr *fraghdr; + struct ip_reassdata *ipr; + struct ip_reass_helper *iprh; + u16_t offset, len, clen; + u8_t hlen; + int valid; + int is_last; + + IPFRAG_STATS_INC(ip_frag.recv); + MIB2_STATS_INC(mib2.ipreasmreqds); + + fraghdr = (struct ip_hdr *)p->payload; + + if (IPH_HL_BYTES(fraghdr) != IP_HLEN) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: IP options currently not supported!\n")); + IPFRAG_STATS_INC(ip_frag.err); + goto nullreturn; + } + + offset = IPH_OFFSET_BYTES(fraghdr); + len = lwip_ntohs(IPH_LEN(fraghdr)); + hlen = IPH_HL_BYTES(fraghdr); + if (hlen > len) { + /* invalid datagram */ + goto nullreturn; + } + len = (u16_t)(len - hlen); + + /* Check if we are allowed to enqueue more datagrams. */ + clen = pbuf_clen(p); + if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || + ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) +#endif /* IP_REASS_FREE_OLDEST */ + { + /* No datagram could be freed and still too many pbufs enqueued */ + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", + ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); + IPFRAG_STATS_INC(ip_frag.memerr); + /* @todo: send ICMP time exceeded here? */ + /* drop this pbuf */ + goto nullreturn; + } + } + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n", + lwip_ntohs(IPH_ID(fraghdr)))); + IPFRAG_STATS_INC(ip_frag.cachehit); + break; + } + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); + /* Bail if unable to enqueue */ + if (ipr == NULL) { + goto nullreturn; + } + } else { + if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && + ((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { + /* ipr->iphdr is not the header from the first fragment, but fraghdr is + * -> copy fraghdr into ipr->iphdr since we want to have the header + * of the first fragment (for ICMP time exceeded and later, for copying + * all options, if supported)*/ + SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); + } + } + + /* At this point, we have either created a new entry or pointing + * to an existing one */ + + /* check for 'no more fragments', and update queue entry*/ + is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0; + if (is_last) { + u16_t datagram_len = (u16_t)(offset + len); + if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) { + /* u16_t overflow, cannot handle this */ + goto nullreturn_ipr; + } + } + /* find the right place to insert this pbuf */ + /* @todo: trim pbufs if fragments are overlapping */ + valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last); + if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) { + goto nullreturn_ipr; + } + /* if we come here, the pbuf has been enqueued */ + + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time + (overflow checked by testing against IP_REASS_MAX_PBUFS) */ + ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen); + if (is_last) { + u16_t datagram_len = (u16_t)(offset + len); + ipr->datagram_len = datagram_len; + ipr->flags |= IP_REASS_FLAG_LASTFRAG; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip4_reass: last fragment seen, total len %"S16_F"\n", + ipr->datagram_len)); + } + + if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) { + struct ip_reassdata *ipr_prev; + /* the totally last fragment (flag more fragments = 0) was received at least + * once AND all fragments are received */ + u16_t datagram_len = (u16_t)(ipr->datagram_len + IP_HLEN); + + /* save the second pbuf before copying the header over the pointer */ + r = ((struct ip_reass_helper *)ipr->p->payload)->next_pbuf; + + /* copy the original ip header back to the first pbuf */ + fraghdr = (struct ip_hdr *)(ipr->p->payload); + SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); + IPH_LEN_SET(fraghdr, lwip_htons(datagram_len)); + IPH_OFFSET_SET(fraghdr, 0); + IPH_CHKSUM_SET(fraghdr, 0); + /* @todo: do we need to set/calculate the correct checksum? */ +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + } +#endif /* CHECKSUM_GEN_IP */ + + p = ipr->p; + + /* chain together the pbufs contained within the reass_data list. */ + while (r != NULL) { + iprh = (struct ip_reass_helper *)r->payload; + + /* hide the ip header for every succeeding fragment */ + pbuf_remove_header(r, IP_HLEN); + pbuf_cat(p, r); + r = iprh->next_pbuf; + } + + /* find the previous entry in the linked list */ + if (ipr == reassdatagrams) { + ipr_prev = NULL; + } else { + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } + + /* release the sources allocate for the fragment queue entry */ + ip_reass_dequeue_datagram(ipr, ipr_prev); + + /* and adjust the number of pbufs currently queued for reassembly. */ + clen = pbuf_clen(p); + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= clen); + ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount - clen); + + MIB2_STATS_INC(mib2.ipreasmoks); + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); + return NULL; + +nullreturn_ipr: + LWIP_ASSERT("ipr != NULL", ipr != NULL); + if (ipr->p == NULL) { + /* dropped pbuf after creating a new datagram entry: remove the entry, too */ + LWIP_ASSERT("not firstalthough just enqueued", ipr == reassdatagrams); + ip_reass_dequeue_datagram(ipr, NULL); + } + +nullreturn: + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: nullreturn\n")); + IPFRAG_STATS_INC(ip_frag.drop); + pbuf_free(p); + return NULL; +} +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref * +ip_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref *)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref *p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ipfrag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref *)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void *)pcr == (void *)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p. + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) +{ + struct pbuf *rambuf; +#if !LWIP_NETIF_TX_SINGLE_PBUF + struct pbuf *newpbuf; + u16_t newpbuflen = 0; + u16_t left_to_copy; +#endif + struct ip_hdr *original_iphdr; + struct ip_hdr *iphdr; + const u16_t nfb = (u16_t)((netif->mtu - IP_HLEN) / 8); + u16_t left, fragsize; + u16_t ofo; + int last; + u16_t poff = IP_HLEN; + u16_t tmp; + int mf_set; + + original_iphdr = (struct ip_hdr *)p->payload; + iphdr = original_iphdr; + if (IPH_HL_BYTES(iphdr) != IP_HLEN) { + /* ip4_frag() does not support IP options */ + return ERR_VAL; + } + LWIP_ERROR("ip4_frag(): pbuf too short", p->len >= IP_HLEN, return ERR_VAL); + + /* Save original offset */ + tmp = lwip_ntohs(IPH_OFFSET(iphdr)); + ofo = tmp & IP_OFFMASK; + /* already fragmented? if so, the last fragment we create must have MF, too */ + mf_set = tmp & IP_MF; + + left = (u16_t)(p->tot_len - IP_HLEN); + + while (left) { + /* Fill this fragment */ + fragsize = LWIP_MIN(left, (u16_t)(nfb * 8)); + +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM); + if (rambuf == NULL) { + goto memerr; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff); + /* make room for the IP header */ + if (pbuf_add_header(rambuf, IP_HLEN)) { + pbuf_free(rambuf); + goto memerr; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = (struct ip_hdr *)rambuf->payload; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link and IP header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); + if (rambuf == NULL) { + goto memerr; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len >= (IP_HLEN))); + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = (struct ip_hdr *)rambuf->payload; + + left_to_copy = fragsize; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + u16_t plen = (u16_t)(p->len - poff); + LWIP_ASSERT("p->len >= poff", p->len >= poff); + newpbuflen = LWIP_MIN(left_to_copy, plen); + /* Is this pbuf already empty? */ + if (!newpbuflen) { + poff = 0; + p = p->next; + continue; + } + pcr = ip_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + goto memerr; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, + (u8_t *)p->payload + poff, newpbuflen); + if (newpbuf == NULL) { + ip_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + goto memerr; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy = (u16_t)(left_to_copy - newpbuflen); + if (left_to_copy) { + poff = 0; + p = p->next; + } + } + poff = (u16_t)(poff + newpbuflen); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + /* Correct header */ + last = (left <= netif->mtu - IP_HLEN); + + /* Set new offset and MF flag */ + tmp = (IP_OFFMASK & (ofo)); + if (!last || mf_set) { + /* the last fragment has MF set if the input frame had it */ + tmp = tmp | IP_MF; + } + IPH_OFFSET_SET(iphdr, lwip_htons(tmp)); + IPH_LEN_SET(iphdr, lwip_htons((u16_t)(fragsize + IP_HLEN))); + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + } +#endif /* CHECKSUM_GEN_IP */ + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + netif->output(netif, rambuf, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left = (u16_t)(left - fragsize); + ofo = (u16_t)(ofo + nfb); + } + MIB2_STATS_INC(mib2.ipfragoks); + return ERR_OK; +memerr: + MIB2_STATS_INC(mib2.ipfragfails); + return ERR_MEM; +} +#endif /* IP_FRAG */ + +#endif /* LWIP_IPV4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/dhcp6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/dhcp6.c new file mode 100644 index 0000000..41444a4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/dhcp6.c @@ -0,0 +1,821 @@ +/** + * @file + * + * @defgroup dhcp6 DHCPv6 + * @ingroup ip6 + * DHCPv6 client: IPv6 address autoconfiguration as per + * RFC 3315 (stateful DHCPv6) and + * RFC 3736 (stateless DHCPv6). + * + * For now, only stateless DHCPv6 is implemented! + * + * TODO: + * - enable/disable API to not always start when RA is received + * - stateful DHCPv6 (for now, only stateless DHCPv6 for DNS and NTP servers works) + * - create Client Identifier? + * - only start requests if a valid local address is available on the netif + * - only start information requests if required (not for every RA) + * + * dhcp6_enable_stateful() enables stateful DHCPv6 for a netif (stateless disabled)\n + * dhcp6_enable_stateless() enables stateless DHCPv6 for a netif (stateful disabled)\n + * dhcp6_disable() disable DHCPv6 for a netif + * + * When enabled, requests are only issued after receipt of RA with the + * corresponding bits set. + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/dhcp6.h" +#include "lwip/prot/dhcp6.h" +#include "lwip/def.h" +#include "lwip/udp.h" +#include "lwip/dns.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif +#ifndef LWIP_HOOK_DHCP6_APPEND_OPTIONS +#define LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len) +#endif +#ifndef LWIP_HOOK_DHCP6_PARSE_OPTION +#define LWIP_HOOK_DHCP6_PARSE_OPTION(netif, dhcp6, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) +#endif + +#if LWIP_DNS && LWIP_DHCP6_MAX_DNS_SERVERS +#if DNS_MAX_SERVERS > LWIP_DHCP6_MAX_DNS_SERVERS +#define LWIP_DHCP6_PROVIDE_DNS_SERVERS LWIP_DHCP6_MAX_DNS_SERVERS +#else +#define LWIP_DHCP6_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS +#endif +#else +#define LWIP_DHCP6_PROVIDE_DNS_SERVERS 0 +#endif + + +/** Option handling: options are parsed in dhcp6_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp6 (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +enum dhcp6_option_idx { + DHCP6_OPTION_IDX_CLI_ID = 0, + DHCP6_OPTION_IDX_SERVER_ID, +#if LWIP_DHCP6_PROVIDE_DNS_SERVERS + DHCP6_OPTION_IDX_DNS_SERVER, + DHCP6_OPTION_IDX_DOMAIN_LIST, +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP6_GET_NTP_SRV + DHCP6_OPTION_IDX_NTP_SERVER, +#endif /* LWIP_DHCP_GET_NTP_SRV */ + DHCP6_OPTION_IDX_MAX +}; + +struct dhcp6_option_info { + u8_t option_given; + u16_t val_start; + u16_t val_length; +}; + +/** Holds the decoded option info, only valid while in dhcp6_recv. */ +struct dhcp6_option_info dhcp6_rx_options[DHCP6_OPTION_IDX_MAX]; + +#define dhcp6_option_given(dhcp6, idx) (dhcp6_rx_options[idx].option_given != 0) +#define dhcp6_got_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 1) +#define dhcp6_clear_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 0) +#define dhcp6_clear_all_options(dhcp6) (memset(dhcp6_rx_options, 0, sizeof(dhcp6_rx_options))) +#define dhcp6_get_option_start(dhcp6, idx) (dhcp6_rx_options[idx].val_start) +#define dhcp6_get_option_length(dhcp6, idx) (dhcp6_rx_options[idx].val_length) +#define dhcp6_set_option(dhcp6, idx, start, len) do { dhcp6_rx_options[idx].val_start = (start); dhcp6_rx_options[idx].val_length = (len); }while(0) + + +const ip_addr_t dhcp6_All_DHCP6_Relay_Agents_and_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010002); +const ip_addr_t dhcp6_All_DHCP6_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010003); + +static struct udp_pcb *dhcp6_pcb; +static u8_t dhcp6_pcb_refcount; + + +/* receive, unfold, parse and free incoming messages */ +static void dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + +/** Ensure DHCP PCB is allocated and bound */ +static err_t +dhcp6_inc_pcb_refcount(void) +{ + if (dhcp6_pcb_refcount == 0) { + LWIP_ASSERT("dhcp6_inc_pcb_refcount(): memory leak", dhcp6_pcb == NULL); + + /* allocate UDP PCB */ + dhcp6_pcb = udp_new_ip6(); + + if (dhcp6_pcb == NULL) { + return ERR_MEM; + } + + ip_set_option(dhcp6_pcb, SOF_BROADCAST); + + /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ + udp_bind(dhcp6_pcb, IP6_ADDR_ANY, DHCP6_CLIENT_PORT); + udp_recv(dhcp6_pcb, dhcp6_recv, NULL); + } + + dhcp6_pcb_refcount++; + + return ERR_OK; +} + +/** Free DHCP PCB if the last netif stops using it */ +static void +dhcp6_dec_pcb_refcount(void) +{ + LWIP_ASSERT("dhcp6_pcb_refcount(): refcount error", (dhcp6_pcb_refcount > 0)); + dhcp6_pcb_refcount--; + + if (dhcp6_pcb_refcount == 0) { + udp_remove(dhcp6_pcb); + dhcp6_pcb = NULL; + } +} + +/** + * @ingroup dhcp6 + * Set a statically allocated struct dhcp6 to work with. + * Using this prevents dhcp6_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct dhcp + * @param dhcp6 (uninitialised) dhcp6 struct allocated by the application + */ +void +dhcp6_set_struct(struct netif *netif, struct dhcp6 *dhcp6) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp6 != NULL", dhcp6 != NULL); + LWIP_ASSERT("netif already has a struct dhcp6 set", netif_dhcp6_data(netif) == NULL); + + /* clear data structure */ + memset(dhcp6, 0, sizeof(struct dhcp6)); + /* dhcp6_set_state(&dhcp, DHCP6_STATE_OFF); */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6); +} + +/** + * @ingroup dhcp6 + * Removes a struct dhcp6 from a netif. + * + * ATTENTION: Only use this when not using dhcp6_set_struct() to allocate the + * struct dhcp6 since the memory is passed back to the heap. + * + * @param netif the netif from which to remove the struct dhcp + */ +void dhcp6_cleanup(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + + if (netif_dhcp6_data(netif) != NULL) { + mem_free(netif_dhcp6_data(netif)); + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL); + } +} + +static struct dhcp6* +dhcp6_get_struct(struct netif *netif, const char *dbg_requester) +{ + struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); + if (dhcp6 == NULL) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: mallocing new DHCPv6 client\n", dbg_requester)); + dhcp6 = (struct dhcp6 *)mem_malloc(sizeof(struct dhcp6)); + if (dhcp6 == NULL) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: could not allocate dhcp6\n", dbg_requester)); + return NULL; + } + + /* clear data structure, this implies DHCP6_STATE_OFF */ + memset(dhcp6, 0, sizeof(struct dhcp6)); + /* store this dhcp6 client in the netif */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6); + } else { + /* already has DHCP6 client attached */ + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("%s: using existing DHCPv6 client\n", dbg_requester)); + } + + if (!dhcp6->pcb_allocated) { + if (dhcp6_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP6 PCB is allocated */ + mem_free(dhcp6); + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL); + return NULL; + } + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: allocated dhcp6", dbg_requester)); + dhcp6->pcb_allocated = 1; + } + return dhcp6; +} + +/* + * Set the DHCPv6 state + * If the state changed, reset the number of tries. + */ +static void +dhcp6_set_state(struct dhcp6 *dhcp6, u8_t new_state, const char *dbg_caller) +{ + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("DHCPv6 state: %d -> %d (%s)\n", + dhcp6->state, new_state, dbg_caller)); + if (new_state != dhcp6->state) { + dhcp6->state = new_state; + dhcp6->tries = 0; + dhcp6->request_timeout = 0; + } +} + +static int +dhcp6_stateless_enabled(struct dhcp6 *dhcp6) +{ + if ((dhcp6->state == DHCP6_STATE_STATELESS_IDLE) || + (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG)) { + return 1; + } + return 0; +} + +/*static int +dhcp6_stateful_enabled(struct dhcp6 *dhcp6) +{ + if (dhcp6->state == DHCP6_STATE_OFF) { + return 0; + } + if (dhcp6_stateless_enabled(dhcp6)) { + return 0; + } + return 1; +}*/ + +/** + * @ingroup dhcp6 + * Enable stateful DHCPv6 on this netif + * Requests are sent on receipt of an RA message with the + * ND6_RA_FLAG_MANAGED_ADDR_CONFIG flag set. + * + * A struct dhcp6 will be allocated for this netif if not + * set via @ref dhcp6_set_struct before. + * + * @todo: stateful DHCPv6 not supported, yet + */ +err_t +dhcp6_enable_stateful(struct netif *netif) +{ + LWIP_UNUSED_ARG(netif); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("stateful dhcp6 not implemented yet")); + return ERR_VAL; +} + +/** + * @ingroup dhcp6 + * Enable stateless DHCPv6 on this netif + * Requests are sent on receipt of an RA message with the + * ND6_RA_FLAG_OTHER_CONFIG flag set. + * + * A struct dhcp6 will be allocated for this netif if not + * set via @ref dhcp6_set_struct before. + */ +err_t +dhcp6_enable_stateless(struct netif *netif) +{ + struct dhcp6 *dhcp6; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_enable_stateless(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + dhcp6 = dhcp6_get_struct(netif, "dhcp6_enable_stateless()"); + if (dhcp6 == NULL) { + return ERR_MEM; + } + if (dhcp6_stateless_enabled(dhcp6)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 already enabled")); + return ERR_OK; + } else if (dhcp6->state != DHCP6_STATE_OFF) { + /* stateful running */ + /* @todo: stop stateful once it is implemented */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): switching from stateful to stateless DHCPv6")); + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 enabled\n")); + dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_enable_stateless"); + return ERR_OK; +} + +/** + * @ingroup dhcp6 + * Disable stateful or stateless DHCPv6 on this netif + * Requests are sent on receipt of an RA message with the + * ND6_RA_FLAG_OTHER_CONFIG flag set. + */ +void +dhcp6_disable(struct netif *netif) +{ + struct dhcp6 *dhcp6; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_disable(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + dhcp6 = netif_dhcp6_data(netif); + if (dhcp6 != NULL) { + if (dhcp6->state != DHCP6_STATE_OFF) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_disable(): DHCPv6 disabled (old state: %s)\n", + (dhcp6_stateless_enabled(dhcp6) ? "stateless" : "stateful"))); + dhcp6_set_state(dhcp6, DHCP6_STATE_OFF, "dhcp6_disable"); + if (dhcp6->pcb_allocated != 0) { + dhcp6_dec_pcb_refcount(); /* free DHCPv6 PCB if not needed any more */ + dhcp6->pcb_allocated = 0; + } + } + } +} + +/** + * Create a DHCPv6 request, fill in common headers + * + * @param netif the netif under DHCPv6 control + * @param dhcp6 dhcp6 control struct + * @param message_type message type of the request + * @param opt_len_alloc option length to allocate + * @param options_out_len option length on exit + * @return a pbuf for the message + */ +static struct pbuf * +dhcp6_create_msg(struct netif *netif, struct dhcp6 *dhcp6, u8_t message_type, + u16_t opt_len_alloc, u16_t *options_out_len) +{ + struct pbuf *p_out; + struct dhcp6_msg *msg_out; + + LWIP_ERROR("dhcp6_create_msg: netif != NULL", (netif != NULL), return NULL;); + LWIP_ERROR("dhcp6_create_msg: dhcp6 != NULL", (dhcp6 != NULL), return NULL;); + p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp6_msg) + opt_len_alloc, PBUF_RAM); + if (p_out == NULL) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp6_create_msg(): could not allocate pbuf\n")); + return NULL; + } + LWIP_ASSERT("dhcp6_create_msg: check that first pbuf can hold struct dhcp6_msg", + (p_out->len >= sizeof(struct dhcp6_msg) + opt_len_alloc)); + + /* @todo: limit new xid for certain message types? */ + /* reuse transaction identifier in retransmissions */ + if (dhcp6->tries == 0) { + dhcp6->xid = LWIP_RAND() & 0xFFFFFF; + } + + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, + ("transaction id xid(%"X32_F")\n", dhcp6->xid)); + + msg_out = (struct dhcp6_msg *)p_out->payload; + memset(msg_out, 0, sizeof(struct dhcp6_msg) + opt_len_alloc); + + msg_out->msgtype = message_type; + msg_out->transaction_id[0] = (u8_t)(dhcp6->xid >> 16); + msg_out->transaction_id[1] = (u8_t)(dhcp6->xid >> 8); + msg_out->transaction_id[2] = (u8_t)dhcp6->xid; + *options_out_len = 0; + return p_out; +} + +static u16_t +dhcp6_option_short(u16_t options_out_len, u8_t *options, u16_t value) +{ + options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8); + options[options_out_len++] = (u8_t) (value & 0x00ffU); + return options_out_len; +} + +static u16_t +dhcp6_option_optionrequest(u16_t options_out_len, u8_t *options, const u16_t *req_options, + u16_t num_req_options, u16_t max_len) +{ + size_t i; + u16_t ret; + + LWIP_ASSERT("dhcp6_option_optionrequest: options_out_len + sizeof(struct dhcp6_msg) + addlen <= max_len", + sizeof(struct dhcp6_msg) + options_out_len + 4U + (2U * num_req_options) <= max_len); + LWIP_UNUSED_ARG(max_len); + + ret = dhcp6_option_short(options_out_len, options, DHCP6_OPTION_ORO); + ret = dhcp6_option_short(ret, options, 2 * num_req_options); + for (i = 0; i < num_req_options; i++) { + ret = dhcp6_option_short(ret, options, req_options[i]); + } + return ret; +} + +/* All options are added, shrink the pbuf to the required size */ +static void +dhcp6_msg_finalize(u16_t options_out_len, struct pbuf *p_out) +{ + /* shrink the pbuf to the actual content length */ + pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp6_msg) + options_out_len)); +} + + +#if LWIP_IPV6_DHCP6_STATELESS +static void +dhcp6_information_request(struct netif *netif, struct dhcp6 *dhcp6) +{ + const u16_t requested_options[] = { +#if LWIP_DHCP6_PROVIDE_DNS_SERVERS + DHCP6_OPTION_DNS_SERVERS, + DHCP6_OPTION_DOMAIN_LIST +#endif +#if LWIP_DHCP6_GET_NTP_SRV + , DHCP6_OPTION_SNTP_SERVERS +#endif + }; + + u16_t msecs; + struct pbuf *p_out; + u16_t options_out_len; + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request()\n")); + /* create and initialize the DHCP message header */ + p_out = dhcp6_create_msg(netif, dhcp6, DHCP6_INFOREQUEST, 4 + sizeof(requested_options), &options_out_len); + if (p_out != NULL) { + err_t err; + struct dhcp6_msg *msg_out = (struct dhcp6_msg *)p_out->payload; + u8_t *options = (u8_t *)(msg_out + 1); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request: making request\n")); + + options_out_len = dhcp6_option_optionrequest(options_out_len, options, requested_options, + LWIP_ARRAYSIZE(requested_options), p_out->len); + LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, DHCP6_STATE_REQUESTING_CONFIG, msg_out, + DHCP6_INFOREQUEST, options_out_len, p_out->len); + dhcp6_msg_finalize(options_out_len, p_out); + + err = udp_sendto_if(dhcp6_pcb, p_out, &dhcp6_All_DHCP6_Relay_Agents_and_Servers, DHCP6_SERVER_PORT, netif); + pbuf_free(p_out); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request: INFOREQUESTING -> %d\n", (int)err)); + LWIP_UNUSED_ARG(err); + } else { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp6_information_request: could not allocate DHCP6 request\n")); + } + dhcp6_set_state(dhcp6, DHCP6_STATE_REQUESTING_CONFIG, "dhcp6_information_request"); + if (dhcp6->tries < 255) { + dhcp6->tries++; + } + msecs = (u16_t)((dhcp6->tries < 6 ? 1 << dhcp6->tries : 60) * 1000); + dhcp6->request_timeout = (u16_t)((msecs + DHCP6_TIMER_MSECS - 1) / DHCP6_TIMER_MSECS); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request(): set request timeout %"U16_F" msecs\n", msecs)); +} + +static err_t +dhcp6_request_config(struct netif *netif, struct dhcp6 *dhcp6) +{ + /* stateless mode enabled and no request running? */ + if (dhcp6->state == DHCP6_STATE_STATELESS_IDLE) { + /* send Information-request and wait for answer; setup receive timeout */ + dhcp6_information_request(netif, dhcp6); + } + + return ERR_OK; +} + +static void +dhcp6_abort_config_request(struct dhcp6 *dhcp6) +{ + if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { + /* abort running request */ + dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_abort_config_request"); + } +} + +/* Handle a REPLY to INFOREQUEST + * This parses DNS and NTP server addresses from the reply. + */ +static void +dhcp6_handle_config_reply(struct netif *netif, struct pbuf *p_msg_in) +{ + struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); + + LWIP_UNUSED_ARG(dhcp6); + LWIP_UNUSED_ARG(p_msg_in); + +#if LWIP_DHCP6_PROVIDE_DNS_SERVERS + if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER)) { + ip_addr_t dns_addr; + ip6_addr_t *dns_addr6; + u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); + u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); + u16_t idx; + u8_t n; + + ip_addr_set_zero_ip6(&dns_addr); + dns_addr6 = ip_2_ip6(&dns_addr); + for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_PROVIDE_DNS_SERVERS); + n++, idx += sizeof(struct ip6_addr_packed)) { + u16_t copied = pbuf_copy_partial(p_msg_in, dns_addr6, sizeof(struct ip6_addr_packed), idx); + if (copied != sizeof(struct ip6_addr_packed)) { + /* pbuf length mismatch */ + return; + } + ip6_addr_assign_zone(dns_addr6, IP6_UNKNOWN, netif); + /* @todo: do we need a different offset than DHCP(v4)? */ + dns_setserver(n, &dns_addr); + } + } + /* @ todo: parse and set Domain Search List */ +#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */ + +#if LWIP_DHCP6_GET_NTP_SRV + if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER)) { + ip_addr_t ntp_server_addrs[LWIP_DHCP6_MAX_NTP_SERVERS]; + u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); + u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); + u16_t idx; + u8_t n; + + for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_MAX_NTP_SERVERS); + n++, idx += sizeof(struct ip6_addr_packed)) { + u16_t copied; + ip6_addr_t *ntp_addr6 = ip_2_ip6(&ntp_server_addrs[n]); + ip_addr_set_zero_ip6(&ntp_server_addrs[n]); + copied = pbuf_copy_partial(p_msg_in, ntp_addr6, sizeof(struct ip6_addr_packed), idx); + if (copied != sizeof(struct ip6_addr_packed)) { + /* pbuf length mismatch */ + return; + } + ip6_addr_assign_zone(ntp_addr6, IP6_UNKNOWN, netif); + } + dhcp6_set_ntp_servers(n, ntp_server_addrs); + } +#endif /* LWIP_DHCP6_GET_NTP_SRV */ +} +#endif /* LWIP_IPV6_DHCP6_STATELESS */ + +/** This function is called from nd6 module when an RA messsage is received + * It triggers DHCPv6 requests (if enabled). + */ +void +dhcp6_nd6_ra_trigger(struct netif *netif, u8_t managed_addr_config, u8_t other_config) +{ + struct dhcp6 *dhcp6; + + LWIP_ASSERT("netif != NULL", netif != NULL); + dhcp6 = netif_dhcp6_data(netif); + + LWIP_UNUSED_ARG(managed_addr_config); + LWIP_UNUSED_ARG(other_config); + LWIP_UNUSED_ARG(dhcp6); + +#if LWIP_IPV6_DHCP6_STATELESS + if (dhcp6 != NULL) { + if (dhcp6_stateless_enabled(dhcp6)) { + if (other_config) { + dhcp6_request_config(netif, dhcp6); + } else { + dhcp6_abort_config_request(dhcp6); + } + } + } +#endif /* LWIP_IPV6_DHCP6_STATELESS */ +} + +/** + * Parse the DHCPv6 message and extract the DHCPv6 options. + * + * Extract the DHCPv6 options (offset + length) so that we can later easily + * check for them or extract the contents. + */ +static err_t +dhcp6_parse_reply(struct pbuf *p, struct dhcp6 *dhcp6) +{ + u16_t offset; + u16_t offset_max; + u16_t options_idx; + struct dhcp6_msg *msg_in; + + LWIP_UNUSED_ARG(dhcp6); + + /* clear received options */ + dhcp6_clear_all_options(dhcp6); + msg_in = (struct dhcp6_msg *)p->payload; + + /* parse options */ + + options_idx = sizeof(struct dhcp6_msg); + /* parse options to the end of the received packet */ + offset_max = p->tot_len; + + offset = options_idx; + /* at least 4 byte to read? */ + while ((offset + 4 <= offset_max)) { + u8_t op_len_buf[4]; + u8_t *op_len; + u16_t op; + u16_t len; + u16_t val_offset = (u16_t)(offset + 4); + if (val_offset < offset) { + /* overflow */ + return ERR_BUF; + } + /* copy option + length, might be split accross pbufs */ + op_len = (u8_t *)pbuf_get_contiguous(p, op_len_buf, 4, 4, offset); + if (op_len == NULL) { + /* failed to get option and length */ + return ERR_VAL; + } + op = (op_len[0] << 8) | op_len[1]; + len = (op_len[2] << 8) | op_len[3]; + offset = val_offset + len; + if (offset < val_offset) { + /* overflow */ + return ERR_BUF; + } + + switch (op) { + case (DHCP6_OPTION_CLIENTID): + dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID); + dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID, val_offset, len); + break; + case (DHCP6_OPTION_SERVERID): + dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID); + dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID, val_offset, len); + break; +#if LWIP_DHCP6_PROVIDE_DNS_SERVERS + case (DHCP6_OPTION_DNS_SERVERS): + dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); + dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER, val_offset, len); + break; + case (DHCP6_OPTION_DOMAIN_LIST): + dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST); + dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST, val_offset, len); + break; +#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP6_GET_NTP_SRV + case (DHCP6_OPTION_SNTP_SERVERS): + dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); + dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER, val_offset, len); + break; +#endif /* LWIP_DHCP6_GET_NTP_SRV*/ + default: + LWIP_DEBUGF(DHCP6_DEBUG, ("skipping option %"U16_F" in options\n", op)); + LWIP_HOOK_DHCP6_PARSE_OPTION(ip_current_netif(), dhcp6, dhcp6->state, msg_in, + msg_in->msgtype, op, len, q, val_offset); + break; + } + } + return ERR_OK; +} + +static void +dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + struct netif *netif = ip_current_input_netif(); + struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); + struct dhcp6_msg *reply_msg = (struct dhcp6_msg *)p->payload; + u8_t msg_type; + u32_t xid; + + LWIP_UNUSED_ARG(arg); + + /* Caught DHCPv6 message from netif that does not have DHCPv6 enabled? -> not interested */ + if ((dhcp6 == NULL) || (dhcp6->pcb_allocated == 0)) { + goto free_pbuf_and_return; + } + + LWIP_ERROR("invalid server address type", IP_IS_V6(addr), goto free_pbuf_and_return;); + + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_recv(pbuf = %p) from DHCPv6 server %s port %"U16_F"\n", (void *)p, + ipaddr_ntoa(addr), port)); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); + /* prevent warnings about unused arguments */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + if (p->len < sizeof(struct dhcp6_msg)) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCPv6 reply message or pbuf too short\n")); + goto free_pbuf_and_return; + } + + /* match transaction ID against what we expected */ + xid = reply_msg->transaction_id[0] << 16; + xid |= reply_msg->transaction_id[1] << 8; + xid |= reply_msg->transaction_id[2]; + if (xid != dhcp6->xid) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("transaction id mismatch reply_msg->xid(%"X32_F")!= dhcp6->xid(%"X32_F")\n", xid, dhcp6->xid)); + goto free_pbuf_and_return; + } + /* option fields could be unfold? */ + if (dhcp6_parse_reply(p, dhcp6) != ERR_OK) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("problem unfolding DHCPv6 message - too short on memory?\n")); + goto free_pbuf_and_return; + } + + /* read DHCP message type */ + msg_type = reply_msg->msgtype; + /* message type is DHCP6 REPLY? */ + if (msg_type == DHCP6_REPLY) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("DHCP6_REPLY received\n")); +#if LWIP_IPV6_DHCP6_STATELESS + /* in info-requesting state? */ + if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { + dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_recv"); + dhcp6_handle_config_reply(netif, p); + } else +#endif /* LWIP_IPV6_DHCP6_STATELESS */ + { + /* @todo: handle reply in other states? */ + } + } else { + /* @todo: handle other message types */ + } + +free_pbuf_and_return: + pbuf_free(p); +} + +/** + * A DHCPv6 request has timed out. + * + * The timer that was started with the DHCPv6 request has + * timed out, indicating no response was received in time. + */ +static void +dhcp6_timeout(struct netif *netif, struct dhcp6 *dhcp6) +{ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout()\n")); + + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(dhcp6); + +#if LWIP_IPV6_DHCP6_STATELESS + /* back-off period has passed, or server selection timed out */ + if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout(): retrying information request\n")); + dhcp6_information_request(netif, dhcp6); + } +#endif /* LWIP_IPV6_DHCP6_STATELESS */ +} + +/** + * DHCPv6 timeout handling (this function must be called every 500ms, + * see @ref DHCP6_TIMER_MSECS). + * + * A DHCPv6 server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCPv6 request is timed out. + */ +void +dhcp6_tmr(void) +{ + struct netif *netif; + /* loop through netif's */ + NETIF_FOREACH(netif) { + struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); + /* only act on DHCPv6 configured interfaces */ + if (dhcp6 != NULL) { + /* timer is active (non zero), and is about to trigger now */ + if (dhcp6->request_timeout > 1) { + dhcp6->request_timeout--; + } else if (dhcp6->request_timeout == 1) { + dhcp6->request_timeout--; + /* { dhcp6->request_timeout == 0 } */ + LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_tmr(): request timeout\n")); + /* this client's request timeout triggered */ + dhcp6_timeout(netif, dhcp6); + } + } + } +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ethip6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ethip6.c new file mode 100644 index 0000000..fec8b28 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ethip6.c @@ -0,0 +1,123 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET + +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/prot/ethernet.h" +#include "netif/ethernet.h" + +#include + +/** + * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. + * + * For IPv6 multicast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, ask the ND6 module what to do. It will either let us + * send the the packet right away, or queue the packet for later itself, unless + * an error occurs. + * + * @todo anycast addresses + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return + * - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue. + */ +err_t +ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) +{ + struct eth_addr dest; + const u8_t *hwaddr; + err_t result; + + LWIP_ASSERT_CORE_LOCKED(); + + /* The destination IP address must be properly zoned from here on down. */ + IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + /* Hash IP multicast address to MAC address.*/ + dest.addr[0] = 0x33; + dest.addr[1] = 0x33; + dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0]; + dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1]; + dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2]; + dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3]; + + /* Send out. */ + return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); + } + + /* We have a unicast destination IP address */ + /* @todo anycast? */ + + /* Ask ND6 what to do with the packet. */ + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); + if (result != ERR_OK) { + return result; + } + + /* If no hardware address is returned, nd6 has queued the packet for later. */ + if (hwaddr == NULL) { + return ERR_OK; + } + + /* Send out the packet using the returned hardware address. */ + SMEMCPY(dest.addr, hwaddr, 6); + return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); +} + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/icmp6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/icmp6.c new file mode 100644 index 0000000..4fd1021 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/icmp6.c @@ -0,0 +1,434 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp6.h" +#include "lwip/prot/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +#include + +#if !LWIP_ICMP6_DATASIZE || (LWIP_ICMP6_DATASIZE > (IP6_MIN_MTU_LENGTH - IP6_HLEN - ICMP6_HLEN)) +#undef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE (IP6_MIN_MTU_LENGTH - IP6_HLEN - ICMP6_HLEN) +#endif + +/* Forward declarations */ +static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); +static void icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, + u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); +static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, + u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif); + + +/** + * Process an input ICMPv6 message. Called by ip6_input. + * + * Will generate a reply for echo requests. Other messages are forwarded + * to nd6_input, or mld6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +icmp6_input(struct pbuf *p, struct netif *inp) +{ + struct icmp6_hdr *icmp6hdr; + struct pbuf *r; + const ip6_addr_t *reply_src; + + ICMP6_STATS_INC(icmp6.recv); + + /* Check that ICMPv6 header fits in payload */ + if (p->len < sizeof(struct icmp6_hdr)) { + /* drop short packets */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.lenerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + +#if CHECKSUM_CHECK_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { + if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), + ip6_current_dest_addr()) != 0) { + /* Checksum failed */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.chkerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } + } +#endif /* CHECKSUM_CHECK_ICMP6 */ + + switch (icmp6hdr->type) { + case ICMP6_TYPE_NA: /* Neighbor advertisement */ + case ICMP6_TYPE_NS: /* Neighbor solicitation */ + case ICMP6_TYPE_RA: /* Router advertisement */ + case ICMP6_TYPE_RD: /* Redirect */ + case ICMP6_TYPE_PTB: /* Packet too big */ + nd6_input(p, inp); + return; + case ICMP6_TYPE_RS: +#if LWIP_IPV6_FORWARD + /* @todo implement router functionality */ +#endif + break; +#if LWIP_IPV6_MLD + case ICMP6_TYPE_MLQ: + case ICMP6_TYPE_MLR: + case ICMP6_TYPE_MLD: + mld6_input(p, inp); + return; +#endif + case ICMP6_TYPE_EREQ: +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* drop */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.drop); + return; + } +#endif /* LWIP_MULTICAST_PING */ + + /* Allocate reply. */ + r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); + if (r == NULL) { + /* drop */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.memerr); + return; + } + + /* Copy echo request. */ + if (pbuf_copy(r, p) != ERR_OK) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.err); + return; + } + + /* Determine reply source IPv6 address. */ +#if LWIP_MULTICAST_PING + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); + if (reply_src == NULL) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + } + else +#endif /* LWIP_MULTICAST_PING */ + { + reply_src = ip6_current_dest_addr(); + } + + /* Set fields in reply. */ + ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send reply. */ + ICMP6_STATS_INC(icmp6.xmit); + ip6_output_if(r, reply_src, ip6_current_src_addr(), + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); + pbuf_free(r); + + break; + default: + ICMP6_STATS_INC(icmp6.proterr); + ICMP6_STATS_INC(icmp6.drop); + break; + } + + pbuf_free(p); +} + + +/** + * Send an icmpv6 'destination unreachable' packet. + * + * This function must be used only in direct response to a packet that is being + * received right now. Otherwise, address zones would be lost. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the unreachable type + */ +void +icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) +{ + icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); +} + +/** + * Send an icmpv6 'packet too big' packet. + * + * This function must be used only in direct response to a packet that is being + * received right now. Otherwise, address zones would be lost. + * + * @param p the input packet for which the 'packet too big' should be sent, + * p->payload pointing to the IPv6 header + * @param mtu the maximum mtu that we can accept + */ +void +icmp6_packet_too_big(struct pbuf *p, u32_t mtu) +{ + icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); +} + +/** + * Send an icmpv6 'time exceeded' packet. + * + * This function must be used only in direct response to a packet that is being + * received right now. Otherwise, address zones would be lost. + * + * @param p the input packet for which the 'time exceeded' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the time exceeded type + */ +void +icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) +{ + icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); +} + +/** + * Send an icmpv6 'time exceeded' packet, with explicit source and destination + * addresses. + * + * This function may be used to send a response sometime after receiving the + * packet for which this response is meant. The provided source and destination + * addresses are used primarily to retain their zone information. + * + * @param p the input packet for which the 'time exceeded' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the time exceeded type + * @param src_addr source address of the original packet, with zone information + * @param dest_addr destination address of the original packet, with zone + * information + */ +void +icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, + const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) +{ + icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr); +} + +/** + * Send an icmpv6 'parameter problem' packet. + * + * This function must be used only in direct response to a packet that is being + * received right now. Otherwise, address zones would be lost and the calculated + * offset would be wrong (calculated against ip6_current_header()). + * + * @param p the input packet for which the 'param problem' should be sent, + * p->payload pointing to the IP header + * @param c ICMPv6 code for the param problem type + * @param pointer the pointer to the byte where the parameter is found + */ +void +icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer) +{ + u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header()); + icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP); +} + +/** + * Send an ICMPv6 packet in response to an incoming packet. + * The packet is sent *to* ip_current_src_addr() on ip_current_netif(). + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + * @param type Type of the ICMPv6 header + */ +static void +icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) +{ + const struct ip6_addr *reply_src, *reply_dest; + struct netif *netif = ip_current_netif(); + + LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL); + reply_dest = ip6_current_src_addr(); + + /* Select an address to use as source. */ + reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); + if (reply_src == NULL) { + ICMP6_STATS_INC(icmp6.rterr); + return; + } + icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif); +} + +/** + * Send an ICMPv6 packet in response to an incoming packet. + * + * Call this function if the packet is NOT sent as a direct response to an + * incoming packet, but rather sometime later (e.g. for a fragment reassembly + * timeout). The caller must provide the zoned source and destination addresses + * from the original packet with the src_addr and dest_addr parameters. The + * reason for this approach is that while the addresses themselves are part of + * the original packet, their zone information is not, thus possibly resulting + * in a link-local response being sent over the wrong link. + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + * @param type Type of the ICMPv6 header + * @param src_addr original source address + * @param dest_addr original destination address + */ +static void +icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, + const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) +{ + const struct ip6_addr *reply_src, *reply_dest; + struct netif *netif; + + /* Get the destination address and netif for this ICMP message. */ + LWIP_ASSERT("must provide both source and destination", src_addr != NULL); + LWIP_ASSERT("must provide both source and destination", dest_addr != NULL); + + /* Special case, as ip6_current_xxx is either NULL, or points + to a different packet than the one that expired. */ + IP6_ADDR_ZONECHECK(src_addr); + IP6_ADDR_ZONECHECK(dest_addr); + /* Swap source and destination for the reply. */ + reply_dest = src_addr; + reply_src = dest_addr; + netif = ip6_route(reply_src, reply_dest); + if (netif == NULL) { + ICMP6_STATS_INC(icmp6.rterr); + return; + } + icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, + reply_dest, netif); +} + +/** + * Send an ICMPv6 packet (with srd/dst address and netif given). + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + * @param type Type of the ICMPv6 header + * @param reply_src source address of the packet to send + * @param reply_dest destination address of the packet to send + * @param netif netif to send the packet + */ +static void +icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type, + const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif) +{ + struct pbuf *q; + struct icmp6_hdr *icmp6hdr; + u16_t datalen = LWIP_MIN(p->tot_len, LWIP_ICMP6_DATASIZE); + u16_t offset; + + /* ICMPv6 header + datalen (as much of the offending packet as possible) */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + datalen, + PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); + ICMP6_STATS_INC(icmp6.memerr); + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp6 header", + (q->len >= (sizeof(struct icmp6_hdr)))); + + icmp6hdr = (struct icmp6_hdr *)q->payload; + icmp6hdr->type = type; + icmp6hdr->code = code; + icmp6hdr->data = lwip_htonl(data); + + /* copy fields from original packet (which may be a chain of pbufs) */ + offset = sizeof(struct icmp6_hdr); + while (p && datalen) { + u16_t len = LWIP_MIN(datalen, p->len); + err_t res = pbuf_take_at(q, p->payload, len, offset); + if (res != ERR_OK) break; + datalen -= len; + offset += len; + p = p->next; + } + + /* calculate checksum */ + icmp6hdr->chksum = 0; +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, + reply_src, reply_dest); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + ICMP6_STATS_INC(icmp6.xmit); + ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(q); +} + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/inet6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/inet6.c new file mode 100644 index 0000000..d9a992c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/inet6.c @@ -0,0 +1,53 @@ +/** + * @file + * + * INET v6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/inet.h" + +/** This variable is initialized by the system to contain the wildcard IPv6 address. + */ +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6.c new file mode 100644 index 0000000..060d5f3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6.c @@ -0,0 +1,1494 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_frag.h" +#include "lwip/icmp6.h" +#include "lwip/priv/raw_priv.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/dhcp6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/debug.h" +#include "lwip/stats.h" + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** + * Finds the appropriate network interface for a given IPv6 address. It tries to select + * a netif following a sequence of heuristics: + * 1) if there is only 1 netif, return it + * 2) if the destination is a zoned address, match its zone to a netif + * 3) if the either the source or destination address is a scoped address, + * match the source address's zone (if set) or address (if not) to a netif + * 4) tries to match the destination subnet to a configured address + * 5) tries to find a router-announced route + * 6) tries to match the (unscoped) source address to the netif + * 7) returns the default netif, if configured + * + * Note that each of the two given addresses may or may not be properly zoned. + * + * @param src the source IPv6 address, if known + * @param dest the destination IPv6 address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) +{ +#if LWIP_SINGLE_NETIF + LWIP_UNUSED_ARG(src); + LWIP_UNUSED_ARG(dest); +#else /* LWIP_SINGLE_NETIF */ + struct netif *netif; + s8_t i; + + LWIP_ASSERT_CORE_LOCKED(); + + /* If single netif configuration, fast return. */ + if ((netif_list != NULL) && (netif_list->next == NULL)) { + if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list) || + (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, netif_list))) { + return NULL; + } + return netif_list; + } + +#if LWIP_IPV6_SCOPES + /* Special processing for zoned destination addresses. This includes link- + * local unicast addresses and interface/link-local multicast addresses. Use + * the zone to find a matching netif. If the address is not zoned, then there + * is technically no "wrong" netif to choose, and we leave routing to other + * rules; in most cases this should be the scoped-source rule below. */ + if (ip6_addr_has_zone(dest)) { + IP6_ADDR_ZONECHECK(dest); + /* Find a netif based on the zone. For custom mappings, one zone may map + * to multiple netifs, so find one that can actually send a packet. */ + NETIF_FOREACH(netif) { + if (ip6_addr_test_zone(dest, netif) && + netif_is_up(netif) && netif_is_link_up(netif)) { + return netif; + } + } + /* No matching netif found. Do no try to route to a different netif, + * as that would be a zone violation, resulting in any packets sent to + * that netif being dropped on output. */ + return NULL; + } +#endif /* LWIP_IPV6_SCOPES */ + + /* Special processing for scoped source and destination addresses. If we get + * here, the destination address does not have a zone, so either way we need + * to look at the source address, which may or may not have a zone. If it + * does, the zone is restrictive: there is (typically) only one matching + * netif for it, and we should avoid routing to any other netif as that would + * result in guaranteed zone violations. For scoped source addresses that do + * not have a zone, use (only) a netif that has that source address locally + * assigned. This case also applies to the loopback source address, which has + * an implied link-local scope. If only the destination address is scoped + * (but, again, not zoned), we still want to use only the source address to + * determine its zone because that's most likely what the user/application + * wants, regardless of whether the source address is scoped. Finally, some + * of this story also applies if scoping is disabled altogether. */ +#if LWIP_IPV6_SCOPES + if (ip6_addr_has_scope(dest, IP6_UNKNOWN) || + ip6_addr_has_scope(src, IP6_UNICAST) || +#else /* LWIP_IPV6_SCOPES */ + if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_iflocal(dest) || + ip6_addr_ismulticast_linklocal(dest) || ip6_addr_islinklocal(src) || +#endif /* LWIP_IPV6_SCOPES */ + ip6_addr_isloopback(src)) { +#if LWIP_IPV6_SCOPES + if (ip6_addr_has_zone(src)) { + /* Find a netif matching the source zone (relatively cheap). */ + NETIF_FOREACH(netif) { + if (netif_is_up(netif) && netif_is_link_up(netif) && + ip6_addr_test_zone(src, netif)) { + return netif; + } + } + } else +#endif /* LWIP_IPV6_SCOPES */ + { + /* Find a netif matching the source address (relatively expensive). */ + NETIF_FOREACH(netif) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp_zoneless(src, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + } + /* Again, do not use any other netif in this case, as that could result in + * zone boundary violations. */ + return NULL; + } + + /* We come here only if neither source nor destination is scoped. */ + IP6_ADDR_ZONECHECK(src); + +#ifdef LWIP_HOOK_IP6_ROUTE + netif = LWIP_HOOK_IP6_ROUTE(src, dest); + if (netif != NULL) { + return netif; + } +#endif + + /* See if the destination subnet matches a configured address. In accordance + * with RFC 5942, dynamically configured addresses do not have an implied + * local subnet, and thus should be considered /128 assignments. However, as + * such, the destination address may still match a local address, and so we + * still need to check for exact matches here. By (lwIP) policy, statically + * configured addresses do always have an implied local /64 subnet. */ + NETIF_FOREACH(netif) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) && + (netif_ip6_addr_isstatic(netif, i) || + ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) { + return netif; + } + } + } + + /* Get the netif for a suitable router-announced route. */ + netif = nd6_find_route(dest); + if (netif != NULL) { + return netif; + } + + /* Try with the netif that matches the source address. Given the earlier rule + * for scoped source addresses, this applies to unscoped addresses only. */ + if (!ip6_addr_isany(src)) { + NETIF_FOREACH(netif) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + } + +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + /* loopif is disabled, loopback traffic is passed through any netif */ + if (ip6_addr_isloopback(dest)) { + /* don't check for link on loopback traffic */ + if (netif_default != NULL && netif_is_up(netif_default)) { + return netif_default; + } + /* default netif is not up, just use any netif for loopback traffic */ + NETIF_FOREACH(netif) { + if (netif_is_up(netif)) { + return netif; + } + } + return NULL; + } +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ +#endif /* !LWIP_SINGLE_NETIF */ + + /* no matching netif found, use default netif, if up */ + if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { + return NULL; + } + return netif_default; +} + +/** + * @ingroup ip6 + * Select the best IPv6 source address for a given destination IPv6 address. + * + * This implementation follows RFC 6724 Sec. 5 to the following extent: + * - Rules 1, 2, 3: fully implemented + * - Rules 4, 5, 5.5: not applicable + * - Rule 6: not implemented + * - Rule 7: not applicable + * - Rule 8: limited to "prefer /64 subnet match over non-match" + * + * For Rule 2, we deliberately deviate from RFC 6724 Sec. 3.1 by considering + * ULAs to be of smaller scope than global addresses, to avoid that a preferred + * ULA is picked over a deprecated global address when given a global address + * as destination, as that would likely result in broken two-way communication. + * + * As long as temporary addresses are not supported (as used in Rule 7), a + * proper implementation of Rule 8 would obviate the need to implement Rule 6. + * + * @param netif the netif on which to send a packet + * @param dest the destination we are trying to reach (possibly not properly + * zoned) + * @return the most suitable source address to use, or NULL if no suitable + * source address is found + */ +const ip_addr_t * +ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) +{ + const ip_addr_t *best_addr; + const ip6_addr_t *cand_addr; + s8_t dest_scope, cand_scope; + s8_t best_scope = IP6_MULTICAST_SCOPE_RESERVED; + u8_t i, cand_pref, cand_bits; + u8_t best_pref = 0; + u8_t best_bits = 0; + + /* Start by determining the scope of the given destination address. These + * tests are hopefully (roughly) in order of likeliness to match. */ + if (ip6_addr_isglobal(dest)) { + dest_scope = IP6_MULTICAST_SCOPE_GLOBAL; + } else if (ip6_addr_islinklocal(dest) || ip6_addr_isloopback(dest)) { + dest_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL; + } else if (ip6_addr_isuniquelocal(dest)) { + dest_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL; + } else if (ip6_addr_ismulticast(dest)) { + dest_scope = ip6_addr_multicast_scope(dest); + } else if (ip6_addr_issitelocal(dest)) { + dest_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL; + } else { + /* no match, consider scope global */ + dest_scope = IP6_MULTICAST_SCOPE_GLOBAL; + } + + best_addr = NULL; + + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + /* Consider only valid (= preferred and deprecated) addresses. */ + if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { + continue; + } + /* Determine the scope of this candidate address. Same ordering idea. */ + cand_addr = netif_ip6_addr(netif, i); + if (ip6_addr_isglobal(cand_addr)) { + cand_scope = IP6_MULTICAST_SCOPE_GLOBAL; + } else if (ip6_addr_islinklocal(cand_addr)) { + cand_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL; + } else if (ip6_addr_isuniquelocal(cand_addr)) { + cand_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL; + } else if (ip6_addr_issitelocal(cand_addr)) { + cand_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL; + } else { + /* no match, treat as low-priority global scope */ + cand_scope = IP6_MULTICAST_SCOPE_RESERVEDF; + } + cand_pref = ip6_addr_ispreferred(netif_ip6_addr_state(netif, i)); + /* @todo compute the actual common bits, for longest matching prefix. */ + /* We cannot count on the destination address having a proper zone + * assignment, so do not compare zones in this case. */ + cand_bits = ip6_addr_netcmp_zoneless(cand_addr, dest); /* just 1 or 0 for now */ + if (cand_bits && ip6_addr_nethostcmp(cand_addr, dest)) { + return netif_ip_addr6(netif, i); /* Rule 1 */ + } + if ((best_addr == NULL) || /* no alternative yet */ + ((cand_scope < best_scope) && (cand_scope >= dest_scope)) || + ((cand_scope > best_scope) && (best_scope < dest_scope)) || /* Rule 2 */ + ((cand_scope == best_scope) && ((cand_pref > best_pref) || /* Rule 3 */ + ((cand_pref == best_pref) && (cand_bits > best_bits))))) { /* Rule 8 */ + /* We found a new "winning" candidate. */ + best_addr = netif_ip_addr6(netif, i); + best_scope = cand_scope; + best_pref = cand_pref; + best_bits = cand_bits; + } + } + + return best_addr; /* may be NULL */ +} + +#if LWIP_IPV6_FORWARD +/** + * Forwards an IPv6 packet. It finds an appropriate route for the + * packet, decrements the HL value of the packet, and outputs + * the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IPv6 header of the input packet + * @param inp the netif on which this packet was received + */ +static void +ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + /* do not forward link-local or loopback addresses */ + if (ip6_addr_islinklocal(ip6_current_dest_addr()) || + ip6_addr_isloopback(ip6_current_dest_addr())) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr()); + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(ip6_current_dest_addr()), + IP6_ADDR_BLOCK2(ip6_current_dest_addr()), + IP6_ADDR_BLOCK3(ip6_current_dest_addr()), + IP6_ADDR_BLOCK4(ip6_current_dest_addr()), + IP6_ADDR_BLOCK5(ip6_current_dest_addr()), + IP6_ADDR_BLOCK6(ip6_current_dest_addr()), + IP6_ADDR_BLOCK7(ip6_current_dest_addr()), + IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } +#if LWIP_IPV6_SCOPES + /* Do not forward packets with a zoned (e.g., link-local) source address + * outside of their zone. We determined the zone a bit earlier, so we know + * that the address is properly zoned here, so we can safely use has_zone. + * Also skip packets with a loopback source address (link-local implied). */ + if ((ip6_addr_has_zone(ip6_current_src_addr()) && + !ip6_addr_test_zone(ip6_current_src_addr(), netif)) || + ip6_addr_isloopback(ip6_current_src_addr())) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding packet beyond its source address zone.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } +#endif /* LWIP_IPV6_SCOPES */ + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + + /* decrement HL */ + IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); + /* send ICMP6 if HL == 0 */ + if (IP6H_HOPLIM(iphdr) == 0) { +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_time_exceeded(p, ICMP6_TE_HL); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.drop); + return; + } + + if (netif->mtu && (p->tot_len > netif->mtu)) { +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_packet_too_big(p, netif->mtu); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.drop); + return; + } + + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(ip6_current_dest_addr()), + IP6_ADDR_BLOCK2(ip6_current_dest_addr()), + IP6_ADDR_BLOCK3(ip6_current_dest_addr()), + IP6_ADDR_BLOCK4(ip6_current_dest_addr()), + IP6_ADDR_BLOCK5(ip6_current_dest_addr()), + IP6_ADDR_BLOCK6(ip6_current_dest_addr()), + IP6_ADDR_BLOCK7(ip6_current_dest_addr()), + IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); + + /* transmit pbuf on chosen interface */ + netif->output_ip6(netif, p, ip6_current_dest_addr()); + IP6_STATS_INC(ip6.fw); + IP6_STATS_INC(ip6.xmit); + return; +} +#endif /* LWIP_IPV6_FORWARD */ + +/** Return true if the current input packet should be accepted on this netif */ +static int +ip6_input_accept(struct netif *netif) +{ + /* interface is up? */ + if (netif_is_up(netif)) { + u8_t i; + /* unicast to this interface address? address configured? */ + /* If custom scopes are used, the destination zone will be tested as + * part of the local-address comparison, but we need to test the source + * scope as well (e.g., is this interface on the same link?). */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i)) +#if IPV6_CUSTOM_SCOPES + && (!ip6_addr_has_zone(ip6_current_src_addr()) || + ip6_addr_test_zone(ip6_current_src_addr(), netif)) +#endif /* IPV6_CUSTOM_SCOPES */ + ) { + /* accept on this netif */ + return 1; + } + } + } + return 0; +} + +/** + * This function is called by the network interface device driver when + * an IPv6 packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip6_forward). + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * @param p the received IPv6 packet (p->payload points to IPv6 header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + * processed, but currently always returns ERR_OK) + */ +err_t +ip6_input(struct pbuf *p, struct netif *inp) +{ + struct ip6_hdr *ip6hdr; + struct netif *netif; + const u8_t *nexth; + u16_t hlen, hlen_tot; /* the current header length */ +#if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ + @todo + int check_ip_src=1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ +#if LWIP_RAW + raw_input_state_t raw_status; +#endif /* LWIP_RAW */ + + LWIP_ASSERT_CORE_LOCKED(); + + IP6_STATS_INC(ip6.recv); + + /* identify the IP header */ + ip6hdr = (struct ip6_hdr *)p->payload; + if (IP6H_V(ip6hdr) != 6) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", + IP6H_V(ip6hdr))); + pbuf_free(p); + IP6_STATS_INC(ip6.err); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + +#ifdef LWIP_HOOK_IP6_INPUT + if (LWIP_HOOK_IP6_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + + /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ + if ((IP6_HLEN > p->len) || (IP6H_PLEN(ip6hdr) > (p->tot_len - IP6_HLEN))) { + if (IP6_HLEN > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", + (u16_t)IP6_HLEN, p->len)); + } + if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", + (u16_t)(IP6H_PLEN(ip6hdr) + IP6_HLEN), p->tot_len)); + } + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + + /* Trim pbuf. This should have been done at the netif layer, + * but we'll do it anyway just to be sure that its done. */ + pbuf_realloc(p, (u16_t)(IP6_HLEN + IP6H_PLEN(ip6hdr))); + + /* copy IP addresses to aligned ip6_addr_t */ + ip_addr_copy_from_ip6_packed(ip_data.current_iphdr_dest, ip6hdr->dest); + ip_addr_copy_from_ip6_packed(ip_data.current_iphdr_src, ip6hdr->src); + + /* Don't accept virtual IPv4 mapped IPv6 addresses. + * Don't accept multicast source addresses. */ + if (ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_dest)) || + ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_src)) || + ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_src))) { + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.err); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + + /* Set the appropriate zone identifier on the addresses. */ + ip6_addr_assign_zone(ip_2_ip6(&ip_data.current_iphdr_dest), IP6_UNKNOWN, inp); + ip6_addr_assign_zone(ip_2_ip6(&ip_data.current_iphdr_src), IP6_UNICAST, inp); + + /* current header pointer. */ + ip_data.current_ip6_header = ip6hdr; + + /* In netif, used in case we need to send ICMPv6 packets back. */ + ip_data.current_netif = inp; + ip_data.current_input_netif = inp; + + /* match packet against an interface, i.e. is this packet for us? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* Always joined to multicast if-local and link-local all-nodes group. */ + if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || + ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { + netif = inp; + } +#if LWIP_IPV6_MLD + else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { + netif = inp; + } +#else /* LWIP_IPV6_MLD */ + else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { + u8_t i; + /* Filter solicited node packets when MLD is not enabled + * (for Neighbor discovery). */ + netif = NULL; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + netif = inp; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + break; + } + } + } +#endif /* LWIP_IPV6_MLD */ + else { + netif = NULL; + } + } else { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. */ + if (ip6_input_accept(inp)) { + netif = inp; + } else { + netif = NULL; +#if !IPV6_CUSTOM_SCOPES + /* Shortcut: stop looking for other interfaces if either the source or + * the destination has a scope constrained to this interface. Custom + * scopes may break the 1:1 link/interface mapping, however. */ + if (ip6_addr_islinklocal(ip6_current_dest_addr()) || + ip6_addr_islinklocal(ip6_current_src_addr())) { + goto netif_found; + } +#endif /* !IPV6_CUSTOM_SCOPES */ +#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF + /* The loopback address is to be considered link-local. Packets to it + * should be dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. + * Its implied scope means packets *from* the loopback address should + * not be accepted on other interfaces, either. These requirements + * cannot be implemented in the case that loopback traffic is sent + * across a non-loopback interface, however. */ + if (ip6_addr_isloopback(ip6_current_dest_addr()) || + ip6_addr_isloopback(ip6_current_src_addr())) { + goto netif_found; + } +#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ +#if !LWIP_SINGLE_NETIF + NETIF_FOREACH(netif) { + if (netif == inp) { + /* we checked that before already */ + continue; + } + if (ip6_input_accept(netif)) { + break; + } + } +#endif /* !LWIP_SINGLE_NETIF */ + } +netif_found: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", + netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); + } + + /* "::" packet source address? (used in duplicate address detection) */ + if (ip6_addr_isany(ip6_current_src_addr()) && + (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { + /* packet source is not valid */ + /* free (drop) packet pbufs */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); +#if LWIP_IPV6_FORWARD + /* non-multicast packet? */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* try to forward IP packet on (other) interfaces */ + ip6_forward(p, ip6hdr, inp); + } +#endif /* LWIP_IPV6_FORWARD */ + pbuf_free(p); + goto ip6_input_cleanup; + } + + /* current netif pointer. */ + ip_data.current_netif = netif; + + /* Save next header type. */ + nexth = &IP6H_NEXTH(ip6hdr); + + /* Init header length. */ + hlen = hlen_tot = IP6_HLEN; + + /* Move to payload. */ + pbuf_remove_header(p, IP6_HLEN); + + /* Process known option extension headers, if present. */ + while (*nexth != IP6_NEXTH_NONE) + { + switch (*nexth) { + case IP6_NEXTH_HOPBYHOP: + { + s32_t opt_offset; + struct ip6_hbh_hdr *hbh_hdr; + struct ip6_opt_hdr *opt_hdr; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); + + /* Get and check the header length, while staying in packet bounds. */ + hbh_hdr = (struct ip6_hbh_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_HBH_NEXTH(hbh_hdr); + + /* Get the header length. */ + hlen = (u16_t)(8 * (1 + hbh_hdr->_hlen)); + + if ((p->len < 8) || (hlen > p->len)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + hlen_tot = (u16_t)(hlen_tot + hlen); + + /* The extended option header starts right after Hop-by-Hop header. */ + opt_offset = IP6_HBH_HLEN; + while (opt_offset < hlen) + { + s32_t opt_dlen = 0; + + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + opt_offset); + + switch (IP6_OPT_TYPE(opt_hdr)) { + /* @todo: process IPV6 Hop-by-Hop option data */ + case IP6_PAD1_OPTION: + /* PAD1 option doesn't have length and value field */ + opt_dlen = -1; + break; + case IP6_PADN_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_ROUTER_ALERT_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_JUMBO_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + default: + /* Check 2 MSB of Hop-by-Hop header type. */ + switch (IP6_OPT_TYPE_ACTION(opt_hdr)) { + case 1: + /* Discard the packet. */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 2: + /* Send ICMP Parameter Problem */ + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 3: + /* Send ICMP Parameter Problem if destination address is not a multicast address */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + } + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + default: + /* Skip over this option. */ + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + } + break; + } + + /* Adjust the offset to move to the next extended option header */ + opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; + } + pbuf_remove_header(p, hlen); + break; + } + case IP6_NEXTH_DESTOPTS: + { + s32_t opt_offset; + struct ip6_dest_hdr *dest_hdr; + struct ip6_opt_hdr *opt_hdr; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); + + dest_hdr = (struct ip6_dest_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_DEST_NEXTH(dest_hdr); + + /* Get the header length. */ + hlen = 8 * (1 + dest_hdr->_hlen); + if ((p->len < 8) || (hlen > p->len)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + hlen_tot = (u16_t)(hlen_tot + hlen); + + /* The extended option header starts right after Destination header. */ + opt_offset = IP6_DEST_HLEN; + while (opt_offset < hlen) + { + s32_t opt_dlen = 0; + + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)dest_hdr + opt_offset); + + switch (IP6_OPT_TYPE(opt_hdr)) + { + /* @todo: process IPV6 Destination option data */ + case IP6_PAD1_OPTION: + /* PAD1 option deosn't have length and value field */ + opt_dlen = -1; + break; + case IP6_PADN_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_ROUTER_ALERT_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_JUMBO_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_HOME_ADDRESS_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + default: + /* Check 2 MSB of Destination header type. */ + switch (IP6_OPT_TYPE_ACTION(opt_hdr)) + { + case 1: + /* Discard the packet. */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 2: + /* Send ICMP Parameter Problem */ + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 3: + /* Send ICMP Parameter Problem if destination address is not a multicast address */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + } + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + default: + /* Skip over this option. */ + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + } + break; + } + + /* Adjust the offset to move to the next extended option header */ + opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; + } + + pbuf_remove_header(p, hlen); + break; + } + case IP6_NEXTH_ROUTING: + { + struct ip6_rout_hdr *rout_hdr; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); + + rout_hdr = (struct ip6_rout_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_ROUT_NEXTH(rout_hdr); + + /* Get the header length. */ + hlen = 8 * (1 + rout_hdr->_hlen); + + if ((p->len < 8) || (hlen > p->len)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + /* Skip over this header. */ + hlen_tot = (u16_t)(hlen_tot + hlen); + + /* if segment left value is 0 in routing header, ignore the option */ + if (IP6_ROUT_SEG_LEFT(rout_hdr)) { + /* The length field of routing option header must be even */ + if (rout_hdr->_hlen & 0x1) { + /* Discard and send parameter field error */ + icmp6_param_problem(p, ICMP6_PP_FIELD, &rout_hdr->_hlen); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + switch (IP6_ROUT_TYPE(rout_hdr)) + { + /* TODO: process routing by the type */ + case IP6_ROUT_TYPE2: + break; + case IP6_ROUT_RPL: + break; + default: + /* Discard unrecognized routing type and send parameter field error */ + icmp6_param_problem(p, ICMP6_PP_FIELD, &IP6_ROUT_TYPE(rout_hdr)); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + } + + pbuf_remove_header(p, hlen); + break; + } + case IP6_NEXTH_FRAGMENT: + { + struct ip6_frag_hdr *frag_hdr; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); + + frag_hdr = (struct ip6_frag_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_FRAG_NEXTH(frag_hdr); + + /* Fragment Header length. */ + hlen = 8; + + /* Make sure this header fits in current pbuf. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_FRAG_STATS_INC(ip6_frag.lenerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto ip6_input_cleanup; + } + + hlen_tot = (u16_t)(hlen_tot + hlen); + + /* check payload length is multiple of 8 octets when mbit is set */ + if (IP6_FRAG_MBIT(frag_hdr) && (IP6H_PLEN(ip6hdr) & 0x7)) { + /* ipv6 payload length is not multiple of 8 octets */ + icmp6_param_problem(p, ICMP6_PP_FIELD, LWIP_PACKED_CAST(const void *, &ip6hdr->_plen)); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid payload length dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + /* Offset == 0 and more_fragments == 0? */ + if ((frag_hdr->_fragment_offset & + PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) { + /* This is a 1-fragment packet. Skip this header and continue. */ + pbuf_remove_header(p, hlen); + } else { +#if LWIP_IPV6_REASS + /* reassemble the packet */ + ip_data.current_ip_header_tot_len = hlen_tot; + p = ip6_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + goto ip6_input_cleanup; + } + + /* Returned p point to IPv6 header. + * Update all our variables and pointers and continue. */ + ip6hdr = (struct ip6_hdr *)p->payload; + nexth = &IP6H_NEXTH(ip6hdr); + hlen = hlen_tot = IP6_HLEN; + pbuf_remove_header(p, IP6_HLEN); + +#else /* LWIP_IPV6_REASS */ + /* free (drop) packet pbufs */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.opterr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; +#endif /* LWIP_IPV6_REASS */ + } + break; + } + default: + goto options_done; + } + + if (*nexth == IP6_NEXTH_HOPBYHOP) { + /* Hop-by-Hop header comes only as a first option */ + icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header dropped (only valid as a first option)\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + } + +options_done: + + /* send to upper layers */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); + ip6_debug_print(p); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + + ip_data.current_ip_header_tot_len = hlen_tot; + +#if LWIP_RAW + /* p points to IPv6 header again for raw_input. */ + pbuf_add_header_force(p, hlen_tot); + /* raw input did not eat the packet? */ + raw_status = raw_input(p, inp); + if (raw_status != RAW_INPUT_EATEN) + { + /* Point to payload. */ + pbuf_remove_header(p, hlen_tot); +#else /* LWIP_RAW */ + { +#endif /* LWIP_RAW */ + switch (*nexth) { + case IP6_NEXTH_NONE: + pbuf_free(p); + break; +#if LWIP_UDP + case IP6_NEXTH_UDP: +#if LWIP_UDPLITE + case IP6_NEXTH_UDPLITE: +#endif /* LWIP_UDPLITE */ + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP6_NEXTH_TCP: + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP6 + case IP6_NEXTH_ICMP6: + icmp6_input(p, inp); + break; +#endif /* LWIP_ICMP */ + default: +#if LWIP_RAW + if (raw_status == RAW_INPUT_DELIVERED) { + /* @todo: ipv6 mib in-delivers? */ + } else +#endif /* LWIP_RAW */ + { +#if LWIP_ICMP6 + /* p points to IPv6 header again for raw_input. */ + pbuf_add_header_force(p, hlen_tot); + /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ + if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && + (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { + icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); + } +#endif /* LWIP_ICMP */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr))); + IP6_STATS_INC(ip6.proterr); + IP6_STATS_INC(ip6.drop); + } + pbuf_free(p); + break; + } + } + +ip6_input_cleanup: + ip_data.current_netif = NULL; + ip_data.current_input_netif = NULL; + ip_data.current_ip6_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip6_addr_set_zero(ip6_current_src_addr()); + ip6_addr_set_zero(ip6_current_dest_addr()); + + return ERR_OK; +} + + +/** + * Sends an IPv6 packet on a network interface. This function constructs + * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is + * used as source (usually during network startup). If the source IPv6 address it + * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network + * interface is filled in as source address. If the destination IPv6 address is + * LWIP_IP_HDRINCL, p is assumed to already include an IPv6 header and + * p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) (src is possibly not + * properly zoned) + * @param dest the destination IPv6 address to send the packet to (possibly not + * properly zoned) + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IPv6/LINK headers + * returns errors returned by netif->output_ip6 + */ +err_t +ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) +{ + const ip6_addr_t *src_used = src; + if (dest != LWIP_IP_HDRINCL) { + if (src != NULL && ip6_addr_isany(src)) { + src_used = ip_2_ip6(ip6_select_source_address(netif, dest)); + if ((src_used == NULL) || ip6_addr_isany(src_used)) { + /* No appropriate source address was found for this packet. */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + } + } + return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif); +} + +/** + * Same as ip6_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) +{ + struct ip6_hdr *ip6hdr; + ip6_addr_t dest_addr; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + /* Should the IPv6 header be generated or is it already included in p? */ + if (dest != LWIP_IP_HDRINCL) { +#if LWIP_IPV6_SCOPES + /* If the destination address is scoped but lacks a zone, add a zone now, + * based on the outgoing interface. The lower layers (e.g., nd6) absolutely + * require addresses to be properly zoned for correctness. In some cases, + * earlier attempts will have been made to add a zone to the destination, + * but this function is the only one that is called in all (other) cases, + * so we must do this here. */ + if (ip6_addr_lacks_zone(dest, IP6_UNKNOWN)) { + ip6_addr_copy(dest_addr, *dest); + ip6_addr_assign_zone(&dest_addr, IP6_UNKNOWN, netif); + dest = &dest_addr; + } +#endif /* LWIP_IPV6_SCOPES */ + + /* generate IPv6 header */ + if (pbuf_add_header(p, IP6_HLEN)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + ip6hdr = (struct ip6_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", + (p->len >= sizeof(struct ip6_hdr))); + + IP6H_HOPLIM_SET(ip6hdr, hl); + IP6H_NEXTH_SET(ip6hdr, nexth); + + /* dest cannot be NULL here */ + ip6_addr_copy_to_packed(ip6hdr->dest, *dest); + + IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); + IP6H_PLEN_SET(ip6hdr, (u16_t)(p->tot_len - IP6_HLEN)); + + if (src == NULL) { + src = IP6_ADDR_ANY6; + } + /* src cannot be NULL here */ + ip6_addr_copy_to_packed(ip6hdr->src, *src); + + } else { + /* IP header already included in p */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); + ip6_addr_assign_zone(&dest_addr, IP6_UNKNOWN, netif); + dest = &dest_addr; + } + + IP6_STATS_INC(ip6.xmit); + + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); + ip6_debug_print(p); + +#if ENABLE_LOOPBACK + { + int i; +#if !LWIP_HAVE_LOOPIF + if (ip6_addr_isloopback(dest)) { + return netif_loop_output(netif, p); + } +#endif /* !LWIP_HAVE_LOOPIF */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); + return netif_loop_output(netif, p); + } + } + } +#if LWIP_MULTICAST_TX_OPTIONS + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p); + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#endif /* ENABLE_LOOPBACK */ +#if LWIP_IPV6_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif_mtu6(netif) && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { + return ip6_frag(p, netif, dest); + } +#endif /* LWIP_IPV6_FRAG */ + + LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); + return netif->output_ip6(netif, p, dest); +} + +/** + * Simple interface to ip6_output_if. It finds the outgoing network + * interface and calls upon ip6_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth) +{ + struct netif *netif; + struct ip6_hdr *ip6hdr; + ip6_addr_t src_addr, dest_addr; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if (dest != LWIP_IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy_from_packed(src_addr, ip6hdr->src); + ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + dest = &dest_addr; + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + return ip6_output_if(p, src, dest, hl, tc, nexth, netif); +} + + +#if LWIP_NETIF_USE_HINTS +/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip6_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param netif_hint netif output hint pointer set to netif->hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif_hint *netif_hint) +{ + struct netif *netif; + struct ip6_hdr *ip6hdr; + ip6_addr_t src_addr, dest_addr; + err_t err; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if (dest != LWIP_IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy_from_packed(src_addr, ip6hdr->src); + ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + dest = &dest_addr; + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + NETIF_SET_HINTS(netif, netif_hint); + err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); + NETIF_RESET_HINTS(netif); + + return err; +} +#endif /* LWIP_NETIF_USE_HINTS*/ + +#if LWIP_IPV6_MLD +/** + * Add a hop-by-hop options header with a router alert option and padding. + * + * Used by MLD when sending a Multicast listener report/done message. + * + * @param p the packet to which we will prepend the options header + * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6) + * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD) + * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise + */ +err_t +ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value) +{ + u8_t *opt_data; + u32_t offset = 0; + struct ip6_hbh_hdr *hbh_hdr; + struct ip6_opt_hdr *opt_hdr; + + /* fixed 4 bytes for router alert option and 2 bytes padding */ + const u8_t hlen = (sizeof(struct ip6_opt_hdr) * 2) + IP6_ROUTER_ALERT_DLEN; + /* Move pointer to make room for hop-by-hop options header. */ + if (pbuf_add_header(p, sizeof(struct ip6_hbh_hdr) + hlen)) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + /* Set fields of Hop-by-Hop header */ + hbh_hdr = (struct ip6_hbh_hdr *)p->payload; + IP6_HBH_NEXTH(hbh_hdr) = nexth; + hbh_hdr->_hlen = 0; + offset = IP6_HBH_HLEN; + + /* Set router alert options to Hop-by-Hop extended option header */ + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); + IP6_OPT_TYPE(opt_hdr) = IP6_ROUTER_ALERT_OPTION; + IP6_OPT_DLEN(opt_hdr) = IP6_ROUTER_ALERT_DLEN; + offset += IP6_OPT_HLEN; + + /* Set router alert option data */ + opt_data = (u8_t *)hbh_hdr + offset; + opt_data[0] = value; + opt_data[1] = 0; + offset += IP6_OPT_DLEN(opt_hdr); + + /* add 2 bytes padding to make 8 bytes Hop-by-Hop header length */ + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); + IP6_OPT_TYPE(opt_hdr) = IP6_PADN_OPTION; + IP6_OPT_DLEN(opt_hdr) = 0; + + return ERR_OK; +} +#endif /* LWIP_IPV6_MLD */ + +#if IP6_DEBUG +/* Print an IPv6 header by using LWIP_DEBUGF + * @param p an IPv6 packet, p->payload pointing to the IPv6 header + */ +void +ip6_debug_print(struct pbuf *p) +{ + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; + + LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", + IP6H_V(ip6hdr), + IP6H_TC(ip6hdr), + IP6H_FL(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", + IP6H_PLEN(ip6hdr), + IP6H_NEXTH(ip6hdr), + IP6H_HOPLIM(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->src)), + IP6_ADDR_BLOCK2(&(ip6hdr->src)), + IP6_ADDR_BLOCK3(&(ip6hdr->src)), + IP6_ADDR_BLOCK4(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->src)), + IP6_ADDR_BLOCK6(&(ip6hdr->src)), + IP6_ADDR_BLOCK7(&(ip6hdr->src)), + IP6_ADDR_BLOCK8(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->dest)), + IP6_ADDR_BLOCK2(&(ip6hdr->dest)), + IP6_ADDR_BLOCK3(&(ip6hdr->dest)), + IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->dest)), + IP6_ADDR_BLOCK6(&(ip6hdr->dest)), + IP6_ADDR_BLOCK7(&(ip6hdr->dest)), + IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP6_DEBUG */ + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_addr.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_addr.c new file mode 100644 index 0000000..687c02f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_addr.c @@ -0,0 +1,343 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Functions for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/def.h" + +#include + +#if LWIP_IPV4 +#include "lwip/ip4_addr.h" /* for ip6addr_aton to handle IPv4-mapped addresses */ +#endif /* LWIP_IPV4 */ + +/* used by IP6_ADDR_ANY(6) in ip6_addr.h */ +const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); + +#define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10)) + +/** + * Check whether "cp" is a valid ascii representation + * of an IPv6 address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * + * @param cp IPv6 address in ascii representation (e.g. "FF01::1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip6addr_aton(const char *cp, ip6_addr_t *addr) +{ + u32_t addr_index, zero_blocks, current_block_index, current_block_value; + const char *s; +#if LWIP_IPV4 + int check_ipv4_mapped = 0; +#endif /* LWIP_IPV4 */ + + /* Count the number of colons, to count the number of blocks in a "::" sequence + zero_blocks may be 1 even if there are no :: sequences */ + zero_blocks = 8; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + zero_blocks--; +#if LWIP_IPV4 + } else if (*s == '.') { + if ((zero_blocks == 5) ||(zero_blocks == 2)) { + check_ipv4_mapped = 1; + /* last block could be the start of an IPv4 address */ + zero_blocks--; + } else { + /* invalid format */ + return 0; + } + break; +#endif /* LWIP_IPV4 */ + } else if (!lwip_isxdigit(*s)) { + break; + } + } + + /* parse each block */ + addr_index = 0; + current_block_index = 0; + current_block_value = 0; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + } + current_block_index++; +#if LWIP_IPV4 + if (check_ipv4_mapped) { + if (current_block_index == 6) { + ip4_addr_t ip4; + int ret = ip4addr_aton(s + 1, &ip4); + if (ret) { + if (addr) { + addr->addr[3] = lwip_htonl(ip4.addr); + current_block_index++; + goto fix_byte_order_and_return; + } + return 1; + } + } + } +#endif /* LWIP_IPV4 */ + current_block_value = 0; + if (current_block_index > 7) { + /* address too long! */ + return 0; + } + if (s[1] == ':') { + if (s[2] == ':') { + /* invalid format: three successive colons */ + return 0; + } + s++; + /* "::" found, set zeros */ + while (zero_blocks > 0) { + zero_blocks--; + if (current_block_index & 0x1) { + addr_index++; + } else { + if (addr) { + addr->addr[addr_index] = 0; + } + } + current_block_index++; + if (current_block_index > 7) { + /* address too long! */ + return 0; + } + } + } + } else if (lwip_isxdigit(*s)) { + /* add current digit */ + current_block_value = (current_block_value << 4) + + (lwip_isdigit(*s) ? (u32_t)(*s - '0') : + (u32_t)(10 + (lwip_islower(*s) ? *s - 'a' : *s - 'A'))); + } else { + /* unexpected digit, space? CRLF? */ + break; + } + } + + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } +#if LWIP_IPV4 +fix_byte_order_and_return: +#endif + /* convert to network byte order. */ + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]); + } + + ip6_addr_clear_zone(addr); + } + + if (current_block_index != 7) { + return 0; + } + + return 1; +} + +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char * +ip6addr_ntoa(const ip6_addr_t *addr) +{ + static char str[40]; + return ip6addr_ntoa_r(addr, str, 40); +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip6 address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) +{ + u32_t current_block_index, current_block_value, next_block_value; + s32_t i; + u8_t zero_flag, empty_block_flag; + +#if LWIP_IPV4 + if (ip6_addr_isipv4mappedipv6(addr)) { + /* This is an IPv4 mapped address */ + ip4_addr_t addr4; + char *ret; +#define IP4MAPPED_HEADER "::FFFF:" + char *buf_ip4 = buf + sizeof(IP4MAPPED_HEADER) - 1; + int buflen_ip4 = buflen - sizeof(IP4MAPPED_HEADER) + 1; + if (buflen < (int)sizeof(IP4MAPPED_HEADER)) { + return NULL; + } + memcpy(buf, IP4MAPPED_HEADER, sizeof(IP4MAPPED_HEADER)); + addr4.addr = addr->addr[3]; + ret = ip4addr_ntoa_r(&addr4, buf_ip4, buflen_ip4); + if (ret != buf_ip4) { + return NULL; + } + return buf; + } +#endif /* LWIP_IPV4 */ + i = 0; + empty_block_flag = 0; /* used to indicate a zero chain for "::' */ + + for (current_block_index = 0; current_block_index < 8; current_block_index++) { + /* get the current 16-bit block */ + current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + /* Check for empty block. */ + if (current_block_value == 0) { + if (current_block_index == 7 && empty_block_flag == 1) { + /* special case, we must render a ':' for the last block. */ + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + break; + } + if (empty_block_flag == 0) { + /* generate empty block "::", but only if more than one contiguous zero block, + * according to current formatting suggestions RFC 5952. */ + next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]); + if ((current_block_index & 0x1) == 0x01) { + next_block_value = next_block_value >> 16; + } + next_block_value &= 0xffff; + if (next_block_value == 0) { + empty_block_flag = 1; + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + continue; /* move on to next block. */ + } + } else if (empty_block_flag == 1) { + /* move on to next block. */ + continue; + } + } else if (empty_block_flag == 1) { + /* Set this flag value so we don't produce multiple empty blocks. */ + empty_block_flag = 2; + } + + if (current_block_index > 0) { + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + } + + if ((current_block_value & 0xf000) == 0) { + zero_flag = 1; + } else { + buf[i++] = lwip_xchar(((current_block_value & 0xf000) >> 12)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + if (((current_block_value & 0xf00) == 0) && (zero_flag)) { + /* do nothing */ + } else { + buf[i++] = lwip_xchar(((current_block_value & 0xf00) >> 8)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + if (((current_block_value & 0xf0) == 0) && (zero_flag)) { + /* do nothing */ + } + else { + buf[i++] = lwip_xchar(((current_block_value & 0xf0) >> 4)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + buf[i++] = lwip_xchar((current_block_value & 0xf)); + if (i >= buflen) { + return NULL; + } + } + + buf[i] = 0; + + return buf; +} + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_frag.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_frag.c new file mode 100644 index 0000000..8b352f5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/ip6_frag.c @@ -0,0 +1,862 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" +#include "lwip/ip6_frag.h" +#include "lwip/ip6.h" +#include "lwip/icmp6.h" +#include "lwip/nd6.h" +#include "lwip/ip.h" + +#include "lwip/pbuf.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#if IPV6_FRAG_COPYHEADER +/* The number of bytes we need to "borrow" from (i.e., overwrite in) the header + * that precedes the fragment header for reassembly pruposes. */ +#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN)) +#endif + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IPv6 header, since it replaces + * the Fragment Header in memory in incoming fragments to keep + * track of the various fragments. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* static variables */ +static struct ip6_reassdata *reassdatagrams; +static u16_t ip6_reass_pbufcount; + +/* Forward declarations. */ +static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr); +#if IP_REASS_FREE_OLDEST +static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed); +#endif /* IP_REASS_FREE_OLDEST */ + +void +ip6_reass_tmr(void) +{ + struct ip6_reassdata *r, *tmp; + +#if !IPV6_FRAG_COPYHEADER + LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", + sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); +#endif /* !IPV6_FRAG_COPYHEADER */ + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + r = r->next; + } else { + /* reassembly timed out */ + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip6_reass_free_complete_datagram(tmp); + } + } +} + +/** + * Free a datagram (struct ip6_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), + * sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + */ +static void +ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) +{ + struct ip6_reassdata *prev; + u16_t pbufs_freed = 0; + u16_t clen; + struct pbuf *p; + struct ip6_reass_helper *iprh; + +#if LWIP_ICMP6 + iprh = (struct ip6_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Restore the part that we've overwritten with our helper structure, or we + * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ + MEMCPY(p->payload, ipr->orig_hdr, sizeof(iprh)); + /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). + This cannot fail since we already checked when receiving this fragment. */ + if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) { + LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); + } + else { + /* Reconstruct the zoned source and destination addresses, so that we do + * not end up sending the ICMP response over the wrong link. */ + ip6_addr_t src_addr, dest_addr; + ip6_addr_copy_from_packed(src_addr, IPV6_FRAG_SRC(ipr)); + ip6_addr_set_zone(&src_addr, ipr->src_zone); + ip6_addr_copy_from_packed(dest_addr, IPV6_FRAG_DEST(ipr)); + ip6_addr_set_zone(&dest_addr, ipr->dest_zone); + /* Send the actual ICMP response. */ + icmp6_time_exceeded_with_addrs(p, ICMP6_TE_FRAG, &src_addr, &dest_addr); + } + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed = (u16_t)(pbufs_freed + clen); + pbuf_free(p); + } +#endif /* LWIP_ICMP6 */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip6_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed = (u16_t)(pbufs_freed + clen); + pbuf_free(pcur); + } + + /* Then, unchain the struct ip6_reassdata from the list and free it. */ + if (ipr == reassdatagrams) { + reassdatagrams = ipr->next; + } else { + prev = reassdatagrams; + while (prev != NULL) { + if (prev->next == ipr) { + break; + } + prev = prev->next; + } + if (prev != NULL) { + prev->next = ipr->next; + } + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* Finally, update number of pbufs in reassembly queue */ + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); + ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount - pbufs_freed); +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram ipr is not freed! + * + * @param ipr ip6_reassdata for the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + */ +static void +ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) +{ + struct ip6_reassdata *r, *oldest; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the current datagram! */ + do { + r = oldest = reassdatagrams; + while (r != NULL) { + if (r != ipr) { + if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + } + } + r = r->next; + } + if (oldest == ipr) { + /* nothing to free, ipr is the only element on the list */ + return; + } + if (oldest != NULL) { + ip6_reass_free_complete_datagram(oldest); + } + } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Reassembles incoming IPv6 fragments into an IPv6 datagram. + * + * @param p points to the IPv6 Fragment Header + * @return NULL if reassembly is incomplete, pbuf pointing to + * IPv6 Header if reassembly is complete + */ +struct pbuf * +ip6_reass(struct pbuf *p) +{ + struct ip6_reassdata *ipr, *ipr_prev; + struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct ip6_frag_hdr *frag_hdr; + u16_t offset, len, start, end; + ptrdiff_t hdrdiff; + u16_t clen; + u8_t valid = 1; + struct pbuf *q, *next_pbuf; + + IP6_FRAG_STATS_INC(ip6_frag.recv); + + /* ip6_frag_hdr must be in the first pbuf, not chained. Checked by caller. */ + LWIP_ASSERT("IPv6 fragment header does not fit in first pbuf", + p->len >= sizeof(struct ip6_frag_hdr)); + + frag_hdr = (struct ip6_frag_hdr *) p->payload; + + clen = pbuf_clen(p); + + offset = lwip_ntohs(frag_hdr->_fragment_offset); + + /* Calculate fragment length from IPv6 payload length. + * Adjust for headers before Fragment Header. + * And finally adjust by Fragment Header length. */ + len = lwip_ntohs(ip6_current_header()->_plen); + hdrdiff = (u8_t*)p->payload - (const u8_t*)ip6_current_header(); + LWIP_ASSERT("not a valid pbuf (ip6_input check missing?)", hdrdiff <= 0xFFFF); + LWIP_ASSERT("not a valid pbuf (ip6_input check missing?)", hdrdiff >= IP6_HLEN); + hdrdiff -= IP6_HLEN; + hdrdiff += IP6_FRAG_HLEN; + if (hdrdiff > len) { + IP6_FRAG_STATS_INC(ip6_frag.proterr); + goto nullreturn; + } + len = (u16_t)(len - hdrdiff); + start = (offset & IP6_FRAG_OFFSET_MASK); + if (start > (0xFFFF - len)) { + /* u16_t overflow, cannot handle this */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + goto nullreturn; + } + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if ((frag_hdr->_identification == ipr->identification) && + ip6_addr_cmp_packed(ip6_current_src_addr(), &(IPV6_FRAG_SRC(ipr)), ipr->src_zone) && + ip6_addr_cmp_packed(ip6_current_dest_addr(), &(IPV6_FRAG_DEST(ipr)), ipr->dest_zone)) { + IP6_FRAG_STATS_INC(ip6_frag.cachehit); + break; + } + ipr_prev = ipr; + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + /* Make room and try again. */ + ip6_reass_remove_oldest_datagram(ipr, clen); + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr != NULL) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else +#endif /* IP_REASS_FREE_OLDEST */ + { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + goto nullreturn; + } + } + + memset(ipr, 0, sizeof(struct ip6_reassdata)); + ipr->timer = IPV6_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + + /* Use the current IPv6 header for src/dest address reference. + * Eventually, we will replace it when we get the first fragment + * (it might be this one, in any case, it is done later). */ + /* need to use the none-const pointer here: */ + ipr->iphdr = ip_data.current_ip6_header; +#if IPV6_FRAG_COPYHEADER + MEMCPY(&ipr->src, &ip6_current_header()->src, sizeof(ipr->src)); + MEMCPY(&ipr->dest, &ip6_current_header()->dest, sizeof(ipr->dest)); +#endif /* IPV6_FRAG_COPYHEADER */ +#if LWIP_IPV6_SCOPES + /* Also store the address zone information. + * @todo It is possible that due to netif destruction and recreation, the + * stored zones end up resolving to a different interface. In that case, we + * risk sending a "time exceeded" ICMP response over the wrong link. + * Ideally, netif destruction would clean up matching pending reassembly + * structures, but custom zone mappings would make that non-trivial. */ + ipr->src_zone = ip6_addr_zone(ip6_current_src_addr()); + ipr->dest_zone = ip6_addr_zone(ip6_current_dest_addr()); +#endif /* LWIP_IPV6_SCOPES */ + /* copy the fragmented packet id. */ + ipr->identification = frag_hdr->_identification; + + /* copy the nexth field */ + ipr->nexth = frag_hdr->_nexth; + } + + /* Check if we are allowed to enqueue more datagrams. */ + if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + ip6_reass_remove_oldest_datagram(ipr, clen); + if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else +#endif /* IP_REASS_FREE_OLDEST */ + { + /* @todo: send ICMPv6 time exceeded here? */ + /* drop this pbuf */ + IP6_FRAG_STATS_INC(ip6_frag.memerr); + goto nullreturn; + } + } + + /* Overwrite Fragment Header with our own helper struct. */ +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + /* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4). + This cannot fail since we already checked when receiving this fragment. */ + u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } +#else /* IPV6_FRAG_COPYHEADER */ + LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", + sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); +#endif /* IPV6_FRAG_COPYHEADER */ + + /* Prepare the pointer to the helper structure, and its initial values. + * Do not yet write to the structure itself, as we still have to make a + * backup of the original data, and we should not do that until we know for + * sure that we are going to add this packet to the list. */ + iprh = (struct ip6_reass_helper *)p->payload; + next_pbuf = NULL; + end = (u16_t)(start + len); + + /* find the right place to insert this pbuf */ + /* Iterate through until we either get to the end of the list (append), + * or we find on with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip6_reass_helper*)q->payload; + if (start < iprh_tmp->start) { +#if IP_REASS_CHECK_OVERLAP + if (end > iprh_tmp->start) { + /* fragment overlaps with following, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + goto nullreturn; + } + if (iprh_prev != NULL) { + if (start < iprh_prev->end) { + /* fragment overlaps with previous, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + goto nullreturn; + } + } +#endif /* IP_REASS_CHECK_OVERLAP */ + /* the new pbuf should be inserted before this */ + next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ + iprh_prev->next_pbuf = p; + } else { + /* fragment with the lowest offset */ + ipr->p = p; + } + break; + } else if (start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + goto nullreturn; +#if IP_REASS_CHECK_OVERLAP + } else if (start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + goto nullreturn; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no gaps. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = p; + if (iprh_prev->end != start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = p; + } + } + + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time */ + ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount + clen); + + /* Remember IPv6 header if this is the first fragment. */ + if (start == 0) { + /* need to use the none-const pointer here: */ + ipr->iphdr = ip_data.current_ip6_header; + /* Make a backup of the part of the packet data that we are about to + * overwrite, so that we can restore the original later. */ + MEMCPY(ipr->orig_hdr, p->payload, sizeof(*iprh)); + /* For IPV6_FRAG_COPYHEADER there is no need to copy src/dst again, as they + * will be the same as they were. With LWIP_IPV6_SCOPES, the same applies + * to the source/destination zones. */ + } + /* Only after the backup do we get to fill in the actual helper structure. */ + iprh->next_pbuf = next_pbuf; + iprh->start = start; + iprh->end = end; + + /* If this is the last fragment, calculate total packet length. */ + if ((offset & IP6_FRAG_MORE_FLAG) == 0) { + ipr->datagram_len = iprh->end; + } + + /* Additional validity tests: we have received first and last fragment. */ + iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; + if (iprh_tmp->start != 0) { + valid = 0; + } + if (ipr->datagram_len == 0) { + valid = 0; + } + + /* Final validity test: no gaps between current and last fragment. */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while ((q != NULL) && valid) { + iprh = (struct ip6_reass_helper*)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + + if (valid) { + /* All fragments have been received */ + struct ip6_hdr* iphdr_ptr; + + /* chain together the pbufs contained within the ip6_reassdata list. */ + iprh = (struct ip6_reass_helper*) ipr->p->payload; + while (iprh != NULL) { + next_pbuf = iprh->next_pbuf; + if (next_pbuf != NULL) { + /* Save next helper struct (will be hidden in next step). */ + iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload; + + /* hide the fragment header for every succeeding fragment */ + pbuf_remove_header(next_pbuf, IP6_FRAG_HLEN); +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + /* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ + u8_t hdrerr = pbuf_remove_header(next_pbuf, IPV6_FRAG_REQROOM); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } +#endif + pbuf_cat(ipr->p, next_pbuf); + } + else { + iprh_tmp = NULL; + } + + iprh = iprh_tmp; + } + + /* Get the first pbuf. */ + p = ipr->p; + +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + u8_t hdrerr; + /* Restore (only) the bytes that we overwrote beyond the fragment header. + * Those bytes may belong to either the IPv6 header or an extension + * header placed before the fragment header. */ + MEMCPY(p->payload, ipr->orig_hdr, IPV6_FRAG_REQROOM); + /* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */ + hdrerr = pbuf_remove_header(p, IPV6_FRAG_REQROOM); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } +#endif + + /* We need to get rid of the fragment header itself, which is somewhere in + * the middle of the packet (but still in the first pbuf of the chain). + * Getting rid of the header is required by RFC 2460 Sec. 4.5 and necessary + * in order to be able to reassemble packets that are close to full size + * (i.e., around 65535 bytes). We simply move up all the headers before the + * fragment header, including the IPv6 header, and adjust the payload start + * accordingly. This works because all these headers are in the first pbuf + * of the chain, and because the caller adjusts all its pointers on + * successful reassembly. */ + MEMMOVE((u8_t*)ipr->iphdr + sizeof(struct ip6_frag_hdr), ipr->iphdr, + (size_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr)); + + /* This is where the IPv6 header is now. */ + iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->iphdr + + sizeof(struct ip6_frag_hdr)); + + /* Adjust datagram length by adding header lengths. */ + ipr->datagram_len = (u16_t)(ipr->datagram_len + ((u8_t*)p->payload - (u8_t*)iphdr_ptr) + - IP6_HLEN); + + /* Set payload length in ip header. */ + iphdr_ptr->_plen = lwip_htons(ipr->datagram_len); + + /* With the fragment header gone, we now need to adjust the next-header + * field of whatever header was originally before it. Since the packet made + * it through the original header processing routines at least up to the + * fragment header, we do not need any further sanity checks here. */ + if (IP6H_NEXTH(iphdr_ptr) == IP6_NEXTH_FRAGMENT) { + iphdr_ptr->_nexth = ipr->nexth; + } else { + u8_t *ptr = (u8_t *)iphdr_ptr + IP6_HLEN; + while (*ptr != IP6_NEXTH_FRAGMENT) { + ptr += 8 * (1 + ptr[1]); + } + *ptr = ipr->nexth; + } + + /* release the resources allocated for the fragment queue entry */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); + ipr_prev->next = ipr->next; + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* adjust the number of pbufs currently queued for reassembly. */ + clen = pbuf_clen(p); + LWIP_ASSERT("ip6_reass_pbufcount >= clen", ip6_reass_pbufcount >= clen); + ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount - clen); + + /* Move pbuf back to IPv6 header. This should never fail. */ + if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) { + LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); + pbuf_free(p); + return NULL; + } + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + return NULL; + +nullreturn: + IP6_FRAG_STATS_INC(ip6_frag.drop); + pbuf_free(p); + return NULL; +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG + +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip6_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ip6_frag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip6_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * Fragment an IPv6 datagram if too large for the netif or path MTU. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p + * + * @param p ipv6 packet to send + * @param netif the netif on which to send + * @param dest destination ipv6 address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) +{ + struct ip6_hdr *original_ip6hdr; + struct ip6_hdr *ip6hdr; + struct ip6_frag_hdr *frag_hdr; + struct pbuf *rambuf; +#if !LWIP_NETIF_TX_SINGLE_PBUF + struct pbuf *newpbuf; + u16_t newpbuflen = 0; + u16_t left_to_copy; +#endif + static u32_t identification; + u16_t left, cop; + const u16_t mtu = nd6_get_destination_mtu(dest, netif); + const u16_t nfb = (u16_t)((mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK); + u16_t fragment_offset = 0; + u16_t last; + u16_t poff = IP6_HLEN; + + identification++; + + original_ip6hdr = (struct ip6_hdr *)p->payload; + + /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ + LWIP_ASSERT("p->tot_len >= IP6_HLEN", p->tot_len >= IP6_HLEN); + left = (u16_t)(p->tot_len - IP6_HLEN); + + while (left) { + last = (left <= nfb); + + /* Fill this fragment */ + cop = last ? left : nfb; + +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff); + /* make room for the IP header */ + if (pbuf_add_header(rambuf, IP6_HLEN)) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); +#else + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len >= (IP6_HLEN))); + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len = (u16_t)(p->len - poff); + p->tot_len = (u16_t)(p->tot_len - poff); + + left_to_copy = cop; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + pcr = ip6_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip6_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy = (u16_t)(left_to_copy - newpbuflen); + if (left_to_copy) { + p = p->next; + } + } + poff = newpbuflen; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + /* Set headers */ + frag_hdr->_nexth = original_ip6hdr->_nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = lwip_htons((u16_t)((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG))); + frag_hdr->_identification = lwip_htonl(identification); + + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); + IP6H_PLEN_SET(ip6hdr, (u16_t)(cop + IP6_FRAG_HLEN)); + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + IP6_FRAG_STATS_INC(ip6_frag.xmit); + netif->output_ip6(netif, rambuf, dest); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left = (u16_t)(left - cop); + fragment_offset = (u16_t)(fragment_offset + cop); + } + return ERR_OK; +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/mld6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/mld6.c new file mode 100644 index 0000000..a9c917d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/mld6.c @@ -0,0 +1,626 @@ +/** + * @file + * Multicast listener discovery + * + * @defgroup mld6 MLD6 + * @ingroup ip6 + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2.\n + * Note: The allnodes (ff01::1, ff02::1) group is assumed be received by your + * netif since it must always be received for correct IPv6 operation (e.g. SLAAC). + * Ensure the netif filters are configured accordingly!\n + * The netif flags also need NETIF_FLAG_MLD6 flag set to enable MLD6 on a + * netif ("netif->flags |= NETIF_FLAG_MLD6;").\n + * To be called from TCPIP thread. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/* Based on igmp.c implementation of igmp v2 protocol */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mld6.h" +#include "lwip/prot/mld6.h" +#include "lwip/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + + +/* + * MLD constants + */ +#define MLD6_HL 1 +#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) + +#define MLD6_GROUP_NON_MEMBER 0 +#define MLD6_GROUP_DELAYING_MEMBER 1 +#define MLD6_GROUP_IDLE_MEMBER 2 + +/* Forward declarations. */ +static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr); +static err_t mld6_remove_group(struct netif *netif, struct mld_group *group); +static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); +static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type); + + +/** + * Stop MLD processing on interface + * + * @param netif network interface on which stop MLD processing + */ +err_t +mld6_stop(struct netif *netif) +{ + struct mld_group *group = netif_mld6_data(netif); + + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL); + + while (group != NULL) { + struct mld_group *next = group->next; /* avoid use-after-free below */ + + /* disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); + } + + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report MLD memberships for this interface + * + * @param netif network interface on which report MLD memberships + */ +void +mld6_report_groups(struct netif *netif) +{ + struct mld_group *group = netif_mld6_data(netif); + + while (group != NULL) { + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + group = group->next; + } +} + +/** + * Search for a group that is joined on a netif + * + * @param ifp the network interface for which to look + * @param addr the group ipv6 address to search for + * @return a struct mld_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct mld_group * +mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) +{ + struct mld_group *group = netif_mld6_data(ifp); + + while (group != NULL) { + if (ip6_addr_cmp(&(group->group_address), addr)) { + return group; + } + group = group->next; + } + + return NULL; +} + + +/** + * create a new group + * + * @param ifp the network interface for which to create + * @param addr the new group ipv6 + * @return a struct mld_group*, + * NULL on memory error. + */ +static struct mld_group * +mld6_new_group(struct netif *ifp, const ip6_addr_t *addr) +{ + struct mld_group *group; + + group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); + if (group != NULL) { + ip6_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = netif_mld6_data(ifp); + + netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group); + } + + return group; +} + +/** + * Remove a group from the mld_group_list, but do not free it yet + * + * @param group the group to remove + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +mld6_remove_group(struct netif *netif, struct mld_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (netif_mld6_data(netif) == group) { + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next); + } else { + /* look for group further down the list */ + struct mld_group *tmpGroup; + for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not find group */ + if (tmpGroup == NULL) { + err = ERR_ARG; + } + } + + return err; +} + + +/** + * Process an input MLD message. Called by icmp6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +mld6_input(struct pbuf *p, struct netif *inp) +{ + struct mld_header *mld_hdr; + struct mld_group *group; + + MLD6_STATS_INC(mld6.recv); + + /* Check that mld header fits in packet. */ + if (p->len < sizeof(struct mld_header)) { + /* @todo debug message */ + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + MLD6_STATS_INC(mld6.drop); + return; + } + + mld_hdr = (struct mld_header *)p->payload; + + switch (mld_hdr->type) { + case ICMP6_TYPE_MLQ: /* Multicast listener query. */ + /* Is it a general query? */ + if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && + ip6_addr_isany(&(mld_hdr->multicast_address))) { + MLD6_STATS_INC(mld6.rx_general); + /* Report all groups, except all nodes group, and if-local groups. */ + group = netif_mld6_data(inp); + while (group != NULL) { + if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && + (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { + mld6_delayed_report(group, lwip_ntohs(mld_hdr->max_resp_delay)); + } + group = group->next; + } + } else { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_group); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* Schedule a report. */ + mld6_delayed_report(group, lwip_ntohs(mld_hdr->max_resp_delay)); + } + } + break; /* ICMP6_TYPE_MLQ */ + case ICMP6_TYPE_MLR: /* Multicast listener report. */ + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_report); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* If we are waiting to report, cancel it. */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + group->timer = 0; /* stopped */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + } + break; /* ICMP6_TYPE_MLR */ + case ICMP6_TYPE_MLD: /* Multicast listener done. */ + /* Do nothing, router will query us. */ + break; /* ICMP6_TYPE_MLD */ + default: + MLD6_STATS_INC(mld6.proterr); + MLD6_STATS_INC(mld6.drop); + break; + } + + pbuf_free(p); +} + +/** + * @ingroup mld6 + * Join a group on one or all network interfaces. + * + * If the group is to be joined on all interfaces, the given group address must + * not have a zone set (i.e., it must have its zone index set to IP6_NO_ZONE). + * If the group is to be joined on one particular interface, the given group + * address may or may not have a zone set. + * + * @param srcaddr ipv6 address (zoned) of the network interface which should + * join a new group. If IP6_ADDR_ANY6, join on all netifs + * @param groupaddr the ipv6 address of the group to join (possibly but not + * necessarily zoned) + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + + /* loop through netif's */ + NETIF_FOREACH(netif) { + /* Should we join this interface ? */ + if (ip6_addr_isany(srcaddr) || + netif_get_ip6_addr_match(netif, srcaddr) >= 0) { + err = mld6_joingroup_netif(netif, groupaddr); + if (err != ERR_OK) { + return err; + } + } + } + + return err; +} + +/** + * @ingroup mld6 + * Join a group on a network interface. + * + * @param netif the network interface which should join a new group. + * @param groupaddr the ipv6 address of the group to join (possibly but not + * necessarily zoned) + * @return ERR_OK if group was joined on the netif, an err_t otherwise + */ +err_t +mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) +{ + struct mld_group *group; +#if LWIP_IPV6_SCOPES + ip6_addr_t ip6addr; + + /* If the address has a particular scope but no zone set, use the netif to + * set one now. Within the mld6 module, all addresses are properly zoned. */ + if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { + ip6_addr_set(&ip6addr, groupaddr); + ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); + groupaddr = &ip6addr; + } + IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); +#endif /* LWIP_IPV6_SCOPES */ + + LWIP_ASSERT_CORE_LOCKED(); + + /* find group or create a new one if not found */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group == NULL) { + /* Joining a new group. Create a new group entry. */ + group = mld6_new_group(netif, groupaddr); + if (group == NULL) { + return ERR_MEM; + } + + /* Activate this address on the MAC layer. */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); + } + + /* Report our membership. */ + MLD6_STATS_INC(mld6.tx_report); + mld6_send(netif, group, ICMP6_TYPE_MLR); + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + + /* Increment group use */ + group->use++; + return ERR_OK; +} + +/** + * @ingroup mld6 + * Leave a group on a network interface. + * + * Zoning of address follows the same rules as @ref mld6_joingroup. + * + * @param srcaddr ipv6 address (zoned) of the network interface which should + * leave the group. If IP6_ADDR_ANY6, leave on all netifs + * @param groupaddr the ipv6 address of the group to leave (possibly, but not + * necessarily zoned) + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + + /* loop through netif's */ + NETIF_FOREACH(netif) { + /* Should we leave this interface ? */ + if (ip6_addr_isany(srcaddr) || + netif_get_ip6_addr_match(netif, srcaddr) >= 0) { + err_t res = mld6_leavegroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Store this result if we have not yet gotten a success */ + err = res; + } + } + } + + return err; +} + +/** + * @ingroup mld6 + * Leave a group on a network interface. + * + * @param netif the network interface which should leave the group. + * @param groupaddr the ipv6 address of the group to leave (possibly, but not + * necessarily zoned) + * @return ERR_OK if group was left on the netif, an err_t otherwise + */ +err_t +mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) +{ + struct mld_group *group; +#if LWIP_IPV6_SCOPES + ip6_addr_t ip6addr; + + if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { + ip6_addr_set(&ip6addr, groupaddr); + ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); + groupaddr = &ip6addr; + } + IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); +#endif /* LWIP_IPV6_SCOPES */ + + LWIP_ASSERT_CORE_LOCKED(); + + /* find group */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Leave if there is no other use of the group */ + if (group->use <= 1) { + /* Remove the group from the list */ + mld6_remove_group(netif, group); + + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + MLD6_STATS_INC(mld6.tx_leave); + mld6_send(netif, group, ICMP6_TYPE_MLD); + } + + /* Disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); + } + + /* free group struct */ + memp_free(MEMP_MLD6_GROUP, group); + } else { + /* Decrement group use */ + group->use--; + } + + /* Left group */ + return ERR_OK; + } + + /* Group not found */ + return ERR_VAL; +} + + +/** + * Periodic timer for mld processing. Must be called every + * MLD6_TMR_INTERVAL milliseconds (100). + * + * When a delaying member expires, a membership report is sent. + */ +void +mld6_tmr(void) +{ + struct netif *netif; + + NETIF_FOREACH(netif) { + struct mld_group *group = netif_mld6_data(netif); + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + MLD6_STATS_INC(mld6.tx_report); + mld6_send(netif, group, ICMP6_TYPE_MLR); + group->group_state = MLD6_GROUP_IDLE_MEMBER; + } + } + } + group = group->next; + } + } +} + +/** + * Schedule a delayed membership report for a group + * + * @param group the mld_group for which "delaying" membership report + * should be sent + * @param maxresp_in the max resp delay provided in the query + */ +static void +mld6_delayed_report(struct mld_group *group, u16_t maxresp_in) +{ + /* Convert maxresp from milliseconds to tmr ticks */ + u16_t maxresp = maxresp_in / MLD6_TMR_INTERVAL; + if (maxresp == 0) { + maxresp = 1; + } + +#ifdef LWIP_RAND + /* Randomize maxresp. (if LWIP_RAND is supported) */ + maxresp = (u16_t)(LWIP_RAND() % maxresp); + if (maxresp == 0) { + maxresp = 1; + } +#endif /* LWIP_RAND */ + + /* Apply timer value if no report has been scheduled already. */ + if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || + ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + group->timer = maxresp; + group->group_state = MLD6_GROUP_DELAYING_MEMBER; + } +} + +/** + * Send a MLD message (report or done). + * + * An IPv6 hop-by-hop options header with a router alert option + * is prepended. + * + * @param group the group to report or quit + * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) + */ +static void +mld6_send(struct netif *netif, struct mld_group *group, u8_t type) +{ + struct mld_header *mld_hdr; + struct pbuf *p; + const ip6_addr_t *src_addr; + + /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + MLD6_HBH_HLEN, PBUF_RAM); + if (p == NULL) { + MLD6_STATS_INC(mld6.memerr); + return; + } + + /* Move to make room for Hop-by-hop options header. */ + if (pbuf_remove_header(p, MLD6_HBH_HLEN)) { + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + return; + } + + /* Select our source address. */ + if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { + /* This is a special case, when we are performing duplicate address detection. + * We must join the multicast group, but we don't have a valid address yet. */ + src_addr = IP6_ADDR_ANY6; + } else { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(netif, 0); + } + + /* MLD message header pointer. */ + mld_hdr = (struct mld_header *)p->payload; + + /* Set fields. */ + mld_hdr->type = type; + mld_hdr->code = 0; + mld_hdr->chksum = 0; + mld_hdr->max_resp_delay = 0; + mld_hdr->reserved = 0; + ip6_addr_copy_to_packed(mld_hdr->multicast_address, group->group_address); + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, + src_addr, &(group->group_address)); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Add hop-by-hop headers options: router alert with MLD value. */ + ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); + + if (type == ICMP6_TYPE_MLR) { + /* Remember we were the last to report */ + group->last_reporter_flag = 1; + } + + /* Send the packet out. */ + MLD6_STATS_INC(mld6.xmit); + ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), + MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif); + pbuf_free(p); +} + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/nd6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/nd6.c new file mode 100644 index 0000000..81992fa --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/ipv6/nd6.c @@ -0,0 +1,2446 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/nd6.h" +#include "lwip/priv/nd6_priv.h" +#include "lwip/prot/nd6.h" +#include "lwip/prot/icmp6.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/mld6.h" +#include "lwip/dhcp6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" +#include "lwip/dns.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK +#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK +#endif + +/* Router tables. */ +struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; +struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; +struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; +struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; + +/* Default values, can be updated by a RA message. */ +u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; +u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ + +/* Index for cache entries. */ +static u8_t nd6_cached_neighbor_index; +static netif_addr_idx_t nd6_cached_destination_index; + +/* Multicast address holder. */ +static ip6_addr_t multicast_address; + +static u8_t nd6_tmr_rs_reduction; + +/* Static buffer to parse RA packet options */ +union ra_options { + struct lladdr_option lladdr; + struct mtu_option mtu; + struct prefix_option prefix; +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS + struct rdnss_option rdnss; +#endif +}; +static union ra_options nd6_ra_buffer; + +/* Forward declarations. */ +static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr); +static s8_t nd6_new_neighbor_cache_entry(void); +static void nd6_free_neighbor_cache_entry(s8_t i); +static s16_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr); +static s16_t nd6_new_destination_cache_entry(void); +static int nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif); +static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif); +static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif); +static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif); +static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); +static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); +static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); +static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q); + +#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 +#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 +#define ND6_SEND_FLAG_ANY_SRC 0x04 +static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); +static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); +static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags); +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +static err_t nd6_send_rs(struct netif *netif); +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +#if LWIP_ND6_QUEUEING +static void nd6_free_q(struct nd6_q_entry *q); +#else /* LWIP_ND6_QUEUEING */ +#define nd6_free_q(q) pbuf_free(q) +#endif /* LWIP_ND6_QUEUEING */ +static void nd6_send_q(s8_t i); + + +/** + * A local address has been determined to be a duplicate. Take the appropriate + * action(s) on the address and the interface as a whole. + * + * @param netif the netif that owns the address + * @param addr_idx the index of the address detected to be a duplicate + */ +static void +nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx) +{ + + /* Mark the address as duplicate, but leave its lifetimes alone. If this was + * a manually assigned address, it will remain in existence as duplicate, and + * as such be unusable for any practical purposes until manual intervention. + * If this was an autogenerated address, the address will follow normal + * expiration rules, and thus disappear once its valid lifetime expires. */ + netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED); + +#if LWIP_IPV6_AUTOCONFIG + /* If the affected address was the link-local address that we use to generate + * all other addresses, then we should not continue to use those derived + * addresses either, so mark them as duplicate as well. For autoconfig-only + * setups, this will make the interface effectively unusable, approaching the + * intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */ + if (addr_idx == 0) { + s8_t i; + for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && + !netif_ip6_addr_isstatic(netif, i)) { + netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED); + } + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ +} + +#if LWIP_IPV6_AUTOCONFIG +/** + * We received a router advertisement that contains a prefix with the + * autoconfiguration flag set. Add or update an associated autogenerated + * address. + * + * @param netif the netif on which the router advertisement arrived + * @param prefix_opt a pointer to the prefix option data + * @param prefix_addr an aligned copy of the prefix address + */ +static void +nd6_process_autoconfig_prefix(struct netif *netif, + struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr) +{ + ip6_addr_t ip6addr; + u32_t valid_life, pref_life; + u8_t addr_state; + s8_t i, free_idx; + + /* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do + * the rest, starting with checks for (c) and (d) here. */ + valid_life = lwip_htonl(prefix_opt->valid_lifetime); + pref_life = lwip_htonl(prefix_opt->preferred_lifetime); + if (pref_life > valid_life || prefix_opt->prefix_length != 64) { + return; /* silently ignore this prefix for autoconfiguration purposes */ + } + + /* If an autogenerated address already exists for this prefix, update its + * lifetimes. An address is considered autogenerated if 1) it is not static + * (i.e., manually assigned), and 2) there is an advertised autoconfiguration + * prefix for it (the one we are processing here). This does not necessarily + * exclude the possibility that the address was actually assigned by, say, + * DHCPv6. If that distinction becomes important in the future, more state + * must be kept. As explained elsewhere we also update lifetimes of tentative + * and duplicate addresses. Skip address slot 0 (the link-local address). */ + for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + addr_state = netif_ip6_addr_state(netif, i); + if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) && + ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) { + /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e). + * The valid lifetime will never drop to zero as a result of this. */ + u32_t remaining_life = netif_ip6_addr_valid_life(netif, i); + if (valid_life > ND6_2HRS || valid_life > remaining_life) { + netif_ip6_addr_set_valid_life(netif, i, valid_life); + } else if (remaining_life > ND6_2HRS) { + netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS); + } + LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i)); + /* Update the preferred lifetime. No bounds checks are needed here. In + * rare cases the advertisement may un-deprecate the address, though. + * Deprecation is left to the timer code where it is handled anyway. */ + if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) { + netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); + } + netif_ip6_addr_set_pref_life(netif, i, pref_life); + return; /* there should be at most one matching address */ + } + } + + /* No autogenerated address exists for this prefix yet. See if we can add a + * new one. However, if IPv6 autoconfiguration is administratively disabled, + * do not generate new addresses, but do keep updating lifetimes for existing + * addresses. Also, when adding new addresses, we must protect explicitly + * against a valid lifetime of zero, because again, we use that as a special + * value. The generated address would otherwise expire immediately anyway. + * Finally, the original link-local address must be usable at all. We start + * creating addresses even if the link-local address is still in tentative + * state though, and deal with the fallout of that upon DAD collision. */ + addr_state = netif_ip6_addr_state(netif, 0); + if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC || + ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) { + return; + } + + /* Construct the new address that we intend to use, and then see if that + * address really does not exist. It might have been added manually, after + * all. As a side effect, find a free slot. Note that we cannot use + * netif_add_ip6_address() here, as it would return ERR_OK if the address + * already did exist, resulting in that address being given lifetimes. */ + IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1], + netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]); + ip6_addr_assign_zone(&ip6addr, IP6_UNICAST, netif); + + free_idx = 0; + for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { + if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) { + return; /* formed address already exists */ + } + } else if (free_idx == 0) { + free_idx = i; + } + } + if (free_idx == 0) { + return; /* no address slots available, try again on next advertisement */ + } + + /* Assign the new address to the interface. */ + ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr); + netif_ip6_addr_set_valid_life(netif, free_idx, valid_life); + netif_ip6_addr_set_pref_life(netif, free_idx, pref_life); + netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE); +} +#endif /* LWIP_IPV6_AUTOCONFIG */ + +/** + * Process an incoming neighbor discovery message + * + * @param p the nd packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +nd6_input(struct pbuf *p, struct netif *inp) +{ + u8_t msg_type; + s8_t i; + s16_t dest_idx; + + ND6_STATS_INC(nd6.recv); + + msg_type = *((u8_t *)p->payload); + switch (msg_type) { + case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ + { + struct na_header *na_hdr; + struct lladdr_option *lladdr_opt; + ip6_addr_t target_address; + + /* Check that na header fits in packet. */ + if (p->len < (sizeof(struct na_header))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + na_hdr = (struct na_header *)p->payload; + + /* Create an aligned, zoned copy of the target address. */ + ip6_addr_copy_from_packed(target_address, na_hdr->target_address); + ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); + + /* Check a subset of the other RFC 4861 Sec. 7.1.2 requirements. */ + if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || na_hdr->code != 0 || + ip6_addr_ismulticast(&target_address)) { + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* @todo RFC MUST: if IP destination is multicast, Solicited flag is zero */ + /* @todo RFC MUST: all included options have a length greater than zero */ + + /* Unsolicited NA?*/ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* This is an unsolicited NA. + * link-layer changed? + * part of DAD mechanism? */ + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* If the target address matches this netif, it is a DAD response. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && + !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + /* We are using a duplicate address. */ + nd6_duplicate_addr_detected(inp, i); + + pbuf_free(p); + return; + } + } +#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ + + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + 2)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* This is an unsolicited NA, most likely there was a LLADDR change. */ + i = nd6_find_neighbor_cache_entry(&target_address); + if (i >= 0) { + if (na_hdr->flags & ND6_FLAG_OVERRIDE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + } + } else { + /* This is a solicited NA. + * neighbor address resolution response? + * neighbor unreachability detection response? */ + + /* Find the cache entry corresponding to this na. */ + i = nd6_find_neighbor_cache_entry(&target_address); + if (i < 0) { + /* We no longer care about this target address. drop it. */ + pbuf_free(p); + return; + } + + /* Update cache entry. */ + if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || + (neighbor_cache[i].state == ND6_INCOMPLETE)) { + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + 2)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + + neighbor_cache[i].netif = inp; + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; + + /* Send queued packets, if any. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + } + + break; /* ICMP6_TYPE_NA */ + } + case ICMP6_TYPE_NS: /* Neighbor solicitation. */ + { + struct ns_header *ns_hdr; + struct lladdr_option *lladdr_opt; + ip6_addr_t target_address; + u8_t accepted; + + /* Check that ns header fits in packet. */ + if (p->len < sizeof(struct ns_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ns_hdr = (struct ns_header *)p->payload; + + /* Create an aligned, zoned copy of the target address. */ + ip6_addr_copy_from_packed(target_address, ns_hdr->target_address); + ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); + + /* Check a subset of the other RFC 4861 Sec. 7.1.1 requirements. */ + if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ns_hdr->code != 0 || + ip6_addr_ismulticast(&target_address)) { + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* @todo RFC MUST: all included options have a length greater than zero */ + /* @todo RFC MUST: if IP source is 'any', destination is solicited-node multicast address */ + /* @todo RFC MUST: if IP source is 'any', there is no source LL address option */ + + /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ + if (p->len >= (sizeof(struct ns_header) + 2)) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { + lladdr_opt = NULL; + } + } else { + lladdr_opt = NULL; + } + + /* Check if the target address is configured on the receiving netif. */ + accepted = 0; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || + (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && + ip6_addr_isany(ip6_current_src_addr()))) && + ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + accepted = 1; + break; + } + } + + /* NS not for us? */ + if (!accepted) { + pbuf_free(p); + return; + } + + /* Check for ANY address in src (DAD algorithm). */ + if (ip6_addr_isany(ip6_current_src_addr())) { + /* Sender is validating this address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + /* Send a NA back so that the sender does not use this address. */ + nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); + if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { + /* We shouldn't use this address either. */ + nd6_duplicate_addr_detected(inp, i); + } + } + } + } else { + /* Sender is trying to resolve our address. */ + /* Verify that they included their own link-layer address. */ + if (lladdr_opt == NULL) { + /* Not a valid message. */ + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if (i>= 0) { + /* We already have a record for the solicitor. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + + /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } else { + /* Add their IPv6 address and link-layer address to neighbor cache. + * We will need it at least to send a unicast NA message, but most + * likely we will also be communicating with this node soon. */ + i = nd6_new_neighbor_cache_entry(); + if (i < 0) { + /* We couldn't assign a cache entry for this neighbor. + * we won't be able to reply. drop it. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + + /* Send back a NA for us. Allocate the reply pbuf. */ + nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); + } + + break; /* ICMP6_TYPE_NS */ + } + case ICMP6_TYPE_RA: /* Router Advertisement. */ + { + struct ra_header *ra_hdr; + u8_t *buffer; /* Used to copy options. */ + u16_t offset; +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS + /* There can be multiple RDNSS options per RA */ + u8_t rdnss_server_idx = 0; +#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ + + /* Check that RA header fits in packet. */ + if (p->len < sizeof(struct ra_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ra_hdr = (struct ra_header *)p->payload; + + /* Check a subset of the other RFC 4861 Sec. 6.1.2 requirements. */ + if (!ip6_addr_islinklocal(ip6_current_src_addr()) || + IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ra_hdr->code != 0) { + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* @todo RFC MUST: all included options have a length greater than zero */ + + /* If we are sending RS messages, stop. */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* ensure at least one solicitation is sent (see RFC 4861, ch. 6.3.7) */ + if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || + (nd6_send_rs(inp) == ERR_OK)) { + inp->rs_count = 0; + } else { + inp->rs_count = 1; + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + + /* Get the matching default router entry. */ + i = nd6_get_router(ip6_current_src_addr(), inp); + if (i < 0) { + /* Create a new router entry. */ + i = nd6_new_router(ip6_current_src_addr(), inp); + } + + if (i < 0) { + /* Could not create a new router entry. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Re-set invalidation timer. */ + default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime); + + /* Re-set default timer values. */ +#if LWIP_ND6_ALLOW_RA_UPDATES + if (ra_hdr->retrans_timer > 0) { + retrans_timer = lwip_htonl(ra_hdr->retrans_timer); + } + if (ra_hdr->reachable_time > 0) { + reachable_time = lwip_htonl(ra_hdr->reachable_time); + } +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + + /* @todo set default hop limit... */ + /* ra_hdr->current_hop_limit;*/ + + /* Update flags in local entry (incl. preference). */ + default_router_list[i].flags = ra_hdr->flags; + +#if LWIP_IPV6_DHCP6 + /* Trigger DHCPv6 if enabled */ + dhcp6_nd6_ra_trigger(inp, ra_hdr->flags & ND6_RA_FLAG_MANAGED_ADDR_CONFIG, + ra_hdr->flags & ND6_RA_FLAG_OTHER_CONFIG); +#endif + + /* Offset to options. */ + offset = sizeof(struct ra_header); + + /* Process each option. */ + while ((p->tot_len - offset) >= 2) { + u8_t option_type; + u16_t option_len; + int option_len8 = pbuf_try_get_at(p, offset + 1); + if (option_len8 <= 0) { + /* read beyond end or zero length */ + goto lenerr_drop_free_return; + } + option_len = ((u8_t)option_len8) << 3; + if (option_len > p->tot_len - offset) { + /* short packet (option does not fit in) */ + goto lenerr_drop_free_return; + } + if (p->len == p->tot_len) { + /* no need to copy from contiguous pbuf */ + buffer = &((u8_t*)p->payload)[offset]; + } else { + /* check if this option fits into our buffer */ + if (option_len > sizeof(nd6_ra_buffer)) { + option_type = pbuf_get_at(p, offset); + /* invalid option length */ + if (option_type != ND6_OPTION_TYPE_RDNSS) { + goto lenerr_drop_free_return; + } + /* we allow RDNSS option to be longer - we'll just drop some servers */ + option_len = sizeof(nd6_ra_buffer); + } + buffer = (u8_t*)&nd6_ra_buffer; + option_len = pbuf_copy_partial(p, &nd6_ra_buffer, option_len, offset); + } + option_type = buffer[0]; + switch (option_type) { + case ND6_OPTION_TYPE_SOURCE_LLADDR: + { + struct lladdr_option *lladdr_opt; + if (option_len < sizeof(struct lladdr_option)) { + goto lenerr_drop_free_return; + } + lladdr_opt = (struct lladdr_option *)buffer; + if ((default_router_list[i].neighbor_entry != NULL) && + (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { + SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); + default_router_list[i].neighbor_entry->state = ND6_REACHABLE; + default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; + } + break; + } + case ND6_OPTION_TYPE_MTU: + { + struct mtu_option *mtu_opt; + u32_t mtu32; + if (option_len < sizeof(struct mtu_option)) { + goto lenerr_drop_free_return; + } + mtu_opt = (struct mtu_option *)buffer; + mtu32 = lwip_htonl(mtu_opt->mtu); + if ((mtu32 >= IP6_MIN_MTU_LENGTH) && (mtu32 <= 0xffff)) { +#if LWIP_ND6_ALLOW_RA_UPDATES + if (inp->mtu) { + /* don't set the mtu for IPv6 higher than the netif driver supports */ + inp->mtu6 = LWIP_MIN(LWIP_MIN(inp->mtu, inp->mtu6), (u16_t)mtu32); + } else { + inp->mtu6 = (u16_t)mtu32; + } +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + } + break; + } + case ND6_OPTION_TYPE_PREFIX_INFO: + { + struct prefix_option *prefix_opt; + ip6_addr_t prefix_addr; + if (option_len < sizeof(struct prefix_option)) { + goto lenerr_drop_free_return; + } + + prefix_opt = (struct prefix_option *)buffer; + + /* Get a memory-aligned copy of the prefix. */ + ip6_addr_copy_from_packed(prefix_addr, prefix_opt->prefix); + ip6_addr_assign_zone(&prefix_addr, IP6_UNICAST, inp); + + if (!ip6_addr_islinklocal(&prefix_addr)) { + if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) && + (prefix_opt->prefix_length == 64)) { + /* Add to on-link prefix list. */ + u32_t valid_life; + s8_t prefix; + + valid_life = lwip_htonl(prefix_opt->valid_lifetime); + + /* find cache entry for this prefix. */ + prefix = nd6_get_onlink_prefix(&prefix_addr, inp); + if (prefix < 0 && valid_life > 0) { + /* Create a new cache entry. */ + prefix = nd6_new_onlink_prefix(&prefix_addr, inp); + } + if (prefix >= 0) { + prefix_list[prefix].invalidation_timer = valid_life; + } + } +#if LWIP_IPV6_AUTOCONFIG + if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { + /* Perform processing for autoconfiguration. */ + nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr); + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + + break; + } + case ND6_OPTION_TYPE_ROUTE_INFO: + /* @todo implement preferred routes. + struct route_option * route_opt; + route_opt = (struct route_option *)buffer;*/ + + break; +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS + case ND6_OPTION_TYPE_RDNSS: + { + u8_t num, n; + u16_t copy_offset = offset + SIZEOF_RDNSS_OPTION_BASE; + struct rdnss_option * rdnss_opt; + if (option_len < SIZEOF_RDNSS_OPTION_BASE) { + goto lenerr_drop_free_return; + } + + rdnss_opt = (struct rdnss_option *)buffer; + num = (rdnss_opt->length - 1) / 2; + for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++, copy_offset += sizeof(ip6_addr_p_t)) { + ip_addr_t rdnss_address; + + /* Copy directly from pbuf to get an aligned, zoned copy of the prefix. */ + if (pbuf_copy_partial(p, &rdnss_address, sizeof(ip6_addr_p_t), copy_offset) == sizeof(ip6_addr_p_t)) { + IP_SET_TYPE_VAL(rdnss_address, IPADDR_TYPE_V6); + ip6_addr_assign_zone(ip_2_ip6(&rdnss_address), IP6_UNKNOWN, inp); + + if (htonl(rdnss_opt->lifetime) > 0) { + /* TODO implement Lifetime > 0 */ + dns_setserver(rdnss_server_idx++, &rdnss_address); + } else { + /* TODO implement DNS removal in dns.c */ + u8_t s; + for (s = 0; s < DNS_MAX_SERVERS; s++) { + const ip_addr_t *addr = dns_getserver(s); + if(ip_addr_cmp(addr, &rdnss_address)) { + dns_setserver(s, NULL); + } + } + } + } + } + break; + } +#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ + default: + /* Unrecognized option, abort. */ + ND6_STATS_INC(nd6.proterr); + break; + } + /* option length is checked earlier to be non-zero to make sure loop ends */ + offset += 8 * (u8_t)option_len8; + } + + break; /* ICMP6_TYPE_RA */ + } + case ICMP6_TYPE_RD: /* Redirect */ + { + struct redirect_header *redir_hdr; + struct lladdr_option *lladdr_opt; + ip6_addr_t destination_address, target_address; + + /* Check that Redir header fits in packet. */ + if (p->len < sizeof(struct redirect_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + redir_hdr = (struct redirect_header *)p->payload; + + /* Create an aligned, zoned copy of the destination address. */ + ip6_addr_copy_from_packed(destination_address, redir_hdr->destination_address); + ip6_addr_assign_zone(&destination_address, IP6_UNICAST, inp); + + /* Check a subset of the other RFC 4861 Sec. 8.1 requirements. */ + if (!ip6_addr_islinklocal(ip6_current_src_addr()) || + IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || + redir_hdr->code != 0 || ip6_addr_ismulticast(&destination_address)) { + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* @todo RFC MUST: IP source address equals first-hop router for destination_address */ + /* @todo RFC MUST: ICMP target address is either link-local address or same as destination_address */ + /* @todo RFC MUST: all included options have a length greater than zero */ + + if (p->len >= (sizeof(struct redirect_header) + 2)) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); + if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { + lladdr_opt = NULL; + } + } else { + lladdr_opt = NULL; + } + + /* Find dest address in cache */ + dest_idx = nd6_find_destination_cache_entry(&destination_address); + if (dest_idx < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Create an aligned, zoned copy of the target address. */ + ip6_addr_copy_from_packed(target_address, redir_hdr->target_address); + ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); + + /* Set the new target address. */ + ip6_addr_copy(destination_cache[dest_idx].next_hop_addr, target_address); + + /* If Link-layer address of other router is given, try to add to neighbor cache. */ + if (lladdr_opt != NULL) { + if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { + i = nd6_find_neighbor_cache_entry(&target_address); + if (i < 0) { + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_copy(neighbor_cache[i].next_hop_address, target_address); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } + if (i >= 0) { + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } + } + } + break; /* ICMP6_TYPE_RD */ + } + case ICMP6_TYPE_PTB: /* Packet too big */ + { + struct icmp6_hdr *icmp6hdr; /* Packet too big message */ + struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ + u32_t pmtu; + ip6_addr_t destination_address; + + /* Check that ICMPv6 header + IPv6 header fit in payload */ + if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { + /* drop short packets */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); + + /* Create an aligned, zoned copy of the destination address. */ + ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); + ip6_addr_assign_zone(&destination_address, IP6_UNKNOWN, inp); + + /* Look for entry in destination cache. */ + dest_idx = nd6_find_destination_cache_entry(&destination_address); + if (dest_idx < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Change the Path MTU. */ + pmtu = lwip_htonl(icmp6hdr->data); + destination_cache[dest_idx].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); + + break; /* ICMP6_TYPE_PTB */ + } + + default: + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + break; /* default */ + } + + pbuf_free(p); + return; +lenerr_drop_free_return: + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + pbuf_free(p); +} + + +/** + * Periodic timer for Neighbor discovery functions: + * + * - Update neighbor reachability states + * - Update destination cache entries age + * - Update invalidation timers of default routers and on-link prefixes + * - Update lifetimes of our addresses + * - Perform duplicate address detection (DAD) for our addresses + * - Send router solicitations + */ +void +nd6_tmr(void) +{ + s8_t i; + struct netif *netif; + + /* Process neighbor entries. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + switch (neighbor_cache[i].state) { + case ND6_INCOMPLETE: + if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && + (!neighbor_cache[i].isrouter)) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); + } + break; + case ND6_REACHABLE: + /* Send queued packets, if any are left. Should have been sent already. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { + /* Change to stale state. */ + neighbor_cache[i].state = ND6_STALE; + neighbor_cache[i].counter.stale_time = 0; + } else { + neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_STALE: + neighbor_cache[i].counter.stale_time++; + break; + case ND6_DELAY: + if (neighbor_cache[i].counter.delay_time <= 1) { + /* Change to PROBE state. */ + neighbor_cache[i].state = ND6_PROBE; + neighbor_cache[i].counter.probes_sent = 0; + } else { + neighbor_cache[i].counter.delay_time--; + } + break; + case ND6_PROBE: + if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && + (!neighbor_cache[i].isrouter)) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0); + } + break; + case ND6_NO_ENTRY: + default: + /* Do nothing. */ + break; + } + } + + /* Process destination entries. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + destination_cache[i].age++; + } + + /* Process router entries. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (default_router_list[i].neighbor_entry != NULL) { + /* Active entry. */ + if (default_router_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { + /* No more than 1 second remaining. Clear this entry. Also clear any of + * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */ + s8_t j; + for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) { + if (ip6_addr_cmp(&destination_cache[j].next_hop_addr, + &default_router_list[i].neighbor_entry->next_hop_address)) { + ip6_addr_set_any(&destination_cache[j].destination_addr); + } + } + default_router_list[i].neighbor_entry->isrouter = 0; + default_router_list[i].neighbor_entry = NULL; + default_router_list[i].invalidation_timer = 0; + default_router_list[i].flags = 0; + } else { + default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + } + } + + /* Process prefix entries. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].netif != NULL) { + if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { + /* Entry timed out, remove it */ + prefix_list[i].invalidation_timer = 0; + prefix_list[i].netif = NULL; + } else { + prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + } + } + + /* Process our own addresses, updating address lifetimes and/or DAD state. */ + NETIF_FOREACH(netif) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + u8_t addr_state; +#if LWIP_IPV6_ADDRESS_LIFETIMES + /* Step 1: update address lifetimes (valid and preferred). */ + addr_state = netif_ip6_addr_state(netif, i); + /* RFC 4862 is not entirely clear as to whether address lifetimes affect + * tentative addresses, and is even less clear as to what should happen + * with duplicate addresses. We choose to track and update lifetimes for + * both those types, although for different reasons: + * - for tentative addresses, the line of thought of Sec. 5.7 combined + * with the potentially long period that an address may be in tentative + * state (due to the interface being down) suggests that lifetimes + * should be independent of external factors which would include DAD; + * - for duplicate addresses, retiring them early could result in a new + * but unwanted attempt at marking them as valid, while retiring them + * late/never could clog up address slots on the netif. + * As a result, we may end up expiring addresses of either type here. + */ + if (!ip6_addr_isinvalid(addr_state) && + !netif_ip6_addr_isstatic(netif, i)) { + u32_t life = netif_ip6_addr_valid_life(netif, i); + if (life <= ND6_TMR_INTERVAL / 1000) { + /* The address has expired. */ + netif_ip6_addr_set_valid_life(netif, i, 0); + netif_ip6_addr_set_pref_life(netif, i, 0); + netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); + } else { + if (!ip6_addr_life_isinfinite(life)) { + life -= ND6_TMR_INTERVAL / 1000; + LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC); + netif_ip6_addr_set_valid_life(netif, i, life); + } + /* The address is still here. Update the preferred lifetime too. */ + life = netif_ip6_addr_pref_life(netif, i); + if (life <= ND6_TMR_INTERVAL / 1000) { + /* This case must also trigger if 'life' was already zero, so as to + * deal correctly with advertised preferred-lifetime reductions. */ + netif_ip6_addr_set_pref_life(netif, i, 0); + if (addr_state == IP6_ADDR_PREFERRED) + netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED); + } else if (!ip6_addr_life_isinfinite(life)) { + life -= ND6_TMR_INTERVAL / 1000; + netif_ip6_addr_set_pref_life(netif, i, life); + } + } + } + /* The address state may now have changed, so reobtain it next. */ +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ + /* Step 2: update DAD state. */ + addr_state = netif_ip6_addr_state(netif, i); + if (ip6_addr_istentative(addr_state)) { + if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { + /* No NA received in response. Mark address as valid. For dynamic + * addresses with an expired preferred lifetime, the state is set to + * deprecated right away. That should almost never happen, though. */ + addr_state = IP6_ADDR_PREFERRED; +#if LWIP_IPV6_ADDRESS_LIFETIMES + if (!netif_ip6_addr_isstatic(netif, i) && + netif_ip6_addr_pref_life(netif, i) == 0) { + addr_state = IP6_ADDR_DEPRECATED; + } +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ + netif_ip6_addr_set_state(netif, i, addr_state); + } else if (netif_is_up(netif) && netif_is_link_up(netif)) { + /* tentative: set next state by increasing by one */ + netif_ip6_addr_set_state(netif, i, addr_state + 1); + /* Send a NS for this address. Use the unspecified address as source + * address in all cases (RFC 4862 Sec. 5.4.2), not in the least + * because as it is, we only consider multicast replies for DAD. */ + nd6_send_ns(netif, netif_ip6_addr(netif, i), + ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC); + } + } + } + } + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send router solicitation messages, if necessary. */ + if (!nd6_tmr_rs_reduction) { + nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; + NETIF_FOREACH(netif) { + if ((netif->rs_count > 0) && netif_is_up(netif) && + netif_is_link_up(netif) && + !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && + !ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) { + if (nd6_send_rs(netif) == ERR_OK) { + netif->rs_count--; + } + } + } + } else { + nd6_tmr_rs_reduction--; + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +} + +/** Send a neighbor solicitation message for a specific neighbor cache entry + * + * @param entry the neightbor cache entry for wich to send the message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags) +{ + nd6_send_ns(entry->netif, &entry->next_hop_address, flags); +} + +/** + * Send a neighbor solicitation message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) +{ + struct ns_header *ns_hdr; + struct pbuf *p; + const ip6_addr_t *src_addr = NULL; + u16_t lladdr_opt_len; + + LWIP_ASSERT("target address is required", target_addr != NULL); + + if (!(flags & ND6_SEND_FLAG_ANY_SRC)) { + int i; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(target_addr, netif_ip6_addr(netif, i))) { + src_addr = netif_ip6_addr(netif, i); + break; + } + } + + if (i == LWIP_IPV6_NUM_ADDRESSES) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("ICMPv6 NS: no available src address\n")); + ND6_STATS_INC(nd6.err); + return; + } + + /* calculate option length (in 8-byte-blocks) */ + lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; + } else { + src_addr = IP6_ADDR_ANY6; + /* Option "MUST NOT be included when the source IP address is the unspecified address." */ + lladdr_opt_len = 0; + } + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + ns_hdr = (struct ns_header *)p->payload; + + ns_hdr->type = ICMP6_TYPE_NS; + ns_hdr->code = 0; + ns_hdr->chksum = 0; + ns_hdr->reserved = 0; + ip6_addr_copy_to_packed(ns_hdr->target_address, *target_addr); + + if (lladdr_opt_len != 0) { + struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); + target_addr = &multicast_address; + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + target_addr); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, + ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +/** + * Send a neighbor advertisement message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) +{ + struct na_header *na_hdr; + struct lladdr_option *lladdr_opt; + struct pbuf *p; + const ip6_addr_t *src_addr; + const ip6_addr_t *dest_addr; + u16_t lladdr_opt_len; + + LWIP_ASSERT("target address is required", target_addr != NULL); + + /* Use link-local address as source address. */ + /* src_addr = netif_ip6_addr(netif, 0); */ + /* Use target address as source address. */ + src_addr = target_addr; + + /* Allocate a packet. */ + lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + na_hdr->type = ICMP6_TYPE_NA; + na_hdr->code = 0; + na_hdr->chksum = 0; + na_hdr->flags = flags & 0xf0; + na_hdr->reserved[0] = 0; + na_hdr->reserved[1] = 0; + na_hdr->reserved[2] = 0; + ip6_addr_copy_to_packed(na_hdr->target_address, *target_addr); + + lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); + dest_addr = &multicast_address; + } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { + ip6_addr_set_allnodes_linklocal(&multicast_address); + ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); + dest_addr = &multicast_address; + } else { + dest_addr = ip6_current_src_addr(); + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + dest_addr); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, src_addr, dest_addr, + ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +/** + * Send a router solicitation message + * + * @param netif the netif on which to send the message + */ +static err_t +nd6_send_rs(struct netif *netif) +{ + struct rs_header *rs_hdr; + struct lladdr_option *lladdr_opt; + struct pbuf *p; + const ip6_addr_t *src_addr; + err_t err; + u16_t lladdr_opt_len = 0; + + /* Link-local source address, or unspecified address? */ + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { + src_addr = netif_ip6_addr(netif, 0); + } else { + src_addr = IP6_ADDR_ANY6; + } + + /* Generate the all routers target address. */ + ip6_addr_set_allrouters_linklocal(&multicast_address); + ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); + + /* Allocate a packet. */ + if (src_addr != IP6_ADDR_ANY6) { + lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + } + p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return ERR_BUF; + } + + /* Set fields. */ + rs_hdr = (struct rs_header *)p->payload; + + rs_hdr->type = ICMP6_TYPE_RS; + rs_hdr->code = 0; + rs_hdr->chksum = 0; + rs_hdr->reserved = 0; + + if (src_addr != IP6_ADDR_ANY6) { + /* Include our hw address. */ + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + &multicast_address); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + + err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, + ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); + + return err; +} +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +/** + * Search for a neighbor cache entry + * + * @param ip6addr the IPv6 address of the neighbor + * @return The neighbor cache entry index that matched, -1 if no + * entry is found + */ +static s8_t +nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { + return i; + } + } + return -1; +} + +/** + * Create a new neighbor cache entry. + * + * If no unused entry is found, will try to recycle an old entry + * according to ad-hoc "age" heuristic. + * + * @return The neighbor cache entry index that was created, -1 if no + * entry could be created + */ +static s8_t +nd6_new_neighbor_cache_entry(void) +{ + s8_t i; + s8_t j; + u32_t time; + + + /* First, try to find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (neighbor_cache[i].state == ND6_NO_ENTRY) { + return i; + } + } + + /* We need to recycle an entry. in general, do not recycle if it is a router. */ + + /* Next, try to find a Stale entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_STALE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Probe entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_PROBE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Delayed entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_DELAY) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find the oldest reachable entry. */ + time = 0xfffffffful; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_REACHABLE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.reachable_time < time) { + j = i; + time = neighbor_cache[i].counter.reachable_time; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry without queued packets. */ + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ( + (neighbor_cache[i].q == NULL) && + (neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry with queued packets. */ + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* No more entries to try. */ + return -1; +} + +/** + * Will free any resources associated with a neighbor cache + * entry, and will mark it as unused. + * + * @param i the neighbor cache entry index to free + */ +static void +nd6_free_neighbor_cache_entry(s8_t i) +{ + if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { + return; + } + if (neighbor_cache[i].isrouter) { + /* isrouter needs to be cleared before deleting a neighbor cache entry */ + return; + } + + /* Free any queued packets. */ + if (neighbor_cache[i].q != NULL) { + nd6_free_q(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } + + neighbor_cache[i].state = ND6_NO_ENTRY; + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = NULL; + neighbor_cache[i].counter.reachable_time = 0; + ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); +} + +/** + * Search for a destination cache entry + * + * @param ip6addr the IPv6 address of the destination + * @return The destination cache entry index that matched, -1 if no + * entry is found + */ +static s16_t +nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) +{ + s16_t i; + + IP6_ADDR_ZONECHECK(ip6addr); + + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { + return i; + } + } + return -1; +} + +/** + * Create a new destination cache entry. If no unused entry is found, + * will recycle oldest entry. + * + * @return The destination cache entry index that was created, -1 if no + * entry was created + */ +static s16_t +nd6_new_destination_cache_entry(void) +{ + s16_t i, j; + u32_t age; + + /* Find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { + return i; + } + } + + /* Find oldest entry. */ + age = 0; + j = LWIP_ND6_NUM_DESTINATIONS - 1; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (destination_cache[i].age > age) { + j = i; + } + } + + return j; +} + +/** + * Clear the destination cache. + * + * This operation may be necessary for consistency in the light of changing + * local addresses and/or use of the gateway hook. + */ +void +nd6_clear_destination_cache(void) +{ + int i; + + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + ip6_addr_set_any(&destination_cache[i].destination_addr); + } +} + +/** + * Determine whether an address matches an on-link prefix or the subnet of a + * statically assigned address. + * + * @param ip6addr the IPv6 address to match + * @return 1 if the address is on-link, 0 otherwise + */ +static int +nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) +{ + s8_t i; + + /* Check to see if the address matches an on-link prefix. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if ((prefix_list[i].netif == netif) && + (prefix_list[i].invalidation_timer > 0) && + ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { + return 1; + } + } + /* Check to see if address prefix matches a manually configured (= static) + * address. Static addresses have an implied /64 subnet assignment. Dynamic + * addresses (from autoconfiguration) have no implied subnet assignment, and + * are thus effectively /128 assignments. See RFC 5942 for more on this. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + netif_ip6_addr_isstatic(netif, i) && + ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { + return 1; + } + } + return 0; +} + +/** + * Select a default router for a destination. + * + * This function is used both for routing and for finding a next-hop target for + * a packet. In the former case, the given netif is NULL, and the returned + * router entry must be for a netif suitable for sending packets (up, link up). + * In the latter case, the given netif is not NULL and restricts router choice. + * + * @param ip6addr the destination address + * @param netif the netif for the outgoing packet, if known + * @return the default router entry index, or -1 if no suitable + * router is found + */ +static s8_t +nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) +{ + struct netif *router_netif; + s8_t i, j, valid_router; + static s8_t last_router; + + LWIP_UNUSED_ARG(ip6addr); /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ + + /* @todo: implement default router preference */ + + /* Look for valid routers. A reachable router is preferred. */ + valid_router = -1; + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + /* Is the router netif both set and apppropriate? */ + if (default_router_list[i].neighbor_entry != NULL) { + router_netif = default_router_list[i].neighbor_entry->netif; + if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : + (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { + /* Is the router valid, i.e., reachable or probably reachable as per + * RFC 4861 Sec. 6.3.6? Note that we will never return a router that + * has no neighbor cache entry, due to the netif association tests. */ + if (default_router_list[i].neighbor_entry->state != ND6_INCOMPLETE) { + /* Is the router known to be reachable? */ + if (default_router_list[i].neighbor_entry->state == ND6_REACHABLE) { + return i; /* valid and reachable - done! */ + } else if (valid_router < 0) { + valid_router = i; /* valid but not known to be reachable */ + } + } + } + } + } + if (valid_router >= 0) { + return valid_router; + } + + /* Look for any router for which we have any information at all. */ + /* last_router is used for round-robin selection of incomplete routers, as + * recommended in RFC 4861 Sec. 6.3.6 point (2). Advance only when picking a + * route, to select the same router as next-hop target in the common case. */ + if ((netif == NULL) && (++last_router >= LWIP_ND6_NUM_ROUTERS)) { + last_router = 0; + } + i = last_router; + for (j = 0; j < LWIP_ND6_NUM_ROUTERS; j++) { + if (default_router_list[i].neighbor_entry != NULL) { + router_netif = default_router_list[i].neighbor_entry->netif; + if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : + (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { + return i; + } + } + if (++i >= LWIP_ND6_NUM_ROUTERS) { + i = 0; + } + } + + /* no suitable router found. */ + return -1; +} + +/** + * Find a router-announced route to the given destination. This route may be + * based on an on-link prefix or a default router. + * + * If a suitable route is found, the returned netif is guaranteed to be in a + * suitable state (up, link up) to be used for packet transmission. + * + * @param ip6addr the destination IPv6 address + * @return the netif to use for the destination, or NULL if none found + */ +struct netif * +nd6_find_route(const ip6_addr_t *ip6addr) +{ + struct netif *netif; + s8_t i; + + /* @todo decide if it makes sense to check the destination cache first */ + + /* Check if there is a matching on-link prefix. There may be multiple + * matches. Pick the first one that is associated with a suitable netif. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + netif = prefix_list[i].netif; + if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) && + netif_is_up(netif) && netif_is_link_up(netif)) { + return netif; + } + } + + /* No on-link prefix match. Find a router that can forward the packet. */ + i = nd6_select_router(ip6addr, NULL); + if (i >= 0) { + LWIP_ASSERT("selected router must have a neighbor entry", + default_router_list[i].neighbor_entry != NULL); + return default_router_list[i].neighbor_entry->netif; + } + + return NULL; +} + +/** + * Find an entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is found, if known + * @return the index of the router entry, or -1 if not found + */ +static s8_t +nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) +{ + s8_t i; + + IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); + + /* Look for router. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if ((default_router_list[i].neighbor_entry != NULL) && + ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && + ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { + return i; + } + } + + /* router not found. */ + return -1; +} + +/** + * Create a new entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is connected, if known + * @return the index on the router table, or -1 if could not be created + */ +static s8_t +nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) +{ + s8_t router_index; + s8_t free_router_index; + s8_t neighbor_index; + + IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); + + /* Do we have a neighbor entry for this router? */ + neighbor_index = nd6_find_neighbor_cache_entry(router_addr); + if (neighbor_index < 0) { + /* Create a neighbor entry for this router. */ + neighbor_index = nd6_new_neighbor_cache_entry(); + if (neighbor_index < 0) { + /* Could not create neighbor entry for this router. */ + return -1; + } + ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); + neighbor_cache[neighbor_index].netif = netif; + neighbor_cache[neighbor_index].q = NULL; + neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; + neighbor_cache[neighbor_index].counter.probes_sent = 1; + nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST); + } + + /* Mark neighbor as router. */ + neighbor_cache[neighbor_index].isrouter = 1; + + /* Look for empty entry. */ + free_router_index = LWIP_ND6_NUM_ROUTERS; + for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { + /* check if router already exists (this is a special case for 2 netifs on the same subnet + - e.g. wifi and cable) */ + if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ + return router_index; + } + if (default_router_list[router_index].neighbor_entry == NULL) { + /* remember lowest free index to create a new entry */ + free_router_index = router_index; + } + } + if (free_router_index < LWIP_ND6_NUM_ROUTERS) { + default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); + return free_router_index; + } + + /* Could not create a router entry. */ + + /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ + neighbor_cache[neighbor_index].isrouter = 0; + + /* router not found. */ + return -1; +} + +/** + * Find the cached entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not found + */ +static s8_t +nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) +{ + s8_t i; + + /* Look for prefix in list. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && + (prefix_list[i].netif == netif)) { + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Creates a new entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not created + */ +static s8_t +nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) +{ + s8_t i; + + /* Create new entry. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((prefix_list[i].netif == NULL) || + (prefix_list[i].invalidation_timer == 0)) { + /* Found empty prefix entry. */ + prefix_list[i].netif = netif; + ip6_addr_set(&(prefix_list[i].prefix), prefix); + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Determine the next hop for a destination. Will determine if the + * destination is on-link, else a suitable on-link router is selected. + * + * The last entry index is cached for fast entry search. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the neighbor cache entry for the next hop, ERR_RTE if no + * suitable next hop was found, ERR_MEM if no cache entry + * could be created + */ +static s8_t +nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) +{ +#ifdef LWIP_HOOK_ND6_GET_GW + const ip6_addr_t *next_hop_addr; +#endif /* LWIP_HOOK_ND6_GET_GW */ + s8_t i; + s16_t dst_idx; + + IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); + +#if LWIP_NETIF_HWADDRHINT + if (netif->hints != NULL) { + /* per-pcb cached entry was given */ + netif_addr_idx_t addr_hint = netif->hints->addr_hint; + if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { + nd6_cached_destination_index = addr_hint; + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look for ip6addr in destination cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + /* the cached entry index is the right one! */ + /* do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + /* Search destination cache. */ + dst_idx = nd6_find_destination_cache_entry(ip6addr); + if (dst_idx >= 0) { + /* found destination entry. make it our new cached index. */ + LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); + nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; + } else { + /* Not found. Create a new destination entry. */ + dst_idx = nd6_new_destination_cache_entry(); + if (dst_idx >= 0) { + /* got new destination entry. make it our new cached index. */ + LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); + nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; + } else { + /* Could not create a destination cache entry. */ + return ERR_MEM; + } + + /* Copy dest address to destination cache. */ + ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); + + /* Now find the next hop. is it a neighbor? */ + if (ip6_addr_islinklocal(ip6addr) || + nd6_is_prefix_in_netif(ip6addr, netif)) { + /* Destination in local link. */ + destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); +#ifdef LWIP_HOOK_ND6_GET_GW + } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { + /* Next hop for destination provided by hook function. */ + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; + ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); +#endif /* LWIP_HOOK_ND6_GET_GW */ + } else { + /* We need to select a router. */ + i = nd6_select_router(ip6addr, netif); + if (i < 0) { + /* No router found. */ + ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); + return ERR_RTE; + } + destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); + } + } + } + +#if LWIP_NETIF_HWADDRHINT + if (netif->hints != NULL) { + /* per-pcb cached entry was given */ + netif->hints->addr_hint = nd6_cached_destination_index; + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look in neighbor cache for the next-hop address. */ + if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), + &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + /* Cache hit. */ + /* Do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); + if (i >= 0) { + /* Found a matching record, make it new cached entry. */ + nd6_cached_neighbor_index = i; + } else { + /* Neighbor not in cache. Make a new entry. */ + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + /* got new neighbor entry. make it our new cached index. */ + nd6_cached_neighbor_index = i; + } else { + /* Could not create a neighbor cache entry. */ + return ERR_MEM; + } + + /* Initialize fields. */ + ip6_addr_copy(neighbor_cache[i].next_hop_address, + destination_cache[nd6_cached_destination_index].next_hop_addr); + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = netif; + neighbor_cache[i].state = ND6_INCOMPLETE; + neighbor_cache[i].counter.probes_sent = 1; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); + } + } + + /* Reset this destination's age. */ + destination_cache[nd6_cached_destination_index].age = 0; + + return nd6_cached_neighbor_index; +} + +/** + * Queue a packet for a neighbor. + * + * @param neighbor_index the index in the neighbor cache table + * @param q packet to be queued + * @return ERR_OK if succeeded, ERR_MEM if out of memory + */ +static err_t +nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) +{ + err_t result = ERR_MEM; + struct pbuf *p; + int copy_needed = 0; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *new_entry, *r; +#endif /* LWIP_ND6_QUEUEING */ + + if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { + return ERR_ARG; + } + + /* IF q includes a pbuf that must be copied, we have to copy the whole chain + * into a new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ + p = q; + while (p) { + if (PBUF_NEEDS_COPY(p)) { + copy_needed = 1; + break; + } + p = p->next; + } + if (copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); + while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ +#if LWIP_ND6_QUEUEING + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); +#else /* LWIP_ND6_QUEUEING */ + pbuf_free(neighbor_cache[neighbor_index].q); + neighbor_cache[neighbor_index].q = NULL; +#endif /* LWIP_ND6_QUEUEING */ + p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet was copied/ref'd? */ + if (p != NULL) { + /* queue packet ... */ +#if LWIP_ND6_QUEUEING + /* allocate a new nd6 queue entry */ + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + } + if (new_entry != NULL) { + new_entry->next = NULL; + new_entry->p = p; + if (neighbor_cache[neighbor_index].q != NULL) { + /* queue was already existent, append the new entry to the end */ + r = neighbor_cache[neighbor_index].q; + while (r->next != NULL) { + r = r->next; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + neighbor_cache[neighbor_index].q = new_entry; + } + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; + } else { + /* the pool MEMP_ND6_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); + /* { result == ERR_MEM } through initialization */ + } +#else /* LWIP_ND6_QUEUEING */ + /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ + if (neighbor_cache[neighbor_index].q != NULL) { + pbuf_free(neighbor_cache[neighbor_index].q); + } + neighbor_cache[neighbor_index].q = p; + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; +#endif /* LWIP_ND6_QUEUEING */ + } else { + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } + + return result; +} + +#if LWIP_ND6_QUEUEING +/** + * Free a complete queue of nd6 q entries + * + * @param q a queue of nd6_q_entry to free + */ +static void +nd6_free_q(struct nd6_q_entry *q) +{ + struct nd6_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ND6_QUEUE, r); + } +} +#endif /* LWIP_ND6_QUEUEING */ + +/** + * Send queued packets for a neighbor + * + * @param i the neighbor to send packets to + */ +static void +nd6_send_q(s8_t i) +{ + struct ip6_hdr *ip6hdr; + ip6_addr_t dest; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *q; +#endif /* LWIP_ND6_QUEUEING */ + + if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { + return; + } + +#if LWIP_ND6_QUEUEING + while (neighbor_cache[i].q != NULL) { + /* remember first in queue */ + q = neighbor_cache[i].q; + /* pop first item off the queue */ + neighbor_cache[i].q = q->next; + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(q->p->payload); + /* Create an aligned copy. */ + ip6_addr_copy_from_packed(dest, ip6hdr->dest); + /* Restore the zone, if applicable. */ + ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest); + /* free the queued IP packet */ + pbuf_free(q->p); + /* now queue entry can be freed */ + memp_free(MEMP_ND6_QUEUE, q); + } +#else /* LWIP_ND6_QUEUEING */ + if (neighbor_cache[i].q != NULL) { + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); + /* Create an aligned copy. */ + ip6_addr_copy_from_packed(dest, ip6hdr->dest); + /* Restore the zone, if applicable. */ + ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest); + /* free the queued IP packet */ + pbuf_free(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } +#endif /* LWIP_ND6_QUEUEING */ +} + +/** + * A packet is to be transmitted to a specific IPv6 destination on a specific + * interface. Check if we can find the hardware address of the next hop to use + * for the packet. If so, give the hardware address to the caller, which should + * use it to send the packet right away. Otherwise, enqueue the packet for + * later transmission while looking up the hardware address, if possible. + * + * As such, this function returns one of three different possible results: + * + * - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now. + * - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later. + * - not ERR_OK: something went wrong; forward the error upward in the stack. + * + * @param netif The lwIP network interface on which the IP packet will be sent. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The destination IPv6 address of the packet. + * @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning + * the packet has been queued). + * @return + * - ERR_OK on success, ERR_RTE if no route was found for the packet, + * or ERR_MEM if low memory conditions prohibit sending the packet at all. + */ +err_t +nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) +{ + s8_t i; + + /* Get next hop record. */ + i = nd6_get_next_hop_entry(ip6addr, netif); + if (i < 0) { + /* failed to get a next hop neighbor record. */ + return i; + } + + /* Now that we have a destination record, send or queue the packet. */ + if (neighbor_cache[i].state == ND6_STALE) { + /* Switch to delay state. */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ + if ((neighbor_cache[i].state == ND6_REACHABLE) || + (neighbor_cache[i].state == ND6_DELAY) || + (neighbor_cache[i].state == ND6_PROBE)) { + + /* Tell the caller to send out the packet now. */ + *hwaddrp = neighbor_cache[i].lladdr; + return ERR_OK; + } + + /* We should queue packet on this interface. */ + *hwaddrp = NULL; + return nd6_queue_packet(i, q); +} + + +/** + * Get the Path MTU for a destination. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the Path MTU, if known, or the netif default MTU + */ +u16_t +nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif) +{ + s16_t i; + + i = nd6_find_destination_cache_entry(ip6addr); + if (i >= 0) { + if (destination_cache[i].pmtu > 0) { + return destination_cache[i].pmtu; + } + } + + if (netif != NULL) { + return netif_mtu6(netif); + } + + return IP6_MIN_MTU_LENGTH; /* Minimum MTU */ +} + + +#if LWIP_ND6_TCP_REACHABILITY_HINTS +/** + * Provide the Neighbor discovery process with a hint that a + * destination is reachable. Called by tcp_receive when ACKs are + * received or sent (as per RFC). This is useful to avoid sending + * NS messages every 30 seconds. + * + * @param ip6addr the destination address which is know to be reachable + * by an upper layer protocol (TCP) + */ +void +nd6_reachability_hint(const ip6_addr_t *ip6addr) +{ + s8_t i; + s16_t dst_idx; + + /* Find destination in cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + dst_idx = nd6_cached_destination_index; + ND6_STATS_INC(nd6.cachehit); + } else { + dst_idx = nd6_find_destination_cache_entry(ip6addr); + } + if (dst_idx < 0) { + return; + } + + /* Find next hop neighbor in cache. */ + if (ip6_addr_cmp(&(destination_cache[dst_idx].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + i = nd6_cached_neighbor_index; + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[dst_idx].next_hop_addr)); + } + if (i < 0) { + return; + } + + /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { + return; + } + + /* Set reachability state. */ + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; +} +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +/** + * Remove all prefix, neighbor_cache and router entries of the specified netif. + * + * @param netif points to a network interface + */ +void +nd6_cleanup_netif(struct netif *netif) +{ + u8_t i; + s8_t router_index; + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].netif == netif) { + prefix_list[i].netif = NULL; + } + } + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (neighbor_cache[i].netif == netif) { + for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { + if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { + default_router_list[router_index].neighbor_entry = NULL; + default_router_list[router_index].flags = 0; + } + } + neighbor_cache[i].isrouter = 0; + nd6_free_neighbor_cache_entry(i); + } + } + /* Clear the destination cache, since many entries may now have become + * invalid for one of several reasons. As destination cache entries have no + * netif association, use a sledgehammer approach (this can be improved). */ + nd6_clear_destination_cache(); +} + +#if LWIP_IPV6_MLD +/** + * The state of a local IPv6 address entry is about to change. If needed, join + * or leave the solicited-node multicast group for the address. + * + * @param netif The netif that owns the address. + * @param addr_idx The index of the address. + * @param new_state The new (IP6_ADDR_) state for the address. + */ +void +nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) +{ + u8_t old_state, old_member, new_member; + + old_state = netif_ip6_addr_state(netif, addr_idx); + + /* Determine whether we were, and should be, a member of the solicited-node + * multicast group for this address. For tentative addresses, the group is + * not joined until the address enters the TENTATIVE_1 (or VALID) state. */ + old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE); + new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE); + + if (old_member != new_member) { + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); + ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); + + if (new_member) { + mld6_joingroup_netif(netif, &multicast_address); + } else { + mld6_leavegroup_netif(netif, &multicast_address); + } + } +} +#endif /* LWIP_IPV6_MLD */ + +/** Netif was added, set up, or reconnected (link up) */ +void +nd6_restart_netif(struct netif *netif) +{ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send Router Solicitation messages (see RFC 4861, ch. 6.3.7). */ + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +} + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/mem.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/mem.c new file mode 100644 index 0000000..315fb3c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/mem.c @@ -0,0 +1,1017 @@ +/** + * @file + * Dynamic memory manager + * + * This is a lightweight replacement for the standard C library malloc(). + * + * If you want to use the standard C library malloc() instead, define + * MEM_LIBC_MALLOC to 1 in your lwipopts.h + * + * To let mem_malloc() use pools (prevents fragmentation and is much faster than + * a heap but might waste some memory), define MEM_USE_POOLS to 1, define + * MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list + * of pools like this (more pools can be added between _START and _END): + * + * Define three pools with sizes 256, 512, and 1512 bytes + * LWIP_MALLOC_MEMPOOL_START + * LWIP_MALLOC_MEMPOOL(20, 256) + * LWIP_MALLOC_MEMPOOL(10, 512) + * LWIP_MALLOC_MEMPOOL(5, 1512) + * LWIP_MALLOC_MEMPOOL_END + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/mem.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/err.h" + +#include + +#if MEM_LIBC_MALLOC +#include /* for malloc()/free() */ +#endif + +/* This is overridable for tests only... */ +#ifndef LWIP_MEM_ILLEGAL_FREE +#define LWIP_MEM_ILLEGAL_FREE(msg) LWIP_ASSERT(msg, 0) +#endif + +#define MEM_STATS_INC_LOCKED(x) SYS_ARCH_LOCKED(MEM_STATS_INC(x)) +#define MEM_STATS_INC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_INC_USED(x, y)) +#define MEM_STATS_DEC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_DEC_USED(x, y)) + +#if MEM_OVERFLOW_CHECK +#define MEM_SANITY_OFFSET MEM_SANITY_REGION_BEFORE_ALIGNED +#define MEM_SANITY_OVERHEAD (MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED) +#else +#define MEM_SANITY_OFFSET 0 +#define MEM_SANITY_OVERHEAD 0 +#endif + +#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK +/** + * Check if a mep element was victim of an overflow or underflow + * (e.g. the restricted area after/before it has been altered) + * + * @param p the mem element to check + * @param size allocated size of the element + * @param descr1 description of the element source shown on error + * @param descr2 description of the element source shown on error + */ +void +mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2) +{ +#if MEM_SANITY_REGION_AFTER_ALIGNED || MEM_SANITY_REGION_BEFORE_ALIGNED + u16_t k; + u8_t *m; + +#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t *)p + size; + for (k = 0; k < MEM_SANITY_REGION_AFTER_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128]; + snprintf(errstr, sizeof(errstr), "detected mem overflow in %s%s", descr1, descr2); + LWIP_ASSERT(errstr, 0); + } + } +#endif /* MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ + +#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; + for (k = 0; k < MEM_SANITY_REGION_BEFORE_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128]; + snprintf(errstr, sizeof(errstr), "detected mem underflow in %s%s", descr1, descr2); + LWIP_ASSERT(errstr, 0); + } + } +#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 */ +#else + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(desc); + LWIP_UNUSED_ARG(descr); +#endif +} + +/** + * Initialize the restricted area of a mem element. + */ +void +mem_overflow_init_raw(void *p, size_t size) +{ +#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 + u8_t *m; +#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; + memset(m, 0xcd, MEM_SANITY_REGION_BEFORE_ALIGNED); +#endif +#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t *)p + size; + memset(m, 0xcd, MEM_SANITY_REGION_AFTER_ALIGNED); +#endif +#else /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(desc); +#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ +} +#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ + +#if MEM_LIBC_MALLOC || MEM_USE_POOLS + +/** mem_init is not used when using pools instead of a heap or using + * C library malloc(). + */ +void +mem_init(void) +{ +} + +/** mem_trim is not used when using pools instead of a heap or using + * C library malloc(): we can't free part of a pool element and the stack + * support mem_trim() to return a different pointer + */ +void * +mem_trim(void *mem, mem_size_t size) +{ + LWIP_UNUSED_ARG(size); + return mem; +} +#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ + +#if MEM_LIBC_MALLOC +/* lwIP heap implemented using C library malloc() */ + +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_clib_free +#define mem_clib_free free +#endif +#ifndef mem_clib_malloc +#define mem_clib_malloc malloc +#endif +#ifndef mem_clib_calloc +#define mem_clib_calloc calloc +#endif + +#if LWIP_STATS && MEM_STATS +#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) +#else +#define MEM_LIBC_STATSHELPER_SIZE 0 +#endif + +/** + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size) +{ + void *ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); + if (ret == NULL) { + MEM_STATS_INC_LOCKED(err); + } else { + LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); +#if LWIP_STATS && MEM_STATS + *(mem_size_t *)ret = size; + ret = (u8_t *)ret + MEM_LIBC_STATSHELPER_SIZE; + MEM_STATS_INC_USED_LOCKED(used, size); +#endif + } + return ret; +} + +/** Put memory back on the heap + * + * @param rmem is the pointer as returned by a previous call to mem_malloc() + */ +void +mem_free(void *rmem) +{ + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); +#if LWIP_STATS && MEM_STATS + rmem = (u8_t *)rmem - MEM_LIBC_STATSHELPER_SIZE; + MEM_STATS_DEC_USED_LOCKED(used, *(mem_size_t *)rmem); +#endif + mem_clib_free(rmem); +} + +#elif MEM_USE_POOLS + +/* lwIP heap implemented with different sized pools */ + +/** + * Allocate memory: determine the smallest pool that is big enough + * to contain an element of 'size' and get an element from that pool. + * + * @param size the size in bytes of the memory needed + * @return a pointer to the allocated memory or NULL if the pool is empty + */ +void * +mem_malloc(mem_size_t size) +{ + void *ret; + struct memp_malloc_helper *element = NULL; + memp_t poolnr; + mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + + for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { + /* is this pool big enough to hold an element of the required size + plus a struct memp_malloc_helper that saves the pool this element came from? */ + if (required_size <= memp_pools[poolnr]->size) { + element = (struct memp_malloc_helper *)memp_malloc(poolnr); + if (element == NULL) { + /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ +#if MEM_USE_POOLS_TRY_BIGGER_POOL + /** Try a bigger pool if this one is empty! */ + if (poolnr < MEMP_POOL_LAST) { + continue; + } +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ + MEM_STATS_INC_LOCKED(err); + return NULL; + } + break; + } + } + if (poolnr > MEMP_POOL_LAST) { + LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); + MEM_STATS_INC_LOCKED(err); + return NULL; + } + + /* save the pool number this element came from */ + element->poolnr = poolnr; + /* and return a pointer to the memory directly after the struct memp_malloc_helper */ + ret = (u8_t *)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + +#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) + /* truncating to u16_t is safe because struct memp_desc::size is u16_t */ + element->size = (u16_t)size; + MEM_STATS_INC_USED_LOCKED(used, element->size); +#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ +#if MEMP_OVERFLOW_CHECK + /* initialize unused memory (diff between requested size and selected pool's size) */ + memset((u8_t *)ret + size, 0xcd, memp_pools[poolnr]->size - size); +#endif /* MEMP_OVERFLOW_CHECK */ + return ret; +} + +/** + * Free memory previously allocated by mem_malloc. Loads the pool number + * and calls memp_free with that pool number to put the element back into + * its pool + * + * @param rmem the memory element to free + */ +void +mem_free(void *rmem) +{ + struct memp_malloc_helper *hmem; + + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); + + /* get the original struct memp_malloc_helper */ + /* cast through void* to get rid of alignment warnings */ + hmem = (struct memp_malloc_helper *)(void *)((u8_t *)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); + + LWIP_ASSERT("hmem != NULL", (hmem != NULL)); + LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); + LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); + + MEM_STATS_DEC_USED_LOCKED(used, hmem->size); +#if MEMP_OVERFLOW_CHECK + { + u16_t i; + LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", + hmem->size <= memp_pools[hmem->poolnr]->size); + /* check that unused memory remained untouched (diff between requested size and selected pool's size) */ + for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) { + u8_t data = *((u8_t *)rmem + i); + LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); + } + } +#endif /* MEMP_OVERFLOW_CHECK */ + + /* and put it in the pool we saved earlier */ + memp_free(hmem->poolnr, hmem); +} + +#else /* MEM_USE_POOLS */ +/* lwIP replacement for your libc malloc() */ + +/** + * The heap is made up as a list of structs of this type. + * This does not have to be aligned since for getting its size, + * we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns. + */ +struct mem { + /** index (-> ram[next]) of the next struct */ + mem_size_t next; + /** index (-> ram[prev]) of the previous struct */ + mem_size_t prev; + /** 1: this area is used; 0: this area is unused */ + u8_t used; +#if MEM_OVERFLOW_CHECK + /** this keeps track of the user allocation size for guard checks */ + mem_size_t user_size; +#endif +}; + +/** All allocated blocks will be MIN_SIZE bytes big, at least! + * MIN_SIZE can be overridden to suit your needs. Smaller values save space, + * larger values could prevent too small blocks to fragment the RAM too much. */ +#ifndef MIN_SIZE +#define MIN_SIZE 12 +#endif /* MIN_SIZE */ +/* some alignment macros: we define them here for better source code layout */ +#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) +#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) +#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) + +/** If you want to relocate the heap to external memory, simply define + * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. + * If so, make sure the memory at that location is big enough (see below on + * how that space is calculated). */ +#ifndef LWIP_RAM_HEAP_POINTER +/** the heap. we need one struct mem at the end and some room for alignment */ +LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM)); +#define LWIP_RAM_HEAP_POINTER ram_heap +#endif /* LWIP_RAM_HEAP_POINTER */ + +/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ +static u8_t *ram; +/** the last entry, always unused! */ +static struct mem *ram_end; + +/** concurrent access protection */ +#if !NO_SYS +static sys_mutex_t mem_mutex; +#endif + +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + +static volatile u8_t mem_free_count; + +/* Allow mem_free from other (e.g. interrupt) context */ +#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) +#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) +#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) +#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) +#define LWIP_MEM_LFREE_VOLATILE volatile + +#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/* Protect the heap only by using a mutex */ +#define LWIP_MEM_FREE_DECL_PROTECT() +#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) +#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) +/* mem_malloc is protected using mutex AND LWIP_MEM_ALLOC_PROTECT */ +#define LWIP_MEM_ALLOC_DECL_PROTECT() +#define LWIP_MEM_ALLOC_PROTECT() +#define LWIP_MEM_ALLOC_UNPROTECT() +#define LWIP_MEM_LFREE_VOLATILE + +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/** pointer to the lowest free block, this is used for faster search */ +static struct mem * LWIP_MEM_LFREE_VOLATILE lfree; + +#if MEM_SANITY_CHECK +static void mem_sanity(void); +#define MEM_SANITY() mem_sanity() +#else +#define MEM_SANITY() +#endif + +#if MEM_OVERFLOW_CHECK +static void +mem_overflow_init_element(struct mem *mem, mem_size_t user_size) +{ + void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; + mem->user_size = user_size; + mem_overflow_init_raw(p, user_size); +} + +static void +mem_overflow_check_element(struct mem *mem) +{ + void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; + mem_overflow_check_raw(p, mem->user_size, "heap", ""); +} +#else /* MEM_OVERFLOW_CHECK */ +#define mem_overflow_init_element(mem, size) +#define mem_overflow_check_element(mem) +#endif /* MEM_OVERFLOW_CHECK */ + +static struct mem * +ptr_to_mem(mem_size_t ptr) +{ + return (struct mem *)(void *)&ram[ptr]; +} + +static mem_size_t +mem_to_ptr(void *mem) +{ + return (mem_size_t)((u8_t *)mem - ram); +} + +/** + * "Plug holes" by combining adjacent empty struct mems. + * After this function is through, there should not exist + * one empty struct mem pointing to another empty struct mem. + * + * @param mem this points to a struct mem which just has been freed + * @internal this function is only called by mem_free() and mem_trim() + * + * This assumes access to the heap is protected by the calling function + * already. + */ +static void +plug_holes(struct mem *mem) +{ + struct mem *nmem; + struct mem *pmem; + + LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); + LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); + LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); + + /* plug hole forward */ + LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); + + nmem = ptr_to_mem(mem->next); + if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { + /* if mem->next is unused and not end of ram, combine mem and mem->next */ + if (lfree == nmem) { + lfree = mem; + } + mem->next = nmem->next; + if (nmem->next != MEM_SIZE_ALIGNED) { + ptr_to_mem(nmem->next)->prev = mem_to_ptr(mem); + } + } + + /* plug hole backward */ + pmem = ptr_to_mem(mem->prev); + if (pmem != mem && pmem->used == 0) { + /* if mem->prev is unused, combine mem and mem->prev */ + if (lfree == mem) { + lfree = pmem; + } + pmem->next = mem->next; + if (mem->next != MEM_SIZE_ALIGNED) { + ptr_to_mem(mem->next)->prev = mem_to_ptr(pmem); + } + } +} + +/** + * Zero the heap and initialize start, end and lowest-free + */ +void +mem_init(void) +{ + struct mem *mem; + + LWIP_ASSERT("Sanity check alignment", + (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT - 1)) == 0); + + /* align the heap */ + ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); + /* initialize the start of the heap */ + mem = (struct mem *)(void *)ram; + mem->next = MEM_SIZE_ALIGNED; + mem->prev = 0; + mem->used = 0; + /* initialize the end of the heap */ + ram_end = ptr_to_mem(MEM_SIZE_ALIGNED); + ram_end->used = 1; + ram_end->next = MEM_SIZE_ALIGNED; + ram_end->prev = MEM_SIZE_ALIGNED; + MEM_SANITY(); + + /* initialize the lowest-free pointer to the start of the heap */ + lfree = (struct mem *)(void *)ram; + + MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); + + if (sys_mutex_new(&mem_mutex) != ERR_OK) { + LWIP_ASSERT("failed to create mem_mutex", 0); + } +} + +/* Check if a struct mem is correctly linked. + * If not, double-free is a possible reason. + */ +static int +mem_link_valid(struct mem *mem) +{ + struct mem *nmem, *pmem; + mem_size_t rmem_idx; + rmem_idx = mem_to_ptr(mem); + nmem = ptr_to_mem(mem->next); + pmem = ptr_to_mem(mem->prev); + if ((mem->next > MEM_SIZE_ALIGNED) || (mem->prev > MEM_SIZE_ALIGNED) || + ((mem->prev != rmem_idx) && (pmem->next != rmem_idx)) || + ((nmem != ram_end) && (nmem->prev != rmem_idx))) { + return 0; + } + return 1; +} + +#if MEM_SANITY_CHECK +static void +mem_sanity(void) +{ + struct mem *mem; + u8_t last_used; + + /* begin with first element here */ + mem = (struct mem *)ram; + LWIP_ASSERT("heap element used valid", (mem->used == 0) || (mem->used == 1)); + last_used = mem->used; + LWIP_ASSERT("heap element prev ptr valid", mem->prev == 0); + LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); + LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); + + /* check all elements before the end of the heap */ + for (mem = ptr_to_mem(mem->next); + ((u8_t *)mem > ram) && (mem < ram_end); + mem = ptr_to_mem(mem->next)) { + LWIP_ASSERT("heap element aligned", LWIP_MEM_ALIGN(mem) == mem); + LWIP_ASSERT("heap element prev ptr valid", mem->prev <= MEM_SIZE_ALIGNED); + LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); + LWIP_ASSERT("heap element prev ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->prev) == ptr_to_mem(mem->prev))); + LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); + + if (last_used == 0) { + /* 2 unused elements in a row? */ + LWIP_ASSERT("heap element unused?", mem->used == 1); + } else { + LWIP_ASSERT("heap element unused member", (mem->used == 0) || (mem->used == 1)); + } + + LWIP_ASSERT("heap element link valid", mem_link_valid(mem)); + + /* used/unused altering */ + last_used = mem->used; + } + LWIP_ASSERT("heap end ptr sanity", mem == ptr_to_mem(MEM_SIZE_ALIGNED)); + LWIP_ASSERT("heap element used valid", mem->used == 1); + LWIP_ASSERT("heap element prev ptr valid", mem->prev == MEM_SIZE_ALIGNED); + LWIP_ASSERT("heap element next ptr valid", mem->next == MEM_SIZE_ALIGNED); +} +#endif /* MEM_SANITY_CHECK */ + +/** + * Put a struct mem back on the heap + * + * @param rmem is the data portion of a struct mem as returned by a previous + * call to mem_malloc() + */ +void +mem_free(void *rmem) +{ + struct mem *mem; + LWIP_MEM_FREE_DECL_PROTECT(); + + if (rmem == NULL) { + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); + return; + } + if ((((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) != 0) { + LWIP_MEM_ILLEGAL_FREE("mem_free: sanity check alignment"); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: sanity check alignment\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } + + /* Get the corresponding struct mem: */ + /* cast through void* to get rid of alignment warnings */ + mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); + + if ((u8_t *)mem < ram || (u8_t *)rmem + MIN_SIZE_ALIGNED > (u8_t *)ram_end) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory"); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } +#if MEM_OVERFLOW_CHECK + mem_overflow_check_element(mem); +#endif + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + /* mem has to be in a used state */ + if (!mem->used) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: double free"); + LWIP_MEM_FREE_UNPROTECT(); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: double free?\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } + + if (!mem_link_valid(mem)) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: non-linked: double free"); + LWIP_MEM_FREE_UNPROTECT(); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: non-linked: double free?\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } + + /* mem is now unused. */ + mem->used = 0; + + if (mem < lfree) { + /* the newly freed struct is now the lowest */ + lfree = mem; + } + + MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); + + /* finally, see if prev or next are free also */ + plug_holes(mem); + MEM_SANITY(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); +} + +/** + * Shrink memory returned by mem_malloc(). + * + * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked + * @param new_size required size after shrinking (needs to be smaller than or + * equal to the previous size) + * @return for compatibility reasons: is always == rmem, at the moment + * or NULL if newsize is > old size, in which case rmem is NOT touched + * or freed! + */ +void * +mem_trim(void *rmem, mem_size_t new_size) +{ + mem_size_t size, newsize; + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; + /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ + LWIP_MEM_FREE_DECL_PROTECT(); + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + newsize = (mem_size_t)LWIP_MEM_ALIGN_SIZE(new_size); + if (newsize < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + newsize = MIN_SIZE_ALIGNED; + } +#if MEM_OVERFLOW_CHECK + newsize += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; +#endif + if ((newsize > MEM_SIZE_ALIGNED) || (newsize < new_size)) { + return NULL; + } + + LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return rmem; + } + /* Get the corresponding struct mem ... */ + /* cast through void* to get rid of alignment warnings */ + mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); +#if MEM_OVERFLOW_CHECK + mem_overflow_check_element(mem); +#endif + /* ... and its offset pointer */ + ptr = mem_to_ptr(mem); + + size = (mem_size_t)((mem_size_t)(mem->next - ptr) - (SIZEOF_STRUCT_MEM + MEM_SANITY_OVERHEAD)); + LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); + if (newsize > size) { + /* not supported */ + return NULL; + } + if (newsize == size) { + /* No change in size, simply return */ + return rmem; + } + + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + + mem2 = ptr_to_mem(mem->next); + if (mem2->used == 0) { + /* The next struct is unused, we can simply move it at little */ + mem_size_t next; + LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); + /* remember the old next pointer */ + next = mem2->next; + /* create new struct mem which is moved directly after the shrinked mem */ + ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); + if (lfree == mem2) { + lfree = ptr_to_mem(ptr2); + } + mem2 = ptr_to_mem(ptr2); + mem2->used = 0; + /* restore the next pointer */ + mem2->next = next; + /* link it back to mem */ + mem2->prev = ptr; + /* link mem to it */ + mem->next = ptr2; + /* last thing to restore linked list: as we have moved mem2, + * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not + * the end of the heap */ + if (mem2->next != MEM_SIZE_ALIGNED) { + ptr_to_mem(mem2->next)->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* no need to plug holes, we've already done that */ + } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { + /* Next struct is used but there's room for another struct mem with + * at least MIN_SIZE_ALIGNED of data. + * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem + * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory */ + ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); + LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); + mem2 = ptr_to_mem(ptr2); + if (mem2 < lfree) { + lfree = mem2; + } + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + mem->next = ptr2; + if (mem2->next != MEM_SIZE_ALIGNED) { + ptr_to_mem(mem2->next)->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* the original mem->next is used, so no need to plug holes! */ + } + /* else { + next struct mem is used but size between mem and mem2 is not big enough + to create another struct mem + -> don't do anyhting. + -> the remaining space stays unused since it is too small + } */ +#if MEM_OVERFLOW_CHECK + mem_overflow_init_element(mem, new_size); +#endif + MEM_SANITY(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); + return rmem; +} + +/** + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size_in is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size_in) +{ + mem_size_t ptr, ptr2, size; + struct mem *mem, *mem2; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + u8_t local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_ALLOC_DECL_PROTECT(); + + if (size_in == 0) { + return NULL; + } + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + size = (mem_size_t)LWIP_MEM_ALIGN_SIZE(size_in); + if (size < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + size = MIN_SIZE_ALIGNED; + } +#if MEM_OVERFLOW_CHECK + size += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; +#endif + if ((size > MEM_SIZE_ALIGNED) || (size < size_in)) { + return NULL; + } + + /* protect the heap from concurrent access */ + sys_mutex_lock(&mem_mutex); + LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* run as long as a mem_free disturbed mem_malloc or mem_trim */ + do { + local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + /* Scan through the heap searching for a free block that is big enough, + * beginning with the lowest free block. + */ + for (ptr = mem_to_ptr(lfree); ptr < MEM_SIZE_ALIGNED - size; + ptr = ptr_to_mem(ptr)->next) { + mem = ptr_to_mem(ptr); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* allow mem_free or mem_trim to run */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem. */ + local_mem_free_count = 1; + break; + } +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + if ((!mem->used) && + (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { + /* mem is not used and at least perfect fit is possible: + * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + + if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { + /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing + * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') + * -> split large block, create empty remainder, + * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if + * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, + * struct mem would fit in but no data between mem2 and mem2->next + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory + */ + ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + size); + LWIP_ASSERT("invalid next ptr",ptr2 != MEM_SIZE_ALIGNED); + /* create mem2 struct */ + mem2 = ptr_to_mem(ptr2); + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + /* and insert it between mem and mem->next */ + mem->next = ptr2; + mem->used = 1; + + if (mem2->next != MEM_SIZE_ALIGNED) { + ptr_to_mem(mem2->next)->prev = ptr2; + } + MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); + } else { + /* (a mem2 struct does no fit into the user data space of mem and mem->next will always + * be used at this point: if not we have 2 unused structs in a row, plug_holes should have + * take care of this). + * -> near fit or exact fit: do not split, no mem2 creation + * also can't move mem->next directly behind mem, since mem->next + * will always be used at this point! + */ + mem->used = 1; + MEM_STATS_INC_USED(used, mem->next - mem_to_ptr(mem)); + } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +mem_malloc_adjust_lfree: +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + if (mem == lfree) { + struct mem *cur = lfree; + /* Find next free block after mem and update lowest free pointer */ + while (cur->used && cur != ram_end) { +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* prevent high interrupt latency... */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem or lfree. */ + goto mem_malloc_adjust_lfree; + } +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + cur = ptr_to_mem(cur->next); + } + lfree = cur; + LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); + } + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", + (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); + LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", + ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); + LWIP_ASSERT("mem_malloc: sanity check alignment", + (((mem_ptr_t)mem) & (MEM_ALIGNMENT - 1)) == 0); + +#if MEM_OVERFLOW_CHECK + mem_overflow_init_element(mem, size_in); +#endif + MEM_SANITY(); + return (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; + } + } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* if we got interrupted by a mem_free, try again */ + } while (local_mem_free_count != 0); +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + MEM_STATS_INC(err); + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); + return NULL; +} + +#endif /* MEM_USE_POOLS */ + +#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) +void * +mem_calloc(mem_size_t count, mem_size_t size) +{ + return mem_clib_calloc(count, size); +} + +#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ +/** + * Contiguously allocates enough space for count objects that are size bytes + * of memory each and returns a pointer to the allocated memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void * +mem_calloc(mem_size_t count, mem_size_t size) +{ + void *p; + size_t alloc_size = (size_t)count * (size_t)size; + + if ((size_t)(mem_size_t)alloc_size != alloc_size) { + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_calloc: could not allocate %"SZT_F" bytes\n", alloc_size)); + return NULL; + } + + /* allocate 'count' objects of size 'size' */ + p = mem_malloc((mem_size_t)alloc_size); + if (p) { + /* zero the memory */ + memset(p, 0, alloc_size); + } + return p; +} +#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/memp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/memp.c new file mode 100644 index 0000000..352ce5a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/memp.c @@ -0,0 +1,447 @@ +/** + * @file + * Dynamic pool memory manager + * + * lwIP has dedicated pools for many structures (netconn, protocol control blocks, + * packet buffers, ...). All these pools are managed here. + * + * @defgroup mempool Memory pools + * @ingroup infrastructure + * Custom memory pools + + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/stats.h" + +#include + +/* Make sure we include everything we need for size calculation required by memp_std.h */ +#include "lwip/pbuf.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/altcp.h" +#include "lwip/ip4_frag.h" +#include "lwip/netbuf.h" +#include "lwip/api.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/api_msg.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/etharp.h" +#include "lwip/igmp.h" +#include "lwip/timeouts.h" +/* needed by default MEMP_NUM_SYS_TIMEOUT */ +#include "netif/ppp/ppp_opts.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" +#include "lwip/priv/nd6_priv.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" + +#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) +#include "lwip/priv/memp_std.h" + +const struct memp_desc *const memp_pools[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, +#include "lwip/priv/memp_std.h" +}; + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2 +#undef MEMP_OVERFLOW_CHECK +/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */ +#define MEMP_OVERFLOW_CHECK 1 +#endif + +#if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC +/** + * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". + */ +static int +memp_sanity(const struct memp_desc *desc) +{ + struct memp *t, *h; + + t = *desc->tab; + if (t != NULL) { + for (h = t->next; (t != NULL) && (h != NULL); t = t->next, + h = ((h->next != NULL) ? h->next->next : NULL)) { + if (t == h) { + return 0; + } + } + } + + return 1; +} +#endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */ + +#if MEMP_OVERFLOW_CHECK +/** + * Check if a memp element was victim of an overflow or underflow + * (e.g. the restricted area after/before it has been altered) + * + * @param p the memp element to check + * @param desc the pool p comes from + */ +static void +memp_overflow_check_element(struct memp *p, const struct memp_desc *desc) +{ + mem_overflow_check_raw((u8_t *)p + MEMP_SIZE, desc->size, "pool ", desc->desc); +} + +/** + * Initialize the restricted area of on memp element. + */ +static void +memp_overflow_init_element(struct memp *p, const struct memp_desc *desc) +{ + mem_overflow_init_raw((u8_t *)p + MEMP_SIZE, desc->size); +} + +#if MEMP_OVERFLOW_CHECK >= 2 +/** + * Do an overflow check for all elements in every pool. + * + * @see memp_overflow_check_element for a description of the check + */ +static void +memp_overflow_check_all(void) +{ + u16_t i, j; + struct memp *p; + SYS_ARCH_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + + for (i = 0; i < MEMP_MAX; ++i) { + p = (struct memp *)LWIP_MEM_ALIGN(memp_pools[i]->base); + for (j = 0; j < memp_pools[i]->num; ++j) { + memp_overflow_check_element(p, memp_pools[i]); + p = LWIP_ALIGNMENT_CAST(struct memp *, ((u8_t *)p + MEMP_SIZE + memp_pools[i]->size + MEM_SANITY_REGION_AFTER_ALIGNED)); + } + } + SYS_ARCH_UNPROTECT(old_level); +} +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +#endif /* MEMP_OVERFLOW_CHECK */ + +/** + * Initialize custom memory pool. + * Related functions: memp_malloc_pool, memp_free_pool + * + * @param desc pool to initialize + */ +void +memp_init_pool(const struct memp_desc *desc) +{ +#if MEMP_MEM_MALLOC + LWIP_UNUSED_ARG(desc); +#else + int i; + struct memp *memp; + + *desc->tab = NULL; + memp = (struct memp *)LWIP_MEM_ALIGN(desc->base); +#if MEMP_MEM_INIT + /* force memset on pool memory */ + memset(memp, 0, (size_t)desc->num * (MEMP_SIZE + desc->size +#if MEMP_OVERFLOW_CHECK + + MEM_SANITY_REGION_AFTER_ALIGNED +#endif + )); +#endif + /* create a linked list of memp elements */ + for (i = 0; i < desc->num; ++i) { + memp->next = *desc->tab; + *desc->tab = memp; +#if MEMP_OVERFLOW_CHECK + memp_overflow_init_element(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + /* cast through void* to get rid of alignment warnings */ + memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size +#if MEMP_OVERFLOW_CHECK + + MEM_SANITY_REGION_AFTER_ALIGNED +#endif + ); + } +#if MEMP_STATS + desc->stats->avail = desc->num; +#endif /* MEMP_STATS */ +#endif /* !MEMP_MEM_MALLOC */ + +#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) + desc->stats->name = desc->desc; +#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */ +} + +/** + * Initializes lwIP built-in pools. + * Related functions: memp_malloc, memp_free + * + * Carves out memp_memory into linked lists for each pool-type. + */ +void +memp_init(void) +{ + u16_t i; + + /* for every pool: */ + for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) { + memp_init_pool(memp_pools[i]); + +#if LWIP_STATS && MEMP_STATS + lwip_stats.memp[i] = memp_pools[i]->stats; +#endif + } + +#if MEMP_OVERFLOW_CHECK >= 2 + /* check everything a first time to see if it worked */ + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +} + +static void * +#if !MEMP_OVERFLOW_CHECK +do_memp_malloc_pool(const struct memp_desc *desc) +#else +do_memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line) +#endif +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + +#if MEMP_MEM_MALLOC + memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size)); + SYS_ARCH_PROTECT(old_level); +#else /* MEMP_MEM_MALLOC */ + SYS_ARCH_PROTECT(old_level); + + memp = *desc->tab; +#endif /* MEMP_MEM_MALLOC */ + + if (memp != NULL) { +#if !MEMP_MEM_MALLOC +#if MEMP_OVERFLOW_CHECK == 1 + memp_overflow_check_element(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + + *desc->tab = memp->next; +#if MEMP_OVERFLOW_CHECK + memp->next = NULL; +#endif /* MEMP_OVERFLOW_CHECK */ +#endif /* !MEMP_MEM_MALLOC */ +#if MEMP_OVERFLOW_CHECK + memp->file = file; + memp->line = line; +#if MEMP_MEM_MALLOC + memp_overflow_init_element(memp, desc); +#endif /* MEMP_MEM_MALLOC */ +#endif /* MEMP_OVERFLOW_CHECK */ + LWIP_ASSERT("memp_malloc: memp properly aligned", + ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); +#if MEMP_STATS + desc->stats->used++; + if (desc->stats->used > desc->stats->max) { + desc->stats->max = desc->stats->used; + } +#endif + SYS_ARCH_UNPROTECT(old_level); + /* cast through u8_t* to get rid of alignment warnings */ + return ((u8_t *)memp + MEMP_SIZE); + } else { +#if MEMP_STATS + desc->stats->err++; +#endif + SYS_ARCH_UNPROTECT(old_level); + LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc)); + } + + return NULL; +} + +/** + * Get an element from a custom pool. + * + * @param desc the pool to get an element from + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc_pool(const struct memp_desc *desc) +#else +memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line) +#endif +{ + LWIP_ASSERT("invalid pool desc", desc != NULL); + if (desc == NULL) { + return NULL; + } + +#if !MEMP_OVERFLOW_CHECK + return do_memp_malloc_pool(desc); +#else + return do_memp_malloc_pool_fn(desc, file, line); +#endif +} + +/** + * Get an element from a specific pool. + * + * @param type the pool to get an element from + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc(memp_t type) +#else +memp_malloc_fn(memp_t type, const char *file, const int line) +#endif +{ + void *memp; + LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); + +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + +#if !MEMP_OVERFLOW_CHECK + memp = do_memp_malloc_pool(memp_pools[type]); +#else + memp = do_memp_malloc_pool_fn(memp_pools[type], file, line); +#endif + + return memp; +} + +static void +do_memp_free_pool(const struct memp_desc *desc, void *mem) +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("memp_free: mem properly aligned", + ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); + + /* cast through void* to get rid of alignment warnings */ + memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE); + + SYS_ARCH_PROTECT(old_level); + +#if MEMP_OVERFLOW_CHECK == 1 + memp_overflow_check_element(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + +#if MEMP_STATS + desc->stats->used--; +#endif + +#if MEMP_MEM_MALLOC + LWIP_UNUSED_ARG(desc); + SYS_ARCH_UNPROTECT(old_level); + mem_free(memp); +#else /* MEMP_MEM_MALLOC */ + memp->next = *desc->tab; + *desc->tab = memp; + +#if MEMP_SANITY_CHECK + LWIP_ASSERT("memp sanity", memp_sanity(desc)); +#endif /* MEMP_SANITY_CHECK */ + + SYS_ARCH_UNPROTECT(old_level); +#endif /* !MEMP_MEM_MALLOC */ +} + +/** + * Put a custom pool element back into its pool. + * + * @param desc the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free_pool(const struct memp_desc *desc, void *mem) +{ + LWIP_ASSERT("invalid pool desc", desc != NULL); + if ((desc == NULL) || (mem == NULL)) { + return; + } + + do_memp_free_pool(desc, mem); +} + +/** + * Put an element back into its pool. + * + * @param type the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free(memp_t type, void *mem) +{ +#ifdef LWIP_HOOK_MEMP_AVAILABLE + struct memp *old_first; +#endif + + LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;); + + if (mem == NULL) { + return; + } + +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + +#ifdef LWIP_HOOK_MEMP_AVAILABLE + old_first = *memp_pools[type]->tab; +#endif + + do_memp_free_pool(memp_pools[type], mem); + +#ifdef LWIP_HOOK_MEMP_AVAILABLE + if (old_first == NULL) { + LWIP_HOOK_MEMP_AVAILABLE(type); + } +#endif +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/netif.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/netif.c new file mode 100644 index 0000000..088b50e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/netif.c @@ -0,0 +1,1817 @@ +/** + * @file + * lwIP network interface abstraction + * + * @defgroup netif Network interface (NETIF) + * @ingroup callbackstyle_api + * + * @defgroup netif_ip4 IPv4 address handling + * @ingroup netif + * + * @defgroup netif_ip6 IPv6 address handling + * @ingroup netif + * + * @defgroup netif_cd Client data handling + * Store data (void*) on a netif for application usage. + * @see @ref LWIP_NUM_NETIF_CLIENT_DATA + * @ingroup netif + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#include "lwip/opt.h" + +#include /* memset */ +#include /* atoi */ + +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/udp.h" +#include "lwip/priv/raw_priv.h" +#include "lwip/snmp.h" +#include "lwip/igmp.h" +#include "lwip/etharp.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/ip.h" +#if ENABLE_LOOPBACK +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/tcpip.h" +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#include "netif/ethernet.h" + +#if LWIP_AUTOIP +#include "lwip/autoip.h" +#endif /* LWIP_AUTOIP */ +#if LWIP_DHCP +#include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ +#if LWIP_IPV6 +#include "lwip/nd6.h" +#endif + +#if LWIP_NETIF_STATUS_CALLBACK +#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) +#else +#define NETIF_STATUS_CALLBACK(n) +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) +#else +#define NETIF_LINK_CALLBACK(n) +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_EXT_STATUS_CALLBACK +static netif_ext_callback_t *ext_callback; +#endif + +#if !LWIP_SINGLE_NETIF +struct netif *netif_list; +#endif /* !LWIP_SINGLE_NETIF */ +struct netif *netif_default; + +#define netif_index_to_num(index) ((index) - 1) +static u8_t netif_num; + +#if LWIP_NUM_NETIF_CLIENT_DATA > 0 +static u8_t netif_client_id; +#endif + +#define NETIF_REPORT_TYPE_IPV4 0x01 +#define NETIF_REPORT_TYPE_IPV6 0x02 +static void netif_issue_reports(struct netif *netif, u8_t report_type); + +#if LWIP_IPV6 +static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 +static err_t netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4 */ + +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr); +#endif +#if LWIP_IPV6 +static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr); +#endif + + +static struct netif loop_netif; + +/** + * Initialize a lwip network interface structure for a loopback interface + * + * @param netif the lwip network interface structure for this loopif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + */ +static err_t +netif_loopif_init(struct netif *netif) +{ + LWIP_ASSERT("netif_loopif_init: invalid netif", netif != NULL); + + /* initialize the snmp variables and counters inside the struct netif + * ifSpeed: no assumption can be made! + */ + MIB2_INIT_NETIF(netif, snmp_ifType_softwareLoopback, 0); + + netif->name[0] = 'l'; + netif->name[1] = 'o'; +#if LWIP_IPV4 + netif->output = netif_loop_output_ipv4; +#endif +#if LWIP_IPV6 + netif->output_ip6 = netif_loop_output_ipv6; +#endif +#if LWIP_LOOPIF_MULTICAST + netif_set_flags(netif, NETIF_FLAG_IGMP); +#endif + NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_DISABLE_ALL); + return ERR_OK; +} +#endif /* LWIP_HAVE_LOOPIF */ + +void +netif_init(void) +{ +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +#define LOOPIF_ADDRINIT &loop_ipaddr, &loop_netmask, &loop_gw, + ip4_addr_t loop_ipaddr, loop_netmask, loop_gw; + IP4_ADDR(&loop_gw, 127, 0, 0, 1); + IP4_ADDR(&loop_ipaddr, 127, 0, 0, 1); + IP4_ADDR(&loop_netmask, 255, 0, 0, 0); +#else /* LWIP_IPV4 */ +#define LOOPIF_ADDRINIT +#endif /* LWIP_IPV4 */ + +#if NO_SYS + netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); +#else /* NO_SYS */ + netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); +#endif /* NO_SYS */ + +#if LWIP_IPV6 + IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); + loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; +#endif /* LWIP_IPV6 */ + + netif_set_link_up(&loop_netif); + netif_set_up(&loop_netif); + +#endif /* LWIP_HAVE_LOOPIF */ +} + +/** + * @ingroup lwip_nosys + * Forwards a received packet for input processing with + * ethernet_input() or ip_input() depending on netif flags. + * Don't call directly, pass to netif_add() and call + * netif->input(). + * Only works if the netif driver correctly sets + * NETIF_FLAG_ETHARP and/or NETIF_FLAG_ETHERNET flag! + */ +err_t +netif_input(struct pbuf *p, struct netif *inp) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("netif_input: invalid pbuf", p != NULL); + LWIP_ASSERT("netif_input: invalid netif", inp != NULL); + +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + return ethernet_input(p, inp); + } else +#endif /* LWIP_ETHERNET */ + return ip_input(p, inp); +} + +/** + * @ingroup netif + * Add a network interface to the list of lwIP netifs. + * + * Same as @ref netif_add but without IPv4 addresses + */ +struct netif * +netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input) +{ + return netif_add(netif, +#if LWIP_IPV4 + NULL, NULL, NULL, +#endif /* LWIP_IPV4*/ + state, init, input); +} + +/** + * @ingroup netif + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack.\n + * It is recommended to use a function that passes the input directly + * to the stack (netif_input(), NO_SYS=1 mode) or via sending a + * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).\n + * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET + * to decide whether to forward to ethernet_input() or ip_input(). + * In other words, the functions only work when the netif + * driver is implemented correctly!\n + * Most members of struct netif should be be initialized by the + * netif init function = netif driver (init parameter of this function).\n + * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after + * setting the MAC address in struct netif.hwaddr + * (IPv6 requires a link-local address). + * + * @return netif, or NULL if failed. + */ +struct netif * +netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input) +{ +#if LWIP_IPV6 + s8_t i; +#endif + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_SINGLE_NETIF + if (netif_default != NULL) { + LWIP_ASSERT("single netif already set", 0); + return NULL; + } +#endif + + LWIP_ERROR("netif_add: invalid netif", netif != NULL, return NULL); + LWIP_ERROR("netif_add: No init function given", init != NULL, return NULL); + +#if LWIP_IPV4 + if (ipaddr == NULL) { + ipaddr = ip_2_ip4(IP4_ADDR_ANY); + } + if (netmask == NULL) { + netmask = ip_2_ip4(IP4_ADDR_ANY); + } + if (gw == NULL) { + gw = ip_2_ip4(IP4_ADDR_ANY); + } + + /* reset new interface configuration state */ + ip_addr_set_zero_ip4(&netif->ip_addr); + ip_addr_set_zero_ip4(&netif->netmask); + ip_addr_set_zero_ip4(&netif->gw); + netif->output = netif_null_output_ip4; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + ip_addr_set_zero_ip6(&netif->ip6_addr[i]); + netif->ip6_addr_state[i] = IP6_ADDR_INVALID; +#if LWIP_IPV6_ADDRESS_LIFETIMES + netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC; + netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC; +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ + } + netif->output_ip6 = netif_null_output_ip6; +#endif /* LWIP_IPV6 */ + NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); + netif->mtu = 0; + netif->flags = 0; +#ifdef netif_get_client_data + memset(netif->client_data, 0, sizeof(netif->client_data)); +#endif /* LWIP_NUM_NETIF_CLIENT_DATA */ +#if LWIP_IPV6 +#if LWIP_IPV6_AUTOCONFIG + /* IPv6 address autoconfiguration not enabled by default */ + netif->ip6_autoconfig_enabled = 0; +#endif /* LWIP_IPV6_AUTOCONFIG */ + nd6_restart_netif(netif); +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + netif->status_callback = NULL; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif->link_callback = NULL; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_IGMP + netif->igmp_mac_filter = NULL; +#endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->mld_mac_filter = NULL; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + /* remember netif specific state information data */ + netif->state = state; + netif->num = netif_num; + netif->input = input; + + NETIF_RESET_HINTS(netif); +#if ENABLE_LOOPBACK + netif->loop_first = NULL; + netif->loop_last = NULL; +#if LWIP_LOOPBACK_MAX_PBUFS + netif->loop_cnt_current = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + netif->reschedule_poll = 0; +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_IPV4 + netif_set_addr(netif, ipaddr, netmask, gw); +#endif /* LWIP_IPV4 */ + + /* call user specified initialization function for netif */ + if (init(netif) != ERR_OK) { + return NULL; + } +#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES + /* Initialize the MTU for IPv6 to the one set by the netif driver. + This can be updated later by RA. */ + netif->mtu6 = netif->mtu; +#endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */ + +#if !LWIP_SINGLE_NETIF + /* Assign a unique netif number in the range [0..254], so that (num+1) can + serve as an interface index that fits in a u8_t. + We assume that the new netif has not yet been added to the list here. + This algorithm is O(n^2), but that should be OK for lwIP. + */ + { + struct netif *netif2; + int num_netifs; + do { + if (netif->num == 255) { + netif->num = 0; + } + num_netifs = 0; + for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) { + LWIP_ASSERT("netif already added", netif2 != netif); + num_netifs++; + LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255); + if (netif2->num == netif->num) { + netif->num++; + break; + } + } + } while (netif2 != NULL); + } + if (netif->num == 254) { + netif_num = 0; + } else { + netif_num = (u8_t)(netif->num + 1); + } + + /* add this netif to the list */ + netif->next = netif_list; + netif_list = netif; +#endif /* "LWIP_SINGLE_NETIF */ + mib2_netif_added(netif); + +#if LWIP_IGMP + /* start IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_start(netif); + } +#endif /* LWIP_IGMP */ + + LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP", + netif->name[0], netif->name[1])); +#if LWIP_IPV4 + LWIP_DEBUGF(NETIF_DEBUG, (" addr ")); + ip4_addr_debug_print(NETIF_DEBUG, ipaddr); + LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); + ip4_addr_debug_print(NETIF_DEBUG, netmask); + LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); + ip4_addr_debug_print(NETIF_DEBUG, gw); +#endif /* LWIP_IPV4 */ + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); + + netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL); + + return netif; +} + +static void +netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) +{ +#if LWIP_TCP + tcp_netif_ip_addr_changed(old_addr, new_addr); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(old_addr, new_addr); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(old_addr, new_addr); +#endif /* LWIP_RAW */ +} + +#if LWIP_IPV4 +static int +netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *old_addr) +{ + LWIP_ASSERT("invalid pointer", ipaddr != NULL); + LWIP_ASSERT("invalid pointer", old_addr != NULL); + + /* address is actually being changed? */ + if (ip4_addr_cmp(ipaddr, netif_ip4_addr(netif)) == 0) { + ip_addr_t new_addr; + *ip_2_ip4(&new_addr) = *ipaddr; + IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4); + + ip_addr_copy(*old_addr, *netif_ip_addr4(netif)); + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); + netif_do_ip_addr_changed(old_addr, &new_addr); + + mib2_remove_ip4(netif); + mib2_remove_route_ip4(0, netif); + /* set new IP address to netif */ + ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr); + IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4); + mib2_add_ip4(netif); + mib2_add_route_ip4(0, netif); + + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4); + + NETIF_STATUS_CALLBACK(netif); + return 1; /* address changed */ + } + return 0; /* address unchanged */ +} + +/** + * @ingroup netif_ip4 + * Change the IP address of a network interface + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * + * @note call netif_set_addr() if you also want to change netmask and + * default gateway + */ +void +netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr) +{ + ip_addr_t old_addr; + + LWIP_ERROR("netif_set_ipaddr: invalid netif", netif != NULL, return); + + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + + LWIP_ASSERT_CORE_LOCKED(); + + if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + netif_ext_callback_args_t args; + args.ipv4_changed.old_address = &old_addr; + netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_ADDRESS_CHANGED, &args); +#endif + } +} + +static int +netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm) +{ + /* address is actually being changed? */ + if (ip4_addr_cmp(netmask, netif_ip4_netmask(netif)) == 0) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + LWIP_ASSERT("invalid pointer", old_nm != NULL); + ip_addr_copy(*old_nm, *netif_ip_netmask4(netif)); +#else + LWIP_UNUSED_ARG(old_nm); +#endif + mib2_remove_route_ip4(0, netif); + /* set new netmask to netif */ + ip4_addr_set(ip_2_ip4(&netif->netmask), netmask); + IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4); + mib2_add_route_ip4(0, netif); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(netif_ip4_netmask(netif)), + ip4_addr2_16(netif_ip4_netmask(netif)), + ip4_addr3_16(netif_ip4_netmask(netif)), + ip4_addr4_16(netif_ip4_netmask(netif)))); + return 1; /* netmask changed */ + } + return 0; /* netmask unchanged */ +} + +/** + * @ingroup netif_ip4 + * Change the netmask of a network interface + * + * @param netif the network interface to change + * @param netmask the new netmask + * + * @note call netif_set_addr() if you also want to change ip address and + * default gateway + */ +void +netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask) +{ +#if LWIP_NETIF_EXT_STATUS_CALLBACK + ip_addr_t old_nm_val; + ip_addr_t *old_nm = &old_nm_val; +#else + ip_addr_t *old_nm = NULL; +#endif + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_netmask: invalid netif", netif != NULL, return); + + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + + if (netif_do_set_netmask(netif, netmask, old_nm)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + netif_ext_callback_args_t args; + args.ipv4_changed.old_netmask = old_nm; + netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_NETMASK_CHANGED, &args); +#endif + } +} + +static int +netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw) +{ + /* address is actually being changed? */ + if (ip4_addr_cmp(gw, netif_ip4_gw(netif)) == 0) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + LWIP_ASSERT("invalid pointer", old_gw != NULL); + ip_addr_copy(*old_gw, *netif_ip_gw4(netif)); +#else + LWIP_UNUSED_ARG(old_gw); +#endif + + ip4_addr_set(ip_2_ip4(&netif->gw), gw); + IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(netif_ip4_gw(netif)), + ip4_addr2_16(netif_ip4_gw(netif)), + ip4_addr3_16(netif_ip4_gw(netif)), + ip4_addr4_16(netif_ip4_gw(netif)))); + return 1; /* gateway changed */ + } + return 0; /* gateway unchanged */ +} + +/** + * @ingroup netif_ip4 + * Change the default gateway for a network interface + * + * @param netif the network interface to change + * @param gw the new default gateway + * + * @note call netif_set_addr() if you also want to change ip address and netmask + */ +void +netif_set_gw(struct netif *netif, const ip4_addr_t *gw) +{ +#if LWIP_NETIF_EXT_STATUS_CALLBACK + ip_addr_t old_gw_val; + ip_addr_t *old_gw = &old_gw_val; +#else + ip_addr_t *old_gw = NULL; +#endif + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_gw: invalid netif", netif != NULL, return); + + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } + + if (netif_do_set_gw(netif, gw, old_gw)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + netif_ext_callback_args_t args; + args.ipv4_changed.old_gw = old_gw; + netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_GATEWAY_CHANGED, &args); +#endif + } +} + +/** + * @ingroup netif_ip4 + * Change IP address configuration for a network interface (including netmask + * and default gateway). + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * @param netmask the new netmask + * @param gw the new default gateway + */ +void +netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, + const ip4_addr_t *gw) +{ +#if LWIP_NETIF_EXT_STATUS_CALLBACK + netif_nsc_reason_t change_reason = LWIP_NSC_NONE; + netif_ext_callback_args_t cb_args; + ip_addr_t old_nm_val; + ip_addr_t old_gw_val; + ip_addr_t *old_nm = &old_nm_val; + ip_addr_t *old_gw = &old_gw_val; +#else + ip_addr_t *old_nm = NULL; + ip_addr_t *old_gw = NULL; +#endif + ip_addr_t old_addr; + int remove; + + LWIP_ASSERT_CORE_LOCKED(); + + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } + + remove = ip4_addr_isany(ipaddr); + if (remove) { + /* when removing an address, we have to remove it *before* changing netmask/gw + to ensure that tcp RST segment can be sent correctly */ + if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; + cb_args.ipv4_changed.old_address = &old_addr; +#endif + } + } + if (netif_do_set_netmask(netif, netmask, old_nm)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + change_reason |= LWIP_NSC_IPV4_NETMASK_CHANGED; + cb_args.ipv4_changed.old_netmask = old_nm; +#endif + } + if (netif_do_set_gw(netif, gw, old_gw)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + change_reason |= LWIP_NSC_IPV4_GATEWAY_CHANGED; + cb_args.ipv4_changed.old_gw = old_gw; +#endif + } + if (!remove) { + /* set ipaddr last to ensure netmask/gw have been set when status callback is called */ + if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; + cb_args.ipv4_changed.old_address = &old_addr; +#endif + } + } + +#if LWIP_NETIF_EXT_STATUS_CALLBACK + if (change_reason != LWIP_NSC_NONE) { + change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED; + netif_invoke_ext_callback(netif, change_reason, &cb_args); + } +#endif +} +#endif /* LWIP_IPV4*/ + +/** + * @ingroup netif + * Remove a network interface from the list of lwIP netifs. + * + * @param netif the network interface to remove + */ +void +netif_remove(struct netif *netif) +{ +#if LWIP_IPV6 + int i; +#endif + + LWIP_ASSERT_CORE_LOCKED(); + + if (netif == NULL) { + return; + } + + netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL); + +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { + netif_do_ip_addr_changed(netif_ip_addr4(netif), NULL); + } + +#if LWIP_IGMP + /* stop IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_stop(netif); + } +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { + netif_do_ip_addr_changed(netif_ip_addr6(netif, i), NULL); + } + } +#if LWIP_IPV6_MLD + /* stop MLD processing */ + mld6_stop(netif); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + if (netif_is_up(netif)) { + /* set netif down before removing (call callback function) */ + netif_set_down(netif); + } + + mib2_remove_ip4(netif); + + /* this netif is default? */ + if (netif_default == netif) { + /* reset default netif */ + netif_set_default(NULL); + } +#if !LWIP_SINGLE_NETIF + /* is it the first netif? */ + if (netif_list == netif) { + netif_list = netif->next; + } else { + /* look for netif further down the list */ + struct netif *tmp_netif; + NETIF_FOREACH(tmp_netif) { + if (tmp_netif->next == netif) { + tmp_netif->next = netif->next; + break; + } + } + if (tmp_netif == NULL) { + return; /* netif is not on the list */ + } + } +#endif /* !LWIP_SINGLE_NETIF */ + mib2_netif_removed(netif); +#if LWIP_NETIF_REMOVE_CALLBACK + if (netif->remove_callback) { + netif->remove_callback(netif); + } +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); +} + +/** + * @ingroup netif + * Set a network interface as the default network interface + * (used to output all packets for which no specific route is found) + * + * @param netif the default network interface + */ +void +netif_set_default(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (netif == NULL) { + /* remove default route */ + mib2_remove_route_ip4(1, netif); + } else { + /* install default route */ + mib2_add_route_ip4(1, netif); + } + netif_default = netif; + LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", + netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); +} + +/** + * @ingroup netif + * Bring an interface up, available for processing + * traffic. + */ +void +netif_set_up(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_up: invalid netif", netif != NULL, return); + + if (!(netif->flags & NETIF_FLAG_UP)) { + netif_set_flags(netif, NETIF_FLAG_UP); + + MIB2_COPY_SYSUPTIME_TO(&netif->ts); + + NETIF_STATUS_CALLBACK(netif); + +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.status_changed.state = 1; + netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); + } +#endif + + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); +#if LWIP_IPV6 + nd6_restart_netif(netif); +#endif /* LWIP_IPV6 */ + } +} + +/** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change + */ +static void +netif_issue_reports(struct netif *netif, u8_t report_type) +{ + LWIP_ASSERT("netif_issue_reports: invalid netif", netif != NULL); + + /* Only send reports when both link and admin states are up */ + if (!(netif->flags & NETIF_FLAG_LINK_UP) || + !(netif->flags & NETIF_FLAG_UP)) { + return; + } + +#if LWIP_IPV4 + if ((report_type & NETIF_REPORT_TYPE_IPV4) && + !ip4_addr_isany_val(*netif_ip4_addr(netif))) { +#if LWIP_ARP + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & (NETIF_FLAG_ETHARP)) { + etharp_gratuitous(netif); + } +#endif /* LWIP_ARP */ + +#if LWIP_IGMP + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups(netif); + } +#endif /* LWIP_IGMP */ + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 + if (report_type & NETIF_REPORT_TYPE_IPV6) { +#if LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups(netif); +#endif /* LWIP_IPV6_MLD */ + } +#endif /* LWIP_IPV6 */ +} + +/** + * @ingroup netif + * Bring an interface down, disabling any traffic processing. + */ +void +netif_set_down(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_down: invalid netif", netif != NULL, return); + + if (netif->flags & NETIF_FLAG_UP) { +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.status_changed.state = 0; + netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); + } +#endif + + netif_clear_flags(netif, NETIF_FLAG_UP); + MIB2_COPY_SYSUPTIME_TO(&netif->ts); + +#if LWIP_IPV4 && LWIP_ARP + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_cleanup_netif(netif); + } +#endif /* LWIP_IPV4 && LWIP_ARP */ + +#if LWIP_IPV6 + nd6_cleanup_netif(netif); +#endif /* LWIP_IPV6 */ + + NETIF_STATUS_CALLBACK(netif); + } +} + +#if LWIP_NETIF_STATUS_CALLBACK +/** + * @ingroup netif + * Set callback to be called when interface is brought up/down or address is changed while up + */ +void +netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (netif) { + netif->status_callback = status_callback; + } +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_REMOVE_CALLBACK +/** + * @ingroup netif + * Set callback to be called when the interface has been removed + */ +void +netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (netif) { + netif->remove_callback = remove_callback; + } +} +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +/** + * @ingroup netif + * Called by a driver when its link goes up + */ +void +netif_set_link_up(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_link_up: invalid netif", netif != NULL, return); + + if (!(netif->flags & NETIF_FLAG_LINK_UP)) { + netif_set_flags(netif, NETIF_FLAG_LINK_UP); + +#if LWIP_DHCP + dhcp_network_changed(netif); +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP + autoip_network_changed(netif); +#endif /* LWIP_AUTOIP */ + + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); +#if LWIP_IPV6 + nd6_restart_netif(netif); +#endif /* LWIP_IPV6 */ + + NETIF_LINK_CALLBACK(netif); +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.link_changed.state = 1; + netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); + } +#endif + } +} + +/** + * @ingroup netif + * Called by a driver when its link goes down + */ +void +netif_set_link_down(struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("netif_set_link_down: invalid netif", netif != NULL, return); + + if (netif->flags & NETIF_FLAG_LINK_UP) { + netif_clear_flags(netif, NETIF_FLAG_LINK_UP); +#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES + netif->mtu6 = netif->mtu; +#endif + + NETIF_LINK_CALLBACK(netif); +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.link_changed.state = 0; + netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); + } +#endif + } +} + +#if LWIP_NETIF_LINK_CALLBACK +/** + * @ingroup netif + * Set callback to be called when link is brought up/down + */ +void +netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (netif) { + netif->link_callback = link_callback; + } +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * @ingroup netif + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is copied and added to an internal queue which is fed to + * netif->input by netif_poll(). + * In multithreaded mode, the call to netif_poll() is queued to be done on the + * TCP/IP thread. + * In callback mode, the user has the responsibility to call netif_poll() in + * the main loop of their application. + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @return ERR_OK if the packet has been sent + * ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p) +{ + struct pbuf *r; + err_t err; + struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if MIB2_STATS +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* MIB2_STATS */ +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + u8_t schedule_poll = 0; +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_ASSERT("netif_loop_output: invalid netif", netif != NULL); + LWIP_ASSERT("netif_loop_output: invalid pbuf", p != NULL); + + /* Allocate a new pbuf */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return ERR_MEM; + } +#if LWIP_LOOPBACK_MAX_PBUFS + clen = pbuf_clen(r); + /* check for overflow or too many pbuf on queue */ + if (((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || + ((netif->loop_cnt_current + clen) > LWIP_MIN(LWIP_LOOPBACK_MAX_PBUFS, 0xFFFF))) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return ERR_MEM; + } + netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current + clen); +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* Copy the whole pbuf queue p into the single pbuf r */ + if ((err = pbuf_copy(r, p)) != ERR_OK) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return err; + } + + /* Put the packet on a linked list which gets emptied through calling + netif_poll(). */ + + /* let last point to the last pbuf in chain r */ + for (last = r; last->next != NULL; last = last->next) { + /* nothing to do here, just get to the last pbuf */ + } + + SYS_ARCH_PROTECT(lev); + if (netif->loop_first != NULL) { + LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); + netif->loop_last->next = r; + netif->loop_last = last; +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + if (netif->reschedule_poll) { + schedule_poll = 1; + netif->reschedule_poll = 0; + } +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + } else { + netif->loop_first = r; + netif->loop_last = last; +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* No existing packets queued, schedule poll */ + schedule_poll = 1; +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + } + SYS_ARCH_UNPROTECT(lev); + + LINK_STATS_INC(link.xmit); + MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len); + MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* For multithreading environment, schedule a call to netif_poll */ + if (schedule_poll) { + if (tcpip_try_callback((tcpip_callback_fn)netif_poll, netif) != ERR_OK) { + SYS_ARCH_PROTECT(lev); + netif->reschedule_poll = 1; + SYS_ARCH_UNPROTECT(lev); + } + } +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + + return ERR_OK; +} + +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +static err_t +netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) +{ + LWIP_UNUSED_ARG(addr); + return netif_loop_output(netif, p); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +static err_t +netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) +{ + LWIP_UNUSED_ARG(addr); + return netif_loop_output(netif, p); +} +#endif /* LWIP_IPV6 */ +#endif /* LWIP_HAVE_LOOPIF */ + + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if MIB2_STATS +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* MIB2_STATS */ + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_ASSERT("netif_poll: invalid netif", netif != NULL); + + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + while (netif->loop_first != NULL) { + struct pbuf *in, *in_end; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = 1; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + in = in_end = netif->loop_first; + while (in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; +#if LWIP_LOOPBACK_MAX_PBUFS + clen++; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + } +#if LWIP_LOOPBACK_MAX_PBUFS + /* adjust the number of pbufs on queue */ + LWIP_ASSERT("netif->loop_cnt_current underflow", + ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); + netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current - clen); +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* 'in_end' now points to the last pbuf from 'in' */ + if (in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; + SYS_ARCH_UNPROTECT(lev); + + in->if_idx = netif_get_index(netif); + + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); + MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); + /* loopback packets are always IP packets! */ + if (ip_input(in, netif) != ERR_OK) { + pbuf_free(in); + } + SYS_ARCH_PROTECT(lev); + } + SYS_ARCH_UNPROTECT(lev); +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ + struct netif *netif; + /* loop through netifs */ + NETIF_FOREACH(netif) { + netif_poll(netif); + } +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_NUM_NETIF_CLIENT_DATA > 0 +/** + * @ingroup netif_cd + * Allocate an index to store data in client_data member of struct netif. + * Returned value is an index in mentioned array. + * @see LWIP_NUM_NETIF_CLIENT_DATA + */ +u8_t +netif_alloc_client_data_id(void) +{ + u8_t result = netif_client_id; + netif_client_id++; + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_NUM_NETIF_CLIENT_DATA > 256 +#error LWIP_NUM_NETIF_CLIENT_DATA must be <= 256 +#endif + LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA); + return (u8_t)(result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX); +} +#endif + +#if LWIP_IPV6 +/** + * @ingroup netif_ip6 + * Change an IPv6 address of a network interface + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param addr6 the new IPv6 address + * + * @note call netif_ip6_addr_set_state() to set the address valid/temptative + */ +void +netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("netif_ip6_addr_set: invalid netif", netif != NULL); + LWIP_ASSERT("netif_ip6_addr_set: invalid addr6", addr6 != NULL); + + netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1], + addr6->addr[2], addr6->addr[3]); +} + +/* + * Change an IPv6 address of a network interface (internal version taking 4 * u32_t) + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param i0 word0 of the new IPv6 address + * @param i1 word1 of the new IPv6 address + * @param i2 word2 of the new IPv6 address + * @param i3 word3 of the new IPv6 address + */ +void +netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3) +{ + ip_addr_t old_addr; + ip_addr_t new_ipaddr; + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); + + ip6_addr_copy(*ip_2_ip6(&old_addr), *netif_ip6_addr(netif, addr_idx)); + IP_SET_TYPE_VAL(old_addr, IPADDR_TYPE_V6); + + /* address is actually being changed? */ + if ((ip_2_ip6(&old_addr)->addr[0] != i0) || (ip_2_ip6(&old_addr)->addr[1] != i1) || + (ip_2_ip6(&old_addr)->addr[2] != i2) || (ip_2_ip6(&old_addr)->addr[3] != i3)) { + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n")); + + IP_ADDR6(&new_ipaddr, i0, i1, i2, i3); + ip6_addr_assign_zone(ip_2_ip6(&new_ipaddr), IP6_UNICAST, netif); + + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { + netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); + } + /* @todo: remove/readd mib2 ip6 entries? */ + + ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr); + + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); + NETIF_STATUS_CALLBACK(netif); + } + +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.ipv6_set.addr_index = addr_idx; + args.ipv6_set.old_address = &old_addr; + netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_SET, &args); + } +#endif + } + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", + addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), + netif_ip6_addr_state(netif, addr_idx))); +} + +/** + * @ingroup netif_ip6 + * Change the state of an IPv6 address of a network interface + * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE + * includes the number of checks done, see ip6_addr.h) + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param state the new IPv6 address state + */ +void +netif_ip6_addr_set_state(struct netif *netif, s8_t addr_idx, u8_t state) +{ + u8_t old_state; + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); + + old_state = netif_ip6_addr_state(netif, addr_idx); + /* state is actually being changed? */ + if (old_state != state) { + u8_t old_valid = old_state & IP6_ADDR_VALID; + u8_t new_valid = state & IP6_ADDR_VALID; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n")); + +#if LWIP_IPV6_MLD + /* Reevaluate solicited-node multicast group membership. */ + if (netif->flags & NETIF_FLAG_MLD6) { + nd6_adjust_mld_membership(netif, addr_idx, state); + } +#endif /* LWIP_IPV6_MLD */ + + if (old_valid && !new_valid) { + /* address about to be removed by setting invalid */ + netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); + /* @todo: remove mib2 ip6 entries? */ + } + netif->ip6_addr_state[addr_idx] = state; + + if (!old_valid && new_valid) { + /* address added by setting valid */ + /* This is a good moment to check that the address is properly zoned. */ + IP6_ADDR_ZONECHECK_NETIF(netif_ip6_addr(netif, addr_idx), netif); + /* @todo: add mib2 ip6 entries? */ + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); + } + if ((old_state & ~IP6_ADDR_TENTATIVE_COUNT_MASK) != + (state & ~IP6_ADDR_TENTATIVE_COUNT_MASK)) { + /* address state has changed -> call the callback function */ + NETIF_STATUS_CALLBACK(netif); + } + +#if LWIP_NETIF_EXT_STATUS_CALLBACK + { + netif_ext_callback_args_t args; + args.ipv6_addr_state_changed.addr_index = addr_idx; + args.ipv6_addr_state_changed.old_state = old_state; + args.ipv6_addr_state_changed.address = netif_ip_addr6(netif, addr_idx); + netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_ADDR_STATE_CHANGED, &args); + } +#endif + } + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", + addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), + netif_ip6_addr_state(netif, addr_idx))); +} + +/** + * Checks if a specific local address is present on the netif and returns its + * index. Depending on its state, it may or may not be assigned to the + * interface (as per RFC terminology). + * + * The given address may or may not be zoned (i.e., have a zone index other + * than IP6_NO_ZONE). If the address is zoned, it must have the correct zone + * for the given netif, or no match will be found. + * + * @param netif the netif to check + * @param ip6addr the IPv6 address to find + * @return >= 0: address found, this is its index + * -1: address not found on this netif + */ +s8_t +netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr) +{ + s8_t i; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("netif_get_ip6_addr_match: invalid netif", netif != NULL); + LWIP_ASSERT("netif_get_ip6_addr_match: invalid ip6addr", ip6addr != NULL); + +#if LWIP_IPV6_SCOPES + if (ip6_addr_has_zone(ip6addr) && !ip6_addr_test_zone(ip6addr, netif)) { + return -1; /* wrong zone, no match */ + } +#endif /* LWIP_IPV6_SCOPES */ + + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp_zoneless(netif_ip6_addr(netif, i), ip6addr)) { + return i; + } + } + return -1; +} + +/** + * @ingroup netif_ip6 + * Create a link-local IPv6 address on a netif (stored in slot 0) + * + * @param netif the netif to create the address on + * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion) + * if == 0, use hwaddr directly as interface ID + */ +void +netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) +{ + u8_t i, addr_index; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("netif_create_ip6_linklocal_address: invalid netif", netif != NULL); + + /* Link-local prefix. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul); + ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0; + + /* Generate interface ID. */ + if (from_mac_48bit) { + /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | + ((u32_t)(netif->hwaddr[1]) << 16) | + ((u32_t)(netif->hwaddr[2]) << 8) | + (0xff)); + ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((u32_t)(0xfeul << 24) | + ((u32_t)(netif->hwaddr[3]) << 16) | + ((u32_t)(netif->hwaddr[4]) << 8) | + (netif->hwaddr[5])); + } else { + /* Use hwaddr directly as interface ID. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0; + ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0; + + addr_index = 3; + for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) { + if (i == 4) { + addr_index--; + } + ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= lwip_htonl(((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03))); + } + } + + /* Set a link-local zone. Even though the zone is implied by the owning + * netif, setting the zone anyway has two important conceptual advantages: + * 1) it avoids the need for a ton of exceptions in internal code, allowing + * e.g. ip6_addr_cmp() to be used on local addresses; + * 2) the properly zoned address is visible externally, e.g. when any outside + * code enumerates available addresses or uses one to bind a socket. + * Any external code unaware of address scoping is likely to just ignore the + * zone field, so this should not create any compatibility problems. */ + ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[0]), IP6_UNICAST, netif); + + /* Set address state. */ +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* Will perform duplicate address detection (DAD). */ + netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE); +#else + /* Consider address valid. */ + netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED); +#endif /* LWIP_IPV6_AUTOCONFIG */ +} + +/** + * @ingroup netif_ip6 + * This function allows for the easy addition of a new IPv6 address to an interface. + * It takes care of finding an empty slot and then sets the address tentative + * (to make sure that all the subsequent processing happens). + * + * @param netif netif to add the address on + * @param ip6addr address to add + * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here + */ +err_t +netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx) +{ + s8_t i; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("netif_add_ip6_address: invalid netif", netif != NULL); + LWIP_ASSERT("netif_add_ip6_address: invalid ip6addr", ip6addr != NULL); + + i = netif_get_ip6_addr_match(netif, ip6addr); + if (i >= 0) { + /* Address already added */ + if (chosen_idx != NULL) { + *chosen_idx = i; + } + return ERR_OK; + } + + /* Find a free slot. The first one is reserved for link-local addresses. */ + for (i = ip6_addr_islinklocal(ip6addr) ? 0 : 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { + ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr); + ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[i]), IP6_UNICAST, netif); + netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE); + if (chosen_idx != NULL) { + *chosen_idx = i; + } + return ERR_OK; + } + } + + if (chosen_idx != NULL) { + *chosen_idx = -1; + } + return ERR_VAL; +} + +/** Dummy IPv6 output function for netifs not supporting IPv6 + */ +static err_t +netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(ipaddr); + + return ERR_IF; +} +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 +/** Dummy IPv4 output function for netifs not supporting IPv4 + */ +static err_t +netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(ipaddr); + + return ERR_IF; +} +#endif /* LWIP_IPV4 */ + +/** +* @ingroup netif +* Return the interface index for the netif with name +* or NETIF_NO_INDEX if not found/on error +* +* @param name the name of the netif +*/ +u8_t +netif_name_to_index(const char *name) +{ + struct netif *netif = netif_find(name); + if (netif != NULL) { + return netif_get_index(netif); + } + /* No name found, return invalid index */ + return NETIF_NO_INDEX; +} + +/** +* @ingroup netif +* Return the interface name for the netif matching index +* or NULL if not found/on error +* +* @param idx the interface index of the netif +* @param name char buffer of at least NETIF_NAMESIZE bytes +*/ +char * +netif_index_to_name(u8_t idx, char *name) +{ + struct netif *netif = netif_get_by_index(idx); + + if (netif != NULL) { + name[0] = netif->name[0]; + name[1] = netif->name[1]; + lwip_itoa(&name[2], NETIF_NAMESIZE - 2, netif_index_to_num(idx)); + return name; + } + return NULL; +} + +/** +* @ingroup netif +* Return the interface for the netif index +* +* @param idx index of netif to find +*/ +struct netif * +netif_get_by_index(u8_t idx) +{ + struct netif *netif; + + LWIP_ASSERT_CORE_LOCKED(); + + if (idx != NETIF_NO_INDEX) { + NETIF_FOREACH(netif) { + if (idx == netif_get_index(netif)) { + return netif; /* found! */ + } + } + } + + return NULL; +} + +/** + * @ingroup netif + * Find a network interface by searching for its name + * + * @param name the name of the netif (like netif->name) plus concatenated number + * in ascii representation (e.g. 'en0') + */ +struct netif * +netif_find(const char *name) +{ + struct netif *netif; + u8_t num; + + LWIP_ASSERT_CORE_LOCKED(); + + if (name == NULL) { + return NULL; + } + + num = (u8_t)atoi(&name[2]); + if (!num && (name[2] != '0')) { + /* this means atoi has failed */ + return NULL; + } + + NETIF_FOREACH(netif) { + if (num == netif->num && + name[0] == netif->name[0] && + name[1] == netif->name[1]) { + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); + return netif; + } + } + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); + return NULL; +} + +#if LWIP_NETIF_EXT_STATUS_CALLBACK +/** + * @ingroup netif + * Add extended netif events listener + * @param callback pointer to listener structure + * @param fn callback function + */ +void +netif_add_ext_callback(netif_ext_callback_t *callback, netif_ext_callback_fn fn) +{ + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("callback must be != NULL", callback != NULL); + LWIP_ASSERT("fn must be != NULL", fn != NULL); + + callback->callback_fn = fn; + callback->next = ext_callback; + ext_callback = callback; +} + +/** + * @ingroup netif + * Remove extended netif events listener + * @param callback pointer to listener structure + */ +void +netif_remove_ext_callback(netif_ext_callback_t* callback) +{ + netif_ext_callback_t *last, *iter; + + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("callback must be != NULL", callback != NULL); + + if (ext_callback == NULL) { + return; + } + + if (callback == ext_callback) { + ext_callback = ext_callback->next; + } else { + last = ext_callback; + for (iter = ext_callback->next; iter != NULL; last = iter, iter = iter->next) { + if (iter == callback) { + LWIP_ASSERT("last != NULL", last != NULL); + last->next = callback->next; + callback->next = NULL; + return; + } + } + } +} + +/** + * Invoke extended netif status event + * @param netif netif that is affected by change + * @param reason change reason + * @param args depends on reason, see reason description + */ +void +netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args) +{ + netif_ext_callback_t *callback = ext_callback; + + LWIP_ASSERT("netif must be != NULL", netif != NULL); + + while (callback != NULL) { + callback->callback_fn(netif, reason, args); + callback = callback->next; + } +} +#endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/pbuf.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/pbuf.c new file mode 100644 index 0000000..7638dfd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/pbuf.c @@ -0,0 +1,1548 @@ +/** + * @file + * Packet buffer management + */ + +/** + * @defgroup pbuf Packet buffers (PBUF) + * @ingroup infrastructure + * + * Packets are built from the pbuf data structure. It supports dynamic + * memory allocation for packet contents or can reference externally + * managed packet contents both in RAM and ROM. Quick allocation for + * incoming packets is provided through pools with fixed sized pbufs. + * + * A packet may span over multiple pbufs, chained as a singly linked + * list. This is called a "pbuf chain". + * + * Multiple packets may be queued, also using this singly linked list. + * This is called a "packet queue". + * + * So, a packet queue consists of one or more pbuf chains, each of + * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE + * NOT SUPPORTED!!! Use helper structs to queue multiple packets. + * + * The differences between a pbuf chain and a packet queue are very + * precise but subtle. + * + * The last pbuf of a packet has a ->tot_len field that equals the + * ->len field. It can be found by traversing the list. If the last + * pbuf of a packet has a ->next field other than NULL, more packets + * are on the queue. + * + * Therefore, looping through a pbuf of a single packet, has an + * loop end condition (tot_len == p->len), NOT (next == NULL). + * + * Example of custom pbuf usage: @ref zerocopyrx + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/netif.h" +#if LWIP_TCP && TCP_QUEUE_OOSEQ +#include "lwip/priv/tcp_priv.h" +#endif +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#include + +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) +/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically + aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ +#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + +static const struct pbuf * +pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset); + +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_IS_EMPTY() +#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ + +#if !NO_SYS +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL +#include "lwip/tcpip.h" +#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ + if (tcpip_try_callback(pbuf_free_ooseq_callback, NULL) != ERR_OK) { \ + SYS_ARCH_PROTECT(old_level); \ + pbuf_free_ooseq_pending = 0; \ + SYS_ARCH_UNPROTECT(old_level); \ + } } while(0) +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ +#endif /* !NO_SYS */ + +volatile u8_t pbuf_free_ooseq_pending; +#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() + +/** + * Attempt to reclaim some memory from queued out-of-sequence TCP segments + * if we run out of pool pbufs. It's better to give priority to new packets + * if we're running out. + * + * This must be done in the correct thread context therefore this function + * can only be used with NO_SYS=0 and through tcpip_callback. + */ +#if !NO_SYS +static +#endif /* !NO_SYS */ +void +pbuf_free_ooseq(void) +{ + struct tcp_pcb *pcb; + SYS_ARCH_SET(pbuf_free_ooseq_pending, 0); + + for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { + if (pcb->ooseq != NULL) { + /** Free the ooseq pbufs of one PCB only */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); + tcp_free_ooseq(pcb); + return; + } + } +} + +#if !NO_SYS +/** + * Just a callback function for tcpip_callback() that calls pbuf_free_ooseq(). + */ +static void +pbuf_free_ooseq_callback(void *arg) +{ + LWIP_UNUSED_ARG(arg); + pbuf_free_ooseq(); +} +#endif /* !NO_SYS */ + +/** Queue a call to pbuf_free_ooseq if not already queued. */ +static void +pbuf_pool_is_empty(void) +{ +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL + SYS_ARCH_SET(pbuf_free_ooseq_pending, 1); +#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ + u8_t queued; + SYS_ARCH_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + queued = pbuf_free_ooseq_pending; + pbuf_free_ooseq_pending = 1; + SYS_ARCH_UNPROTECT(old_level); + + if (!queued) { + /* queue a call to pbuf_free_ooseq if not already queued */ + PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); + } +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ +} +#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ + +/* Initialize members of struct pbuf after allocation */ +static void +pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags) +{ + p->next = NULL; + p->payload = payload; + p->tot_len = tot_len; + p->len = len; + p->type_internal = (u8_t)type; + p->flags = flags; + p->ref = 1; + p->if_idx = NETIF_NO_INDEX; +} + +/** + * @ingroup pbuf + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param layer header size + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + * chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + * protocol headers. Additional headers must be prepended + * by allocating another pbuf and chain in to the front of + * the ROM pbuf. It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + * protocol headers. It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ +struct pbuf * +pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) +{ + struct pbuf *p; + u16_t offset = (u16_t)layer; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); + + switch (type) { + case PBUF_REF: /* fall through */ + case PBUF_ROM: + p = pbuf_alloc_reference(NULL, length, type); + break; + case PBUF_POOL: { + struct pbuf *q, *last; + u16_t rem_len; /* remaining length */ + p = NULL; + last = NULL; + rem_len = length; + do { + u16_t qlen; + q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + if (q == NULL) { + PBUF_POOL_IS_EMPTY(); + /* free chain so far allocated */ + if (p) { + pbuf_free(p); + } + /* bail out unsuccessfully */ + return NULL; + } + qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); + pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), + rem_len, qlen, type, 0); + LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", + ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", + (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); + if (p == NULL) { + /* allocated head of pbuf chain (into p) */ + p = q; + } else { + /* make previous pbuf point to this pbuf */ + last->next = q; + } + last = q; + rem_len = (u16_t)(rem_len - qlen); + offset = 0; + } while (rem_len > 0); + break; + } + case PBUF_RAM: { + mem_size_t payload_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length)); + mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len); + + /* bug #50040: Check for integer overflow when calculating alloc_len */ + if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) || + (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) { + return NULL; + } + + /* If pbuf is to be allocated in RAM, allocate memory for it. */ + p = (struct pbuf *)mem_malloc(alloc_len); + if (p == NULL) { + return NULL; + } + pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), + length, length, type, 0); + LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + break; + } + default: + LWIP_ASSERT("pbuf_alloc: erroneous type", 0); + return NULL; + } + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); + return p; +} + +/** + * @ingroup pbuf + * Allocates a pbuf for referenced data. + * Referenced data can be volatile (PBUF_REF) or long-lived (PBUF_ROM). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param payload referenced payload + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_ROM: It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * + * @return the allocated pbuf. + */ +struct pbuf * +pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type) +{ + struct pbuf *p; + LWIP_ASSERT("invalid pbuf_type", (type == PBUF_REF) || (type == PBUF_ROM)); + /* only allocate memory for the pbuf structure */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF); + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_alloc_reference: Could not allocate MEMP_PBUF for PBUF_%s.\n", + (type == PBUF_ROM) ? "ROM" : "REF")); + return NULL; + } + pbuf_init_alloced_pbuf(p, payload, length, length, type, 0); + return p; +} + + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** + * @ingroup pbuf + * Initialize a custom pbuf (already allocated). + * Example of custom pbuf usage: @ref zerocopyrx + * + * @param l header size + * @param length size of the pbuf's payload + * @param type type of the pbuf (only used to treat the pbuf accordingly, as + * this function allocates no memory) + * @param p pointer to the custom pbuf to initialize (already allocated) + * @param payload_mem pointer to the buffer that is used for payload and headers, + * must be at least big enough to hold 'length' plus the header size, + * may be NULL if set later. + * ATTENTION: The caller is responsible for correct alignment of this buffer!! + * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least + * big enough to hold 'length' plus the header size + */ +struct pbuf * +pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, + void *payload_mem, u16_t payload_mem_len) +{ + u16_t offset = (u16_t)l; + void *payload; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); + + if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); + return NULL; + } + + if (payload_mem != NULL) { + payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); + } else { + payload = NULL; + } + pbuf_init_alloced_pbuf(&p->pbuf, payload, length, length, type, PBUF_FLAG_IS_CUSTOM); + return &p->pbuf; +} +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** + * @ingroup pbuf + * Shrink a pbuf chain to a desired length. + * + * @param p pbuf to shrink. + * @param new_len desired new length of pbuf chain + * + * Depending on the desired length, the first few pbufs in a chain might + * be skipped and left unchanged. The new last pbuf in the chain will be + * resized, and any remaining pbufs will be freed. + * + * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. + * @note May not be called on a packet queue. + * + * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). + */ +void +pbuf_realloc(struct pbuf *p, u16_t new_len) +{ + struct pbuf *q; + u16_t rem_len; /* remaining length */ + u16_t shrink; + + LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); + + /* desired length larger than current length? */ + if (new_len >= p->tot_len) { + /* enlarging not yet supported */ + return; + } + + /* the pbuf chain grows by (new_len - p->tot_len) bytes + * (which may be negative in case of shrinking) */ + shrink = (u16_t)(p->tot_len - new_len); + + /* first, step over any pbufs that should remain in the chain */ + rem_len = new_len; + q = p; + /* should this pbuf be kept? */ + while (rem_len > q->len) { + /* decrease remaining length by pbuf length */ + rem_len = (u16_t)(rem_len - q->len); + /* decrease total length indicator */ + q->tot_len = (u16_t)(q->tot_len - shrink); + /* proceed to next pbuf in chain */ + q = q->next; + LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); + } + /* we have now reached the new last pbuf (in q) */ + /* rem_len == desired length for pbuf q */ + + /* shrink allocated memory for PBUF_RAM */ + /* (other types merely adjust their length fields */ + if (pbuf_match_allocsrc(q, PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) && (rem_len != q->len) +#if LWIP_SUPPORT_CUSTOM_PBUF + && ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0) +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + ) { + /* reallocate and adjust the length of the pbuf that will be split */ + q = (struct pbuf *)mem_trim(q, (mem_size_t)(((u8_t *)q->payload - (u8_t *)q) + rem_len)); + LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); + } + /* adjust length fields for new last pbuf */ + q->len = rem_len; + q->tot_len = q->len; + + /* any remaining pbufs in chain? */ + if (q->next != NULL) { + /* free remaining pbufs in chain */ + pbuf_free(q->next); + } + /* q is last packet in chain */ + q->next = NULL; + +} + +/** + * Adjusts the payload pointer to reveal headers in the payload. + * @see pbuf_add_header. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size. + * @param force Allow 'header_size_increment > 0' for PBUF_REF/PBUF_ROM types + * + * @return non-zero on failure, zero on success. + * + */ +static u8_t +pbuf_add_header_impl(struct pbuf *p, size_t header_size_increment, u8_t force) +{ + u16_t type_internal; + void *payload; + u16_t increment_magnitude; + + LWIP_ASSERT("p != NULL", p != NULL); + if ((p == NULL) || (header_size_increment > 0xFFFF)) { + return 1; + } + if (header_size_increment == 0) { + return 0; + } + + increment_magnitude = (u16_t)header_size_increment; + /* Do not allow tot_len to wrap as a result. */ + if ((u16_t)(increment_magnitude + p->tot_len) < increment_magnitude) { + return 1; + } + + type_internal = p->type_internal; + + /* pbuf types containing payloads? */ + if (type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS) { + /* set new payload pointer */ + payload = (u8_t *)p->payload - header_size_increment; + /* boundary check fails? */ + if ((u8_t *)payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, + ("pbuf_add_header: failed as %p < %p (not enough space for new header size)\n", + (void *)payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF))); + /* bail out unsuccessfully */ + return 1; + } + /* pbuf types referring to external payloads? */ + } else { + /* hide a header in the payload? */ + if (force) { + payload = (u8_t *)p->payload - header_size_increment; + } else { + /* cannot expand payload to front (yet!) + * bail out unsuccessfully */ + return 1; + } + } + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_add_header: old %p new %p (%"U16_F")\n", + (void *)p->payload, (void *)payload, increment_magnitude)); + + /* modify pbuf fields */ + p->payload = payload; + p->len = (u16_t)(p->len + increment_magnitude); + p->tot_len = (u16_t)(p->tot_len + increment_magnitude); + + + return 0; +} + +/** + * Adjusts the payload pointer to reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * If header_size_increment is 0, this function does nothing and returns successful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_add_header(struct pbuf *p, size_t header_size_increment) +{ + return pbuf_add_header_impl(p, header_size_increment, 0); +} + +/** + * Same as @ref pbuf_add_header but does not check if 'header_size > 0' is allowed. + * This is used internally only, to allow PBUF_REF for RX. + */ +u8_t +pbuf_add_header_force(struct pbuf *p, size_t header_size_increment) +{ + return pbuf_add_header_impl(p, header_size_increment, 1); +} + +/** + * Adjusts the payload pointer to hide headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * disappears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_decrement Number of bytes to decrement header size which + * decreases the size of the pbuf. + * If header_size_decrement is 0, this function does nothing and returns successful. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_remove_header(struct pbuf *p, size_t header_size_decrement) +{ + void *payload; + u16_t increment_magnitude; + + LWIP_ASSERT("p != NULL", p != NULL); + if ((p == NULL) || (header_size_decrement > 0xFFFF)) { + return 1; + } + if (header_size_decrement == 0) { + return 0; + } + + increment_magnitude = (u16_t)header_size_decrement; + /* Check that we aren't going to move off the end of the pbuf */ + LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); + + /* remember current payload pointer */ + payload = p->payload; + LWIP_UNUSED_ARG(payload); /* only used in LWIP_DEBUGF below */ + + /* increase payload pointer (guarded by length check above) */ + p->payload = (u8_t *)p->payload + header_size_decrement; + /* modify pbuf length fields */ + p->len = (u16_t)(p->len - increment_magnitude); + p->tot_len = (u16_t)(p->tot_len - increment_magnitude); + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_remove_header: old %p new %p (%"U16_F")\n", + (void *)payload, (void *)p->payload, increment_magnitude)); + + return 0; +} + +static u8_t +pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force) +{ + if (header_size_increment < 0) { + return pbuf_remove_header(p, (size_t) - header_size_increment); + } else { + return pbuf_add_header_impl(p, (size_t)header_size_increment, force); + } +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If header_size_increment is 0, this function does nothing and returns successful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size_increment) +{ + return pbuf_header_impl(p, header_size_increment, 0); +} + +/** + * Same as pbuf_header but does not check if 'header_size > 0' is allowed. + * This is used internally only, to allow PBUF_REF for RX. + */ +u8_t +pbuf_header_force(struct pbuf *p, s16_t header_size_increment) +{ + return pbuf_header_impl(p, header_size_increment, 1); +} + +/** Similar to pbuf_header(-size) but de-refs header pbufs for (size >= p->len) + * + * @param q pbufs to operate on + * @param size The number of bytes to remove from the beginning of the pbuf list. + * While size >= p->len, pbufs are freed. + * ATTENTION: this is the opposite direction as @ref pbuf_header, but + * takes an u16_t not s16_t! + * @return the new head pbuf + */ +struct pbuf * +pbuf_free_header(struct pbuf *q, u16_t size) +{ + struct pbuf *p = q; + u16_t free_left = size; + while (free_left && p) { + if (free_left >= p->len) { + struct pbuf *f = p; + free_left = (u16_t)(free_left - p->len); + p = p->next; + f->next = 0; + pbuf_free(f); + } else { + pbuf_remove_header(p, free_left); + free_left = 0; + } + } + return p; +} + +/** + * @ingroup pbuf + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param p The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + * + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ +u8_t +pbuf_free(struct pbuf *p) +{ + u8_t alloc_src; + struct pbuf *q; + u8_t count; + + if (p == NULL) { + LWIP_ASSERT("p != NULL", p != NULL); + /* if assertions are disabled, proceed with debug output */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_free(p == NULL) was called.\n")); + return 0; + } + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); + + PERF_START; + + count = 0; + /* de-allocate all consecutive pbufs from the head of the chain that + * obtain a zero reference count after decrementing*/ + while (p != NULL) { + LWIP_PBUF_REF_T ref; + SYS_ARCH_DECL_PROTECT(old_level); + /* Since decrementing ref cannot be guaranteed to be a single machine operation + * we must protect it. We put the new ref into a local variable to prevent + * further protection. */ + SYS_ARCH_PROTECT(old_level); + /* all pbufs in a chain are referenced at least once */ + LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); + /* decrease reference count (number of pointers to pbuf) */ + ref = --(p->ref); + SYS_ARCH_UNPROTECT(old_level); + /* this pbuf is no longer referenced to? */ + if (ref == 0) { + /* remember next pbuf in chain for next iteration */ + q = p->next; + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); + alloc_src = pbuf_get_allocsrc(p); +#if LWIP_SUPPORT_CUSTOM_PBUF + /* is this a custom pbuf? */ + if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { + struct pbuf_custom *pc = (struct pbuf_custom *)p; + LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); + pc->custom_free_function(p); + } else +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + { + /* is this a pbuf from the pool? */ + if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) { + memp_free(MEMP_PBUF_POOL, p); + /* is this a ROM or RAM referencing pbuf? */ + } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF) { + memp_free(MEMP_PBUF, p); + /* type == PBUF_RAM */ + } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) { + mem_free(p); + } else { + /* @todo: support freeing other types */ + LWIP_ASSERT("invalid pbuf type", 0); + } + } + count++; + /* proceed to next pbuf */ + p = q; + /* p->ref > 0, this pbuf is still referenced to */ + /* (and so the remaining pbufs in chain as well) */ + } else { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)ref)); + /* stop walking through the chain */ + p = NULL; + } + } + PERF_STOP("pbuf_free"); + /* return number of de-allocated pbufs */ + return count; +} + +/** + * Count number of pbufs in a chain + * + * @param p first pbuf of chain + * @return the number of pbufs in a chain + */ +u16_t +pbuf_clen(const struct pbuf *p) +{ + u16_t len; + + len = 0; + while (p != NULL) { + ++len; + p = p->next; + } + return len; +} + +/** + * @ingroup pbuf + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void +pbuf_ref(struct pbuf *p) +{ + /* pbuf given? */ + if (p != NULL) { + SYS_ARCH_SET(p->ref, (LWIP_PBUF_REF_T)(p->ref + 1)); + LWIP_ASSERT("pbuf ref overflow", p->ref > 0); + } +} + +/** + * @ingroup pbuf + * Concatenate two pbufs (each may be a pbuf chain) and take over + * the caller's reference of the tail pbuf. + * + * @note The caller MAY NOT reference the tail pbuf afterwards. + * Use pbuf_chain() for that purpose. + * + * This function explicitly does not check for tot_len overflow to prevent + * failing to queue too long pbufs. This can produce invalid pbufs, so + * handle with care! + * + * @see pbuf_chain() + */ +void +pbuf_cat(struct pbuf *h, struct pbuf *t) +{ + struct pbuf *p; + + LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", + ((h != NULL) && (t != NULL)), return;); + + /* proceed to last pbuf of chain */ + for (p = h; p->next != NULL; p = p->next) { + /* add total length of second chain to all totals of first chain */ + p->tot_len = (u16_t)(p->tot_len + t->tot_len); + } + /* { p is last pbuf of first h chain, p->next == NULL } */ + LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); + LWIP_ASSERT("p->next == NULL", p->next == NULL); + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len = (u16_t)(p->tot_len + t->tot_len); + /* chain last pbuf of head (p) with first of tail (t) */ + p->next = t; + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. + */ +} + +/** + * @ingroup pbuf + * Chain two pbufs (or pbuf chains) together. + * + * The caller MUST call pbuf_free(t) once it has stopped + * using it. Use pbuf_cat() instead if you no longer use t. + * + * @param h head pbuf (chain) + * @param t tail pbuf (chain) + * @note The pbufs MUST belong to the same packet. + * @note MAY NOT be called on a packet queue. + * + * The ->tot_len fields of all pbufs of the head chain are adjusted. + * The ->next field of the last pbuf of the head chain is adjusted. + * The ->ref field of the first pbuf of the tail chain is adjusted. + * + */ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ + pbuf_cat(h, t); + /* t is now referenced by h */ + pbuf_ref(t); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); +} + +/** + * Dechains the first pbuf from its succeeding pbufs in the chain. + * + * Makes p->tot_len field equal to p->len. + * @param p pbuf to dechain + * @return remainder of the pbuf chain, or NULL if it was de-allocated. + * @note May not be called on a packet queue. + */ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + u8_t tail_gone = 1; + /* tail */ + q = p->next; + /* pbuf has successor in chain? */ + if (q != NULL) { + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); + /* enforce invariant if assertion is disabled */ + q->tot_len = (u16_t)(p->tot_len - p->len); + /* decouple pbuf from remainder */ + p->next = NULL; + /* total length of pbuf p is its own length only */ + p->tot_len = p->len; + /* q is no longer referenced by p, free it */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); + tail_gone = pbuf_free(q); + if (tail_gone > 0) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, + ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); + } + /* return remaining tail or NULL if deallocated */ + } + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); + return ((tail_gone > 0) ? NULL : q); +} + +/** + * @ingroup pbuf + * Create PBUF_RAM copies of pbufs. + * + * Used to queue packets on behalf of the lwIP stack, such as + * ARP based queueing. + * + * @note You MUST explicitly use p = pbuf_take(p); + * + * @note Only one packet is copied, no packet queue! + * + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy + * + * @return ERR_OK if pbuf was copied + * ERR_ARG if one of the pbufs is NULL or p_to is not big + * enough to hold p_from + */ +err_t +pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from) +{ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", + (const void *)p_to, (const void *)p_from)); + + LWIP_ERROR("pbuf_copy: invalid source", p_from != NULL, return ERR_ARG;); + return pbuf_copy_partial_pbuf(p_to, p_from, p_from->tot_len, 0); +} + +/** + * @ingroup pbuf + * Copy part or all of one packet buffer into another, to a specified offset. + * + * @note Only data in one packet is copied, no packet queue! + * @note Argument order is shared with pbuf_copy, but different than pbuf_copy_partial. + * + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy + * @param copy_len number of bytes to copy + * @param offset offset in destination pbuf where to copy to + * + * @return ERR_OK if copy_len bytes were copied + * ERR_ARG if one of the pbufs is NULL or p_from is shorter than copy_len + * or p_to is not big enough to hold copy_len at offset + * ERR_VAL if any of the pbufs are part of a queue + */ +err_t +pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_len, u16_t offset) +{ + size_t offset_to = offset, offset_from = 0, len_calc; + u16_t len; + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy_partial_pbuf(%p, %p, %"U16_F", %"U16_F")\n", + (const void *)p_to, (const void *)p_from, copy_len, offset)); + + /* is the copy_len in range? */ + LWIP_ERROR("pbuf_copy_partial_pbuf: copy_len bigger than source", ((p_from != NULL) && + (p_from->tot_len >= copy_len)), return ERR_ARG;); + /* is the target big enough to hold the source? */ + LWIP_ERROR("pbuf_copy_partial_pbuf: target not big enough", ((p_to != NULL) && + (p_to->tot_len >= (offset + copy_len))), return ERR_ARG;); + + /* iterate through pbuf chain */ + do { + /* copy one part of the original chain */ + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { + /* complete current p_from fits into current p_to */ + len_calc = p_from->len - offset_from; + } else { + /* current p_from does not fit into current p_to */ + len_calc = p_to->len - offset_to; + } + len = (u16_t)LWIP_MIN(copy_len, len_calc); + MEMCPY((u8_t *)p_to->payload + offset_to, (u8_t *)p_from->payload + offset_from, len); + offset_to += len; + offset_from += len; + copy_len -= len; + LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); + LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); + if (offset_from >= p_from->len) { + /* on to next p_from (if any) */ + offset_from = 0; + p_from = p_from->next; + LWIP_ERROR("p_from != NULL", (p_from != NULL) || (copy_len == 0), return ERR_ARG;); + } + if (offset_to == p_to->len) { + /* on to next p_to (if any) */ + offset_to = 0; + p_to = p_to->next; + LWIP_ERROR("p_to != NULL", (p_to != NULL) || (copy_len == 0), return ERR_ARG;); + } + + if ((p_from != NULL) && (p_from->len == p_from->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy_partial_pbuf() does not allow packet queues!", + (p_from->next == NULL), return ERR_VAL;); + } + if ((p_to != NULL) && (p_to->len == p_to->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy_partial_pbuf() does not allow packet queues!", + (p_to->next == NULL), return ERR_VAL;); + } + } while (copy_len); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy_partial_pbuf: copy complete.\n")); + return ERR_OK; +} + +/** + * @ingroup pbuf + * Copy (part of) the contents of a packet buffer + * to an application supplied buffer. + * + * @param buf the pbuf from which to copy data + * @param dataptr the application supplied buffer + * @param len length of data to copy (dataptr must be big enough). No more + * than buf->tot_len will be copied, irrespective of len + * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure + */ +u16_t +pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) +{ + const struct pbuf *p; + u16_t left = 0; + u16_t buf_copy_len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for (p = buf; len != 0 && p != NULL; p = p->next) { + if ((offset != 0) && (offset >= p->len)) { + /* don't copy from this buffer -> on to the next */ + offset = (u16_t)(offset - p->len); + } else { + /* copy from this buffer. maybe only partially. */ + buf_copy_len = (u16_t)(p->len - offset); + if (buf_copy_len > len) { + buf_copy_len = len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(&((char *)dataptr)[left], &((char *)p->payload)[offset], buf_copy_len); + copied_total = (u16_t)(copied_total + buf_copy_len); + left = (u16_t)(left + buf_copy_len); + len = (u16_t)(len - buf_copy_len); + offset = 0; + } + } + return copied_total; +} + +/** + * @ingroup pbuf + * Get part of a pbuf's payload as contiguous memory. The returned memory is + * either a pointer into the pbuf's payload or, if split over multiple pbufs, + * a copy into the user-supplied buffer. + * + * @param p the pbuf from which to copy data + * @param buffer the application supplied buffer + * @param bufsize size of the application supplied buffer + * @param len length of data to copy (dataptr must be big enough). No more + * than buf->tot_len will be copied, irrespective of len + * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure + */ +void * +pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) +{ + const struct pbuf *q; + u16_t out_offset; + + LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;); + LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;); + LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;); + + q = pbuf_skip_const(p, offset, &out_offset); + if (q != NULL) { + if (q->len >= (out_offset + len)) { + /* all data in this pbuf, return zero-copy */ + return (u8_t *)q->payload + out_offset; + } + /* need to copy */ + if (pbuf_copy_partial(q, buffer, len, out_offset) != len) { + /* copying failed: pbuf is too short */ + return NULL; + } + return buffer; + } + /* pbuf is too short (offset does not fit in) */ + return NULL; +} + +#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE +/** + * This method modifies a 'pbuf chain', so that its total length is + * smaller than 64K. The remainder of the original pbuf chain is stored + * in *rest. + * This function never creates new pbufs, but splits an existing chain + * in two parts. The tot_len of the modified packet queue will likely be + * smaller than 64K. + * 'packet queues' are not supported by this function. + * + * @param p the pbuf queue to be split + * @param rest pointer to store the remainder (after the first 64K) + */ +void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) +{ + *rest = NULL; + if ((p != NULL) && (p->next != NULL)) { + u16_t tot_len_front = p->len; + struct pbuf *i = p; + struct pbuf *r = p->next; + + /* continue until the total length (summed up as u16_t) overflows */ + while ((r != NULL) && ((u16_t)(tot_len_front + r->len) >= tot_len_front)) { + tot_len_front = (u16_t)(tot_len_front + r->len); + i = r; + r = r->next; + } + /* i now points to last packet of the first segment. Set next + pointer to NULL */ + i->next = NULL; + + if (r != NULL) { + /* Update the tot_len field in the first part */ + for (i = p; i != NULL; i = i->next) { + i->tot_len = (u16_t)(i->tot_len - r->tot_len); + LWIP_ASSERT("tot_len/len mismatch in last pbuf", + (i->next != NULL) || (i->tot_len == i->len)); + } + if (p->flags & PBUF_FLAG_TCP_FIN) { + r->flags |= PBUF_FLAG_TCP_FIN; + } + + /* tot_len field in rest does not need modifications */ + /* reference counters do not need modifications */ + *rest = r; + } + } +} +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + +/* Actual implementation of pbuf_skip() but returning const pointer... */ +static const struct pbuf * +pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset) +{ + u16_t offset_left = in_offset; + const struct pbuf *q = in; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= offset_left)) { + offset_left = (u16_t)(offset_left - q->len); + q = q->next; + } + if (out_offset != NULL) { + *out_offset = offset_left; + } + return q; +} + +/** + * @ingroup pbuf + * Skip a number of bytes at the start of a pbuf + * + * @param in input pbuf + * @param in_offset offset to skip + * @param out_offset resulting offset in the returned pbuf + * @return the pbuf in the queue where the offset is + */ +struct pbuf * +pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset) +{ + const struct pbuf *out = pbuf_skip_const(in, in_offset, out_offset); + return LWIP_CONST_CAST(struct pbuf *, out); +} + +/** + * @ingroup pbuf + * Copy application supplied data into a pbuf. + * This function can only be used to copy the equivalent of buf->tot_len data. + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ + struct pbuf *p; + size_t buf_copy_len; + size_t total_copy_len = len; + size_t copied_total = 0; + + LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;); + LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;); + LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;); + + if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { + return ERR_ARG; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for (p = buf; total_copy_len != 0; p = p->next) { + LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); + buf_copy_len = total_copy_len; + if (buf_copy_len > p->len) { + /* this pbuf cannot hold all remaining data */ + buf_copy_len = p->len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(p->payload, &((const char *)dataptr)[copied_total], buf_copy_len); + total_copy_len -= buf_copy_len; + copied_total += buf_copy_len; + } + LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); + return ERR_OK; +} + +/** + * @ingroup pbuf + * Same as pbuf_take() but puts data at an offset + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * @param offset offset in pbuf where to copy dataptr to + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset) +{ + u16_t target_offset; + struct pbuf *q = pbuf_skip(buf, offset, &target_offset); + + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->tot_len >= target_offset + len)) { + u16_t remaining_len = len; + const u8_t *src_ptr = (const u8_t *)dataptr; + /* copy the part that goes into the first pbuf */ + u16_t first_copy_len; + LWIP_ASSERT("check pbuf_skip result", target_offset < q->len); + first_copy_len = (u16_t)LWIP_MIN(q->len - target_offset, len); + MEMCPY(((u8_t *)q->payload) + target_offset, dataptr, first_copy_len); + remaining_len = (u16_t)(remaining_len - first_copy_len); + src_ptr += first_copy_len; + if (remaining_len > 0) { + return pbuf_take(q->next, src_ptr, remaining_len); + } + return ERR_OK; + } + return ERR_MEM; +} + +/** + * @ingroup pbuf + * Creates a single pbuf out of a queue of pbufs. + * + * @remark: Either the source pbuf 'p' is freed by this function or the original + * pbuf 'p' is returned, therefore the caller has to check the result! + * + * @param p the source pbuf + * @param layer pbuf_layer of the new pbuf + * + * @return a new, single pbuf (p->next is NULL) + * or the old pbuf if allocation fails + */ +struct pbuf * +pbuf_coalesce(struct pbuf *p, pbuf_layer layer) +{ + struct pbuf *q; + if (p->next == NULL) { + return p; + } + q = pbuf_clone(layer, PBUF_RAM, p); + if (q == NULL) { + /* @todo: what do we do now? */ + return p; + } + pbuf_free(p); + return q; +} + +/** + * @ingroup pbuf + * Allocates a new pbuf of same length (via pbuf_alloc()) and copies the source + * pbuf into this new pbuf (using pbuf_copy()). + * + * @param layer pbuf_layer of the new pbuf + * @param type this parameter decides how and where the pbuf should be allocated + * (@see pbuf_alloc()) + * @param p the source pbuf + * + * @return a new pbuf or NULL if allocation fails + */ +struct pbuf * +pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p) +{ + struct pbuf *q; + err_t err; + q = pbuf_alloc(layer, p->tot_len, type); + if (q == NULL) { + return NULL; + } + err = pbuf_copy(q, p); + LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); + return q; +} + +#if LWIP_CHECKSUM_ON_COPY +/** + * Copies data into a single pbuf (*not* into a pbuf queue!) and updates + * the checksum while copying + * + * @param p the pbuf to copy data into + * @param start_offset offset of p->payload where to copy the data to + * @param dataptr data to copy into the pbuf + * @param len length of data to copy into the pbuf + * @param chksum pointer to the checksum which is updated + * @return ERR_OK if successful, another error if the data does not fit + * within the (first) pbuf (no pbuf queues!) + */ +err_t +pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum) +{ + u32_t acc; + u16_t copy_chksum; + char *dst_ptr; + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("dataptr != NULL", dataptr != NULL); + LWIP_ASSERT("chksum != NULL", chksum != NULL); + LWIP_ASSERT("len != 0", len != 0); + + if ((start_offset >= p->len) || (start_offset + len > p->len)) { + return ERR_ARG; + } + + dst_ptr = ((char *)p->payload) + start_offset; + copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); + if ((start_offset & 1) != 0) { + copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); + } + acc = *chksum; + acc += copy_chksum; + *chksum = FOLD_U32T(acc); + return ERR_OK; +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + +/** + * @ingroup pbuf + * Get one byte from the specified position in a pbuf + * WARNING: returns zero for offset >= p->tot_len + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len + */ +u8_t +pbuf_get_at(const struct pbuf *p, u16_t offset) +{ + int ret = pbuf_try_get_at(p, offset); + if (ret >= 0) { + return (u8_t)ret; + } + return 0; +} + +/** + * @ingroup pbuf + * Get one byte from the specified position in a pbuf + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len + */ +int +pbuf_try_get_at(const struct pbuf *p, u16_t offset) +{ + u16_t q_idx; + const struct pbuf *q = pbuf_skip_const(p, offset, &q_idx); + + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > q_idx)) { + return ((u8_t *)q->payload)[q_idx]; + } + return -1; +} + +/** + * @ingroup pbuf + * Put one byte to the specified position in a pbuf + * WARNING: silently ignores offset >= p->tot_len + * + * @param p pbuf to fill + * @param offset offset into p of the byte to write + * @param data byte to write at an offset into p + */ +void +pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data) +{ + u16_t q_idx; + struct pbuf *q = pbuf_skip(p, offset, &q_idx); + + /* write requested data if pbuf is OK */ + if ((q != NULL) && (q->len > q_idx)) { + ((u8_t *)q->payload)[q_idx] = data; + } +} + +/** + * @ingroup pbuf + * Compare pbuf contents at specified offset with memory s2, both of length n + * + * @param p pbuf to compare + * @param offset offset into p at which to start comparing + * @param s2 buffer to compare + * @param n length of buffer to compare + * @return zero if equal, nonzero otherwise + * (0xffff if p is too short, diffoffset+1 otherwise) + */ +u16_t +pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n) +{ + u16_t start = offset; + const struct pbuf *q = p; + u16_t i; + + /* pbuf long enough to perform check? */ + if (p->tot_len < (offset + n)) { + return 0xffff; + } + + /* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */ + while ((q != NULL) && (q->len <= start)) { + start = (u16_t)(start - q->len); + q = q->next; + } + + /* return requested data if pbuf is OK */ + for (i = 0; i < n; i++) { + /* We know pbuf_get_at() succeeds because of p->tot_len check above. */ + u8_t a = pbuf_get_at(q, (u16_t)(start + i)); + u8_t b = ((const u8_t *)s2)[i]; + if (a != b) { + return (u16_t)LWIP_MIN(i + 1, 0xFFFF); + } + } + return 0; +} + +/** + * @ingroup pbuf + * Find occurrence of mem (with length mem_len) in pbuf p, starting at offset + * start_offset. + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param mem search for the contents of this buffer + * @param mem_len length of 'mem' + * @param start_offset offset into p at which to start searching + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_memfind(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset) +{ + u16_t i; + u16_t max_cmp_start = (u16_t)(p->tot_len - mem_len); + if (p->tot_len >= mem_len + start_offset) { + for (i = start_offset; i <= max_cmp_start; i++) { + u16_t plus = pbuf_memcmp(p, i, mem, mem_len); + if (plus == 0) { + return i; + } + } + } + return 0xFFFF; +} + +/** + * Find occurrence of substr with length substr_len in pbuf p, start at offset + * start_offset + * WARNING: in contrast to strstr(), this one does not stop at the first \0 in + * the pbuf/source string! + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param substr string to search for in p, maximum length is 0xFFFE + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_strstr(const struct pbuf *p, const char *substr) +{ + size_t substr_len; + if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { + return 0xFFFF; + } + substr_len = strlen(substr); + if (substr_len >= 0xFFFF) { + return 0xFFFF; + } + return pbuf_memfind(p, substr, (u16_t)substr_len, 0); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/raw.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/raw.c new file mode 100644 index 0000000..3b34544 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/raw.c @@ -0,0 +1,671 @@ +/** + * @file + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP.\n + * See also @ref raw_raw + * + * @defgroup raw_raw RAW + * @ingroup callbackstyle_api + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP.\n + * @see @ref api + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" +#include "lwip/priv/raw_priv.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" + +#include + +/** The list of RAW PCBs */ +static struct raw_pcb *raw_pcbs; + +static u8_t +raw_input_local_match(struct raw_pcb *pcb, u8_t broadcast) +{ + LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + return 0; + } + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { +#if IP_SOF_BROADCAST_RECV + if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { + return 0; + } +#endif /* IP_SOF_BROADCAST_RECV */ + return 1; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* Only need to check PCB if incoming IP version matches PCB IP version */ + if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { +#if LWIP_IPV4 + /* Special case: IPv4 broadcast: receive all broadcasts + * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ + if (broadcast != 0) { +#if IP_SOF_BROADCAST_RECV + if (ip_get_option(pcb, SOF_BROADCAST)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) { + return 1; + } + } + } else +#endif /* LWIP_IPV4 */ + /* Handle IPv4 and IPv6: catch all or exact match */ + if (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + return 1; + } + } + + return 0; +} + +/** + * Determine if in incoming IP packet is covered by a RAW PCB + * and if so, pass it to a user-provided receive callback function. + * + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and calls the corresponding receive + * callback function. + * + * @param p pbuf to be demultiplexed to a RAW PCB. + * @param inp network interface on which the datagram was received. + * @return - 1 if the packet has been eaten by a RAW PCB receive + * callback function. The caller MAY NOT not reference the + * packet any longer, and MAY NOT call pbuf_free(). + * @return - 0 if packet is not eaten (pbuf is still referenced by the + * caller). + * + */ +raw_input_state_t +raw_input(struct pbuf *p, struct netif *inp) +{ + struct raw_pcb *pcb, *prev; + s16_t proto; + raw_input_state_t ret = RAW_INPUT_NONE; + u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); + + LWIP_UNUSED_ARG(inp); + +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_HDR_GET_VERSION(p->payload) == 6) +#endif /* LWIP_IPV4 */ + { + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; + proto = IP6H_NEXTH(ip6hdr); + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + proto = IPH_PROTO((struct ip_hdr *)p->payload); + } +#endif /* LWIP_IPV4 */ + + prev = NULL; + pcb = raw_pcbs; + /* loop through all raw pcbs until the packet is eaten by one */ + /* this allows multiple pcbs to match against the packet by design */ + while (pcb != NULL) { + if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && + (((pcb->flags & RAW_FLAGS_CONNECTED) == 0) || + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + /* receive callback function available? */ + if (pcb->recv != NULL) { + u8_t eaten; +#ifndef LWIP_NOASSERT + void *old_payload = p->payload; +#endif + ret = RAW_INPUT_DELIVERED; + /* the receive callback function did not eat the packet? */ + eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()); + if (eaten != 0) { + /* receive function ate the packet */ + p = NULL; + if (prev != NULL) { + /* move the pcb to the front of raw_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + return RAW_INPUT_EATEN; + } else { + /* sanity-check that the receive callback did not alter the pbuf */ + LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", + p->payload == old_payload); + } + } + /* no receive callback function was set for this raw PCB */ + } + /* drop the packet */ + prev = pcb; + pcb = pcb->next; + } + return ret; +} + +/** + * @ingroup raw_raw + * Bind a RAW PCB. + * + * @param pcb RAW PCB to be bound with a local address ipaddr. + * @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to + * bind to all local interfaces. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_USE. The specified IP address is already bound to by + * another RAW PCB. + * + * @see raw_disconnect() + */ +err_t +raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) +{ + LWIP_ASSERT_CORE_LOCKED(); + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now. + * This is legacy support: scope-aware callers should always provide properly + * zoned source addresses. */ + if (IP_IS_V6(&pcb->local_ip) && + ip6_addr_lacks_zone(ip_2_ip6(&pcb->local_ip), IP6_UNKNOWN)) { + ip6_addr_select_zone(ip_2_ip6(&pcb->local_ip), ip_2_ip6(&pcb->local_ip)); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + return ERR_OK; +} + +/** + * @ingroup raw_raw + * Bind an RAW PCB to a specific netif. + * After calling this function, all packets received via this PCB + * are guaranteed to have come in via the specified netif, and all + * outgoing packets will go out via the specified netif. + * + * @param pcb RAW PCB to be bound with netif. + * @param netif netif to bind to. Can be NULL. + * + * @see raw_disconnect() + */ +void +raw_bind_netif(struct raw_pcb *pcb, const struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (netif != NULL) { + pcb->netif_idx = netif_get_index(netif); + } else { + pcb->netif_idx = NETIF_NO_INDEX; + } +} + +/** + * @ingroup raw_raw + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_sendto() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_sendto() + */ +err_t +raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) +{ + LWIP_ASSERT_CORE_LOCKED(); + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now, + * using the bound address to make a more informed decision when possible. */ + if (IP_IS_V6(&pcb->remote_ip) && + ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) { + ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip)); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + raw_set_flags(pcb, RAW_FLAGS_CONNECTED); + return ERR_OK; +} + +/** + * @ingroup raw_raw + * Disconnect a RAW PCB. + * + * @param pcb the raw pcb to disconnect. + */ +void +raw_disconnect(struct raw_pcb *pcb) +{ + LWIP_ASSERT_CORE_LOCKED(); + /* reset remote address association */ +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); + } else { +#endif + ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); +#if LWIP_IPV4 && LWIP_IPV6 + } +#endif + pcb->netif_idx = NETIF_NO_INDEX; + /* mark PCB as unconnected */ + raw_clear_flags(pcb, RAW_FLAGS_CONNECTED); +} + +/** + * @ingroup raw_raw + * Set the callback function for received packets that match the + * raw PCB's protocol and binding. + * + * The callback function MUST either + * - eat the packet by calling pbuf_free() and returning non-zero. The + * packet will not be passed to other raw PCBs or other protocol layers. + * - not free the packet, and return zero. The packet will be matched + * against further PCBs and/or forwarded to another protocol layers. + */ +void +raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) +{ + LWIP_ASSERT_CORE_LOCKED(); + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * @ingroup raw_raw + * Send the raw IP packet to the given address. An IP header will be prepended + * to the packet, unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that + * case, the packet must include an IP header, which will then be sent as is. + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) +{ + struct netif *netif; + const ip_addr_t *src_ip; + + if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { + return ERR_VAL; + } + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); + + if (pcb->netif_idx != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->netif_idx); + } else { +#if LWIP_MULTICAST_TX_OPTIONS + netif = NULL; + if (ip_addr_ismulticast(ipaddr)) { + /* For multicast-destined packets, use the user-provided interface index to + * determine the outgoing interface, if an interface index is set and a + * matching netif can be found. Otherwise, fall back to regular routing. */ + netif = netif_get_by_index(pcb->mcast_ifindex); + } + + if (netif == NULL) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + { + netif = ip_route(&pcb->local_ip, ipaddr); + } + } + + if (netif == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); + ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr); + return ERR_RTE; + } + + if (ip_addr_isany(&pcb->local_ip) || ip_addr_ismulticast(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = ip_netif_get_local_ip(netif, ipaddr); +#if LWIP_IPV6 + if (src_ip == NULL) { + return ERR_RTE; + } +#endif /* LWIP_IPV6 */ + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &pcb->local_ip; + } + + return raw_sendto_if_src(pcb, p, ipaddr, netif, src_ip); +} + +/** + * @ingroup raw_raw + * Send the raw IP packet to the given address, using a particular outgoing + * netif and source IP address. An IP header will be prepended to the packet, + * unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that case, the + * packet must include an IP header, which will then be sent as is. + * + * @param pcb RAW PCB used to send the data + * @param p chain of pbufs to be sent + * @param dst_ip destination IP address + * @param netif the netif used for sending + * @param src_ip source IP address + */ +err_t +raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + struct netif *netif, const ip_addr_t *src_ip) +{ + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + u16_t header_size; + u8_t ttl; + + LWIP_ASSERT_CORE_LOCKED(); + + if ((pcb == NULL) || (dst_ip == NULL) || (netif == NULL) || (src_ip == NULL) || + !IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + + header_size = ( +#if LWIP_IPV4 && LWIP_IPV6 + IP_IS_V6(dst_ip) ? IP6_HLEN : IP_HLEN); +#elif LWIP_IPV4 + IP_HLEN); +#else + IP6_HLEN); +#endif + + /* Handle the HDRINCL option as an exception: none of the code below applies + * to this case, and sending the packet needs to be done differently too. */ + if (pcb->flags & RAW_FLAGS_HDRINCL) { + /* A full header *must* be present in the first pbuf of the chain, as the + * output routines may access its fields directly. */ + if (p->len < header_size) { + return ERR_VAL; + } + /* @todo multicast loop support, if at all desired for this scenario.. */ + NETIF_SET_HINTS(netif, &pcb->netif_hints); + err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif); + NETIF_RESET_HINTS(netif); + return err; + } + + /* packet too large to add an IP header without causing an overflow? */ + if ((u16_t)(p->tot_len + header_size) < p->tot_len) { + return ERR_MEM; + } + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_add_header(p, header_size)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + } + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + if (pbuf_remove_header(q, header_size)) { + LWIP_ASSERT("Can't restore header we just removed!", 0); + return ERR_MEM; + } + } + +#if IP_SOF_BROADCAST + if (IP_IS_V4(dst_ip)) { + /* broadcast filter? */ + if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(dst_ip, netif)) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; + } + } +#endif /* IP_SOF_BROADCAST */ + + /* Multicast Loop? */ +#if LWIP_MULTICAST_TX_OPTIONS + if (((pcb->flags & RAW_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_IPV6 + /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, + compute the checksum and update the checksum in the payload. */ + if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) { + u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip)); + LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); + SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); + } +#endif + + /* Determine TTL to use */ +#if LWIP_MULTICAST_TX_OPTIONS + ttl = (ip_addr_ismulticast(dst_ip) ? raw_get_multicast_ttl(pcb) : pcb->ttl); +#else /* LWIP_MULTICAST_TX_OPTIONS */ + ttl = pcb->ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + NETIF_SET_HINTS(netif, &pcb->netif_hints); + err = ip_output_if(q, src_ip, dst_ip, ttl, pcb->tos, pcb->protocol, netif); + NETIF_RESET_HINTS(netif); + + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * @ingroup raw_raw + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * + */ +err_t +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ + return raw_sendto(pcb, p, &pcb->remote_ip); +} + +/** + * @ingroup raw_raw + * Remove an RAW PCB. + * + * @param pcb RAW PCB to be removed. The PCB is removed from the list of + * RAW PCB's and the data structure is freed from memory. + * + * @see raw_new() + */ +void +raw_remove(struct raw_pcb *pcb) +{ + struct raw_pcb *pcb2; + LWIP_ASSERT_CORE_LOCKED(); + /* pcb to be removed is first in list? */ + if (raw_pcbs == pcb) { + /* make list start at 2nd pcb */ + raw_pcbs = raw_pcbs->next; + /* pcb not 1st in list */ + } else { + for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in raw_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + break; + } + } + } + memp_free(MEMP_RAW_PCB, pcb); +} + +/** + * @ingroup raw_raw + * Create a RAW PCB. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new(u8_t proto) +{ + struct raw_pcb *pcb; + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); + LWIP_ASSERT_CORE_LOCKED(); + + pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); + /* could allocate RAW PCB? */ + if (pcb != NULL) { + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct raw_pcb)); + pcb->protocol = proto; + pcb->ttl = RAW_TTL; +#if LWIP_MULTICAST_TX_OPTIONS + raw_set_multicast_ttl(pcb, RAW_TTL); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + return pcb; +} + +/** + * @ingroup raw_raw + * Create a RAW PCB for specific IP type. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) packets, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @param proto the protocol number (next header) of the IPv6 packet payload + * (e.g. IP6_NEXTH_ICMP6) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new_ip_type(u8_t type, u8_t proto) +{ + struct raw_pcb *pcb; + LWIP_ASSERT_CORE_LOCKED(); + pcb = raw_new(proto); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** This function is called from netif.c when address is changed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change + */ +void raw_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) +{ + struct raw_pcb *rpcb; + + if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { + for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&rpcb->local_ip, old_addr)) { + /* The PCB is bound to the old ipaddr and + * is set to bound to the new one instead */ + ip_addr_copy(rpcb->local_ip, *new_addr); + } + } + } +} + +#endif /* LWIP_RAW */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/stats.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/stats.c new file mode 100644 index 0000000..34e9b27 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/stats.c @@ -0,0 +1,169 @@ +/** + * @file + * Statistics module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/debug.h" + +#include + +struct stats_ lwip_stats; + +void +stats_init(void) +{ +#ifdef LWIP_DEBUG +#if MEM_STATS + lwip_stats.mem.name = "MEM"; +#endif /* MEM_STATS */ +#endif /* LWIP_DEBUG */ +} + +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, const char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); + LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); + LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); + LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); + LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); + LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); +} + +#if IGMP_STATS || MLD6_STATS +void +stats_display_igmp(struct stats_igmp *igmp, const char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); + LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); + LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n\t", igmp->rx_group)); + LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", igmp->rx_general)); + LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); + LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); + LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); + LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n", igmp->tx_report)); +} +#endif /* IGMP_STATS || MLD6_STATS */ + +#if MEM_STATS || MEMP_STATS +void +stats_display_mem(struct stats_mem *mem, const char *name) +{ + LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); + LWIP_PLATFORM_DIAG(("avail: %"MEM_SIZE_F"\n\t", mem->avail)); + LWIP_PLATFORM_DIAG(("used: %"MEM_SIZE_F"\n\t", mem->used)); + LWIP_PLATFORM_DIAG(("max: %"MEM_SIZE_F"\n\t", mem->max)); + LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n", mem->err)); +} + +#if MEMP_STATS +void +stats_display_memp(struct stats_mem *mem, int idx) +{ + if (idx < MEMP_MAX) { + stats_display_mem(mem, mem->name); + } +} +#endif /* MEMP_STATS */ +#endif /* MEM_STATS || MEMP_STATS */ + +#if SYS_STATS +void +stats_display_sys(struct stats_sys *sys) +{ + LWIP_PLATFORM_DIAG(("\nSYS\n\t")); + LWIP_PLATFORM_DIAG(("sem.used: %"STAT_COUNTER_F"\n\t", sys->sem.used)); + LWIP_PLATFORM_DIAG(("sem.max: %"STAT_COUNTER_F"\n\t", sys->sem.max)); + LWIP_PLATFORM_DIAG(("sem.err: %"STAT_COUNTER_F"\n\t", sys->sem.err)); + LWIP_PLATFORM_DIAG(("mutex.used: %"STAT_COUNTER_F"\n\t", sys->mutex.used)); + LWIP_PLATFORM_DIAG(("mutex.max: %"STAT_COUNTER_F"\n\t", sys->mutex.max)); + LWIP_PLATFORM_DIAG(("mutex.err: %"STAT_COUNTER_F"\n\t", sys->mutex.err)); + LWIP_PLATFORM_DIAG(("mbox.used: %"STAT_COUNTER_F"\n\t", sys->mbox.used)); + LWIP_PLATFORM_DIAG(("mbox.max: %"STAT_COUNTER_F"\n\t", sys->mbox.max)); + LWIP_PLATFORM_DIAG(("mbox.err: %"STAT_COUNTER_F"\n", sys->mbox.err)); +} +#endif /* SYS_STATS */ + +void +stats_display(void) +{ + s16_t i; + + LINK_STATS_DISPLAY(); + ETHARP_STATS_DISPLAY(); + IPFRAG_STATS_DISPLAY(); + IP6_FRAG_STATS_DISPLAY(); + IP_STATS_DISPLAY(); + ND6_STATS_DISPLAY(); + IP6_STATS_DISPLAY(); + IGMP_STATS_DISPLAY(); + MLD6_STATS_DISPLAY(); + ICMP_STATS_DISPLAY(); + ICMP6_STATS_DISPLAY(); + UDP_STATS_DISPLAY(); + TCP_STATS_DISPLAY(); + MEM_STATS_DISPLAY(); + for (i = 0; i < MEMP_MAX; i++) { + MEMP_STATS_DISPLAY(i); + } + SYS_STATS_DISPLAY(); +} +#endif /* LWIP_STATS_DISPLAY */ + +#endif /* LWIP_STATS */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/sys.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/sys.c new file mode 100644 index 0000000..5f08352 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/sys.c @@ -0,0 +1,148 @@ +/** + * @file + * lwIP Operating System abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/** + * @defgroup sys_layer Porting (system abstraction layer) + * @ingroup lwip + * + * @defgroup sys_os OS abstraction layer + * @ingroup sys_layer + * No need to implement functions in this section in NO_SYS mode. + * The OS-specific code should be implemented in arch/sys_arch.h + * and sys_arch.c of your port. + * + * The operating system emulation layer provides a common interface + * between the lwIP code and the underlying operating system kernel. The + * general idea is that porting lwIP to new architectures requires only + * small changes to a few header files and a new sys_arch + * implementation. It is also possible to do a sys_arch implementation + * that does not rely on any underlying operating system. + * + * The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full + * lwIP functionality, multiple threads support can be implemented in the + * sys_arch, but this is not required for the basic lwIP + * functionality. Timer scheduling is implemented in lwIP, but can be implemented + * by the sys_arch port (LWIP_TIMERS_CUSTOM==1). + * + * In addition to the source file providing the functionality of sys_arch, + * the OS emulation layer must provide several header files defining + * macros used throughout lwip. The files required and the macros they + * must define are listed below the sys_arch description. + * + * Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that + * allows both using pointers or actual OS structures to be used. This way, memory + * required for such types can be either allocated in place (globally or on the + * stack) or on the heap (allocated internally in the "*_new()" functions). + * + * Note: + * ----- + * Be careful with using mem_malloc() in sys_arch. When malloc() refers to + * mem_malloc() you can run into a circular function call problem. In mem.c + * mem_init() tries to allocate a semaphore using mem_malloc, which of course + * can't be performed when sys_arch uses mem_malloc. + * + * @defgroup sys_sem Semaphores + * @ingroup sys_os + * Semaphores can be either counting or binary - lwIP works with both + * kinds. + * Semaphores are represented by the type "sys_sem_t" which is typedef'd + * in the sys_arch.h file. Mailboxes are equivalently represented by the + * type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t". + * lwIP does not place any restrictions on how these types are represented + * internally. + * + * @defgroup sys_mutex Mutexes + * @ingroup sys_os + * Mutexes are recommended to correctly handle priority inversion, + * especially if you use LWIP_CORE_LOCKING . + * + * @defgroup sys_mbox Mailboxes + * @ingroup sys_os + * Mailboxes should be implemented as a queue which allows multiple messages + * to be posted (implementing as a rendez-vous point where only one message can be + * posted at a time can have a highly negative impact on performance). A message + * in a mailbox is just a pointer, nothing more. + * + * @defgroup sys_time Time + * @ingroup sys_layer + * + * @defgroup sys_prot Critical sections + * @ingroup sys_layer + * Used to protect short regions of code against concurrent access. + * - Your system is a bare-metal system (probably with an RTOS) + * and interrupts are under your control: + * Implement this as LockInterrupts() / UnlockInterrupts() + * - Your system uses an RTOS with deferred interrupt handling from a + * worker thread: Implement as a global mutex or lock/unlock scheduler + * - Your system uses a high-level OS with e.g. POSIX signals: + * Implement as a global mutex + * + * @defgroup sys_misc Misc + * @ingroup sys_os + */ + +#include "lwip/opt.h" + +#include "lwip/sys.h" + +/* Most of the functions defined in sys.h must be implemented in the + * architecture-dependent file sys_arch.c */ + +#if !NO_SYS + +#ifndef sys_msleep +/** + * Sleep for some ms. Timeouts are NOT processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ + if (ms > 0) { + sys_sem_t delaysem; + err_t err = sys_sem_new(&delaysem, 0); + if (err == ERR_OK) { + sys_arch_sem_wait(&delaysem, ms); + sys_sem_free(&delaysem); + } + } +} +#endif /* sys_msleep */ + +#endif /* !NO_SYS */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp.c new file mode 100644 index 0000000..371db2b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp.c @@ -0,0 +1,2690 @@ +/** + * @file + * Transmission Control Protocol for IP + * See also @ref tcp_raw + * + * @defgroup tcp_raw TCP + * @ingroup callbackstyle_api + * Transmission Control Protocol for IP\n + * @see @ref api + * + * Common functions for the TCP implementation, such as functions + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n + * + * TCP connection setup + * -------------------- + * The functions used for setting up connections is similar to that of + * the sequential API and of the BSD socket API. A new TCP connection + * identifier (i.e., a protocol control block - PCB) is created with the + * tcp_new() function. This PCB can then be either set to listen for new + * incoming connections or be explicitly connected to another host. + * - tcp_new() + * - tcp_bind() + * - tcp_listen() and tcp_listen_with_backlog() + * - tcp_accept() + * - tcp_connect() + * + * Sending TCP data + * ---------------- + * TCP data is sent by enqueueing the data with a call to tcp_write() and + * triggering to send by calling tcp_output(). When the data is successfully + * transmitted to the remote host, the application will be notified with a + * call to a specified callback function. + * - tcp_write() + * - tcp_output() + * - tcp_sent() + * + * Receiving TCP data + * ------------------ + * TCP data reception is callback based - an application specified + * callback function is called when new data arrives. When the + * application has taken the data, it has to call the tcp_recved() + * function to indicate that TCP can advertise increase the receive + * window. + * - tcp_recv() + * - tcp_recved() + * + * Application polling + * ------------------- + * When a connection is idle (i.e., no data is either transmitted or + * received), lwIP will repeatedly poll the application by calling a + * specified callback function. This can be used either as a watchdog + * timer for killing connections that have stayed idle for too long, or + * as a method of waiting for memory to become available. For instance, + * if a call to tcp_write() has failed because memory wasn't available, + * the application may use the polling functionality to call tcp_write() + * again when the connection has been idle for a while. + * - tcp_poll() + * + * Closing and aborting connections + * -------------------------------- + * - tcp_close() + * - tcp_abort() + * - tcp_err() + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/nd6.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#ifndef TCP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define TCP_LOCAL_PORT_RANGE_START 0xc000 +#define TCP_LOCAL_PORT_RANGE_END 0xffff +#define TCP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)) +#endif + +#if LWIP_TCP_KEEPALIVE +#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) +#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) +#else /* LWIP_TCP_KEEPALIVE */ +#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE +#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT +#endif /* LWIP_TCP_KEEPALIVE */ + +/* As initial send MSS, we use TCP_MSS but limit it to 536. */ +#if TCP_MSS > 536 +#define INITIAL_MSS 536 +#else +#define INITIAL_MSS TCP_MSS +#endif + +static const char *const tcp_state_str[] = { + "CLOSED", + "LISTEN", + "SYN_SENT", + "SYN_RCVD", + "ESTABLISHED", + "FIN_WAIT_1", + "FIN_WAIT_2", + "CLOSE_WAIT", + "CLOSING", + "LAST_ACK", + "TIME_WAIT" +}; + +/* last local TCP port */ +static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; + +/* Incremented every coarse grained timer shot (typically every 500 ms). */ +u32_t tcp_ticks; +static const u8_t tcp_backoff[13] = +{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; +/* Times per slowtmr hits */ +static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; + +/* The TCP PCB lists. */ + +/** List of all TCP PCBs bound but not yet (connected || listening) */ +struct tcp_pcb *tcp_bound_pcbs; +/** List of all TCP PCBs in LISTEN state */ +union tcp_listen_pcbs_t tcp_listen_pcbs; +/** List of all TCP PCBs that are in a state in which + * they accept or send data. */ +struct tcp_pcb *tcp_active_pcbs; +/** List of all TCP PCBs in TIME-WAIT state */ +struct tcp_pcb *tcp_tw_pcbs; + +/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ +struct tcp_pcb **const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, + &tcp_active_pcbs, &tcp_tw_pcbs +}; + +u8_t tcp_active_pcbs_changed; + +/** Timer counter to handle calling slow-timer from tcp_tmr() */ +static u8_t tcp_timer; +static u8_t tcp_timer_ctr; +static u16_t tcp_new_port(void); + +static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); +#if LWIP_TCP_PCB_NUM_EXT_ARGS +static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); +#endif + +/** + * Initialize this module. + */ +void +tcp_init(void) +{ +#ifdef LWIP_RAND + tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RAND */ +} + +/** Free a tcp pcb */ +void +tcp_free(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN); +#if LWIP_TCP_PCB_NUM_EXT_ARGS + tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); +#endif + memp_free(MEMP_TCP_PCB, pcb); +} + +/** Free a tcp listen pcb */ +static void +tcp_free_listen(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_free_listen: !LISTEN", pcb->state != LISTEN); +#if LWIP_TCP_PCB_NUM_EXT_ARGS + tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); +#endif + memp_free(MEMP_TCP_PCB_LISTEN, pcb); +} + +/** + * Called periodically to dispatch TCP timers. + */ +void +tcp_tmr(void) +{ + /* Call tcp_fasttmr() every 250 ms */ + tcp_fasttmr(); + + if (++tcp_timer & 1) { + /* Call tcp_slowtmr() every 500 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} + +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG +/** Called when a listen pcb is closed. Iterates one pcb list and removes the + * closed listener pcb from pcb->listener if matching. + */ +static void +tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb) +{ + struct tcp_pcb *pcb; + + LWIP_ASSERT("tcp_remove_listener: invalid listener", lpcb != NULL); + + for (pcb = list; pcb != NULL; pcb = pcb->next) { + if (pcb->listener == lpcb) { + pcb->listener = NULL; + } + } +} +#endif + +/** Called when a listen pcb is closed. Iterates all pcb lists and removes the + * closed listener pcb from pcb->listener if matching. + */ +static void +tcp_listen_closed(struct tcp_pcb *pcb) +{ +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + size_t i; + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN); + for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { + tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb); + } +#endif + LWIP_UNUSED_ARG(pcb); +} + +#if TCP_LISTEN_BACKLOG +/** @ingroup tcp_raw + * Delay accepting a connection in respect to the listen backlog: + * the number of outstanding connections is increased until + * tcp_backlog_accepted() is called. + * + * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() + * or else the backlog feature will get out of sync! + * + * @param pcb the connection pcb which is not fully accepted yet + */ +void +tcp_backlog_delayed(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT_CORE_LOCKED(); + if ((pcb->flags & TF_BACKLOGPEND) == 0) { + if (pcb->listener != NULL) { + pcb->listener->accepts_pending++; + LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); + tcp_set_flags(pcb, TF_BACKLOGPEND); + } + } +} + +/** @ingroup tcp_raw + * A delayed-accept a connection is accepted (or closed/aborted): decreases + * the number of outstanding connections after calling tcp_backlog_delayed(). + * + * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() + * or else the backlog feature will get out of sync! + * + * @param pcb the connection pcb which is now fully accepted (or closed/aborted) + */ +void +tcp_backlog_accepted(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT_CORE_LOCKED(); + if ((pcb->flags & TF_BACKLOGPEND) != 0) { + if (pcb->listener != NULL) { + LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); + pcb->listener->accepts_pending--; + tcp_clear_flags(pcb, TF_BACKLOGPEND); + } + } +} +#endif /* TCP_LISTEN_BACKLOG */ + +/** + * Closes the TX side of a connection held by the PCB. + * For tcp_close(), a RST is sent if the application didn't receive all data + * (tcp_recved() not called for all data passed to recv callback). + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +static err_t +tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) +{ + LWIP_ASSERT("tcp_close_shutdown: invalid pcb", pcb != NULL); + + if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { + if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) { + /* Not all data received by application, send RST to tell the remote + side about this. */ + LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); + + /* don't call tcp_abort here: we must not deallocate the pcb since + that might not be expected when calling tcp_close */ + tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + /* Deallocate the pcb since we already sent a RST for it */ + if (tcp_input_pcb == pcb) { + /* prevent using a deallocated pcb: free it from tcp_input later */ + tcp_trigger_input_pcb_close(); + } else { + tcp_free(pcb); + } + return ERR_OK; + } + } + + /* - states which free the pcb are handled here, + - states which send FIN and change state are handled in tcp_close_shutdown_fin() */ + switch (pcb->state) { + case CLOSED: + /* Closing a pcb in the CLOSED state might seem erroneous, + * however, it is in this state once allocated and as yet unused + * and the user needs some way to free it should the need arise. + * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) + * or for a pcb that has been used and then entered the CLOSED state + * is erroneous, but this should never happen as the pcb has in those cases + * been freed, and so any remaining handles are bogus. */ + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + tcp_free(pcb); + break; + case LISTEN: + tcp_listen_closed(pcb); + tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); + tcp_free_listen(pcb); + break; + case SYN_SENT: + TCP_PCB_REMOVE_ACTIVE(pcb); + tcp_free(pcb); + MIB2_STATS_INC(mib2.tcpattemptfails); + break; + default: + return tcp_close_shutdown_fin(pcb); + } + return ERR_OK; +} + +static err_t +tcp_close_shutdown_fin(struct tcp_pcb *pcb) +{ + err_t err; + LWIP_ASSERT("pcb != NULL", pcb != NULL); + + switch (pcb->state) { + case SYN_RCVD: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + tcp_backlog_accepted(pcb); + MIB2_STATS_INC(mib2.tcpattemptfails); + pcb->state = FIN_WAIT_1; + } + break; + case ESTABLISHED: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + MIB2_STATS_INC(mib2.tcpestabresets); + pcb->state = FIN_WAIT_1; + } + break; + case CLOSE_WAIT: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + MIB2_STATS_INC(mib2.tcpestabresets); + pcb->state = LAST_ACK; + } + break; + default: + /* Has already been closed, do nothing. */ + return ERR_OK; + } + + if (err == ERR_OK) { + /* To ensure all data has been sent when tcp_close returns, we have + to make sure tcp_output doesn't fail. + Since we don't really have to ensure all data has been sent when tcp_close + returns (unsent data is sent from tcp timer functions, also), we don't care + for the return value of tcp_output for now. */ + tcp_output(pcb); + } else if (err == ERR_MEM) { + /* Mark this pcb for closing. Closing is retried from tcp_tmr. */ + tcp_set_flags(pcb, TF_CLOSEPEND); + /* We have to return ERR_OK from here to indicate to the callers that this + pcb should not be used any more as it will be freed soon via tcp_tmr. + This is OK here since sending FIN does not guarantee a time frime for + actually freeing the pcb, either (it is left in closure states for + remote ACK or timeout) */ + return ERR_OK; + } + return err; +} + +/** + * @ingroup tcp_raw + * Closes the connection held by the PCB. + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it (unless an error is returned). + * + * The function may return ERR_MEM if no memory + * was available for closing the connection. If so, the application + * should wait and try again either by using the acknowledgment + * callback or the polling functionality. If the close succeeds, the + * function returns ERR_OK. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_close: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); + + tcp_debug_print_state(pcb->state); + + if (pcb->state != LISTEN) { + /* Set a flag not to receive any more data... */ + tcp_set_flags(pcb, TF_RXCLOSED); + } + /* ... and close */ + return tcp_close_shutdown(pcb, 1); +} + +/** + * @ingroup tcp_raw + * Causes all or part of a full-duplex connection of this PCB to be shut down. + * This doesn't deallocate the PCB unless shutting down both sides! + * Shutting down both sides is the same as calling tcp_close, so if it succeds + * (i.e. returns ER_OK), the PCB must not be referenced any more! + * + * @param pcb PCB to shutdown + * @param shut_rx shut down receive side if this is != 0 + * @param shut_tx shut down send side if this is != 0 + * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) + * another err_t on error. + */ +err_t +tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_shutdown: invalid pcb", pcb != NULL, return ERR_ARG); + + if (pcb->state == LISTEN) { + return ERR_CONN; + } + if (shut_rx) { + /* shut down the receive side: set a flag not to receive any more data... */ + tcp_set_flags(pcb, TF_RXCLOSED); + if (shut_tx) { + /* shutting down the tx AND rx side is the same as closing for the raw API */ + return tcp_close_shutdown(pcb, 1); + } + /* ... and free buffered data */ + if (pcb->refused_data != NULL) { + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + } + if (shut_tx) { + /* This can't happen twice since if it succeeds, the pcb's state is changed. + Only close in these states as the others directly deallocate the PCB */ + switch (pcb->state) { + case SYN_RCVD: + case ESTABLISHED: + case CLOSE_WAIT: + return tcp_close_shutdown(pcb, (u8_t)shut_rx); + default: + /* Not (yet?) connected, cannot shutdown the TX side as that would bring us + into CLOSED state, where the PCB is deallocated. */ + return ERR_CONN; + } + } + return ERR_OK; +} + +/** + * Abandons a connection and optionally sends a RST to the remote + * host. Deletes the local protocol control block. This is done when + * a connection is killed because of shortage of memory. + * + * @param pcb the tcp_pcb to abort + * @param reset boolean to indicate whether a reset should be sent + */ +void +tcp_abandon(struct tcp_pcb *pcb, int reset) +{ + u32_t seqno, ackno; +#if LWIP_CALLBACK_API + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + void *errf_arg; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_abandon: invalid pcb", pcb != NULL, return); + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", + pcb->state != LISTEN); + /* Figure out on which TCP PCB list we are, and remove us. If we + are in an active state, call the receive function associated with + the PCB with a NULL argument, and send an RST to the remote end. */ + if (pcb->state == TIME_WAIT) { + tcp_pcb_remove(&tcp_tw_pcbs, pcb); + tcp_free(pcb); + } else { + int send_rst = 0; + u16_t local_port = 0; + enum tcp_state last_state; + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + if (pcb->state == CLOSED) { + if (pcb->local_port != 0) { + /* bound, not yet opened */ + TCP_RMV(&tcp_bound_pcbs, pcb); + } + } else { + send_rst = reset; + local_port = pcb->local_port; + TCP_PCB_REMOVE_ACTIVE(pcb); + } + if (pcb->unacked != NULL) { + tcp_segs_free(pcb->unacked); + } + if (pcb->unsent != NULL) { + tcp_segs_free(pcb->unsent); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + tcp_segs_free(pcb->ooseq); + } +#endif /* TCP_QUEUE_OOSEQ */ + tcp_backlog_accepted(pcb); + if (send_rst) { + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); + tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); + } + last_state = pcb->state; + tcp_free(pcb); + TCP_EVENT_ERR(last_state, errf, errf_arg, ERR_ABRT); + } +} + +/** + * @ingroup tcp_raw + * Aborts the connection by sending a RST (reset) segment to the remote + * host. The pcb is deallocated. This function never fails. + * + * ATTENTION: When calling this from one of the TCP callbacks, make + * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + * or you will risk accessing deallocated memory or memory leaks! + * + * @param pcb the tcp pcb to abort + */ +void +tcp_abort(struct tcp_pcb *pcb) +{ + tcp_abandon(pcb, 1); +} + +/** + * @ingroup tcp_raw + * Binds the connection to a local port number and IP address. If the + * IP address is not given (i.e., ipaddr == IP_ANY_TYPE), the connection is + * bound to all local IP addresses. + * If another connection is bound to the same port, the function will + * return ERR_USE, otherwise ERR_OK is returned. + * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB + * + * @param pcb the tcp_pcb to bind (no check is done whether this pcb is + * already bound!) + * @param ipaddr the local ip address to bind to (use IPx_ADDR_ANY to bind + * to any local address + * @param port the local port to bind to + * @return ERR_USE if the port is already in use + * ERR_VAL if bind failed because the PCB is not in a valid state + * ERR_OK if bound + */ +err_t +tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + int i; + int max_pcb_list = NUM_TCP_PCB_LISTS; + struct tcp_pcb *cpcb; +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + ip_addr_t zoned_ipaddr; +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY; + } +#else /* LWIP_IPV4 */ + LWIP_ERROR("tcp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); +#endif /* LWIP_IPV4 */ + + LWIP_ERROR("tcp_bind: invalid pcb", pcb != NULL, return ERR_ARG); + + LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); + +#if SO_REUSE + /* Unless the REUSEADDR flag is set, + we have to check the pcbs in TIME-WAIT state, also. + We do not dump TIME_WAIT pcb's; they can still be matched by incoming + packets using both local and remote IP addresses and ports to distinguish. + */ + if (ip_get_option(pcb, SOF_REUSEADDR)) { + max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; + } +#endif /* SO_REUSE */ + +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now. + * This is legacy support: scope-aware callers should always provide properly + * zoned source addresses. Do the zone selection before the address-in-use + * check below; as such we have to make a temporary copy of the address. */ + if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNICAST)) { + ip_addr_copy(zoned_ipaddr, *ipaddr); + ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); + ipaddr = &zoned_ipaddr; + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + if (port == 0) { + port = tcp_new_port(); + if (port == 0) { + return ERR_BUF; + } + } else { + /* Check if the address already is in use (on all lists) */ + for (i = 0; i < max_pcb_list; i++) { + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { +#if SO_REUSE + /* Omit checking for the same port if both pcbs have REUSEADDR set. + For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in + tcp_connect. */ + if (!ip_get_option(pcb, SOF_REUSEADDR) || + !ip_get_option(cpcb, SOF_REUSEADDR)) +#endif /* SO_REUSE */ + { + /* @todo: check accept_any_ip_version */ + if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && + (ip_addr_isany(&cpcb->local_ip) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&cpcb->local_ip, ipaddr))) { + return ERR_USE; + } + } + } + } + } + } + + if (!ip_addr_isany(ipaddr) +#if LWIP_IPV4 && LWIP_IPV6 + || (IP_GET_TYPE(ipaddr) != IP_GET_TYPE(&pcb->local_ip)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + ) { + ip_addr_set(&pcb->local_ip, ipaddr); + } + pcb->local_port = port; + TCP_REG(&tcp_bound_pcbs, pcb); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); + return ERR_OK; +} + +/** + * @ingroup tcp_raw + * Binds the connection to a netif and IP address. + * After calling this function, all packets received via this PCB + * are guaranteed to have come in via the specified netif, and all + * outgoing packets will go out via the specified netif. + * + * @param pcb the tcp_pcb to bind. + * @param netif the netif to bind to. Can be NULL. + */ +void +tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (netif != NULL) { + pcb->netif_idx = netif_get_index(netif); + } else { + pcb->netif_idx = NETIF_NO_INDEX; + } +} + +#if LWIP_CALLBACK_API +/** + * Default accept callback if no accept callback is specified by the user. + */ +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + LWIP_ASSERT("tcp_accept_null: invalid pcb", pcb != NULL); + + tcp_abort(pcb); + + return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * @ingroup tcp_raw + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * When an incoming connection is accepted, the function specified with + * the tcp_accept() function will be called. The pcb has to be bound + * to a local port with the tcp_bind() function. + * + * The tcp_listen() function returns a new connection identifier, and + * the one passed as an argument to the function will be + * deallocated. The reason for this behavior is that less memory is + * needed for a connection that is listening, so tcp_listen() will + * reclaim the memory needed for the original connection and allocate a + * new smaller memory block for the listening connection. + * + * tcp_listen() may return NULL if no memory was available for the + * listening connection. If so, the memory associated with the pcb + * passed as an argument to tcp_listen() will not be deallocated. + * + * The backlog limits the number of outstanding connections + * in the listen queue to the value specified by the backlog argument. + * To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen_with_backlog(tpcb, backlog); + */ +struct tcp_pcb * +tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + LWIP_ASSERT_CORE_LOCKED(); + return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); +} + +/** + * @ingroup tcp_raw + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @param err when NULL is returned, this contains the error reason + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); + */ +struct tcp_pcb * +tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) +{ + struct tcp_pcb_listen *lpcb = NULL; + err_t res; + + LWIP_UNUSED_ARG(backlog); + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_listen_with_backlog_and_err: invalid pcb", pcb != NULL, res = ERR_ARG; goto done); + LWIP_ERROR("tcp_listen_with_backlog_and_err: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); + + /* already listening? */ + if (pcb->state == LISTEN) { + lpcb = (struct tcp_pcb_listen *)pcb; + res = ERR_ALREADY; + goto done; + } +#if SO_REUSE + if (ip_get_option(pcb, SOF_REUSEADDR)) { + /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage + is declared (listen-/connection-pcb), we have to make sure now that + this port is only used once for every local IP. */ + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((lpcb->local_port == pcb->local_port) && + ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + /* this address/port is already used */ + lpcb = NULL; + res = ERR_USE; + goto done; + } + } + } +#endif /* SO_REUSE */ + lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); + if (lpcb == NULL) { + res = ERR_MEM; + goto done; + } + lpcb->callback_arg = pcb->callback_arg; + lpcb->local_port = pcb->local_port; + lpcb->state = LISTEN; + lpcb->prio = pcb->prio; + lpcb->so_options = pcb->so_options; + lpcb->netif_idx = pcb->netif_idx; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; +#if LWIP_IPV4 && LWIP_IPV6 + IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + ip_addr_copy(lpcb->local_ip, pcb->local_ip); + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } +#if LWIP_TCP_PCB_NUM_EXT_ARGS + /* copy over ext_args to listening pcb */ + memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args)); +#endif + tcp_free(pcb); +#if LWIP_CALLBACK_API + lpcb->accept = tcp_accept_null; +#endif /* LWIP_CALLBACK_API */ +#if TCP_LISTEN_BACKLOG + lpcb->accepts_pending = 0; + tcp_backlog_set(lpcb, backlog); +#endif /* TCP_LISTEN_BACKLOG */ + TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); + res = ERR_OK; +done: + if (err != NULL) { + *err = res; + } + return (struct tcp_pcb *)lpcb; +} + +/** + * Update the state that tracks the available window space to advertise. + * + * Returns how much extra window would be advertised if we sent an + * update now. + */ +u32_t +tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) +{ + u32_t new_right_edge; + + LWIP_ASSERT("tcp_update_rcv_ann_wnd: invalid pcb", pcb != NULL); + new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; + + if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { + /* we can advertise more window */ + pcb->rcv_ann_wnd = pcb->rcv_wnd; + return new_right_edge - pcb->rcv_ann_right_edge; + } else { + if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { + /* Can happen due to other end sending out of advertised window, + * but within actual available (but not yet advertised) window */ + pcb->rcv_ann_wnd = 0; + } else { + /* keep the right edge of window constant */ + u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; +#if !LWIP_WND_SCALE + LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); +#endif + pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; + } + return 0; + } +} + +/** + * @ingroup tcp_raw + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + * + * @param pcb the tcp_pcb for which data is read + * @param len the amount of bytes that have been read by the application + */ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ + u32_t wnd_inflation; + tcpwnd_size_t rcv_wnd; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_recved: invalid pcb", pcb != NULL, return); + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_recved for listen-pcbs", + pcb->state != LISTEN); + + rcv_wnd = (tcpwnd_size_t)(pcb->rcv_wnd + len); + if ((rcv_wnd > TCP_WND_MAX(pcb)) || (rcv_wnd < pcb->rcv_wnd)) { + /* window got too big or tcpwnd_size_t overflow */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: window got too big or tcpwnd_size_t overflow\n")); + pcb->rcv_wnd = TCP_WND_MAX(pcb); + } else { + pcb->rcv_wnd = rcv_wnd; + } + + wnd_inflation = tcp_update_rcv_ann_wnd(pcb); + + /* If the change in the right edge of window is significant (default + * watermark is TCP_WND/4), then send an explicit update now. + * Otherwise wait for a packet to be sent in the normal course of + * events (or more window to be available later) */ + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { + tcp_ack_now(pcb); + tcp_output(pcb); + } + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F").\n", + len, pcb->rcv_wnd, (u16_t)(TCP_WND_MAX(pcb) - pcb->rcv_wnd))); +} + +/** + * Allocate a new local TCP port. + * + * @return a new (free) local TCP port number + */ +static u16_t +tcp_new_port(void) +{ + u8_t i; + u16_t n = 0; + struct tcp_pcb *pcb; + +again: + tcp_port++; + if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { + tcp_port = TCP_LOCAL_PORT_RANGE_START; + } + /* Check all PCB lists. */ + for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { + for (pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == tcp_port) { + n++; + if (n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + } + return tcp_port; +} + +/** + * @ingroup tcp_raw + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + * Sets up the pcb to connect to the remote host and sends the + * initial SYN segment which opens the connection. + * + * The tcp_connect() function returns immediately; it does not wait for + * the connection to be properly setup. Instead, it will call the + * function specified as the fourth argument (the "connected" argument) + * when the connection is established. If the connection could not be + * properly established, either because the other host refused the + * connection or because the other host didn't answer, the "err" + * callback function of this pcb (registered with tcp_err, see below) + * will be called. + * + * The tcp_connect() function can return ERR_MEM if no memory is + * available for enqueueing the SYN segment. If the SYN indeed was + * enqueued successfully, the tcp_connect() function returns ERR_OK. + * + * @param pcb the tcp_pcb used to establish the connection + * @param ipaddr the remote ip address to connect to + * @param port the remote tcp port to connect to + * @param connected callback function to call when connected (on error, + the err calback will be called) + * @return ERR_VAL if invalid arguments are given + * ERR_OK if connect request has been sent + * other err_t values if connect request couldn't be sent + */ +err_t +tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, + tcp_connected_fn connected) +{ + struct netif *netif = NULL; + err_t ret; + u32_t iss; + u16_t old_local_port; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_connect: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("tcp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); + + LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); + ip_addr_set(&pcb->remote_ip, ipaddr); + pcb->remote_port = port; + + if (pcb->netif_idx != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->netif_idx); + } else { + /* check if we have a route to the remote host */ + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + } + if (netif == NULL) { + /* Don't even try to send a SYN packet if we have no route since that will fail. */ + return ERR_RTE; + } + + /* check if local IP has been assigned to pcb, if not, get one */ + if (ip_addr_isany(&pcb->local_ip)) { + const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, ipaddr); + if (local_ip == NULL) { + return ERR_RTE; + } + ip_addr_copy(pcb->local_ip, *local_ip); + } + +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now. + * Given that we already have the target netif, this is easy and cheap. */ + if (IP_IS_V6(&pcb->remote_ip) && + ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST)) { + ip6_addr_assign_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST, netif); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + old_local_port = pcb->local_port; + if (pcb->local_port == 0) { + pcb->local_port = tcp_new_port(); + if (pcb->local_port == 0) { + return ERR_BUF; + } + } else { +#if SO_REUSE + if (ip_get_option(pcb, SOF_REUSEADDR)) { + /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure + now that the 5-tuple is unique. */ + struct tcp_pcb *cpcb; + int i; + /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ + for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if ((cpcb->local_port == pcb->local_port) && + (cpcb->remote_port == port) && + ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && + ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { + /* linux returns EISCONN here, but ERR_USE should be OK for us */ + return ERR_USE; + } + } + } + } +#endif /* SO_REUSE */ + } + + iss = tcp_next_iss(pcb); + pcb->rcv_nxt = 0; + pcb->snd_nxt = iss; + pcb->lastack = iss - 1; + pcb->snd_wl2 = iss - 1; + pcb->snd_lbb = iss - 1; + /* Start with a window that does not need scaling. When window scaling is + enabled and used, the window is enlarged when both sides agree on scaling. */ + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->snd_wnd = TCP_WND; + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = INITIAL_MSS; +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss_netif(pcb->mss, netif, &pcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + pcb->cwnd = 1; +#if LWIP_CALLBACK_API + pcb->connected = connected; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(connected); +#endif /* LWIP_CALLBACK_API */ + + /* Send a SYN together with the MSS option. */ + ret = tcp_enqueue_flags(pcb, TCP_SYN); + if (ret == ERR_OK) { + /* SYN segment was enqueued, changed the pcbs state now */ + pcb->state = SYN_SENT; + if (old_local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + TCP_REG_ACTIVE(pcb); + MIB2_STATS_INC(mib2.tcpactiveopens); + + tcp_output(pcb); + } + return ret; +} + +/** + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_slowtmr(void) +{ + struct tcp_pcb *pcb, *prev; + tcpwnd_size_t eff_wnd; + u8_t pcb_remove; /* flag if a PCB should be removed */ + u8_t pcb_reset; /* flag if a RST should be sent when removing */ + err_t err; + + err = ERR_OK; + + ++tcp_ticks; + ++tcp_timer_ctr; + +tcp_slowtmr_start: + /* Steps through all of the active PCBs. */ + prev = NULL; + pcb = tcp_active_pcbs; + if (pcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); + } + while (pcb != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + if (pcb->last_timer == tcp_timer_ctr) { + /* skip this pcb, we have already processed it */ + prev = pcb; + pcb = pcb->next; + continue; + } + pcb->last_timer = tcp_timer_ctr; + + pcb_remove = 0; + pcb_reset = 0; + + if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); + } else if (pcb->nrtx >= TCP_MAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); + } else { + if (pcb->persist_backoff > 0) { + LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); + LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); + if (pcb->persist_probe >= TCP_MAXRTX) { + ++pcb_remove; /* max probes reached */ + } else { + u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; + if (pcb->persist_cnt < backoff_cnt) { + pcb->persist_cnt++; + } + if (pcb->persist_cnt >= backoff_cnt) { + int next_slot = 1; /* increment timer to next slot */ + /* If snd_wnd is zero, send 1 byte probes */ + if (pcb->snd_wnd == 0) { + if (tcp_zero_window_probe(pcb) != ERR_OK) { + next_slot = 0; /* try probe again with current slot */ + } + /* snd_wnd not fully closed, split unsent head and fill window */ + } else { + if (tcp_split_unsent_seg(pcb, (u16_t)pcb->snd_wnd) == ERR_OK) { + if (tcp_output(pcb) == ERR_OK) { + /* sending will cancel persist timer, else retry with current slot */ + next_slot = 0; + } + } + } + if (next_slot) { + pcb->persist_cnt = 0; + if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { + pcb->persist_backoff++; + } + } + } + } + } else { + /* Increase the retransmission timer if it is running */ + if ((pcb->rtime >= 0) && (pcb->rtime < 0x7FFF)) { + ++pcb->rtime; + } + + if (pcb->rtime >= pcb->rto) { + /* Time for a retransmission. */ + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F + " pcb->rto %"S16_F"\n", + pcb->rtime, pcb->rto)); + /* If prepare phase fails but we have unsent data but no unacked data, + still execute the backoff calculations below, as this means we somehow + failed to send segment. */ + if ((tcp_rexmit_rto_prepare(pcb) == ERR_OK) || ((pcb->unacked == NULL) && (pcb->unsent != NULL))) { + /* Double retransmission time-out unless we are trying to + * connect to somebody (i.e., we are in SYN_SENT). */ + if (pcb->state != SYN_SENT) { + u8_t backoff_idx = LWIP_MIN(pcb->nrtx, sizeof(tcp_backoff) - 1); + int calc_rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[backoff_idx]; + pcb->rto = (s16_t)LWIP_MIN(calc_rto, 0x7FFF); + } + + /* Reset the retransmission timer. */ + pcb->rtime = 0; + + /* Reduce congestion window and ssthresh. */ + eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); + pcb->ssthresh = eff_wnd >> 1; + if (pcb->ssthresh < (tcpwnd_size_t)(pcb->mss << 1)) { + pcb->ssthresh = (tcpwnd_size_t)(pcb->mss << 1); + } + pcb->cwnd = pcb->mss; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + pcb->bytes_acked = 0; + + /* The following needs to be called AFTER cwnd is set to one + mss - STJ */ + tcp_rexmit_rto_commit(pcb); + } + } + } + } + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if (pcb->state == FIN_WAIT_2) { + /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ + if (pcb->flags & TF_RXCLOSED) { + /* PCB was fully closed (either through close() or SHUT_RDWR): + normal FIN-WAIT timeout handling. */ + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); + } + } + } + + /* Check if KEEPALIVE should be sent */ + if (ip_get_option(pcb, SOF_KEEPALIVE) && + ((pcb->state == ESTABLISHED) || + (pcb->state == CLOSE_WAIT))) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); + ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + ++pcb_remove; + ++pcb_reset; + } else if ((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) + / TCP_SLOW_INTERVAL) { + err = tcp_keepalive(pcb); + if (err == ERR_OK) { + pcb->keep_cnt_sent++; + } + } + } + + /* If this PCB has queued out of sequence data, but has been + inactive for too long, will drop the data (it will eventually + be retransmitted). */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL && + (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); + tcp_free_ooseq(pcb); + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if (pcb->state == SYN_RCVD) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); + } + } + + /* Check if this PCB has stayed too long in LAST-ACK */ + if (pcb->state == LAST_ACK) { + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); + } + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; +#if LWIP_CALLBACK_API + tcp_err_fn err_fn = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + void *err_arg; + enum tcp_state last_state; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + if (pcb_reset) { + tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + } + + err_arg = pcb->callback_arg; + last_state = pcb->state; + pcb2 = pcb; + pcb = pcb->next; + tcp_free(pcb2); + + tcp_active_pcbs_changed = 0; + TCP_EVENT_ERR(last_state, err_fn, err_arg, ERR_ABRT); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + } else { + /* get the 'next' element now and work with 'prev' below (in case of abort) */ + prev = pcb; + pcb = pcb->next; + + /* We check if we should poll the connection. */ + ++prev->polltmr; + if (prev->polltmr >= prev->pollinterval) { + prev->polltmr = 0; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + tcp_active_pcbs_changed = 0; + TCP_EVENT_POLL(prev, err); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + /* if err == ERR_ABRT, 'prev' is already deallocated */ + if (err == ERR_OK) { + tcp_output(prev); + } + } + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while (pcb != NULL) { + LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb; + pcb = pcb->next; + tcp_free(pcb2); + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs or pending FINs. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb; + + ++tcp_timer_ctr; + +tcp_fasttmr_start: + pcb = tcp_active_pcbs; + + while (pcb != NULL) { + if (pcb->last_timer != tcp_timer_ctr) { + struct tcp_pcb *next; + pcb->last_timer = tcp_timer_ctr; + /* send delayed ACKs */ + if (pcb->flags & TF_ACK_DELAY) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + tcp_output(pcb); + tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); + } + /* send pending FIN */ + if (pcb->flags & TF_CLOSEPEND) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); + tcp_clear_flags(pcb, TF_CLOSEPEND); + tcp_close_shutdown_fin(pcb); + } + + next = pcb->next; + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + tcp_active_pcbs_changed = 0; + tcp_process_refused_data(pcb); + if (tcp_active_pcbs_changed) { + /* application callback has changed the pcb list: restart the loop */ + goto tcp_fasttmr_start; + } + } + pcb = next; + } else { + pcb = pcb->next; + } + } +} + +/** Call tcp_output for all active pcbs that have TF_NAGLEMEMERR set */ +void +tcp_txnow(void) +{ + struct tcp_pcb *pcb; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->flags & TF_NAGLEMEMERR) { + tcp_output(pcb); + } + } +} + +/** Pass pcb->refused_data to the recv callback */ +err_t +tcp_process_refused_data(struct tcp_pcb *pcb) +{ +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + struct pbuf *rest; +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + + LWIP_ERROR("tcp_process_refused_data: invalid pcb", pcb != NULL, return ERR_ARG); + +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + while (pcb->refused_data != NULL) +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + { + err_t err; + u8_t refused_flags = pcb->refused_data->flags; + /* set pcb->refused_data to NULL in case the callback frees it and then + closes the pcb */ + struct pbuf *refused_data = pcb->refused_data; +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + pbuf_split_64k(refused_data, &rest); + pcb->refused_data = rest; +#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = NULL; +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + /* Notify again application with data previously received. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); + TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); + if (err == ERR_OK) { + /* did refused_data include a FIN? */ + if ((refused_flags & PBUF_FLAG_TCP_FIN) +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + && (rest == NULL) +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + ) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + } + } else if (err == ERR_ABRT) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + /* Drop incoming packets because pcb is "full" (only if the incoming + segment contains data). */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); + return ERR_ABRT; + } else { + /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_cat(refused_data, rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = refused_data; + return ERR_INPROGRESS; + } + } + return ERR_OK; +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + * @param seg tcp_seg list of TCP segments to free + */ +void +tcp_segs_free(struct tcp_seg *seg) +{ + while (seg != NULL) { + struct tcp_seg *next = seg->next; + tcp_seg_free(seg); + seg = next; + } +} + +/** + * Frees a TCP segment (tcp_seg structure). + * + * @param seg single tcp_seg to free + */ +void +tcp_seg_free(struct tcp_seg *seg) +{ + if (seg != NULL) { + if (seg->p != NULL) { + pbuf_free(seg->p); +#if TCP_DEBUG + seg->p = NULL; +#endif /* TCP_DEBUG */ + } + memp_free(MEMP_TCP_SEG, seg); + } +} + +/** + * @ingroup tcp + * Sets the priority of a connection. + * + * @param pcb the tcp_pcb to manipulate + * @param prio new priority + */ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_setprio: invalid pcb", pcb != NULL, return); + + pcb->prio = prio; +} + +#if TCP_QUEUE_OOSEQ +/** + * Returns a copy of the given TCP segment. + * The pbuf and data are not copied, only the pointers + * + * @param seg the old tcp_seg + * @return a copy of seg + */ +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ + struct tcp_seg *cseg; + + LWIP_ASSERT("tcp_seg_copy: invalid seg", seg != NULL); + + cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); + if (cseg == NULL) { + return NULL; + } + SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); + pbuf_ref(cseg->p); + return cseg; +} +#endif /* TCP_QUEUE_OOSEQ */ + +#if LWIP_CALLBACK_API +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + + LWIP_ERROR("tcp_recv_null: invalid pcb", pcb != NULL, return ERR_ARG); + + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } else if (err == ERR_OK) { + return tcp_close(pcb); + } + return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Kills the oldest active connection that has a lower priority than 'prio'. + * + * @param prio minimum priority + */ +static void +tcp_kill_prio(u8_t prio) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + u8_t mprio; + + mprio = LWIP_MIN(TCP_PRIO_MAX, prio); + + /* We want to kill connections with a lower prio, so bail out if + * supplied prio is 0 - there can never be a lower prio + */ + if (mprio == 0) { + return; + } + + /* We only want kill connections with a lower prio, so decrement prio by one + * and start searching for oldest connection with same or lower priority than mprio. + * We want to find the connections with the lowest possible prio, and among + * these the one with the longest inactivity time. + */ + mprio--; + + inactivity = 0; + inactive = NULL; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + /* lower prio is always a kill candidate */ + if ((pcb->prio < mprio) || + /* longer inactivity is also a kill candidate */ + ((pcb->prio == mprio) && ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity))) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + mprio = pcb->prio; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/** + * Kills the oldest connection that is in specific state. + * Called from tcp_alloc() for LAST_ACK and CLOSING if no more connections are available. + */ +static void +tcp_kill_state(enum tcp_state state) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + LWIP_ASSERT("invalid state", (state == CLOSING) || (state == LAST_ACK)); + + inactivity = 0; + inactive = NULL; + /* Go through the list of active pcbs and get the oldest pcb that is in state + CLOSING/LAST_ACK. */ + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == state) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", + tcp_state_str[state], (void *)inactive, inactivity)); + /* Don't send a RST, since no data is lost. */ + tcp_abandon(inactive, 0); + } +} + +/** + * Kills the oldest connection that is in TIME_WAIT state. + * Called from tcp_alloc() if no more connections are available. + */ +static void +tcp_kill_timewait(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/* Called when allocating a pcb fails. + * In this case, we want to handle all pcbs that want to close first: if we can + * now send the FIN (which failed before), the pcb might be in a state that is + * OK for us to now free it. + */ +static void +tcp_handle_closepend(void) +{ + struct tcp_pcb *pcb = tcp_active_pcbs; + + while (pcb != NULL) { + struct tcp_pcb *next = pcb->next; + /* send pending FIN */ + if (pcb->flags & TF_CLOSEPEND) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_handle_closepend: pending FIN\n")); + tcp_clear_flags(pcb, TF_CLOSEPEND); + tcp_close_shutdown_fin(pcb); + } + pcb = next; + } +} + +/** + * Allocate a new tcp_pcb structure. + * + * @param prio priority for the new pcb + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + + LWIP_ASSERT_CORE_LOCKED(); + + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try to send FIN for all pcbs stuck in TF_CLOSEPEND first */ + tcp_handle_closepend(); + + /* Try killing oldest connection in TIME-WAIT. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); + tcp_kill_timewait(); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in LAST-ACK (these wouldn't go to TIME-WAIT). */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest LAST-ACK connection\n")); + tcp_kill_state(LAST_ACK); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in CLOSING. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest CLOSING connection\n")); + tcp_kill_state(CLOSING); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest active connection with lower priority than the new one. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing oldest connection with prio lower than %d\n", prio)); + tcp_kill_prio(prio); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed above */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* zero out the whole pcb, so there is no need to initialize members to zero */ + memset(pcb, 0, sizeof(struct tcp_pcb)); + pcb->prio = prio; + pcb->snd_buf = TCP_SND_BUF; + /* Start with a window that does not need scaling. When window scaling is + enabled and used, the window is enlarged when both sides agree on scaling. */ + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->ttl = TCP_TTL; + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = INITIAL_MSS; + pcb->rto = 3000 / TCP_SLOW_INTERVAL; + pcb->sv = 3000 / TCP_SLOW_INTERVAL; + pcb->rtime = -1; + pcb->cwnd = 1; + pcb->tmr = tcp_ticks; + pcb->last_timer = tcp_timer_ctr; + + /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example + of using the largest advertised receive window. We've seen complications with + receiving TCPs that use window scaling and/or window auto-tuning where the + initial advertised window is very small and then grows rapidly once the + connection is established. To avoid these complications, we set ssthresh to the + largest effective cwnd (amount of in-flight data) that the sender can have. */ + pcb->ssthresh = TCP_SND_BUF; + +#if LWIP_CALLBACK_API + pcb->recv = tcp_recv_null; +#endif /* LWIP_CALLBACK_API */ + + /* Init KEEPALIVE timer */ + pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; + +#if LWIP_TCP_KEEPALIVE + pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; + pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; +#endif /* LWIP_TCP_KEEPALIVE */ + } + return pcb; +} + +/** + * @ingroup tcp_raw + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * If memory is not available for creating the new pcb, NULL is returned. + * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB + * + * @internal: Maybe there should be a idle TCP PCB list where these + * PCBs are put on. Port reservation using tcp_bind() is implemented but + * allocated pcbs that are not bound can't be killed automatically if wanting + * to allocate a pcb with higher prio (@see tcp_kill_prio()) + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new(void) +{ + return tcp_alloc(TCP_PRIO_NORMAL); +} + +/** + * @ingroup tcp_raw + * Creates a new TCP protocol control block but doesn't + * place it on any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) connections, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new_ip_type(u8_t type) +{ + struct tcp_pcb *pcb; + pcb = tcp_alloc(TCP_PRIO_NORMAL); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** + * @ingroup tcp_raw + * Specifies the program specific state that should be passed to all + * other callback functions. The "pcb" argument is the current TCP + * connection control block, and the "arg" argument is the argument + * that will be passed to the callbacks. + * + * @param pcb tcp_pcb to set the callback argument + * @param arg void pointer argument to pass to callback functions + */ +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{ + LWIP_ASSERT_CORE_LOCKED(); + /* This function is allowed to be called for both listen pcbs and + connection pcbs. */ + if (pcb != NULL) { + pcb->callback_arg = arg; + } +} +#if LWIP_CALLBACK_API + +/** + * @ingroup tcp_raw + * Sets the callback function that will be called when new data + * arrives. The callback function will be passed a NULL pbuf to + * indicate that the remote host has closed the connection. If the + * callback function returns ERR_OK or ERR_ABRT it must have + * freed the pbuf, otherwise it must not have freed it. + * + * @param pcb tcp_pcb to set the recv callback + * @param recv callback function to call for this pcb when data is received + */ +void +tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); + pcb->recv = recv; + } +} + +/** + * @ingroup tcp_raw + * Specifies the callback function that should be called when data has + * successfully been received (i.e., acknowledged) by the remote + * host. The len argument passed to the callback function gives the + * amount bytes that was acknowledged by the last acknowledgment. + * + * @param pcb tcp_pcb to set the sent callback + * @param sent callback function to call for this pcb when data is successfully sent + */ +void +tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); + pcb->sent = sent; + } +} + +/** + * @ingroup tcp_raw + * Used to specify the function that should be called when a fatal error + * has occurred on the connection. + * + * If a connection is aborted because of an error, the application is + * alerted of this event by the err callback. Errors that might abort a + * connection are when there is a shortage of memory. The callback + * function to be called is set using the tcp_err() function. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param pcb tcp_pcb to set the err callback + * @param err callback function to call for this pcb when a fatal error + * has occurred on the connection + */ +void +tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); + pcb->errf = err; + } +} + +/** + * @ingroup tcp_raw + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB + * + * @param pcb tcp_pcb to set the accept callback + * @param accept callback function to call for this pcb when LISTENing + * connection has been connected to another host + */ +void +tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) +{ + LWIP_ASSERT_CORE_LOCKED(); + if ((pcb != NULL) && (pcb->state == LISTEN)) { + struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen *)pcb; + lpcb->accept = accept; + } +} +#endif /* LWIP_CALLBACK_API */ + + +/** + * @ingroup tcp_raw + * Specifies the polling interval and the callback function that should + * be called to poll the application. The interval is specified in + * number of TCP coarse grained timer shots, which typically occurs + * twice a second. An interval of 10 means that the application would + * be polled every 5 seconds. + * + * When a connection is idle (i.e., no data is either transmitted or + * received), lwIP will repeatedly poll the application by calling a + * specified callback function. This can be used either as a watchdog + * timer for killing connections that have stayed idle for too long, or + * as a method of waiting for memory to become available. For instance, + * if a call to tcp_write() has failed because memory wasn't available, + * the application may use the polling functionality to call tcp_write() + * again when the connection has been idle for a while. + */ +void +tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("tcp_poll: invalid pcb", pcb != NULL, return); + LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); + +#if LWIP_CALLBACK_API + pcb->poll = poll; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(poll); +#endif /* LWIP_CALLBACK_API */ + pcb->pollinterval = interval; +} + +/** + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory + * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). + * + * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! + */ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ + LWIP_ERROR("tcp_pcb_purge: invalid pcb", pcb != NULL, return); + + if (pcb->state != CLOSED && + pcb->state != TIME_WAIT && + pcb->state != LISTEN) { + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + + tcp_backlog_accepted(pcb); + + if (pcb->refused_data != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + if (pcb->unsent != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); + } + if (pcb->unacked != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); + tcp_free_ooseq(pcb); + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Stop the retransmission timer as it will expect data on unacked + queue if it fires */ + pcb->rtime = -1; + + tcp_segs_free(pcb->unsent); + tcp_segs_free(pcb->unacked); + pcb->unacked = pcb->unsent = NULL; +#if TCP_OVERSIZE + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + } +} + +/** + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + * @param pcblist PCB list to purge. + * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! + */ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_pcb_remove: invalid pcb", pcb != NULL); + LWIP_ASSERT("tcp_pcb_remove: invalid pcblist", pcblist != NULL); + + TCP_RMV(pcblist, pcb); + + tcp_pcb_purge(pcb); + + /* if there is an outstanding delayed ACKs, send it */ + if ((pcb->state != TIME_WAIT) && + (pcb->state != LISTEN) && + (pcb->flags & TF_ACK_DELAY)) { + tcp_ack_now(pcb); + tcp_output(pcb); + } + + if (pcb->state != LISTEN) { + LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); + LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); +#if TCP_QUEUE_OOSEQ + LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); +#endif /* TCP_QUEUE_OOSEQ */ + } + + pcb->state = CLOSED; + /* reset the local port to prevent the pcb from being 'bound' */ + pcb->local_port = 0; + + LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} + +/** + * Calculates a new initial sequence number for new connections. + * + * @return u32_t pseudo random sequence number + */ +u32_t +tcp_next_iss(struct tcp_pcb *pcb) +{ +#ifdef LWIP_HOOK_TCP_ISN + LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); + return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); +#else /* LWIP_HOOK_TCP_ISN */ + static u32_t iss = 6510; + + LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); + LWIP_UNUSED_ARG(pcb); + + iss += tcp_ticks; /* XXX */ + return iss; +#endif /* LWIP_HOOK_TCP_ISN */ +} + +#if TCP_CALCULATE_EFF_SEND_MSS +/** + * Calculates the effective send mss that can be used for a specific IP address + * by calculating the minimum of TCP_MSS and the mtu (if set) of the target + * netif (if not NULL). + */ +u16_t +tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest) +{ + u16_t mss_s; + u16_t mtu; + + LWIP_UNUSED_ARG(dest); /* in case IPv6 is disabled */ + + LWIP_ASSERT("tcp_eff_send_mss_netif: invalid dst_ip", dest != NULL); + +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_IS_V6(dest)) +#endif /* LWIP_IPV4 */ + { + /* First look in destination cache, to see if there is a Path MTU. */ + mtu = nd6_get_destination_mtu(ip_2_ip6(dest), outif); + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + if (outif == NULL) { + return sendmss; + } + mtu = outif->mtu; + } +#endif /* LWIP_IPV4 */ + + if (mtu != 0) { + u16_t offset; +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_IS_V6(dest)) +#endif /* LWIP_IPV4 */ + { + offset = IP6_HLEN + TCP_HLEN; + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + offset = IP_HLEN + TCP_HLEN; + } +#endif /* LWIP_IPV4 */ + mss_s = (mtu > offset) ? (u16_t)(mtu - offset) : 0; + /* RFC 1122, chap 4.2.2.6: + * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize + * We correct for TCP options in tcp_write(), and don't support IP options. + */ + sendmss = LWIP_MIN(sendmss, mss_s); + } + return sendmss; +} +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +/** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */ +static void +tcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb_list) +{ + struct tcp_pcb *pcb; + pcb = pcb_list; + + LWIP_ASSERT("tcp_netif_ip_addr_changed_pcblist: invalid old_addr", old_addr != NULL); + + while (pcb != NULL) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&pcb->local_ip, old_addr) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) +#endif /* LWIP_AUTOIP */ + ) { + /* this connection must be aborted */ + struct tcp_pcb *next = pcb->next; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); + tcp_abort(pcb); + pcb = next; + } else { + pcb = pcb->next; + } + } +} + +/** This function is called from netif.c when address is changed or netif is removed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change or NULL if netif has been removed + */ +void +tcp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) +{ + struct tcp_pcb_listen *lpcb; + + if (!ip_addr_isany(old_addr)) { + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); + + if (!ip_addr_isany(new_addr)) { + /* PCB bound to current local interface address? */ + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { + /* The PCB is listening to the old ipaddr and + * is set to listen to the new one instead */ + ip_addr_copy(lpcb->local_ip, *new_addr); + } + } + } + } +} + +const char * +tcp_debug_state_str(enum tcp_state s) +{ + return tcp_state_str[s]; +} + +err_t +tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port) +{ + if (pcb) { + if (local) { + if (addr) { + *addr = pcb->local_ip; + } + if (port) { + *port = pcb->local_port; + } + } else { + if (addr) { + *addr = pcb->remote_ip; + } + if (port) { + *port = pcb->remote_port; + } + } + return ERR_OK; + } + return ERR_VAL; +} + +#if TCP_QUEUE_OOSEQ +/* Free all ooseq pbufs (and possibly reset SACK state) */ +void +tcp_free_ooseq(struct tcp_pcb *pcb) +{ + if (pcb->ooseq) { + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; +#if LWIP_TCP_SACK_OUT + memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); +#endif /* LWIP_TCP_SACK_OUT */ + } +} +#endif /* TCP_QUEUE_OOSEQ */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +/** + * Print a tcp header for debugging purposes. + * + * @param tcphdr pointer to a struct tcp_hdr + */ +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ + LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", + lwip_ntohl(tcphdr->seqno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", + lwip_ntohl(tcphdr->ackno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", + TCPH_HDRLEN(tcphdr), + (u16_t)(TCPH_FLAGS(tcphdr) >> 5 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 4 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 3 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) & 1), + lwip_ntohs(tcphdr->wnd))); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", + lwip_ntohs(tcphdr->chksum), lwip_ntohs(tcphdr->urgp))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} + +/** + * Print a tcp state for debugging purposes. + * + * @param s enum tcp_state to print + */ +void +tcp_debug_print_state(enum tcp_state s) +{ + LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); +} + +/** + * Print tcp flags for debugging purposes. + * + * @param flags tcp flags, all active flags are printed + */ +void +tcp_debug_print_flags(u8_t flags) +{ + if (flags & TCP_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); + } + if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); + } + if (flags & TCP_RST) { + LWIP_DEBUGF(TCP_DEBUG, ("RST ")); + } + if (flags & TCP_PSH) { + LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); + } + if (flags & TCP_ACK) { + LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); + } + if (flags & TCP_URG) { + LWIP_DEBUGF(TCP_DEBUG, ("URG ")); + } + if (flags & TCP_ECE) { + LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); + } + if (flags & TCP_CWR) { + LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); +} + +/** + * Print all tcp_pcbs in every list for debugging purposes. + */ +void +tcp_debug_print_pcbs(void) +{ + struct tcp_pcb *pcb; + struct tcp_pcb_listen *pcbl; + + LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + + LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); + for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F" ", pcbl->local_port)); + tcp_debug_print_state(pcbl->state); + } + + LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } +} + +/** + * Check state consistency of the tcp_pcb lists. + */ +s16_t +tcp_pcbs_sane(void) +{ + struct tcp_pcb *pcb; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + } + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + } + return 1; +} +#endif /* TCP_DEBUG */ + +#if LWIP_TCP_PCB_NUM_EXT_ARGS +/** + * @defgroup tcp_raw_extargs ext arguments + * @ingroup tcp_raw + * Additional data storage per tcp pcb\n + * @see @ref tcp_raw + * + * When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) + * includes a number of additional argument entries in an array. + * + * To support memory management, in addition to a 'void *', callbacks can be + * provided to manage transition from listening pcbs to connections and to + * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). + * + * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get + * to store and load arguments from this index for a given pcb. + */ + +static u8_t tcp_ext_arg_id; + +/** + * @ingroup tcp_raw_extargs + * Allocate an index to store data in ext_args member of struct tcp_pcb. + * Returned value is an index in mentioned array. + * The index is *global* over all pcbs! + * + * When @ref LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) + * includes a number of additional argument entries in an array. + * + * To support memory management, in addition to a 'void *', callbacks can be + * provided to manage transition from listening pcbs to connections and to + * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). + * + * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get + * to store and load arguments from this index for a given pcb. + * + * @return a unique index into struct tcp_pcb.ext_args + */ +u8_t +tcp_ext_arg_alloc_id(void) +{ + u8_t result = tcp_ext_arg_id; + tcp_ext_arg_id++; + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_TCP_PCB_NUM_EXT_ARGS >= 255 +#error LWIP_TCP_PCB_NUM_EXT_ARGS +#endif + LWIP_ASSERT("Increase LWIP_TCP_PCB_NUM_EXT_ARGS in lwipopts.h", result < LWIP_TCP_PCB_NUM_EXT_ARGS); + return result; +} + +/** + * @ingroup tcp_raw_extargs + * Set callbacks for a given index of ext_args on the specified pcb. + * + * @param pcb tcp_pcb for which to set the callback + * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) + * @param callbacks callback table (const since it is referenced, not copied!) + */ +void +tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); + LWIP_ASSERT("callbacks != NULL", callbacks != NULL); + + LWIP_ASSERT_CORE_LOCKED(); + + pcb->ext_args[id].callbacks = callbacks; +} + +/** + * @ingroup tcp_raw_extargs + * Set data for a given index of ext_args on the specified pcb. + * + * @param pcb tcp_pcb for which to set the data + * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) + * @param arg data pointer to set + */ +void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); + + LWIP_ASSERT_CORE_LOCKED(); + + pcb->ext_args[id].data = arg; +} + +/** + * @ingroup tcp_raw_extargs + * Set data for a given index of ext_args on the specified pcb. + * + * @param pcb tcp_pcb for which to set the data + * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) + * @return data pointer at the given index + */ +void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); + + LWIP_ASSERT_CORE_LOCKED(); + + return pcb->ext_args[id].data; +} + +/** This function calls the "destroy" callback for all ext_args once a pcb is + * freed. + */ +static void +tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args) +{ + int i; + LWIP_ASSERT("ext_args != NULL", ext_args != NULL); + + for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { + if (ext_args[i].callbacks != NULL) { + if (ext_args[i].callbacks->destroy != NULL) { + ext_args[i].callbacks->destroy((u8_t)i, ext_args[i].data); + } + } + } +} + +/** This function calls the "passive_open" callback for all ext_args if a connection + * is in the process of being accepted. This is called just after the SYN is + * received and before a SYN/ACK is sent, to allow to modify the very first + * segment sent even on passive open. Naturally, the "accepted" callback of the + * pcb has not been called yet! + */ +err_t +tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb) +{ + int i; + LWIP_ASSERT("lpcb != NULL", lpcb != NULL); + LWIP_ASSERT("cpcb != NULL", cpcb != NULL); + + for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { + if (lpcb->ext_args[i].callbacks != NULL) { + if (lpcb->ext_args[i].callbacks->passive_open != NULL) { + err_t err = lpcb->ext_args[i].callbacks->passive_open((u8_t)i, lpcb, cpcb); + if (err != ERR_OK) { + return err; + } + } + } + } + return ERR_OK; +} +#endif /* LWIP_TCP_PCB_NUM_EXT_ARGS */ + +#endif /* LWIP_TCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_in.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_in.c new file mode 100644 index 0000000..2202e38 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_in.c @@ -0,0 +1,2179 @@ +/** + * @file + * Transmission Control Protocol, incoming traffic + * + * The input processing functions of the TCP layer. + * + * These functions are generally called in the order (ip_input() ->) + * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcp_priv.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#if LWIP_ND6_TCP_REACHABILITY_HINTS +#include "lwip/nd6.h" +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Initial CWND calculation as defined RFC 2581 */ +#define LWIP_TCP_CALC_INITIAL_CWND(mss) ((tcpwnd_size_t)LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U))) + +/* These variables are global to all functions involved in the input + processing of TCP segments. They are set by the tcp_input() + function. */ +static struct tcp_seg inseg; +static struct tcp_hdr *tcphdr; +static u16_t tcphdr_optlen; +static u16_t tcphdr_opt1len; +static u8_t *tcphdr_opt2; +static u16_t tcp_optidx; +static u32_t seqno, ackno; +static tcpwnd_size_t recv_acked; +static u16_t tcplen; +static u8_t flags; + +static u8_t recv_flags; +static struct pbuf *recv_data; + +struct tcp_pcb *tcp_input_pcb; + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb); +static void tcp_receive(struct tcp_pcb *pcb); +static void tcp_parseopt(struct tcp_pcb *pcb); + +static void tcp_listen_input(struct tcp_pcb_listen *pcb); +static void tcp_timewait_input(struct tcp_pcb *pcb); + +static int tcp_input_delayed_close(struct tcp_pcb *pcb); + +#if LWIP_TCP_SACK_OUT +static void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); +static void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) +static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ +#endif /* LWIP_TCP_SACK_OUT */ + +/** + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + * + * @param p received TCP segment to process (p->payload pointing to the TCP header) + * @param inp network interface on which this segment was received + */ +void +tcp_input(struct pbuf *p, struct netif *inp) +{ + struct tcp_pcb *pcb, *prev; + struct tcp_pcb_listen *lpcb; +#if SO_REUSE + struct tcp_pcb *lpcb_prev = NULL; + struct tcp_pcb_listen *lpcb_any = NULL; +#endif /* SO_REUSE */ + u8_t hdrlen_bytes; + err_t err; + + LWIP_UNUSED_ARG(inp); + LWIP_ASSERT_CORE_LOCKED(); + LWIP_ASSERT("tcp_input: invalid pbuf", p != NULL); + + PERF_START; + + TCP_STATS_INC(tcp.recv); + MIB2_STATS_INC(mib2.tcpinsegs); + + tcphdr = (struct tcp_hdr *)p->payload; + +#if TCP_INPUT_DEBUG + tcp_debug_print(tcphdr); +#endif + + /* Check that TCP header fits in payload */ + if (p->len < TCP_HLEN) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* Don't even process incoming broadcasts/multicasts. */ + if (ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()) || + ip_addr_ismulticast(ip_current_dest_addr())) { + TCP_STATS_INC(tcp.proterr); + goto dropped; + } + +#if CHECKSUM_CHECK_TCP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { + /* Verify TCP checksum. */ + u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + ip_current_src_addr(), ip_current_dest_addr()); + if (chksum != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + chksum)); + tcp_debug_print(tcphdr); + TCP_STATS_INC(tcp.chkerr); + goto dropped; + } + } +#endif /* CHECKSUM_CHECK_TCP */ + + /* sanity-check header length */ + hdrlen_bytes = TCPH_HDRLEN_BYTES(tcphdr); + if ((hdrlen_bytes < TCP_HLEN) || (hdrlen_bytes > p->tot_len)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: invalid header length (%"U16_F")\n", (u16_t)hdrlen_bytes)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + tcphdr_optlen = (u16_t)(hdrlen_bytes - TCP_HLEN); + tcphdr_opt2 = NULL; + if (p->len >= hdrlen_bytes) { + /* all options are in the first pbuf */ + tcphdr_opt1len = tcphdr_optlen; + pbuf_remove_header(p, hdrlen_bytes); /* cannot fail */ + } else { + u16_t opt2len; + /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ + /* there must be a next pbuf, due to hdrlen_bytes sanity check above */ + LWIP_ASSERT("p->next != NULL", p->next != NULL); + + /* advance over the TCP header (cannot fail) */ + pbuf_remove_header(p, TCP_HLEN); + + /* determine how long the first and second parts of the options are */ + tcphdr_opt1len = p->len; + opt2len = (u16_t)(tcphdr_optlen - tcphdr_opt1len); + + /* options continue in the next pbuf: set p to zero length and hide the + options in the next pbuf (adjusting p->tot_len) */ + pbuf_remove_header(p, tcphdr_opt1len); + + /* check that the options fit in the second pbuf */ + if (opt2len > p->next->len) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: options overflow second pbuf (%"U16_F" bytes)\n", p->next->len)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* remember the pointer to the second part of the options */ + tcphdr_opt2 = (u8_t *)p->next->payload; + + /* advance p->next to point after the options, and manually + adjust p->tot_len to keep it consistent with the changed p->next */ + pbuf_remove_header(p->next, opt2len); + p->tot_len = (u16_t)(p->tot_len - opt2len); + + LWIP_ASSERT("p->len == 0", p->len == 0); + LWIP_ASSERT("p->tot_len == p->next->tot_len", p->tot_len == p->next->tot_len); + } + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = lwip_ntohs(tcphdr->src); + tcphdr->dest = lwip_ntohs(tcphdr->dest); + seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno); + ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno); + tcphdr->wnd = lwip_ntohs(tcphdr->wnd); + + flags = TCPH_FLAGS(tcphdr); + tcplen = p->tot_len; + if (flags & (TCP_FIN | TCP_SYN)) { + tcplen++; + if (tcplen < p->tot_len) { + /* u16_t overflow, cannot handle this */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: length u16_t overflow, cannot handle this\n")); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + } + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. */ + prev = NULL; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + prev = pcb; + continue; + } + + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); + if (prev != NULL) { + prev->next = pcb->next; + pcb->next = tcp_active_pcbs; + tcp_active_pcbs = pcb; + } else { + TCP_STATS_INC(tcp.cachehit); + } + LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); + break; + } + prev = pcb; + } + + if (pcb == NULL) { + /* If it did not go to an active connection, we check the connections + in the TIME-WAIT state. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + continue; + } + + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + /* We don't really care enough to move this PCB to the front + of the list since we are not very likely to receive that + many segments for connections in TIME-WAIT. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); +#ifdef LWIP_HOOK_TCP_INPACKET_PCB + if (LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, tcphdr_opt1len, + tcphdr_opt2, p) == ERR_OK) +#endif + { + tcp_timewait_input(pcb); + } + pbuf_free(p); + return; + } + } + + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ + prev = NULL; + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + /* check if PCB is bound to specific netif */ + if ((lpcb->netif_idx != NETIF_NO_INDEX) && + (lpcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + prev = (struct tcp_pcb *)lpcb; + continue; + } + + if (lpcb->local_port == tcphdr->dest) { + if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { + /* found an ANY TYPE (IPv4/IPv6) match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ + break; +#endif /* SO_REUSE */ + } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { + if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { + /* found an exact match */ + break; + } else if (ip_addr_isany(&lpcb->local_ip)) { + /* found an ANY-match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ + break; +#endif /* SO_REUSE */ + } + } + } + prev = (struct tcp_pcb *)lpcb; + } +#if SO_REUSE + /* first try specific local IP */ + if (lpcb == NULL) { + /* only pass to ANY if no specific local IP has been found */ + lpcb = lpcb_any; + prev = lpcb_prev; + } +#endif /* SO_REUSE */ + if (lpcb != NULL) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if (prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } else { + TCP_STATS_INC(tcp.cachehit); + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); +#ifdef LWIP_HOOK_TCP_INPACKET_PCB + if (LWIP_HOOK_TCP_INPACKET_PCB((struct tcp_pcb *)lpcb, tcphdr, tcphdr_optlen, + tcphdr_opt1len, tcphdr_opt2, p) == ERR_OK) +#endif + { + tcp_listen_input(lpcb); + } + pbuf_free(p); + return; + } + } + +#if TCP_INPUT_DEBUG + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + +#ifdef LWIP_HOOK_TCP_INPACKET_PCB + if ((pcb != NULL) && LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, + tcphdr_opt1len, tcphdr_opt2, p) != ERR_OK) { + pbuf_free(p); + return; + } +#endif + if (pcb != NULL) { + /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_INPUT_DEBUG */ + + /* Set up a tcp_seg structure. */ + inseg.next = NULL; + inseg.len = p->tot_len; + inseg.p = p; + inseg.tcphdr = tcphdr; + + recv_data = NULL; + recv_flags = 0; + recv_acked = 0; + + if (flags & TCP_PSH) { + p->flags |= PBUF_FLAG_PUSH; + } + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + if ((tcp_process_refused_data(pcb) == ERR_ABRT) || + ((pcb->refused_data != NULL) && (tcplen > 0))) { + /* pcb has been aborted or refused data is still refused and the new + segment contains data */ + if (pcb->rcv_ann_wnd == 0) { + /* this is a zero-window probe, we respond to it with current RCV.NXT + and drop the data segment */ + tcp_send_empty_ack(pcb); + } + TCP_STATS_INC(tcp.drop); + MIB2_STATS_INC(mib2.tcpinerrs); + goto aborted; + } + } + tcp_input_pcb = pcb; + err = tcp_process(pcb); + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if (err != ERR_ABRT) { + if (recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb); + tcp_free(pcb); + } else { + err = ERR_OK; + /* If the application has registered a "sent" function to be + called when new send buffer space is available, we call it + now. */ + if (recv_acked > 0) { + u16_t acked16; +#if LWIP_WND_SCALE + /* recv_acked is u32_t but the sent callback only takes a u16_t, + so we might have to call it multiple times. */ + u32_t acked = recv_acked; + while (acked > 0) { + acked16 = (u16_t)LWIP_MIN(acked, 0xffffu); + acked -= acked16; +#else + { + acked16 = recv_acked; +#endif + TCP_EVENT_SENT(pcb, (u16_t)acked16, err); + if (err == ERR_ABRT) { + goto aborted; + } + } + recv_acked = 0; + } + if (tcp_input_delayed_close(pcb)) { + goto aborted; + } +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + while (recv_data != NULL) { + struct pbuf *rest = NULL; + pbuf_split_64k(recv_data, &rest); +#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + if (recv_data != NULL) { +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + + LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); + if (pcb->flags & TF_RXCLOSED) { + /* received data although already closed -> abort (send RST) to + notify the remote host that not all data has been processed */ + pbuf_free(recv_data); +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_free(rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + tcp_abort(pcb); + goto aborted; + } + + /* Notify application that data has been received. */ + TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + if (err == ERR_ABRT) { +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_free(rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + goto aborted; + } + + /* If the upper layer can't receive this data, store it */ + if (err != ERR_OK) { +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_cat(recv_data, rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = recv_data; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + break; + } else { + /* Upper layer received the data, go on with the rest if > 64K */ + recv_data = rest; +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + } + } + + /* If a FIN segment was received, we call the callback + function with a NULL buffer to indicate EOF. */ + if (recv_flags & TF_GOT_FIN) { + if (pcb->refused_data != NULL) { + /* Delay this if we have refused data. */ + pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; + } else { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto aborted; + } + } + } + + tcp_input_pcb = NULL; + if (tcp_input_delayed_close(pcb)) { + goto aborted; + } + /* Try to send something out. */ + tcp_output(pcb); +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + } + } + /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). + Below this line, 'pcb' may not be dereferenced! */ +aborted: + tcp_input_pcb = NULL; + recv_data = NULL; + + /* give up our reference to inseg.p */ + if (inseg.p != NULL) { + pbuf_free(inseg.p); + inseg.p = NULL; + } + } else { + /* If no matching PCB was found, send a TCP RST (reset) to the + sender. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); + if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { + TCP_STATS_INC(tcp.proterr); + TCP_STATS_INC(tcp.drop); + tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } + pbuf_free(p); + } + + LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); + return; +dropped: + TCP_STATS_INC(tcp.drop); + MIB2_STATS_INC(mib2.tcpinerrs); + pbuf_free(p); +} + +/** Called from tcp_input to check for TF_CLOSED flag. This results in closing + * and deallocating a pcb at the correct place to ensure noone references it + * any more. + * @returns 1 if the pcb has been closed and deallocated, 0 otherwise + */ +static int +tcp_input_delayed_close(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_input_delayed_close: invalid pcb", pcb != NULL); + + if (recv_flags & TF_CLOSED) { + /* The connection has been closed and we will deallocate the + PCB. */ + if (!(pcb->flags & TF_RXCLOSED)) { + /* Connection closed although the application has only shut down the + tx side: call the PCB's err callback and indicate the closure to + ensure the application doesn't continue using the PCB. */ + TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); + } + tcp_pcb_remove(&tcp_active_pcbs, pcb); + tcp_free(pcb); + return 1; + } + return 0; +} + +/** + * Called by tcp_input() when a segment arrives for a listening + * connection (from tcp_input()). + * + * @param pcb the tcp_pcb_listen for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static void +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + u32_t iss; + err_t rc; + + if (flags & TCP_RST) { + /* An incoming RST should be ignored. Return. */ + return; + } + + LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); + + /* In the LISTEN state, we check for incoming SYN segments, + creates a new PCB, and responds with a SYN|ACK. */ + if (flags & TCP_ACK) { + /* For incoming segments with the ACK flag set, respond with a + RST. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); + tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } else if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); +#if TCP_LISTEN_BACKLOG + if (pcb->accepts_pending >= pcb->backlog) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); + return; + } +#endif /* TCP_LISTEN_BACKLOG */ + npcb = tcp_alloc(pcb->prio); + /* If a new PCB could not be created (probably due to lack of memory), + we don't do anything, but rely on the sender will retransmit the + SYN at a time when we have more memory available. */ + if (npcb == NULL) { + err_t err; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); + TCP_STATS_INC(tcp.memerr); + TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); + LWIP_UNUSED_ARG(err); /* err not useful here */ + return; + } +#if TCP_LISTEN_BACKLOG + pcb->accepts_pending++; + tcp_set_flags(npcb, TF_BACKLOGPEND); +#endif /* TCP_LISTEN_BACKLOG */ + /* Set up the new PCB. */ + ip_addr_copy(npcb->local_ip, *ip_current_dest_addr()); + ip_addr_copy(npcb->remote_ip, *ip_current_src_addr()); + npcb->local_port = pcb->local_port; + npcb->remote_port = tcphdr->src; + npcb->state = SYN_RCVD; + npcb->rcv_nxt = seqno + 1; + npcb->rcv_ann_right_edge = npcb->rcv_nxt; + iss = tcp_next_iss(npcb); + npcb->snd_wl2 = iss; + npcb->snd_nxt = iss; + npcb->lastack = iss; + npcb->snd_lbb = iss; + npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ + npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + npcb->listener = pcb; +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + /* inherit socket options */ + npcb->so_options = pcb->so_options & SOF_INHERITED; + npcb->netif_idx = pcb->netif_idx; + /* Register the new PCB so that we can begin receiving segments + for it. */ + TCP_REG_ACTIVE(npcb); + + /* Parse any options in the SYN. */ + tcp_parseopt(npcb); + npcb->snd_wnd = tcphdr->wnd; + npcb->snd_wnd_max = npcb->snd_wnd; + +#if TCP_CALCULATE_EFF_SEND_MSS + npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + MIB2_STATS_INC(mib2.tcppassiveopens); + +#if LWIP_TCP_PCB_NUM_EXT_ARGS + if (tcp_ext_arg_invoke_callbacks_passive_open(pcb, npcb) != ERR_OK) { + tcp_abandon(npcb, 0); + return; + } +#endif + + /* Send a SYN|ACK together with the MSS option. */ + rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); + if (rc != ERR_OK) { + tcp_abandon(npcb, 0); + return; + } + tcp_output(npcb); + } + return; +} + +/** + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static void +tcp_timewait_input(struct tcp_pcb *pcb) +{ + /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ + /* RFC 793 3.9 Event Processing - Segment Arrives: + * - first check sequence number - we skip that one in TIME_WAIT (always + * acceptable since we only send ACKs) + * - second check the RST bit (... return) */ + if (flags & TCP_RST) { + return; + } + + LWIP_ASSERT("tcp_timewait_input: invalid pcb", pcb != NULL); + + /* - fourth, check the SYN bit, */ + if (flags & TCP_SYN) { + /* If an incoming segment is not acceptable, an acknowledgment + should be sent in reply */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { + /* If the SYN is in the window it is an error, send a reset */ + tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + return; + } + } else if (flags & TCP_FIN) { + /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. + Restart the 2 MSL time-wait timeout.*/ + pcb->tmr = tcp_ticks; + } + + if ((tcplen > 0)) { + /* Acknowledge data, FIN or out-of-window SYN */ + tcp_ack_now(pcb); + tcp_output(pcb); + } + return; +} + +/** + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static err_t +tcp_process(struct tcp_pcb *pcb) +{ + struct tcp_seg *rseg; + u8_t acceptable = 0; + err_t err; + + err = ERR_OK; + + LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL); + + /* Process incoming RST segments. */ + if (flags & TCP_RST) { + /* First, determine if the reset is acceptable. */ + if (pcb->state == SYN_SENT) { + /* "In the SYN-SENT state (a RST received in response to an initial SYN), + the RST is acceptable if the ACK field acknowledges the SYN." */ + if (ackno == pcb->snd_nxt) { + acceptable = 1; + } + } else { + /* "In all states except SYN-SENT, all reset (RST) segments are validated + by checking their SEQ-fields." */ + if (seqno == pcb->rcv_nxt) { + acceptable = 1; + } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd)) { + /* If the sequence number is inside the window, we send a challenge ACK + and wait for a re-send with matching sequence number. + This follows RFC 5961 section 3.2 and addresses CVE-2004-0230 + (RST spoofing attack), which is present in RFC 793 RST handling. */ + tcp_ack_now(pcb); + } + } + + if (acceptable) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); + LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); + recv_flags |= TF_RESET; + tcp_clear_flags(pcb, TF_ACK_DELAY); + return ERR_RST; + } else { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + return ERR_OK; + } + } + + if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { + /* Cope with new connection attempt after remote end crashed */ + tcp_ack_now(pcb); + return ERR_OK; + } + + if ((pcb->flags & TF_RXCLOSED) == 0) { + /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ + pcb->tmr = tcp_ticks; + } + pcb->keep_cnt_sent = 0; + pcb->persist_probe = 0; + + tcp_parseopt(pcb); + + /* Do different things depending on the TCP state. */ + switch (pcb->state) { + case SYN_SENT: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %s %"U32_F"\n", + ackno, pcb->snd_nxt, pcb->unacked ? "" : " empty:", + pcb->unacked ? lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0)); + /* received SYN ACK with expected sequence number? */ + if ((flags & TCP_ACK) && (flags & TCP_SYN) + && (ackno == pcb->lastack + 1)) { + pcb->rcv_nxt = seqno + 1; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->lastack = ackno; + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wnd_max = pcb->snd_wnd; + pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ + pcb->state = ESTABLISHED; + +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); + --pcb->snd_queuelen; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); + rseg = pcb->unacked; + if (rseg == NULL) { + /* might happen if tcp_output fails in tcp_rexmit_rto() + in which case the segment is on the unsent list */ + rseg = pcb->unsent; + LWIP_ASSERT("no segment to free", rseg != NULL); + pcb->unsent = rseg->next; + } else { + pcb->unacked = rseg->next; + } + tcp_seg_free(rseg); + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if (pcb->unacked == NULL) { + pcb->rtime = -1; + } else { + pcb->rtime = 0; + pcb->nrtx = 0; + } + + /* Call the user specified function to call when successfully + * connected. */ + TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + tcp_ack_now(pcb); + } + /* received ACK? possibly a half-open connection */ + else if (flags & TCP_ACK) { + /* send a RST to bring the other side in a non-synchronized state. */ + tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + /* Resend SYN immediately (don't wait for rto timeout) to establish + connection faster, but do not send more SYNs than we otherwise would + have, or we might get caught in a loop on loopback interfaces. */ + if (pcb->nrtx < TCP_SYNMAXRTX) { + pcb->rtime = 0; + tcp_rexmit_rto(pcb); + } + } + break; + case SYN_RCVD: + if (flags & TCP_ACK) { + /* expected ACK number? */ + if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { + pcb->state = ESTABLISHED; + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + if (pcb->listener == NULL) { + /* listen pcb might be closed by now */ + err = ERR_VAL; + } else +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + { +#if LWIP_CALLBACK_API + LWIP_ASSERT("pcb->listener->accept != NULL", pcb->listener->accept != NULL); +#endif + tcp_backlog_accepted(pcb); + /* Call the accept function. */ + TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, ERR_OK, err); + } + if (err != ERR_OK) { + /* If the accept function returns with an error, we abort + * the connection. */ + /* Already aborted? */ + if (err != ERR_ABRT) { + tcp_abort(pcb); + } + return ERR_ABRT; + } + /* If there was any data contained within this ACK, + * we'd better pass it on to the application as well. */ + tcp_receive(pcb); + + /* Prevent ACK for SYN to generate a sent event */ + if (recv_acked != 0) { + recv_acked--; + } + + pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + + if (recv_flags & TF_GOT_FIN) { + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + } else { + /* incorrect ACK number, send RST */ + tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } + } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { /* passive close */ + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && + pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, + ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && + pcb->unsent == NULL) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ + recv_flags |= TF_CLOSED; + } + break; + default: + break; + } + return ERR_OK; +} + +#if TCP_QUEUE_OOSEQ +/** + * Insert segment into the list (segments covered with new one will be deleted) + * + * Called from tcp_receive() + */ +static void +tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) +{ + struct tcp_seg *old_seg; + + LWIP_ASSERT("tcp_oos_insert_segment: invalid cseg", cseg != NULL); + + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + /* received segment overlaps all following segments */ + tcp_segs_free(next); + next = NULL; + } else { + /* delete some following segments + oos queue may have segments with FIN flag */ + while (next && + TCP_SEQ_GEQ((seqno + cseg->len), + (next->tcphdr->seqno + next->len))) { + /* cseg with FIN already processed */ + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); + } + old_seg = next; + next = next->next; + tcp_seg_free(old_seg); + } + if (next && + TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + cseg->len = (u16_t)(next->tcphdr->seqno - seqno); + pbuf_realloc(cseg->p, cseg->len); + } + } + cseg->next = next; +} +#endif /* TCP_QUEUE_OOSEQ */ + +/** Remove segments from a list if the incoming ACK acknowledges them */ +static struct tcp_seg * +tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const char *dbg_list_name, + struct tcp_seg *dbg_other_seg_list) +{ + struct tcp_seg *next; + u16_t clen; + + LWIP_UNUSED_ARG(dbg_list_name); + LWIP_UNUSED_ARG(dbg_other_seg_list); + + while (seg_list != NULL && + TCP_SEQ_LEQ(lwip_ntohl(seg_list->tcphdr->seqno) + + TCP_TCPLEN(seg_list), ackno)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->%s\n", + lwip_ntohl(seg_list->tcphdr->seqno), + lwip_ntohl(seg_list->tcphdr->seqno) + TCP_TCPLEN(seg_list), + dbg_list_name)); + + next = seg_list; + seg_list = seg_list->next; + + clen = pbuf_clen(next->p); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", + (tcpwnd_size_t)pcb->snd_queuelen)); + LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= clen)); + + pcb->snd_queuelen = (u16_t)(pcb->snd_queuelen - clen); + recv_acked = (tcpwnd_size_t)(recv_acked + next->len); + tcp_seg_free(next); + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing %s)\n", + (tcpwnd_size_t)pcb->snd_queuelen, + dbg_list_name)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", + seg_list != NULL || dbg_other_seg_list != NULL); + } + } + return seg_list; +} + +/** + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, it places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + * + * Called from tcp_process(). + */ +static void +tcp_receive(struct tcp_pcb *pcb) +{ + s16_t m; + u32_t right_wnd_edge; + int found_dupack = 0; + + LWIP_ASSERT("tcp_receive: invalid pcb", pcb != NULL); + LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); + + if (flags & TCP_ACK) { + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; + + /* Update window. */ + if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && (u32_t)SND_WND_SCALE(pcb, tcphdr->wnd) > pcb->snd_wnd)) { + pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); + /* keep track of the biggest window announced by the remote host to calculate + the maximum segment size */ + if (pcb->snd_wnd_max < pcb->snd_wnd) { + pcb->snd_wnd_max = pcb->snd_wnd; + } + pcb->snd_wl1 = seqno; + pcb->snd_wl2 = ackno; + LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"TCPWNDSIZE_F"\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG + } else { + if (pcb->snd_wnd != (tcpwnd_size_t)SND_WND_SCALE(pcb, tcphdr->wnd)) { + LWIP_DEBUGF(TCP_WND_DEBUG, + ("tcp_receive: no window update lastack %"U32_F" ackno %" + U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", + pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + } +#endif /* TCP_WND_DEBUG */ + } + + /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a + * duplicate ack if: + * 1) It doesn't ACK new data + * 2) length of received packet is zero (i.e. no payload) + * 3) the advertised window hasn't changed + * 4) There is outstanding unacknowledged data (retransmission timer running) + * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) + * + * If it passes all five, should process as a dupack: + * a) dupacks < 3: do nothing + * b) dupacks == 3: fast retransmit + * c) dupacks > 3: increase cwnd + * + * If it only passes 1-3, should reset dupack counter (and add to + * stats, which we don't do in lwIP) + * + * If it only passes 1, should reset dupack counter + * + */ + + /* Clause 1 */ + if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { + /* Clause 2 */ + if (tcplen == 0) { + /* Clause 3 */ + if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { + /* Clause 4 */ + if (pcb->rtime >= 0) { + /* Clause 5 */ + if (pcb->lastack == ackno) { + found_dupack = 1; + if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { + ++pcb->dupacks; + } + if (pcb->dupacks > 3) { + /* Inflate the congestion window */ + TCP_WND_INC(pcb->cwnd, pcb->mss); + } + if (pcb->dupacks >= 3) { + /* Do fast retransmit (checked via TF_INFR, not via dupacks count) */ + tcp_rexmit_fast(pcb); + } + } + } + } + } + /* If Clause (1) or more is true, but not a duplicate ack, reset + * count of consecutive duplicate acks */ + if (!found_dupack) { + pcb->dupacks = 0; + } + } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { + /* We come here when the ACK acknowledges new data. */ + tcpwnd_size_t acked; + + /* Reset the "IN Fast Retransmit" flag, since we are no longer + in fast retransmit. Also reset the congestion window to the + slow start threshold. */ + if (pcb->flags & TF_INFR) { + tcp_clear_flags(pcb, TF_INFR); + pcb->cwnd = pcb->ssthresh; + pcb->bytes_acked = 0; + } + + /* Reset the number of retransmissions. */ + pcb->nrtx = 0; + + /* Reset the retransmission time-out. */ + pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); + + /* Record how much data this ACK acks */ + acked = (tcpwnd_size_t)(ackno - pcb->lastack); + + /* Reset the fast retransmit variables. */ + pcb->dupacks = 0; + pcb->lastack = ackno; + + /* Update the congestion control variables (cwnd and + ssthresh). */ + if (pcb->state >= ESTABLISHED) { + if (pcb->cwnd < pcb->ssthresh) { + tcpwnd_size_t increase; + /* limit to 1 SMSS segment during period following RTO */ + u8_t num_seg = (pcb->flags & TF_RTO) ? 1 : 2; + /* RFC 3465, section 2.2 Slow Start */ + increase = LWIP_MIN(acked, (tcpwnd_size_t)(num_seg * pcb->mss)); + TCP_WND_INC(pcb->cwnd, increase); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); + } else { + /* RFC 3465, section 2.1 Congestion Avoidance */ + TCP_WND_INC(pcb->bytes_acked, acked); + if (pcb->bytes_acked >= pcb->cwnd) { + pcb->bytes_acked = (tcpwnd_size_t)(pcb->bytes_acked - pcb->cwnd); + TCP_WND_INC(pcb->cwnd, pcb->mss); + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); + } + } + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", + ackno, + pcb->unacked != NULL ? + lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0, + pcb->unacked != NULL ? + lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked) : 0)); + + /* Remove segment from the unacknowledged list if the incoming + ACK acknowledges them. */ + pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); + /* We go through the ->unsent list to see if any of the segments + on the list are acknowledged by the ACK. This may seem + strange since an "unsent" segment shouldn't be acked. The + rationale is that lwIP puts all outstanding segments on the + ->unsent list after a retransmission, so these segments may + in fact have been sent once. */ + pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if (pcb->unacked == NULL) { + pcb->rtime = -1; + } else { + pcb->rtime = 0; + } + + pcb->polltmr = 0; + +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (ip_current_is_v6()) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + + pcb->snd_buf = (tcpwnd_size_t)(pcb->snd_buf + recv_acked); + /* check if this ACK ends our retransmission of in-flight data */ + if (pcb->flags & TF_RTO) { + /* RTO is done if + 1) both queues are empty or + 2) unacked is empty and unsent head contains data not part of RTO or + 3) unacked head contains data not part of RTO */ + if (pcb->unacked == NULL) { + if ((pcb->unsent == NULL) || + (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unsent->tcphdr->seqno)))) { + tcp_clear_flags(pcb, TF_RTO); + } + } else if (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unacked->tcphdr->seqno))) { + tcp_clear_flags(pcb, TF_RTO); + } + } + /* End of ACK for new data processing. */ + } else { + /* Out of sequence ACK, didn't really ack anything */ + tcp_send_empty_ack(pcb); + } + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", + pcb->rttest, pcb->rtseq, ackno)); + + /* RTT estimation calculations. This is done by checking if the + incoming segment acknowledges the segment we use to take a + round-trip time measurement. */ + if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { + /* diff between this shouldn't exceed 32K since this are tcp timer ticks + and a round-trip shouldn't be that long... */ + m = (s16_t)(tcp_ticks - pcb->rttest); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", + m, (u16_t)(m * TCP_SLOW_INTERVAL))); + + /* This is taken directly from VJs original code in his paper */ + m = (s16_t)(m - (pcb->sa >> 3)); + pcb->sa = (s16_t)(pcb->sa + m); + if (m < 0) { + m = (s16_t) - m; + } + m = (s16_t)(m - (pcb->sv >> 2)); + pcb->sv = (s16_t)(pcb->sv + m); + pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", + pcb->rto, (u16_t)(pcb->rto * TCP_SLOW_INTERVAL))); + + pcb->rttest = 0; + } + } + + /* If the incoming segment contains data, we must process it + further unless the pcb already received a FIN. + (RFC 793, chapter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, + LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ + if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { + if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ + if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)) { + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + + struct pbuf *p = inseg.p; + u32_t off32 = pcb->rcv_nxt - seqno; + u16_t new_tot_len, off; + LWIP_ASSERT("inseg.p != NULL", inseg.p); + LWIP_ASSERT("insane offset!", (off32 < 0xffff)); + off = (u16_t)off32; + LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); + inseg.len -= off; + new_tot_len = (u16_t)(inseg.p->tot_len - off); + while (p->len < off) { + off -= p->len; + /* all pbufs up to and including this one have len==0, so tot_len is equal */ + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + /* cannot fail... */ + pbuf_remove_header(p, off); + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } else { + if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { + /* the whole segment is < rcv_nxt */ + /* must be a duplicate of a packet that has already been correctly handled */ + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); + tcp_ack_now(pcb); + } + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd - 1)) { + if (pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ + tcplen = TCP_TCPLEN(&inseg); + + if (tcplen > pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) & ~(unsigned int)TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + TCPWND_CHECK16(pcb->rcv_wnd); + inseg.len = (u16_t)pcb->rcv_wnd; + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } +#if TCP_QUEUE_OOSEQ + /* Received in-sequence data, adjust ooseq data if: + - FIN has been received or + - inseq overlaps with ooseq */ + if (pcb->ooseq != NULL) { + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: received in-order FIN, binning ooseq queue\n")); + /* Received in-order FIN means anything that was received + * out of order must now have been received in-order, so + * bin the ooseq queue */ + while (pcb->ooseq != NULL) { + struct tcp_seg *old_ooseq = pcb->ooseq; + pcb->ooseq = pcb->ooseq->next; + tcp_seg_free(old_ooseq); + } + } else { + struct tcp_seg *next = pcb->ooseq; + /* Remove all segments on ooseq that are covered by inseg already. + * FIN is copied from ooseq to inseg if present. */ + while (next && + TCP_SEQ_GEQ(seqno + tcplen, + next->tcphdr->seqno + next->len)) { + struct tcp_seg *tmp; + /* inseg cannot have FIN here (already processed above) */ + if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && + (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { + TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); + tcplen = TCP_TCPLEN(&inseg); + } + tmp = next; + next = next->next; + tcp_seg_free(tmp); + } + /* Now trim right side of inseg if it overlaps with the first + * segment on ooseq */ + if (next && + TCP_SEQ_GT(seqno + tcplen, + next->tcphdr->seqno)) { + /* inseg cannot have FIN here (already processed above) */ + inseg.len = (u16_t)(next->tcphdr->seqno - seqno); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", + (seqno + tcplen) == next->tcphdr->seqno); + } + pcb->ooseq = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + pcb->rcv_nxt = seqno + tcplen; + + /* Update the receiver's (our) window. */ + LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); + pcb->rcv_wnd -= tcplen; + + tcp_update_rcv_ann_wnd(pcb); + + /* If there is data in the segment, we make preparations to + pass this up to the application. The ->recv_data variable + is used for holding the pbuf that goes to the + application. The code for reassembling out-of-sequence data + chains its data on this pbuf as well. + + If the segment was a FIN, we set the TF_GOT_FIN flag that will + be used to indicate to the application that the remote side has + closed its end of the connection. */ + if (inseg.p->tot_len > 0) { + recv_data = inseg.p; + /* Since this pbuf now is the responsibility of the + application, we delete our reference to it so that we won't + (mistakingly) deallocate it. */ + inseg.p = NULL; + } + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); + recv_flags |= TF_GOT_FIN; + } + +#if TCP_QUEUE_OOSEQ + /* We now check if we have segments on the ->ooseq queue that + are now in sequence. */ + while (pcb->ooseq != NULL && + pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + + struct tcp_seg *cseg = pcb->ooseq; + seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += TCP_TCPLEN(cseg); + LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", + pcb->rcv_wnd >= TCP_TCPLEN(cseg)); + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + + tcp_update_rcv_ann_wnd(pcb); + + if (cseg->p->tot_len > 0) { + /* Chain this pbuf onto the pbuf that we will pass to + the application. */ + /* With window scaling, this can overflow recv_data->tot_len, but + that's not a problem since we explicitly fix that before passing + recv_data to the application. */ + if (recv_data) { + pbuf_cat(recv_data, cseg->p); + } else { + recv_data = cseg->p; + } + cseg->p = NULL; + } + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); + recv_flags |= TF_GOT_FIN; + if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ + pcb->state = CLOSE_WAIT; + } + } + + pcb->ooseq = cseg->next; + tcp_seg_free(cseg); + } +#if LWIP_TCP_SACK_OUT + if (pcb->flags & TF_SACK) { + if (pcb->ooseq != NULL) { + /* Some segments may have been removed from ooseq, let's remove all SACKs that + describe anything before the new beginning of that list. */ + tcp_remove_sacks_lt(pcb, pcb->ooseq->tcphdr->seqno); + } else if (LWIP_TCP_SACK_VALID(pcb, 0)) { + /* ooseq has been cleared. Nothing to SACK */ + memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); + } + } +#endif /* LWIP_TCP_SACK_OUT */ +#endif /* TCP_QUEUE_OOSEQ */ + + + /* Acknowledge the segment(s). */ + tcp_ack(pcb); + +#if LWIP_TCP_SACK_OUT + if (LWIP_TCP_SACK_VALID(pcb, 0)) { + /* Normally the ACK for the data received could be piggy-backed on a data packet, + but lwIP currently does not support including SACKs in data packets. So we force + it to respond with an empty ACK packet (only if there is at least one SACK to be sent). + NOTE: tcp_send_empty_ack() on success clears the ACK flags (set by tcp_ack()) */ + tcp_send_empty_ack(pcb); + } +#endif /* LWIP_TCP_SACK_OUT */ + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (ip_current_is_v6()) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + + } else { + /* We get here if the incoming segment is out-of-sequence. */ + +#if TCP_QUEUE_OOSEQ + /* We queue the segment on the ->ooseq queue. */ + if (pcb->ooseq == NULL) { + pcb->ooseq = tcp_seg_copy(&inseg); +#if LWIP_TCP_SACK_OUT + if (pcb->flags & TF_SACK) { + /* All the SACKs should be invalid, so we can simply store the most recent one: */ + pcb->rcv_sacks[0].left = seqno; + pcb->rcv_sacks[0].right = seqno + inseg.len; + } +#endif /* LWIP_TCP_SACK_OUT */ + } else { + /* If the queue is not empty, we walk through the queue and + try to find a place where the sequence number of the + incoming segment is between the sequence numbers of the + previous and the next segment on the ->ooseq queue. That is + the place where we put the incoming segment. If needed, we + trim the second edges of the previous and the incoming + segment so that it will fit into the sequence. + + If the incoming segment has the same sequence number as a + segment on the ->ooseq queue, we discard the segment that + contains less data. */ + +#if LWIP_TCP_SACK_OUT + /* This is the left edge of the lowest possible SACK range. + It may start before the newly received segment (possibly adjusted below). */ + u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; +#endif /* LWIP_TCP_SACK_OUT */ + struct tcp_seg *next, *prev = NULL; + for (next = pcb->ooseq; next != NULL; next = next->next) { + if (seqno == next->tcphdr->seqno) { + /* The sequence number of the incoming segment is the + same as the sequence number of the segment on + ->ooseq. We check the lengths to see which one to + discard. */ + if (inseg.len > next->len) { + /* The incoming segment is larger than the old + segment. We replace some segments with the new + one. */ + struct tcp_seg *cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + if (prev != NULL) { + prev->next = cseg; + } else { + pcb->ooseq = cseg; + } + tcp_oos_insert_segment(cseg, next); + } + break; + } else { + /* Either the lengths are the same or the incoming + segment was smaller than the old one; in either + case, we ditch the incoming segment. */ + break; + } + } else { + if (prev == NULL) { + if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is lower + than the sequence number of the first segment on the + queue. We put the incoming segment first on the + queue. */ + struct tcp_seg *cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + pcb->ooseq = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } else { + /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && + TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ + if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno + 1, next->tcphdr->seqno - 1)) { + /* The sequence number of the incoming segment is in + between the sequence numbers of the previous and + the next segment on ->ooseq. We trim trim the previous + segment, delete next segments that included in received segment + and trim received, if needed. */ + struct tcp_seg *cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { + /* We need to trim the prev segment. */ + prev->len = (u16_t)(seqno - prev->tcphdr->seqno); + pbuf_realloc(prev->p, prev->len); + } + prev->next = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } + +#if LWIP_TCP_SACK_OUT + /* The new segment goes after the 'next' one. If there is a "hole" in sequence numbers + between 'prev' and the beginning of 'next', we want to move sackbeg. */ + if (prev != NULL && prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { + sackbeg = next->tcphdr->seqno; + } +#endif /* LWIP_TCP_SACK_OUT */ + + /* We don't use 'prev' below, so let's set it to current 'next'. + This way even if we break the loop below, 'prev' will be pointing + at the segment right in front of the newly added one. */ + prev = next; + + /* If the "next" segment is the last segment on the + ooseq queue, we add the incoming segment to the end + of the list. */ + if (next->next == NULL && + TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + /* segment "next" already contains all data */ + break; + } + next->next = tcp_seg_copy(&inseg); + if (next->next != NULL) { + if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { + /* We need to trim the last segment. */ + next->len = (u16_t)(seqno - next->tcphdr->seqno); + pbuf_realloc(next->p, next->len); + } + /* check if the remote side overruns our receive window */ + if (TCP_SEQ_GT((u32_t)tcplen + seqno, pcb->rcv_nxt + (u32_t)pcb->rcv_wnd)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) & ~TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + next->next->len = (u16_t)(pcb->rcv_nxt + pcb->rcv_wnd - seqno); + pbuf_realloc(next->next->p, next->next->len); + tcplen = TCP_TCPLEN(next->next); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } + } + break; + } + } + } + +#if LWIP_TCP_SACK_OUT + if (pcb->flags & TF_SACK) { + if (prev == NULL) { + /* The new segment is at the beginning. sackbeg should already be set properly. + We need to find the right edge. */ + next = pcb->ooseq; + } else if (prev->next != NULL) { + /* The new segment was added after 'prev'. If there is a "hole" between 'prev' and 'prev->next', + we need to move sackbeg. After that we should find the right edge. */ + next = prev->next; + if (prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { + sackbeg = next->tcphdr->seqno; + } + } else { + next = NULL; + } + if (next != NULL) { + u32_t sackend = next->tcphdr->seqno; + for ( ; (next != NULL) && (sackend == next->tcphdr->seqno); next = next->next) { + sackend += next->len; + } + tcp_add_sack(pcb, sackbeg, sackend); + } + } +#endif /* LWIP_TCP_SACK_OUT */ + } +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) + { + /* Check that the data on ooseq doesn't exceed one of the limits + and throw away everything above that limit. */ +#ifdef TCP_OOSEQ_BYTES_LIMIT + const u32_t ooseq_max_blen = TCP_OOSEQ_BYTES_LIMIT(pcb); + u32_t ooseq_blen = 0; +#endif +#ifdef TCP_OOSEQ_PBUFS_LIMIT + const u16_t ooseq_max_qlen = TCP_OOSEQ_PBUFS_LIMIT(pcb); + u16_t ooseq_qlen = 0; +#endif + struct tcp_seg *next, *prev = NULL; + for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { + struct pbuf *p = next->p; + int stop_here = 0; +#ifdef TCP_OOSEQ_BYTES_LIMIT + ooseq_blen += p->tot_len; + if (ooseq_blen > ooseq_max_blen) { + stop_here = 1; + } +#endif +#ifdef TCP_OOSEQ_PBUFS_LIMIT + ooseq_qlen += pbuf_clen(p); + if (ooseq_qlen > ooseq_max_qlen) { + stop_here = 1; + } +#endif + if (stop_here) { +#if LWIP_TCP_SACK_OUT + if (pcb->flags & TF_SACK) { + /* Let's remove all SACKs from next's seqno up. */ + tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); + } +#endif /* LWIP_TCP_SACK_OUT */ + /* too much ooseq data, dump this and everything after it */ + tcp_segs_free(next); + if (prev == NULL) { + /* first ooseq segment is too much, dump the whole queue */ + pcb->ooseq = NULL; + } else { + /* just dump 'next' and everything after it */ + prev->next = NULL; + } + break; + } + } + } +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ +#endif /* TCP_QUEUE_OOSEQ */ + + /* We send the ACK packet after we've (potentially) dealt with SACKs, + so they can be included in the acknowledgment. */ + tcp_send_empty_ack(pcb); + } + } else { + /* The incoming segment is not within the window. */ + tcp_send_empty_ack(pcb); + } + } else { + /* Segments with length 0 is taken care of here. Segments that + fall out of the window are ACKed. */ + if (!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)) { + tcp_ack_now(pcb); + } + } +} + +static u8_t +tcp_get_next_optbyte(void) +{ + u16_t optidx = tcp_optidx++; + if ((tcphdr_opt2 == NULL) || (optidx < tcphdr_opt1len)) { + u8_t *opts = (u8_t *)tcphdr + TCP_HLEN; + return opts[optidx]; + } else { + u8_t idx = (u8_t)(optidx - tcphdr_opt1len); + return tcphdr_opt2[idx]; + } +} + +/** + * Parses the options contained in the incoming segment. + * + * Called from tcp_listen_input() and tcp_process(). + * Currently, only the MSS option is supported! + * + * @param pcb the tcp_pcb for which a segment arrived + */ +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ + u8_t data; + u16_t mss; +#if LWIP_TCP_TIMESTAMPS + u32_t tsval; +#endif + + LWIP_ASSERT("tcp_parseopt: invalid pcb", pcb != NULL); + + /* Parse the TCP MSS option, if present. */ + if (tcphdr_optlen != 0) { + for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { + u8_t opt = tcp_get_next_optbyte(); + switch (opt) { + case LWIP_TCP_OPT_EOL: + /* End of options. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); + return; + case LWIP_TCP_OPT_NOP: + /* NOP option. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); + break; + case LWIP_TCP_OPT_MSS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); + if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* An MSS option with the right option length. */ + mss = (u16_t)(tcp_get_next_optbyte() << 8); + mss |= tcp_get_next_optbyte(); + /* Limit the mss to the configured TCP_MSS and prevent division by zero */ + pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; + break; +#if LWIP_WND_SCALE + case LWIP_TCP_OPT_WS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); + if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* An WND_SCALE option with the right option length. */ + data = tcp_get_next_optbyte(); + /* If syn was received with wnd scale option, + activate wnd scale opt, but only if this is not a retransmission */ + if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) { + pcb->snd_scale = data; + if (pcb->snd_scale > 14U) { + pcb->snd_scale = 14U; + } + pcb->rcv_scale = TCP_RCV_SCALE; + tcp_set_flags(pcb, TF_WND_SCALE); + /* window scaling is enabled, we can use the full receive window */ + LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); + LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; + } + break; +#endif /* LWIP_WND_SCALE */ +#if LWIP_TCP_TIMESTAMPS + case LWIP_TCP_OPT_TS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); + if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* TCP timestamp option with valid length */ + tsval = tcp_get_next_optbyte(); + tsval |= (tcp_get_next_optbyte() << 8); + tsval |= (tcp_get_next_optbyte() << 16); + tsval |= (tcp_get_next_optbyte() << 24); + if (flags & TCP_SYN) { + pcb->ts_recent = lwip_ntohl(tsval); + /* Enable sending timestamps in every segment now that we know + the remote host supports it. */ + tcp_set_flags(pcb, TF_TIMESTAMP); + } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno + tcplen)) { + pcb->ts_recent = lwip_ntohl(tsval); + } + /* Advance to next option (6 bytes already read) */ + tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; + break; +#endif /* LWIP_TCP_TIMESTAMPS */ +#if LWIP_TCP_SACK_OUT + case LWIP_TCP_OPT_SACK_PERM: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: SACK_PERM\n")); + if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_SACK_PERM || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_SACK_PERM) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* TCP SACK_PERM option with valid length */ + if (flags & TCP_SYN) { + /* We only set it if we receive it in a SYN (or SYN+ACK) packet */ + tcp_set_flags(pcb, TF_SACK); + } + break; +#endif /* LWIP_TCP_SACK_OUT */ + default: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); + data = tcp_get_next_optbyte(); + if (data < 2) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + /* If the length field is zero, the options are malformed + and we don't process them further. */ + return; + } + /* All other options have a length field, so that we easily + can skip past them. */ + tcp_optidx += data - 2; + } + } + } +} + +void +tcp_trigger_input_pcb_close(void) +{ + recv_flags |= TF_CLOSED; +} + +#if LWIP_TCP_SACK_OUT +/** + * Called by tcp_receive() to add new SACK entry. + * + * The new SACK entry will be placed at the beginning of rcv_sacks[], as the newest one. + * Existing SACK entries will be "pushed back", to preserve their order. + * This is the behavior described in RFC 2018, section 4. + * + * @param pcb the tcp_pcb for which a segment arrived + * @param left the left side of the SACK (the first sequence number) + * @param right the right side of the SACK (the first sequence number past this SACK) + */ +static void +tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right) +{ + u8_t i; + u8_t unused_idx; + + if ((pcb->flags & TF_SACK) == 0 || !TCP_SEQ_LT(left, right)) { + return; + } + + /* First, let's remove all SACKs that are no longer needed (because they overlap with the newest one), + while moving all other SACKs forward. + We run this loop for all entries, until we find the first invalid one. + There is no point checking after that. */ + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { + /* We only want to use SACK at [i] if it doesn't overlap with left:right range. + It does not overlap if its right side is before the newly added SACK, + or if its left side is after the newly added SACK. + NOTE: The equality should not really happen, but it doesn't hurt. */ + if (TCP_SEQ_LEQ(pcb->rcv_sacks[i].right, left) || TCP_SEQ_LEQ(right, pcb->rcv_sacks[i].left)) { + if (unused_idx != i) { + /* We don't need to copy if it's already in the right spot */ + pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; + } + ++unused_idx; + } + } + + /* Now 'unused_idx' is the index of the first invalid SACK entry, + anywhere between 0 (no valid entries) and LWIP_TCP_MAX_SACK_NUM (all entries are valid). + We want to clear this and all following SACKs. + However, we will be adding another one in the front (and shifting everything else back). + So let's just iterate from the back, and set each entry to the one to the left if it's valid, + or to 0 if it is not. */ + for (i = LWIP_TCP_MAX_SACK_NUM - 1; i > 0; --i) { + /* [i] is the index we are setting, and the value should be at index [i-1], + or 0 if that index is unused (>= unused_idx). */ + if (i - 1 >= unused_idx) { + /* [i-1] is unused. Let's clear [i]. */ + pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; + } else { + pcb->rcv_sacks[i] = pcb->rcv_sacks[i - 1]; + } + } + + /* And now we can store the newest SACK */ + pcb->rcv_sacks[0].left = left; + pcb->rcv_sacks[0].right = right; +} + +/** + * Called to remove a range of SACKs. + * + * SACK entries will be removed or adjusted to not acknowledge any sequence + * numbers that are less than 'seq' passed. It not only invalidates entries, + * but also moves all entries that are still valid to the beginning. + * + * @param pcb the tcp_pcb to modify + * @param seq the lowest sequence number to keep in SACK entries + */ +static void +tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) +{ + u8_t i; + u8_t unused_idx; + + /* We run this loop for all entries, until we find the first invalid one. + There is no point checking after that. */ + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { + /* We only want to use SACK at index [i] if its right side is > 'seq'. */ + if (TCP_SEQ_GT(pcb->rcv_sacks[i].right, seq)) { + if (unused_idx != i) { + /* We only copy it if it's not in the right spot already. */ + pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; + } + /* NOTE: It is possible that its left side is < 'seq', in which case we should adjust it. */ + if (TCP_SEQ_LT(pcb->rcv_sacks[unused_idx].left, seq)) { + pcb->rcv_sacks[unused_idx].left = seq; + } + ++unused_idx; + } + } + + /* We also need to invalidate everything from 'unused_idx' till the end */ + for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { + pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; + } +} + +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) +/** + * Called to remove a range of SACKs. + * + * SACK entries will be removed or adjusted to not acknowledge any sequence + * numbers that are greater than (or equal to) 'seq' passed. It not only invalidates entries, + * but also moves all entries that are still valid to the beginning. + * + * @param pcb the tcp_pcb to modify + * @param seq the highest sequence number to keep in SACK entries + */ +static void +tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) +{ + u8_t i; + u8_t unused_idx; + + /* We run this loop for all entries, until we find the first invalid one. + There is no point checking after that. */ + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { + /* We only want to use SACK at index [i] if its left side is < 'seq'. */ + if (TCP_SEQ_LT(pcb->rcv_sacks[i].left, seq)) { + if (unused_idx != i) { + /* We only copy it if it's not in the right spot already. */ + pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; + } + /* NOTE: It is possible that its right side is > 'seq', in which case we should adjust it. */ + if (TCP_SEQ_GT(pcb->rcv_sacks[unused_idx].right, seq)) { + pcb->rcv_sacks[unused_idx].right = seq; + } + ++unused_idx; + } + } + + /* We also need to invalidate everything from 'unused_idx' till the end */ + for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { + pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; + } +} +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ + +#endif /* LWIP_TCP_SACK_OUT */ + +#endif /* LWIP_TCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_out.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_out.c new file mode 100644 index 0000000..8149d39 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/tcp_out.c @@ -0,0 +1,2191 @@ +/** + * @file + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + * There are two distinct ways for TCP segments to get sent: + * - queued data: these are segments transferring data or segments containing + * SYN or FIN (which both count as one sequence number). They are created as + * struct @ref pbuf together with a struct tcp_seg and enqueue to the + * unsent list of the pcb. They are sent by tcp_output: + * - @ref tcp_write : creates data segments + * - @ref tcp_split_unsent_seg : splits a data segment + * - @ref tcp_enqueue_flags : creates SYN-only or FIN-only segments + * - @ref tcp_output / tcp_output_segment : finalize the tcp header + * (e.g. sequence numbers, options, checksum) and output to IP + * - the various tcp_rexmit functions shuffle around segments between the + * unsent an unacked lists to retransmit them + * - tcp_create_segment and tcp_pbuf_prealloc allocate pbuf and + * segment for these functions + * - direct send: these segments don't contain data but control the connection + * behaviour. They are created as pbuf only and sent directly without + * enqueueing them: + * - @ref tcp_send_empty_ack sends an ACK-only segment + * - @ref tcp_rst sends a RST segment + * - @ref tcp_keepalive sends a keepalive segment + * - @ref tcp_zero_window_probe sends a window probe segment + * - tcp_output_alloc_header allocates a header-only pbuf for these functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcp_priv.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#if LWIP_TCP_TIMESTAMPS +#include "lwip/sys.h" +#endif + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/* Allow to add custom TCP header options by defining this hook */ +#ifdef LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH +#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH(pcb, LWIP_TCP_OPT_LENGTH(flags)) +#else +#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_TCP_OPT_LENGTH(flags) +#endif + +/* Define some copy-macros for checksum-on-copy so that the code looks + nicer by preventing too many ifdef's. */ +#if TCP_CHECKSUM_ON_COPY +#define TCP_DATA_COPY(dst, src, len, seg) do { \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ + len, &seg->chksum, &seg->chksum_swapped); \ + seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); +#else /* TCP_CHECKSUM_ON_COPY*/ +#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) +#endif /* TCP_CHECKSUM_ON_COPY*/ + +/** Define this to 1 for an extra check that the output checksum is valid + * (usefule when the checksum is generated by the application, not the stack) */ +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 +#endif +/* Allow to override the failure of sanity check from warning to e.g. hard failure */ +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(msg) LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, msg) +#endif +#endif + +#if TCP_OVERSIZE +/** The size of segment pbufs created when TCP_OVERSIZE is enabled */ +#ifndef TCP_OVERSIZE_CALC_LENGTH +#define TCP_OVERSIZE_CALC_LENGTH(length) ((length) + TCP_OVERSIZE) +#endif +#endif + +/* Forward declarations.*/ +static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif); + +/* tcp_route: common code that returns a fixed bound netif or calls ip_route */ +static struct netif * +tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) +{ + LWIP_UNUSED_ARG(src); /* in case IPv4-only and source-based routing is disabled */ + + if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { + return netif_get_by_index(pcb->netif_idx); + } else { + return ip_route(src, dst); + } +} + +/** + * Create a TCP segment with prefilled header. + * + * Called by @ref tcp_write, @ref tcp_enqueue_flags and @ref tcp_split_unsent_seg + * + * @param pcb Protocol control block for the TCP connection. + * @param p pbuf that is used to hold the TCP header. + * @param hdrflags TCP flags for header. + * @param seqno TCP sequence number of this packet + * @param optflags options to include in TCP header + * @return a new tcp_seg pointing to p, or NULL. + * The TCP header is filled in except ackno and wnd. + * p is freed on failure. + */ +static struct tcp_seg * +tcp_create_segment(const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, u32_t seqno, u8_t optflags) +{ + struct tcp_seg *seg; + u8_t optlen; + + LWIP_ASSERT("tcp_create_segment: invalid pcb", pcb != NULL); + LWIP_ASSERT("tcp_create_segment: invalid pbuf", p != NULL); + + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); + + if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n")); + pbuf_free(p); + return NULL; + } + seg->flags = optflags; + seg->next = NULL; + seg->p = p; + LWIP_ASSERT("p->tot_len >= optlen", p->tot_len >= optlen); + seg->len = p->tot_len - optlen; +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = 0; + seg->chksum_swapped = 0; + /* check optflags */ + LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", + (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* build TCP header */ + if (pbuf_add_header(p, TCP_HLEN)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no room for TCP header in pbuf.\n")); + TCP_STATS_INC(tcp.err); + tcp_seg_free(seg); + return NULL; + } + seg->tcphdr = (struct tcp_hdr *)seg->p->payload; + seg->tcphdr->src = lwip_htons(pcb->local_port); + seg->tcphdr->dest = lwip_htons(pcb->remote_port); + seg->tcphdr->seqno = lwip_htonl(seqno); + /* ackno is set in tcp_output */ + TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), hdrflags); + /* wnd and chksum are set in tcp_output */ + seg->tcphdr->urgp = 0; + return seg; +} + +/** + * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. + * + * This function is like pbuf_alloc(layer, length, PBUF_RAM) except + * there may be extra bytes available at the end. + * + * Called by @ref tcp_write + * + * @param layer flag to define header size. + * @param length size of the pbuf's payload. + * @param max_length maximum usable size of payload+oversize. + * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. + * @param pcb The TCP connection that will enqueue the pbuf. + * @param apiflags API flags given to tcp_write. + * @param first_seg true when this pbuf will be used in the first enqueued segment. + */ +#if TCP_OVERSIZE +static struct pbuf * +tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, + u16_t *oversize, const struct tcp_pcb *pcb, u8_t apiflags, + u8_t first_seg) +{ + struct pbuf *p; + u16_t alloc = length; + + LWIP_ASSERT("tcp_pbuf_prealloc: invalid oversize", oversize != NULL); + LWIP_ASSERT("tcp_pbuf_prealloc: invalid pcb", pcb != NULL); + +#if LWIP_NETIF_TX_SINGLE_PBUF + LWIP_UNUSED_ARG(max_length); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(apiflags); + LWIP_UNUSED_ARG(first_seg); + alloc = max_length; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (length < max_length) { + /* Should we allocate an oversized pbuf, or just the minimum + * length required? If tcp_write is going to be called again + * before this segment is transmitted, we want the oversized + * buffer. If the segment will be transmitted immediately, we can + * save memory by allocating only length. We use a simple + * heuristic based on the following information: + * + * Did the user set TCP_WRITE_FLAG_MORE? + * + * Will the Nagle algorithm defer transmission of this segment? + */ + if ((apiflags & TCP_WRITE_FLAG_MORE) || + (!(pcb->flags & TF_NODELAY) && + (!first_seg || + pcb->unsent != NULL || + pcb->unacked != NULL))) { + alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(TCP_OVERSIZE_CALC_LENGTH(length))); + } + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(layer, alloc, PBUF_RAM); + if (p == NULL) { + return NULL; + } + LWIP_ASSERT("need unchained pbuf", p->next == NULL); + *oversize = p->len - length; + /* trim p->len to the currently used size */ + p->len = p->tot_len = length; + return p; +} +#else /* TCP_OVERSIZE */ +#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) +#endif /* TCP_OVERSIZE */ + +#if TCP_CHECKSUM_ON_COPY +/** Add a checksum of newly added data to the segment. + * + * Called by tcp_write and tcp_split_unsent_seg. + */ +static void +tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, + u8_t *seg_chksum_swapped) +{ + u32_t helper; + /* add chksum to old chksum and fold to u16_t */ + helper = chksum + *seg_chksum; + chksum = FOLD_U32T(helper); + if ((len & 1) != 0) { + *seg_chksum_swapped = 1 - *seg_chksum_swapped; + chksum = SWAP_BYTES_IN_WORD(chksum); + } + *seg_chksum = chksum; +} +#endif /* TCP_CHECKSUM_ON_COPY */ + +/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). + * + * @param pcb the tcp pcb to check for + * @param len length of data to send (checked agains snd_buf) + * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise + */ +static err_t +tcp_write_checks(struct tcp_pcb *pcb, u16_t len) +{ + LWIP_ASSERT("tcp_write_checks: invalid pcb", pcb != NULL); + + /* connection is in invalid state for data transmission? */ + if ((pcb->state != ESTABLISHED) && + (pcb->state != CLOSE_WAIT) && + (pcb->state != SYN_SENT) && + (pcb->state != SYN_RCVD)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); + return ERR_CONN; + } else if (len == 0) { + return ERR_OK; + } + + /* fail on too much data */ + if (len > pcb->snd_buf) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"TCPWNDSIZE_F")\n", + len, pcb->snd_buf)); + tcp_set_flags(pcb, TF_NAGLEMEMERR); + return ERR_MEM; + } + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); + + /* If total number of pbufs on the unsent/unacked queues exceeds the + * configured maximum, return an error */ + /* check for configured max queuelen and possible overflow */ + if (pcb->snd_queuelen >= LWIP_MIN(TCP_SND_QUEUELEN, (TCP_SNDQUEUELEN_OVERFLOW + 1))) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + tcp_set_flags(pcb, TF_NAGLEMEMERR); + return ERR_MEM; + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", + pcb->unacked != NULL || pcb->unsent != NULL); + } else { + LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", + pcb->unacked == NULL && pcb->unsent == NULL); + } + return ERR_OK; +} + +/** + * @ingroup tcp_raw + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + * + * This function enqueues the data pointed to by the argument dataptr. The length of + * the data is passed as the len parameter. The apiflags can be one or more of: + * - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated + * for the data to be copied into. If this flag is not given, no new memory + * should be allocated and the data should only be referenced by pointer. This + * also means that the memory behind dataptr must not change until the data is + * ACKed by the remote host + * - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted, + * the PSH flag is set in the last segment created by this call to tcp_write. + * If this flag is given, the PSH flag is not set. + * + * The tcp_write() function will fail and return ERR_MEM if the length + * of the data exceeds the current send buffer size or if the length of + * the queue of outgoing segment is larger than the upper limit defined + * in lwipopts.h. The number of bytes available in the output queue can + * be retrieved with the tcp_sndbuf() function. + * + * The proper way to use this function is to call the function with at + * most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, + * the application should wait until some of the currently enqueued + * data has been successfully received by the other host and try again. + * + * @param pcb Protocol control block for the TCP connection to enqueue data for. + * @param arg Pointer to the data to be enqueued for sending. + * @param len Data length in bytes + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will not be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) +{ + struct pbuf *concat_p = NULL; + struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; + u16_t pos = 0; /* position in 'arg' data */ + u16_t queuelen; + u8_t optlen; + u8_t optflags = 0; +#if TCP_OVERSIZE + u16_t oversize = 0; + u16_t oversize_used = 0; +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_add = 0; +#endif /* TCP_OVERSIZE_DBGCHECK*/ +#endif /* TCP_OVERSIZE */ + u16_t extendlen = 0; +#if TCP_CHECKSUM_ON_COPY + u16_t concat_chksum = 0; + u8_t concat_chksum_swapped = 0; + u16_t concat_chksummed = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + err_t err; + u16_t mss_local; + + LWIP_ERROR("tcp_write: invalid pcb", pcb != NULL, return ERR_ARG); + + /* don't allocate segments bigger than half the maximum window we ever received */ + mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2)); + mss_local = mss_local ? mss_local : pcb->mss; + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Always copy to try to create single pbufs for TX */ + apiflags |= TCP_WRITE_FLAG_COPY; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)apiflags)); + LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", + arg != NULL, return ERR_ARG;); + + err = tcp_write_checks(pcb, len); + if (err != ERR_OK) { + return err; + } + queuelen = pcb->snd_queuelen; + +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + /* Make sure the timestamp option is only included in data segments if we + agreed about it with the remote host. */ + optflags = TF_SEG_OPTS_TS; + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(TF_SEG_OPTS_TS, pcb); + /* ensure that segments can hold at least one data byte... */ + mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); + } else +#endif /* LWIP_TCP_TIMESTAMPS */ + { + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); + } + + + /* + * TCP segmentation is done in three phases with increasing complexity: + * + * 1. Copy data directly into an oversized pbuf. + * 2. Chain a new pbuf to the end of pcb->unsent. + * 3. Create new segments. + * + * We may run out of memory at any point. In that case we must + * return ERR_MEM and not change anything in pcb. Therefore, all + * changes are recorded in local variables and committed at the end + * of the function. Some pcb fields are maintained in local copies: + * + * queuelen = pcb->snd_queuelen + * oversize = pcb->unsent_oversize + * + * These variables are set consistently by the phases: + * + * seg points to the last segment tampered with. + * + * pos records progress as data is segmented. + */ + + /* Find the tail of the unsent queue. */ + if (pcb->unsent != NULL) { + u16_t space; + u16_t unsent_optlen; + + /* @todo: this could be sped up by keeping last_unsent in the pcb */ + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + /* Usable space at the end of the last unsent segment */ + unsent_optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(last_unsent->flags, pcb); + LWIP_ASSERT("mss_local is too small", mss_local >= last_unsent->len + unsent_optlen); + space = mss_local - (last_unsent->len + unsent_optlen); + + /* + * Phase 1: Copy data directly into an oversized pbuf. + * + * The number of bytes copied is recorded in the oversize_used + * variable. The actual copying is done at the bottom of the + * function. + */ +#if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->oversize_left */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ + oversize = pcb->unsent_oversize; + if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize <= space); + seg = last_unsent; + oversize_used = LWIP_MIN(space, LWIP_MIN(oversize, len)); + pos += oversize_used; + oversize -= oversize_used; + space -= oversize_used; + } + /* now we are either finished or oversize is zero */ + LWIP_ASSERT("inconsistent oversize vs. len", (oversize == 0) || (pos == len)); +#endif /* TCP_OVERSIZE */ + +#if !LWIP_NETIF_TX_SINGLE_PBUF + /* + * Phase 2: Chain a new pbuf to the end of pcb->unsent. + * + * As an exception when NOT copying the data, if the given data buffer + * directly follows the last unsent data buffer in memory, extend the last + * ROM pbuf reference to the buffer, thus saving a ROM pbuf allocation. + * + * We don't extend segments containing SYN/FIN flags or options + * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at + * the end. + * + * This phase is skipped for LWIP_NETIF_TX_SINGLE_PBUF as we could only execute + * it after rexmit puts a segment from unacked to unsent and at this point, + * oversize info is lost. + */ + if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { + u16_t seglen = LWIP_MIN(space, len - pos); + seg = last_unsent; + + /* Create a pbuf with a copy or reference to seglen bytes. We + * can use PBUF_RAW here since the data appears in the middle of + * a segment. A header will never be prepended. */ + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* Data is copied */ + if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", + seglen)); + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + oversize_add = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ + TCP_DATA_COPY2(concat_p->payload, (const u8_t *)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); +#if TCP_CHECKSUM_ON_COPY + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + queuelen += pbuf_clen(concat_p); + } else { + /* Data is not copied */ + /* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */ + struct pbuf *p; + for (p = last_unsent->p; p->next != NULL; p = p->next); + if (((p->type_internal & (PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_DATA_VOLATILE)) == 0) && + (const u8_t *)p->payload + p->len == (const u8_t *)arg) { + LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0); + extendlen = seglen; + } else { + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } + /* reference the non-volatile payload data */ + ((struct pbuf_rom *)concat_p)->payload = (const u8_t *)arg + pos; + queuelen += pbuf_clen(concat_p); + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + tcp_seg_add_chksum(~inet_chksum((const u8_t *)arg + pos, seglen), seglen, + &concat_chksum, &concat_chksum_swapped); + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + } + + pos += seglen; + } +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + } else { +#if TCP_OVERSIZE + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); +#endif /* TCP_OVERSIZE */ + } + + /* + * Phase 3: Create new segments. + * + * The new segments are chained together in the local 'queue' + * variable, ready to be appended to pcb->unsent. + */ + while (pos < len) { + struct pbuf *p; + u16_t left = len - pos; + u16_t max_len = mss_local - optlen; + u16_t seglen = LWIP_MIN(left, max_len); +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* If copy is set, memory should be allocated and data copied + * into pbuf */ + if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + goto memerr; + } + LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", + (p->len >= seglen)); + TCP_DATA_COPY2((char *)p->payload + optlen, (const u8_t *)arg + pos, seglen, &chksum, &chksum_swapped); + } else { + /* Copy is not set: First allocate a pbuf for holding the data. + * Since the referenced data is available at least until it is + * sent out on the link (as it has to be ACKed by the remote + * party) we can safely use PBUF_ROM instead of PBUF_REF here. + */ + struct pbuf *p2; +#if TCP_OVERSIZE + LWIP_ASSERT("oversize == 0", oversize == 0); +#endif /* TCP_OVERSIZE */ + if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + chksum = ~inet_chksum((const u8_t *)arg + pos, seglen); + if (seglen & 1) { + chksum_swapped = 1; + chksum = SWAP_BYTES_IN_WORD(chksum); + } +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + ((struct pbuf_rom *)p2)->payload = (const u8_t *)arg + pos; + + /* Second, allocate a pbuf for the headers. */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + /* If allocation fails, we have to deallocate the data pbuf as + * well. */ + pbuf_free(p2); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for header pbuf\n")); + goto memerr; + } + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(p/*header*/, p2/*data*/); + } + + queuelen += pbuf_clen(p); + + /* Now that there are more segments queued, we check again if the + * length of the queue exceeds the configured maximum or + * overflows. */ + if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", + queuelen, (int)TCP_SND_QUEUELEN)); + pbuf_free(p); + goto memerr; + } + + if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = chksum; + seg->chksum_swapped = chksum_swapped; + seg->flags |= TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* first segment of to-be-queued data? */ + if (queue == NULL) { + queue = seg; + } else { + /* Attach the segment to the end of the queued segments */ + LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); + prev_seg->next = seg; + } + /* remember last segment of to-be-queued data for next iteration */ + prev_seg = seg; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", + lwip_ntohl(seg->tcphdr->seqno), + lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); + + pos += seglen; + } + + /* + * All three segmentation phases were successful. We can commit the + * transaction. + */ +#if TCP_OVERSIZE_DBGCHECK + if ((last_unsent != NULL) && (oversize_add != 0)) { + last_unsent->oversize_left += oversize_add; + } +#endif /* TCP_OVERSIZE_DBGCHECK */ + + /* + * Phase 1: If data has been added to the preallocated tail of + * last_unsent, we update the length fields of the pbuf chain. + */ +#if TCP_OVERSIZE + if (oversize_used > 0) { + struct pbuf *p; + /* Bump tot_len of whole chain, len of tail */ + for (p = last_unsent->p; p; p = p->next) { + p->tot_len += oversize_used; + if (p->next == NULL) { + TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); + p->len += oversize_used; + } + } + last_unsent->len += oversize_used; +#if TCP_OVERSIZE_DBGCHECK + LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", + last_unsent->oversize_left >= oversize_used); + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ + } + pcb->unsent_oversize = oversize; +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: concat_p can be concatenated onto last_unsent->p, unless we + * determined that the last ROM pbuf can be extended to include the new data. + */ + if (concat_p != NULL) { + LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", + (last_unsent != NULL)); + pbuf_cat(last_unsent->p, concat_p); + last_unsent->len += concat_p->tot_len; + } else if (extendlen > 0) { + struct pbuf *p; + LWIP_ASSERT("tcp_write: extension of reference requires reference", + last_unsent != NULL && last_unsent->p != NULL); + for (p = last_unsent->p; p->next != NULL; p = p->next) { + p->tot_len += extendlen; + } + p->tot_len += extendlen; + p->len += extendlen; + last_unsent->len += extendlen; + } + +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + LWIP_ASSERT("tcp_write: concat checksum needs concatenated data", + concat_p != NULL || extendlen > 0); + /*if concat checksumm swapped - swap it back */ + if (concat_chksum_swapped) { + concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); + } + tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, + &last_unsent->chksum_swapped); + last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; + } +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* + * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that + * is harmless + */ + if (last_unsent == NULL) { + pcb->unsent = queue; + } else { + last_unsent->next = queue; + } + + /* + * Finally update the pcb state. + */ + pcb->snd_lbb += len; + pcb->snd_buf -= len; + pcb->snd_queuelen = queuelen; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", + pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + /* Set the PSH flag in the last segment that we enqueued. */ + if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE) == 0)) { + TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); + } + + return ERR_OK; +memerr: + tcp_set_flags(pcb, TF_NAGLEMEMERR); + TCP_STATS_INC(tcp.memerr); + + if (concat_p != NULL) { + pbuf_free(concat_p); + } + if (queue != NULL) { + tcp_segs_free(queue); + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); + return ERR_MEM; +} + +/** + * Split segment on the head of the unsent queue. If return is not + * ERR_OK, existing head remains intact + * + * The split is accomplished by creating a new TCP segment and pbuf + * which holds the remainder payload after the split. The original + * pbuf is trimmed to new length. This allows splitting of read-only + * pbufs + * + * @param pcb the tcp_pcb for which to split the unsent head + * @param split the amount of payload to remain in the head + */ +err_t +tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split) +{ + struct tcp_seg *seg = NULL, *useg = NULL; + struct pbuf *p = NULL; + u8_t optlen; + u8_t optflags; + u8_t split_flags; + u8_t remainder_flags; + u16_t remainder; + u16_t offset; +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; + struct pbuf *q; +#endif /* TCP_CHECKSUM_ON_COPY */ + + LWIP_ASSERT("tcp_split_unsent_seg: invalid pcb", pcb != NULL); + + useg = pcb->unsent; + if (useg == NULL) { + return ERR_MEM; + } + + if (split == 0) { + LWIP_ASSERT("Can't split segment into length 0", 0); + return ERR_VAL; + } + + if (useg->len <= split) { + return ERR_OK; + } + + LWIP_ASSERT("split <= mss", split <= pcb->mss); + LWIP_ASSERT("useg->len > 0", useg->len > 0); + + /* We should check that we don't exceed TCP_SND_QUEUELEN but we need + * to split this packet so we may actually exceed the max value by + * one! + */ + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: split_unsent_seg: %u\n", (unsigned int)pcb->snd_queuelen)); + + optflags = useg->flags; +#if TCP_CHECKSUM_ON_COPY + /* Remove since checksum is not stored until after tcp_create_segment() */ + optflags &= ~TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + optlen = LWIP_TCP_OPT_LENGTH(optflags); + remainder = useg->len - split; + + /* Create new pbuf for the remainder of the split */ + p = pbuf_alloc(PBUF_TRANSPORT, remainder + optlen, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_split_unsent_seg: could not allocate memory for pbuf remainder %u\n", remainder)); + goto memerr; + } + + /* Offset into the original pbuf is past TCP/IP headers, options, and split amount */ + offset = useg->p->tot_len - useg->len + split; + /* Copy remainder into new pbuf, headers and options will not be filled out */ + if (pbuf_copy_partial(useg->p, (u8_t *)p->payload + optlen, remainder, offset ) != remainder) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_split_unsent_seg: could not copy pbuf remainder %u\n", remainder)); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum on remainder data */ + tcp_seg_add_chksum(~inet_chksum((const u8_t *)p->payload + optlen, remainder), remainder, + &chksum, &chksum_swapped); +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* Options are created when calling tcp_output() */ + + /* Migrate flags from original segment */ + split_flags = TCPH_FLAGS(useg->tcphdr); + remainder_flags = 0; /* ACK added in tcp_output() */ + + if (split_flags & TCP_PSH) { + split_flags &= ~TCP_PSH; + remainder_flags |= TCP_PSH; + } + if (split_flags & TCP_FIN) { + split_flags &= ~TCP_FIN; + remainder_flags |= TCP_FIN; + } + /* SYN should be left on split, RST should not be present with data */ + + seg = tcp_create_segment(pcb, p, remainder_flags, lwip_ntohl(useg->tcphdr->seqno) + split, optflags); + if (seg == NULL) { + p = NULL; /* Freed by tcp_create_segment */ + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_split_unsent_seg: could not create new TCP segment\n")); + goto memerr; + } + +#if TCP_CHECKSUM_ON_COPY + seg->chksum = chksum; + seg->chksum_swapped = chksum_swapped; + seg->flags |= TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* Remove this segment from the queue since trimming it may free pbufs */ + pcb->snd_queuelen -= pbuf_clen(useg->p); + + /* Trim the original pbuf into our split size. At this point our remainder segment must be setup + successfully because we are modifying the original segment */ + pbuf_realloc(useg->p, useg->p->tot_len - remainder); + useg->len -= remainder; + TCPH_SET_FLAG(useg->tcphdr, split_flags); +#if TCP_OVERSIZE_DBGCHECK + /* By trimming, realloc may have actually shrunk the pbuf, so clear oversize_left */ + useg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ + + /* Add back to the queue with new trimmed pbuf */ + pcb->snd_queuelen += pbuf_clen(useg->p); + +#if TCP_CHECKSUM_ON_COPY + /* The checksum on the split segment is now incorrect. We need to re-run it over the split */ + useg->chksum = 0; + useg->chksum_swapped = 0; + q = useg->p; + offset = q->tot_len - useg->len; /* Offset due to exposed headers */ + + /* Advance to the pbuf where the offset ends */ + while (q != NULL && offset > q->len) { + offset -= q->len; + q = q->next; + } + LWIP_ASSERT("Found start of payload pbuf", q != NULL); + /* Checksum the first payload pbuf accounting for offset, then other pbufs are all payload */ + for (; q != NULL; offset = 0, q = q->next) { + tcp_seg_add_chksum(~inet_chksum((const u8_t *)q->payload + offset, q->len - offset), q->len - offset, + &useg->chksum, &useg->chksum_swapped); + } +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* Update number of segments on the queues. Note that length now may + * exceed TCP_SND_QUEUELEN! We don't have to touch pcb->snd_buf + * because the total amount of data is constant when packet is split */ + pcb->snd_queuelen += pbuf_clen(seg->p); + + /* Finally insert remainder into queue after split (which stays head) */ + seg->next = useg->next; + useg->next = seg; + +#if TCP_OVERSIZE + /* If remainder is last segment on the unsent, ensure we clear the oversize amount + * because the remainder is always sized to the exact remaining amount */ + if (seg->next == NULL) { + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + return ERR_OK; +memerr: + TCP_STATS_INC(tcp.memerr); + + LWIP_ASSERT("seg == NULL", seg == NULL); + if (p != NULL) { + pbuf_free(p); + } + + return ERR_MEM; +} + +/** + * Called by tcp_close() to send a segment including FIN flag but not data. + * This FIN may be added to an existing segment or a new, otherwise empty + * segment is enqueued. + * + * @param pcb the tcp_pcb over which to send a segment + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_fin(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_send_fin: invalid pcb", pcb != NULL); + + /* first, try to add the fin to the last unsent segment */ + if (pcb->unsent != NULL) { + struct tcp_seg *last_unsent; + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { + /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ + TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); + tcp_set_flags(pcb, TF_FIN); + return ERR_OK; + } + } + /* no data, no length, flags, copy=1, no optdata */ + return tcp_enqueue_flags(pcb, TCP_FIN); +} + +/** + * Enqueue SYN or FIN for transmission. + * + * Called by @ref tcp_connect, tcp_listen_input, and @ref tcp_close + * (via @ref tcp_send_fin) + * + * @param pcb Protocol control block for the TCP connection. + * @param flags TCP header flags to set in the outgoing segment. + */ +err_t +tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) +{ + struct pbuf *p; + struct tcp_seg *seg; + u8_t optflags = 0; + u8_t optlen = 0; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", + (flags & (TCP_SYN | TCP_FIN)) != 0); + LWIP_ASSERT("tcp_enqueue_flags: invalid pcb", pcb != NULL); + + /* No need to check pcb->snd_queuelen if only SYN or FIN are allowed! */ + + /* Get options for this segment. This is a special case since this is the + only place where a SYN can be sent. */ + if (flags & TCP_SYN) { + optflags = TF_SEG_OPTS_MSS; +#if LWIP_WND_SCALE + if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) { + /* In a (sent in state SYN_RCVD), the window scale option may only + be sent if we received a window scale option from the remote host. */ + optflags |= TF_SEG_OPTS_WND_SCALE; + } +#endif /* LWIP_WND_SCALE */ +#if LWIP_TCP_SACK_OUT + if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_SACK)) { + /* In a (sent in state SYN_RCVD), the SACK_PERM option may only + be sent if we received a SACK_PERM option from the remote host. */ + optflags |= TF_SEG_OPTS_SACK_PERM; + } +#endif /* LWIP_TCP_SACK_OUT */ + } +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP) || ((flags & TCP_SYN) && (pcb->state != SYN_RCVD))) { + /* Make sure the timestamp option is only included in data segments if we + agreed about it with the remote host (and in active open SYN segments). */ + optflags |= TF_SEG_OPTS_TS; + } +#endif /* LWIP_TCP_TIMESTAMPS */ + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); + + /* Allocate pbuf with room for TCP header + options */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + tcp_set_flags(pcb, TF_NAGLEMEMERR); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", + (p->len >= optlen)); + + /* Allocate memory for tcp_seg, and fill in fields. */ + if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { + tcp_set_flags(pcb, TF_NAGLEMEMERR); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % LWIP_MIN(MEM_ALIGNMENT, 4)) == 0); + LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, + ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", + lwip_ntohl(seg->tcphdr->seqno), + lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), + (u16_t)flags)); + + /* Now append seg to pcb->unsent queue */ + if (pcb->unsent == NULL) { + pcb->unsent = seg; + } else { + struct tcp_seg *useg; + for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); + useg->next = seg; + } +#if TCP_OVERSIZE + /* The new unsent tail has no space */ + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + + /* SYN and FIN bump the sequence number */ + if ((flags & TCP_SYN) || (flags & TCP_FIN)) { + pcb->snd_lbb++; + /* optlen does not influence snd_buf */ + } + if (flags & TCP_FIN) { + tcp_set_flags(pcb, TF_FIN); + } + + /* update number of segments on the queues */ + pcb->snd_queuelen += pbuf_clen(seg->p); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + return ERR_OK; +} + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void +tcp_build_timestamp_option(const struct tcp_pcb *pcb, u32_t *opts) +{ + LWIP_ASSERT("tcp_build_timestamp_option: invalid pcb", pcb != NULL); + + /* Pad with two NOP options to make everything nicely aligned */ + opts[0] = PP_HTONL(0x0101080A); + opts[1] = lwip_htonl(sys_now()); + opts[2] = lwip_htonl(pcb->ts_recent); +} +#endif + +#if LWIP_TCP_SACK_OUT +/** + * Calculates the number of SACK entries that should be generated. + * It takes into account whether TF_SACK flag is set, + * the number of SACK entries in tcp_pcb that are valid, + * as well as the available options size. + * + * @param pcb tcp_pcb + * @param optlen the length of other TCP options (in bytes) + * @return the number of SACK ranges that can be used + */ +static u8_t +tcp_get_num_sacks(const struct tcp_pcb *pcb, u8_t optlen) +{ + u8_t num_sacks = 0; + + LWIP_ASSERT("tcp_get_num_sacks: invalid pcb", pcb != NULL); + + if (pcb->flags & TF_SACK) { + u8_t i; + + /* The first SACK takes up 12 bytes (it includes SACK header and two NOP options), + each additional one - 8 bytes. */ + optlen += 12; + + /* Max options size = 40, number of SACK array entries = LWIP_TCP_MAX_SACK_NUM */ + for (i = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (optlen <= TCP_MAX_OPTION_BYTES) && + LWIP_TCP_SACK_VALID(pcb, i); ++i) { + ++num_sacks; + optlen += 8; + } + } + + return num_sacks; +} + +/** Build a SACK option (12 or more bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the SACK option + * @param num_sacks the number of SACKs to store + */ +static void +tcp_build_sack_option(const struct tcp_pcb *pcb, u32_t *opts, u8_t num_sacks) +{ + u8_t i; + + LWIP_ASSERT("tcp_build_sack_option: invalid pcb", pcb != NULL); + LWIP_ASSERT("tcp_build_sack_option: invalid opts", opts != NULL); + + /* Pad with two NOP options to make everything nicely aligned. + We add the length (of just the SACK option, not the NOPs in front of it), + which is 2B of header, plus 8B for each SACK. */ + *(opts++) = PP_HTONL(0x01010500 + 2 + num_sacks * 8); + + for (i = 0; i < num_sacks; ++i) { + *(opts++) = lwip_htonl(pcb->rcv_sacks[i].left); + *(opts++) = lwip_htonl(pcb->rcv_sacks[i].right); + } +} + +#endif + +#if LWIP_WND_SCALE +/** Build a window scale option (3 bytes long) at the specified options pointer) + * + * @param opts option pointer where to store the window scale option + */ +static void +tcp_build_wnd_scale_option(u32_t *opts) +{ + LWIP_ASSERT("tcp_build_wnd_scale_option: invalid opts", opts != NULL); + + /* Pad with one NOP option to make everything nicely aligned */ + opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE); +} +#endif + +/** + * @ingroup tcp_raw + * Find out what we can send and send it + * + * @param pcb Protocol control block for the TCP connection to send data + * @return ERR_OK if data has been sent or nothing to send + * another err_t on error + */ +err_t +tcp_output(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg, *useg; + u32_t wnd, snd_nxt; + err_t err; + struct netif *netif; +#if TCP_CWND_DEBUG + s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("tcp_output: invalid pcb", pcb != NULL); + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_output for listen-pcbs", + pcb->state != LISTEN); + + /* First, check if we are invoked by the TCP input processing + code. If so, we do not output anything. Instead, we rely on the + input processing code to call us when input processing is done + with. */ + if (tcp_input_pcb == pcb) { + return ERR_OK; + } + + wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + + seg = pcb->unsent; + + if (seg == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", + (void *)pcb->unsent)); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F + ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F + ", seg == NULL, ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); + + /* If the TF_ACK_NOW flag is set and the ->unsent queue is empty, construct + * an empty ACK segment and send it. */ + if (pcb->flags & TF_ACK_NOW) { + return tcp_send_empty_ack(pcb); + } + /* nothing to send: shortcut out of here */ + goto output_done; + } else { + LWIP_DEBUGF(TCP_CWND_DEBUG, + ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F + ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, + lwip_ntohl(seg->tcphdr->seqno), pcb->lastack)); + } + + netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + return ERR_RTE; + } + + /* If we don't have a local IP address, we get one from netif */ + if (ip_addr_isany(&pcb->local_ip)) { + const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, &pcb->remote_ip); + if (local_ip == NULL) { + return ERR_RTE; + } + ip_addr_copy(pcb->local_ip, *local_ip); + } + + /* Handle the current segment not fitting within the window */ + if (lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd) { + /* We need to start the persistent timer when the next unsent segment does not fit + * within the remaining (could be 0) send window and RTO timer is not running (we + * have no in-flight data). If window is still too small after persist timer fires, + * then we split the segment. We don't consider the congestion window since a cwnd + * smaller than 1 SMSS implies in-flight data + */ + if (wnd == pcb->snd_wnd && pcb->unacked == NULL && pcb->persist_backoff == 0) { + pcb->persist_cnt = 0; + pcb->persist_backoff = 1; + pcb->persist_probe = 0; + } + /* We need an ACK, but can't send data now, so send an empty ACK */ + if (pcb->flags & TF_ACK_NOW) { + return tcp_send_empty_ack(pcb); + } + goto output_done; + } + /* Stop persist timer, above conditions are not active */ + pcb->persist_backoff = 0; + + /* useg should point to last segment on unacked queue */ + useg = pcb->unacked; + if (useg != NULL) { + for (; useg->next != NULL; useg = useg->next); + } + /* data available and window allows it to be sent? */ + while (seg != NULL && + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { + LWIP_ASSERT("RST not expected here!", + (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); + /* Stop sending if the nagle algorithm would prevent it + * Don't stop: + * - if tcp_write had a memory error before (prevent delayed ACK timeout) or + * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - + * either seg->next != NULL or pcb->unacked == NULL; + * RST is no sent using tcp_write/tcp_output. + */ + if ((tcp_do_output_nagle(pcb) == 0) && + ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { + break; + } +#if TCP_CWND_DEBUG + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + lwip_ntohl(seg->tcphdr->seqno) + seg->len - + pcb->lastack, + lwip_ntohl(seg->tcphdr->seqno), pcb->lastack, i)); + ++i; +#endif /* TCP_CWND_DEBUG */ + + if (pcb->state != SYN_SENT) { + TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); + } + + err = tcp_output_segment(seg, pcb, netif); + if (err != ERR_OK) { + /* segment could not be sent, for whatever reason */ + tcp_set_flags(pcb, TF_NAGLEMEMERR); + return err; + } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ + pcb->unsent = seg->next; + if (pcb->state != SYN_SENT) { + tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); + } + snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; + } + /* put segment on unacknowledged list if length > 0 */ + if (TCP_TCPLEN(seg) > 0) { + seg->next = NULL; + /* unacked list is empty? */ + if (pcb->unacked == NULL) { + pcb->unacked = seg; + useg = seg; + /* unacked list is not empty? */ + } else { + /* In the case of fast retransmit, the packet should not go to the tail + * of the unacked queue, but rather somewhere before it. We need to check for + * this case. -STJ Jul 27, 2004 */ + if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; + } else { + /* add segment to tail of unacked list */ + useg->next = seg; + useg = useg->next; + } + } + /* do not queue empty segments on the unacked list */ + } else { + tcp_seg_free(seg); + } + seg = pcb->unsent; + } +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + +output_done: + tcp_clear_flags(pcb, TF_NAGLEMEMERR); + return ERR_OK; +} + +/** Check if a segment's pbufs are used by someone else than TCP. + * This can happen on retransmission if the pbuf of this segment is still + * referenced by the netif driver due to deferred transmission. + * This is the case (only!) if someone down the TX call path called + * pbuf_ref() on one of the pbufs! + * + * @arg seg the tcp segment to check + * @return 1 if ref != 1, 0 if ref == 1 + */ +static int +tcp_output_segment_busy(const struct tcp_seg *seg) +{ + LWIP_ASSERT("tcp_output_segment_busy: invalid seg", seg != NULL); + + /* We only need to check the first pbuf here: + If a pbuf is queued for transmission, a driver calls pbuf_ref(), + which only changes the ref count of the first pbuf */ + if (seg->p->ref != 1) { + /* other reference found */ + return 1; + } + /* no other references found */ + return 0; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + * @param netif the netif used to send the segment + */ +static err_t +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif) +{ + err_t err; + u16_t len; + u32_t *opts; +#if TCP_CHECKSUM_ON_COPY + int seg_chksum_was_swapped = 0; +#endif + + LWIP_ASSERT("tcp_output_segment: invalid seg", seg != NULL); + LWIP_ASSERT("tcp_output_segment: invalid pcb", pcb != NULL); + LWIP_ASSERT("tcp_output_segment: invalid netif", netif != NULL); + + if (tcp_output_segment_busy(seg)) { + /* This should not happen: rexmit functions should have checked this. + However, since this function modifies p->len, we must not continue in this case. */ + LWIP_DEBUGF(TCP_RTO_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_output_segment: segment busy\n")); + return ERR_OK; + } + + /* The TCP header has already been constructed, but the ackno and + wnd fields remain. */ + seg->tcphdr->ackno = lwip_htonl(pcb->rcv_nxt); + + /* advertise our receive window size in this TCP segment */ +#if LWIP_WND_SCALE + if (seg->flags & TF_SEG_OPTS_WND_SCALE) { + /* The Window field in a SYN segment itself (the only type where we send + the window scale option) is never scaled. */ + seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(pcb->rcv_ann_wnd)); + } else +#endif /* LWIP_WND_SCALE */ + { + seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); + } + + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + + /* Add any requested options. NB MSS option is only set on SYN + packets, so ignore it here */ + /* cast through void* to get rid of alignment warnings */ + opts = (u32_t *)(void *)(seg->tcphdr + 1); + if (seg->flags & TF_SEG_OPTS_MSS) { + u16_t mss; +#if TCP_CALCULATE_EFF_SEND_MSS + mss = tcp_eff_send_mss_netif(TCP_MSS, netif, &pcb->remote_ip); +#else /* TCP_CALCULATE_EFF_SEND_MSS */ + mss = TCP_MSS; +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + *opts = TCP_BUILD_MSS_OPTION(mss); + opts += 1; + } +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (seg->flags & TF_SEG_OPTS_TS) { + tcp_build_timestamp_option(pcb, opts); + opts += 3; + } +#endif +#if LWIP_WND_SCALE + if (seg->flags & TF_SEG_OPTS_WND_SCALE) { + tcp_build_wnd_scale_option(opts); + opts += 1; + } +#endif +#if LWIP_TCP_SACK_OUT + if (seg->flags & TF_SEG_OPTS_SACK_PERM) { + /* Pad with two NOP options to make everything nicely aligned + * NOTE: When we send both timestamp and SACK_PERM options, + * we could use the first two NOPs before the timestamp to store SACK_PERM option, + * but that would complicate the code. + */ + *(opts++) = PP_HTONL(0x01010402); + } +#endif + + /* Set retransmission timer running if it is not currently enabled + This must be set before checking the route. */ + if (pcb->rtime < 0) { + pcb->rtime = 0; + } + + if (pcb->rttest == 0) { + pcb->rttest = tcp_ticks; + pcb->rtseq = lwip_ntohl(seg->tcphdr->seqno); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", + lwip_htonl(seg->tcphdr->seqno), lwip_htonl(seg->tcphdr->seqno) + + seg->len)); + + len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + if (len == 0) { + /** Exclude retransmitted segments from this count. */ + MIB2_STATS_INC(mib2.tcpoutsegs); + } + + seg->p->len -= len; + seg->p->tot_len -= len; + + seg->p->payload = seg->tcphdr; + + seg->tcphdr->chksum = 0; + +#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS + opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(seg->p, seg->tcphdr, pcb, opts); +#endif + LWIP_ASSERT("options not filled", (u8_t *)opts == ((u8_t *)(seg->tcphdr + 1)) + LWIP_TCP_OPT_LENGTH_SEGMENT(seg->flags, pcb)); + +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { +#if TCP_CHECKSUM_ON_COPY + u32_t acc; +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { + LWIP_ASSERT("data included but not checksummed", + seg->p->tot_len == TCPH_HDRLEN_BYTES(seg->tcphdr)); + } + + /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ + acc = ip_chksum_pseudo_partial(seg->p, IP_PROTO_TCP, + seg->p->tot_len, TCPH_HDRLEN_BYTES(seg->tcphdr), &pcb->local_ip, &pcb->remote_ip); + /* add payload checksum */ + if (seg->chksum_swapped) { + seg_chksum_was_swapped = 1; + seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); + seg->chksum_swapped = 0; + } + acc = (u16_t)~acc + seg->chksum; + seg->tcphdr->chksum = (u16_t)~FOLD_U32T(acc); +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + if (chksum_slow != seg->tcphdr->chksum) { + TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL( + ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", + seg->tcphdr->chksum, chksum_slow)); + seg->tcphdr->chksum = chksum_slow; + } +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ +#else /* TCP_CHECKSUM_ON_COPY */ + seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CHECKSUM_ON_COPY */ + } +#endif /* CHECKSUM_GEN_TCP */ + TCP_STATS_INC(tcp.xmit); + + NETIF_SET_HINTS(netif, &(pcb->netif_hints)); + err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + pcb->tos, IP_PROTO_TCP, netif); + NETIF_RESET_HINTS(netif); + +#if TCP_CHECKSUM_ON_COPY + if (seg_chksum_was_swapped) { + /* if data is added to this segment later, chksum needs to be swapped, + so restore this now */ + seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); + seg->chksum_swapped = 1; + } +#endif + + return err; +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +err_t +tcp_rexmit_rto_prepare(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + LWIP_ASSERT("tcp_rexmit_rto_prepare: invalid pcb", pcb != NULL); + + if (pcb->unacked == NULL) { + return ERR_VAL; + } + + /* Move all unacked segments to the head of the unsent queue. + However, give up if any of the unsent pbufs are still referenced by the + netif driver due to deferred transmission. No point loading the link further + if it is struggling to flush its buffered writes. */ + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next) { + if (tcp_output_segment_busy(seg)) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_rto: segment busy\n")); + return ERR_VAL; + } + } + if (tcp_output_segment_busy(seg)) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_rto: segment busy\n")); + return ERR_VAL; + } + /* concatenate unsent queue after unacked queue */ + seg->next = pcb->unsent; +#if TCP_OVERSIZE_DBGCHECK + /* if last unsent changed, we need to update unsent_oversize */ + if (pcb->unsent == NULL) { + pcb->unsent_oversize = seg->oversize_left; + } +#endif /* TCP_OVERSIZE_DBGCHECK */ + /* unsent queue is the concatenated queue (of unacked, unsent) */ + pcb->unsent = pcb->unacked; + /* unacked queue is now empty */ + pcb->unacked = NULL; + + /* Mark RTO in-progress */ + tcp_set_flags(pcb, TF_RTO); + /* Record the next byte following retransmit */ + pcb->rto_end = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + /* Don't take any RTT measurements after retransmitting. */ + pcb->rttest = 0; + + return ERR_OK; +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto_commit(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_rexmit_rto_commit: invalid pcb", pcb != NULL); + + /* increment number of retransmissions */ + if (pcb->nrtx < 0xFF) { + ++pcb->nrtx; + } + /* Do the actual retransmission */ + tcp_output(pcb); +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_process() only, tcp_slowtmr() needs to do some things between + * "prepare" and "commit". + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_rexmit_rto: invalid pcb", pcb != NULL); + + if (tcp_rexmit_rto_prepare(pcb) == ERR_OK) { + tcp_rexmit_rto_commit(pcb); + } +} + +/** + * Requeue the first unacked segment for retransmission + * + * Called by tcp_receive() for fast retransmit. + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +err_t +tcp_rexmit(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + struct tcp_seg **cur_seg; + + LWIP_ASSERT("tcp_rexmit: invalid pcb", pcb != NULL); + + if (pcb->unacked == NULL) { + return ERR_VAL; + } + + seg = pcb->unacked; + + /* Give up if the segment is still referenced by the netif driver + due to deferred transmission. */ + if (tcp_output_segment_busy(seg)) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n")); + return ERR_VAL; + } + + /* Move the first unacked segment to the unsent queue */ + /* Keep the unsent queue sorted. */ + pcb->unacked = seg->next; + + cur_seg = &(pcb->unsent); + while (*cur_seg && + TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = *cur_seg; + *cur_seg = seg; +#if TCP_OVERSIZE + if (seg->next == NULL) { + /* the retransmitted segment is last in unsent, so reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + if (pcb->nrtx < 0xFF) { + ++pcb->nrtx; + } + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + MIB2_STATS_INC(mib2.tcpretranssegs); + /* No need to call tcp_output: we are always called from tcp_input() + and thus tcp_output directly returns. */ + return ERR_OK; +} + + +/** + * Handle retransmission after three dupacks received + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit_fast(struct tcp_pcb *pcb) +{ + LWIP_ASSERT("tcp_rexmit_fast: invalid pcb", pcb != NULL); + + if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: dupacks %"U16_F" (%"U32_F + "), fast retransmit %"U32_F"\n", + (u16_t)pcb->dupacks, pcb->lastack, + lwip_ntohl(pcb->unacked->tcphdr->seqno))); + if (tcp_rexmit(pcb) == ERR_OK) { + /* Set ssthresh to half of the minimum of the current + * cwnd and the advertised window */ + pcb->ssthresh = LWIP_MIN(pcb->cwnd, pcb->snd_wnd) / 2; + + /* The minimum value for ssthresh should be 2 MSS */ + if (pcb->ssthresh < (2U * pcb->mss)) { + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: The minimum value for ssthresh %"TCPWNDSIZE_F + " should be min 2 mss %"U16_F"...\n", + pcb->ssthresh, (u16_t)(2 * pcb->mss))); + pcb->ssthresh = 2 * pcb->mss; + } + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + tcp_set_flags(pcb, TF_INFR); + + /* Reset the retransmission timer to prevent immediate rto retransmissions */ + pcb->rtime = 0; + } + } +} + +static struct pbuf * +tcp_output_alloc_header_common(u32_t ackno, u16_t optlen, u16_t datalen, + u32_t seqno_be /* already in network byte order */, + u16_t src_port, u16_t dst_port, u8_t flags, u16_t wnd) +{ + struct tcp_hdr *tcphdr; + struct pbuf *p; + + p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= TCP_HLEN + optlen)); + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = lwip_htons(src_port); + tcphdr->dest = lwip_htons(dst_port); + tcphdr->seqno = seqno_be; + tcphdr->ackno = lwip_htonl(ackno); + TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), flags); + tcphdr->wnd = lwip_htons(wnd); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + } + return p; +} + +/** Allocate a pbuf and create a tcphdr at p->payload, used for output + * functions other than the default tcp_output -> tcp_output_segment + * (e.g. tcp_send_empty_ack, etc.) + * + * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) + * @param optlen length of header-options + * @param datalen length of tcp data to reserve in pbuf + * @param seqno_be seqno in network byte order (big-endian) + * @return pbuf with p->payload being the tcp_hdr + */ +static struct pbuf * +tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, + u32_t seqno_be /* already in network byte order */) +{ + struct pbuf *p; + + LWIP_ASSERT("tcp_output_alloc_header: invalid pcb", pcb != NULL); + + p = tcp_output_alloc_header_common(pcb->rcv_nxt, optlen, datalen, + seqno_be, pcb->local_port, pcb->remote_port, TCP_ACK, + TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); + if (p != NULL) { + /* If we're sending a packet, update the announced right window edge */ + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + } + return p; +} + +/* Fill in options for control segments */ +static void +tcp_output_fill_options(const struct tcp_pcb *pcb, struct pbuf *p, u8_t optflags, u8_t num_sacks) +{ + struct tcp_hdr *tcphdr; + u32_t *opts; + u16_t sacks_len = 0; + + LWIP_ASSERT("tcp_output_fill_options: invalid pbuf", p != NULL); + + tcphdr = (struct tcp_hdr *)p->payload; + opts = (u32_t *)(void *)(tcphdr + 1); + + /* NB. MSS and window scale options are only sent on SYNs, so ignore them here */ + +#if LWIP_TCP_TIMESTAMPS + if (optflags & TF_SEG_OPTS_TS) { + tcp_build_timestamp_option(pcb, opts); + opts += 3; + } +#endif + +#if LWIP_TCP_SACK_OUT + if (pcb && (num_sacks > 0)) { + tcp_build_sack_option(pcb, opts, num_sacks); + /* 1 word for SACKs header (including 2xNOP), and 2 words for each SACK */ + sacks_len = 1 + num_sacks * 2; + opts += sacks_len; + } +#else + LWIP_UNUSED_ARG(num_sacks); +#endif + +#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS + opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(p, tcphdr, pcb, opts); +#endif + + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(sacks_len); + LWIP_ASSERT("options not filled", (u8_t *)opts == ((u8_t *)(tcphdr + 1)) + sacks_len * 4 + LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb)); + LWIP_UNUSED_ARG(optflags); /* for LWIP_NOASSERT */ + LWIP_UNUSED_ARG(opts); /* for LWIP_NOASSERT */ +} + +/** Output a control segment pbuf to IP. + * + * Called from tcp_rst, tcp_send_empty_ack, tcp_keepalive and tcp_zero_window_probe, + * this function combines selecting a netif for transmission, generating the tcp + * header checksum and calling ip_output_if while handling netif hints and stats. + */ +static err_t +tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, + const ip_addr_t *src, const ip_addr_t *dst) +{ + err_t err; + struct netif *netif; + + LWIP_ASSERT("tcp_output_control_segment: invalid pbuf", p != NULL); + + netif = tcp_route(pcb, src, dst); + if (netif == NULL) { + err = ERR_RTE; + } else { + u8_t ttl, tos; +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + src, dst); + } +#endif + if (pcb != NULL) { + NETIF_SET_HINTS(netif, LWIP_CONST_CAST(struct netif_hint*, &(pcb->netif_hints))); + ttl = pcb->ttl; + tos = pcb->tos; + } else { + /* Send output with hardcoded TTL/HL since we have no access to the pcb */ + ttl = TCP_TTL; + tos = 0; + } + TCP_STATS_INC(tcp.xmit); + err = ip_output_if(p, src, dst, ttl, tos, IP_PROTO_TCP, netif); + NETIF_RESET_HINTS(netif); + } + pbuf_free(p); + return err; +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) either to + * abort a connection or to show that there is no matching local connection + * for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param pcb TCP pcb (may be NULL if no pcb is available) + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + u16_t wnd; + u8_t optlen; + + LWIP_ASSERT("tcp_rst: invalid local_ip", local_ip != NULL); + LWIP_ASSERT("tcp_rst: invalid remote_ip", remote_ip != NULL); + + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); + +#if LWIP_WND_SCALE + wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); +#else + wnd = PP_HTONS(TCP_WND); +#endif + + p = tcp_output_alloc_header_common(ackno, optlen, 0, lwip_htonl(seqno), local_port, + remote_port, TCP_RST | TCP_ACK, wnd); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + tcp_output_fill_options(pcb, p, 0, 0); + + MIB2_STATS_INC(mib2.tcpoutrsts); + + tcp_output_control_segment(pcb, p, local_ip, remote_ip); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/** + * Send an ACK without data. + * + * @param pcb Protocol control block for the TCP connection to send the ACK + */ +err_t +tcp_send_empty_ack(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + u8_t optlen, optflags = 0; + u8_t num_sacks = 0; + + LWIP_ASSERT("tcp_send_empty_ack: invalid pcb", pcb != NULL); + +#if LWIP_TCP_TIMESTAMPS + if (pcb->flags & TF_TIMESTAMP) { + optflags = TF_SEG_OPTS_TS; + } +#endif + optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); + +#if LWIP_TCP_SACK_OUT + /* For now, SACKs are only sent with empty ACKs */ + if ((num_sacks = tcp_get_num_sacks(pcb, optlen)) > 0) { + optlen += 4 + num_sacks * 8; /* 4 bytes for header (including 2*NOP), plus 8B for each SACK */ + } +#endif + + p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt)); + if (p == NULL) { + /* let tcp_fasttmr retry sending this ACK */ + tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); + return ERR_BUF; + } + tcp_output_fill_options(pcb, p, optflags, num_sacks); + +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; +#endif + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, + ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); + err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); + if (err != ERR_OK) { + /* let tcp_fasttmr retry sending this ACK */ + tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); + } else { + /* remove ACK flags from the PCB, as we sent an empty ACK now */ + tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); + } + + return err; +} + +/** + * Send keepalive packets to keep a connection active although + * no data is sent over it. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a keepalive packet + */ +err_t +tcp_keepalive(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); + + LWIP_ASSERT("tcp_keepalive: invalid pcb", pcb != NULL); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); + ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent)); + + p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt - 1)); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_keepalive: could not allocate memory for pbuf\n")); + return ERR_MEM; + } + tcp_output_fill_options(pcb, p, 0, 0); + err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F" err %d.\n", + pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); + return err; +} + +/** + * Send persist timer zero-window probes to keep a connection active + * when a window update is lost. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a zero-window probe packet + */ +err_t +tcp_zero_window_probe(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + struct tcp_hdr *tcphdr; + struct tcp_seg *seg; + u16_t len; + u8_t is_fin; + u32_t snd_nxt; + u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); + + LWIP_ASSERT("tcp_zero_window_probe: invalid pcb", pcb != NULL); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); + ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_zero_window_probe: tcp_ticks %"U32_F + " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent)); + + /* Only consider unsent, persist timer should be off when there is data in-flight */ + seg = pcb->unsent; + if (seg == NULL) { + /* Not expected, persist timer should be off when the send buffer is empty */ + return ERR_OK; + } + + /* increment probe count. NOTE: we record probe even if it fails + to actually transmit due to an error. This ensures memory exhaustion/ + routing problem doesn't leave a zero-window pcb as an indefinite zombie. + RTO mechanism has similar behavior, see pcb->nrtx */ + if (pcb->persist_probe < 0xFF) { + ++pcb->persist_probe; + } + + is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); + /* we want to send one seqno: either FIN or data (no options) */ + len = is_fin ? 0 : 1; + + p = tcp_output_alloc_header(pcb, optlen, len, seg->tcphdr->seqno); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); + return ERR_MEM; + } + tcphdr = (struct tcp_hdr *)p->payload; + + if (is_fin) { + /* FIN segment, no data */ + TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); + } else { + /* Data segment, copy in one byte from the head of the unacked queue */ + char *d = ((char *)p->payload + TCP_HLEN); + /* Depending on whether the segment has already been sent (unacked) or not + (unsent), seg->p->payload points to the IP header or TCP header. + Ensure we copy the first TCP data byte: */ + pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); + } + + /* The byte may be acknowledged without the window being opened. */ + snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + 1; + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; + } + tcp_output_fill_options(pcb, p, 0, 0); + + err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F + " ackno %"U32_F" err %d.\n", + pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); + return err; +} +#endif /* LWIP_TCP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/timeouts.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/timeouts.c new file mode 100644 index 0000000..f37acfe --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/timeouts.c @@ -0,0 +1,451 @@ +/** + * @file + * Stack-internal timers implementation. + * This file includes timer callbacks for stack-internal timers as well as + * functions to set up or stop timers and check for expired timers. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#include "lwip/timeouts.h" +#include "lwip/priv/tcp_priv.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/priv/tcpip_priv.h" + +#include "lwip/ip4_frag.h" +#include "lwip/etharp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" +#include "lwip/dhcp6.h" +#include "lwip/sys.h" +#include "lwip/pbuf.h" + +#if LWIP_DEBUG_TIMERNAMES +#define HANDLER(x) x, #x +#else /* LWIP_DEBUG_TIMERNAMES */ +#define HANDLER(x) x +#endif /* LWIP_DEBUG_TIMERNAMES */ + +#define LWIP_MAX_TIMEOUT 0x7fffffff + +/* Check if timer's expiry time is greater than time and care about u32_t wraparounds */ +#define TIME_LESS_THAN(t, compare_to) ( (((u32_t)((t)-(compare_to))) > LWIP_MAX_TIMEOUT) ? 1 : 0 ) + +/** This array contains all stack-internal cyclic timers. To get the number of + * timers, use LWIP_ARRAYSIZE() */ +const struct lwip_cyclic_timer lwip_cyclic_timers[] = { +#if LWIP_TCP + /* The TCP timer is a special case: it does not have to run always and + is triggered to start from TCP using tcp_timer_needed() */ + {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, +#endif /* LWIP_TCP */ +#if LWIP_IPV4 +#if IP_REASSEMBLY + {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, +#endif /* IP_REASSEMBLY */ +#if LWIP_ARP + {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, +#endif /* LWIP_ARP */ +#if LWIP_DHCP + {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, + {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP + {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4 */ +#if LWIP_DNS + {DNS_TMR_INTERVAL, HANDLER(dns_tmr)}, +#endif /* LWIP_DNS */ +#if LWIP_IPV6 + {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)}, +#if LWIP_IPV6_REASS + {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)}, +#endif /* LWIP_IPV6_REASS */ +#if LWIP_IPV6_MLD + {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)}, +#endif /* LWIP_IPV6_MLD */ +#if LWIP_IPV6_DHCP6 + {DHCP6_TIMER_MSECS, HANDLER(dhcp6_tmr)}, +#endif /* LWIP_IPV6_DHCP6 */ +#endif /* LWIP_IPV6 */ +}; +const int lwip_num_cyclic_timers = LWIP_ARRAYSIZE(lwip_cyclic_timers); + +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM + +/** The one and only timeout list */ +static struct sys_timeo *next_timeout; + +static u32_t current_timeout_due_time; + +#if LWIP_TESTMODE +struct sys_timeo** +sys_timeouts_get_next_timeout(void) +{ + return &next_timeout; +} +#endif + +#if LWIP_TCP +/** global variable that shows if the tcp timer is currently scheduled or not */ +static int tcpip_tcp_timer_active; + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +tcpip_tcp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + /* call TCP timer handler */ + tcp_tmr(); + /* timer still needed? */ + if (tcp_active_pcbs || tcp_tw_pcbs) { + /* restart timer */ + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } else { + /* disable timer */ + tcpip_tcp_timer_active = 0; + } +} + +/** + * Called from TCP_REG when registering a new PCB: + * the reason is to have the TCP timer only running when + * there are active (or time-wait) PCBs. + */ +void +tcp_timer_needed(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + /* timer is off but needed again? */ + if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { + /* enable and start timer */ + tcpip_tcp_timer_active = 1; + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } +} +#endif /* LWIP_TCP */ + +static void +#if LWIP_DEBUG_TIMERNAMES +sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg, const char *handler_name) +#else /* LWIP_DEBUG_TIMERNAMES */ +sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg) +#endif +{ + struct sys_timeo *timeout, *t; + + timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); + return; + } + + timeout->next = NULL; + timeout->h = handler; + timeout->arg = arg; + timeout->time = abs_time; + +#if LWIP_DEBUG_TIMERNAMES + timeout->handler_name = handler_name; + LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p abs_time=%"U32_F" handler=%s arg=%p\n", + (void *)timeout, abs_time, handler_name, (void *)arg)); +#endif /* LWIP_DEBUG_TIMERNAMES */ + + if (next_timeout == NULL) { + next_timeout = timeout; + return; + } + if (TIME_LESS_THAN(timeout->time, next_timeout->time)) { + timeout->next = next_timeout; + next_timeout = timeout; + } else { + for (t = next_timeout; t != NULL; t = t->next) { + if ((t->next == NULL) || TIME_LESS_THAN(timeout->time, t->next->time)) { + timeout->next = t->next; + t->next = timeout; + break; + } + } + } +} + +/** + * Timer callback function that calls cyclic->handler() and reschedules itself. + * + * @param arg unused argument + */ +#if !LWIP_TESTMODE +static +#endif +void +lwip_cyclic_timer(void *arg) +{ + u32_t now; + u32_t next_timeout_time; + const struct lwip_cyclic_timer *cyclic = (const struct lwip_cyclic_timer *)arg; + +#if LWIP_DEBUG_TIMERNAMES + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name)); +#endif + cyclic->handler(); + + now = sys_now(); + next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ + if (TIME_LESS_THAN(next_timeout_time, now)) { + /* timer would immediately expire again -> "overload" -> restart without any correction */ +#if LWIP_DEBUG_TIMERNAMES + sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg, cyclic->handler_name); +#else + sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg); +#endif + + } else { + /* correct cyclic interval with handler execution delay and sys_check_timeouts jitter */ +#if LWIP_DEBUG_TIMERNAMES + sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg, cyclic->handler_name); +#else + sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg); +#endif + } +} + +/** Initialize this module */ +void sys_timeouts_init(void) +{ + size_t i; + /* tcp_tmr() at index 0 is started on demand */ + for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) { + /* we have to cast via size_t to get rid of const warning + (this is OK as cyclic_timer() casts back to const* */ + sys_timeout(lwip_cyclic_timers[i].interval_ms, lwip_cyclic_timer, LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i])); + } +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_timeouts_mbox_fetch() + * - by calling sys_check_timeouts() (NO_SYS==1 only) + * + * @param msecs time in milliseconds after that the timer should expire + * @param handler callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +#if LWIP_DEBUG_TIMERNAMES +void +sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char *handler_name) +#else /* LWIP_DEBUG_TIMERNAMES */ +void +sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +#endif /* LWIP_DEBUG_TIMERNAMES */ +{ + u32_t next_timeout_time; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("Timeout time too long, max is LWIP_UINT32_MAX/4 msecs", msecs <= (LWIP_UINT32_MAX / 4)); + + next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ + +#if LWIP_DEBUG_TIMERNAMES + sys_timeout_abs(next_timeout_time, handler, arg, handler_name); +#else + sys_timeout_abs(next_timeout_time, handler, arg); +#endif +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry (subsequent entries remain untouched), even though the timeout has not + * triggered yet. + * + * @param handler callback function that would be called by the timeout + * @param arg callback argument that would be passed to handler +*/ +void +sys_untimeout(sys_timeout_handler handler, void *arg) +{ + struct sys_timeo *prev_t, *t; + + LWIP_ASSERT_CORE_LOCKED(); + + if (next_timeout == NULL) { + return; + } + + for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { + if ((t->h == handler) && (t->arg == arg)) { + /* We have a match */ + /* Unlink from previous in list */ + if (prev_t == NULL) { + next_timeout = t->next; + } else { + prev_t->next = t->next; + } + memp_free(MEMP_SYS_TIMEOUT, t); + return; + } + } + return; +} + +/** + * @ingroup lwip_nosys + * Handle timeouts for NO_SYS==1 (i.e. without using + * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout + * handler functions when timeouts expire. + * + * Must be called periodically from your main loop. + */ +void +sys_check_timeouts(void) +{ + u32_t now; + + LWIP_ASSERT_CORE_LOCKED(); + + /* Process only timers expired at the start of the function. */ + now = sys_now(); + + do { + struct sys_timeo *tmptimeout; + sys_timeout_handler handler; + void *arg; + + PBUF_CHECK_FREE_OOSEQ(); + + tmptimeout = next_timeout; + if (tmptimeout == NULL) { + return; + } + + if (TIME_LESS_THAN(now, tmptimeout->time)) { + return; + } + + /* Timeout has expired */ + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; + current_timeout_due_time = tmptimeout->time; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s t=%"U32_F" arg=%p\n", + tmptimeout->handler_name, sys_now() - tmptimeout->time, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { + handler(arg); + } + LWIP_TCPIP_THREAD_ALIVE(); + + /* Repeat until all expired timers have been called */ + } while (1); +} + +/** Rebase the timeout times to the current time. + * This is necessary if sys_check_timeouts() hasn't been called for a long + * time (e.g. while saving energy) to prevent all timer functions of that + * period being called. + */ +void +sys_restart_timeouts(void) +{ + u32_t now; + u32_t base; + struct sys_timeo *t; + + if (next_timeout == NULL) { + return; + } + + now = sys_now(); + base = next_timeout->time; + + for (t = next_timeout; t != NULL; t = t->next) { + t->time = (t->time - base) + now; + } +} + +/** Return the time left before the next timeout is due. If no timeouts are + * enqueued, returns 0xffffffff + */ +u32_t +sys_timeouts_sleeptime(void) +{ + u32_t now; + + LWIP_ASSERT_CORE_LOCKED(); + + if (next_timeout == NULL) { + return SYS_TIMEOUTS_SLEEPTIME_INFINITE; + } + now = sys_now(); + if (TIME_LESS_THAN(next_timeout->time, now)) { + return 0; + } else { + u32_t ret = (u32_t)(next_timeout->time - now); + LWIP_ASSERT("invalid sleeptime", ret <= LWIP_MAX_TIMEOUT); + return ret; + } +} + +#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ +/* Satisfy the TCP code which calls this function */ +void +tcp_timer_needed(void) +{ +} +#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/udp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/udp.c new file mode 100644 index 0000000..0b609d3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/core/udp.c @@ -0,0 +1,1320 @@ +/** + * @file + * User Datagram Protocol module\n + * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n + * See also @ref udp_raw + * + * @defgroup udp_raw UDP + * @ingroup callbackstyle_api + * User Datagram Protocol module\n + * @see @ref api + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! + */ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/icmp6.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" + +#include + +#ifndef UDP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define UDP_LOCAL_PORT_RANGE_START 0xc000 +#define UDP_LOCAL_PORT_RANGE_END 0xffff +#define UDP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)) +#endif + +/* last local UDP port */ +static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * Initialize this module. + */ +void +udp_init(void) +{ +#ifdef LWIP_RAND + udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RAND */ +} + +/** + * Allocate a new local UDP port. + * + * @return a new (free) local UDP port number + */ +static u16_t +udp_new_port(void) +{ + u16_t n = 0; + struct udp_pcb *pcb; + +again: + if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { + udp_port = UDP_LOCAL_PORT_RANGE_START; + } + /* Check all PCBs. */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == udp_port) { + if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + return udp_port; +} + +/** Common code to see if the current input packet matches the pcb + * (current input packet is accessed via ip(4/6)_current_* macros) + * + * @param pcb pcb to check + * @param inp network interface on which the datagram was received (only used for IPv4) + * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4) + * @return 1 on match, 0 otherwise + */ +static u8_t +udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) +{ + LWIP_UNUSED_ARG(inp); /* in IPv6 only case */ + LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ + + LWIP_ASSERT("udp_input_local_match: invalid pcb", pcb != NULL); + LWIP_ASSERT("udp_input_local_match: invalid netif", inp != NULL); + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + return 0; + } + + /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { +#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV + if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { + return 0; + } +#endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */ + return 1; + } + + /* Only need to check PCB if incoming IP version matches PCB IP version */ + if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { +#if LWIP_IPV4 + /* Special case: IPv4 broadcast: all or broadcasts in my subnet + * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ + if (broadcast != 0) { +#if IP_SOF_BROADCAST_RECV + if (ip_get_option(pcb, SOF_BROADCAST)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || + ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || + ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { + return 1; + } + } + } else +#endif /* LWIP_IPV4 */ + /* Handle IPv4 and IPv6: all or exact match */ + if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + return 1; + } + } + + return 0; +} + +/** + * Process an incoming UDP datagram. + * + * Given an incoming UDP datagram (as a chain of pbufs) this function + * finds a corresponding UDP PCB and hands over the pbuf to the pcbs + * recv function. If no pcb is found or the datagram is incorrect, the + * pbuf is freed. + * + * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) + * @param inp network interface on which the datagram was received. + * + */ +void +udp_input(struct pbuf *p, struct netif *inp) +{ + struct udp_hdr *udphdr; + struct udp_pcb *pcb, *prev; + struct udp_pcb *uncon_pcb; + u16_t src, dest; + u8_t broadcast; + u8_t for_us = 0; + + LWIP_UNUSED_ARG(inp); + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("udp_input: invalid pbuf", p != NULL); + LWIP_ASSERT("udp_input: invalid netif", inp != NULL); + + PERF_START; + + UDP_STATS_INC(udp.recv); + + /* Check minimum length (UDP header) */ + if (p->len < UDP_HLEN) { + /* drop short packets */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); + UDP_STATS_INC(udp.lenerr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + goto end; + } + + udphdr = (struct udp_hdr *)p->payload; + + /* is broadcast packet ? */ + broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); + + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); + + /* convert src and dest ports to host byte order */ + src = lwip_ntohs(udphdr->src); + dest = lwip_ntohs(udphdr->dest); + + udp_debug_print(udphdr); + + /* print the UDP source and destination */ + LWIP_DEBUGF(UDP_DEBUG, ("udp (")); + ip_addr_debug_print_val(UDP_DEBUG, *ip_current_dest_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); + ip_addr_debug_print_val(UDP_DEBUG, *ip_current_src_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); + + pcb = NULL; + prev = NULL; + uncon_pcb = NULL; + /* Iterate through the UDP pcb list for a matching pcb. + * 'Perfect match' pcbs (connected to the remote port & ip address) are + * preferred. If no perfect match is found, the first unconnected pcb that + * matches the local port and ip address gets the datagram. */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + /* print the PCB local and remote address */ + LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); + ip_addr_debug_print_val(UDP_DEBUG, pcb->local_ip); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); + ip_addr_debug_print_val(UDP_DEBUG, pcb->remote_ip); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); + + /* compare PCB local addr+port to UDP destination addr+port */ + if ((pcb->local_port == dest) && + (udp_input_local_match(pcb, inp, broadcast) != 0)) { + if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) { + if (uncon_pcb == NULL) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; +#if LWIP_IPV4 + } else if (broadcast && ip4_current_dest_addr()->addr == IPADDR_BROADCAST) { + /* global broadcast address (only valid for IPv4; match was checked before) */ + if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_cmp(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) { + /* uncon_pcb does not match the input netif, check this pcb */ + if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) { + /* better match */ + uncon_pcb = pcb; + } + } +#endif /* LWIP_IPV4 */ + } +#if SO_REUSE + else if (!ip_addr_isany(&pcb->local_ip)) { + /* prefer specific IPs over catch-all */ + uncon_pcb = pcb; + } +#endif /* SO_REUSE */ + } + + /* compare PCB remote addr+port to UDP source addr+port */ + if ((pcb->remote_port == src) && + (ip_addr_isany_val(pcb->remote_ip) || + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + /* the first fully matching PCB */ + if (prev != NULL) { + /* move the pcb to the front of udp_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } else { + UDP_STATS_INC(udp.cachehit); + } + break; + } + } + + prev = pcb; + } + /* no fully matching pcb found? then look for an unconnected pcb */ + if (pcb == NULL) { + pcb = uncon_pcb; + } + + /* Check checksum if this is a match or if it was directed at us. */ + if (pcb != NULL) { + for_us = 1; + } else { +#if LWIP_IPV6 + if (ip_current_is_v6()) { + for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + if (!ip_current_is_v6()) { + for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); + } +#endif /* LWIP_IPV4 */ + } + + if (for_us) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); +#if CHECKSUM_CHECK_UDP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_UDP) { +#if LWIP_UDPLITE + if (ip_current_header_proto() == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ + u16_t chklen = lwip_ntohs(udphdr->len); + if (chklen < sizeof(struct udp_hdr)) { + if (chklen == 0) { + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet (See RFC 3828 chap. 3.1) */ + chklen = p->tot_len; + } else { + /* At least the UDP-Lite header must be covered by the + checksum! (Again, see RFC 3828 chap. 3.1) */ + goto chkerr; + } + } + if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, + p->tot_len, chklen, + ip_current_src_addr(), ip_current_dest_addr()) != 0) { + goto chkerr; + } + } else +#endif /* LWIP_UDPLITE */ + { + if (udphdr->chksum != 0) { + if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, + ip_current_src_addr(), + ip_current_dest_addr()) != 0) { + goto chkerr; + } + } + } + } +#endif /* CHECKSUM_CHECK_UDP */ + if (pbuf_remove_header(p, UDP_HLEN)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + goto end; + } + + if (pcb != NULL) { + MIB2_STATS_INC(mib2.udpindatagrams); +#if SO_REUSE && SO_REUSE_RXTOALL + if (ip_get_option(pcb, SOF_REUSEADDR) && + (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { + /* pass broadcast- or multicast packets to all multicast pcbs + if SOF_REUSEADDR is set on the first match */ + struct udp_pcb *mpcb; + for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { + if (mpcb != pcb) { + /* compare PCB local addr+port to UDP destination addr+port */ + if ((mpcb->local_port == dest) && + (udp_input_local_match(mpcb, inp, broadcast) != 0)) { + /* pass a copy of the packet to all local matches */ + if (mpcb->recv != NULL) { + struct pbuf *q; + q = pbuf_clone(PBUF_RAW, PBUF_POOL, p); + if (q != NULL) { + mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + } + } + } + } + } + } +#endif /* SO_REUSE && SO_REUSE_RXTOALL */ + /* callback */ + if (pcb->recv != NULL) { + /* now the recv function is responsible for freeing p */ + pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); + } else { + /* no recv function registered? then we have to free the pbuf! */ + pbuf_free(p); + goto end; + } + } else { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); + +#if LWIP_ICMP || LWIP_ICMP6 + /* No match was found, send ICMP destination port unreachable unless + destination address was broadcast/multicast. */ + if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { + /* move payload pointer back to ip header */ + pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN)); + icmp_port_unreach(ip_current_is_v6(), p); + } +#endif /* LWIP_ICMP || LWIP_ICMP6 */ + UDP_STATS_INC(udp.proterr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpnoports); + pbuf_free(p); + } + } else { + pbuf_free(p); + } +end: + PERF_STOP("udp_input"); + return; +#if CHECKSUM_CHECK_UDP +chkerr: + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + PERF_STOP("udp_input"); +#endif /* CHECKSUM_CHECK_UDP */ +} + +/** + * @ingroup udp_raw + * Sends the pbuf p using UDP. The pbuf is not deallocated. + * + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * + * The datagram will be sent to the current remote_ip & remote_port + * stored in pcb. If the pcb is not bound to a port, it will + * automatically be bound to a random port. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * - ERR_VAL. No PCB or PCB is dual-stack + * - More errors could be returned by lower protocol layers. + * + * @see udp_disconnect() udp_sendto() + */ +err_t +udp_send(struct udp_pcb *pcb, struct pbuf *p) +{ + LWIP_ERROR("udp_send: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_send: invalid pbuf", p != NULL, return ERR_ARG); + + if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { + return ERR_VAL; + } + + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); +} + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +/** @ingroup udp_raw + * Same as udp_send() but with checksum + */ +err_t +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + LWIP_ERROR("udp_send_chksum: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_send_chksum: invalid pbuf", p != NULL, return ERR_ARG); + + if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { + return ERR_VAL; + } + + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +/** + * @ingroup udp_raw + * Send data to a specified address using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * If the PCB already has a remote address association, it will + * be restored after the data is sent. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** @ingroup udp_raw + * Same as udp_sendto(), but with checksum */ +err_t +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct netif *netif; + + LWIP_ERROR("udp_sendto: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto: invalid pbuf", p != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto: invalid dst_ip", dst_ip != NULL, return ERR_ARG); + + if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); + + if (pcb->netif_idx != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->netif_idx); + } else { +#if LWIP_MULTICAST_TX_OPTIONS + netif = NULL; + if (ip_addr_ismulticast(dst_ip)) { + /* For IPv6, the interface to use for packets with a multicast destination + * is specified using an interface index. The same approach may be used for + * IPv4 as well, in which case it overrides the IPv4 multicast override + * address below. Here we have to look up the netif by going through the + * list, but by doing so we skip a route lookup. If the interface index has + * gone stale, we fall through and do the regular route lookup after all. */ + if (pcb->mcast_ifindex != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->mcast_ifindex); + } +#if LWIP_IPV4 + else +#if LWIP_IPV6 + if (IP_IS_V4(dst_ip)) +#endif /* LWIP_IPV6 */ + { + /* IPv4 does not use source-based routing by default, so we use an + administratively selected interface for multicast by default. + However, this can be overridden by setting an interface address + in pcb->mcast_ip4 that is used for routing. If this routing lookup + fails, we try regular routing as though no override was set. */ + if (!ip4_addr_isany_val(pcb->mcast_ip4) && + !ip4_addr_cmp(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { + netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4); + } + } +#endif /* LWIP_IPV4 */ + } + + if (netif == NULL) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + { + /* find the outgoing network interface for this packet */ + netif = ip_route(&pcb->local_ip, dst_ip); + } + } + + /* no outgoing network interface could be found? */ + if (netif == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip); + LWIP_DEBUGF(UDP_DEBUG, ("\n")); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +} + +/** + * @ingroup udp_raw + * Send data to a specified address using UDP. + * The netif used for sending can be specified. + * + * This function exists mainly for DHCP, to be able to send UDP packets + * on a netif that is still down. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * @param netif the netif used for sending. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + const ip_addr_t *src_ip; + + LWIP_ERROR("udp_sendto_if: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if: invalid pbuf", p != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if: invalid dst_ip", dst_ip != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if: invalid netif", netif != NULL, return ERR_ARG); + + if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + + /* PCB local address is IP_ANY_ADDR or multicast? */ +#if LWIP_IPV6 + if (IP_IS_V6(dst_ip)) { + if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip)) || + ip6_addr_ismulticast(ip_2_ip6(&pcb->local_ip))) { + src_ip = ip6_select_source_address(netif, ip_2_ip6(dst_ip)); + if (src_ip == NULL) { + /* No suitable source address was found. */ + return ERR_RTE; + } + } else { + /* use UDP PCB local IPv6 address as source address, if still valid. */ + if (netif_get_ip6_addr_match(netif, ip_2_ip6(&pcb->local_ip)) < 0) { + /* Address isn't valid anymore. */ + return ERR_RTE; + } + src_ip = &pcb->local_ip; + } + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || + ip4_addr_ismulticast(ip_2_ip4(&pcb->local_ip))) { + /* if the local_ip is any or multicast + * use the outgoing network interface IP address as source address */ + src_ip = netif_ip_addr4(netif); + } else { + /* check if UDP PCB local IP address is correct + * this could be an old address if netif->ip_addr has changed */ + if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { + /* local_ip doesn't match, drop the packet */ + return ERR_RTE; + } + /* use UDP PCB local IP address as source address */ + src_ip = &pcb->local_ip; + } +#endif /* LWIP_IPV4 */ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); +#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +} + +/** @ingroup udp_raw + * Same as @ref udp_sendto_if, but with source address */ +err_t +udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); +} + +/** Same as udp_sendto_if_src(), but with checksum */ +err_t +udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum, const ip_addr_t *src_ip) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct udp_hdr *udphdr; + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + u8_t ip_proto; + u8_t ttl; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("udp_sendto_if_src: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if_src: invalid pbuf", p != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if_src: invalid dst_ip", dst_ip != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if_src: invalid src_ip", src_ip != NULL, return ERR_ARG); + LWIP_ERROR("udp_sendto_if_src: invalid netif", netif != NULL, return ERR_ARG); + + if (!IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || + !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + +#if LWIP_IPV4 && IP_SOF_BROADCAST + /* broadcast filter? */ + if (!ip_get_option(pcb, SOF_BROADCAST) && +#if LWIP_IPV6 + IP_IS_V4(dst_ip) && +#endif /* LWIP_IPV6 */ + ip_addr_isbroadcast(dst_ip, netif)) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + return ERR_VAL; + } +#endif /* LWIP_IPV4 && IP_SOF_BROADCAST */ + + /* if the PCB is not yet bound to a port, bind it here */ + if (pcb->local_port == 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); + err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); + return err; + } + } + + /* packet too large to add a UDP header without causing an overflow? */ + if ((u16_t)(p->tot_len + UDP_HLEN) < p->tot_len) { + return ERR_MEM; + } + /* not enough space to add an UDP header to first pbuf in given p chain? */ + if (pbuf_add_header(p, UDP_HLEN)) { + /* allocate header in a separate new pbuf */ + q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p (only if p contains data) */ + pbuf_chain(q, p); + } + /* first pbuf q points to header pbuf */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* adding space for header within p succeeded */ + /* first pbuf q equals given pbuf */ + q = p; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); + } + LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", + (q->len >= sizeof(struct udp_hdr))); + /* q now represents the packet to be sent */ + udphdr = (struct udp_hdr *)q->payload; + udphdr->src = lwip_htons(pcb->local_port); + udphdr->dest = lwip_htons(dst_port); + /* in UDP, 0 checksum means 'no checksum' */ + udphdr->chksum = 0x0000; + + /* Multicast Loop? */ +#if LWIP_MULTICAST_TX_OPTIONS + if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); + +#if LWIP_UDPLITE + /* UDP Lite protocol? */ + if (pcb->flags & UDP_FLAGS_UDPLITE) { + u16_t chklen, chklen_hdr; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); + /* set UDP message length in UDP header */ + chklen_hdr = chklen = pcb->chksum_len_tx; + if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { + if (chklen != 0) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); + } + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet. (See RFC 3828 chap. 3.1) + At least the UDP-Lite header must be covered by the + checksum, therefore, if chksum_len has an illegal + value, we generate the checksum over the complete + packet to be safe. */ + chklen_hdr = 0; + chklen = q->tot_len; + } + udphdr->len = lwip_htons(chklen_hdr); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + chklen = UDP_HLEN; + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, + q->tot_len, chklen, src_ip, dst_ip); +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } + } +#endif /* CHECKSUM_GEN_UDP */ + + ip_proto = IP_PROTO_UDPLITE; + } else +#endif /* LWIP_UDPLITE */ + { /* UDP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); + udphdr->len = lwip_htons(q->tot_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { + /* Checksum is mandatory over IPv6. */ + if (IP_IS_V6(dst_ip) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, + q->tot_len, UDP_HLEN, src_ip, dst_ip); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, + src_ip, dst_ip); + } + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; + } + } +#endif /* CHECKSUM_GEN_UDP */ + ip_proto = IP_PROTO_UDP; + } + + /* Determine TTL to use */ +#if LWIP_MULTICAST_TX_OPTIONS + ttl = (ip_addr_ismulticast(dst_ip) ? udp_get_multicast_ttl(pcb) : pcb->ttl); +#else /* LWIP_MULTICAST_TX_OPTIONS */ + ttl = pcb->ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); + /* output to IP */ + NETIF_SET_HINTS(netif, &(pcb->netif_hints)); + err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); + NETIF_RESET_HINTS(netif); + + /* @todo: must this be increased even if error occurred? */ + MIB2_STATS_INC(mib2.udpoutdatagrams); + + /* did we chain a separate header pbuf earlier? */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + q = NULL; + /* p is still referenced by the caller, and will live on */ + } + + UDP_STATS_INC(udp.xmit); + return err; +} + +/** + * @ingroup udp_raw + * Bind an UDP PCB. + * + * @param pcb UDP PCB to be bound with a local address ipaddr and port. + * @param ipaddr local IP address to bind with. Use IP_ANY_TYPE to + * bind to all local interfaces. + * @param port local UDP port to bind with. Use 0 to automatically bind + * to a random port between UDP_LOCAL_PORT_RANGE_START and + * UDP_LOCAL_PORT_RANGE_END. + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_USE. The specified ipaddr and port are already bound to by + * another UDP PCB. + * + * @see udp_disconnect() + */ +err_t +udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + u8_t rebind; +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + ip_addr_t zoned_ipaddr; +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + LWIP_ASSERT_CORE_LOCKED(); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY; + } +#else /* LWIP_IPV4 */ + LWIP_ERROR("udp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); +#endif /* LWIP_IPV4 */ + + LWIP_ERROR("udp_bind: invalid pcb", pcb != NULL, return ERR_ARG); + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); + + rebind = 0; + /* Check for double bind and rebind of the same pcb */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + /* is this UDP PCB already on active list? */ + if (pcb == ipcb) { + rebind = 1; + break; + } + } + +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now. + * This is legacy support: scope-aware callers should always provide properly + * zoned source addresses. Do the zone selection before the address-in-use + * check below; as such we have to make a temporary copy of the address. */ + if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { + ip_addr_copy(zoned_ipaddr, *ipaddr); + ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); + ipaddr = &zoned_ipaddr; + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + /* no port specified? */ + if (port == 0) { + port = udp_new_port(); + if (port == 0) { + /* no more ports available in local range */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); + return ERR_USE; + } + } else { + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb != ipcb) { + /* By default, we don't allow to bind to a port that any other udp + PCB is already bound to, unless *all* PCBs with that port have tha + REUSEADDR flag set. */ +#if SO_REUSE + if (!ip_get_option(pcb, SOF_REUSEADDR) || + !ip_get_option(ipcb, SOF_REUSEADDR)) +#endif /* SO_REUSE */ + { + /* port matches that of PCB in list and REUSEADDR not set -> reject */ + if ((ipcb->local_port == port) && + (((IP_GET_TYPE(&ipcb->local_ip) == IP_GET_TYPE(ipaddr)) && + /* IP address matches or any IP used? */ + (ip_addr_cmp(&ipcb->local_ip, ipaddr) || + ip_addr_isany(ipaddr) || + ip_addr_isany(&ipcb->local_ip))) || + (IP_GET_TYPE(&ipcb->local_ip) == IPADDR_TYPE_ANY) || + (IP_GET_TYPE(ipaddr) == IPADDR_TYPE_ANY))) { + /* other PCB already binds to this local IP and port */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); + return ERR_USE; + } + } + } + } + } + + ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); + + pcb->local_port = port; + mib2_udp_bind(pcb); + /* pcb not active yet? */ + if (rebind == 0) { + /* place the PCB on the active list if not already there */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); + ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, pcb->local_ip); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); + return ERR_OK; +} + +/** + * @ingroup udp_raw + * Bind an UDP PCB to a specific netif. + * After calling this function, all packets received via this PCB + * are guaranteed to have come in via the specified netif, and all + * outgoing packets will go out via the specified netif. + * + * @param pcb UDP PCB to be bound. + * @param netif netif to bind udp pcb to. Can be NULL. + * + * @see udp_disconnect() + */ +void +udp_bind_netif(struct udp_pcb *pcb, const struct netif *netif) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (netif != NULL) { + pcb->netif_idx = netif_get_index(netif); + } else { + pcb->netif_idx = NETIF_NO_INDEX; + } +} + +/** + * @ingroup udp_raw + * Sets the remote end of the pcb. This function does not generate any + * network traffic, but only sets the remote address of the pcb. + * + * @param pcb UDP PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * @param port remote UDP port to connect with. + * + * @return lwIP error code + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * The udp pcb is bound to a random local port if not already bound. + * + * @see udp_disconnect() + */ +err_t +udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("udp_connect: invalid pcb", pcb != NULL, return ERR_ARG); + LWIP_ERROR("udp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); + + if (pcb->local_port == 0) { + err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + return err; + } + } + + ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); +#if LWIP_IPV6 && LWIP_IPV6_SCOPES + /* If the given IP address should have a zone but doesn't, assign one now, + * using the bound address to make a more informed decision when possible. */ + if (IP_IS_V6(&pcb->remote_ip) && + ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) { + ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip)); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ + + pcb->remote_port = port; + pcb->flags |= UDP_FLAGS_CONNECTED; + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); + ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + pcb->remote_ip); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); + + /* Insert UDP PCB into the list of active UDP PCBs. */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb == ipcb) { + /* already on the list, just return */ + return ERR_OK; + } + } + /* PCB not yet on the list, add PCB now */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + return ERR_OK; +} + +/** + * @ingroup udp_raw + * Remove the remote end of the pcb. This function does not generate + * any network traffic, but only removes the remote address of the pcb. + * + * @param pcb the udp pcb to disconnect. + */ +void +udp_disconnect(struct udp_pcb *pcb) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("udp_disconnect: invalid pcb", pcb != NULL, return); + + /* reset remote address association */ +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); + } else { +#endif + ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); +#if LWIP_IPV4 && LWIP_IPV6 + } +#endif + pcb->remote_port = 0; + pcb->netif_idx = NETIF_NO_INDEX; + /* mark PCB as unconnected */ + udp_clear_flags(pcb, UDP_FLAGS_CONNECTED); +} + +/** + * @ingroup udp_raw + * Set a receive callback for a UDP PCB. + * This callback will be called when receiving a datagram for the pcb. + * + * @param pcb the pcb for which to set the recv callback + * @param recv function pointer of the callback function + * @param recv_arg additional argument to pass to the callback function + */ +void +udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) +{ + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("udp_recv: invalid pcb", pcb != NULL, return); + + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * @ingroup udp_raw + * Removes and deallocates the pcb. + * + * @param pcb UDP PCB to be removed. The PCB is removed from the list of + * UDP PCB's and the data structure is freed from memory. + * + * @see udp_new() + */ +void +udp_remove(struct udp_pcb *pcb) +{ + struct udp_pcb *pcb2; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ERROR("udp_remove: invalid pcb", pcb != NULL, return); + + mib2_udp_unbind(pcb); + /* pcb to be removed is first in list? */ + if (udp_pcbs == pcb) { + /* make list start at 2nd pcb */ + udp_pcbs = udp_pcbs->next; + /* pcb not 1st in list */ + } else { + for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in udp_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + break; + } + } + } + memp_free(MEMP_UDP_PCB, pcb); +} + +/** + * @ingroup udp_raw + * Creates a new UDP pcb which can be used for UDP communication. The + * pcb is not active until it has either been bound to a local address + * or connected to a remote address. + * @see MEMP_NUM_UDP_PCB + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new(void) +{ + struct udp_pcb *pcb; + + LWIP_ASSERT_CORE_LOCKED(); + + pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); + /* could allocate UDP PCB? */ + if (pcb != NULL) { + /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 + * which means checksum is generated over the whole datagram per default + * (recommended as default by RFC 3828). */ + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct udp_pcb)); + pcb->ttl = UDP_TTL; +#if LWIP_MULTICAST_TX_OPTIONS + udp_set_multicast_ttl(pcb, UDP_TTL); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + } + return pcb; +} + +/** + * @ingroup udp_raw + * Create a UDP PCB for specific IP type. + * The pcb is not active until it has either been bound to a local address + * or connected to a remote address. + * @see MEMP_NUM_UDP_PCB + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) packets, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new_ip_type(u8_t type) +{ + struct udp_pcb *pcb; + + LWIP_ASSERT_CORE_LOCKED(); + + pcb = udp_new(); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** This function is called from netif.c when address is changed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change + */ +void udp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) +{ + struct udp_pcb *upcb; + + if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { + for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&upcb->local_ip, old_addr)) { + /* The PCB is bound to the old ipaddr and + * is set to bound to the new one instead */ + ip_addr_copy(upcb->local_ip, *new_addr); + } + } + } +} + +#if UDP_DEBUG +/** + * Print UDP header information for debug purposes. + * + * @param udphdr pointer to the udp header in memory. + */ +void +udp_debug_print(struct udp_hdr *udphdr) +{ + LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + lwip_ntohs(udphdr->src), lwip_ntohs(udphdr->dest))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", + lwip_ntohs(udphdr->len), lwip_ntohs(udphdr->chksum))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/arpa/inet.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/arpa/inet.h new file mode 100644 index 0000000..0ed9baf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/arpa/inet.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/sockets.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/sockets.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/net/if.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/net/if.h new file mode 100644 index 0000000..6b8e63a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/net/if.h @@ -0,0 +1,36 @@ +/** + * @file + * This file is a posix wrapper for lwip/if_api.h. + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/if_api.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/netdb.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/netdb.h new file mode 100644 index 0000000..12d4c7f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/netdb.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/netdb.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/netdb.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/sys/socket.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/sys/socket.h new file mode 100644 index 0000000..0ed9baf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/posix/sys/socket.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/sockets.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/sockets.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/stdc/errno.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/stdc/errno.h new file mode 100644 index 0000000..98a9aec --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/compat/stdc/errno.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix/stdc wrapper for lwip/errno.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/errno.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp.h new file mode 100644 index 0000000..1b24544 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp.h @@ -0,0 +1,206 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * + * This file contains the generic API. + * For more details see @ref altcp_api. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_H +#define LWIP_HDR_ALTCP_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcpbase.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_pcb; +struct altcp_functions; + +typedef err_t (*altcp_accept_fn)(void *arg, struct altcp_pcb *new_conn, err_t err); +typedef err_t (*altcp_connected_fn)(void *arg, struct altcp_pcb *conn, err_t err); +typedef err_t (*altcp_recv_fn)(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err); +typedef err_t (*altcp_sent_fn)(void *arg, struct altcp_pcb *conn, u16_t len); +typedef err_t (*altcp_poll_fn)(void *arg, struct altcp_pcb *conn); +typedef void (*altcp_err_fn)(void *arg, err_t err); + +typedef struct altcp_pcb* (*altcp_new_fn)(void *arg, u8_t ip_type); + +struct altcp_pcb { + const struct altcp_functions *fns; + struct altcp_pcb *inner_conn; + void *arg; + void *state; + /* application callbacks */ + altcp_accept_fn accept; + altcp_connected_fn connected; + altcp_recv_fn recv; + altcp_sent_fn sent; + altcp_poll_fn poll; + altcp_err_fn err; + u8_t pollinterval; +}; + +/** @ingroup altcp */ +typedef struct altcp_allocator_s { + /** Allocator function */ + altcp_new_fn alloc; + /** Argument to allocator function */ + void *arg; +} altcp_allocator_t; + +struct altcp_pcb *altcp_new(altcp_allocator_t *allocator); +struct altcp_pcb *altcp_new_ip6(altcp_allocator_t *allocator); +struct altcp_pcb *altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type); + +void altcp_arg(struct altcp_pcb *conn, void *arg); +void altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept); +void altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv); +void altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent); +void altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval); +void altcp_err(struct altcp_pcb *conn, altcp_err_fn err); + +void altcp_recved(struct altcp_pcb *conn, u16_t len); +err_t altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); +err_t altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); + +/* return conn for source code compatibility to tcp callback API only */ +struct altcp_pcb *altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err); +#define altcp_listen_with_backlog(conn, backlog) altcp_listen_with_backlog_and_err(conn, backlog, NULL) +/** @ingroup altcp */ +#define altcp_listen(conn) altcp_listen_with_backlog_and_err(conn, TCP_DEFAULT_LISTEN_BACKLOG, NULL) + +void altcp_abort(struct altcp_pcb *conn); +err_t altcp_close(struct altcp_pcb *conn); +err_t altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx); + +err_t altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); +err_t altcp_output(struct altcp_pcb *conn); + +u16_t altcp_mss(struct altcp_pcb *conn); +u16_t altcp_sndbuf(struct altcp_pcb *conn); +u16_t altcp_sndqueuelen(struct altcp_pcb *conn); +void altcp_nagle_disable(struct altcp_pcb *conn); +void altcp_nagle_enable(struct altcp_pcb *conn); +int altcp_nagle_disabled(struct altcp_pcb *conn); + +void altcp_setprio(struct altcp_pcb *conn, u8_t prio); + +err_t altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); +ip_addr_t *altcp_get_ip(struct altcp_pcb *conn, int local); +u16_t altcp_get_port(struct altcp_pcb *conn, int local); + +#if LWIP_TCP_KEEPALIVE +void altcp_keepalive_disable(struct altcp_pcb *conn); +void altcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count); +#endif + +#ifdef LWIP_DEBUG +enum tcp_state altcp_dbg_get_tcp_state(struct altcp_pcb *conn); +#endif + +#ifdef __cplusplus +} +#endif + +#else /* LWIP_ALTCP */ + +/* ALTCP disabled, define everything to link against tcp callback API (e.g. to get a small non-ssl httpd) */ + +#include "lwip/tcp.h" + +#define altcp_accept_fn tcp_accept_fn +#define altcp_connected_fn tcp_connected_fn +#define altcp_recv_fn tcp_recv_fn +#define altcp_sent_fn tcp_sent_fn +#define altcp_poll_fn tcp_poll_fn +#define altcp_err_fn tcp_err_fn + +#define altcp_pcb tcp_pcb +#define altcp_tcp_new_ip_type tcp_new_ip_type +#define altcp_tcp_new tcp_new +#define altcp_tcp_new_ip6 tcp_new_ip6 + +#define altcp_new(allocator) tcp_new() +#define altcp_new_ip6(allocator) tcp_new_ip6() +#define altcp_new_ip_type(allocator, ip_type) tcp_new_ip_type(ip_type) + +#define altcp_arg tcp_arg +#define altcp_accept tcp_accept +#define altcp_recv tcp_recv +#define altcp_sent tcp_sent +#define altcp_poll tcp_poll +#define altcp_err tcp_err + +#define altcp_recved tcp_recved +#define altcp_bind tcp_bind +#define altcp_connect tcp_connect + +#define altcp_listen_with_backlog_and_err tcp_listen_with_backlog_and_err +#define altcp_listen_with_backlog tcp_listen_with_backlog +#define altcp_listen tcp_listen + +#define altcp_abort tcp_abort +#define altcp_close tcp_close +#define altcp_shutdown tcp_shutdown + +#define altcp_write tcp_write +#define altcp_output tcp_output + +#define altcp_mss tcp_mss +#define altcp_sndbuf tcp_sndbuf +#define altcp_sndqueuelen tcp_sndqueuelen +#define altcp_nagle_disable tcp_nagle_disable +#define altcp_nagle_enable tcp_nagle_enable +#define altcp_nagle_disabled tcp_nagle_disabled +#define altcp_setprio tcp_setprio + +#define altcp_get_tcp_addrinfo tcp_get_tcp_addrinfo +#define altcp_get_ip(pcb, local) ((local) ? (&(pcb)->local_ip) : (&(pcb)->remote_ip)) + +#ifdef LWIP_DEBUG +#define altcp_dbg_get_tcp_state tcp_dbg_get_tcp_state +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tcp.h new file mode 100644 index 0000000..dbde584 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tcp.h @@ -0,0 +1,72 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the base implementation calling into tcp. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_TCP_H +#define LWIP_HDR_ALTCP_TCP_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_pcb *altcp_tcp_new_ip_type(u8_t ip_type); + +#define altcp_tcp_new() altcp_tcp_new_ip_type(IPADDR_TYPE_V4) +#define altcp_tcp_new_ip6() altcp_tcp_new_ip_type(IPADDR_TYPE_V6) + +struct altcp_pcb *altcp_tcp_alloc(void *arg, u8_t ip_type); + +struct tcp_pcb; +struct altcp_pcb *altcp_tcp_wrap(struct tcp_pcb *tpcb); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_TCP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tls.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tls.h new file mode 100644 index 0000000..ff797f2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/altcp_tls.h @@ -0,0 +1,143 @@ +/** + * @file + * Application layered TCP/TLS connection API (to be used from TCPIP thread) + * + * @defgroup altcp_tls TLS layer + * @ingroup altcp + * This file contains function prototypes for a TLS layer. + * A port to ARM mbedtls is provided in the apps/ tree + * (LWIP_ALTCP_TLS_MBEDTLS option). + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_TLS_H +#define LWIP_HDR_ALTCP_TLS_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#if LWIP_ALTCP_TLS + +#include "lwip/altcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup altcp_tls + * ALTCP_TLS configuration handle, content depends on port (e.g. mbedtls) + */ +struct altcp_tls_config; + +/** @ingroup altcp_tls + * Create an ALTCP_TLS server configuration handle prepared for multiple certificates + */ +struct altcp_tls_config *altcp_tls_create_config_server(uint8_t cert_count); + +/** @ingroup altcp_tls + * Add a certificate to an ALTCP_TLS server configuration handle + */ +err_t altcp_tls_config_server_add_privkey_cert(struct altcp_tls_config *config, + const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len); + +/** @ingroup altcp_tls + * Create an ALTCP_TLS server configuration handle with one certificate + * (short version of calling @ref altcp_tls_create_config_server and + * @ref altcp_tls_config_server_add_privkey_cert) + */ +struct altcp_tls_config *altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len); + +/** @ingroup altcp_tls + * Create an ALTCP_TLS client configuration handle + */ +struct altcp_tls_config *altcp_tls_create_config_client(const u8_t *cert, size_t cert_len); + +/** @ingroup altcp_tls + * Create an ALTCP_TLS client configuration handle with two-way server/client authentication + */ +struct altcp_tls_config *altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len); + +/** @ingroup altcp_tls + * Free an ALTCP_TLS configuration handle + */ +void altcp_tls_free_config(struct altcp_tls_config *conf); + +/** @ingroup altcp_tls + * Free an ALTCP_TLS global entropy instance. + * All ALTCP_TLS configuration are linked to one altcp_tls_entropy_rng structure + * that handle an unique system entropy & ctr_drbg instance. + * This function allow application to free this altcp_tls_entropy_rng structure + * when all configuration referencing it were destroyed. + * This function does nothing if some ALTCP_TLS configuration handle are still + * active. + */ +void altcp_tls_free_entropy(void); + +/** @ingroup altcp_tls + * Create new ALTCP_TLS layer wrapping an existing pcb as inner connection (e.g. TLS over TCP) + */ +struct altcp_pcb *altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb); + +/** @ingroup altcp_tls + * Create new ALTCP_TLS pcb and its inner tcp pcb + */ +struct altcp_pcb *altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type); + +/** @ingroup altcp_tls + * Create new ALTCP_TLS layer pcb and its inner tcp pcb. + * Same as @ref altcp_tls_new but this allocator function fits to + * @ref altcp_allocator_t / @ref altcp_new.\n + 'arg' must contain a struct altcp_tls_config *. + */ +struct altcp_pcb *altcp_tls_alloc(void *arg, u8_t ip_type); + +/** @ingroup altcp_tls + * Return pointer to internal TLS context so application can tweak it. + * Real type depends on port (e.g. mbedtls) + */ +void *altcp_tls_context(struct altcp_pcb *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP_TLS */ +#endif /* LWIP_ALTCP */ +#endif /* LWIP_HDR_ALTCP_TLS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/api.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/api.h new file mode 100644 index 0000000..c2afaf2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/api.h @@ -0,0 +1,431 @@ +/** + * @file + * netconn API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_H +#define LWIP_HDR_API_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/arch.h" +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 +#define NETCONN_NOAUTORCVD 0x08 /* prevent netconn_recv_data_tcp() from updating the tcp window - must be done manually via netconn_tcp_recvd() */ +#define NETCONN_NOFIN 0x10 /* upper layer already received data, leave FIN in queue until called again */ + +/* Flags for struct netconn.flags (u8_t) */ +/** This netconn had an error, don't block on recvmbox/acceptmbox any more */ +#define NETCONN_FLAG_MBOXCLOSED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +#if LWIP_NETCONN_FULLDUPLEX + /** The mbox of this netconn is being deallocated, don't use it anymore */ +#define NETCONN_FLAG_MBOXINVALID 0x08 +#endif /* LWIP_NETCONN_FULLDUPLEX */ +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 +#if LWIP_IPV6 +/** If this flag is set then only IPv6 communication is allowed on the + netconn. As per RFC#3493 this features defaults to OFF allowing + dual-stack usage by default. */ +#define NETCONN_FLAG_IPV6_V6ONLY 0x20 +#endif /* LWIP_IPV6 */ +#if LWIP_NETBUF_RECVINFO +/** Received packet info will be recorded for this netconn */ +#define NETCONN_FLAG_PKTINFO 0x40 +#endif /* LWIP_NETBUF_RECVINFO */ +/** A FIN has been received but not passed to the application yet */ +#define NETCONN_FIN_RX_PENDING 0x80 + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#if LWIP_IPV6 +#define NETCONN_TYPE_IPV6 0x08 +#define NETCONNTYPE_ISIPV6(t) (((t)&NETCONN_TYPE_IPV6) != 0) +#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM) +#else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISIPV6(t) (0) +#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) +#endif /* LWIP_IPV6 */ + +/** @ingroup netconn_common + * Protocol family and type of the netconn + */ +enum netconn_type { + NETCONN_INVALID = 0, + /** TCP IPv4 */ + NETCONN_TCP = 0x10, +#if LWIP_IPV6 + /** TCP IPv6 */ + NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, +#endif /* LWIP_IPV6 */ + /** UDP IPv4 */ + NETCONN_UDP = 0x20, + /** UDP IPv4 lite */ + NETCONN_UDPLITE = 0x21, + /** UDP IPv4 no checksum */ + NETCONN_UDPNOCHKSUM = 0x22, + +#if LWIP_IPV6 + /** UDP IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, + /** UDP IPv6 lite (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, + /** UDP IPv6 no checksum (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, +#endif /* LWIP_IPV6 */ + + /** Raw connection IPv4 */ + NETCONN_RAW = 0x40 +#if LWIP_IPV6 + /** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ +#endif /* LWIP_IPV6 */ +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Used to inform the callback function about changes + * + * Event explanation: + * + * In the netconn implementation, there are three ways to block a client: + * + * - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept()) + * - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data()) + * - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write()) + * + * The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking + * connections, you need to know in advance whether a call to a netconn function call would block or not, + * and these events tell you about that. + * + * RCVPLUS events say: Safe to perform a potentially blocking call call once more. + * They are counted in sockets - three RCVPLUS events for accept mbox means you are safe + * to call netconn_accept 3 times without being blocked. + * Same thing for receive mbox. + * + * RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged". + * Socket implementation decrements the counter. + * + * For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something. + * SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again. + * A SENDMINUS event occurs when the next call to a netconn_send() would be blocking. + */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/* Used for netconn_gethostbyname_addrtype(), these should match the DNS_ADDRTYPE defines in dns.h */ +#define NETCONN_DNS_DEFAULT NETCONN_DNS_IPV4_IPV6 +#define NETCONN_DNS_IPV4 0 +#define NETCONN_DNS_IPV6 1 +#define NETCONN_DNS_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define NETCONN_DNS_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#endif /* LWIP_DNS */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last asynchronous unreported error this netconn had */ + err_t pending_err; +#if !LWIP_NETCONN_SEM_PER_THREAD + /** sem that is used to synchronously execute functions in the core context */ + sys_sem_t op_completed; +#endif + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ +#if LWIP_NETCONN_FULLDUPLEX + /** number of threads waiting on an mbox. This is required to unblock + all threads when closing while threads are waiting. */ + int mbox_threads_waiting; +#endif + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_SNDTIMEO + /** timeout to wait for sending data (which means enqueueing data for sending + in internal buffers) in milliseconds */ + s32_t send_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVTIMEO + /** timeout in milliseconds to wait for new data to be received + (or connections to arrive for listening netconns) */ + u32_t recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + /** values <0 mean linger is disabled, values > 0 are seconds to linger */ + s16_t linger; +#endif /* LWIP_SO_LINGER */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** This vector type is passed to @ref netconn_write_vectors_partly to send + * multiple buffers at once. + * ATTENTION: This type has to directly map struct iovec since one is casted + * into the other! + */ +struct netvector { + /** pointer to the application buffer that contains the data to send */ + const void *ptr; + /** size of the application data to send */ + size_t len; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/* Network connection functions: */ + +/** @ingroup netconn_common + * Create new netconn connection + * @param t @ref netconn_type */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_prepare_delete(struct netconn *conn); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +/** @ingroup netconn_common */ +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +/** @ingroup netconn_common */ +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_bind_if(struct netconn *conn, u8_t if_idx); +err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +/** @ingroup netconn_tcp */ +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +err_t netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags); +err_t netconn_tcp_recvd(struct netconn *conn, size_t len); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + const ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written); +err_t netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, + u8_t apiflags, size_t *bytes_written); +/** @ingroup netconn_tcp */ +#define netconn_write(conn, dataptr, size, apiflags) \ + netconn_write_partly(conn, dataptr, size, apiflags, NULL) +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +err_t netconn_join_leave_group(struct netconn *conn, const ip_addr_t *multiaddr, + const ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +err_t netconn_join_leave_group_netif(struct netconn *conn, const ip_addr_t *multiaddr, + u8_t if_idx, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if LWIP_DNS +#if LWIP_IPV4 && LWIP_IPV6 +err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); +#define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) +#else /* LWIP_IPV4 && LWIP_IPV6 */ +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#define netconn_gethostbyname_addrtype(name, addr, dns_addrtype) netconn_gethostbyname(name, addr) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#endif /* LWIP_DNS */ + +err_t netconn_err(struct netconn *conn); +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +#define netconn_set_flags(conn, set_flags) do { (conn)->flags = (u8_t)((conn)->flags | (set_flags)); } while(0) +#define netconn_clear_flags(conn, clr_flags) do { (conn)->flags = (u8_t)((conn)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) +#define netconn_is_flag_set(conn, flag) (((conn)->flags & (flag)) != 0) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + netconn_set_flags(conn, NETCONN_FLAG_NON_BLOCKING); \ +} else { \ + netconn_clear_flags(conn, NETCONN_FLAG_NON_BLOCKING); }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +#if LWIP_IPV6 +/** @ingroup netconn_common + * TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_set_ipv6only(conn, val) do { if(val) { \ + netconn_set_flags(conn, NETCONN_FLAG_IPV6_V6ONLY); \ +} else { \ + netconn_clear_flags(conn, NETCONN_FLAG_IPV6_V6ONLY); }} while(0) +/** @ingroup netconn_common + * TCP: Get the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_get_ipv6only(conn) (((conn)->flags & NETCONN_FLAG_IPV6_V6ONLY) != 0) +#endif /* LWIP_IPV6 */ + +#if LWIP_SO_SNDTIMEO +/** Set the send timeout in milliseconds */ +#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) +/** Get the send timeout in milliseconds */ +#define netconn_get_sendtimeout(conn) ((conn)->send_timeout) +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#if LWIP_NETCONN_SEM_PER_THREAD +void netconn_thread_init(void); +void netconn_thread_cleanup(void); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define netconn_thread_init() +#define netconn_thread_cleanup() +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_API_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/FILES b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/FILES new file mode 100644 index 0000000..adfc0f3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/FILES @@ -0,0 +1,2 @@ +This directory contains application headers. +Every application shall provide one api file APP.h and optionally one options file APP_opts.h diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_proxyconnect.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_proxyconnect.h new file mode 100644 index 0000000..65d3127 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_proxyconnect.h @@ -0,0 +1,79 @@ +/** + * @file + * Application layered TCP connection API that executes a proxy-connect. + * + * This file provides a starting layer that executes a proxy-connect e.g. to + * set up TLS connections through a http proxy. + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H +#define LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_proxyconnect_config { + ip_addr_t proxy_addr; + u16_t proxy_port; +}; + + +struct altcp_pcb *altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb); +struct altcp_pcb *altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type); + +struct altcp_pcb *altcp_proxyconnect_alloc(void *arg, u8_t ip_type); + +#if LWIP_ALTCP_TLS +struct altcp_proxyconnect_tls_config { + struct altcp_proxyconnect_config proxy; + struct altcp_tls_config *tls_config; +}; + +struct altcp_pcb *altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type); +#endif /* LWIP_ALTCP_TLS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP */ +#endif /* LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_tls_mbedtls_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_tls_mbedtls_opts.h new file mode 100644 index 0000000..71aa599 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/altcp_tls_mbedtls_opts.h @@ -0,0 +1,105 @@ +/** + * @file + * Application layered TCP/TLS connection API (to be used from TCPIP thread) + * + * This file contains options for an mbedtls port of the TLS layer. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_TLS_OPTS_H +#define LWIP_HDR_ALTCP_TLS_OPTS_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +/** LWIP_ALTCP_TLS_MBEDTLS==1: use mbedTLS for TLS support for altcp API + * mbedtls include directory must be reachable via include search path + */ +#ifndef LWIP_ALTCP_TLS_MBEDTLS +#define LWIP_ALTCP_TLS_MBEDTLS 0 +#endif + +/** Configure debug level of this file */ +#ifndef ALTCP_MBEDTLS_DEBUG +#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_OFF +#endif + +/** Configure lwIP debug level of the mbedTLS library */ +#ifndef ALTCP_MBEDTLS_LIB_DEBUG +#define ALTCP_MBEDTLS_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** Configure minimum internal debug level of the mbedTLS library */ +#ifndef ALTCP_MBEDTLS_LIB_DEBUG_LEVEL_MIN +#define ALTCP_MBEDTLS_LIB_DEBUG_LEVEL_MIN 0 +#endif + +/** Enable the basic session cache + * ATTENTION: Using a session cache can lower security by reusing keys! + */ +#ifndef ALTCP_MBEDTLS_USE_SESSION_CACHE +#define ALTCP_MBEDTLS_USE_SESSION_CACHE 0 +#endif + +/** Maximum cache size of the basic session cache */ +#ifndef ALTCP_MBEDTLS_SESSION_CACHE_SIZE +#define ALTCP_MBEDTLS_SESSION_CACHE_SIZE 30 +#endif + +/** Set a session timeout in seconds for the basic session cache */ +#ifndef ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS +#define ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS (60 * 60) +#endif + +/** Use session tickets to speed up connection setup (needs + * MBEDTLS_SSL_SESSION_TICKETS enabled in mbedTLS config). + * ATTENTION: Using session tickets can lower security by reusing keys! + */ +#ifndef ALTCP_MBEDTLS_USE_SESSION_TICKETS +#define ALTCP_MBEDTLS_USE_SESSION_TICKETS 0 +#endif + +/** Session ticket cipher */ +#ifndef ALTCP_MBEDTLS_SESSION_TICKET_CIPHER +#define ALTCP_MBEDTLS_SESSION_TICKET_CIPHER MBEDTLS_CIPHER_AES_256_GCM +#endif + +/** Maximum timeout for session tickets */ +#ifndef ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS +#define ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS (60 * 60 * 24) +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_TLS_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/fs.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/fs.h new file mode 100644 index 0000000..67b9a60 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/fs.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_APPS_FS_H +#define LWIP_HDR_APPS_FS_H + +#include "httpd_opts.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FS_READ_EOF -1 +#define FS_READ_DELAYED -2 + +#if HTTPD_PRECALCULATED_CHECKSUM +struct fsdata_chksum { + u32_t offset; + u16_t chksum; + u16_t len; +}; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + +#define FS_FILE_FLAGS_HEADER_INCLUDED 0x01 +#define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02 +#define FS_FILE_FLAGS_HEADER_HTTPVER_1_1 0x04 +#define FS_FILE_FLAGS_SSI 0x08 + +/** Define FS_FILE_EXTENSION_T_DEFINED if you have typedef'ed to your private + * pointer type (defaults to 'void' so the default usage is 'void*') + */ +#ifndef FS_FILE_EXTENSION_T_DEFINED +typedef void fs_file_extension; +#endif + +struct fs_file { + const char *data; + int len; + int index; + /* pextension is free for implementations to hold private (extensional) + arbitrary data, e.g. holding some file state or file system handle */ + fs_file_extension *pextension; +#if HTTPD_PRECALCULATED_CHECKSUM + const struct fsdata_chksum *chksum; + u16_t chksum_count; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + u8_t flags; +#if LWIP_HTTPD_CUSTOM_FILES + u8_t is_custom_file; +#endif /* LWIP_HTTPD_CUSTOM_FILES */ +#if LWIP_HTTPD_FILE_STATE + void *state; +#endif /* LWIP_HTTPD_FILE_STATE */ +}; + +#if LWIP_HTTPD_FS_ASYNC_READ +typedef void (*fs_wait_cb)(void *arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + +err_t fs_open(struct fs_file *file, const char *name); +void fs_close(struct fs_file *file); +#if LWIP_HTTPD_DYNAMIC_FILE_READ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_read(struct fs_file *file, char *buffer, int count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_bytes_left(struct fs_file *file); + +#if LWIP_HTTPD_FILE_STATE +/** This user-defined function is called when a file is opened. */ +void *fs_state_init(struct fs_file *file, const char *name); +/** This user-defined function is called when a file is closed. */ +void fs_state_free(struct fs_file *file, void *state); +#endif /* #if LWIP_HTTPD_FILE_STATE */ + +struct fsdata_file { + const struct fsdata_file *next; + const unsigned char *name; + const unsigned char *data; + int len; + u8_t flags; +#if HTTPD_PRECALCULATED_CHECKSUM + u16_t chksum_count; + const struct fsdata_chksum *chksum; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_FS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/http_client.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/http_client.h new file mode 100644 index 0000000..8a06308 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/http_client.h @@ -0,0 +1,160 @@ +/** + * @file + * HTTP client + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_APPS_HTTP_CLIENT_H +#define LWIP_HDR_APPS_HTTP_CLIENT_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/altcp.h" +#include "lwip/prot/iana.h" +#include "lwip/pbuf.h" + +#if LWIP_TCP && LWIP_CALLBACK_API + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup httpc + * HTTPC_HAVE_FILE_IO: define this to 1 to have functions dowloading directly + * to disk via fopen/fwrite. + * These functions are example implementations of the interface only. + */ +#ifndef LWIP_HTTPC_HAVE_FILE_IO +#define LWIP_HTTPC_HAVE_FILE_IO 0 +#endif + +/** + * @ingroup httpc + * The default TCP port used for HTTP + */ +#define HTTP_DEFAULT_PORT LWIP_IANA_PORT_HTTP + +/** + * @ingroup httpc + * HTTP client result codes + */ +typedef enum ehttpc_result { + /** File successfully received */ + HTTPC_RESULT_OK = 0, + /** Unknown error */ + HTTPC_RESULT_ERR_UNKNOWN = 1, + /** Connection to server failed */ + HTTPC_RESULT_ERR_CONNECT = 2, + /** Failed to resolve server hostname */ + HTTPC_RESULT_ERR_HOSTNAME = 3, + /** Connection unexpectedly closed by remote server */ + HTTPC_RESULT_ERR_CLOSED = 4, + /** Connection timed out (server didn't respond in time) */ + HTTPC_RESULT_ERR_TIMEOUT = 5, + /** Server responded with an error code */ + HTTPC_RESULT_ERR_SVR_RESP = 6, + /** Local memory error */ + HTTPC_RESULT_ERR_MEM = 7, + /** Local abort */ + HTTPC_RESULT_LOCAL_ABORT = 8, + /** Content length mismatch */ + HTTPC_RESULT_ERR_CONTENT_LEN = 9 +} httpc_result_t; + +typedef struct _httpc_state httpc_state_t; + +/** + * @ingroup httpc + * Prototype of a http client callback function + * + * @param arg argument specified when initiating the request + * @param httpc_result result of the http transfer (see enum httpc_result_t) + * @param rx_content_len number of bytes received (without headers) + * @param srv_res this contains the http status code received (if any) + * @param err an error returned by internal lwip functions, can help to specify + * the source of the error but must not necessarily be != ERR_OK + */ +typedef void (*httpc_result_fn)(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err); + +/** + * @ingroup httpc + * Prototype of http client callback: called when the headers are received + * + * @param connection http client connection + * @param arg argument specified when initiating the request + * @param hdr header pbuf(s) (may contain data also) + * @param hdr_len length of the heders in 'hdr' + * @param content_len content length as received in the headers (-1 if not received) + * @return if != ERR_OK is returned, the connection is aborted + */ +typedef err_t (*httpc_headers_done_fn)(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len); + +typedef struct _httpc_connection { + ip_addr_t proxy_addr; + u16_t proxy_port; + u8_t use_proxy; + /* @todo: add username:pass? */ + +#if LWIP_ALTCP + altcp_allocator_t *altcp_allocator; +#endif + + /* this callback is called when the transfer is finished (or aborted) */ + httpc_result_fn result_fn; + /* this callback is called after receiving the http headers + It can abort the connection by returning != ERR_OK */ + httpc_headers_done_fn headers_done_fn; +} httpc_connection_t; + +err_t httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings, + altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection); +err_t httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings, + altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection); + +#if LWIP_HTTPC_HAVE_FILE_IO +err_t httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings, + void* callback_arg, const char* local_file_name, httpc_state_t **connection); +err_t httpc_get_file_dns_to_disk(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings, + void* callback_arg, const char* local_file_name, httpc_state_t **connection); +#endif /* LWIP_HTTPC_HAVE_FILE_IO */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP && LWIP_CALLBACK_API */ + +#endif /* LWIP_HDR_APPS_HTTP_CLIENT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd.h new file mode 100644 index 0000000..e872429 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd.h @@ -0,0 +1,255 @@ +/** + * @file + * HTTP server + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_H +#define LWIP_HDR_APPS_HTTPD_H + +#include "httpd_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_HTTPD_CGI + +/** + * @ingroup httpd + * Function pointer for a CGI script handler. + * + * This function is called each time the HTTPD server is asked for a file + * whose name was previously registered as a CGI function using a call to + * http_set_cgi_handlers. The iIndex parameter provides the index of the + * CGI within the cgis array passed to http_set_cgi_handlers. Parameters + * pcParam and pcValue provide access to the parameters provided along with + * the URI. iNumParams provides a count of the entries in the pcParam and + * pcValue arrays. Each entry in the pcParam array contains the name of a + * parameter with the corresponding entry in the pcValue array containing the + * value for that parameter. Note that pcParam may contain multiple elements + * with the same name if, for example, a multi-selection list control is used + * in the form generating the data. + * + * The function should return a pointer to a character string which is the + * path and filename of the response that is to be sent to the connected + * browser, for example "/thanks.htm" or "/response/error.ssi". + * + * The maximum number of parameters that will be passed to this function via + * iNumParams is defined by LWIP_HTTPD_MAX_CGI_PARAMETERS. Any parameters in + * the incoming HTTP request above this number will be discarded. + * + * Requests intended for use by this CGI mechanism must be sent using the GET + * method (which encodes all parameters within the URI rather than in a block + * later in the request). Attempts to use the POST method will result in the + * request being ignored. + * + */ +typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], + char *pcValue[]); + +/** + * @ingroup httpd + * Structure defining the base filename (URL) of a CGI and the associated + * function which is to be called when that URL is requested. + */ +typedef struct +{ + const char *pcCGIName; + tCGIHandler pfnCGIHandler; +} tCGI; + +void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); + +#endif /* LWIP_HTTPD_CGI */ + +#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI + +#if LWIP_HTTPD_CGI_SSI +/* we have to prototype this struct here to make it available for the handler */ +struct fs_file; + +/** Define this generic CGI handler in your application. + * It is called once for every URI with parameters. + * The parameters can be stored to the object passed as connection_state, which + * is allocated to file->state via fs_state_init() from fs_open() or fs_open_custom(). + * Content creation via SSI or complete dynamic files can retrieve the CGI params from there. + */ +extern void httpd_cgi_handler(struct fs_file *file, const char* uri, int iNumParams, + char **pcParam, char **pcValue +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); +#endif /* LWIP_HTTPD_CGI_SSI */ + +#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */ + +#if LWIP_HTTPD_SSI + +/** + * @ingroup httpd + * Function pointer for the SSI tag handler callback. + * + * This function will be called each time the HTTPD server detects a tag of the + * form in files with extensions mentioned in the g_pcSSIExtensions + * array (currently .shtml, .shtm, .ssi, .xml, .json) where "name" appears as + * one of the tags supplied to http_set_ssi_handler in the tags array. The + * returned insert string, which will be appended after the the string + * "" in file sent back to the client, should be written to pointer + * pcInsert. iInsertLen contains the size of the buffer pointed to by + * pcInsert. The iIndex parameter provides the zero-based index of the tag as + * found in the tags array and identifies the tag that is to be processed. + * + * The handler returns the number of characters written to pcInsert excluding + * any terminating NULL or HTTPD_SSI_TAG_UNKNOWN when tag is not recognized. + * + * Note that the behavior of this SSI mechanism is somewhat different from the + * "normal" SSI processing as found in, for example, the Apache web server. In + * this case, the inserted text is appended following the SSI tag rather than + * replacing the tag entirely. This allows for an implementation that does not + * require significant additional buffering of output data yet which will still + * offer usable SSI functionality. One downside to this approach is when + * attempting to use SSI within JavaScript. The SSI tag is structured to + * resemble an HTML comment but this syntax does not constitute a comment + * within JavaScript and, hence, leaving the tag in place will result in + * problems in these cases. In order to avoid these problems, define + * LWIP_HTTPD_SSI_INCLUDE_TAG as zero in your lwip options file, or use JavaScript + * style block comments in the form / * # name * / (without the spaces). + */ +typedef u16_t (*tSSIHandler)( +#if LWIP_HTTPD_SSI_RAW + const char* ssi_tag_name, +#else /* LWIP_HTTPD_SSI_RAW */ + int iIndex, +#endif /* LWIP_HTTPD_SSI_RAW */ + char *pcInsert, int iInsertLen +#if LWIP_HTTPD_SSI_MULTIPART + , u16_t current_tag_part, u16_t *next_tag_part +#endif /* LWIP_HTTPD_SSI_MULTIPART */ +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); + +/** Set the SSI handler function + * (if LWIP_HTTPD_SSI_RAW==1, only the first argument is used) + */ +void http_set_ssi_handler(tSSIHandler pfnSSIHandler, + const char **ppcTags, int iNumTags); + +/** For LWIP_HTTPD_SSI_RAW==1, return this to indicate the tag is unknown. + * In this case, the webserver writes a warning into the page. + * You can also just return 0 to write nothing for unknown tags. + */ +#define HTTPD_SSI_TAG_UNKNOWN 0xFFFF + +#endif /* LWIP_HTTPD_SSI */ + +#if LWIP_HTTPD_SUPPORT_POST + +/* These functions must be implemented by the application */ + +/** + * @ingroup httpd + * Called when a POST request has been received. The application can decide + * whether to accept it or not. + * + * @param connection Unique connection identifier, valid until httpd_post_end + * is called. + * @param uri The HTTP header URI receiving the POST request. + * @param http_request The raw HTTP request (the first packet, normally). + * @param http_request_len Size of 'http_request'. + * @param content_len Content-Length from HTTP header. + * @param response_uri Filename of response file, to be filled when denying the + * request + * @param response_uri_len Size of the 'response_uri' buffer. + * @param post_auto_wnd Set this to 0 to let the callback code handle window + * updates by calling 'httpd_post_data_recved' (to throttle rx speed) + * default is 1 (httpd handles window updates automatically) + * @return ERR_OK: Accept the POST request, data may be passed in + * another err_t: Deny the POST request, send back 'bad request'. + */ +err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, + u16_t http_request_len, int content_len, char *response_uri, + u16_t response_uri_len, u8_t *post_auto_wnd); + +/** + * @ingroup httpd + * Called for each pbuf of data that has been received for a POST. + * ATTENTION: The application is responsible for freeing the pbufs passed in! + * + * @param connection Unique connection identifier. + * @param p Received data. + * @return ERR_OK: Data accepted. + * another err_t: Data denied, http_post_get_response_uri will be called. + */ +err_t httpd_post_receive_data(void *connection, struct pbuf *p); + +/** + * @ingroup httpd + * Called when all data is received or when the connection is closed. + * The application must return the filename/URI of a file to send in response + * to this POST request. If the response_uri buffer is untouched, a 404 + * response is returned. + * + * @param connection Unique connection identifier. + * @param response_uri Filename of response file, to be filled when denying the request + * @param response_uri_len Size of the 'response_uri' buffer. + */ +void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); + +#if LWIP_HTTPD_POST_MANUAL_WND +void httpd_post_data_recved(void *connection, u16_t recved_len); +#endif /* LWIP_HTTPD_POST_MANUAL_WND */ + +#endif /* LWIP_HTTPD_SUPPORT_POST */ + +void httpd_init(void); + +#if HTTPD_ENABLE_HTTPS +struct altcp_tls_config; +void httpd_inits(struct altcp_tls_config *conf); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_HTTPD_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd_opts.h new file mode 100644 index 0000000..8723961 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/httpd_opts.h @@ -0,0 +1,396 @@ +/** + * @file + * HTTP server options list + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_OPTS_H +#define LWIP_HDR_APPS_HTTPD_OPTS_H + +#include "lwip/opt.h" +#include "lwip/prot/iana.h" + +/** + * @defgroup httpd_opts Options + * @ingroup httpd + * @{ + */ + +/** Set this to 1 to support CGI (old style). + * + * This old style CGI support works by registering an array of URLs and + * associated CGI handler functions (@ref http_set_cgi_handlers). + * This list is scanned just before fs_open is called from request handling. + * The handler can return a new URL that is used internally by the httpd to + * load the returned page (passed to fs_open). + * + * Use this CGI type e.g. to execute specific actions and return a page that + * does not depend on the CGI parameters. + */ +#if !defined LWIP_HTTPD_CGI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI 0 +#endif + +/** Set this to 1 to support CGI (new style). + * + * This new style CGI support works by calling a global function + * (@ref tCGIHandler) for all URLs that are found. fs_open is called first + * and the URL can not be written by the CGI handler. Instead, this handler gets + * passed the http file state, an object where it can store information derived + * from the CGI URL or parameters. This file state is later passed to SSI, so + * the SSI code can return data depending on CGI input. + * + * Use this CGI handler if you want CGI information passed on to SSI. + */ +#if !defined LWIP_HTTPD_CGI_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI_SSI 0 +#endif + +/** Set this to 1 to support SSI (Server-Side-Includes) + * + * In contrast to other http servers, this only calls a preregistered callback + * function (@see http_set_ssi_handler) for each tag (in the format of + * ) encountered in SSI-enabled pages. + * SSI-enabled pages must have one of the predefined SSI-enabled file extensions. + * All files with one of these extensions are parsed when sent. + * + * A downside of the current SSI implementation is that persistent connections + * don't work, as the file length is not known in advance (and httpd currently + * relies on the Content-Length header for persistent connections). + * + * To save memory, the maximum tag length is limited (@see LWIP_HTTPD_MAX_TAG_NAME_LEN). + * To save memory, the maximum insertion string length is limited (@see + * LWIP_HTTPD_MAX_TAG_INSERT_LEN). If this is not enought, @ref LWIP_HTTPD_SSI_MULTIPART + * can be used. + */ +#if !defined LWIP_HTTPD_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI 0 +#endif + +/** Set this to 1 to implement an SSI tag handler callback that gets a const char* + * to the tag (instead of an index into a pre-registered array of known tags) + * If this is 0, the SSI handler callback function is only called pre-registered tags. + */ +#if !defined LWIP_HTTPD_SSI_RAW || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_RAW 0 +#endif + +/** Set this to 0 to prevent parsing the file extension at runtime to decide + * if a file should be scanned for SSI tags or not. + * Default is 1 (file extensions are checked using the g_pcSSIExtensions array) + * Set to 2 to override this runtime test function. + * + * This is enabled by default, but if you only use a newer version of makefsdata + * supporting the "-ssi" option, this info is already present in + */ +#if !defined LWIP_HTTPD_SSI_BY_FILE_EXTENSION || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_BY_FILE_EXTENSION 1 +#endif + +/** Set this to 1 to support HTTP POST */ +#if !defined LWIP_HTTPD_SUPPORT_POST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_POST 0 +#endif + +/* The maximum number of parameters that the CGI handler can be sent. */ +#if !defined LWIP_HTTPD_MAX_CGI_PARAMETERS || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 +#endif + +/** LWIP_HTTPD_SSI_MULTIPART==1: SSI handler function is called with 2 more + * arguments indicating a counter for insert string that are too long to be + * inserted at once: the SSI handler function must then set 'next_tag_part' + * which will be passed back to it in the next call. */ +#if !defined LWIP_HTTPD_SSI_MULTIPART || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_MULTIPART 0 +#endif + +/* The maximum length of the string comprising the SSI tag name + * ATTENTION: tags longer than this are ignored, not truncated! + */ +#if !defined LWIP_HTTPD_MAX_TAG_NAME_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 +#endif + +/* The maximum length of string that can be returned to replace any given tag + * If this buffer is not long enough, use LWIP_HTTPD_SSI_MULTIPART. + */ +#if !defined LWIP_HTTPD_MAX_TAG_INSERT_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 +#endif + +#if !defined LWIP_HTTPD_POST_MANUAL_WND || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MANUAL_WND 0 +#endif + +/** This string is passed in the HTTP header as "Server: " */ +#if !defined HTTPD_SERVER_AGENT || defined __DOXYGEN__ +#define HTTPD_SERVER_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)" +#endif + +/** Set this to 1 if you want to include code that creates HTTP headers + * at runtime. Default is off: HTTP headers are then created statically + * by the makefsdata tool. Static headers mean smaller code size, but + * the (readonly) fsdata will grow a bit as every file includes the HTTP + * header. */ +#if !defined LWIP_HTTPD_DYNAMIC_HEADERS || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_HEADERS 0 +#endif + +#if !defined HTTPD_DEBUG || defined __DOXYGEN__ +#define HTTPD_DEBUG LWIP_DBG_OFF +#endif + +/** Set this to 1 to use a memp pool for allocating + * struct http_state instead of the heap. + * If enabled, you'll need to define MEMP_NUM_PARALLEL_HTTPD_CONNS + * (and MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS for SSI) to set the size of + * the pool(s). + */ +#if !defined HTTPD_USE_MEM_POOL || defined __DOXYGEN__ +#define HTTPD_USE_MEM_POOL 0 +#endif + +/** The server port for HTTPD to use */ +#if !defined HTTPD_SERVER_PORT || defined __DOXYGEN__ +#define HTTPD_SERVER_PORT LWIP_IANA_PORT_HTTP +#endif + +/** The https server port for HTTPD to use */ +#if !defined HTTPD_SERVER_PORT_HTTPS || defined __DOXYGEN__ +#define HTTPD_SERVER_PORT_HTTPS LWIP_IANA_PORT_HTTPS +#endif + +/** Enable https support? */ +#if !defined HTTPD_ENABLE_HTTPS || defined __DOXYGEN__ +#define HTTPD_ENABLE_HTTPS 0 +#endif + +/** Maximum retries before the connection is aborted/closed. + * - number of times pcb->poll is called -> default is 4*500ms = 2s; + * - reset when pcb->sent is called + */ +#if !defined HTTPD_MAX_RETRIES || defined __DOXYGEN__ +#define HTTPD_MAX_RETRIES 4 +#endif + +/** The poll delay is X*500ms */ +#if !defined HTTPD_POLL_INTERVAL || defined __DOXYGEN__ +#define HTTPD_POLL_INTERVAL 4 +#endif + +/** Priority for tcp pcbs created by HTTPD (very low by default). + * Lower priorities get killed first when running out of memory. + */ +#if !defined HTTPD_TCP_PRIO || defined __DOXYGEN__ +#define HTTPD_TCP_PRIO TCP_PRIO_MIN +#endif + +/** Set this to 1 to enable timing each file sent */ +#if !defined LWIP_HTTPD_TIMING || defined __DOXYGEN__ +#define LWIP_HTTPD_TIMING 0 +#endif +/** Set this to 1 to enable timing each file sent */ +#if !defined HTTPD_DEBUG_TIMING || defined __DOXYGEN__ +#define HTTPD_DEBUG_TIMING LWIP_DBG_OFF +#endif + +/** Set this to one to show error pages when parsing a request fails instead + of simply closing the connection. */ +#if !defined LWIP_HTTPD_SUPPORT_EXTSTATUS || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_EXTSTATUS 0 +#endif + +/** Set this to 0 to drop support for HTTP/0.9 clients (to save some bytes) */ +#if !defined LWIP_HTTPD_SUPPORT_V09 || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_V09 1 +#endif + +/** Set this to 1 to enable HTTP/1.1 persistent connections. + * ATTENTION: If the generated file system includes HTTP headers, these must + * include the "Connection: keep-alive" header (pass argument "-11" to makefsdata). + */ +#if !defined LWIP_HTTPD_SUPPORT_11_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_11_KEEPALIVE 0 +#endif + +/** Set this to 1 to support HTTP request coming in in multiple packets/pbufs */ +#if !defined LWIP_HTTPD_SUPPORT_REQUESTLIST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_REQUESTLIST 1 +#endif + +#if LWIP_HTTPD_SUPPORT_REQUESTLIST +/** Number of rx pbufs to enqueue to parse an incoming request (up to the first + newline) */ +#if !defined LWIP_HTTPD_REQ_QUEUELEN || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_QUEUELEN 5 +#endif + +/** Number of (TCP payload-) bytes (in pbufs) to enqueue to parse and incoming + request (up to the first double-newline) */ +#if !defined LWIP_HTTPD_REQ_BUFSIZE || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH +#endif + +/** Defines the maximum length of a HTTP request line (up to the first CRLF, + copied from pbuf into this a global buffer when pbuf- or packet-queues + are received - otherwise the input pbuf is used directly) */ +#if !defined LWIP_HTTPD_MAX_REQ_LENGTH || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQ_LENGTH LWIP_MIN(1023, (LWIP_HTTPD_REQ_QUEUELEN * PBUF_POOL_BUFSIZE)) +#endif +#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ + +/** This is the size of a static buffer used when URIs end with '/'. + * In this buffer, the directory requested is concatenated with all the + * configured default file names. + * Set to 0 to disable checking default filenames on non-root directories. + */ +#if !defined LWIP_HTTPD_MAX_REQUEST_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 63 +#endif + +/** Maximum length of the filename to send as response to a POST request, + * filled in by the application when a POST is finished. + */ +#if !defined LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63 +#endif + +/** Set this to 0 to not send the SSI tag (default is on, so the tag will + * be sent in the HTML page */ +#if !defined LWIP_HTTPD_SSI_INCLUDE_TAG || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_INCLUDE_TAG 1 +#endif + +/** Set this to 1 to call tcp_abort when tcp_close fails with memory error. + * This can be used to prevent consuming all memory in situations where the + * HTTP server has low priority compared to other communication. */ +#if !defined LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR || defined __DOXYGEN__ +#define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0 +#endif + +/** Set this to 1 to kill the oldest connection when running out of + * memory for 'struct http_state' or 'struct http_ssi_state'. + * ATTENTION: This puts all connections on a linked list, so may be kind of slow. + */ +#if !defined LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED || defined __DOXYGEN__ +#define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 +#endif + +/** Set this to 1 to send URIs without extension without headers + * (who uses this at all??) */ +#if !defined LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI || defined __DOXYGEN__ +#define LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI 0 +#endif + +/** Default: Tags are sent from struct http_state and are therefore volatile */ +#if !defined HTTP_IS_TAG_VOLATILE || defined __DOXYGEN__ +#define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY +#endif + +/* By default, the httpd is limited to send 2*pcb->mss to keep resource usage low + when http is not an important protocol in the device. */ +#if !defined HTTPD_LIMIT_SENDING_TO_2MSS || defined __DOXYGEN__ +#define HTTPD_LIMIT_SENDING_TO_2MSS 1 +#endif + +/* Define this to a function that returns the maximum amount of data to enqueue. + The function have this signature: u16_t fn(struct altcp_pcb* pcb); + The best place to define this is the hooks file (@see LWIP_HOOK_FILENAME) */ +#if !defined HTTPD_MAX_WRITE_LEN || defined __DOXYGEN__ +#if HTTPD_LIMIT_SENDING_TO_2MSS +#define HTTPD_MAX_WRITE_LEN(pcb) ((u16_t)(2 * altcp_mss(pcb))) +#endif +#endif + +/*------------------- FS OPTIONS -------------------*/ + +/** Set this to 1 and provide the functions: + * - "int fs_open_custom(struct fs_file *file, const char *name)" + * Called first for every opened file to allow opening files + * that are not included in fsdata(_custom).c + * - "void fs_close_custom(struct fs_file *file)" + * Called to free resources allocated by fs_open_custom(). + */ +#if !defined LWIP_HTTPD_CUSTOM_FILES || defined __DOXYGEN__ +#define LWIP_HTTPD_CUSTOM_FILES 0 +#endif + +/** Set this to 1 to support fs_read() to dynamically read file data. + * Without this (default=off), only one-block files are supported, + * and the contents must be ready after fs_open(). + */ +#if !defined LWIP_HTTPD_DYNAMIC_FILE_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_FILE_READ 0 +#endif + +/** Set this to 1 to include an application state argument per file + * that is opened. This allows to keep a state per connection/file. + */ +#if !defined LWIP_HTTPD_FILE_STATE || defined __DOXYGEN__ +#define LWIP_HTTPD_FILE_STATE 0 +#endif + +/** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for + * predefined (MSS-sized) chunks of the files to prevent having to calculate + * the checksums at runtime. */ +#if !defined HTTPD_PRECALCULATED_CHECKSUM || defined __DOXYGEN__ +#define HTTPD_PRECALCULATED_CHECKSUM 0 +#endif + +/** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations + * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). + */ +#if !defined LWIP_HTTPD_FS_ASYNC_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_FS_ASYNC_READ 0 +#endif + +/** Filename (including path) to use as FS data file */ +#if !defined HTTPD_FSDATA_FILE || defined __DOXYGEN__ +/* HTTPD_USE_CUSTOM_FSDATA: Compatibility with deprecated lwIP option */ +#if defined(HTTPD_USE_CUSTOM_FSDATA) && (HTTPD_USE_CUSTOM_FSDATA != 0) +#define HTTPD_FSDATA_FILE "fsdata_custom.c" +#else +#define HTTPD_FSDATA_FILE "fsdata.c" +#endif +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_HTTPD_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/lwiperf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/lwiperf.h new file mode 100644 index 0000000..cc86e7f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/lwiperf.h @@ -0,0 +1,100 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_LWIPERF_H +#define LWIP_HDR_APPS_LWIPERF_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIPERF_TCP_PORT_DEFAULT 5001 + +/** lwIPerf test results */ +enum lwiperf_report_type +{ + /** The server side test is done */ + LWIPERF_TCP_DONE_SERVER, + /** The client side test is done */ + LWIPERF_TCP_DONE_CLIENT, + /** Local error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL, + /** Data check error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, + /** Transmit error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_TXERROR, + /** Remote side aborted the test */ + LWIPERF_TCP_ABORTED_REMOTE +}; + +/** Control */ +enum lwiperf_client_type +{ + /** Unidirectional tx only test */ + LWIPERF_CLIENT, + /** Do a bidirectional test simultaneously */ + LWIPERF_DUAL, + /** Do a bidirectional test individually */ + LWIPERF_TRADEOFF +}; + +/** Prototype of a report function that is called when a session is finished. + This report function can show the test results. + @param report_type contains the test result */ +typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, + const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, + u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); + +void* lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port, + enum lwiperf_client_type type, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr, + lwiperf_report_fn report_fn, void* report_arg); + +void lwiperf_abort(void* lwiperf_session); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns.h new file mode 100644 index 0000000..20d7ee2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns.h @@ -0,0 +1,105 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_H +#define LWIP_HDR_APPS_MDNS_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MDNS_RESPONDER + +enum mdns_sd_proto { + DNSSD_PROTO_UDP = 0, + DNSSD_PROTO_TCP = 1 +}; + +#define MDNS_PROBING_CONFLICT 0 +#define MDNS_PROBING_SUCCESSFUL 1 + +#define MDNS_LABEL_MAXLEN 63 + +struct mdns_host; +struct mdns_service; + +/** Callback function to add text to a reply, called when generating the reply */ +typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata); + +/** Callback function to let application know the result of probing network for name + * uniqueness, called with result MDNS_PROBING_SUCCESSFUL if no other node claimed + * use for the name for the netif or a service and is safe to use, or MDNS_PROBING_CONFLICT + * if another node is already using it and mdns is disabled on this interface */ +typedef void (*mdns_name_result_cb_t)(struct netif* netif, u8_t result); + +void mdns_resp_init(void); + +void mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb); + +err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); +err_t mdns_resp_remove_netif(struct netif *netif); +err_t mdns_resp_rename_netif(struct netif *netif, const char *hostname); + +s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); +err_t mdns_resp_del_service(struct netif *netif, s8_t slot); +err_t mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name); + +err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len); + +void mdns_resp_restart(struct netif *netif); +void mdns_resp_announce(struct netif *netif); + +/** + * @ingroup mdns + * Announce IP settings have changed on netif. + * Call this in your callback registered by netif_set_status_callback(). + * No need to call this function when LWIP_NETIF_EXT_STATUS_CALLBACK==1, + * this handled automatically for you. + * @param netif The network interface where settings have changed. + */ +#define mdns_resp_netif_settings_changed(netif) mdns_resp_announce(netif) + +#endif /* LWIP_MDNS_RESPONDER */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MDNS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_opts.h new file mode 100644 index 0000000..45f2c50 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_opts.h @@ -0,0 +1,81 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_OPTS_H +#define LWIP_HDR_APPS_MDNS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup mdns_opts Options + * @ingroup mdns + * @{ + */ + +/** + * LWIP_MDNS_RESPONDER==1: Turn on multicast DNS module. UDP must be available for MDNS + * transport. IGMP is needed for IPv4 multicast. + */ +#ifndef LWIP_MDNS_RESPONDER +#define LWIP_MDNS_RESPONDER 0 +#endif /* LWIP_MDNS_RESPONDER */ + +/** The maximum number of services per netif */ +#ifndef MDNS_MAX_SERVICES +#define MDNS_MAX_SERVICES 1 +#endif + +/** MDNS_RESP_USENETIF_EXTCALLBACK==1: register an ext_callback on the netif + * to automatically restart probing/announcing on status or address change. + */ +#ifndef MDNS_RESP_USENETIF_EXTCALLBACK +#define MDNS_RESP_USENETIF_EXTCALLBACK LWIP_NETIF_EXT_STATUS_CALLBACK +#endif + +/** + * MDNS_DEBUG: Enable debugging for multicast DNS. + */ +#ifndef MDNS_DEBUG +#define MDNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_MDNS_OPTS_H */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_priv.h new file mode 100644 index 0000000..9635b5b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mdns_priv.h @@ -0,0 +1,74 @@ +/** + * @file + * MDNS responder private definitions + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ +#ifndef LWIP_HDR_MDNS_PRIV_H +#define LWIP_HDR_MDNS_PRIV_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MDNS_RESPONDER + +/* Domain struct and methods - visible for unit tests */ + +#define MDNS_DOMAIN_MAXLEN 256 +#define MDNS_READNAME_ERROR 0xFFFF + +struct mdns_domain { + /* Encoded domain name */ + u8_t name[MDNS_DOMAIN_MAXLEN]; + /* Total length of domain name, including zero */ + u16_t length; + /* Set if compression of this domain is not allowed */ + u8_t skip_compression; +}; + +err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); +u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); +int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); +u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); + +#endif /* LWIP_MDNS_RESPONDER */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MDNS_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt.h new file mode 100644 index 0000000..c2bb228 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt.h @@ -0,0 +1,205 @@ +/** + * @file + * MQTT client + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H +#define LWIP_HDR_APPS_MQTT_CLIENT_H + +#include "lwip/apps/mqtt_opts.h" +#include "lwip/err.h" +#include "lwip/ip_addr.h" +#include "lwip/prot/iana.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mqtt_client_s mqtt_client_t; + +#if LWIP_ALTCP && LWIP_ALTCP_TLS +struct altcp_tls_config; +#endif + +/** @ingroup mqtt + * Default MQTT port (non-TLS) */ +#define MQTT_PORT LWIP_IANA_PORT_MQTT +/** @ingroup mqtt + * Default MQTT TLS port */ +#define MQTT_TLS_PORT LWIP_IANA_PORT_SECURE_MQTT + +/*---------------------------------------------------------------------------------------------- */ +/* Connection with server */ + +/** + * @ingroup mqtt + * Client information and connection parameters */ +struct mqtt_connect_client_info_t { + /** Client identifier, must be set by caller */ + const char *client_id; + /** User name, set to NULL if not used */ + const char* client_user; + /** Password, set to NULL if not used */ + const char* client_pass; + /** keep alive time in seconds, 0 to disable keep alive functionality*/ + u16_t keep_alive; + /** will topic, set to NULL if will is not to be used, + will_msg, will_qos and will retain are then ignored */ + const char* will_topic; + /** will_msg, see will_topic */ + const char* will_msg; + /** will_qos, see will_topic */ + u8_t will_qos; + /** will_retain, see will_topic */ + u8_t will_retain; +#if LWIP_ALTCP && LWIP_ALTCP_TLS + /** TLS configuration for secure connections */ + struct altcp_tls_config *tls_config; +#endif +}; + +/** + * @ingroup mqtt + * Connection status codes */ +typedef enum +{ + /** Accepted */ + MQTT_CONNECT_ACCEPTED = 0, + /** Refused protocol version */ + MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1, + /** Refused identifier */ + MQTT_CONNECT_REFUSED_IDENTIFIER = 2, + /** Refused server */ + MQTT_CONNECT_REFUSED_SERVER = 3, + /** Refused user credentials */ + MQTT_CONNECT_REFUSED_USERNAME_PASS = 4, + /** Refused not authorized */ + MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5, + /** Disconnected */ + MQTT_CONNECT_DISCONNECTED = 256, + /** Timeout */ + MQTT_CONNECT_TIMEOUT = 257 +} mqtt_connection_status_t; + +/** + * @ingroup mqtt + * Function prototype for mqtt connection status callback. Called when + * client has connected to the server after initiating a mqtt connection attempt by + * calling mqtt_client_connect() or when connection is closed by server or an error + * + * @param client MQTT client itself + * @param arg Additional argument to pass to the callback function + * @param status Connect result code or disconnection notification @see mqtt_connection_status_t + * + */ +typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status); + + +/** + * @ingroup mqtt + * Data callback flags */ +enum { + /** Flag set when last fragment of data arrives in data callback */ + MQTT_DATA_FLAG_LAST = 1 +}; + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish data callback function. Called when data + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param data User data, pointed object, data may not be referenced after callback return, + NULL is passed when all publish data are delivered + * @param len Length of publish data fragment + * @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message + * + */ +typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); + + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish function. Called when an incoming publish + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param topic Zero terminated Topic text string, topic may not be referenced after callback return + * @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked + */ +typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); + + +/** + * @ingroup mqtt + * Function prototype for mqtt request callback. Called when a subscribe, unsubscribe + * or publish request has completed + * @param arg Pointer to user data supplied when invoking request + * @param err ERR_OK on success + * ERR_TIMEOUT if no response was received within timeout, + * ERR_ABRT if (un)subscribe was denied + */ +typedef void (*mqtt_request_cb_t)(void *arg, err_t err); + + +err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg, + const struct mqtt_connect_client_info_t *client_info); + +void mqtt_disconnect(mqtt_client_t *client); + +mqtt_client_t *mqtt_client_new(void); +void mqtt_client_free(mqtt_client_t* client); + +u8_t mqtt_client_is_connected(mqtt_client_t *client); + +void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, + mqtt_incoming_data_cb_t data_cb, void *arg); + +err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub); + +/** @ingroup mqtt + *Subscribe to topic */ +#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) +/** @ingroup mqtt + * Unsubscribe to topic */ +#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0) + +err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain, + mqtt_request_cb_t cb, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_opts.h new file mode 100644 index 0000000..4226d21 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_opts.h @@ -0,0 +1,103 @@ +/** + * @file + * MQTT client options + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_OPTS_H +#define LWIP_HDR_APPS_MQTT_OPTS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mqtt_opts Options + * @ingroup mqtt + * @{ + */ + +/** + * Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads + */ +#ifndef MQTT_OUTPUT_RINGBUF_SIZE +#define MQTT_OUTPUT_RINGBUF_SIZE 256 +#endif + +/** + * Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8 + * If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8 + */ +#ifndef MQTT_VAR_HEADER_BUFFER_LEN +#define MQTT_VAR_HEADER_BUFFER_LEN 128 +#endif + +/** + * Maximum number of pending subscribe, unsubscribe and publish requests to server . + */ +#ifndef MQTT_REQ_MAX_IN_FLIGHT +#define MQTT_REQ_MAX_IN_FLIGHT 4 +#endif + +/** + * Seconds between each cyclic timer call. + */ +#ifndef MQTT_CYCLIC_TIMER_INTERVAL +#define MQTT_CYCLIC_TIMER_INTERVAL 5 +#endif + +/** + * Publish, subscribe and unsubscribe request timeout in seconds. + */ +#ifndef MQTT_REQ_TIMEOUT +#define MQTT_REQ_TIMEOUT 30 +#endif + +/** + * Seconds for MQTT connect response timeout after sending connect request + */ +#ifndef MQTT_CONNECT_TIMOUT +#define MQTT_CONNECT_TIMOUT 100 +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_priv.h new file mode 100644 index 0000000..b775913 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/mqtt_priv.h @@ -0,0 +1,104 @@ +/** + * @file + * MQTT client (private interface) + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_PRIV_H +#define LWIP_HDR_APPS_MQTT_PRIV_H + +#include "lwip/apps/mqtt.h" +#include "lwip/altcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Pending request item, binds application callback to pending server requests */ +struct mqtt_request_t +{ + /** Next item in list, NULL means this is the last in chain, + next pointing at itself means request is unallocated */ + struct mqtt_request_t *next; + /** Callback to upper layer */ + mqtt_request_cb_t cb; + void *arg; + /** MQTT packet identifier */ + u16_t pkt_id; + /** Expire time relative to element before this */ + u16_t timeout_diff; +}; + +/** Ring buffer */ +struct mqtt_ringbuf_t { + u16_t put; + u16_t get; + u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; +}; + +/** MQTT client */ +struct mqtt_client_s +{ + /** Timers and timeouts */ + u16_t cyclic_tick; + u16_t keep_alive; + u16_t server_watchdog; + /** Packet identifier generator*/ + u16_t pkt_id_seq; + /** Packet identifier of pending incoming publish */ + u16_t inpub_pkt_id; + /** Connection state */ + u8_t conn_state; + struct altcp_pcb *conn; + /** Connection callback */ + void *connect_arg; + mqtt_connection_cb_t connect_cb; + /** Pending requests to server */ + struct mqtt_request_t *pend_req_queue; + struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT]; + void *inpub_arg; + /** Incoming data callback */ + mqtt_incoming_data_cb_t data_cb; + mqtt_incoming_publish_cb_t pub_cb; + /** Input */ + u32_t msg_idx; + u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN]; + /** Output ring-buffer */ + struct mqtt_ringbuf_t output; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns.h new file mode 100644 index 0000000..a326d33 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns.h @@ -0,0 +1,51 @@ +/** + * @file + * NETBIOS name service responder + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_H +#define LWIP_HDR_APPS_NETBIOS_H + +#include "lwip/apps/netbiosns_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void netbiosns_init(void); +#ifndef NETBIOS_LWIP_NAME +void netbiosns_set_name(const char* hostname); +#endif +void netbiosns_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_NETBIOS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns_opts.h new file mode 100644 index 0000000..1f51ab0 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/netbiosns_opts.h @@ -0,0 +1,66 @@ +/** + * @file + * NETBIOS name service responder options + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_OPTS_H +#define LWIP_HDR_APPS_NETBIOS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup netbiosns_opts Options + * @ingroup netbiosns + * @{ + */ + +/** NetBIOS name of lwip device + * This must be uppercase until NETBIOS_STRCMP() is defined to a string + * comparision function that is case insensitive. + * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): + * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") + * + * If this is not defined, netbiosns_set_name() can be called at runtime to change the name. + */ +#ifdef __DOXYGEN__ +#define NETBIOS_LWIP_NAME "NETBIOSLWIPDEV" +#endif + +/** Respond to NetBIOS name queries + * Default is disabled + */ +#if !defined LWIP_NETBIOS_RESPOND_NAME_QUERY || defined __DOXYGEN__ +#define LWIP_NETBIOS_RESPOND_NAME_QUERY 0 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_NETBIOS_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp.h new file mode 100644 index 0000000..fb4a4a7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp.h @@ -0,0 +1,128 @@ +#ifndef LWIP_HDR_APPS_SMTP_H +#define LWIP_HDR_APPS_SMTP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/apps/smtp_opts.h" +#include "lwip/err.h" +#include "lwip/prot/iana.h" + +/** The default TCP port used for SMTP */ +#define SMTP_DEFAULT_PORT LWIP_IANA_PORT_SMTP +/** The default TCP port used for SMTPS */ +#define SMTPS_DEFAULT_PORT LWIP_IANA_PORT_SMTPS + +/** Email successfully sent */ +#define SMTP_RESULT_OK 0 +/** Unknown error */ +#define SMTP_RESULT_ERR_UNKNOWN 1 +/** Connection to server failed */ +#define SMTP_RESULT_ERR_CONNECT 2 +/** Failed to resolve server hostname */ +#define SMTP_RESULT_ERR_HOSTNAME 3 +/** Connection unexpectedly closed by remote server */ +#define SMTP_RESULT_ERR_CLOSED 4 +/** Connection timed out (server didn't respond in time) */ +#define SMTP_RESULT_ERR_TIMEOUT 5 +/** Server responded with an unknown response code */ +#define SMTP_RESULT_ERR_SVR_RESP 6 +/** Out of resources locally */ +#define SMTP_RESULT_ERR_MEM 7 + +/** Prototype of an smtp callback function + * + * @param arg argument specified when initiating the email + * @param smtp_result result of the mail transfer (see defines SMTP_RESULT_*) + * @param srv_err if aborted by the server, this contains the error code received + * @param err an error returned by internal lwip functions, can help to specify + * the source of the error but must not necessarily be != ERR_OK + */ +typedef void (*smtp_result_fn)(void *arg, u8_t smtp_result, u16_t srv_err, err_t err); + +/** This structure is used as argument for smtp_send_mail_int(), + * which in turn can be used with tcpip_callback() to send mail + * from interrupt context, e.g. like this: + * struct smtp_send_request *req; (to be filled) + * tcpip_try_callback(smtp_send_mail_int, (void*)req); + * + * For member description, see parameter description of smtp_send_mail(). + * When using with tcpip_callback, this structure has to stay allocated + * (e.g. using mem_malloc/mem_free) until its 'callback_fn' is called. + */ +struct smtp_send_request { + const char *from; + const char* to; + const char* subject; + const char* body; + smtp_result_fn callback_fn; + void* callback_arg; + /** If this is != 0, data is *not* copied into an extra buffer + * but used from the pointers supplied in this struct. + * This means less memory usage, but data must stay untouched until + * the callback function is called. */ + u8_t static_data; +}; + + +#if SMTP_BODYDH + +#ifndef SMTP_BODYDH_BUFFER_SIZE +#define SMTP_BODYDH_BUFFER_SIZE 256 +#endif /* SMTP_BODYDH_BUFFER_SIZE */ + +struct smtp_bodydh { + u16_t state; + u16_t length; /* Length of content in buffer */ + char buffer[SMTP_BODYDH_BUFFER_SIZE]; /* buffer for generated content */ +#ifdef SMTP_BODYDH_USER_SIZE + u8_t user[SMTP_BODYDH_USER_SIZE]; +#endif /* SMTP_BODYDH_USER_SIZE */ +}; + +enum bdh_retvals_e { + BDH_DONE = 0, + BDH_WORKING +}; + +/** Prototype of an smtp body callback function + * It receives a struct smtp_bodydh, and a buffer to write data, + * must return BDH_WORKING to be called again and BDH_DONE when + * it has finished processing. This one tries to fill one TCP buffer with + * data, your function will be repeatedly called until that happens; so if you + * know you'll be taking too long to serve your request, pause once in a while + * by writing length=0 to avoid hogging system resources + * + * @param arg argument specified when initiating the email + * @param smtp_bodydh state handling + buffer structure + */ +typedef int (*smtp_bodycback_fn)(void *arg, struct smtp_bodydh *bodydh); + +err_t smtp_send_mail_bodycback(const char *from, const char* to, const char* subject, + smtp_bodycback_fn bodycback_fn, smtp_result_fn callback_fn, void* callback_arg); + +#endif /* SMTP_BODYDH */ + + +err_t smtp_set_server_addr(const char* server); +void smtp_set_server_port(u16_t port); +#if LWIP_ALTCP && LWIP_ALTCP_TLS +struct altcp_tls_config; +void smtp_set_tls_config(struct altcp_tls_config *tls_config); +#endif +err_t smtp_set_auth(const char* username, const char* pass); +err_t smtp_send_mail(const char *from, const char* to, const char* subject, const char* body, + smtp_result_fn callback_fn, void* callback_arg); +err_t smtp_send_mail_static(const char *from, const char* to, const char* subject, const char* body, + smtp_result_fn callback_fn, void* callback_arg); +void smtp_send_mail_int(void *arg); +#ifdef LWIP_DEBUG +const char* smtp_result_str(u8_t smtp_result); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SMTP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp_opts.h new file mode 100644 index 0000000..bc743f6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/smtp_opts.h @@ -0,0 +1,81 @@ +#ifndef LWIP_HDR_APPS_SMTP_OPTS_H +#define LWIP_HDR_APPS_SMTP_OPTS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup smtp_opts Options + * @ingroup smtp + * + * @{ + */ + +/** Set this to 1 to enable data handler callback on BODY */ +#ifndef SMTP_BODYDH +#define SMTP_BODYDH 0 +#endif + +/** SMTP_DEBUG: Enable debugging for SNTP. */ +#ifndef SMTP_DEBUG +#define SMTP_DEBUG LWIP_DBG_OFF +#endif + +/** Maximum length reserved for server name including terminating 0 byte */ +#ifndef SMTP_MAX_SERVERNAME_LEN +#define SMTP_MAX_SERVERNAME_LEN 256 +#endif + +/** Maximum length reserved for username */ +#ifndef SMTP_MAX_USERNAME_LEN +#define SMTP_MAX_USERNAME_LEN 32 +#endif + +/** Maximum length reserved for password */ +#ifndef SMTP_MAX_PASS_LEN +#define SMTP_MAX_PASS_LEN 32 +#endif + +/** Set this to 0 if you know the authentication data will not change + * during the smtp session, which saves some heap space. */ +#ifndef SMTP_COPY_AUTHDATA +#define SMTP_COPY_AUTHDATA 1 +#endif + +/** Set this to 0 to save some code space if you know for sure that all data + * passed to this module conforms to the requirements in the SMTP RFC. + * WARNING: use this with care! + */ +#ifndef SMTP_CHECK_DATA +#define SMTP_CHECK_DATA 1 +#endif + +/** Set this to 1 to enable AUTH PLAIN support */ +#ifndef SMTP_SUPPORT_AUTH_PLAIN +#define SMTP_SUPPORT_AUTH_PLAIN 1 +#endif + +/** Set this to 1 to enable AUTH LOGIN support */ +#ifndef SMTP_SUPPORT_AUTH_LOGIN +#define SMTP_SUPPORT_AUTH_LOGIN 1 +#endif + +/* Memory allocation/deallocation can be overridden... */ +#ifndef SMTP_STATE_MALLOC +#define SMTP_STATE_MALLOC(size) mem_malloc(size) +#define SMTP_STATE_FREE(ptr) mem_free(ptr) +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* SMTP_OPTS_H */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp.h new file mode 100644 index 0000000..a3f8eb1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp.h @@ -0,0 +1,135 @@ +/** + * @file + * SNMP server main API - start and basic configuration + */ + +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * Martin Hentschel + * + */ +#ifndef LWIP_HDR_APPS_SNMP_H +#define LWIP_HDR_APPS_SNMP_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/apps/snmp_core.h" + +/** SNMP variable binding descriptor (publically needed for traps) */ +struct snmp_varbind +{ + /** pointer to next varbind, NULL for last in list */ + struct snmp_varbind *next; + /** pointer to previous varbind, NULL for first in list */ + struct snmp_varbind *prev; + + /** object identifier */ + struct snmp_obj_id oid; + + /** value ASN1 type */ + u8_t type; + /** object value length */ + u16_t value_len; + /** object value */ + void *value; +}; + +/** + * @ingroup snmp_core + * Agent setup, start listening to port 161. + */ +void snmp_init(void); +void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs); + +void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid); +const struct snmp_obj_id* snmp_get_device_enterprise_oid(void); + +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst); + +/** Generic trap: cold start */ +#define SNMP_GENTRAP_COLDSTART 0 +/** Generic trap: warm start */ +#define SNMP_GENTRAP_WARMSTART 1 +/** Generic trap: link down */ +#define SNMP_GENTRAP_LINKDOWN 2 +/** Generic trap: link up */ +#define SNMP_GENTRAP_LINKUP 3 +/** Generic trap: authentication failure */ +#define SNMP_GENTRAP_AUTH_FAILURE 4 +/** Generic trap: EGP neighbor lost */ +#define SNMP_GENTRAP_EGP_NEIGHBOR_LOSS 5 +/** Generic trap: enterprise specific */ +#define SNMP_GENTRAP_ENTERPRISE_SPECIFIC 6 + +err_t snmp_send_trap_generic(s32_t generic_trap); +err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds); +err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); + +#define SNMP_AUTH_TRAPS_DISABLED 0 +#define SNMP_AUTH_TRAPS_ENABLED 1 +void snmp_set_auth_traps_enabled(u8_t enable); +u8_t snmp_get_auth_traps_enabled(void); + +u8_t snmp_v1_enabled(void); +u8_t snmp_v2c_enabled(void); +u8_t snmp_v3_enabled(void); +void snmp_v1_enable(u8_t enable); +void snmp_v2c_enable(u8_t enable); +void snmp_v3_enable(u8_t enable); + +const char * snmp_get_community(void); +const char * snmp_get_community_write(void); +const char * snmp_get_community_trap(void); +void snmp_set_community(const char * const community); +void snmp_set_community_write(const char * const community); +void snmp_set_community_trap(const char * const community); + +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +typedef void (*snmp_write_callback_fct)(const u32_t* oid, u8_t oid_len, void* callback_arg); +void snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_core.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_core.h new file mode 100644 index 0000000..6021c72 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_core.h @@ -0,0 +1,377 @@ +/** + * @file + * SNMP core API for implementing MIBs + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Christiaan Simons + * Martin Hentschel + */ + +#ifndef LWIP_HDR_APPS_SNMP_CORE_H +#define LWIP_HDR_APPS_SNMP_CORE_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* basic ASN1 defines */ +#define SNMP_ASN1_CLASS_UNIVERSAL 0x00 +#define SNMP_ASN1_CLASS_APPLICATION 0x40 +#define SNMP_ASN1_CLASS_CONTEXT 0x80 +#define SNMP_ASN1_CLASS_PRIVATE 0xC0 + +#define SNMP_ASN1_CONTENTTYPE_PRIMITIVE 0x00 +#define SNMP_ASN1_CONTENTTYPE_CONSTRUCTED 0x20 + +/* universal tags (from ASN.1 spec.) */ +#define SNMP_ASN1_UNIVERSAL_END_OF_CONTENT 0 +#define SNMP_ASN1_UNIVERSAL_INTEGER 2 +#define SNMP_ASN1_UNIVERSAL_OCTET_STRING 4 +#define SNMP_ASN1_UNIVERSAL_NULL 5 +#define SNMP_ASN1_UNIVERSAL_OBJECT_ID 6 +#define SNMP_ASN1_UNIVERSAL_SEQUENCE_OF 16 + +/* application specific (SNMP) tags (from SNMPv2-SMI) */ +#define SNMP_ASN1_APPLICATION_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */ +#define SNMP_ASN1_APPLICATION_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */ +#define SNMP_ASN1_APPLICATION_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */ + +/* context specific (SNMP) tags (from RFC 1905) */ +#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE 1 + +/* full ASN1 type defines */ +#define SNMP_ASN1_TYPE_END_OF_CONTENT (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_END_OF_CONTENT) +#define SNMP_ASN1_TYPE_INTEGER (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_INTEGER) +#define SNMP_ASN1_TYPE_OCTET_STRING (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OCTET_STRING) +#define SNMP_ASN1_TYPE_NULL (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_NULL) +#define SNMP_ASN1_TYPE_OBJECT_ID (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OBJECT_ID) +#define SNMP_ASN1_TYPE_SEQUENCE (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_UNIVERSAL_SEQUENCE_OF) +#define SNMP_ASN1_TYPE_IPADDR (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_IPADDR) +#define SNMP_ASN1_TYPE_IPADDRESS SNMP_ASN1_TYPE_IPADDR +#define SNMP_ASN1_TYPE_COUNTER (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER) +#define SNMP_ASN1_TYPE_COUNTER32 SNMP_ASN1_TYPE_COUNTER +#define SNMP_ASN1_TYPE_GAUGE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_GAUGE) +#define SNMP_ASN1_TYPE_GAUGE32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_UNSIGNED32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_TIMETICKS (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_TIMETICKS) +#define SNMP_ASN1_TYPE_OPAQUE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_OPAQUE) +#if LWIP_HAVE_INT64 +#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64) +#endif + +#define SNMP_VARBIND_EXCEPTION_OFFSET 0xF0 +#define SNMP_VARBIND_EXCEPTION_MASK 0x0F + +/** error codes predefined by SNMP prot. */ +typedef enum { + SNMP_ERR_NOERROR = 0, +/* +outdated v1 error codes. do not use anmore! +#define SNMP_ERR_NOSUCHNAME 2 use SNMP_ERR_NOSUCHINSTANCE instead +#define SNMP_ERR_BADVALUE 3 use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead +#define SNMP_ERR_READONLY 4 use SNMP_ERR_NOTWRITABLE instead +*/ + SNMP_ERR_GENERROR = 5, + SNMP_ERR_NOACCESS = 6, + SNMP_ERR_WRONGTYPE = 7, + SNMP_ERR_WRONGLENGTH = 8, + SNMP_ERR_WRONGENCODING = 9, + SNMP_ERR_WRONGVALUE = 10, + SNMP_ERR_NOCREATION = 11, + SNMP_ERR_INCONSISTENTVALUE = 12, + SNMP_ERR_RESOURCEUNAVAILABLE = 13, + SNMP_ERR_COMMITFAILED = 14, + SNMP_ERR_UNDOFAILED = 15, + SNMP_ERR_NOTWRITABLE = 17, + SNMP_ERR_INCONSISTENTNAME = 18, + + SNMP_ERR_NOSUCHINSTANCE = SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE +} snmp_err_t; + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + u32_t id[SNMP_MAX_OBJ_ID_LEN]; +}; + +struct snmp_obj_id_const_ref +{ + u8_t len; + const u32_t* id; +}; + +extern const struct snmp_obj_id_const_ref snmp_zero_dot_zero; /* administrative identifier from SNMPv2-SMI */ + +/** SNMP variant value, used as reference in struct snmp_node_instance and table implementation */ +union snmp_variant_value +{ + void* ptr; + const void* const_ptr; + u32_t u32; + s32_t s32; +#if LWIP_HAVE_INT64 + u64_t u64; +#endif +}; + + +/** +SNMP MIB node types + tree node is the only node the stack can process in order to walk the tree, + all other nodes are assumed to be leaf nodes. + This cannot be an enum because users may want to define their own node types. +*/ +#define SNMP_NODE_TREE 0x00 +/* predefined leaf node types */ +#define SNMP_NODE_SCALAR 0x01 +#define SNMP_NODE_SCALAR_ARRAY 0x02 +#define SNMP_NODE_TABLE 0x03 +#define SNMP_NODE_THREADSYNC 0x04 + +/** node "base class" layout, the mandatory fields for a node */ +struct snmp_node +{ + /** one out of SNMP_NODE_TREE or any leaf node type (like SNMP_NODE_SCALAR) */ + u8_t node_type; + /** the number assigned to this node which used as part of the full OID */ + u32_t oid; +}; + +/** SNMP node instance access types */ +typedef enum { + SNMP_NODE_INSTANCE_ACCESS_READ = 1, + SNMP_NODE_INSTANCE_ACCESS_WRITE = 2, + SNMP_NODE_INSTANCE_READ_ONLY = SNMP_NODE_INSTANCE_ACCESS_READ, + SNMP_NODE_INSTANCE_READ_WRITE = (SNMP_NODE_INSTANCE_ACCESS_READ | SNMP_NODE_INSTANCE_ACCESS_WRITE), + SNMP_NODE_INSTANCE_WRITE_ONLY = SNMP_NODE_INSTANCE_ACCESS_WRITE, + SNMP_NODE_INSTANCE_NOT_ACCESSIBLE = 0 +} snmp_access_t; + +struct snmp_node_instance; + +typedef s16_t (*node_instance_get_value_method)(struct snmp_node_instance*, void*); +typedef snmp_err_t (*node_instance_set_test_method)(struct snmp_node_instance*, u16_t, void*); +typedef snmp_err_t (*node_instance_set_value_method)(struct snmp_node_instance*, u16_t, void*); +typedef void (*node_instance_release_method)(struct snmp_node_instance*); + +#define SNMP_GET_VALUE_RAW_DATA 0x4000 /* do not use 0x8000 because return value of node_instance_get_value_method is signed16 and 0x8000 would be the signed bit */ + +/** SNMP node instance */ +struct snmp_node_instance +{ + /** prefilled with the node, get_instance() is called on; may be changed by user to any value to pass an arbitrary node between calls to get_instance() and get_value/test_value/set_value */ + const struct snmp_node* node; + /** prefilled with the instance id requested; for get_instance() this is the exact oid requested; for get_next_instance() this is the relative starting point, stack expects relative oid of next node here */ + struct snmp_obj_id instance_oid; + + /** ASN type for this object (see snmp_asn1.h for definitions) */ + u8_t asn1_type; + /** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */ + snmp_access_t access; + + /** returns object value for the given object identifier. Return values <0 to indicate an error */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; + /** called in any case when the instance is not required anymore by stack (useful for freeing memory allocated in get_instance/get_next_instance methods) */ + node_instance_release_method release_instance; + + /** reference to pass arbitrary value between calls to get_instance() and get_value/test_value/set_value */ + union snmp_variant_value reference; + /** see reference (if reference is a pointer, the length of underlying data may be stored here or anything else) */ + u32_t reference_len; +}; + + +/** SNMP tree node */ +struct snmp_tree_node +{ + /** inherited "base class" members */ + struct snmp_node node; + u16_t subnode_count; + const struct snmp_node* const *subnodes; +}; + +#define SNMP_CREATE_TREE_NODE(oid, subnodes) \ + {{ SNMP_NODE_TREE, (oid) }, \ + (u16_t)LWIP_ARRAYSIZE(subnodes), (subnodes) } + +#define SNMP_CREATE_EMPTY_TREE_NODE(oid) \ + {{ SNMP_NODE_TREE, (oid) }, \ + 0, NULL } + +/** SNMP leaf node */ +struct snmp_leaf_node +{ + /** inherited "base class" members */ + struct snmp_node node; + snmp_err_t (*get_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + snmp_err_t (*get_next_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +}; + +/** represents a single mib with its base oid and root node */ +struct snmp_mib +{ + const u32_t *base_oid; + u8_t base_oid_len; + const struct snmp_node *root_node; +}; + +#define SNMP_MIB_CREATE(oid_list, root_node) { (oid_list), (u8_t)LWIP_ARRAYSIZE(oid_list), root_node } + +/** OID range structure */ +struct snmp_oid_range +{ + u32_t min; + u32_t max; +}; + +/** checks if incoming OID length and values are in allowed ranges */ +u8_t snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len); + +typedef enum { + SNMP_NEXT_OID_STATUS_SUCCESS, + SNMP_NEXT_OID_STATUS_NO_MATCH, + SNMP_NEXT_OID_STATUS_BUF_TO_SMALL +} snmp_next_oid_status_t; + +/** state for next_oid_init / next_oid_check functions */ +struct snmp_next_oid_state +{ + const u32_t* start_oid; + u8_t start_oid_len; + + u32_t* next_oid; + u8_t next_oid_len; + u8_t next_oid_max_len; + + snmp_next_oid_status_t status; + void* reference; +}; + +void snmp_next_oid_init(struct snmp_next_oid_state *state, + const u32_t *start_oid, u8_t start_oid_len, + u32_t *next_oid_buf, u8_t next_oid_max_len); +u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len); +u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len, void* reference); + +void snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +void snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +u8_t snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +s8_t snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); + +#if LWIP_IPV4 +u8_t snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip); +void snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +u8_t snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip); +void snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 || LWIP_IPV6 +u8_t snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid); +u8_t snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid); + +u8_t snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip); +u8_t snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port); +#endif /* LWIP_IPV4 || LWIP_IPV6 */ + +struct netif; +u8_t netif_to_num(const struct netif *netif); + +snmp_err_t snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value); /* generic function which can be used if test is always successful */ + +err_t snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value); +err_t snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value); +u8_t snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count); +u8_t snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value); + +struct snmp_statistics +{ + u32_t inpkts; + u32_t outpkts; + u32_t inbadversions; + u32_t inbadcommunitynames; + u32_t inbadcommunityuses; + u32_t inasnparseerrs; + u32_t intoobigs; + u32_t innosuchnames; + u32_t inbadvalues; + u32_t inreadonlys; + u32_t ingenerrs; + u32_t intotalreqvars; + u32_t intotalsetvars; + u32_t ingetrequests; + u32_t ingetnexts; + u32_t insetrequests; + u32_t ingetresponses; + u32_t intraps; + u32_t outtoobigs; + u32_t outnosuchnames; + u32_t outbadvalues; + u32_t outgenerrs; + u32_t outgetrequests; + u32_t outgetnexts; + u32_t outsetrequests; + u32_t outgetresponses; + u32_t outtraps; +#if LWIP_SNMP_V3 + u32_t unsupportedseclevels; + u32_t notintimewindows; + u32_t unknownusernames; + u32_t unknownengineids; + u32_t wrongdigests; + u32_t decryptionerrors; +#endif +}; + +extern struct snmp_statistics snmp_stats; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_CORE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_mib2.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_mib2.h new file mode 100644 index 0000000..2f4a689 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_mib2.h @@ -0,0 +1,78 @@ +/** + * @file + * SNMP MIB2 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_APPS_SNMP_MIB2_H +#define LWIP_HDR_APPS_SNMP_MIB2_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ +#if SNMP_LWIP_MIB2 + +#include "lwip/apps/snmp_core.h" + +extern const struct snmp_mib mib2; + +#if SNMP_USE_NETCONN +#include "lwip/apps/snmp_threadsync.h" +void snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg); +extern struct snmp_threadsync_instance snmp_mib2_lwip_locks; +#endif + +#ifndef SNMP_SYSSERVICES +#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) +#endif + +void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */ +void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen); + +#endif /* SNMP_LWIP_MIB2 */ +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_MIB2_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_opts.h new file mode 100644 index 0000000..c892d22 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_opts.h @@ -0,0 +1,297 @@ +/** + * @file + * SNMP server options list + */ + +/* + * Copyright (c) 2015 Dirk Ziegelmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_OPTS_H +#define LWIP_HDR_SNMP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup snmp_opts Options + * @ingroup snmp + * @{ + */ + +/** + * LWIP_SNMP==1: This enables the lwIP SNMP agent. UDP must be available + * for SNMP transport. + * If you want to use your own SNMP agent, leave this disabled. + * To integrate MIB2 of an external agent, you need to enable + * LWIP_MIB2_CALLBACKS and MIB2_STATS. This will give you the callbacks + * and statistics counters you need to get MIB2 working. + */ +#if !defined LWIP_SNMP || defined __DOXYGEN__ +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_USE_NETCONN: Use netconn API instead of raw API. + * Makes SNMP agent run in a worker thread, so blocking operations + * can be done in MIB calls. + */ +#if !defined SNMP_USE_NETCONN || defined __DOXYGEN__ +#define SNMP_USE_NETCONN 0 +#endif + +/** + * SNMP_USE_RAW: Use raw API. + * SNMP agent does not run in a worker thread, so blocking operations + * should not be done in MIB calls. + */ +#if !defined SNMP_USE_RAW || defined __DOXYGEN__ +#define SNMP_USE_RAW 1 +#endif + +#if SNMP_USE_NETCONN && SNMP_USE_RAW +#error SNMP stack can use only one of the APIs {raw, netconn} +#endif + +#if LWIP_SNMP && !SNMP_USE_NETCONN && !SNMP_USE_RAW +#error SNMP stack needs a receive API and UDP {raw, netconn} +#endif + +#if SNMP_USE_NETCONN +/** + * SNMP_STACK_SIZE: Stack size of SNMP netconn worker thread + */ +#if !defined SNMP_STACK_SIZE || defined __DOXYGEN__ +#define SNMP_STACK_SIZE DEFAULT_THREAD_STACKSIZE +#endif + +/** + * SNMP_THREAD_PRIO: SNMP netconn worker thread priority + */ +#if !defined SNMP_THREAD_PRIO || defined __DOXYGEN__ +#define SNMP_THREAD_PRIO DEFAULT_THREAD_PRIO +#endif +#endif /* SNMP_USE_NETCONN */ + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#if !defined SNMP_TRAP_DESTINATIONS || defined __DOXYGEN__ +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#if !defined SNMP_SAFE_REQUESTS || defined __DOXYGEN__ +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. + */ +#if !defined SNMP_MAX_OCTET_STRING_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum number of Sub ID's inside an object identifier. + * Indirectly this also limits the maximum depth of SNMP tree. + */ +#if !defined SNMP_MAX_OBJ_ID_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OBJ_ID_LEN 50 +#endif + +#if !defined SNMP_MAX_VALUE_SIZE || defined __DOXYGEN__ +/** + * The minimum size of a value. + */ +#define SNMP_MIN_VALUE_SIZE (2 * sizeof(u32_t*)) /* size required to store the basic types (8 bytes for counter64) */ +/** + * The maximum size of a value. + */ +#define SNMP_MAX_VALUE_SIZE LWIP_MAX(LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN), sizeof(u32_t)*(SNMP_MAX_OBJ_ID_LEN)), SNMP_MIN_VALUE_SIZE) +#endif + +/** + * The snmp read-access community. Used for write-access and traps, too + * unless SNMP_COMMUNITY_WRITE or SNMP_COMMUNITY_TRAP are enabled, respectively. + */ +#if !defined SNMP_COMMUNITY || defined __DOXYGEN__ +#define SNMP_COMMUNITY "public" +#endif + +/** + * The snmp write-access community. + * Set this community to "" in order to disallow any write access. + */ +#if !defined SNMP_COMMUNITY_WRITE || defined __DOXYGEN__ +#define SNMP_COMMUNITY_WRITE "private" +#endif + +/** + * The snmp community used for sending traps. + */ +#if !defined SNMP_COMMUNITY_TRAP || defined __DOXYGEN__ +#define SNMP_COMMUNITY_TRAP "public" +#endif + +/** + * The maximum length of community string. + * If community names shall be adjusted at runtime via snmp_set_community() calls, + * enter here the possible maximum length (+1 for terminating null character). + */ +#if !defined SNMP_MAX_COMMUNITY_STR_LEN || defined __DOXYGEN__ +#define SNMP_MAX_COMMUNITY_STR_LEN LWIP_MAX(LWIP_MAX(sizeof(SNMP_COMMUNITY), sizeof(SNMP_COMMUNITY_WRITE)), sizeof(SNMP_COMMUNITY_TRAP)) +#endif + +/** + * The OID identifiying the device. This may be the enterprise OID itself or any OID located below it in tree. + */ +#if !defined SNMP_DEVICE_ENTERPRISE_OID || defined __DOXYGEN__ +#define SNMP_LWIP_ENTERPRISE_OID 26381 +/** + * IANA assigned enterprise ID for lwIP is 26381 + * @see http://www.iana.org/assignments/enterprise-numbers + * + * @note this enterprise ID is assigned to the lwIP project, + * all object identifiers living under this ID are assigned + * by the lwIP maintainers! + * @note don't change this define, use snmp_set_device_enterprise_oid() + * + * If you need to create your own private MIB you'll need + * to apply for your own enterprise ID with IANA: + * http://www.iana.org/numbers.html + */ +#define SNMP_DEVICE_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, SNMP_LWIP_ENTERPRISE_OID} +/** + * Length of SNMP_DEVICE_ENTERPRISE_OID + */ +#define SNMP_DEVICE_ENTERPRISE_OID_LEN 7 +#endif + +/** + * SNMP_DEBUG: Enable debugging for SNMP messages. + */ +#if !defined SNMP_DEBUG || defined __DOXYGEN__ +#define SNMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#if !defined SNMP_MIB_DEBUG || defined __DOXYGEN__ +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * Indicates if the MIB2 implementation of LWIP SNMP stack is used. + */ +#if !defined SNMP_LWIP_MIB2 || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2 LWIP_SNMP +#endif + +/** + * Value return for sysDesc field of MIB2. + */ +#if !defined SNMP_LWIP_MIB2_SYSDESC || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSDESC "lwIP" +#endif + +/** + * Value return for sysName field of MIB2. + * To make sysName field settable, call snmp_mib2_set_sysname() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSNAME || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSNAME "FQDN-unk" +#endif + +/** + * Value return for sysContact field of MIB2. + * To make sysContact field settable, call snmp_mib2_set_syscontact() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSCONTACT || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSCONTACT "" +#endif + +/** + * Value return for sysLocation field of MIB2. + * To make sysLocation field settable, call snmp_mib2_set_syslocation() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSLOCATION || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSLOCATION "" +#endif + +/** + * This value is used to limit the repetitions processed in GetBulk requests (value == 0 means no limitation). + * This may be useful to limit the load for a single request. + * According to SNMP RFC 1905 it is allowed to not return all requested variables from a GetBulk request if system load would be too high. + * so the effect is that the client will do more requests to gather all data. + * For the stack this could be useful in case that SNMP processing is done in TCP/IP thread. In this situation a request with many + * repetitions could block the thread for a longer time. Setting limit here will keep the stack more responsive. + */ +#if !defined SNMP_LWIP_GETBULK_MAX_REPETITIONS || defined __DOXYGEN__ +#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0 +#endif + +/** + * @} + */ + +/* + ------------------------------------ + ---------- SNMPv3 options ---------- + ------------------------------------ +*/ + +/** + * LWIP_SNMP_V3==1: This enables EXPERIMENTAL SNMPv3 support. LWIP_SNMP must + * also be enabled. + * THIS IS UNDER DEVELOPMENT AND SHOULD NOT BE ENABLED IN PRODUCTS. + */ +#ifndef LWIP_SNMP_V3 +#define LWIP_SNMP_V3 0 +#endif + +#ifndef LWIP_SNMP_V3_MBEDTLS +#define LWIP_SNMP_V3_MBEDTLS LWIP_SNMP_V3 +#endif + +#ifndef LWIP_SNMP_V3_CRYPTO +#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3_MBEDTLS +#endif + +#ifndef LWIP_SNMP_CONFIGURE_VERSIONS +#define LWIP_SNMP_CONFIGURE_VERSIONS 0 +#endif + +#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_scalar.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_scalar.h new file mode 100644 index 0000000..40a060c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_scalar.h @@ -0,0 +1,113 @@ +/** + * @file + * SNMP server MIB API to implement scalar nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_SCALAR_H +#define LWIP_HDR_APPS_SNMP_SCALAR_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** basic scalar node */ +struct snmp_scalar_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u8_t asn1_type; + snmp_access_t access; + node_instance_get_value_method get_value; + node_instance_set_test_method set_test; + node_instance_set_value_method set_value; +}; + + +snmp_err_t snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_NODE(oid, access, asn1_type, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR, (oid) }, \ + snmp_scalar_get_instance, \ + snmp_scalar_get_next_instance }, \ + (asn1_type), (access), (get_value_method), (set_test_method), (set_value_method) } + +#define SNMP_SCALAR_CREATE_NODE_READONLY(oid, asn1_type, get_value_method) SNMP_SCALAR_CREATE_NODE(oid, SNMP_NODE_INSTANCE_READ_ONLY, asn1_type, get_value_method, NULL, NULL) + +/** scalar array node - a tree node which contains scalars only as children */ +struct snmp_scalar_array_node_def +{ + u32_t oid; + u8_t asn1_type; + snmp_access_t access; +}; + +typedef s16_t (*snmp_scalar_array_get_value_method)(const struct snmp_scalar_array_node_def*, void*); +typedef snmp_err_t (*snmp_scalar_array_set_test_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); +typedef snmp_err_t (*snmp_scalar_array_set_value_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); + +/** basic scalar array node */ +struct snmp_scalar_array_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t array_node_count; + const struct snmp_scalar_array_node_def* array_nodes; + snmp_scalar_array_get_value_method get_value; + snmp_scalar_array_set_test_method set_test; + snmp_scalar_array_set_value_method set_value; +}; + +snmp_err_t snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_ARRAY_NODE(oid, array_nodes, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR_ARRAY, (oid) }, \ + snmp_scalar_array_get_instance, \ + snmp_scalar_array_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(array_nodes), (array_nodes), (get_value_method), (set_test_method), (set_value_method) } + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_SCALAR_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_framework.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_framework.h new file mode 100644 index 0000000..47409cc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_framework.h @@ -0,0 +1,32 @@ +/* +Generated by LwipMibCompiler +*/ + +#ifndef LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H +#define LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H + +#include "lwip/apps/snmp_opts.h" +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "lwip/apps/snmp_core.h" + +extern const struct snmp_obj_id usmNoAuthProtocol; +extern const struct snmp_obj_id usmHMACMD5AuthProtocol; +extern const struct snmp_obj_id usmHMACSHAAuthProtocol; + +extern const struct snmp_obj_id usmNoPrivProtocol; +extern const struct snmp_obj_id usmDESPrivProtocol; +extern const struct snmp_obj_id usmAESPrivProtocol; + +extern const struct snmp_mib snmpframeworkmib; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LWIP_SNMP */ +#endif /* LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_usm.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_usm.h new file mode 100644 index 0000000..88cfcd8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_snmpv2_usm.h @@ -0,0 +1,24 @@ +/* +Generated by LwipMibCompiler +*/ + +#ifndef LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H +#define LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H + +#include "lwip/apps/snmp_opts.h" +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "lwip/apps/snmp_core.h" + +extern const struct snmp_mib snmpusmmib; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LWIP_SNMP */ +#endif /* LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_table.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_table.h new file mode 100644 index 0000000..4988b51 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_table.h @@ -0,0 +1,134 @@ +/** + * @file + * SNMP server MIB API to implement table nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_TABLE_H +#define LWIP_HDR_APPS_SNMP_TABLE_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** default (customizable) read/write table */ +struct snmp_table_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_access_t access; +}; + +/** table node */ +struct snmp_table_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_col_def* columns; + snmp_err_t (*get_cell_instance)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); + snmp_err_t (*get_next_cell_instance)(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); + /** returns object value for the given object identifier */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; +}; + +snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE(oid, columns, get_cell_instance_method, get_next_cell_instance_method, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_get_instance, \ + snmp_table_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), \ + (get_cell_instance_method), (get_next_cell_instance_method), \ + (get_value_method), (set_test_method), (set_value_method)} + +#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */ + + +/** simple read-only table */ +typedef enum { + SNMP_VARIANT_VALUE_TYPE_U32, + SNMP_VARIANT_VALUE_TYPE_S32, + SNMP_VARIANT_VALUE_TYPE_PTR, + SNMP_VARIANT_VALUE_TYPE_CONST_PTR +} snmp_table_column_data_type_t; + +struct snmp_table_simple_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_table_column_data_type_t data_type; /* depending of what union member is used to store the value*/ +}; + +/** simple read-only table node */ +struct snmp_table_simple_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_simple_col_def* columns; + snmp_err_t (*get_cell_value)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len); + snmp_err_t (*get_next_cell_instance_and_value)(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len); +}; + +snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE_SIMPLE(oid, columns, get_cell_value_method, get_next_cell_instance_and_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_simple_get_instance, \ + snmp_table_simple_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), (get_cell_value_method), (get_next_cell_instance_and_value_method) } + +s16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_TABLE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_threadsync.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_threadsync.h new file mode 100644 index 0000000..a25dbf2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmp_threadsync.h @@ -0,0 +1,114 @@ +/** + * @file + * SNMP server MIB API to implement thread synchronization + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_THREADSYNC_H +#define LWIP_HDR_APPS_SNMP_THREADSYNC_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_core.h" +#include "lwip/sys.h" + +typedef void (*snmp_threadsync_called_fn)(void* arg); +typedef void (*snmp_threadsync_synchronizer_fn)(snmp_threadsync_called_fn fn, void* arg); + + +/** Thread sync runtime data. For internal usage only. */ +struct threadsync_data +{ + union { + snmp_err_t err; + s16_t s16; + } retval; + union { + const u32_t *root_oid; + void *value; + } arg1; + union { + u8_t root_oid_len; + u16_t len; + } arg2; + const struct snmp_threadsync_node *threadsync_node; + struct snmp_node_instance proxy_instance; +}; + +/** Thread sync instance. Needed EXCATLY once for every thread to be synced into. */ +struct snmp_threadsync_instance +{ + sys_sem_t sem; + sys_mutex_t sem_usage_mutex; + snmp_threadsync_synchronizer_fn sync_fn; + struct threadsync_data data; +}; + +/** SNMP thread sync proxy leaf node */ +struct snmp_threadsync_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + + const struct snmp_leaf_node *target; + struct snmp_threadsync_instance *instance; +}; + +snmp_err_t snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +/** Create thread sync proxy node */ +#define SNMP_CREATE_THREAD_SYNC_NODE(oid, target_leaf_node, threadsync_instance) \ + {{{ SNMP_NODE_THREADSYNC, (oid) }, \ + snmp_threadsync_get_instance, \ + snmp_threadsync_get_next_instance }, \ + (target_leaf_node), \ + (threadsync_instance) } + +/** Create thread sync instance data */ +void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_THREADSYNC_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmpv3.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmpv3.h new file mode 100644 index 0000000..e0dda64 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/snmpv3.h @@ -0,0 +1,114 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_H +#define LWIP_HDR_APPS_SNMP_V3_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP && LWIP_SNMP_V3 + +typedef enum +{ + SNMP_V3_AUTH_ALGO_INVAL = 0, + SNMP_V3_AUTH_ALGO_MD5 = 1, + SNMP_V3_AUTH_ALGO_SHA = 2 +} snmpv3_auth_algo_t; + +typedef enum +{ + SNMP_V3_PRIV_ALGO_INVAL = 0, + SNMP_V3_PRIV_ALGO_DES = 1, + SNMP_V3_PRIV_ALGO_AES = 2 +} snmpv3_priv_algo_t; + +typedef enum +{ + SNMP_V3_USER_STORAGETYPE_OTHER = 1, + SNMP_V3_USER_STORAGETYPE_VOLATILE = 2, + SNMP_V3_USER_STORAGETYPE_NONVOLATILE = 3, + SNMP_V3_USER_STORAGETYPE_PERMANENT = 4, + SNMP_V3_USER_STORAGETYPE_READONLY = 5 +} snmpv3_user_storagetype_t; + +/* + * The following callback functions must be implemented by the application. + * There is a dummy implementation in snmpv3_dummy.c. + */ + +void snmpv3_get_engine_id(const char **id, u8_t *len); +err_t snmpv3_set_engine_id(const char* id, u8_t len); + +u32_t snmpv3_get_engine_boots(void); +void snmpv3_set_engine_boots(u32_t boots); + +u32_t snmpv3_get_engine_time(void); +void snmpv3_reset_engine_time(void); + +err_t snmpv3_get_user(const char* username, snmpv3_auth_algo_t *auth_algo, u8_t *auth_key, snmpv3_priv_algo_t *priv_algo, u8_t *priv_key); +u8_t snmpv3_get_amount_of_users(void); +err_t snmpv3_get_user_storagetype(const char *username, snmpv3_user_storagetype_t *storagetype); +err_t snmpv3_get_username(char *username, u8_t index); + +/* The following functions are provided by the SNMPv3 agent */ + +void snmpv3_engine_id_changed(void); +s32_t snmpv3_get_engine_time_internal(void); + +void snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + size_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 16-octet buffer */ + +void snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + size_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 20-octet buffer */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp.h new file mode 100644 index 0000000..c415253 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp.h @@ -0,0 +1,80 @@ +/** + * @file + * SNTP client API + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_H +#define LWIP_HDR_APPS_SNTP_H + +#include "lwip/apps/sntp_opts.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* SNTP operating modes: default is to poll using unicast. + The mode has to be set before calling sntp_init(). */ +#define SNTP_OPMODE_POLL 0 +#define SNTP_OPMODE_LISTENONLY 1 +void sntp_setoperatingmode(u8_t operating_mode); +u8_t sntp_getoperatingmode(void); + +void sntp_init(void); +void sntp_stop(void); +u8_t sntp_enabled(void); + +void sntp_setserver(u8_t idx, const ip_addr_t *addr); +const ip_addr_t* sntp_getserver(u8_t idx); + +#if SNTP_MONITOR_SERVER_REACHABILITY +u8_t sntp_getreachability(u8_t idx); +#endif /* SNTP_MONITOR_SERVER_REACHABILITY */ + +#if SNTP_SERVER_DNS +void sntp_setservername(u8_t idx, const char *server); +const char *sntp_getservername(u8_t idx); +#endif /* SNTP_SERVER_DNS */ + +#if SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6 +void sntp_servermode_dhcp(int set_servers_from_dhcp); +#else /* SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6 */ +#define sntp_servermode_dhcp(x) +#endif /* SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNTP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp_opts.h new file mode 100644 index 0000000..cb62771 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/sntp_opts.h @@ -0,0 +1,215 @@ +/** + * @file + * SNTP client options list + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_OPTS_H +#define LWIP_HDR_APPS_SNTP_OPTS_H + +#include "lwip/opt.h" +#include "lwip/prot/iana.h" + +/** + * @defgroup sntp_opts Options + * @ingroup sntp + * @{ + */ + +/** SNTP macro to change system time in seconds + * Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds + * instead of this one if you need the additional precision. Alternatively, + * define SNTP_SET_SYSTEM_TIME_NTP(sec, frac) in order to work with native + * NTP timestamps instead. + */ +#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec) +#endif + +/** The maximum number of SNTP servers that can be set */ +#if !defined SNTP_MAX_SERVERS || defined __DOXYGEN__ +#define SNTP_MAX_SERVERS LWIP_DHCP_MAX_NTP_SERVERS +#endif + +/** Set this to 1 to implement the callback function called by dhcp when + * NTP servers are received. */ +#if !defined SNTP_GET_SERVERS_FROM_DHCP || defined __DOXYGEN__ +#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV +#endif + +/** Set this to 1 to implement the callback function called by dhcpv6 when + * NTP servers are received. */ +#if !defined SNTP_GET_SERVERS_FROM_DHCPV6 || defined __DOXYGEN__ +#define SNTP_GET_SERVERS_FROM_DHCPV6 LWIP_DHCP6_GET_NTP_SRV +#endif + +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ +#define SNTP_SERVER_DNS 0 +#endif + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#if !defined SNTP_DEBUG || defined __DOXYGEN__ +#define SNTP_DEBUG LWIP_DBG_OFF +#endif + +/** SNTP server port */ +#if !defined SNTP_PORT || defined __DOXYGEN__ +#define SNTP_PORT LWIP_IANA_PORT_SNTP +#endif + +/** Sanity check: + * Define this to + * - 0 to turn off sanity checks (default; smaller code) + * - >= 1 to check address and port of the response packet to ensure the + * response comes from the server we sent the request to. + * - >= 2 to check returned Originate Timestamp against Transmit Timestamp + * sent to the server (to ensure response to older request). + * - >= 3 @todo: discard reply if any of the VN, Stratum, or Transmit Timestamp + * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). + * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each + * greater than or equal to 0 and less than infinity, where infinity is + * currently a cozy number like one second. This check avoids using a + * server whose synchronization source has expired for a very long time. + */ +#if !defined SNTP_CHECK_RESPONSE || defined __DOXYGEN__ +#define SNTP_CHECK_RESPONSE 0 +#endif + +/** Enable round-trip delay compensation. + * Compensate for the round-trip delay by calculating the clock offset from + * the originate, receive, transmit and destination timestamps, as per RFC. + * + * The calculation requires compiler support for 64-bit integers. Also, either + * SNTP_SET_SYSTEM_TIME_US or SNTP_SET_SYSTEM_TIME_NTP has to be implemented + * for setting the system clock with sub-second precision. Likewise, either + * SNTP_GET_SYSTEM_TIME or SNTP_GET_SYSTEM_TIME_NTP needs to be implemented + * with sub-second precision. + * + * Although not strictly required, it makes sense to combine this option with + * SNTP_CHECK_RESPONSE >= 2 for sanity-checking of the received timestamps. + * Also, in order for the round-trip calculation to work, the difference + * between the local clock and the NTP server clock must not be larger than + * about 34 years. If that limit is exceeded, the implementation will fall back + * to setting the clock without compensation. In order to ensure that the local + * clock is always within the permitted range for compensation, even at first + * try, it may be necessary to store at least the current year in non-volatile + * memory. + */ +#if !defined SNTP_COMP_ROUNDTRIP || defined __DOXYGEN__ +#define SNTP_COMP_ROUNDTRIP 0 +#endif + +/** According to the RFC, this shall be a random delay + * between 1 and 5 minutes (in milliseconds) to prevent load peaks. + * This can be defined to a random generation function, + * which must return the delay in milliseconds as u32_t. + * Turned off by default. + */ +#if !defined SNTP_STARTUP_DELAY || defined __DOXYGEN__ +#ifdef LWIP_RAND +#define SNTP_STARTUP_DELAY 1 +#else +#define SNTP_STARTUP_DELAY 0 +#endif +#endif + +/** If you want the startup delay to be a function, define this + * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. + */ +#if !defined SNTP_STARTUP_DELAY_FUNC || defined __DOXYGEN__ +#define SNTP_STARTUP_DELAY_FUNC (LWIP_RAND() % 5000) +#endif + +/** SNTP receive timeout - in milliseconds + * Also used as retry timeout - this shouldn't be too low. + * Default is 15 seconds. Must not be beolw 15 seconds by specification (i.e. 15000) + */ +#if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RECV_TIMEOUT 15000 +#endif + +/** SNTP update delay - in milliseconds + * Default is 1 hour. Must not be beolw 60 seconds by specification (i.e. 60000) + */ +#if !defined SNTP_UPDATE_DELAY || defined __DOXYGEN__ +#define SNTP_UPDATE_DELAY 3600000 +#endif + +/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 + * to send in request and compare in response. Also used for round-trip + * delay compensation if SNTP_COMP_ROUNDTRIP != 0. + * Alternatively, define SNTP_GET_SYSTEM_TIME_NTP(sec, frac) in order to + * work with native NTP timestamps instead. + */ +#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) +#endif + +/** Default retry timeout (in milliseconds) if the response + * received is invalid. + * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. + */ +#if !defined SNTP_RETRY_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT +#endif + +/** Maximum retry timeout (in milliseconds). */ +#if !defined SNTP_RETRY_TIMEOUT_MAX || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) +#endif + +/** Increase retry timeout with every retry sent + * Default is on to conform to RFC. + */ +#if !defined SNTP_RETRY_TIMEOUT_EXP || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_EXP 1 +#endif + +/** Keep a reachability shift register per server + * Default is on to conform to RFC. + */ +#if !defined SNTP_MONITOR_SERVER_REACHABILITY || defined __DOXYGEN__ +#define SNTP_MONITOR_SERVER_REACHABILITY 1 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_opts.h new file mode 100644 index 0000000..198f632 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_opts.h @@ -0,0 +1,106 @@ +/** + * + * @file tftp_opts.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) implementation options + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_OPTS_H +#define LWIP_HDR_APPS_TFTP_OPTS_H + +#include "lwip/opt.h" +#include "lwip/prot/iana.h" + +/** + * @defgroup tftp_opts Options + * @ingroup tftp + * @{ + */ + +/** + * Enable TFTP debug messages + */ +#if !defined TFTP_DEBUG || defined __DOXYGEN__ +#define TFTP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TFTP server port + */ +#if !defined TFTP_PORT || defined __DOXYGEN__ +#define TFTP_PORT LWIP_IANA_PORT_TFTP +#endif + +/** + * TFTP timeout + */ +#if !defined TFTP_TIMEOUT_MSECS || defined __DOXYGEN__ +#define TFTP_TIMEOUT_MSECS 10000 +#endif + +/** + * Max. number of retries when a file is read from server + */ +#if !defined TFTP_MAX_RETRIES || defined __DOXYGEN__ +#define TFTP_MAX_RETRIES 5 +#endif + +/** + * TFTP timer cyclic interval + */ +#if !defined TFTP_TIMER_MSECS || defined __DOXYGEN__ +#define TFTP_TIMER_MSECS (TFTP_TIMEOUT_MSECS / 10) +#endif + +/** + * Max. length of TFTP filename + */ +#if !defined TFTP_MAX_FILENAME_LEN || defined __DOXYGEN__ +#define TFTP_MAX_FILENAME_LEN 20 +#endif + +/** + * Max. length of TFTP mode + */ +#if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__ +#define TFTP_MAX_MODE_LEN 7 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_TFTP_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_server.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_server.h new file mode 100644 index 0000000..0a7fbee --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/apps/tftp_server.h @@ -0,0 +1,95 @@ +/** + * + * @file tftp_server.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_SERVER_H +#define LWIP_HDR_APPS_TFTP_SERVER_H + +#include "lwip/apps/tftp_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup tftp + * TFTP context containing callback functions for TFTP transfers + */ +struct tftp_context { + /** + * Open file for read/write. + * @param fname Filename + * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) + * @param write Flag indicating read (0) or write (!= 0) access + * @returns File handle supplied to other functions + */ + void* (*open)(const char* fname, const char* mode, u8_t write); + /** + * Close file handle + * @param handle File handle returned by open() + */ + void (*close)(void* handle); + /** + * Read from file + * @param handle File handle returned by open() + * @param buf Target buffer to copy read data to + * @param bytes Number of bytes to copy to buf + * @returns >= 0: Success; < 0: Error + */ + int (*read)(void* handle, void* buf, int bytes); + /** + * Write to file + * @param handle File handle returned by open() + * @param pbuf PBUF adjusted such that payload pointer points + * to the beginning of write data. In other words, + * TFTP headers are stripped off. + * @returns >= 0: Success; < 0: Error + */ + int (*write)(void* handle, struct pbuf* p); +}; + +err_t tftp_init(const struct tftp_context* ctx); +void tftp_cleanup(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_TFTP_SERVER_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/arch.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/arch.h new file mode 100644 index 0000000..253ce0d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/arch.h @@ -0,0 +1,393 @@ +/** + * @file + * Support for different processor and compiler architectures + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ARCH_H +#define LWIP_HDR_ARCH_H + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** + * @defgroup compiler_abstraction Compiler/platform abstraction + * @ingroup sys_layer + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/cc.h! + * If the compiler does not provide memset() this file must include a + * definition of it, or include a file which defines it. + * These options cannot be \#defined in lwipopts.h since they are not options + * of lwIP itself, but options of the lwIP port to your system. + * @{ + */ + +/** Define the byte order of the system. + * Needed for conversion of network data to host byte order. + * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN + */ +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +/** Define random number generator function of your system */ +#ifdef __DOXYGEN__ +#define LWIP_RAND() ((u32_t)rand()) +#endif + +/** Platform specific diagnostic output.\n + * Note the default implementation pulls in printf, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_DIAG +#define LWIP_PLATFORM_DIAG(x) do {bsp_printf x;} while(0) +#include +#include +#endif + +/** Platform specific assertion handling.\n + * Note the default implementation pulls in printf, fflush and abort, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_ASSERT +#define LWIP_PLATFORM_ASSERT(x) do {bsp_printf("Assertion \"%s\" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) +#include +#include +#endif + +/** Define this to 1 in arch/cc.h of your port if you do not want to + * include stddef.h header to get size_t. You need to typedef size_t + * by yourself in this case. + */ +#ifndef LWIP_NO_STDDEF_H +#define LWIP_NO_STDDEF_H 0 +#endif + +#if !LWIP_NO_STDDEF_H +#include /* for size_t */ +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the stdint.h header. You need to typedef the generic types listed in + * lwip/arch.h yourself in this case (u8_t, u16_t...). + */ +#ifndef LWIP_NO_STDINT_H +#define LWIP_NO_STDINT_H 0 +#endif + +/* Define generic types used in lwIP */ +#if !LWIP_NO_STDINT_H +#include +/* stdint.h is C99 which should also provide support for 64-bit integers */ +#if !defined(LWIP_HAVE_INT64) && defined(UINT64_MAX) +#define LWIP_HAVE_INT64 1 +#endif +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +#if LWIP_HAVE_INT64 +typedef uint64_t u64_t; +typedef int64_t s64_t; +#endif +typedef uintptr_t mem_ptr_t; +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the inttypes.h header. You need to define the format strings listed in + * lwip/arch.h yourself in this case (X8_F, U16_F...). + */ +#ifndef LWIP_NO_INTTYPES_H +#define LWIP_NO_INTTYPES_H 0 +#endif + +/* Define (sn)printf formatters for these lwIP types */ +#if !LWIP_NO_INTTYPES_H +#include +#ifndef X8_F +#define X8_F "02" PRIx8 +#endif +#ifndef U16_F +#define U16_F PRIu16 +#endif +#ifndef S16_F +#define S16_F PRId16 +#endif +#ifndef X16_F +#define X16_F PRIx16 +#endif +#ifndef U32_F +#define U32_F PRIu32 +#endif +#ifndef S32_F +#define S32_F PRId32 +#endif +#ifndef X32_F +#define X32_F PRIx32 +#endif +#ifndef SZT_F +#define SZT_F PRIuPTR +#endif +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the limits.h header. You need to define the type limits yourself in this case + * (e.g. INT_MAX, SSIZE_MAX). + */ +#ifndef LWIP_NO_LIMITS_H +#define LWIP_NO_LIMITS_H 0 +#endif + +/* Include limits.h? */ +#if !LWIP_NO_LIMITS_H +#include +#endif + +/* Do we need to define ssize_t? This is a compatibility hack: + * Unfortunately, this type seems to be unavailable on some systems (even if + * sys/types or unistd.h are available). + * Being like that, we define it to 'int' if SSIZE_MAX is not defined. + */ +#ifdef SSIZE_MAX +/* If SSIZE_MAX is defined, unistd.h should provide the type as well */ +#ifndef LWIP_NO_UNISTD_H +#define LWIP_NO_UNISTD_H 0 +#endif +#if !LWIP_NO_UNISTD_H +#include +#endif +#else /* SSIZE_MAX */ +typedef int ssize_t; +#define SSIZE_MAX INT_MAX +#endif /* SSIZE_MAX */ + +/* some maximum values needed in lwip code */ +#define LWIP_UINT32_MAX 0xffffffff + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the ctype.h header. If ctype.h is available, a few character functions + * are mapped to the appropriate functions (lwip_islower, lwip_isdigit...), if + * not, a private implementation is provided. + */ +#ifndef LWIP_NO_CTYPE_H +#define LWIP_NO_CTYPE_H 0 +#endif + +#if LWIP_NO_CTYPE_H +#define lwip_in_range(c, lo, up) ((u8_t)(c) >= (lo) && (u8_t)(c) <= (up)) +#define lwip_isdigit(c) lwip_in_range((c), '0', '9') +#define lwip_isxdigit(c) (lwip_isdigit(c) || lwip_in_range((c), 'a', 'f') || lwip_in_range((c), 'A', 'F')) +#define lwip_islower(c) lwip_in_range((c), 'a', 'z') +#define lwip_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v') +#define lwip_isupper(c) lwip_in_range((c), 'A', 'Z') +#define lwip_tolower(c) (lwip_isupper(c) ? (c) - 'A' + 'a' : c) +#define lwip_toupper(c) (lwip_islower(c) ? (c) - 'a' + 'A' : c) +#else +#include +#define lwip_isdigit(c) isdigit((unsigned char)(c)) +#define lwip_isxdigit(c) isxdigit((unsigned char)(c)) +#define lwip_islower(c) islower((unsigned char)(c)) +#define lwip_isspace(c) isspace((unsigned char)(c)) +#define lwip_isupper(c) isupper((unsigned char)(c)) +#define lwip_tolower(c) tolower((unsigned char)(c)) +#define lwip_toupper(c) toupper((unsigned char)(c)) +#endif + +/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ +#ifndef LWIP_CONST_CAST +#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) +#endif + +/** Get rid of alignment cast warnings (GCC -Wcast-align) */ +#ifndef LWIP_ALIGNMENT_CAST +#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, + * e.g. "conversion from 'u8_t' to 'void *' of greater size" + */ +#ifndef LWIP_PTR_NUMERIC_CAST +#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Avoid warnings/errors related to implicitly casting away packed attributes by doing a explicit cast */ +#ifndef LWIP_PACKED_CAST +#define LWIP_PACKED_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Allocates a memory buffer of specified size that is of sufficient size to align + * its start address using LWIP_MEM_ALIGN. + * You can declare your own version here e.g. to enforce alignment without adding + * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement + * requirements.\n + * e.g. if you use gcc and need 32 bit alignment:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n + * or more portable:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] + */ +#ifndef LWIP_DECLARE_MEMORY_ALIGNED +#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] +#endif + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** Packed structs support. + * Placed BEFORE declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +/** Packed structs support. + * Placed AFTER declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +/** Packed structs support. + * Placed between end of declaration of a packed struct and trailing semicolon.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_STRUCT +#if defined(__GNUC__) || defined(__clang__) +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#else +#define PACK_STRUCT_STRUCT +#endif +#endif /* PACK_STRUCT_STRUCT */ + +/** Packed structs support. + * Wraps u32_t and u16_t members.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + +/** Packed structs support. + * Wraps u8_t members, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_8 +#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_8 */ + +/** Packed structs support. + * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_S +#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_S */ + +/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.\n + * The file included BEFORE the struct is "arch/bpstruct.h".\n + * The file included AFTER the struct is "arch/epstruct.h".\n + * This can be used to implement struct packing on MS Visual C compilers, see + * the Win32 port in the lwIP contrib repository for reference. + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifdef __DOXYGEN__ +#define PACK_STRUCT_USE_INCLUDES +#endif + +/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + +/** LWIP_PROVIDE_ERRNO==1: Let lwIP provide ERRNO values and the 'errno' variable. + * If this is disabled, cc.h must either define 'errno', include , + * define LWIP_ERRNO_STDINCLUDE to get included or + * define LWIP_ERRNO_INCLUDE to or equivalent. + */ +#if defined __DOXYGEN__ +#define LWIP_PROVIDE_ERRNO +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ARCH_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/autoip.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/autoip.h new file mode 100644 index 0000000..1d85bcc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/autoip.h @@ -0,0 +1,99 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_AUTOIP_H +#define LWIP_HDR_AUTOIP_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +/* #include "lwip/udp.h" */ +#include "lwip/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/** AutoIP state information per netif */ +struct autoip +{ + /** the currently selected, probed, announced or used LL IP-Address */ + ip4_addr_t llipaddr; + /** current AutoIP state machine state */ + u8_t state; + /** sent number of probes or announces, dependent on state */ + u8_t sent_num; + /** ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u16_t ttw; + /** ticks until a conflict can be solved by defending */ + u8_t lastconflict; + /** total number of probed/used Link Local IP-Addresses */ + u8_t tried_llipaddr; +}; + + +void autoip_set_struct(struct netif *netif, struct autoip *autoip); +/** Remove a struct autoip previously set to the netif using autoip_set_struct() */ +#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) +err_t autoip_start(struct netif *netif); +err_t autoip_stop(struct netif *netif); +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); +void autoip_tmr(void); +void autoip_network_changed(struct netif *netif); +u8_t autoip_supplied_address(const struct netif *netif); + +/* for lwIP internal use by ip4.c */ +u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); + +#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_AUTOIP */ + +#endif /* LWIP_HDR_AUTOIP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/debug.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/debug.h new file mode 100644 index 0000000..579fd24 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/debug.h @@ -0,0 +1,159 @@ +/** + * @file + * Debug messages infrastructure + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_DEBUG_H +#define LWIP_HDR_DEBUG_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +/** + * @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values + * @ingroup lwip_opts_debugmsg + * @{ + */ + +/** @name Debug level (LWIP_DBG_MIN_LEVEL) + * @{ + */ +/** Debug level: ALL messages*/ +#define LWIP_DBG_LEVEL_ALL 0x00 +/** Debug level: Warnings. bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_WARNING 0x01 +/** Debug level: Serious. memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 +/** Debug level: Severe */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +/** + * @} + */ + +#define LWIP_DBG_MASK_LEVEL 0x03 +/* compatibility define only */ +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL + +/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U +/** + * @} + */ + +/** @name Debug message types (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup lwip_assertions Assertion handling + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_NOASSERT: Disable LWIP_ASSERT checks: + * To disable assertions define LWIP_NOASSERT in arch/cc.h. + */ +#ifdef __DOXYGEN__ +#define LWIP_NOASSERT +#undef LWIP_NOASSERT +#endif +/** + * @} + */ + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \ + LWIP_PLATFORM_ASSERT(message); }} while(0) +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +#ifndef LWIP_ERROR +#ifdef LWIP_DEBUG +#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_DIAG((message)) +#else +#define LWIP_PLATFORM_ERROR(message) +#endif + +/* if "expression" isn't true, then print "message" and execute "handler" expression */ +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ERROR(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +/** Enable debug message printing, but only if debug message type is enabled + * AND is of correct type AND is at least LWIP_DBG_LEVEL. + */ +#ifdef __DOXYGEN__ +#define LWIP_DEBUG +#undef LWIP_DEBUG +#endif + +#ifdef LWIP_DEBUG +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* LWIP_HDR_DEBUG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/def.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/def.h new file mode 100644 index 0000000..dfb266d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/def.h @@ -0,0 +1,152 @@ +/** + * @file + * various utility macros + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/** + * @defgroup perf Performance measurement + * @ingroup sys_layer + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/perf.h! + * Measurement calls made throughout lwip, these can be defined to nothing. + * - PERF_START: start measuring something. + * - PERF_STOP(x): stop measuring something, and record the result. + */ + +#ifndef LWIP_HDR_DEF_H +#define LWIP_HDR_DEF_H + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" +#if LWIP_PERF +#include "arch/perf.h" +#else /* LWIP_PERF */ +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ +#endif /* LWIP_PERF */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +/* Get the number of entries in an array ('x' must NOT be a pointer!) */ +#define LWIP_ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) + +/** Create u32_t value from bytes */ +#define LWIP_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff)) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) ((u16_t)(x)) +#define lwip_ntohs(x) ((u16_t)(x)) +#define lwip_htonl(x) ((u32_t)(x)) +#define lwip_ntohl(x) ((u32_t)(x)) +#define PP_HTONS(x) ((u16_t)(x)) +#define PP_NTOHS(x) ((u16_t)(x)) +#define PP_HTONL(x) ((u32_t)(x)) +#define PP_NTOHL(x) ((u32_t)(x)) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#ifndef lwip_htons +u16_t lwip_htons(u16_t x); +#endif +#define lwip_ntohs(x) lwip_htons(x) + +#ifndef lwip_htonl +u32_t lwip_htonl(u32_t x); +#endif +#define lwip_ntohl(x) lwip_htonl(x) + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((u16_t)((((x) & (u16_t)0x00ffU) << 8) | (((x) & (u16_t)0xff00U) >> 8))) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & (u32_t)0x000000ffUL) << 24) | \ + (((x) & (u32_t)0x0000ff00UL) << 8) | \ + (((x) & (u32_t)0x00ff0000UL) >> 8) | \ + (((x) & (u32_t)0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +/* Provide usual function names as macros for users, but this can be turned off */ +#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif + +/* Functions that are not available as standard implementations. + * In cc.h, you can #define these to implementations available on + * your platform to save some code bytes if you use these functions + * in your application, too. + */ + +#ifndef lwip_itoa +/* This can be #defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform */ +void lwip_itoa(char* result, size_t bufsize, int number); +#endif +#ifndef lwip_strnicmp +/* This can be #defined to strnicmp() or strncasecmp() depending on your platform */ +int lwip_strnicmp(const char* str1, const char* str2, size_t len); +#endif +#ifndef lwip_stricmp +/* This can be #defined to stricmp() or strcasecmp() depending on your platform */ +int lwip_stricmp(const char* str1, const char* str2); +#endif +#ifndef lwip_strnstr +/* This can be #defined to strnstr() depending on your platform */ +char* lwip_strnstr(const char* buffer, const char* token, size_t n); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_DEF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp.h new file mode 100644 index 0000000..c78aa0b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp.h @@ -0,0 +1,139 @@ +/** + * @file + * DHCP client API + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_DHCP_H +#define LWIP_HDR_DHCP_H + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_BOOT_FILE_LEN 128U + +/* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ +typedef enum { + DHCP_AUTOIP_COOP_STATE_OFF = 0, + DHCP_AUTOIP_COOP_STATE_ON = 1 +} dhcp_autoip_coop_state_enum_t; + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** track PCB allocation state */ + u8_t pcb_allocated; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ + u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ + u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ + u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ + ip4_addr_t offered_ip_addr; + ip4_addr_t offered_sn_mask; + ip4_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 87.5 of lease period) */ +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_t offered_si_addr; + char boot_file_name[DHCP_BOOT_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL) +void dhcp_cleanup(struct netif *netif); +err_t dhcp_start(struct netif *netif); +err_t dhcp_renew(struct netif *netif); +err_t dhcp_release(struct netif *netif); +void dhcp_stop(struct netif *netif); +void dhcp_release_and_stop(struct netif *netif); +void dhcp_inform(struct netif *netif); +void dhcp_network_changed(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); +#endif +u8_t dhcp_supplied_address(const struct netif *netif); +/* to be called every minute */ +void dhcp_coarse_tmr(void); +/* to be called every half second */ +void dhcp_fine_tmr(void); + +#if LWIP_DHCP_GET_NTP_SRV +/** This function must exist, in other to add offered NTP servers to + * the NTP (or SNTP) engine. + * See LWIP_DHCP_MAX_NTP_SERVERS */ +extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*LWIP_HDR_DHCP_H*/ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp6.h new file mode 100644 index 0000000..5cc4a01 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dhcp6.h @@ -0,0 +1,104 @@ +/** + * @file + * + * DHCPv6 client: IPv6 address autoconfiguration as per + * RFC 3315 (stateful DHCPv6) and + * RFC 3736 (stateless DHCPv6). + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + */ + +#ifndef LWIP_HDR_IP6_DHCP6_H +#define LWIP_HDR_IP6_DHCP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in milliseconds) of the application calling dhcp6_tmr() */ +#define DHCP6_TIMER_MSECS 500 + +struct dhcp6 +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** track PCB allocation state */ + u8_t pcb_allocated; + /** current DHCPv6 state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; + /** if request config is triggered while another action is active, this keeps track of it */ + u8_t request_config_pending; + /** #ticks with period DHCP6_TIMER_MSECS for request timeout */ + u16_t request_timeout; +#if LWIP_IPV6_DHCP6_STATEFUL + /* @todo: add more members here to keep track of stateful DHCPv6 data, like lease times */ +#endif /* LWIP_IPV6_DHCP6_STATEFUL */ +}; + +void dhcp6_set_struct(struct netif *netif, struct dhcp6 *dhcp6); +/** Remove a struct dhcp6 previously set to the netif using dhcp6_set_struct() */ +#define dhcp6_remove_struct(netif) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL) +void dhcp6_cleanup(struct netif *netif); + +err_t dhcp6_enable_stateful(struct netif *netif); +err_t dhcp6_enable_stateless(struct netif *netif); +void dhcp6_disable(struct netif *netif); + +void dhcp6_tmr(void); + +void dhcp6_nd6_ra_trigger(struct netif *netif, u8_t managed_addr_config, u8_t other_config); + +#if LWIP_DHCP6_GET_NTP_SRV +/** This function must exist, in other to add offered NTP servers to + * the NTP (or SNTP) engine. + * See LWIP_DHCP6_MAX_NTP_SERVERS */ +extern void dhcp6_set_ntp_servers(u8_t num_ntp_servers, const ip_addr_t* ntp_server_addrs); +#endif /* LWIP_DHCP6_GET_NTP_SRV */ + +#define netif_dhcp6_data(netif) ((struct dhcp6*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_DHCP6 */ + +#endif /* LWIP_HDR_IP6_DHCP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dns.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dns.h new file mode 100644 index 0000000..0913415 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/dns.h @@ -0,0 +1,131 @@ +/** + * @file + * DNS API + */ + +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 LWIP_HDR_DNS_H +#define LWIP_HDR_DNS_H + +#include "lwip/opt.h" + +#if LWIP_DNS + +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/* DNS resolve types: */ +#define LWIP_DNS_ADDRTYPE_IPV4 0 +#define LWIP_DNS_ADDRTYPE_IPV6 1 +#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#if LWIP_IPV4 && LWIP_IPV6 +#ifndef LWIP_DNS_ADDRTYPE_DEFAULT +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4_IPV6 +#endif +#elif LWIP_IPV4 +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4 +#else +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV6 +#endif + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#define DNS_LOCAL_HOSTLIST_ELEM(name, addr_init) {name, addr_init, NULL} +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#if LWIP_IPV4 +extern const ip_addr_t dns_mquery_v4group; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +extern const ip_addr_t dns_mquery_v6group; +#endif /* LWIP_IPV6 */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, const ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver); +const ip_addr_t* dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); +err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg, + u8_t dns_addrtype); + + +#if DNS_LOCAL_HOSTLIST +size_t dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg); +err_t dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype); +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* LWIP_HDR_DNS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/err.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/err.h new file mode 100644 index 0000000..887d9b3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/err.h @@ -0,0 +1,117 @@ +/** + * @file + * lwIP Error codes + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERR_H +#define LWIP_HDR_ERR_H + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup infrastructure_errors Error codes + * @ingroup infrastructure + * @{ + */ + +/** Definitions for error constants. */ +typedef enum { +/** No error, everything OK. */ + ERR_OK = 0, +/** Out of memory error. */ + ERR_MEM = -1, +/** Buffer error. */ + ERR_BUF = -2, +/** Timeout. */ + ERR_TIMEOUT = -3, +/** Routing problem. */ + ERR_RTE = -4, +/** Operation in progress */ + ERR_INPROGRESS = -5, +/** Illegal value. */ + ERR_VAL = -6, +/** Operation would block. */ + ERR_WOULDBLOCK = -7, +/** Address in use. */ + ERR_USE = -8, +/** Already connecting. */ + ERR_ALREADY = -9, +/** Conn already established.*/ + ERR_ISCONN = -10, +/** Not connected. */ + ERR_CONN = -11, +/** Low-level netif error */ + ERR_IF = -12, + +/** Connection aborted. */ + ERR_ABRT = -13, +/** Connection reset. */ + ERR_RST = -14, +/** Connection closed. */ + ERR_CLSD = -15, +/** Illegal argument. */ + ERR_ARG = -16 +} err_enum_t; + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/** + * @} + */ + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#if !NO_SYS +int err_to_errno(err_t err); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERR_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/errno.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/errno.h new file mode 100644 index 0000000..48d6b53 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/errno.h @@ -0,0 +1,198 @@ +/** + * @file + * Posix Errno defines + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERRNO_H +#define LWIP_HDR_ERRNO_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +#ifndef errno +extern int errno; +#endif + +#else /* LWIP_PROVIDE_ERRNO */ + +/* Define LWIP_ERRNO_STDINCLUDE if you want to include here */ +#ifdef LWIP_ERRNO_STDINCLUDE +#include +#else /* LWIP_ERRNO_STDINCLUDE */ +/* Define LWIP_ERRNO_INCLUDE to an equivalent of to include the error defines here */ +#ifdef LWIP_ERRNO_INCLUDE +#include LWIP_ERRNO_INCLUDE +#endif /* LWIP_ERRNO_INCLUDE */ +#endif /* LWIP_ERRNO_STDINCLUDE */ + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERRNO_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/etharp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/etharp.h new file mode 100644 index 0000000..2036b24 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/etharp.h @@ -0,0 +1,105 @@ +/** + * @file + * Ethernet output function - handles OUTGOING ethernet level traffic, implements + * ARP resolving. + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHARP_H +#define LWIP_HDR_NETIF_ETHARP_H + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/prot/ethernet.h" + +#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/prot/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 seconds period */ +#define ARP_TMR_INTERVAL 1000 + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct etharp_q_entry { + struct etharp_q_entry *next; + struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, no init needed. */ +void etharp_tmr(void); +ssize_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, + struct eth_addr **eth_ret, const ip4_addr_t **ip_ret); +int etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret); +err_t etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), netif_ip4_addr(netif)) +void etharp_cleanup_netif(struct netif *netif); + +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr); +err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +void etharp_input(struct pbuf *p, struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_ARP */ +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#endif /* LWIP_HDR_NETIF_ETHARP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ethip6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ethip6.h new file mode 100644 index 0000000..5e88dff --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ethip6.h @@ -0,0 +1,68 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ETHIP6_H +#define LWIP_HDR_ETHIP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +err_t ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + +#endif /* LWIP_HDR_ETHIP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp.h new file mode 100644 index 0000000..f5a31fd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp.h @@ -0,0 +1,110 @@ +/** + * @file + * ICMP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ICMP_H +#define LWIP_HDR_ICMP_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp.h" + +#if LWIP_IPV6 && LWIP_ICMP6 +#include "lwip/icmp6.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP destination unreachable codes */ +enum icmp_dur_type { + /** net unreachable */ + ICMP_DUR_NET = 0, + /** host unreachable */ + ICMP_DUR_HOST = 1, + /** protocol unreachable */ + ICMP_DUR_PROTO = 2, + /** port unreachable */ + ICMP_DUR_PORT = 3, + /** fragmentation needed and DF set */ + ICMP_DUR_FRAG = 4, + /** source route failed */ + ICMP_DUR_SR = 5 +}; + +/** ICMP time exceeded codes */ +enum icmp_te_type { + /** time to live exceeded in transit */ + ICMP_TE_TTL = 0, + /** fragment reassembly time exceeded */ + ICMP_TE_FRAG = 1 +}; + +#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp); +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#endif /* LWIP_IPV4 && LWIP_ICMP */ + +#if LWIP_IPV4 && LWIP_IPV6 +#if LWIP_ICMP && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ + icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ + icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) +#elif LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) do{ if(!(isipv6)) { icmp_dest_unreach(pbuf, ICMP_DUR_PORT);}}while(0) +#elif LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) do{ if(isipv6) { icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT);}}while(0) +#else +#define icmp_port_unreach(isipv6, pbuf) +#endif +#elif LWIP_IPV6 && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) +#elif LWIP_IPV4 && LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) +#else /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) */ +#define icmp_port_unreach(isipv6, pbuf) +#endif /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) LWIP_IPV4*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ICMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp6.h new file mode 100644 index 0000000..0ccb789 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/icmp6.h @@ -0,0 +1,72 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_ICMP6_H +#define LWIP_HDR_ICMP6_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +void icmp6_input(struct pbuf *p, struct netif *inp); +void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); +void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); +void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); +void icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, + const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); +void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer); + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* LWIP_HDR_ICMP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/if_api.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/if_api.h new file mode 100644 index 0000000..b7269e2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/if_api.h @@ -0,0 +1,70 @@ +/** + * @file + * Interface Identification APIs from: + * RFC 3493: Basic Socket Interface Extensions for IPv6 + * Section 4: Interface Identification + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Joel Cunningham + * + */ +#ifndef LWIP_HDR_IF_H +#define LWIP_HDR_IF_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef IF_NAMESIZE +#define IF_NAMESIZE NETIF_NAMESIZE +#endif + +char * lwip_if_indextoname(unsigned int ifindex, char *ifname); +unsigned int lwip_if_nametoindex(const char *ifname); + +#if LWIP_COMPAT_SOCKETS +#define if_indextoname(ifindex, ifname) lwip_if_indextoname(ifindex,ifname) +#define if_nametoindex(ifname) lwip_if_nametoindex(ifname) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_HDR_IF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/igmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/igmp.h new file mode 100644 index 0000000..ffd80e6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/igmp.h @@ -0,0 +1,115 @@ +/** + * @file + * IGMP API + */ + +/* + * Copyright (c) 2002 CITEL Technologies 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of CITEL Technologies Ltd 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 CITEL TECHNOLOGIES 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 CITEL TECHNOLOGIES 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. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef LWIP_HDR_IGMP_H +#define LWIP_HDR_IGMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* Compatibility defines (don't use for new code) */ +#define IGMP_DEL_MAC_FILTER NETIF_DEL_MAC_FILTER +#define IGMP_ADD_MAC_FILTER NETIF_ADD_MAC_FILTER + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** multicast address */ + ip4_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void); +err_t igmp_start(struct netif *netif); +err_t igmp_stop(struct netif *netif); +void igmp_report_groups(struct netif *netif); +struct igmp_group *igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr); +void igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest); +err_t igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +void igmp_tmr(void); + +/** @ingroup igmp + * Get list head of IGMP groups for netif. + * Note: The allsystems group IP is contained in the list as first entry. + * @see @ref netif_set_igmp_mac_filter() + */ +#define netif_igmp_data(netif) ((struct igmp_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_IGMP */ + +#endif /* LWIP_HDR_IGMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet.h new file mode 100644 index 0000000..2982a0f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet.h @@ -0,0 +1,169 @@ +/** + * @file + * This file (together with sockets.h) aims to provide structs and functions from + * - arpa/inet.h + * - netinet/in.h + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_H +#define LWIP_HDR_INET_H + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) +typedef u32_t in_addr_t; +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct in6_addr { + union { + u32_t u32_addr[4]; + u8_t u8_addr[16]; + } un; +#define s6_addr un.u8_addr +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 wildcard address. */ +#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 loopback address. */ +#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} +/** This variable is initialized by the system to contain the wildcard IPv6 address. */ +extern const struct in6_addr in6addr_any; + +/* Definitions of the bits in an (IPv4) Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX +#endif +#if LWIP_IPV6 +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX +#endif +#endif + +#if LWIP_IPV4 + +#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) +#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ + (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3]; \ + ip6_addr_clear_zone(target_ip6addr);} + +/* directly map this to the lwip internal functions */ +#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) +#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) +#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet_chksum.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet_chksum.h new file mode 100644 index 0000000..76893ef --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/inet_chksum.h @@ -0,0 +1,105 @@ +/** + * @file + * IP checksum calculation functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_CHKSUM_H +#define LWIP_HDR_INET_CHKSUM_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like lwip_htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) ((u32_t)(((u) >> 16) + ((u) & 0x0000ffffUL))) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +# ifndef LWIP_CHKSUM_COPY +# define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +# ifndef LWIP_CHKSUM_COPY_ALGORITHM +# define LWIP_CHKSUM_COPY_ALGORITHM 1 +# endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +# else /* LWIP_CHKSUM_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +# endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(const void *dataptr, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#if LWIP_IPV4 +u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip4_addr_t *src, const ip4_addr_t *dest); +u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, + u16_t proto_len, u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest); +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip6_addr_t *src, const ip6_addr_t *dest); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest); +#endif /* LWIP_IPV6 */ + + +u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip_addr_t *src, const ip_addr_t *dest); +u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h new file mode 100644 index 0000000..6cabfc8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h @@ -0,0 +1,100 @@ +/** + * @file + * lwIP initialization API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INIT_H +#define LWIP_HDR_INIT_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup lwip_version Version + * @ingroup lwip + * @{ + */ + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 2 +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 1 +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 3 +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC LWIP_RC_RELEASE + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255 +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ +#define LWIP_RC_DEVELOPMENT 0 + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/* Some helper defines to get a version string */ +#define LWIP_VERSTR2(x) #x +#define LWIP_VERSTR(x) LWIP_VERSTR2(x) +#if LWIP_VERSION_IS_RELEASE +#define LWIP_VERSION_STRING_SUFFIX "" +#elif LWIP_VERSION_IS_DEVELOPMENT +#define LWIP_VERSION_STRING_SUFFIX "d" +#else +#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) +#endif + +/** Provides the version of the stack */ +#define LWIP_VERSION ((LWIP_VERSION_MAJOR) << 24 | (LWIP_VERSION_MINOR) << 16 | \ + (LWIP_VERSION_REVISION) << 8 | (LWIP_VERSION_RC)) +/** Provides the version of the stack as string */ +#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX + +/** + * @} + */ + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INIT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h.cmake.in b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h.cmake.in new file mode 100644 index 0000000..9b609b7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/init.h.cmake.in @@ -0,0 +1,100 @@ +/** + * @file + * lwIP initialization API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INIT_H +#define LWIP_HDR_INIT_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup lwip_version Version + * @ingroup lwip + * @{ + */ + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR ${LWIP_VERSION_MAJOR} +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR ${LWIP_VERSION_MINOR} +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION ${LWIP_VERSION_REVISION} +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC ${LWIP_VERSION_RC} + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255 +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ +#define LWIP_RC_DEVELOPMENT 0 + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/* Some helper defines to get a version string */ +#define LWIP_VERSTR2(x) #x +#define LWIP_VERSTR(x) LWIP_VERSTR2(x) +#if LWIP_VERSION_IS_RELEASE +#define LWIP_VERSION_STRING_SUFFIX "" +#elif LWIP_VERSION_IS_DEVELOPMENT +#define LWIP_VERSION_STRING_SUFFIX "d" +#else +#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) +#endif + +/** Provides the version of the stack */ +#define LWIP_VERSION ((LWIP_VERSION_MAJOR) << 24 | (LWIP_VERSION_MINOR) << 16 | \ + (LWIP_VERSION_REVISION) << 8 | (LWIP_VERSION_RC)) +/** Provides the version of the stack as string */ +#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX + +/** + * @} + */ + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INIT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip.h new file mode 100644 index 0000000..653c3b2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip.h @@ -0,0 +1,330 @@ +/** + * @file + * IP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_H +#define LWIP_HDR_IP_H + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/ip6.h" +#include "lwip/prot/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#define LWIP_IP_HDRINCL NULL + +/** pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ +#ifndef LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX +#define LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p) LWIP_ASSERT("p->ref == 1", (p)->ref == 1) +#endif + +#if LWIP_NETIF_USE_HINTS +#define IP_PCB_NETIFHINT ;struct netif_hint netif_hints +#else /* LWIP_NETIF_USE_HINTS */ +#define IP_PCB_NETIFHINT +#endif /* LWIP_NETIF_USE_HINTS */ + +/** This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Bound netif index */ \ + u8_t netif_idx; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_NETIFHINT + +struct ip_pcb { + /* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX in sockets.h + */ +#define SOF_REUSEADDR 0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE 0x08U /* keep connections alive */ +#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) + +/** Global variables of this module, kept in a struct for efficient access using base+index. */ +struct ip_globals +{ + /** The interface that accepted the packet for the current callback invocation. */ + struct netif *current_netif; + /** The interface that received the packet for the current callback invocation. */ + struct netif *current_input_netif; +#if LWIP_IPV4 + /** Header of the input packet currently being processed. */ + const struct ip_hdr *current_ip4_header; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Header of the input IPv6 packet currently being processed. */ + struct ip6_hdr *current_ip6_header; +#endif /* LWIP_IPV6 */ + /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ + u16_t current_ip_header_tot_len; + /** Source IP address of current_header */ + ip_addr_t current_iphdr_src; + /** Destination IP address of current_header */ + ip_addr_t current_iphdr_dest; +}; +extern struct ip_globals ip_data; + + +/** Get the interface that accepted the current packet. + * This may or may not be the receiving netif, depending on your netif/network setup. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (ip_data.current_netif) +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_input_netif() (ip_data.current_input_netif) +/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ +#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) +/** Source IP address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if LWIP_IPV4 && LWIP_IPV6 +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ip_data.current_ip4_header +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ +#define ip_current_is_v6() (ip6_current_header() != NULL) +/** Source IPv6 address of current_header */ +#define ip6_current_src_addr() (ip_2_ip6(&ip_data.current_iphdr_src)) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (ip_2_ip6(&ip_data.current_iphdr_dest)) +/** Get the transport layer protocol */ +#define ip_current_header_proto() (ip_current_is_v6() ? \ + IP6H_NEXTH(ip6_current_header()) :\ + IPH_PROTO(ip4_current_header())) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((ip_current_is_v6() ? \ + (const u8_t*)ip6_current_header() : (const u8_t*)ip4_current_header()) + ip_current_header_tot_len())) + +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (ip_2_ip4(&ip_data.current_iphdr_src)) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (ip_2_ip4(&ip_data.current_iphdr_dest)) + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ip_data.current_ip4_header +/** Always returns FALSE when only supporting IPv4 only */ +#define ip_current_is_v6() 0 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IPH_PROTO(ip4_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((const u8_t*)ip4_current_header() + ip_current_header_tot_len())) +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (&ip_data.current_iphdr_dest) + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Always returns TRUE when only supporting IPv6 only */ +#define ip_current_is_v6() 1 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IP6H_NEXTH(ip6_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)(((const u8_t*)ip6_current_header()) + ip_current_header_tot_len())) +/** Source IP6 address of current_header */ +#define ip6_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP6 address of current_header */ +#define ip6_current_dest_addr() (&ip_data.current_iphdr_dest) + +#endif /* LWIP_IPV6 */ + +/** Union source address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Union destination address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +/** Gets an IP pcb option (SOF_* flags) */ +#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt)) +/** Sets an IP pcb option (SOF_* flags) */ +#define ip_set_option(pcb, opt) ((pcb)->so_options = (u8_t)((pcb)->so_options | (opt))) +/** Resets an IP pcb option (SOF_* flags) */ +#define ip_reset_option(pcb, opt) ((pcb)->so_options = (u8_t)((pcb)->so_options & ~(opt))) + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ip + * Output IP packet, netif is selected by source address + */ +#define ip_output(p, src, dest, ttl, tos, proto) \ + (IP_IS_V6(dest) ? \ + ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ + ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto)) +/** + * @ingroup ip + * Output IP packet to specified interface + */ +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** + * @ingroup ip + * Output IP packet to interface specifying source address + */ +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if_src(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** Output IP packet that already includes an IP header. */ +#define ip_output_if_hdrincl(p, src, dest, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if(p, ip_2_ip6(src), LWIP_IP_HDRINCL, 0, 0, 0, netif) : \ + ip4_output_if(p, ip_2_ip4(src), LWIP_IP_HDRINCL, 0, 0, 0, netif)) +/** Output IP packet with netif_hint */ +#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ + (IP_IS_V6(dest) ? \ + ip6_output_hinted(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif_hint) : \ + ip4_output_hinted(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif_hint)) +/** + * @ingroup ip + * Get netif for address combination. See \ref ip6_route and \ref ip4_route + */ +#define ip_route(src, dest) \ + (IP_IS_V6(dest) ? \ + ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ + ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest))) +/** + * @ingroup ip + * Get netif for IP. + */ +#define ip_netif_get_local_ip(netif, dest) (IP_IS_V6(dest) ? \ + ip6_netif_get_local_ip(netif, ip_2_ip6(dest)) : \ + ip4_netif_get_local_ip(netif)) +#define ip_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip4_debug_print(p)) + +err_t ip_input(struct pbuf *p, struct netif *inp); + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip4_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ + ip4_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) +#define ip_output_if_hdrincl(p, src, dest, netif) \ + ip4_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) +#define ip_route(src, dest) \ + ip4_route_src(src, dest) +#define ip_netif_get_local_ip(netif, dest) \ + ip4_netif_get_local_ip(netif) +#define ip_debug_print(is_ipv6, p) ip4_debug_print(p) + +#define ip_input ip4_input + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip6_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ + ip6_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) +#define ip_output_if_hdrincl(p, src, dest, netif) \ + ip6_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) +#define ip_route(src, dest) \ + ip6_route(src, dest) +#define ip_netif_get_local_ip(netif, dest) \ + ip6_netif_get_local_ip(netif, dest) +#define ip_debug_print(is_ipv6, p) ip6_debug_print(p) + +#define ip_input ip6_input + +#endif /* LWIP_IPV6 */ + +#define ip_route_get_local_ip(src, dest, netif, ipaddr) do { \ + (netif) = ip_route(src, dest); \ + (ipaddr) = ip_netif_get_local_ip(netif, dest); \ +}while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4.h new file mode 100644 index 0000000..fd35a33 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4.h @@ -0,0 +1,111 @@ +/** + * @file + * IPv4 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_H +#define LWIP_HDR_IP4_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/prot/ip4.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +#define LWIP_IPV4_SRC_ROUTING 1 +#else +#define LWIP_IPV4_SRC_ROUTING 0 +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) + +#define ip_init() /* Compatibility define, no init needed. */ +struct netif *ip4_route(const ip4_addr_t *dest); +#if LWIP_IPV4_SRC_ROUTING +struct netif *ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest); +#else /* LWIP_IPV4_SRC_ROUTING */ +#define ip4_route_src(src, dest) ip4_route(dest) +#endif /* LWIP_IPV4_SRC_ROUTING */ +err_t ip4_input(struct pbuf *p, struct netif *inp); +err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto); +err_t ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +#if LWIP_NETIF_USE_HINTS +err_t ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif_hint *netif_hint); +#endif /* LWIP_NETIF_USE_HINTS */ +#if IP_OPTIONS_SEND +err_t ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +#endif /* IP_OPTIONS_SEND */ + +#if LWIP_MULTICAST_TX_OPTIONS +void ip4_set_default_multicast_netif(struct netif* default_multicast_netif); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#define ip4_netif_get_local_ip(netif) (((netif) != NULL) ? netif_ip_addr4(netif) : NULL) + +#if IP_DEBUG +void ip4_debug_print(struct pbuf *p); +#else +#define ip4_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_addr.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_addr.h new file mode 100644 index 0000000..f244c4f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_addr.h @@ -0,0 +1,216 @@ +/** + * @file + * IPv4 address API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_ADDR_H +#define LWIP_HDR_IP4_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the aligned version of ip4_addr_t, + used as local variable, on the stack, etc. */ +struct ip4_addr { + u32_t addr; +}; + +/** ip4_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip4_addr_t as well as on ip4_addr_p_t. */ +typedef struct ip4_addr ip4_addr_t; + +/* Forward declaration to not include netif.h */ +struct netif; + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** Copy IP address - faster than ip4_addr_set: no NULL check */ +#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip4_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for lwip_htonl()) */ +#define ip4_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip4_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Check if an address is in the loopback region */ +#define ip4_addr_isloopback(ipaddr) (((ipaddr)->addr & PP_HTONL(IP_CLASSA_NET)) == PP_HTONL(((u32_t)IP_LOOPBACKNET) << 24)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip4_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + lwip_htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip4_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY) +#define ip4_addr_isany(addr1) ((addr1) == NULL || ip4_addr_isany_val(*(addr1))) + +#define ip4_addr_isbroadcast(addr1, netif) ip4_addr_isbroadcast_u32((addr1)->addr, netif) +u8_t ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif); + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask); + +#define ip4_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip4_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip4_addr_debug_print_parts(debug, a, b, c, d) \ + LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d)) +#define ip4_addr_debug_print(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0)) +#define ip4_addr_debug_print_val(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + ip4_addr1_16_val(ipaddr), \ + ip4_addr2_16_val(ipaddr), \ + ip4_addr3_16_val(ipaddr), \ + ip4_addr4_16_val(ipaddr)) + +/* Get one byte from the 4-byte address */ +#define ip4_addr_get_byte(ipaddr, idx) (((const u8_t*)(&(ipaddr)->addr))[idx]) +#define ip4_addr1(ipaddr) ip4_addr_get_byte(ipaddr, 0) +#define ip4_addr2(ipaddr) ip4_addr_get_byte(ipaddr, 1) +#define ip4_addr3(ipaddr) ip4_addr_get_byte(ipaddr, 2) +#define ip4_addr4(ipaddr) ip4_addr_get_byte(ipaddr, 3) +/* Get one byte from the 4-byte address, but argument is 'ip4_addr_t', + * not a pointer */ +#define ip4_addr_get_byte_val(ipaddr, idx) ((u8_t)(((ipaddr).addr >> (idx * 8)) & 0xff)) +#define ip4_addr1_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 0) +#define ip4_addr2_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 1) +#define ip4_addr3_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 2) +#define ip4_addr4_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 3) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) +#define ip4_addr1_16_val(ipaddr) ((u16_t)ip4_addr1_val(ipaddr)) +#define ip4_addr2_16_val(ipaddr) ((u16_t)ip4_addr2_val(ipaddr)) +#define ip4_addr3_16_val(ipaddr) ((u16_t)ip4_addr3_val(ipaddr)) +#define ip4_addr4_16_val(ipaddr) ((u16_t)ip4_addr4_val(ipaddr)) + +#define IP4ADDR_STRLEN_MAX 16 + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp); +int ip4addr_aton(const char *cp, ip4_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip4addr_ntoa(const ip4_addr_t *addr); +char *ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_frag.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_frag.h new file mode 100644 index 0000000..ed5bf14 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip4_frag.h @@ -0,0 +1,100 @@ +/** + * @file + * IP fragmentation/reassembly + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef LWIP_HDR_IP4_FRAG_H +#define LWIP_HDR_IP4_FRAG_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/** IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void); +void ip_reass_tmr(void); +struct pbuf * ip4_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !LWIP_NETIF_TX_SINGLE_PBUF +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP4_FRAG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6.h new file mode 100644 index 0000000..f894e06 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6.h @@ -0,0 +1,93 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_H +#define LWIP_HDR_IP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); +const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); +err_t ip6_input(struct pbuf *p, struct netif *inp); +err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth); +err_t ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +#if LWIP_NETIF_USE_HINTS +err_t ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif_hint *netif_hint); +#endif /* LWIP_NETIF_USE_HINTS */ +#if LWIP_IPV6_MLD +err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); +#endif /* LWIP_IPV6_MLD */ + +#define ip6_netif_get_local_ip(netif, dest) (((netif) != NULL) ? \ + ip6_select_source_address(netif, dest) : NULL) + +#if IP6_DEBUG +void ip6_debug_print(struct pbuf *p); +#else +#define ip6_debug_print(p) +#endif /* IP6_DEBUG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_addr.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_addr.h new file mode 100644 index 0000000..29c2a34 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_addr.h @@ -0,0 +1,352 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Structs and macros for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_ADDR_H +#define LWIP_HDR_IP6_ADDR_H + +#include "lwip/opt.h" +#include "def.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_zone.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** This is the aligned version of ip6_addr_t, + used as local variable, on the stack, etc. */ +struct ip6_addr { + u32_t addr[4]; +#if LWIP_IPV6_SCOPES + u8_t zone; +#endif /* LWIP_IPV6_SCOPES */ +}; + +/** IPv6 address */ +typedef struct ip6_addr ip6_addr_t; + +/** Set an IPv6 partial address given by byte-parts */ +#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** Set a full IPv6 address by passing the 4 u32_t indices in network byte order + (use PP_HTONL() for constants) */ +#define IP6_ADDR(ip6addr, idx0, idx1, idx2, idx3) do { \ + (ip6addr)->addr[0] = idx0; \ + (ip6addr)->addr[1] = idx1; \ + (ip6addr)->addr[2] = idx2; \ + (ip6addr)->addr[3] = idx3; \ + ip6_addr_clear_zone(ip6addr); } while(0) + +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3])) & 0xffff)) + +/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3]; \ + ip6_addr_copy_zone((dest), (src)); }while(0) +/** Safely copy one IPv6 address to another (src may be NULL) */ +#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3]; \ + ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src)); }while(0) + +/** Copy packed IPv6 address to unpacked IPv6 address; zone is not set */ +#define ip6_addr_copy_from_packed(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3]; \ + ip6_addr_clear_zone(&dest); }while(0) + +/** Copy unpacked IPv6 address to packed IPv6 address; zone is lost */ +#define ip6_addr_copy_to_packed(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3]; }while(0) + +/** Set complete address to zero */ +#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = 0; \ + ip6_addr_clear_zone(ip6addr);}while(0) + +/** Set address to ipv6 'any' (no need for lwip_htonl()) */ +#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) +/** Set address to ipv6 loopback address */ +#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL); \ + ip6_addr_clear_zone(ip6addr);}while(0) +/** Safely copy one IPv6 address to another and change byte order + * from host- to network-order. */ +#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : lwip_htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : lwip_htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : lwip_htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : lwip_htonl((src)->addr[3]); \ + ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src));}while(0) + + +/** Compare IPv6 networks, ignoring zone information. To be used sparingly! */ +#define ip6_addr_netcmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1])) + +/** + * Determine if two IPv6 address are on the same network. + * + * @param addr1 IPv6 address 1 + * @param addr2 IPv6 address 2 + * @return 1 if the network identifiers of both address match, 0 if not + */ +#define ip6_addr_netcmp(addr1, addr2) (ip6_addr_netcmp_zoneless((addr1), (addr2)) && \ + ip6_addr_cmp_zone((addr1), (addr2))) + +/* Exact-host comparison *after* ip6_addr_netcmp() succeeded, for efficiency. */ +#define ip6_addr_nethostcmp(addr1, addr2) (((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) + +/** Compare IPv6 addresses, ignoring zone information. To be used sparingly! */ +#define ip6_addr_cmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) +/** + * Determine if two IPv6 addresses are the same. In particular, the address + * part of both must be the same, and the zone must be compatible. + * + * @param addr1 IPv6 address 1 + * @param addr2 IPv6 address 2 + * @return 1 if the addresses are considered equal, 0 if not + */ +#define ip6_addr_cmp(addr1, addr2) (ip6_addr_cmp_zoneless((addr1), (addr2)) && \ + ip6_addr_cmp_zone((addr1), (addr2))) + +/** Compare IPv6 address to packed address and zone */ +#define ip6_addr_cmp_packed(ip6addr, paddr, zone_idx) (((ip6addr)->addr[0] == (paddr)->addr[0]) && \ + ((ip6addr)->addr[1] == (paddr)->addr[1]) && \ + ((ip6addr)->addr[2] == (paddr)->addr[2]) && \ + ((ip6addr)->addr[3] == (paddr)->addr[3]) && \ + ip6_addr_equals_zone((ip6addr), (zone_idx))) + +#define ip6_get_subnet_id(ip6addr) (lwip_htonl((ip6addr)->addr[2]) & 0x0000ffffUL) + +#define ip6_addr_isany_val(ip6addr) (((ip6addr).addr[0] == 0) && \ + ((ip6addr).addr[1] == 0) && \ + ((ip6addr).addr[2] == 0) && \ + ((ip6addr).addr[3] == 0)) +#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || ip6_addr_isany_val(*(ip6addr))) + +#define ip6_addr_isloopback(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) + +#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) + +#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) + +#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) + +#define ip6_addr_isipv4mappedipv6(ip6addr) (((ip6addr)->addr[0] == 0) && ((ip6addr)->addr[1] == 0) && (((ip6addr)->addr[2]) == PP_HTONL(0x0000FFFFUL))) + +#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) +#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) +#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) +#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) +#define ip6_addr_multicast_scope(ip6addr) ((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xf) +#define IP6_MULTICAST_SCOPE_RESERVED 0x0 +#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 +#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 +#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 +#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 +#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 +#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 +#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IP6_MULTICAST_SCOPE_GLOBAL 0xe +#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf +#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff010000UL)) +#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff020000UL)) +#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff040000UL)) +#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff050000UL)) +#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff080000UL)) +#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff0e0000UL)) + +/* Scoping note: while interface-local and link-local multicast addresses do + * have a scope (i.e., they are meaningful only in the context of a particular + * interface), the following functions are not assigning or comparing zone + * indices. The reason for this is backward compatibility. Any call site that + * produces a non-global multicast address must assign a multicast address as + * appropriate itself. */ + +#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) +#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL); \ + ip6_addr_clear_zone(ip6addr); }while(0) + +#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) +#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000002UL); \ + ip6_addr_clear_zone(ip6addr); }while(0) + +#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) + +#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ + (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id)); \ + ip6_addr_clear_zone(ip6addr); }while(0) + +#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) + +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */ +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */ +#define IP6_ADDR_DUPLICATED 0x40 /* Failed DAD test, not valid */ + +#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */ + +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) +#define ip6_addr_isduplicated(addr_state) (addr_state == IP6_ADDR_DUPLICATED) + +#if LWIP_IPV6_ADDRESS_LIFETIMES +#define IP6_ADDR_LIFE_STATIC (0) +#define IP6_ADDR_LIFE_INFINITE (0xffffffffUL) +#define ip6_addr_life_isstatic(addr_life) ((addr_life) == IP6_ADDR_LIFE_STATIC) +#define ip6_addr_life_isinfinite(addr_life) ((addr_life) == IP6_ADDR_LIFE_INFINITE) +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ + +#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \ + LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \ + a, b, c, d, e, f, g, h)) +#define ip6_addr_debug_print(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) +#define ip6_addr_debug_print_val(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + IP6_ADDR_BLOCK1(&(ipaddr)), \ + IP6_ADDR_BLOCK2(&(ipaddr)), \ + IP6_ADDR_BLOCK3(&(ipaddr)), \ + IP6_ADDR_BLOCK4(&(ipaddr)), \ + IP6_ADDR_BLOCK5(&(ipaddr)), \ + IP6_ADDR_BLOCK6(&(ipaddr)), \ + IP6_ADDR_BLOCK7(&(ipaddr)), \ + IP6_ADDR_BLOCK8(&(ipaddr))) + +#define IP6ADDR_STRLEN_MAX 46 + +int ip6addr_aton(const char *cp, ip6_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip6addr_ntoa(const ip6_addr_t *addr); +char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); + + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_ADDR_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_frag.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_frag.h new file mode 100644 index 0000000..87e0e86 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_frag.h @@ -0,0 +1,144 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_FRAG_H +#define LWIP_HDR_IP6_FRAG_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + +/** The IPv6 reassembly timer interval in milliseconds. */ +#define IP6_REASS_TMR_INTERVAL 1000 + +/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, "struct + * ip6_reass_helper" is too large to be stored in the IPv6 fragment header, and + * will bleed into the header before it, which may be the IPv6 header or an + * extension header. This means that for each first fragment packet, we need to + * 1) make a copy of some IPv6 header fields (src+dest) that we need later on, + * just in case we do overwrite part of the IPv6 header, and 2) make a copy of + * the header data that we overwrote, so that we can restore it before either + * completing reassembly or sending an ICMPv6 reply. The last part is true even + * if this setting is disabled, but if it is enabled, we need to save a bit + * more data (up to the size of a pointer) because we overwrite more. */ +#ifndef IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_COPYHEADER 0 +#endif + +/* With IPV6_FRAG_COPYHEADER==1, a helper structure may (or, depending on the + * presence of extensions, may not) overwrite part of the IP header. Therefore, + * we copy the fields that we need from the IP header for as long as the helper + * structure may still be in place. This is easier than temporarily restoring + * those fields in the IP header each time we need to perform checks on them. */ +#if IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_SRC(ipr) ((ipr)->src) +#define IPV6_FRAG_DEST(ipr) ((ipr)->dest) +#else /* IPV6_FRAG_COPYHEADER */ +#define IPV6_FRAG_SRC(ipr) ((ipr)->iphdr->src) +#define IPV6_FRAG_DEST(ipr) ((ipr)->iphdr->dest) +#endif /* IPV6_FRAG_COPYHEADER */ + +/** IPv6 reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip6_reassdata { + struct ip6_reassdata *next; + struct pbuf *p; + struct ip6_hdr *iphdr; /* pointer to the first (original) IPv6 header */ +#if IPV6_FRAG_COPYHEADER + ip6_addr_p_t src; /* copy of the source address in the IP header */ + ip6_addr_p_t dest; /* copy of the destination address in the IP header */ + /* This buffer (for the part of the original header that we overwrite) will + * be slightly oversized, but we cannot compute the exact size from here. */ + u8_t orig_hdr[sizeof(struct ip6_frag_hdr) + sizeof(void*)]; +#else /* IPV6_FRAG_COPYHEADER */ + /* In this case we still need the buffer, for sending ICMPv6 replies. */ + u8_t orig_hdr[sizeof(struct ip6_frag_hdr)]; +#endif /* IPV6_FRAG_COPYHEADER */ + u32_t identification; + u16_t datagram_len; + u8_t nexth; + u8_t timer; +#if LWIP_IPV6_SCOPES + u8_t src_zone; /* zone of original packet's source address */ + u8_t dest_zone; /* zone of original packet's destination address */ +#endif /* LWIP_IPV6_SCOPES */ +}; + +#define ip6_reass_init() /* Compatibility define */ +void ip6_reass_tmr(void); +struct pbuf *ip6_reass(struct pbuf *p); + +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ + +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ + +err_t ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest); + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP6_FRAG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_zone.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_zone.h new file mode 100644 index 0000000..525790e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip6_zone.h @@ -0,0 +1,304 @@ +/** + * @file + * + * IPv6 address scopes, zones, and scoping policy. + * + * This header provides the means to implement support for IPv6 address scopes, + * as per RFC 4007. An address scope can be either global or more constrained. + * In lwIP, we say that an address "has a scope" or "is scoped" when its scope + * is constrained, in which case the address is meaningful only in a specific + * "zone." For unicast addresses, only link-local addresses have a scope; in + * that case, the scope is the link. For multicast addresses, there are various + * scopes defined by RFC 4007 and others. For any constrained scope, a system + * must establish a (potentially one-to-many) mapping between zones and local + * interfaces. For example, a link-local address is valid on only one link (its + * zone). That link may be attached to one or more local interfaces. The + * decisions on which scopes are constrained and the mapping between zones and + * interfaces is together what we refer to as the "scoping policy" - more on + * this in a bit. + * + * In lwIP, each IPv6 address has an associated zone index. This zone index may + * be set to "no zone" (IP6_NO_ZONE, 0) or an actual zone. We say that an + * address "has a zone" or "is zoned" when its zone index is *not* set to "no + * zone." In lwIP, in principle, each address should be "properly zoned," which + * means that if the address has a zone if and only if has a scope. As such, it + * is a rule that an unscoped (e.g., global) address must never have a zone. + * Even though one could argue that there is always one zone even for global + * scopes, this rule exists for implementation simplicity. Violation of the + * rule will trigger assertions or otherwise result in undesired behavior. + * + * Backward compatibility prevents us from requiring that applications always + * provide properly zoned addresses. We do enforce the rule that the in the + * lwIP link layer (everything below netif->output_ip6() and in particular ND6) + * *all* addresses are properly zoned. Thus, on the output paths down the + * stack, various places deal with the case of addresses that lack a zone. + * Some of them are best-effort for efficiency (e.g. the PCB bind and connect + * API calls' attempts to add missing zones); ultimately the IPv6 output + * handler (@ref ip6_output_if_src) will set a zone if necessary. + * + * Aside from dealing with scoped addresses lacking a zone, a proper IPv6 + * implementation must also ensure that a packet with a scoped source and/or + * destination address does not leave its zone. This is currently implemented + * in the input and forward functions. However, for output, these checks are + * deliberately omitted in order to keep the implementation lightweight. The + * routing algorithm in @ref ip6_route will take decisions such that it will + * not cause zone violations unless the application sets bad addresses, though. + * + * In terms of scoping policy, lwIP implements the default policy from RFC 4007 + * using macros in this file. This policy considers link-local unicast + * addresses and (only) interface-local and link-local multicast addresses as + * having a scope. For all these addresses, the zone is equal to the interface. + * As shown below in this file, it is possible to implement a custom policy. + */ + +/* + * Copyright (c) 2017 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: David van Moolenbroek + * + */ +#ifndef LWIP_HDR_IP6_ZONE_H +#define LWIP_HDR_IP6_ZONE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup ip6_zones IPv6 Zones + * @ingroup ip6 + * @{ + */ + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +/** Identifier for "no zone". */ +#define IP6_NO_ZONE 0 + +#if LWIP_IPV6_SCOPES + +/** Zone initializer for static IPv6 address initialization, including comma. */ +#define IPADDR6_ZONE_INIT , IP6_NO_ZONE + +/** Return the zone index of the given IPv6 address; possibly "no zone". */ +#define ip6_addr_zone(ip6addr) ((ip6addr)->zone) + +/** Does the given IPv6 address have a zone set? (0/1) */ +#define ip6_addr_has_zone(ip6addr) (ip6_addr_zone(ip6addr) != IP6_NO_ZONE) + +/** Set the zone field of an IPv6 address to a particular value. */ +#define ip6_addr_set_zone(ip6addr, zone_idx) ((ip6addr)->zone = (zone_idx)) + +/** Clear the zone field of an IPv6 address, setting it to "no zone". */ +#define ip6_addr_clear_zone(ip6addr) ((ip6addr)->zone = IP6_NO_ZONE) + +/** Copy the zone field from the second IPv6 address to the first one. */ +#define ip6_addr_copy_zone(ip6addr1, ip6addr2) ((ip6addr1).zone = (ip6addr2).zone) + +/** Is the zone field of the given IPv6 address equal to the given zone index? (0/1) */ +#define ip6_addr_equals_zone(ip6addr, zone_idx) ((ip6addr)->zone == (zone_idx)) + +/** Are the zone fields of the given IPv6 addresses equal? (0/1) + * This macro must only be used on IPv6 addresses of the same scope. */ +#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone) + +/** Symbolic constants for the 'type' parameters in some of the macros. + * These exist for efficiency only, allowing the macros to avoid certain tests + * when the address is known not to be of a certain type. Dead code elimination + * will do the rest. IP6_MULTICAST is supported but currently not optimized. + * @see ip6_addr_has_scope, ip6_addr_assign_zone, ip6_addr_lacks_zone. + */ +enum lwip_ipv6_scope_type +{ + /** Unknown */ + IP6_UNKNOWN = 0, + /** Unicast */ + IP6_UNICAST = 1, + /** Multicast */ + IP6_MULTICAST = 2 +}; + +/** IPV6_CUSTOM_SCOPES: together, the following three macro definitions, + * @ref ip6_addr_has_scope, @ref ip6_addr_assign_zone, and + * @ref ip6_addr_test_zone, completely define the lwIP scoping policy. + * The definitions below implement the default policy from RFC 4007 Sec. 6. + * Should an implementation desire to implement a different policy, it can + * define IPV6_CUSTOM_SCOPES to 1 and supply its own definitions for the three + * macros instead. + */ +#ifndef IPV6_CUSTOM_SCOPES +#define IPV6_CUSTOM_SCOPES 0 +#endif /* !IPV6_CUSTOM_SCOPES */ + +#if !IPV6_CUSTOM_SCOPES + +/** + * Determine whether an IPv6 address has a constrained scope, and as such is + * meaningful only if accompanied by a zone index to identify the scope's zone. + * The given address type may be used to eliminate at compile time certain + * checks that will evaluate to false at run time anyway. + * + * This default implementation follows the default model of RFC 4007, where + * only interface-local and link-local scopes are defined. + * + * Even though the unicast loopback address does have an implied link-local + * scope, in this implementation it does not have an explicitly assigned zone + * index. As such it should not be tested for in this macro. + * + * @param ip6addr the IPv6 address (const); only its address part is examined. + * @param type address type; see @ref lwip_ipv6_scope_type. + * @return 1 if the address has a constrained scope, 0 if it does not. + */ +#define ip6_addr_has_scope(ip6addr, type) \ + (ip6_addr_islinklocal(ip6addr) || (((type) != IP6_UNICAST) && \ + (ip6_addr_ismulticast_iflocal(ip6addr) || \ + ip6_addr_ismulticast_linklocal(ip6addr)))) + +/** + * Assign a zone index to an IPv6 address, based on a network interface. If the + * given address has a scope, the assigned zone index is that scope's zone of + * the given netif; otherwise, the assigned zone index is "no zone". + * + * This default implementation follows the default model of RFC 4007, where + * only interface-local and link-local scopes are defined, and the zone index + * of both of those scopes always equals the index of the network interface. + * As such, this default implementation need not distinguish between different + * constrained scopes when assigning the zone. + * + * @param ip6addr the IPv6 address; its address part is examined, and its zone + * index is assigned. + * @param type address type; see @ref lwip_ipv6_scope_type. + * @param netif the network interface (const). + */ +#define ip6_addr_assign_zone(ip6addr, type, netif) \ + (ip6_addr_set_zone((ip6addr), \ + ip6_addr_has_scope((ip6addr), (type)) ? netif_get_index(netif) : 0)) + +/** + * Test whether an IPv6 address is "zone-compatible" with a network interface. + * That is, test whether the network interface is part of the zone associated + * with the address. For efficiency, this macro is only ever called if the + * given address is either scoped or zoned, and thus, it need not test this. + * If an address is scoped but not zoned, or zoned and not scoped, it is + * considered not zone-compatible with any netif. + * + * This default implementation follows the default model of RFC 4007, where + * only interface-local and link-local scopes are defined, and the zone index + * of both of those scopes always equals the index of the network interface. + * As such, there is always only one matching netif for a specific zone index, + * but all call sites of this macro currently support multiple matching netifs + * as well (at no additional expense in the common case). + * + * @param ip6addr the IPv6 address (const). + * @param netif the network interface (const). + * @return 1 if the address is scope-compatible with the netif, 0 if not. + */ +#define ip6_addr_test_zone(ip6addr, netif) \ + (ip6_addr_equals_zone((ip6addr), netif_get_index(netif))) + +#endif /* !IPV6_CUSTOM_SCOPES */ + +/** Does the given IPv6 address have a scope, and as such should also have a + * zone to be meaningful, but does not actually have a zone? (0/1) */ +#define ip6_addr_lacks_zone(ip6addr, type) \ + (!ip6_addr_has_zone(ip6addr) && ip6_addr_has_scope((ip6addr), (type))) + +/** + * Try to select a zone for a scoped address that does not yet have a zone. + * Called from PCB bind and connect routines, for two reasons: 1) to save on + * this (relatively expensive) selection for every individual packet route + * operation and 2) to allow the application to obtain the selected zone from + * the PCB as is customary for e.g. getsockname/getpeername BSD socket calls. + * + * Ideally, callers would always supply a properly zoned address, in which case + * this function would not be needed. It exists both for compatibility with the + * BSD socket API (which accepts zoneless destination addresses) and for + * backward compatibility with pre-scoping lwIP code. + * + * It may be impossible to select a zone, e.g. if there are no netifs. In that + * case, the address's zone field will be left as is. + * + * @param dest the IPv6 address for which to select and set a zone. + * @param src source IPv6 address (const); may be equal to dest. + */ +#define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ + selected_netif = ip6_route((src), (dest)); \ + if (selected_netif != NULL) { \ + ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ + } } while (0) + +/** + * @} + */ + +#else /* LWIP_IPV6_SCOPES */ + +#define IPADDR6_ZONE_INIT +#define ip6_addr_zone(ip6addr) (IP6_NO_ZONE) +#define ip6_addr_has_zone(ip6addr) (0) +#define ip6_addr_set_zone(ip6addr, zone_idx) +#define ip6_addr_clear_zone(ip6addr) +#define ip6_addr_copy_zone(ip6addr1, ip6addr2) +#define ip6_addr_equals_zone(ip6addr, zone_idx) (1) +#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) (1) +#define IPV6_CUSTOM_SCOPES 0 +#define ip6_addr_has_scope(ip6addr, type) (0) +#define ip6_addr_assign_zone(ip6addr, type, netif) +#define ip6_addr_test_zone(ip6addr, netif) (1) +#define ip6_addr_lacks_zone(ip6addr, type) (0) +#define ip6_addr_select_zone(ip6addr, src) + +#endif /* LWIP_IPV6_SCOPES */ + +#if LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG + +/** Verify that the given IPv6 address is properly zoned. */ +#define IP6_ADDR_ZONECHECK(ip6addr) LWIP_ASSERT("IPv6 zone check failed", \ + ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) == ip6_addr_has_zone(ip6addr)) + +/** Verify that the given IPv6 address is properly zoned for the given netif. */ +#define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) LWIP_ASSERT("IPv6 netif zone check failed", \ + ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) ? \ + (ip6_addr_has_zone(ip6addr) && \ + (((netif) == NULL) || ip6_addr_test_zone((ip6addr), (netif)))) : \ + !ip6_addr_has_zone(ip6addr)) + +#else /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ + +#define IP6_ADDR_ZONECHECK(ip6addr) +#define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) + +#endif /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ + +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP6_ZONE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip_addr.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip_addr.h new file mode 100644 index 0000000..2f97770 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/ip_addr.h @@ -0,0 +1,438 @@ +/** + * @file + * IP address API (common IPv4 and IPv6) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_ADDR_H +#define LWIP_HDR_IP_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include "lwip/ip4_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup ipaddr + * IP address types for use in ip_addr_t.type member. + * @see tcp_new_ip_type(), udp_new_ip_type(), raw_new_ip_type(). + */ +enum lwip_ip_addr_type { + /** IPv4 */ + IPADDR_TYPE_V4 = 0U, + /** IPv6 */ + IPADDR_TYPE_V6 = 6U, + /** IPv4+IPv6 ("dual-stack") */ + IPADDR_TYPE_ANY = 46U +}; + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ipaddr + * A union struct for both IP version's addresses. + * ATTENTION: watch out for its size when adding IPv6 address scope! + */ +typedef struct ip_addr { + union { + ip6_addr_t ip6; + ip4_addr_t ip4; + } u_addr; + /** @ref lwip_ip_addr_type */ + u8_t type; +} ip_addr_t; + +extern const ip_addr_t ip_addr_any_type; + +/** @ingroup ip4addr */ +#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V4 } +/** @ingroup ip4addr */ +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) + +/** @ingroup ip6addr */ +#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V6 } +/** @ingroup ip6addr */ +#define IPADDR6_INIT_HOST(a, b, c, d) { { { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V6 } + +/** @ingroup ipaddr */ +#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY) +/** @ingroup ipaddr */ +#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_ANY } + +/** @ingroup ip4addr */ +#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4) +/** @ingroup ip6addr */ +#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6) +/** @ingroup ip4addr */ +#define IP_IS_V4(ipaddr) (((ipaddr) == NULL) || IP_IS_V4_VAL(*(ipaddr))) +/** @ingroup ip6addr */ +#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr))) + +#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) +#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0) +#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) + +#define IP_ADDR_RAW_SIZE(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4 ? sizeof(ip4_addr_t) : sizeof(ip6_addr_t)) + +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr)) +#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) + +/** @ingroup ip6addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) +/** @ingroup ip4addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) + +/** @ingroup ip4addr */ +#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +#define ip_clear_no4(ipaddr) do { ip_2_ip6(ipaddr)->addr[1] = \ + ip_2_ip6(ipaddr)->addr[2] = \ + ip_2_ip6(ipaddr)->addr[3] = 0; \ + ip6_addr_clear_zone(ip_2_ip6(ipaddr)); }while(0) + +/** @ingroup ipaddr */ +#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); ip_clear_no4(&dest); }}while(0) +/** @ingroup ip6addr */ +#define ip_addr_copy_from_ip6(dest, src) do{ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) +/** @ingroup ip6addr */ +#define ip_addr_copy_from_ip6_packed(dest, src) do{ \ + ip6_addr_copy_from_packed(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_copy_from_ip4(dest, src) do{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V4); ip_clear_no4(&dest); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_set_ip4_u32(ipaddr, val) do{if(ipaddr){ip4_addr_set_u32(ip_2_ip4(ipaddr), val); \ + IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) +/** @ingroup ip4addr */ +#define ip_addr_set_ip4_u32_val(ipaddr, val) do{ ip4_addr_set_u32(ip_2_ip4(&(ipaddr)), val); \ + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_get_ip4_u32(ipaddr) (((ipaddr) && IP_IS_V4(ipaddr)) ? \ + ip4_addr_get_u32(ip_2_ip4(ipaddr)) : 0) +/** @ingroup ipaddr */ +#define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, IP_GET_TYPE(src)); if(IP_IS_V6(src)){ \ + ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); }else{ \ + ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); ip_clear_no4(dest); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_ipaddr(dest, src) ip_addr_set(dest, src) +/** @ingroup ipaddr */ +#define ip_addr_set_zero(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, 0); }while(0) +/** @ingroup ip5addr */ +#define ip_addr_set_zero_ip4(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }while(0) +/** @ingroup ip6addr */ +#define ip_addr_set_zero_ip6(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_any(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_any_val(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ip_2_ip6(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_any(ip_2_ip4(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_loopback(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_loopback_val(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ip_2_ip6(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_loopback(ip_2_ip4(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_hton(dest, src) do{if(IP_IS_V6(src)){ \ + ip6_addr_set_hton(ip_2_ip6(dest), ip_2_ip6(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_hton(ip_2_ip4(dest), ip_2_ip4(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_get_network(target, host, netmask) do{if(IP_IS_V6(host)){ \ + ip4_addr_set_zero(ip_2_ip4(target)); IP_SET_TYPE(target, IPADDR_TYPE_V6); } else { \ + ip4_addr_get_network(ip_2_ip4(target), ip_2_ip4(host), ip_2_ip4(netmask)); IP_SET_TYPE(target, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_netcmp(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ + 0 : \ + ip4_addr_netcmp(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) +/** @ingroup ipaddr */ +#define ip_addr_cmp(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_cmp(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** @ingroup ipaddr */ +#define ip_addr_cmp_zoneless(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_cmp_zoneless(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** @ingroup ipaddr */ +#define ip_addr_isany(ipaddr) (((ipaddr) == NULL) ? 1 : ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isany(ip_2_ip6(ipaddr)) : \ + ip4_addr_isany(ip_2_ip4(ipaddr)))) +/** @ingroup ipaddr */ +#define ip_addr_isany_val(ipaddr) ((IP_IS_V6_VAL(ipaddr)) ? \ + ip6_addr_isany_val(*ip_2_ip6(&(ipaddr))) : \ + ip4_addr_isany_val(*ip_2_ip4(&(ipaddr)))) +/** @ingroup ipaddr */ +#define ip_addr_isbroadcast(ipaddr, netif) ((IP_IS_V6(ipaddr)) ? \ + 0 : \ + ip4_addr_isbroadcast(ip_2_ip4(ipaddr), netif)) +/** @ingroup ipaddr */ +#define ip_addr_ismulticast(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_ismulticast(ip_2_ip6(ipaddr)) : \ + ip4_addr_ismulticast(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_isloopback(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isloopback(ip_2_ip6(ipaddr)) : \ + ip4_addr_isloopback(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_islinklocal(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_islinklocal(ip_2_ip6(ipaddr)) : \ + ip4_addr_islinklocal(ip_2_ip4(ipaddr))) +#define ip_addr_debug_print(debug, ipaddr) do { if(IP_IS_V6(ipaddr)) { \ + ip6_addr_debug_print(debug, ip_2_ip6(ipaddr)); } else { \ + ip4_addr_debug_print(debug, ip_2_ip4(ipaddr)); }}while(0) +#define ip_addr_debug_print_val(debug, ipaddr) do { if(IP_IS_V6_VAL(ipaddr)) { \ + ip6_addr_debug_print_val(debug, *ip_2_ip6(&(ipaddr))); } else { \ + ip4_addr_debug_print_val(debug, *ip_2_ip4(&(ipaddr))); }}while(0) +char *ipaddr_ntoa(const ip_addr_t *addr); +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen); +int ipaddr_aton(const char *cp, ip_addr_t *addr); + +/** @ingroup ipaddr */ +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +/** @ingroup ipaddr */ +#define ip4_2_ipv4_mapped_ipv6(ip6addr, ip4addr) do { \ + (ip6addr)->addr[3] = (ip4addr)->addr; \ + (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[0] = 0; \ + ip6_addr_clear_zone(ip6addr); } while(0); + +/** @ingroup ipaddr */ +#define unmap_ipv4_mapped_ipv6(ip4addr, ip6addr) \ + (ip4addr)->addr = (ip6addr)->addr[3]; + +#define IP46_ADDR_ANY(type) (((type) == IPADDR_TYPE_V6)? IP6_ADDR_ANY : IP4_ADDR_ANY) + +#else /* LWIP_IPV4 && LWIP_IPV6 */ + +#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1 + +#define ip_addr_set_any_val(is_ipv6, ipaddr) ip_addr_set_any(is_ipv6, &(ipaddr)) +#define ip_addr_set_loopback_val(is_ipv6, ipaddr) ip_addr_set_loopback(is_ipv6, &(ipaddr)) + +#if LWIP_IPV4 + +typedef ip4_addr_t ip_addr_t; +#define IPADDR4_INIT(u32val) { u32val } +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) +#define IP_IS_V4_VAL(ipaddr) 1 +#define IP_IS_V6_VAL(ipaddr) 0 +#define IP_IS_V4(ipaddr) 1 +#define IP_IS_V6(ipaddr) 0 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V4 +#define IP_ADDR_RAW_SIZE(ipaddr) sizeof(ip4_addr_t) +#define ip_2_ip4(ipaddr) (ipaddr) +#define IP_ADDR4(ipaddr,a,b,c,d) IP4_ADDR(ipaddr,a,b,c,d) + +#define ip_addr_copy(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_copy_from_ip4(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_set_ip4_u32(ipaddr, val) ip4_addr_set_u32(ip_2_ip4(ipaddr), val) +#define ip_addr_set_ip4_u32_val(ipaddr, val) ip_addr_set_ip4_u32(&(ipaddr), val) +#define ip_addr_get_ip4_u32(ipaddr) ip4_addr_get_u32(ip_2_ip4(ipaddr)) +#define ip_addr_set(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip4(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip4_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip4_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip4_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip4_addr_get_network(target, host, mask) +#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_netcmp(addr1, addr2, mask) +#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2) +#define ip_addr_isany(ipaddr) ip4_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip4_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip4_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip4_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) ip4_addr_isbroadcast(addr, netif) +#define ip_addr_ismulticast(ipaddr) ip4_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip4_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip4_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip4addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip4addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip4addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP4_ADDR_ANY) + +#else /* LWIP_IPV4 */ + +typedef ip6_addr_t ip_addr_t; +#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } IPADDR6_ZONE_INIT } +#define IPADDR6_INIT_HOST(a, b, c, d) { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } IPADDR6_ZONE_INIT } +#define IP_IS_V4_VAL(ipaddr) 0 +#define IP_IS_V6_VAL(ipaddr) 1 +#define IP_IS_V4(ipaddr) 0 +#define IP_IS_V6(ipaddr) 1 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V6 +#define IP_ADDR_RAW_SIZE(ipaddr) sizeof(ip6_addr_t) +#define ip_2_ip6(ipaddr) (ipaddr) +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,i3) +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +#define ip_addr_copy(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_copy_from_ip6(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_copy_from_ip6_packed(dest, src) ip6_addr_copy_from_packed(dest, src) +#define ip_addr_set(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip6(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip6_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip6_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip6_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip6_addr_set_zero(target) +#define ip_addr_netcmp(addr1, addr2, mask) 0 +#define ip_addr_cmp(addr1, addr2) ip6_addr_cmp(addr1, addr2) +#define ip_addr_cmp_zoneless(addr1, addr2) ip6_addr_cmp_zoneless(addr1, addr2) +#define ip_addr_isany(ipaddr) ip6_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip6_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip6_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip6_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) 0 +#define ip_addr_ismulticast(ipaddr) ip6_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip6_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip6_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip6addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip6addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip6addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP6_ADDR_ANY) + +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_IPV4 + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IP wildcard. + * Defined to @ref IP4_ADDR_ANY when IPv4 is enabled. + * Defined to @ref IP6_ADDR_ANY in IPv6 only systems. + * Use this if you can handle IPv4 _AND_ IPv6 addresses. + * Use @ref IP4_ADDR_ANY or @ref IP6_ADDR_ANY when the IP + * type matters. + */ +#define IP_ADDR_ANY IP4_ADDR_ANY +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IPv4 wildcard and the broadcast address + */ +#define IP4_ADDR_ANY (&ip_addr_any) +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip4_addr_t + * for the wildcard and the broadcast address + */ +#define IP4_ADDR_ANY4 (ip_2_ip4(&ip_addr_any)) + +/** @ingroup ip4addr */ +#define IP_ADDR_BROADCAST (&ip_addr_broadcast) +/** @ingroup ip4addr */ +#define IP4_ADDR_BROADCAST (ip_2_ip4(&ip_addr_broadcast)) + +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 + +extern const ip_addr_t ip6_addr_any; + +/** + * @ingroup ip6addr + * IP6_ADDR_ANY can be used as a fixed ip_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY (&ip6_addr_any) +/** + * @ingroup ip6addr + * IP6_ADDR_ANY6 can be used as a fixed ip6_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY6 (ip_2_ip6(&ip6_addr_any)) + +#if !LWIP_IPV4 +/** IPv6-only configurations */ +#define IP_ADDR_ANY IP6_ADDR_ANY +#endif /* !LWIP_IPV4 */ + +#endif + +#if LWIP_IPV4 && LWIP_IPV6 +/** @ingroup ipaddr */ +#define IP_ANY_TYPE (&ip_addr_any_type) +#else +#define IP_ANY_TYPE IP_ADDR_ANY +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mem.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mem.h new file mode 100644 index 0000000..ff208d2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mem.h @@ -0,0 +1,82 @@ +/** + * @file + * Heap API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_MEM_H +#define LWIP_HDR_MEM_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include "lwip/arch.h" + +typedef size_t mem_size_t; +#define MEM_SIZE_F SZT_F + +#elif MEM_USE_POOLS + +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F + +#else + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000L +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ +#endif + +void mem_init(void); +void *mem_trim(void *mem, mem_size_t size); +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void mem_free(void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEM_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/memp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/memp.h new file mode 100644 index 0000000..1630b26 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/memp.h @@ -0,0 +1,155 @@ +/** + * @file + * Memory pool API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_H +#define LWIP_HDR_MEMP_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* run once with empty definition to handle all custom includes in lwippools.h */ +#define LWIP_MEMPOOL(name,num,size,desc) +#include "lwip/priv/memp_std.h" + +/** Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, +#include "lwip/priv/memp_std.h" + MEMP_MAX +} memp_t; + +#include "lwip/priv/memp_priv.h" +#include "lwip/stats.h" + +extern const struct memp_desc* const memp_pools[MEMP_MAX]; + +/** + * @ingroup mempool + * Declare prototype for private memory pool if it is used in multiple files + */ +#define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc memp_ ## name + +#if MEMP_MEM_MALLOC + +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size) \ + }; + +#else /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Declare a private memory pool + * Private mempools example: + * .h: only when pool is used in multiple .c files: LWIP_MEMPOOL_PROTOTYPE(my_private_pool); + * .c: + * - in global variables section: LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description") + * - call ONCE before using pool (e.g. in some init() function): LWIP_MEMPOOL_INIT(my_private_pool); + * - allocate: void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool); + * - free: LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem); + * + * To relocate a pool, declare it as extern in cc.h. Example for GCC: + * extern u8_t \_\_attribute\_\_((section(".onchip_mem"))) memp_memory_my_private_pool_base[]; + */ +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ + \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + \ + static struct memp *memp_tab_ ## name; \ + \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size), \ + (num), \ + memp_memory_ ## name ## _base, \ + &memp_tab_ ## name \ + }; + +#endif /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Initialize a private memory pool + */ +#define LWIP_MEMPOOL_INIT(name) memp_init_pool(&memp_ ## name) +/** + * @ingroup mempool + * Allocate from a private memory pool + */ +#define LWIP_MEMPOOL_ALLOC(name) memp_malloc_pool(&memp_ ## name) +/** + * @ingroup mempool + * Free element from a private memory pool + */ +#define LWIP_MEMPOOL_FREE(name, x) memp_free_pool(&memp_ ## name, (x)) + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. + * This has to be defined here as it is required for pool size calculation. */ +struct memp_malloc_helper +{ + memp_t poolnr; +#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) + u16_t size; +#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type); +#endif +void memp_free(memp_t type, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mld6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mld6.h new file mode 100644 index 0000000..7fa0797 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/mld6.h @@ -0,0 +1,99 @@ +/** + * @file + * + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2. + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_MLD6_H +#define LWIP_HDR_MLD6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** MLD group */ +struct mld_group { + /** next link */ + struct mld_group *next; + /** multicast address */ + ip6_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ + +err_t mld6_stop(struct netif *netif); +void mld6_report_groups(struct netif *netif); +void mld6_tmr(void); +struct mld_group *mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr); +void mld6_input(struct pbuf *p, struct netif *inp); +err_t mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); + +/** @ingroup mld6 + * Get list head of MLD6 groups for netif. + * Note: The allnodes group IP is NOT in the list, since it must always + * be received for correct IPv6 operation. + * @see @ref netif_set_mld_mac_filter() + */ +#define netif_mld6_data(netif) ((struct mld_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ + +#endif /* LWIP_HDR_MLD6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/nd6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/nd6.h new file mode 100644 index 0000000..c30e624 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/nd6.h @@ -0,0 +1,90 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_H +#define LWIP_HDR_ND6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period */ +#define ND6_TMR_INTERVAL 1000 + +/** Router solicitations are sent in 4 second intervals (see RFC 4861, ch. 6.3.7) */ +#ifndef ND6_RTR_SOLICITATION_INTERVAL +#define ND6_RTR_SOLICITATION_INTERVAL 4000 +#endif + +struct pbuf; +struct netif; + +void nd6_tmr(void); +void nd6_input(struct pbuf *p, struct netif *inp); +void nd6_clear_destination_cache(void); +struct netif *nd6_find_route(const ip6_addr_t *ip6addr); +err_t nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp); +u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); +#if LWIP_ND6_TCP_REACHABILITY_HINTS +void nd6_reachability_hint(const ip6_addr_t *ip6addr); +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ +void nd6_cleanup_netif(struct netif *netif); +#if LWIP_IPV6_MLD +void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state); +#endif /* LWIP_IPV6_MLD */ +void nd6_restart_netif(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netbuf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netbuf.h new file mode 100644 index 0000000..42a911b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netbuf.h @@ -0,0 +1,116 @@ +/** + * @file + * netbuf API (for netconn API) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETBUF_H +#define LWIP_HDR_NETBUF_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +/** "Network buffer" - contains data and addressing info */ +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY + u8_t flags; + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void); +void netbuf_delete (struct netbuf *buf); +void * netbuf_alloc (struct netbuf *buf, u16_t size); +void netbuf_free (struct netbuf *buf); +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size); +void netbuf_chain (struct netbuf *head, struct netbuf *tail); + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len); +s8_t netbuf_next (struct netbuf *buf); +void netbuf_first (struct netbuf *buf); + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(&((buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(&((buf)->toaddr), destaddr) +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#else /* LWIP_CHECKSUM_ON_COPY */ +#define netbuf_destport(buf) ((buf)->toport_chksum) +#endif /* LWIP_CHECKSUM_ON_COPY */ +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETBUF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netdb.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netdb.h new file mode 100644 index 0000000..d3d15df --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netdb.h @@ -0,0 +1,150 @@ +/** + * @file + * NETDB API (sockets) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_NETDB_H +#define LWIP_HDR_NETDB_H + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/arch.h" +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_FLAGS +#define LWIP_DNS_API_DEFINE_FLAGS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 +#define EAI_FAMILY 204 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DEFINE_FLAGS +/* input flags for struct addrinfo */ +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_NUMERICSERV 0x08 +#define AI_V4MAPPED 0x10 +#define AI_ALL 0x20 +#define AI_ADDRCONFIG 0x40 +#endif /* LWIP_DNS_API_DEFINE_FLAGS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessible error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +/** @ingroup netdbapi */ +#define gethostbyname(name) lwip_gethostbyname(name) +/** @ingroup netdbapi */ +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +/** @ingroup netdbapi */ +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +/** @ingroup netdbapi */ +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETDB_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netif.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netif.h new file mode 100644 index 0000000..9a16ded --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netif.h @@ -0,0 +1,673 @@ +/** + * @file + * netif API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_H +#define LWIP_HDR_NETIF_H + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** Must be the maximum of all used hardware address lengths + across all types of interfaces in use. + This does not have to be changed, normally. */ +#ifndef NETIF_MAX_HWADDR_LEN +#define NETIF_MAX_HWADDR_LEN 6U +#endif + +/** The size of a fully constructed netif name which the + * netif can be identified by in APIs. Composed of + * 2 chars, 3 (max) digits, and 1 \0 + */ +#define NETIF_NAMESIZE 6 + +/** + * @defgroup netif_flags Flags + * @ingroup netif + * @{ + */ + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It must be set by the startup code before this netif can be used + * (also for dhcp/autoip). + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x04U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x08U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x10U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x20U +/** If set, the netif has MLD6 capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_MLD6 0x40U + +/** + * @} + */ + +enum lwip_internal_netif_client_data_index +{ +#if LWIP_IPV4 +#if LWIP_DHCP + LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, +#endif +#if LWIP_AUTOIP + LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, +#endif +#if LWIP_IGMP + LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, +#endif +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +#if LWIP_IPV6_DHCP6 + LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, +#endif +#if LWIP_IPV6_MLD + LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, +#endif +#endif /* LWIP_IPV6 */ + LWIP_NETIF_CLIENT_DATA_INDEX_MAX +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_CHECKSUM_GEN_IP 0x0001 +#define NETIF_CHECKSUM_GEN_UDP 0x0002 +#define NETIF_CHECKSUM_GEN_TCP 0x0004 +#define NETIF_CHECKSUM_GEN_ICMP 0x0008 +#define NETIF_CHECKSUM_GEN_ICMP6 0x0010 +#define NETIF_CHECKSUM_CHECK_IP 0x0100 +#define NETIF_CHECKSUM_CHECK_UDP 0x0200 +#define NETIF_CHECKSUM_CHECK_TCP 0x0400 +#define NETIF_CHECKSUM_CHECK_ICMP 0x0800 +#define NETIF_CHECKSUM_CHECK_ICMP6 0x1000 +#define NETIF_CHECKSUM_ENABLE_ALL 0xFFFF +#define NETIF_CHECKSUM_DISABLE_ALL 0x0000 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +struct netif; + +/** MAC Filter Actions, these are passed to a netif's igmp_mac_filter or + * mld_mac_filter callback function. */ +enum netif_mac_filter_action { + /** Delete a filter entry */ + NETIF_DEL_MAC_FILTER = 0, + /** Add a filter entry */ + NETIF_ADD_MAC_FILTER = 1 +}; + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + * @return ERR_OK if the packet was handled + * != ERR_OK is the packet was NOT handled, in this case, the caller has + * to free the pbuf + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV4 +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 +/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'ethip6_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IPv6 address to which the packet shall be sent + */ +typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, + const ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ + +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +#if LWIP_IPV4 && LWIP_IGMP +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + const ip4_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** Function prototype for netif mld_mac_filter functions */ +typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, + const ip6_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if LWIP_DHCP || LWIP_AUTOIP || LWIP_IGMP || LWIP_IPV6_MLD || LWIP_IPV6_DHCP6 || (LWIP_NUM_NETIF_CLIENT_DATA > 0) +#if LWIP_NUM_NETIF_CLIENT_DATA > 0 +u8_t netif_alloc_client_data_id(void); +#endif +/** @ingroup netif_cd + * Set client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_set_client_data(netif, id, data) netif_get_client_data(netif, id) = (data) +/** @ingroup netif_cd + * Get client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_get_client_data(netif, id) (netif)->client_data[(id)] +#endif + +#if (LWIP_IPV4 && LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) || (LWIP_IPV6 && (LWIP_ND6_NUM_DESTINATIONS > 0x7f)) +typedef u16_t netif_addr_idx_t; +#define NETIF_ADDR_IDX_MAX 0x7FFF +#else +typedef u8_t netif_addr_idx_t; +#define NETIF_ADDR_IDX_MAX 0x7F +#endif + +#if LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_USE_HINTS 1 +struct netif_hint { + netif_addr_idx_t addr_hint; +}; +#else /* LWIP_NETIF_HWADDRHINT */ +#define LWIP_NETIF_USE_HINTS 0 +#endif /* LWIP_NETIF_HWADDRHINT */ + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { +#if !LWIP_SINGLE_NETIF + /** pointer to next in linked list */ + struct netif *next; +#endif + +#if LWIP_IPV4 + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Array of IPv6 addresses for this netif. */ + ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; + /** The state of each IPv6 address (Tentative, Preferred, etc). + * @see ip6_addr.h */ + u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; +#if LWIP_IPV6_ADDRESS_LIFETIMES + /** Remaining valid and preferred lifetime of each IPv6 address, in seconds. + * For valid lifetimes, the special value of IP6_ADDR_LIFE_STATIC (0) + * indicates the address is static and has no lifetimes. */ + u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES]; + u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES]; +#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ +#endif /* LWIP_IPV6 */ + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. */ + netif_input_fn input; +#if LWIP_IPV4 + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually etharp_output() */ + netif_output_fn output; +#endif /* LWIP_IPV4 */ + /** This function is called by ethernet_output() when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. */ + netif_linkoutput_fn linkoutput; +#if LWIP_IPV6 + /** This function is called by the IPv6 module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually ethip6_output() */ + netif_output_ip6_fn output_ip6; +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK + /** This function is called when the netif has been removed */ + netif_status_callback_fn remove_callback; +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. */ + void *state; +#ifdef netif_get_client_data + void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; +#endif +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + const char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ +#if LWIP_CHECKSUM_CTRL_PER_NETIF + u16_t chksum_flags; +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ + /** maximum transfer unit (in bytes) */ + u16_t mtu; +#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES + /** maximum transfer unit (in bytes), updated by RA */ + u16_t mtu6; +#endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */ + /** link level hardware address of this interface */ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** number of bytes used in hwaddr */ + u8_t hwaddr_len; + /** flags (@see @ref netif_flags) */ + u8_t flags; + /** descriptive abbreviation */ + char name[2]; + /** number of this interface. Used for @ref if_api and @ref netifapi_netif, + * as well as for IPv6 zones */ + u8_t num; +#if LWIP_IPV6_AUTOCONFIG + /** is this netif enabled for IPv6 autoconfiguration */ + u8_t ip6_autoconfig_enabled; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /** Number of Router Solicitation messages that remain to be sent. */ + u8_t rs_count; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if MIB2_STATS + /** link type (from "snmp_ifType" enum from snmp_mib2.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + struct stats_mib2_netif_ctrs mib2_counters; +#endif /* MIB2_STATS */ +#if LWIP_IPV4 && LWIP_IGMP + /** This function could be called to add or delete an entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /** This function could be called to add or delete an entry in the IPv6 multicast + filter table of the ethernet MAC. */ + netif_mld_mac_filter_fn mld_mac_filter; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if LWIP_NETIF_USE_HINTS + struct netif_hint *hints; +#endif /* LWIP_NETIF_USE_HINTS */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. */ + struct pbuf *loop_first; + struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* Used if the original scheduling failed. */ + u8_t reschedule_poll; +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ + (netif)->chksum_flags = chksumflags; } while(0) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +#if LWIP_SINGLE_NETIF +#define NETIF_FOREACH(netif) if (((netif) = netif_default) != NULL) +#else /* LWIP_SINGLE_NETIF */ +/** The list of network interfaces. */ +extern struct netif *netif_list; +#define NETIF_FOREACH(netif) for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) +#endif /* LWIP_SINGLE_NETIF */ +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void); + +struct netif *netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); + +#if LWIP_IPV4 +struct netif *netif_add(struct netif *netif, + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, + void *state, netif_init_fn init, netif_input_fn input); +void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, + const ip4_addr_t *gw); +#else /* LWIP_IPV4 */ +struct netif *netif_add(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); +#endif /* LWIP_IPV4 */ +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(const char *name); + +void netif_set_default(struct netif *netif); + +#if LWIP_IPV4 +void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); +void netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask); +void netif_set_gw(struct netif *netif, const ip4_addr_t *gw); +/** @ingroup netif_ip4 */ +#define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) +/** @ingroup netif_ip4 */ +#define netif_ip4_netmask(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->netmask))) +/** @ingroup netif_ip4 */ +#define netif_ip4_gw(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->gw))) +/** @ingroup netif_ip4 */ +#define netif_ip_addr4(netif) ((const ip_addr_t*)&((netif)->ip_addr)) +/** @ingroup netif_ip4 */ +#define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask)) +/** @ingroup netif_ip4 */ +#define netif_ip_gw4(netif) ((const ip_addr_t*)&((netif)->gw)) +#endif /* LWIP_IPV4 */ + +#define netif_set_flags(netif, set_flags) do { (netif)->flags = (u8_t)((netif)->flags | (set_flags)); } while(0) +#define netif_clear_flags(netif, clr_flags) do { (netif)->flags = (u8_t)((netif)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) +#define netif_is_flag_set(netif, flag) (((netif)->flags & (flag)) != 0) + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +/** @ingroup netif + * Ask if an interface is up + */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +/** @ingroup netif */ +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +/** @ingroup netif */ +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +/** @ingroup netif */ +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** @ingroup netif */ +#define netif_set_mld_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->mld_mac_filter = function; }}while(0) +#define netif_get_mld_mac_filter(netif) (((netif) != NULL) ? ((netif)->mld_mac_filter) : NULL) +#define netif_mld_mac_filter(netif, addr, action) do { if((netif) && (netif)->mld_mac_filter) { (netif)->mld_mac_filter((netif), (addr), (action)); }}while(0) +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +err_t netif_input(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV6 +/** @ingroup netif_ip6 */ +#define netif_ip_addr6(netif, i) ((const ip_addr_t*)(&((netif)->ip6_addr[i]))) +/** @ingroup netif_ip6 */ +#define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) +void netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6); +void netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3); +#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) +void netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state); +s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr); +void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit); +err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx); +#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0) +#if LWIP_IPV6_ADDRESS_LIFETIMES +#define netif_ip6_addr_valid_life(netif, i) \ + (((netif) != NULL) ? ((netif)->ip6_addr_valid_life[i]) : IP6_ADDR_LIFE_STATIC) +#define netif_ip6_addr_set_valid_life(netif, i, secs) \ + do { if (netif != NULL) { (netif)->ip6_addr_valid_life[i] = (secs); }} while (0) +#define netif_ip6_addr_pref_life(netif, i) \ + (((netif) != NULL) ? ((netif)->ip6_addr_pref_life[i]) : IP6_ADDR_LIFE_STATIC) +#define netif_ip6_addr_set_pref_life(netif, i, secs) \ + do { if (netif != NULL) { (netif)->ip6_addr_pref_life[i] = (secs); }} while (0) +#define netif_ip6_addr_isstatic(netif, i) \ + (netif_ip6_addr_valid_life((netif), (i)) == IP6_ADDR_LIFE_STATIC) +#else /* !LWIP_IPV6_ADDRESS_LIFETIMES */ +#define netif_ip6_addr_isstatic(netif, i) (1) /* all addresses are static */ +#endif /* !LWIP_IPV6_ADDRESS_LIFETIMES */ +#if LWIP_ND6_ALLOW_RA_UPDATES +#define netif_mtu6(netif) ((netif)->mtu6) +#else /* LWIP_ND6_ALLOW_RA_UPDATES */ +#define netif_mtu6(netif) ((netif)->mtu) +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ +#endif /* LWIP_IPV6 */ + +#if LWIP_NETIF_USE_HINTS +#define NETIF_SET_HINTS(netif, netifhint) (netif)->hints = (netifhint) +#define NETIF_RESET_HINTS(netif) (netif)->hints = NULL +#else /* LWIP_NETIF_USE_HINTS */ +#define NETIF_SET_HINTS(netif, netifhint) +#define NETIF_RESET_HINTS(netif) +#endif /* LWIP_NETIF_USE_HINTS */ + +u8_t netif_name_to_index(const char *name); +char * netif_index_to_name(u8_t idx, char *name); +struct netif* netif_get_by_index(u8_t idx); + +/* Interface indexes always start at 1 per RFC 3493, section 4, num starts at 0 (internal index is 0..254)*/ +#define netif_get_index(netif) ((u8_t)((netif)->num + 1)) +#define NETIF_NO_INDEX (0) + +/** + * @ingroup netif + * Extended netif status callback (NSC) reasons flags. + * May be extended in the future! + */ +typedef u16_t netif_nsc_reason_t; + +/* used for initialization only */ +#define LWIP_NSC_NONE 0x0000 +/** netif was added. arg: NULL. Called AFTER netif was added. */ +#define LWIP_NSC_NETIF_ADDED 0x0001 +/** netif was removed. arg: NULL. Called BEFORE netif is removed. */ +#define LWIP_NSC_NETIF_REMOVED 0x0002 +/** link changed */ +#define LWIP_NSC_LINK_CHANGED 0x0004 +/** netif administrative status changed.\n + * up is called AFTER netif is set up.\n + * down is called BEFORE the netif is actually set down. */ +#define LWIP_NSC_STATUS_CHANGED 0x0008 +/** IPv4 address has changed */ +#define LWIP_NSC_IPV4_ADDRESS_CHANGED 0x0010 +/** IPv4 gateway has changed */ +#define LWIP_NSC_IPV4_GATEWAY_CHANGED 0x0020 +/** IPv4 netmask has changed */ +#define LWIP_NSC_IPV4_NETMASK_CHANGED 0x0040 +/** called AFTER IPv4 address/gateway/netmask changes have been applied */ +#define LWIP_NSC_IPV4_SETTINGS_CHANGED 0x0080 +/** IPv6 address was added */ +#define LWIP_NSC_IPV6_SET 0x0100 +/** IPv6 address state has changed */ +#define LWIP_NSC_IPV6_ADDR_STATE_CHANGED 0x0200 + +/** @ingroup netif + * Argument supplied to netif_ext_callback_fn. + */ +typedef union +{ + /** Args to LWIP_NSC_LINK_CHANGED callback */ + struct link_changed_s + { + /** 1: up; 0: down */ + u8_t state; + } link_changed; + /** Args to LWIP_NSC_STATUS_CHANGED callback */ + struct status_changed_s + { + /** 1: up; 0: down */ + u8_t state; + } status_changed; + /** Args to LWIP_NSC_IPV4_ADDRESS_CHANGED|LWIP_NSC_IPV4_GATEWAY_CHANGED|LWIP_NSC_IPV4_NETMASK_CHANGED|LWIP_NSC_IPV4_SETTINGS_CHANGED callback */ + struct ipv4_changed_s + { + /** Old IPv4 address */ + const ip_addr_t* old_address; + const ip_addr_t* old_netmask; + const ip_addr_t* old_gw; + } ipv4_changed; + /** Args to LWIP_NSC_IPV6_SET callback */ + struct ipv6_set_s + { + /** Index of changed IPv6 address */ + s8_t addr_index; + /** Old IPv6 address */ + const ip_addr_t* old_address; + } ipv6_set; + /** Args to LWIP_NSC_IPV6_ADDR_STATE_CHANGED callback */ + struct ipv6_addr_state_changed_s + { + /** Index of affected IPv6 address */ + s8_t addr_index; + /** Old IPv6 address state */ + u8_t old_state; + /** Affected IPv6 address */ + const ip_addr_t* address; + } ipv6_addr_state_changed; +} netif_ext_callback_args_t; + +/** + * @ingroup netif + * Function used for extended netif status callbacks + * Note: When parsing reason argument, keep in mind that more reasons may be added in the future! + * @param netif netif that is affected by change + * @param reason change reason + * @param args depends on reason, see reason description + */ +typedef void (*netif_ext_callback_fn)(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args); + +#if LWIP_NETIF_EXT_STATUS_CALLBACK +struct netif_ext_callback; +typedef struct netif_ext_callback +{ + netif_ext_callback_fn callback_fn; + struct netif_ext_callback* next; +} netif_ext_callback_t; + +#define NETIF_DECLARE_EXT_CALLBACK(name) static netif_ext_callback_t name; +void netif_add_ext_callback(netif_ext_callback_t* callback, netif_ext_callback_fn fn); +void netif_remove_ext_callback(netif_ext_callback_t* callback); +void netif_invoke_ext_callback(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args); +#else +#define NETIF_DECLARE_EXT_CALLBACK(name) +#define netif_add_ext_callback(callback, fn) +#define netif_remove_ext_callback(callback) +#define netif_invoke_ext_callback(netif, reason, args) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netifapi.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netifapi.h new file mode 100644 index 0000000..e063179 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/netifapi.h @@ -0,0 +1,161 @@ +/** + * @file + * netif API (to be used from non-TCPIP threads) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_NETIFAPI_H +#define LWIP_HDR_NETIFAPI_H + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/api_msg.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* API for application */ +#if LWIP_ARP && LWIP_IPV4 +/* Used for netfiapi_arp_* APIs */ +enum netifapi_arp_entry { + NETIFAPI_ARP_PERM /* Permanent entry */ + /* Other entry types can be added here */ +}; + +/** @ingroup netifapi_arp */ +err_t netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type); +/** @ingroup netifapi_arp */ +err_t netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type); +#endif /* LWIP_ARP && LWIP_IPV4 */ + +err_t netifapi_netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input); + +#if LWIP_IPV4 +err_t netifapi_netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, const ip4_addr_t *gw); +#endif /* LWIP_IPV4*/ + +err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +/** @ingroup netifapi_netif */ +err_t netifapi_netif_name_to_index(const char *name, u8_t *index); +/** @ingroup netifapi_netif */ +err_t netifapi_netif_index_to_name(u8_t index, char *name); + +/** @ingroup netifapi_netif + * @see netif_remove() + */ +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +/** @ingroup netifapi_netif + * @see netif_set_up() + */ +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +/** @ingroup netifapi_netif + * @see netif_set_down() + */ +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +/** @ingroup netifapi_netif + * @see netif_set_default() + */ +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +/** @ingroup netifapi_netif + * @see netif_set_link_up() + */ +#define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL) +/** @ingroup netifapi_netif + * @see netif_set_link_down() + */ +#define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL) + +/** + * @defgroup netifapi_dhcp4 DHCPv4 + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_dhcp4 + * @see dhcp_start() + */ +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +/** + * @ingroup netifapi_dhcp4 + * @deprecated Use netifapi_dhcp_release_and_stop() instead. + */ +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +/** @ingroup netifapi_dhcp4 + * @see dhcp_inform() + */ +#define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) +/** @ingroup netifapi_dhcp4 + * @see dhcp_renew() + */ +#define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) +/** + * @ingroup netifapi_dhcp4 + * @deprecated Use netifapi_dhcp_release_and_stop() instead. + */ +#define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) +/** @ingroup netifapi_dhcp4 + * @see dhcp_release_and_stop() + */ +#define netifapi_dhcp_release_and_stop(n) netifapi_netif_common(n, dhcp_release_and_stop, NULL) + +/** + * @defgroup netifapi_autoip AUTOIP + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_autoip + * @see autoip_start() + */ +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +/** @ingroup netifapi_autoip + * @see autoip_stop() + */ +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* LWIP_HDR_NETIFAPI_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/opt.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/opt.h new file mode 100644 index 0000000..d8c82d1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/opt.h @@ -0,0 +1,3526 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - + * without this, doxygen does not see the actual #define + */ + +#if !defined LWIP_HDR_OPT_H +#define LWIP_HDR_OPT_H + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/** + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts + */ + + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ +#define NO_SYS 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif + +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * MEMMOVE: override this if you have a faster implementation at hand than the + * one included in your C library. lwIP currently uses MEMMOVE only when IPv6 + * fragmentation support is enabled. + */ +#if !defined MEMMOVE || defined __DOXYGEN__ +#define MEMMOVE(dst,src,len) memmove(dst,src,len) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 1 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif + +/** + * Macro/function to check whether lwIP's threading/locking + * requirements are satisfied during current function call. + * This macro usually calls a function that is implemented in the OS-dependent + * sys layer and performs the following checks: + * - Not in ISR (this should be checked for NO_SYS==1, too!) + * - If @ref LWIP_TCPIP_CORE_LOCKING = 1: TCPIP core lock is held + * - If @ref LWIP_TCPIP_CORE_LOCKING = 0: function is called from TCPIP thread + * @see @ref multithreading + */ +#if !defined LWIP_ASSERT_CORE_LOCKED || defined __DOXYGEN__ +#define LWIP_ASSERT_CORE_LOCKED() +#endif + +/** + * Called as first thing in the lwIP TCPIP thread. Can be used in conjunction + * with @ref LWIP_ASSERT_CORE_LOCKED to check core locking. + * @see @ref multithreading + */ +#if !defined LWIP_MARK_TCPIP_THREAD || defined __DOXYGEN__ +#define LWIP_MARK_TCPIP_THREAD() +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 0 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEMP_MEM_INIT==1: Force use of memset to initialize pool memory. + * Useful if pool are moved in uninitialized section of memory. This will ensure + * default values in pcbs struct are well initialized in all conditions. + */ +#if !defined MEMP_MEM_INIT || defined __DOXYGEN__ +#define MEMP_MEM_INIT 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 + */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_OVERFLOW_CHECK: mem overflow protection reserves a configurable + * amount of bytes before and after each heap allocation chunk and fills + * it with a prominent default value. + * MEM_OVERFLOW_CHECK == 0 no checking + * MEM_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEM_OVERFLOW_CHECK >= 2 checks all heap elements every time + * mem_malloc() or mem_free() is called (useful but slow!) + */ +#if !defined MEM_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEM_OVERFLOW_CHECK 0 +#endif + +/** + * MEM_SANITY_CHECK==1: run a sanity check after each mem_free() to make + * sure that the linked list of heap elements is not corrupted. + */ +#if !defined MEM_SANITY_CHECK || defined __DOXYGEN__ +#define MEM_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_ALTCP_PCB: the number of simultaneously active altcp layer pcbs. + * (requires the LWIP_ALTCP option) + * Connections with multiple layers require more than one altcp_pcb (e.g. TLS + * over TCP requires 2 altcp_pcbs, one for TLS and one for TCP). + */ +#if !defined MEMP_NUM_ALTCP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * The number of sys timeouts used by the core stack (not apps) + * The default number of timeouts is calculated here for all enabled modules. + */ +#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD))) + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT LWIP_NUM_SYS_TIMEOUT_INTERNAL +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_SELECT_CB: the number of struct lwip_select_cb. + * (Only needed if you have LWIP_MPU_COMPATIBLE==1 and use the socket API. + * In that case, you need one per thread calling lwip_select.) + */ +#if !defined MEMP_NUM_SELECT_CB || defined __DOXYGEN__ +#define MEMP_NUM_SELECT_CB 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 16 +#endif + +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#if !defined LWIP_ARP || defined __DOXYGEN__ +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 10 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 0 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 3 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#if !defined IP_FORWARD || defined __DOXYGEN__ +#define IP_FORWARD 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ +#define IP_REASSEMBLY 1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#if !defined IP_FRAG || defined __DOXYGEN__ +#define IP_FRAG 1 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ +#define IP_REASS_MAXAGE 15 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + * When IPv4 *and* IPv6 are enabled, this even changes to + * (PBUF_POOL_SIZE > 2 * IP_REASS_MAX_PBUFS)! + */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL IP_DEFAULT_TTL +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL IP_DEFAULT_TTL +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ +#define LWIP_DHCP 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK (LWIP_DHCP && LWIP_ARP) +#endif + +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 0 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DNS servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ +#define LWIP_AUTOIP 0 +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + -------- Multicast options ------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_multicast Multicast + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP, as well as (currently only) + * core support for the corresponding IPv6 options. + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ +#define LWIP_IGMP 0 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#if !defined LWIP_DNS || defined __DOXYGEN__ +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS maximum number of retries when asking for a name, before "timeout". */ +#if !defined DNS_MAX_RETRIES || defined __DOXYGEN__ +#define DNS_MAX_RETRIES 4 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#if !defined LWIP_UDP || defined __DOXYGEN__ +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL IP_DEFAULT_TTL +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL IP_DEFAULT_TTL +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ LWIP_TCP +#endif + +/** + * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). + */ +#if !defined LWIP_TCP_SACK_OUT || defined __DOXYGEN__ +#define LWIP_TCP_SACK_OUT 0 +#endif + +/** + * LWIP_TCP_MAX_SACK_NUM: The maximum number of SACK values to include in TCP segments. + * Must be at least 1, but is only used if LWIP_TCP_SACK_OUT is enabled. + * NOTE: Even though we never send more than 3 or 4 SACK ranges in a single segment + * (depending on other options), setting this option to values greater than 4 is not pointless. + * This is basically the max number of SACK ranges we want to keep track of. + * As new data is delivered, some of the SACK ranges may be removed or merged. + * In that case some of those older SACK ranges may be used again. + * The amount of memory used to store SACK ranges is LWIP_TCP_MAX_SACK_NUM * 8 bytes for each TCP PCB. + */ +#if !defined LWIP_TCP_MAX_SACK_NUM || defined __DOXYGEN__ +#define LWIP_TCP_MAX_SACK_NUM 4 +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF (2 * TCP_MSS) +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The default maximum number of bytes queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_BYTES_LIMIT(pcb): Return the maximum number of bytes to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && + * TCP_OOSEQ_MAX_BYTES==1. + * Use this to override TCP_OOSEQ_MAX_BYTES to a dynamic value per pcb. + */ +#if !defined TCP_OOSEQ_BYTES_LIMIT +#if TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#elif defined __DOXYGEN__ +#define TCP_OOSEQ_BYTES_LIMIT(pcb) +#endif +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The default maximum number of pbufs queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_OOSEQ_PBUFS_LIMIT(pcb): Return the maximum number of pbufs to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && + * TCP_OOSEQ_MAX_PBUFS==1. + * Use this to override TCP_OOSEQ_MAX_PBUFS to a dynamic value per pcb. + */ +#if !defined TCP_OOSEQ_PBUFS_LIMIT +#if TCP_OOSEQ_MAX_PBUFS +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#elif defined __DOXYGEN__ +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) +#endif +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif + +/** + * LWIP_TCP_PCB_NUM_EXT_ARGS: + * When this is > 0, every tcp pcb (including listen pcb) includes a number of + * additional argument entries in an array (see tcp_ext_arg_alloc_id) + */ +#if !defined LWIP_TCP_PCB_NUM_EXT_ARGS || defined __DOXYGEN__ +#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 +#endif + +/** LWIP_ALTCP==1: enable the altcp API. + * altcp is an abstraction layer that prevents applications linking against the + * tcp.h functions but provides the same functionality. It is used to e.g. add + * SSL/TLS or proxy-connect support to an application written for the tcp callback + * API without that application knowing the protocol details. + * + * With LWIP_ALTCP==0, applications written against the altcp API can still be + * compiled but are directly linked against the tcp.h callback API and then + * cannot use layered protocols. + * + * See @ref altcp_api + */ +#if !defined LWIP_ALTCP || defined __DOXYGEN__ +#define LWIP_ALTCP 0 +#endif + +/** LWIP_ALTCP_TLS==1: enable TLS support for altcp API. + * This needs a port of the functions in altcp_tls.h to a TLS library. + * A port to ARM mbedtls is provided with lwIP, see apps/altcp_tls/ directory + * and LWIP_ALTCP_TLS_MBEDTLS option. + */ +#if !defined LWIP_ALTCP_TLS || defined __DOXYGEN__ +#define LWIP_ALTCP_TLS 0 +#endif + +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 0 +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+PBUF_IP_HLEN+PBUF_TRANSPORT_HLEN+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif + +/** + * LWIP_PBUF_REF_T: Refcount type in pbuf. + * Default width of u8_t can be increased if 255 refs are not enough for you. + */ +#if !defined LWIP_PBUF_REF_T || defined __DOXYGEN__ +#define LWIP_PBUF_REF_T u8_t +#endif + +/** + * LWIP_PBUF_CUSTOM_DATA: Store private data on pbufs (e.g. timestamps) + * This extends struct pbuf so user can store custom data on every pbuf. + */ +#if !defined LWIP_PBUF_CUSTOM_DATA || defined __DOXYGEN__ +#define LWIP_PBUF_CUSTOM_DATA +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for + * small real-life targets. Some code like routing etc. can be left out. + */ +#if !defined LWIP_SINGLE_NETIF || defined __DOXYGEN__ +#define LWIP_SINGLE_NETIF 0 +#endif + +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * for several netif related event that supports multiple subscribers. + * @see netif_ext_status_callback + */ +#if !defined LWIP_NETIF_EXT_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP *tries* to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * ATTENTION: a driver should *NOT* rely on getting single pbufs but check TX + * pbufs for being in one piece. If not, @ref pbuf_clone can be used to get + * a single pbuf: + * if (p->next != NULL) { + * struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); + * if (q == NULL) { + * return ERR_MEM; + * } + * p = q; ATTENTION: do NOT free the old 'p' as the ref belongs to the caller! + * } + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif (max. 256). + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 1 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once! + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 0 +#endif + +/** + * LWIP_SOCKET_SELECT==1 (default): enable select() for sockets (uses a netconn + * callback to keep track of events). + * This saves RAM (counters per socket) and code (netconn event callback), which + * should improve performance a bit). + */ +#if !defined LWIP_SOCKET_SELECT || defined __DOXYGEN__ +#define LWIP_SOCKET_SELECT 1 +#endif + +/** + * LWIP_SOCKET_POLL==1 (default): enable poll() for sockets (including + * struct pollfd, nfds_t, and constants) + */ +#if !defined LWIP_SOCKET_POLL || defined __DOXYGEN__ +#define LWIP_SOCKET_POLL 1 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} + */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#endif + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 0 +#endif + +/** + * IPV6_REASS_MAXAGE: Maximum time (in multiples of IP6_REASS_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IPV6_REASS_MAXAGE || defined __DOXYGEN__ +#define IPV6_REASS_MAXAGE 60 +#endif + +/** + * LWIP_IPV6_SCOPES==1: Enable support for IPv6 address scopes, ensuring that + * e.g. link-local addresses are really treated as link-local. Disable this + * setting only for single-interface configurations. + * All addresses that have a scope according to the default policy (link-local + * unicast addresses, interface-local and link-local multicast addresses) should + * now have a zone set on them before being passed to the core API, although + * lwIP will currently attempt to select a zone on the caller's behalf when + * necessary. Applications that directly assign IPv6 addresses to interfaces + * (which is NOT recommended) must now ensure that link-local addresses carry + * the netif's zone. See the new ip6_zone.h header file for more information and + * relevant macros. For now it is still possible to turn off scopes support + * through the new LWIP_IPV6_SCOPES option. When upgrading an implementation that + * uses the core API directly, it is highly recommended to enable + * LWIP_IPV6_SCOPES_DEBUG at least for a while, to ensure e.g. proper address + * initialization. + */ +#if !defined LWIP_IPV6_SCOPES || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_IPV6_SCOPES_DEBUG==1: Perform run-time checks to verify that addresses + * are properly zoned (see ip6_zone.h on what that means) where it matters. + * Enabling this setting is highly recommended when upgrading from an existing + * installation that is not yet scope-aware; otherwise it may be too expensive. + */ +#if !defined LWIP_IPV6_SCOPES_DEBUG || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES_DEBUG 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 1 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS LWIP_IPV6 +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT LWIP_IPV6 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG LWIP_IPV6 +#endif + +/** + * LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each + * IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled + * otherwise, in which case the application may assign address lifetimes with + * the appropriate macros. Addresses with no lifetime are assumed to be static. + * If this option is disabled, all addresses are assumed to be static. + */ +#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__ +#define LWIP_IPV6_ADDRESS_LIFETIMES LWIP_IPV6_AUTOCONFIG +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 LWIP_IPV6 +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages (0 = default of IP6_MIN_MTU_LENGTH) + * ATTENTION: RFC4443 section 2.4 says IP6_MIN_MTU_LENGTH is a MUST, + * so override this only if you absolutely have to! + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 0 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD LWIP_IPV6 +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING LWIP_IPV6 +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_dhcpv6 DHCPv6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful/stateless address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/** + * LWIP_IPV6_DHCP6_STATEFUL==1: enable DHCPv6 stateful address autoconfiguration. + * (not supported, yet!) + */ +#if !defined LWIP_IPV6_DHCP6_STATEFUL || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6_STATEFUL 0 +#endif + +/** + * LWIP_IPV6_DHCP6_STATELESS==1: enable DHCPv6 stateless address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6_STATELESS || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 +#endif + +/** + * LWIP_DHCP6_GETS_NTP==1: Request NTP servers via DHCPv6. For each + * response packet, a callback is called, which has to be provided by the port: + * void dhcp6_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP6_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP6_GET_NTP_SRV 0 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP6_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP6_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP6_MAX_DNS_SERVERS > 0: Request DNS servers via DHCPv6. + * DNS servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP6_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to \#include in files that provide hooks. + * Declare your hook function prototypes in there, you may also \#include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature:\code{.c} + * u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * \endcode + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_TCP_INPACKET_PCB: + * Hook for intercepting incoming packets before they are passed to a pcb. This + * allows updating some state or even dropping a packet. + * Signature:\code{.c} + * err_t my_hook_tcp_inpkt(struct tcp_pcb *pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p); + * \endcode + * Arguments: + * - pcb: tcp_pcb selected for input of this packet (ATTENTION: this may be + * struct tcp_pcb_listen if pcb->state == LISTEN) + * - hdr: pointer to tcp header (ATTENTION: tcp options may not be in one piece!) + * - optlen: tcp option length + * - opt1len: tcp option length 1st part + * - opt2: if this is != NULL, tcp options are split among 2 pbufs. In that case, + * options start at right after the tcp header ('(u8_t*)(hdr + 1)') for + * the first 'opt1len' bytes and the rest starts at 'opt2'. opt2len can + * be simply calculated: 'opt2len = optlen - opt1len;' + * - p: input packet, p->payload points to application data (that's why tcp hdr + * and options are passed in seperately) + * Return value: + * - ERR_OK: continue input of this packet as normal + * - != ERR_OK: drop this packet for input (don't continue input processing) + * + * ATTENTION: don't call any tcp api functions that might change tcp state (pcb + * state or any pcb lists) from this callback! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) +#endif + +/** + * LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH: + * Hook for increasing the size of the options allocated with a tcp header. + * Together with LWIP_HOOK_TCP_OUT_ADD_TCPOPTS, this can be used to add custom + * options to outgoing tcp segments. + * Signature:\code{.c} + * u8_t my_hook_tcp_out_tcpopt_length(const struct tcp_pcb *pcb, u8_t internal_option_length); + * \endcode + * Arguments: + * - pcb: tcp_pcb that transmits (ATTENTION: this may be NULL or + * struct tcp_pcb_listen if pcb->state == LISTEN) + * - internal_option_length: tcp option length used by the stack internally + * Return value: + * - a number of bytes to allocate for tcp options (internal_option_length <= ret <= 40) + * + * ATTENTION: don't call any tcp api functions that might change tcp state (pcb + * state or any pcb lists) from this callback! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH(pcb, internal_len) +#endif + +/** + * LWIP_HOOK_TCP_OUT_ADD_TCPOPTS: + * Hook for adding custom options to outgoing tcp segments. + * Space for these custom options has to be reserved via LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH. + * Signature:\code{.c} + * u32_t *my_hook_tcp_out_add_tcpopts(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts); + * \endcode + * Arguments: + * - p: output packet, p->payload pointing to tcp header, data follows + * - hdr: tcp header + * - pcb: tcp_pcb that transmits (ATTENTION: this may be NULL or + * struct tcp_pcb_listen if pcb->state == LISTEN) + * - opts: pointer where to add the custom options (there may already be options + * between the header and these) + * Return value: + * - pointer pointing directly after the inserted options + * + * ATTENTION: don't call any tcp api functions that might change tcp state (pcb + * state or any pcb lists) from this callback! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(p, hdr, pcb, opts) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * Called from ip_input() (IPv4) + * Signature:\code{.c} + * int my_hook(struct pbuf *pbuf, struct netif *input_netif); + * \endcode + * Arguments: + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * Called from ip_route() (IPv4) + * Signature:\code{.c} + * struct netif *my_hook(const ip4_addr_t *dest); + * \endcode + * Arguments: + * - dest: destination IPv4 address + * Returns values: + * - the destination netif + * - NULL if no destination netif is found. In that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(src, dest): + * Source-based routing for IPv4 - called from ip_route() (IPv4) + * Signature:\code{.c} + * struct netif *my_hook(const ip4_addr_t *src, const ip4_addr_t *dest); + * \endcode + * Arguments: + * - src: local/source IPv4 address + * - dest: destination IPv4 address + * Returns values: + * - the destination netif + * - NULL if no destination netif is found. In that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(src, dest) +#endif + +/** + * LWIP_HOOK_IP4_CANFORWARD(src, dest): + * Check if an IPv4 can be forwarded - called from: + * ip4_input() -> ip4_forward() -> ip4_canforward() (IPv4) + * - source address is available via ip4_current_src_addr() + * - calling an output function in this context (e.g. multicast router) is allowed + * Signature:\code{.c} + * int my_hook(struct pbuf *p, u32_t dest_addr_hostorder); + * \endcode + * Arguments: + * - p: packet to forward + * - dest: destination IPv4 address + * Returns values: + * - 1: forward + * - 0: don't forward + * - -1: no decision. In that case, ip4_canforward() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_CANFORWARD(src, dest) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * Called from etharp_output() (IPv4) + * Signature:\code{.c} + * const ip4_addr_t *my_hook(struct netif *netif, const ip4_addr_t *dest); + * \endcode + * Arguments: + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Return values: + * - the IPv4 address of the gateway to handle the specified destination IPv4 address + * - NULL, in which case the netif's default gateway is used + * + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * Called from ip6_input() (IPv6) + * Signature:\code{.c} + * int my_hook(struct pbuf *pbuf, struct netif *input_netif); + * \endcode + * Arguments: + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * Called from ip_route() (IPv6) + * Signature:\code{.c} + * struct netif *my_hook(const ip6_addr_t *dest, const ip6_addr_t *src); + * \endcode + * Arguments: + * - src: source IPv6 address + * - dest: destination IPv6 address + * Return values: + * - the destination netif + * - NULL if no destination netif is found. In that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * Called from nd6_get_next_hop_entry() (IPv6) + * Signature:\code{.c} + * const ip6_addr_t *my_hook(struct netif *netif, const ip6_addr_t *dest); + * \endcode + * Arguments: + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Return values: + * - the IPv6 address of the next hop to handle the specified destination IPv6 address + * - NULL, in which case a NDP-discovered router is used instead + * + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * Called from ethernet_input() if VLAN support is enabled + * Signature:\code{.c} + * int my_hook(struct netif *netif, struct eth_hdr *eth_hdr, struct eth_vlan_hdr *vlan_hdr); + * \endcode + * Arguments: + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature:\code{.c} + * s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * \endcode + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * Called from memp_free() when a memp pool was empty and an item is now available + * Signature:\code{.c} + * void my_hook(memp_t type); + * \endcode + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Signature:\code{.c} + * err_t my_hook(struct pbuf* pbuf, struct netif* netif); + * \endcode + * Arguments: + * - p: rx packet with unknown eth type + * - netif: netif on which the packet has been received + * Return values: + * - ERR_OK if packet is accepted (hook function now owns the pbuf) + * - any error code otherwise (pbuf is freed) + * + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif + +/** + * LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr): + * Called from various dhcp functions when sending a DHCP message. + * This hook is called just before the DHCP message trailer is added, so the + * options are at the end of a DHCP message. + * Signature:\code{.c} + * void my_hook(struct netif *netif, struct dhcp *dhcp, u8_t state, struct dhcp_msg *msg, + * u8_t msg_type, u16_t *options_len_ptr); + * \endcode + * Arguments: + * - netif: struct netif that the packet will be sent through + * - dhcp: struct dhcp on that netif + * - state: current dhcp state (dhcp_state_enum_t as an u8_t) + * - msg: struct dhcp_msg that will be sent + * - msg_type: dhcp message type to be sent (u8_t) + * - options_len_ptr: pointer to the current length of options in the dhcp_msg "msg" + * (must be increased when options are added!) + * + * Options need to appended like this: + * LWIP_ASSERT("dhcp option overflow", *options_len_ptr + option_len + 2 <= DHCP_OPTIONS_LEN); + * msg->options[(*options_len_ptr)++] = <option_number>; + * msg->options[(*options_len_ptr)++] = <option_len>; + * msg->options[(*options_len_ptr)++] = <option_bytes>; + * [...] + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) +#endif + +/** + * LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, option_value_offset): + * Called from dhcp_parse_reply when receiving a DHCP message. + * This hook is called for every option in the received message that is not handled internally. + * Signature:\code{.c} + * void my_hook(struct netif *netif, struct dhcp *dhcp, u8_t state, struct dhcp_msg *msg, + * u8_t msg_type, u8_t option, u8_t option_len, struct pbuf *pbuf, u16_t option_value_offset); + * \endcode + * Arguments: + * - netif: struct netif that the packet will be sent through + * - dhcp: struct dhcp on that netif + * - state: current dhcp state (dhcp_state_enum_t as an u8_t) + * - msg: struct dhcp_msg that was received + * - msg_type: dhcp message type received (u8_t, ATTENTION: only valid after + * the message type option has been parsed!) + * - option: option value (u8_t) + * - len: option data length (u8_t) + * - pbuf: pbuf where option data is contained + * - option_value_offset: offset in pbuf where option data begins + * + * A nice way to get the option contents is pbuf_get_contiguous(): + * u8_t buf[32]; + * u8_t *ptr = (u8_t*)pbuf_get_contiguous(p, buf, sizeof(buf), LWIP_MIN(option_len, sizeof(buf)), offset); + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) +#endif + +/** + * LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len): + * Called from various dhcp6 functions when sending a DHCP6 message. + * This hook is called just before the DHCP6 message is sent, so the + * options are at the end of a DHCP6 message. + * Signature:\code{.c} + * void my_hook(struct netif *netif, struct dhcp6 *dhcp, u8_t state, struct dhcp6_msg *msg, + * u8_t msg_type, u16_t *options_len_ptr); + * \endcode + * Arguments: + * - netif: struct netif that the packet will be sent through + * - dhcp6: struct dhcp6 on that netif + * - state: current dhcp6 state (dhcp6_state_enum_t as an u8_t) + * - msg: struct dhcp6_msg that will be sent + * - msg_type: dhcp6 message type to be sent (u8_t) + * - options_len_ptr: pointer to the current length of options in the dhcp6_msg "msg" + * (must be increased when options are added!) + * + * Options need to appended like this: + * u8_t *options = (u8_t *)(msg + 1); + * LWIP_ASSERT("dhcp option overflow", sizeof(struct dhcp6_msg) + *options_len_ptr + newoptlen <= max_len); + * options[(*options_len_ptr)++] = <option_data>; + * [...] + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len) +#endif + +/** + * LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) + * Called from socket API to implement setsockopt() for options not provided by lwIP. + * Core lock is held when this hook is called. + * Signature:\code{.c} + * int my_hook(int s, struct lwip_sock *sock, int level, int optname, const void *optval, socklen_t optlen, int *err) + * \endcode + * Arguments: + * - s: socket file descriptor + * - sock: internal socket descriptor (see lwip/priv/sockets_priv.h) + * - level: protocol level at which the option resides + * - optname: option to set + * - optval: value to set + * - optlen: size of optval + * - err: output error + * Return values: + * - 0: Hook has not consumed the option, code continues as normal (to internal options) + * - != 0: Hook has consumed the option, 'err' is returned + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) +#endif + +/** + * LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) + * Called from socket API to implement getsockopt() for options not provided by lwIP. + * Core lock is held when this hook is called. + * Signature:\code{.c} + * int my_hook(int s, struct lwip_sock *sock, int level, int optname, void *optval, socklen_t *optlen, int *err) + * \endcode + * Arguments: + * - s: socket file descriptor + * - sock: internal socket descriptor (see lwip/priv/sockets_priv.h) + * - level: protocol level at which the option resides + * - optname: option to get + * - optval: value to get + * - optlen: size of optval + * - err: output error + * Return values: + * - 0: Hook has not consumed the option, code continues as normal (to internal options) + * - != 0: Hook has consumed the option, 'err' is returned + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) +#endif + +/** + * LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, addrtype, err) + * Called from netconn APIs (not usable with callback apps) allowing an + * external DNS resolver (which uses sequential API) to handle the query. + * Signature:\code{.c} + * int my_hook(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err) + * \endcode + * Arguments: + * - name: hostname to resolve + * - addr: output host address + * - addrtype: type of address to query + * - err: output error + * Return values: + * - 0: Hook has not consumed hostname query, query continues into DNS module + * - != 0: Hook has consumed the query + * + * err must also be checked to determine if the hook consumed the query, but + * the query failed + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, addrtype, err) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP6_DEBUG: Enable debugging in dhcp6.c. + */ +#if !defined DHCP6_DEBUG || defined __DOXYGEN__ +#define DHCP6_DEBUG LWIP_DBG_OFF +#endif +/** + * @} + */ + +/** + * LWIP_TESTMODE: Changes to make unit test possible + */ +#if !defined LWIP_TESTMODE +#define LWIP_TESTMODE 0 +#endif + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + +#endif /* LWIP_HDR_OPT_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/pbuf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/pbuf.h new file mode 100644 index 0000000..e5daf96 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/pbuf.h @@ -0,0 +1,326 @@ +/** + * @file + * pbuf API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_PBUF_H +#define LWIP_HDR_PBUF_H + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** LWIP_SUPPORT_CUSTOM_PBUF==1: Custom pbufs behave much like their pbuf type + * but they are allocated by external code (initialised by calling + * pbuf_alloced_custom()) and when pbuf_free gives up their last reference, they + * are freed by calling pbuf_custom->custom_free_function(). + * Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG, unless required by external driver/application code. */ +#ifndef LWIP_SUPPORT_CUSTOM_PBUF +#define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) +#endif + +/** @ingroup pbuf + * PBUF_NEEDS_COPY(p): return a boolean value indicating whether the given + * pbuf needs to be copied in order to be kept around beyond the current call + * stack without risking being corrupted. The default setting provides safety: + * it will make a copy iof any pbuf chain that does not consist entirely of + * PBUF_ROM type pbufs. For setups with zero-copy support, it may be redefined + * to evaluate to true in all cases, for example. However, doing so also has an + * effect on the application side: any buffers that are *not* copied must also + * *not* be reused by the application after passing them to lwIP. For example, + * when setting PBUF_NEEDS_COPY to (0), after using udp_send() with a PBUF_RAM + * pbuf, the application must free the pbuf immediately, rather than reusing it + * for other purposes. For more background information on this, see tasks #6735 + * and #7896, and bugs #11400 and #49914. */ +#ifndef PBUF_NEEDS_COPY +#define PBUF_NEEDS_COPY(p) ((p)->type_internal & PBUF_TYPE_FLAG_DATA_VOLATILE) +#endif /* PBUF_NEEDS_COPY */ + +/* @todo: We need a mechanism to prevent wasting memory in every pbuf + (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ + +#define PBUF_TRANSPORT_HLEN 20 +#if LWIP_IPV6 +#define PBUF_IP_HLEN 40 +#else +#define PBUF_IP_HLEN 20 +#endif + +/** + * @ingroup pbuf + * Enumeration of pbuf layers + */ +typedef enum { + /** Includes spare room for transport layer header, e.g. UDP header. + * Use this if you intend to pass the pbuf to functions like udp_send(). + */ + PBUF_TRANSPORT = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN, + /** Includes spare room for IP header. + * Use this if you intend to pass the pbuf to functions like raw_send(). + */ + PBUF_IP = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN, + /** Includes spare room for link layer header (ethernet header). + * Use this if you intend to pass the pbuf to functions like ethernet_output(). + * @see PBUF_LINK_HLEN + */ + PBUF_LINK = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN, + /** Includes spare room for additional encapsulation header before ethernet + * headers (e.g. 802.11). + * Use this if you intend to pass the pbuf to functions like netif->linkoutput(). + * @see PBUF_LINK_ENCAPSULATION_HLEN + */ + PBUF_RAW_TX = PBUF_LINK_ENCAPSULATION_HLEN, + /** Use this for input packets in a netif driver when calling netif->input() + * in the most common case - ethernet-layer netif driver. */ + PBUF_RAW = 0 +} pbuf_layer; + + +/* Base flags for pbuf_type definitions: */ + +/** Indicates that the payload directly follows the struct pbuf. + * This makes @ref pbuf_header work in both directions. */ +#define PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS 0x80 +/** Indicates the data stored in this pbuf can change. If this pbuf needs + * to be queued, it must be copied/duplicated. */ +#define PBUF_TYPE_FLAG_DATA_VOLATILE 0x40 +/** 4 bits are reserved for 16 allocation sources (e.g. heap, pool1, pool2, etc) + * Internally, we use: 0=heap, 1=MEMP_PBUF, 2=MEMP_PBUF_POOL -> 13 types free*/ +#define PBUF_TYPE_ALLOC_SRC_MASK 0x0F +/** Indicates this pbuf is used for RX (if not set, indicates use for TX). + * This information can be used to keep some spare RX buffers e.g. for + * receiving TCP ACKs to unblock a connection) */ +#define PBUF_ALLOC_FLAG_RX 0x0100 +/** Indicates the application needs the pbuf payload to be in one piece */ +#define PBUF_ALLOC_FLAG_DATA_CONTIGUOUS 0x0200 + +#define PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP 0x00 +#define PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF 0x01 +#define PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL 0x02 +/** First pbuf allocation type for applications */ +#define PBUF_TYPE_ALLOC_SRC_MASK_APP_MIN 0x03 +/** Last pbuf allocation type for applications */ +#define PBUF_TYPE_ALLOC_SRC_MASK_APP_MAX PBUF_TYPE_ALLOC_SRC_MASK + +/** + * @ingroup pbuf + * Enumeration of pbuf types + */ +typedef enum { + /** pbuf data is stored in RAM, used for TX mostly, struct pbuf and its payload + are allocated in one piece of contiguous memory (so the first payload byte + can be calculated from struct pbuf). + pbuf_alloc() allocates PBUF_RAM pbufs as unchained pbufs (although that might + change in future versions). + This should be used for all OUTGOING packets (TX).*/ + PBUF_RAM = (PBUF_ALLOC_FLAG_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP), + /** pbuf data is stored in ROM, i.e. struct pbuf and its payload are located in + totally different memory areas. Since it points to ROM, payload does not + have to be copied when queued for transmission. */ + PBUF_ROM = PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF, + /** pbuf comes from the pbuf pool. Much like PBUF_ROM but payload might change + so it has to be duplicated when queued before transmitting, depending on + who has a 'ref' to it. */ + PBUF_REF = (PBUF_TYPE_FLAG_DATA_VOLATILE | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF), + /** pbuf payload refers to RAM. This one comes from a pool and should be used + for RX. Payload can be chained (scatter-gather RX) but like PBUF_RAM, struct + pbuf and its payload are allocated in one piece of contiguous memory (so + the first payload byte can be calculated from struct pbuf). + Don't use this for TX, if the pool becomes empty e.g. because of TCP queuing, + you are unable to receive TCP acks! */ + PBUF_POOL = (PBUF_ALLOC_FLAG_RX | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free calls pbuf_custom->custom_free_function() + when the last reference is released (plus custom PBUF_RAM cannot be trimmed) */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U +/** indicates this pbuf was received as link-level broadcast */ +#define PBUF_FLAG_LLBCAST 0x08U +/** indicates this pbuf was received as link-level multicast */ +#define PBUF_FLAG_LLMCAST 0x10U +/** indicates this pbuf includes a TCP FIN flag */ +#define PBUF_FLAG_TCP_FIN 0x20U + +/** Main packet buffer struct */ +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** a bit field indicating pbuf type and allocation sources + (see PBUF_TYPE_FLAG_*, PBUF_ALLOC_FLAG_* and PBUF_TYPE_ALLOC_SRC_MASK) + */ + u8_t type_internal; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + LWIP_PBUF_REF_T ref; + + /** For incoming packets, this contains the input netif's index */ + u8_t if_idx; + + /** In case the user needs to store data custom data on a pbuf */ + LWIP_PBUF_CUSTOM_DATA +}; + + +/** Helper struct for const-correctness only. + * The only meaning of this one is to provide a const payload pointer + * for PBUF_ROM type. + */ +struct pbuf_rom { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + const void *payload; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ +#ifndef PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_FREE_OOSEQ 1 +#endif /* PBUF_POOL_FREE_OOSEQ */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ +extern volatile u8_t pbuf_free_ooseq_pending; +void pbuf_free_ooseq(void); +/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level to check if ooseq pbufs need to be + freed! */ +#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ + /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ + ooseq queued pbufs now */ \ + pbuf_free_ooseq(); }}while(0) +#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */ + /* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */ + #define PBUF_CHECK_FREE_OOSEQ() +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len); +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size); +#define pbuf_get_allocsrc(p) ((p)->type_internal & PBUF_TYPE_ALLOC_SRC_MASK) +#define pbuf_match_allocsrc(p, type) (pbuf_get_allocsrc(p) == ((type) & PBUF_TYPE_ALLOC_SRC_MASK)) +#define pbuf_match_type(p, type) pbuf_match_allocsrc(p, type) +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +u8_t pbuf_header_force(struct pbuf *p, s16_t header_size); +u8_t pbuf_add_header(struct pbuf *p, size_t header_size_increment); +u8_t pbuf_add_header_force(struct pbuf *p, size_t header_size_increment); +u8_t pbuf_remove_header(struct pbuf *p, size_t header_size); +struct pbuf *pbuf_free_header(struct pbuf *q, u16_t size); +void pbuf_ref(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u16_t pbuf_clen(const struct pbuf *p); +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from); +err_t pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_len, u16_t offset); +u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +void *pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset); +struct pbuf *pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); +struct pbuf *pbuf_clone(pbuf_layer l, pbuf_type type, struct pbuf *p); +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE +void pbuf_split_64k(struct pbuf *p, struct pbuf **rest); +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + +u8_t pbuf_get_at(const struct pbuf* p, u16_t offset); +int pbuf_try_get_at(const struct pbuf* p, u16_t offset); +void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data); +u16_t pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n); +u16_t pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); +u16_t pbuf_strstr(const struct pbuf* p, const char* substr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PBUF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/altcp_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/altcp_priv.h new file mode 100644 index 0000000..d1de9b1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/altcp_priv.h @@ -0,0 +1,159 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_PRIV_H +#define LWIP_HDR_ALTCP_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_pcb *altcp_alloc(void); +void altcp_free(struct altcp_pcb *conn); + +/* Function prototypes for application layers */ +typedef void (*altcp_set_poll_fn)(struct altcp_pcb *conn, u8_t interval); +typedef void (*altcp_recved_fn)(struct altcp_pcb *conn, u16_t len); +typedef err_t (*altcp_bind_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); +typedef err_t (*altcp_connect_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); + +typedef struct altcp_pcb *(*altcp_listen_fn)(struct altcp_pcb *conn, u8_t backlog, err_t *err); + +typedef void (*altcp_abort_fn)(struct altcp_pcb *conn); +typedef err_t (*altcp_close_fn)(struct altcp_pcb *conn); +typedef err_t (*altcp_shutdown_fn)(struct altcp_pcb *conn, int shut_rx, int shut_tx); + +typedef err_t (*altcp_write_fn)(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); +typedef err_t (*altcp_output_fn)(struct altcp_pcb *conn); + +typedef u16_t (*altcp_mss_fn)(struct altcp_pcb *conn); +typedef u16_t (*altcp_sndbuf_fn)(struct altcp_pcb *conn); +typedef u16_t (*altcp_sndqueuelen_fn)(struct altcp_pcb *conn); +typedef void (*altcp_nagle_disable_fn)(struct altcp_pcb *conn); +typedef void (*altcp_nagle_enable_fn)(struct altcp_pcb *conn); +typedef int (*altcp_nagle_disabled_fn)(struct altcp_pcb *conn); + +typedef void (*altcp_setprio_fn)(struct altcp_pcb *conn, u8_t prio); + +typedef void (*altcp_dealloc_fn)(struct altcp_pcb *conn); + +typedef err_t (*altcp_get_tcp_addrinfo_fn)(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); +typedef ip_addr_t *(*altcp_get_ip_fn)(struct altcp_pcb *conn, int local); +typedef u16_t (*altcp_get_port_fn)(struct altcp_pcb *conn, int local); + +#if LWIP_TCP_KEEPALIVE +typedef void (*altcp_keepalive_disable_fn)(struct altcp_pcb *conn); +typedef void (*altcp_keepalive_enable_fn)(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count); +#endif + +#ifdef LWIP_DEBUG +typedef enum tcp_state (*altcp_dbg_get_tcp_state_fn)(struct altcp_pcb *conn); +#endif + +struct altcp_functions { + altcp_set_poll_fn set_poll; + altcp_recved_fn recved; + altcp_bind_fn bind; + altcp_connect_fn connect; + altcp_listen_fn listen; + altcp_abort_fn abort; + altcp_close_fn close; + altcp_shutdown_fn shutdown; + altcp_write_fn write; + altcp_output_fn output; + altcp_mss_fn mss; + altcp_sndbuf_fn sndbuf; + altcp_sndqueuelen_fn sndqueuelen; + altcp_nagle_disable_fn nagle_disable; + altcp_nagle_enable_fn nagle_enable; + altcp_nagle_disabled_fn nagle_disabled; + altcp_setprio_fn setprio; + altcp_dealloc_fn dealloc; + altcp_get_tcp_addrinfo_fn addrinfo; + altcp_get_ip_fn getip; + altcp_get_port_fn getport; +#if LWIP_TCP_KEEPALIVE + altcp_keepalive_disable_fn keepalive_disable; + altcp_keepalive_enable_fn keepalive_enable; +#endif +#ifdef LWIP_DEBUG + altcp_dbg_get_tcp_state_fn dbg_get_tcp_state; +#endif +}; + +void altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval); +void altcp_default_recved(struct altcp_pcb *conn, u16_t len); +err_t altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); +err_t altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx); +err_t altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); +err_t altcp_default_output(struct altcp_pcb *conn); +u16_t altcp_default_mss(struct altcp_pcb *conn); +u16_t altcp_default_sndbuf(struct altcp_pcb *conn); +u16_t altcp_default_sndqueuelen(struct altcp_pcb *conn); +void altcp_default_nagle_disable(struct altcp_pcb *conn); +void altcp_default_nagle_enable(struct altcp_pcb *conn); +int altcp_default_nagle_disabled(struct altcp_pcb *conn); +void altcp_default_setprio(struct altcp_pcb *conn, u8_t prio); +void altcp_default_dealloc(struct altcp_pcb *conn); +err_t altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); +ip_addr_t *altcp_default_get_ip(struct altcp_pcb *conn, int local); +u16_t altcp_default_get_port(struct altcp_pcb *conn, int local); +#if LWIP_TCP_KEEPALIVE +void altcp_default_keepalive_disable(struct altcp_pcb *conn); +void altcp_default_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count); +#endif +#ifdef LWIP_DEBUG +enum tcp_state altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/api_msg.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/api_msg.h new file mode 100644 index 0000000..9e8ffc9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/api_msg.h @@ -0,0 +1,272 @@ +/** + * @file + * netconn API lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_MSG_H +#define LWIP_HDR_API_MSG_H + +#include "lwip/opt.h" + +#include "lwip/arch.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#if LWIP_MPU_COMPATIBLE +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_MSG_M_DEF_SEM(m) *m +#else +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif +#else /* LWIP_MPU_COMPATIBLE */ +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif /* LWIP_MPU_COMPATIBLE */ + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for lwip_netconn_do_send */ + struct netbuf *b; + /** used for lwip_netconn_do_newconn */ + struct { + u8_t proto; + } n; + /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ + struct { + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; + u8_t if_idx; + } bc; + /** used for lwip_netconn_do_getaddr */ + struct { + ip_addr_t API_MSG_M_DEF(ipaddr); + u16_t API_MSG_M_DEF(port); + u8_t local; + } ad; + /** used for lwip_netconn_do_write */ + struct { + /** current vector to write */ + const struct netvector *vector; + /** number of unwritten vectors */ + u16_t vector_cnt; + /** offset into current vector */ + size_t vector_off; + /** total length across vectors */ + size_t len; + /** offset into total length/output of bytes written when err == ERR_OK */ + size_t offset; + u8_t apiflags; +#if LWIP_SO_SNDTIMEO + u32_t time_started; +#endif /* LWIP_SO_SNDTIMEO */ + } w; + /** used for lwip_netconn_do_recv */ + struct { + size_t len; + } r; +#if LWIP_TCP + /** used for lwip_netconn_do_close (/shutdown) */ + struct { + u8_t shut; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + u32_t time_started; +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + u8_t polls_left; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + } sd; +#endif /* LWIP_TCP */ +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) + /** used for lwip_netconn_do_join_leave_group */ + struct { + API_MSG_M_DEF_C(ip_addr_t, multiaddr); + API_MSG_M_DEF_C(ip_addr_t, netif_addr); + u8_t if_idx; + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +#if LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t* op_completed_sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +}; + +#if LWIP_NETCONN_SEM_PER_THREAD +#define LWIP_API_MSG_SEM(msg) ((msg)->op_completed_sem) +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define LWIP_API_MSG_SEM(msg) (&(msg)->conn->op_completed) +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + +#if LWIP_DNS +/** As lwip_netconn_do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ +#if LWIP_MPU_COMPATIBLE + char name[DNS_MAX_NAME_LENGTH]; +#else /* LWIP_MPU_COMPATIBLE */ + const char *name; +#endif /* LWIP_MPU_COMPATIBLE */ + /** The resolved address is stored here */ + ip_addr_t API_MSG_M_DEF(addr); +#if LWIP_IPV4 && LWIP_IPV6 + /** Type of resolve call */ + u8_t dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t API_MSG_M_DEF_SEM(sem); + /** Errors are given back here */ + err_t API_MSG_M_DEF(err); +}; +#endif /* LWIP_DNS */ + +#if LWIP_NETCONN_FULLDUPLEX +int lwip_netconn_is_deallocated_msg(void *msg); +#endif +int lwip_netconn_is_err_msg(void *msg, err_t *err); +void lwip_netconn_do_newconn (void *m); +void lwip_netconn_do_delconn (void *m); +void lwip_netconn_do_bind (void *m); +void lwip_netconn_do_bind_if (void *m); +void lwip_netconn_do_connect (void *m); +void lwip_netconn_do_disconnect (void *m); +void lwip_netconn_do_listen (void *m); +void lwip_netconn_do_send (void *m); +void lwip_netconn_do_recv (void *m); +#if TCP_LISTEN_BACKLOG +void lwip_netconn_do_accepted (void *m); +#endif /* TCP_LISTEN_BACKLOG */ +void lwip_netconn_do_write (void *m); +void lwip_netconn_do_getaddr (void *m); +void lwip_netconn_do_close (void *m); +void lwip_netconn_do_shutdown (void *m); +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +void lwip_netconn_do_join_leave_group(void *m); +void lwip_netconn_do_join_leave_group_netif(void *m); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +void lwip_netconn_do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +/* netifapi related lwIP internal definitions */ + +#if LWIP_MPU_COMPATIBLE +#define NETIFAPI_IPADDR_DEF(type, m) type m +#else /* LWIP_MPU_COMPATIBLE */ +#define NETIFAPI_IPADDR_DEF(type, m) const type * m +#endif /* LWIP_MPU_COMPATIBLE */ + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg { + struct tcpip_api_call_data call; + struct netif *netif; + union { + struct { +#if LWIP_IPV4 + NETIFAPI_IPADDR_DEF(ip4_addr_t, ipaddr); + NETIFAPI_IPADDR_DEF(ip4_addr_t, netmask); + NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); +#endif /* LWIP_IPV4 */ + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + struct { +#if LWIP_MPU_COMPATIBLE + char name[NETIF_NAMESIZE]; +#else /* LWIP_MPU_COMPATIBLE */ + char *name; +#endif /* LWIP_MPU_COMPATIBLE */ + u8_t index; + } ifs; + } msg; +}; + +#endif /* LWIP_NETIF_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_API_MSG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/mem_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/mem_priv.h new file mode 100644 index 0000000..8630d75 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/mem_priv.h @@ -0,0 +1,84 @@ +/** + * @file + * lwIP internal memory implementations (do not use in application code) + */ + +/* + * Copyright (c) 2018 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_MEM_PRIV_H +#define LWIP_HDR_MEM_PRIV_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/mem.h" + +#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK +/* if MEM_OVERFLOW_CHECK or MEMP_OVERFLOW_CHECK is turned on, we reserve some + * bytes at the beginning and at the end of each element, initialize them as + * 0xcd and check them later. + * If MEM(P)_OVERFLOW_CHECK is >= 2, on every call to mem(p)_malloc or mem(p)_free, + * every single element in each pool/heap is checked! + * This is VERY SLOW but also very helpful. + * MEM_SANITY_REGION_BEFORE and MEM_SANITY_REGION_AFTER can be overridden in + * lwipopts.h to change the amount reserved for checking. */ +#ifndef MEM_SANITY_REGION_BEFORE +#define MEM_SANITY_REGION_BEFORE 16 +#endif /* MEM_SANITY_REGION_BEFORE*/ +#if MEM_SANITY_REGION_BEFORE > 0 +#define MEM_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SANITY_REGION_BEFORE) +#else +#define MEM_SANITY_REGION_BEFORE_ALIGNED 0 +#endif /* MEM_SANITY_REGION_BEFORE*/ +#ifndef MEM_SANITY_REGION_AFTER +#define MEM_SANITY_REGION_AFTER 16 +#endif /* MEM_SANITY_REGION_AFTER*/ +#if MEM_SANITY_REGION_AFTER > 0 +#define MEM_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SANITY_REGION_AFTER) +#else +#define MEM_SANITY_REGION_AFTER_ALIGNED 0 +#endif /* MEM_SANITY_REGION_AFTER*/ + +void mem_overflow_init_raw(void *p, size_t size); +void mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2); + +#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_priv.h new file mode 100644 index 0000000..1f14cb1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_priv.h @@ -0,0 +1,161 @@ +/** + * @file + * memory pools lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_PRIV_H +#define LWIP_HDR_MEMP_PRIV_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/mem.h" +#include "lwip/priv/mem_priv.h" + +#if MEMP_OVERFLOW_CHECK + + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEM_SANITY_REGION_BEFORE_ALIGNED) +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEM_SANITY_REGION_AFTER_ALIGNED) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE 0 +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + +#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK +struct memp { + struct memp *next; +#if MEMP_OVERFLOW_CHECK + const char *file; + int line; +#endif /* MEMP_OVERFLOW_CHECK */ +}; +#endif /* !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK */ + +#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/priv/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/priv/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS */ + +/** Memory pool descriptor */ +struct memp_desc { +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY + /** Textual description */ + const char *desc; +#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */ +#if MEMP_STATS + /** Statistics */ + struct stats_mem *stats; +#endif + + /** Element size */ + u16_t size; + +#if !MEMP_MEM_MALLOC + /** Number of elements */ + u16_t num; + + /** Base address */ + u8_t *base; + + /** First free element of each pool. Elements form a linked list. */ + struct memp **tab; +#endif /* MEMP_MEM_MALLOC */ +}; + +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY +#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc), +#else +#define DECLARE_LWIP_MEMPOOL_DESC(desc) +#endif + +#if MEMP_STATS +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) static struct stats_mem name; +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) &name, +#else +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) +#endif + +void memp_init_pool(const struct memp_desc *desc); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_pool_fn(const struct memp_desc* desc, const char* file, const int line); +#define memp_malloc_pool(d) memp_malloc_pool_fn((d), __FILE__, __LINE__) +#else +void *memp_malloc_pool(const struct memp_desc *desc); +#endif +void memp_free_pool(const struct memp_desc* desc, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_std.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_std.h new file mode 100644 index 0000000..669ad4d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/memp_std.h @@ -0,0 +1,153 @@ +/** + * @file + * lwIP internal memory pools (do not use in application code) + * This file is deliberately included multiple times: once with empty + * definition of LWIP_MEMPOOL() to handle all includes and multiple times + * to build up various lists of mem pools. + */ + +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))), "MALLOC_"#size) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + LWIP_MEM_ALIGN_SIZE(payload)), desc) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB") +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB") +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB") +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG") +#endif /* LWIP_TCP */ + +#if LWIP_ALTCP && LWIP_TCP +LWIP_MEMPOOL(ALTCP_PCB, MEMP_NUM_ALTCP_PCB, sizeof(struct altcp_pcb), "ALTCP_PCB") +#endif /* LWIP_ALTCP && LWIP_TCP */ + +#if LWIP_IPV4 && IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") +#endif /* LWIP_IPV4 && IP_REASSEMBLY */ +#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG) +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") +#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */ + +#if LWIP_NETCONN || LWIP_SOCKET +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL(API_MSG, MEMP_NUM_API_MSG, sizeof(struct api_msg), "API_MSG") +#if LWIP_DNS +LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg), "DNS_API_MSG") +#endif +#if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKING +LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") +#endif +#if LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) +LWIP_MEMPOOL(SELECT_CB, MEMP_NUM_SELECT_CB, sizeof(struct lwip_select_cb), "SELECT_CB") +#endif /* LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) */ +#if LWIP_NETIF_API +LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") +#endif +#endif /* LWIP_MPU_COMPATIBLE */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") +#endif /* LWIP_IGMP */ + +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") +#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ + +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#if LWIP_IPV6 && LWIP_ND6_QUEUEING +LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") +#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ + +#if LWIP_IPV6 && LWIP_IPV6_REASS +LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_MEMPOOL(PBUF, MEMP_NUM_PBUF, sizeof(struct pbuf), "PBUF_REF/ROM") +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL") + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/nd6_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/nd6_priv.h new file mode 100644 index 0000000..cc3007d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/nd6_priv.h @@ -0,0 +1,142 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_PRIV_H +#define LWIP_HDR_ND6_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ND6_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct nd6_q_entry { + struct nd6_q_entry *next; + struct pbuf *p; +}; +#endif /* LWIP_ND6_QUEUEING */ + +/** Struct for tables. */ +struct nd6_neighbor_cache_entry { + ip6_addr_t next_hop_address; + struct netif *netif; + u8_t lladdr[NETIF_MAX_HWADDR_LEN]; + /*u32_t pmtu;*/ +#if LWIP_ND6_QUEUEING + /** Pointer to queue of pending outgoing packets on this entry. */ + struct nd6_q_entry *q; +#else /* LWIP_ND6_QUEUEING */ + /** Pointer to a single pending outgoing packet on this entry. */ + struct pbuf *q; +#endif /* LWIP_ND6_QUEUEING */ + u8_t state; + u8_t isrouter; + union { + u32_t reachable_time; /* in seconds */ + u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */ + u32_t probes_sent; + u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */ + } counter; +}; + +struct nd6_destination_cache_entry { + ip6_addr_t destination_addr; + ip6_addr_t next_hop_addr; + u16_t pmtu; + u32_t age; +}; + +struct nd6_prefix_list_entry { + ip6_addr_t prefix; + struct netif *netif; + u32_t invalidation_timer; /* in seconds */ +}; + +struct nd6_router_list_entry { + struct nd6_neighbor_cache_entry *neighbor_entry; + u32_t invalidation_timer; /* in seconds */ + u8_t flags; +}; + +enum nd6_neighbor_cache_entry_state { + ND6_NO_ENTRY = 0, + ND6_INCOMPLETE, + ND6_REACHABLE, + ND6_STALE, + ND6_DELAY, + ND6_PROBE +}; + +#define ND6_HOPLIM 255 /* maximum hop limit, required in all ND packets */ + +#define ND6_2HRS 7200 /* two hours, expressed in number of seconds */ + +/* Router tables. */ +/* @todo make these static? and entries accessible through API? */ +extern struct nd6_neighbor_cache_entry neighbor_cache[]; +extern struct nd6_destination_cache_entry destination_cache[]; +extern struct nd6_prefix_list_entry prefix_list[]; +extern struct nd6_router_list_entry default_router_list[]; + +/* Default values, can be updated by a RA message. */ +extern u32_t reachable_time; +extern u32_t retrans_timer; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/raw_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/raw_priv.h new file mode 100644 index 0000000..d4561d4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/raw_priv.h @@ -0,0 +1,69 @@ +/** + * @file + * raw API internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_RAW_PRIV_H +#define LWIP_HDR_RAW_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/raw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** return codes for raw_input */ +typedef enum raw_input_state +{ + RAW_INPUT_NONE = 0, /* pbuf did not match any pcbs */ + RAW_INPUT_EATEN, /* pbuf handed off and delivered to pcb */ + RAW_INPUT_DELIVERED /* pbuf only delivered to pcb (pbuf can still be referenced) */ +} raw_input_state_t; + +/* The following functions are the lower layer interface to RAW. */ +raw_input_state_t raw_input(struct pbuf *p, struct netif *inp); + +void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* LWIP_HDR_RAW_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/sockets_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/sockets_priv.h new file mode 100644 index 0000000..d8f9904 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/sockets_priv.h @@ -0,0 +1,175 @@ +/** + * @file + * Sockets API internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Joel Cunningham + * + */ +#ifndef LWIP_HDR_SOCKETS_PRIV_H +#define LWIP_HDR_SOCKETS_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NUM_SOCKETS MEMP_NUM_NETCONN + +/** This is overridable for the rare case where more than 255 threads + * select on the same socket... + */ +#ifndef SELWAIT_T +#define SELWAIT_T u8_t +#endif + +union lwip_sock_lastdata { + struct netbuf *netbuf; + struct pbuf *pbuf; +}; + +/** Contains all internal pointers and states used for a socket */ +struct lwip_sock { + /** sockets currently are built on netconns, each socket has one netconn */ + struct netconn *conn; + /** data that was left from the previous read */ + union lwip_sock_lastdata lastdata; +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + /** number of times data was received, set by event_callback(), + tested by the receive and select functions */ + s16_t rcvevent; + /** number of times data was ACKed (free send buffer), set by event_callback(), + tested by select */ + u16_t sendevent; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; + /** counter of how many threads are waiting for this socket using select */ + SELWAIT_T select_waiting; +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ +#if LWIP_NETCONN_FULLDUPLEX + /* counter of how many threads are using a struct lwip_sock (not the 'int') */ + u8_t fd_used; + /* status of pending close/delete actions */ + u8_t fd_free_pending; +#define LWIP_SOCK_FD_FREE_TCP 1 +#define LWIP_SOCK_FD_FREE_FREE 2 +#endif +}; + +#ifndef set_errno +#define set_errno(err) do { if (err) { errno = (err); } } while(0) +#endif + +#if !LWIP_TCPIP_CORE_LOCKING +/** Maximum optlen used by setsockopt/getsockopt */ +#define LWIP_SETGETSOCKOPT_MAXOPTLEN LWIP_MAX(16, sizeof(struct ifreq)) + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { + /** socket index for which to change options */ + int s; + /** level of the option to process */ + int level; + /** name of the option to process */ + int optname; + /** set: value to set the option to + * get: value of the option is stored here */ +#if LWIP_MPU_COMPATIBLE + u8_t optval[LWIP_SETGETSOCKOPT_MAXOPTLEN]; +#else + union { + void *p; + const void *pc; + } optval; +#endif + /** size of *optval */ + socklen_t optlen; + /** if an error occurs, it is temporarily stored here */ + int err; + /** semaphore to wake up the calling task */ + void* completed_sem; +}; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + +#ifdef __cplusplus +} +#endif + +struct lwip_sock* lwip_socket_dbg_get_socket(int fd); + +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + +#if LWIP_NETCONN_SEM_PER_THREAD +#define SELECT_SEM_T sys_sem_t* +#define SELECT_SEM_PTR(sem) (sem) +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define SELECT_SEM_T sys_sem_t +#define SELECT_SEM_PTR(sem) (&(sem)) +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +/** Description for a task waiting in select */ +struct lwip_select_cb { + /** Pointer to the next waiting task */ + struct lwip_select_cb *next; + /** Pointer to the previous waiting task */ + struct lwip_select_cb *prev; +#if LWIP_SOCKET_SELECT + /** readset passed to select */ + fd_set *readset; + /** writeset passed to select */ + fd_set *writeset; + /** unimplemented: exceptset passed to select */ + fd_set *exceptset; +#endif /* LWIP_SOCKET_SELECT */ +#if LWIP_SOCKET_POLL + /** fds passed to poll; NULL if select */ + struct pollfd *poll_fds; + /** nfds passed to poll; 0 if select */ + nfds_t poll_nfds; +#endif /* LWIP_SOCKET_POLL */ + /** don't signal the same semaphore twice: set to 1 when signalled */ + int sem_signalled; + /** semaphore to wake up a task waiting for select */ + SELECT_SEM_T sem; +}; +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_HDR_SOCKETS_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcp_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcp_priv.h new file mode 100644 index 0000000..72f9126 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcp_priv.h @@ -0,0 +1,523 @@ +/** + * @file + * TCP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_PRIV_H +#define LWIP_HDR_TCP_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/tcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +void tcp_init (void); /* Initialize this module. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + +/* Call this from a netif driver (watch out for threading issues!) that has + returned a memory error on transmit and now has free buffers to send more. + This iterates all active pcbs that had an error and tries to call + tcp_output, so use this with care as it might slow down the system. */ +void tcp_txnow (void); + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio); +void tcp_free (struct tcp_pcb *pcb); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +err_t tcp_send_empty_ack(struct tcp_pcb *pcb); +err_t tcp_rexmit (struct tcp_pcb *pcb); +err_t tcp_rexmit_rto_prepare(struct tcp_pcb *pcb); +void tcp_rexmit_rto_commit(struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); +void tcp_rexmit_fast (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); +err_t tcp_process_refused_data(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) || \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +#define TCP_TCPLEN(seg) ((seg)->len + (((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0) ? 1U : 0U)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was successfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) ret = lwip_tcp_event(arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) do { if ((pcb)->state != SYN_RCVD) { \ + ret = lwip_tcp_event((pcb)->callback_arg, (pcb), LWIP_EVENT_POLL, NULL, 0, ERR_OK); \ + } else { \ + ret = ERR_ARG; } } while(0) +/* For event API, last state SYN_RCVD must be excluded here: the application + has not seen this pcb, yet! */ +#define TCP_EVENT_ERR(last_state,errf,arg,err) do { if (last_state != SYN_RCVD) { \ + lwip_tcp_event((arg), NULL, LWIP_EVENT_ERR, NULL, 0, (err)); } } while(0) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) \ + do { \ + if((lpcb)->accept != NULL) \ + (ret) = (lpcb)->accept((arg),(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(last_state,errf,arg,err) \ + do { \ + LWIP_UNUSED_ARG(last_state); \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segments on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversize only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option (only used in SYN segments) */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ +#define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option (only used in SYN segments) */ +#define TF_SEG_OPTS_SACK_PERM (u8_t)0x10U /* Include SACK Permitted option (only used in SYN segments) */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_EOL 0 +#define LWIP_TCP_OPT_NOP 1 +#define LWIP_TCP_OPT_MSS 2 +#define LWIP_TCP_OPT_WS 3 +#define LWIP_TCP_OPT_SACK_PERM 4 +#define LWIP_TCP_OPT_TS 8 + +#define LWIP_TCP_OPT_LEN_MSS 4 +#if LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_OPT_LEN_TS 10 +#define LWIP_TCP_OPT_LEN_TS_OUT 12 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_TS_OUT 0 +#endif +#if LWIP_WND_SCALE +#define LWIP_TCP_OPT_LEN_WS 3 +#define LWIP_TCP_OPT_LEN_WS_OUT 4 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_WS_OUT 0 +#endif + +#if LWIP_TCP_SACK_OUT +#define LWIP_TCP_OPT_LEN_SACK_PERM 2 +#define LWIP_TCP_OPT_LEN_SACK_PERM_OUT 4 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_SACK_PERM_OUT 0 +#endif + +#define LWIP_TCP_OPT_LENGTH(flags) \ + ((flags) & TF_SEG_OPTS_MSS ? LWIP_TCP_OPT_LEN_MSS : 0) + \ + ((flags) & TF_SEG_OPTS_TS ? LWIP_TCP_OPT_LEN_TS_OUT : 0) + \ + ((flags) & TF_SEG_OPTS_WND_SCALE ? LWIP_TCP_OPT_LEN_WS_OUT : 0) + \ + ((flags) & TF_SEG_OPTS_SACK_PERM ? LWIP_TCP_OPT_LEN_SACK_PERM_OUT : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(mss) lwip_htonl(0x02040000 | ((mss) & 0xFFFF)) + +#if LWIP_WND_SCALE +#define TCPWNDSIZE_F U32_F +#define TCPWND_MAX 0xFFFFFFFFU +#define TCPWND_CHECK16(x) LWIP_ASSERT("window size > 0xFFFF", (x) <= 0xFFFF) +#define TCPWND_MIN16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#else /* LWIP_WND_SCALE */ +#define TCPWNDSIZE_F U16_F +#define TCPWND_MAX 0xFFFFU +#define TCPWND_CHECK16(x) +#define TCPWND_MIN16(x) x +#endif /* LWIP_WND_SCALE */ + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; +extern u8_t tcp_active_pcbs_changed; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 +#define NUM_TCP_PCB_LISTS 4 +extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %"U16_F"\n", (void *)(npcb), (npcb)->local_port)); \ + for (tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_REG: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (void *)(npcb), (void *)(*(pcbs)))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for (tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (void *)(npcb), (void *)(*(pcbs)))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + struct tcp_pcb *tcp_tmp_pcb; \ + for (tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + +#define TCP_REG_ACTIVE(npcb) \ + do { \ + TCP_REG(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_RMV_ACTIVE(npcb) \ + do { \ + TCP_RMV(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_PCB_REMOVE_ACTIVE(pcb) \ + do { \ + tcp_pcb_remove(&tcp_active_pcbs, pcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +void tcp_segs_free(struct tcp_seg *seg); +void tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + tcp_clear_flags(pcb, TF_ACK_DELAY); \ + tcp_ack_now(pcb); \ + } \ + else { \ + tcp_set_flags(pcb, TF_ACK_DELAY); \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + tcp_set_flags(pcb, TF_ACK_NOW) + +err_t tcp_send_fin(struct tcp_pcb *pcb); +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(const struct tcp_pcb* pcb, u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(struct tcp_pcb *pcb); + +err_t tcp_keepalive(struct tcp_pcb *pcb); +err_t tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split); +err_t tcp_zero_window_probe(struct tcp_pcb *pcb); +void tcp_trigger_input_pcb_close(void); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, + const ip_addr_t *dest); +#define tcp_eff_send_mss(sendmss, src, dest) \ + tcp_eff_send_mss_netif(sendmss, ip_route(src, dest), dest) +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void); + +void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#if TCP_QUEUE_OOSEQ +void tcp_free_ooseq(struct tcp_pcb *pcb); +#endif + +#if LWIP_TCP_PCB_NUM_EXT_ARGS +err_t tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcpip_priv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcpip_priv.h new file mode 100644 index 0000000..74be634 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/priv/tcpip_priv.h @@ -0,0 +1,170 @@ +/** + * @file + * TCPIP API internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_PRIV_H +#define LWIP_HDR_TCPIP_PRIV_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pbuf; +struct netif; + +#if LWIP_MPU_COMPATIBLE +#define API_VAR_REF(name) (*(name)) +#define API_VAR_DECLARE(type, name) type * name +#define API_VAR_ALLOC_EXT(type, pool, name, errorblock) do { \ + name = (type *)memp_malloc(pool); \ + if (name == NULL) { \ + errorblock; \ + } \ + } while(0) +#define API_VAR_ALLOC(type, pool, name, errorval) API_VAR_ALLOC_EXT(type, pool, name, return errorval) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) do { \ + name = (type *)LWIP_MEMPOOL_ALLOC(pool); \ + if (name == NULL) { \ + return errorval; \ + } \ + } while(0) +#define API_VAR_FREE(pool, name) memp_free(pool, name) +#define API_VAR_FREE_POOL(pool, name) LWIP_MEMPOOL_FREE(pool, name) +#define API_EXPR_REF(expr) (&(expr)) +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_EXPR_REF_SEM(expr) (expr) +#else +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#endif +#define API_EXPR_DEREF(expr) expr +#define API_MSG_M_DEF(m) m +#define API_MSG_M_DEF_C(t, m) t m +#else /* LWIP_MPU_COMPATIBLE */ +#define API_VAR_REF(name) name +#define API_VAR_DECLARE(type, name) type name +#define API_VAR_ALLOC_EXT(type, pool, name, errorblock) +#define API_VAR_ALLOC(type, pool, name, errorval) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) +#define API_VAR_FREE(pool, name) +#define API_VAR_FREE_POOL(pool, name) +#define API_EXPR_REF(expr) expr +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#define API_EXPR_DEREF(expr) (*(expr)) +#define API_MSG_M_DEF(m) *m +#define API_MSG_M_DEF_C(t, m) const t * m +#endif /* LWIP_MPU_COMPATIBLE */ + +err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem); + +struct tcpip_api_call_data +{ +#if !LWIP_TCPIP_CORE_LOCKING + err_t err; +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +#else /* !LWIP_TCPIP_CORE_LOCKING */ + u8_t dummy; /* avoid empty struct :-( */ +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +}; +typedef err_t (*tcpip_api_call_fn)(struct tcpip_api_call_data* call); +err_t tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call); + +enum tcpip_msg_type { +#if !LWIP_TCPIP_CORE_LOCKING + TCPIP_MSG_API, + TCPIP_MSG_API_CALL, +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT + TCPIP_MSG_INPKT, +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + TCPIP_MSG_CALLBACK, + TCPIP_MSG_CALLBACK_STATIC +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + union { +#if !LWIP_TCPIP_CORE_LOCKING + struct { + tcpip_callback_fn function; + void* msg; + } api_msg; + struct { + tcpip_api_call_fn function; + struct tcpip_api_call_data *arg; + sys_sem_t *sem; + } api_call; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT + struct { + struct pbuf *p; + struct netif *netif; + netif_input_fn input_fn; + } inp; +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_PRIV_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/autoip.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/autoip.h new file mode 100644 index 0000000..fd3af8a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/autoip.h @@ -0,0 +1,78 @@ +/** + * @file + * AutoIP protocol definitions + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_PROT_AUTOIP_H +#define LWIP_HDR_PROT_AUTOIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* 169.254.0.0 */ +#define AUTOIP_NET 0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +typedef enum { + AUTOIP_STATE_OFF = 0, + AUTOIP_STATE_PROBING = 1, + AUTOIP_STATE_ANNOUNCING = 2, + AUTOIP_STATE_BOUND = 3 +} autoip_state_enum_t; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_AUTOIP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp.h new file mode 100644 index 0000000..ab18dca --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp.h @@ -0,0 +1,178 @@ +/** + * @file + * DHCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_PROT_DHCP_H +#define LWIP_HDR_PROT_DHCP_H + +#include "lwip/opt.h" +#include "lwip/arch.h" +#include "lwip/prot/ip4.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /* DHCP message item offsets and length */ +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_OFS 44U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_OFS 108U +#define DHCP_FILE_LEN 128U +#define DHCP_MSG_LEN 236U +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4U) /* 4 byte: cookie */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FLD_8(u8_t op); + PACK_STRUCT_FLD_8(u8_t htype); + PACK_STRUCT_FLD_8(u8_t hlen); + PACK_STRUCT_FLD_8(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FLD_S(ip4_addr_p_t ciaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t yiaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t siaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t giaddr); + PACK_STRUCT_FLD_8(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FLD_8(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FLD_8(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FLD_8(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +/* DHCP client states */ +typedef enum { + DHCP_STATE_OFF = 0, + DHCP_STATE_REQUESTING = 1, + DHCP_STATE_INIT = 2, + DHCP_STATE_REBOOTING = 3, + DHCP_STATE_REBINDING = 4, + DHCP_STATE_RENEWING = 5, + DHCP_STATE_SELECTING = 6, + DHCP_STATE_INFORMING = 7, + DHCP_STATE_CHECKING = 8, + DHCP_STATE_PERMANENT = 9, /* not yet implemented */ + DHCP_STATE_BOUND = 10, + DHCP_STATE_RELEASING = 11, /* not yet implemented */ + DHCP_STATE_BACKING_OFF = 12 +} dhcp_state_enum_t; + +/* DHCP op codes */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/* BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_NTP 42 +#define DHCP_OPTION_END 255 + +/* DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/* possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_DHCP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp6.h new file mode 100644 index 0000000..0754c91 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dhcp6.h @@ -0,0 +1,138 @@ +/** + * @file + * DHCPv6 protocol definitions + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_PROT_DHCP6_H +#define LWIP_HDR_PROT_DHCP6_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DHCP6_CLIENT_PORT 546 +#define DHCP6_SERVER_PORT 547 + + + /* DHCPv6 message item offsets and length */ +#define DHCP6_TRANSACTION_ID_LEN 3 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCPv6 message */ +struct dhcp6_msg +{ + PACK_STRUCT_FLD_8(u8_t msgtype); + PACK_STRUCT_FLD_8(u8_t transaction_id[DHCP6_TRANSACTION_ID_LEN]); + /* options follow */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +/* DHCP6 client states */ +typedef enum { + DHCP6_STATE_OFF = 0, + DHCP6_STATE_STATELESS_IDLE = 1, + DHCP6_STATE_REQUESTING_CONFIG = 2 +} dhcp6_state_enum_t; + +/* DHCPv6 message types */ +#define DHCP6_SOLICIT 1 +#define DHCP6_ADVERTISE 2 +#define DHCP6_REQUEST 3 +#define DHCP6_CONFIRM 4 +#define DHCP6_RENEW 5 +#define DHCP6_REBIND 6 +#define DHCP6_REPLY 7 +#define DHCP6_RELEASE 8 +#define DHCP6_DECLINE 9 +#define DHCP6_RECONFIGURE 10 +#define DHCP6_INFOREQUEST 11 +#define DHCP6_RELAYFORW 12 +#define DHCP6_RELAYREPL 13 +/* More message types see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ + +/** DHCPv6 status codes */ +#define DHCP6_STATUS_SUCCESS 0 /* Success. */ +#define DHCP6_STATUS_UNSPECFAIL 1 /* Failure, reason unspecified; this status code is sent by either a client or a server to indicate a failure not explicitly specified in this document. */ +#define DHCP6_STATUS_NOADDRSAVAIL 2 /* Server has no addresses available to assign to the IA(s). */ +#define DHCP6_STATUS_NOBINDING 3 /* Client record (binding) unavailable. */ +#define DHCP6_STATUS_NOTONLINK 4 /* The prefix for the address is not appropriate for the link to which the client is attached. */ +#define DHCP6_STATUS_USEMULTICAST 5 /* Sent by a server to a client to force the client to send messages to the server using the All_DHCP_Relay_Agents_and_Servers address. */ +/* More status codes see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ + +/** DHCPv6 DUID types */ +#define DHCP6_DUID_LLT 1 /* LLT: Link-layer Address Plus Time */ +#define DHCP6_DUID_EN 2 /* EN: Enterprise number */ +#define DHCP6_DUID_LL 3 /* LL: Link-layer Address */ +#define DHCP6_DUID_UUID 4 /* UUID (RFC 6355) */ + +/* DHCPv6 options */ +#define DHCP6_OPTION_CLIENTID 1 +#define DHCP6_OPTION_SERVERID 2 +#define DHCP6_OPTION_IA_NA 3 +#define DHCP6_OPTION_IA_TA 4 +#define DHCP6_OPTION_IAADDR 5 +#define DHCP6_OPTION_ORO 6 +#define DHCP6_OPTION_PREFERENCE 7 +#define DHCP6_OPTION_ELAPSED_TIME 8 +#define DHCP6_OPTION_RELAY_MSG 9 +#define DHCP6_OPTION_AUTH 11 +#define DHCP6_OPTION_UNICAST 12 +#define DHCP6_OPTION_STATUS_CODE 13 +#define DHCP6_OPTION_RAPID_COMMIT 14 +#define DHCP6_OPTION_USER_CLASS 15 +#define DHCP6_OPTION_VENDOR_CLASS 16 +#define DHCP6_OPTION_VENDOR_OPTS 17 +#define DHCP6_OPTION_INTERFACE_ID 18 +#define DHCP6_OPTION_RECONF_MSG 19 +#define DHCP6_OPTION_RECONF_ACCEPT 20 +/* More options see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ +#define DHCP6_OPTION_DNS_SERVERS 23 /* RFC 3646 */ +#define DHCP6_OPTION_DOMAIN_LIST 24 /* RFC 3646 */ +#define DHCP6_OPTION_SNTP_SERVERS 31 /* RFC 4075 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_DHCP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dns.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dns.h new file mode 100644 index 0000000..94782d6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/dns.h @@ -0,0 +1,140 @@ +/** + * @file + * DNS - host name to IP address resolver. + */ + +/* + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + * + * security fixes and more by Simon Goldschmidt + * + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 LWIP_HDR_PROT_DNS_H +#define LWIP_HDR_PROT_DNS_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS server port address */ +#ifndef DNS_SERVER_PORT +#define DNS_SERVER_PORT 53 +#endif + +/* DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_AAAA 28 /* IPv6 address */ +#define DNS_RRTYPE_SRV 33 /* service location */ +#define DNS_RRTYPE_ANY 255 /* any type */ + +/* DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_ANY 255 /* any class */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +#define DNS_HDR_GET_OPCODE(hdr) ((((hdr)->flags1) >> 3) & 0xF) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS message header */ +struct dns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FLD_8(u8_t flags1); + PACK_STRUCT_FLD_8(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_HDR 12 + + +/* Multicast DNS definitions */ + +/** UDP port for multicast DNS queries */ +#ifndef DNS_MQUERY_PORT +#define DNS_MQUERY_PORT 5353 +#endif + +/* IPv4 group for multicast DNS queries: 224.0.0.251 */ +#ifndef DNS_MQUERY_IPV4_GROUP_INIT +#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251) +#endif + +/* IPv6 group for multicast DNS queries: FF02::FB */ +#ifndef DNS_MQUERY_IPV6_GROUP_INIT +#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_DNS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/etharp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/etharp.h new file mode 100644 index 0000000..811c228 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/etharp.h @@ -0,0 +1,114 @@ +/** + * @file + * ARP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHARP_H +#define LWIP_HDR_PROT_ETHARP_H + +#include "lwip/arch.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN ETH_HWADDR_LEN +#endif + +/** + * struct ip4_addr_wordaligned is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr_wordaligned { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T +#define IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) +#endif + + /** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T +#define IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message, see RFC 826 ("Packet format") */ +struct etharp_hdr { + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FLD_8(u8_t hwlen); + PACK_STRUCT_FLD_8(u8_t protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FLD_S(struct eth_addr shwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr); + PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETHARP_HDR 28 + +/* ARP message types (opcodes) */ +enum etharp_opcode { + ARP_REQUEST = 1, + ARP_REPLY = 2 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHARP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ethernet.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ethernet.h new file mode 100644 index 0000000..309e574 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ethernet.h @@ -0,0 +1,125 @@ +/** + * @file + * Ethernet protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHERNET_H +#define LWIP_HDR_PROT_ETHERNET_H + +#include "lwip/arch.h" +#include "lwip/prot/ieee.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETH_HWADDR_LEN +#ifdef ETHARP_HWADDR_LEN +#define ETH_HWADDR_LEN ETHARP_HWADDR_LEN /* compatibility mode */ +#else +#define ETH_HWADDR_LEN 6 +#endif +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** An Ethernet MAC address */ +struct eth_addr { + PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Initialize a struct eth_addr with its 6 bytes (takes care of correct braces) */ +#define ETH_ADDR(b0, b1, b2, b3, b4, b5) {{b0, b1, b2, b3, b4, b5}} + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** Ethernet header */ +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FLD_8(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FLD_S(struct eth_addr dest); + PACK_STRUCT_FLD_S(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ +struct eth_vlan_hdr { + PACK_STRUCT_FIELD(u16_t prio_vid); + PACK_STRUCT_FIELD(u16_t tpid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (lwip_htons((vlan_hdr)->prio_vid) & 0xFFF) + +/** The 24-bit IANA IPv4-multicast OUI is 01-00-5e: */ +#define LL_IP4_MULTICAST_ADDR_0 0x01 +#define LL_IP4_MULTICAST_ADDR_1 0x00 +#define LL_IP4_MULTICAST_ADDR_2 0x5e + +/** IPv6 multicast uses this prefix */ +#define LL_IP6_MULTICAST_ADDR_0 0x33 +#define LL_IP6_MULTICAST_ADDR_1 0x33 + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHERNET_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/iana.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/iana.h new file mode 100644 index 0000000..32890cc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/iana.h @@ -0,0 +1,97 @@ +/** + * @file + * IANA assigned numbers (RFC 1700 and successors) + * + * @defgroup iana IANA assigned numbers + * @ingroup infrastructure + */ + +/* + * Copyright (c) 2017 Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIP_HDR_PROT_IANA_H +#define LWIP_HDR_PROT_IANA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup iana + * Hardware types + */ +enum lwip_iana_hwtype { + /** Ethernet */ + LWIP_IANA_HWTYPE_ETHERNET = 1 +}; + +/** + * @ingroup iana + * Port numbers + * https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt + */ +enum lwip_iana_port_number { + /** SMTP */ + LWIP_IANA_PORT_SMTP = 25, + /** DHCP server */ + LWIP_IANA_PORT_DHCP_SERVER = 67, + /** DHCP client */ + LWIP_IANA_PORT_DHCP_CLIENT = 68, + /** TFTP */ + LWIP_IANA_PORT_TFTP = 69, + /** HTTP */ + LWIP_IANA_PORT_HTTP = 80, + /** SNTP */ + LWIP_IANA_PORT_SNTP = 123, + /** NETBIOS */ + LWIP_IANA_PORT_NETBIOS = 137, + /** SNMP */ + LWIP_IANA_PORT_SNMP = 161, + /** SNMP traps */ + LWIP_IANA_PORT_SNMP_TRAP = 162, + /** HTTPS */ + LWIP_IANA_PORT_HTTPS = 443, + /** SMTPS */ + LWIP_IANA_PORT_SMTPS = 465, + /** MQTT */ + LWIP_IANA_PORT_MQTT = 1883, + /** MDNS */ + LWIP_IANA_PORT_MDNS = 5353, + /** Secure MQTT */ + LWIP_IANA_PORT_SECURE_MQTT = 8883 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IANA_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp.h new file mode 100644 index 0000000..7d19385 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp.h @@ -0,0 +1,91 @@ +/** + * @file + * ICMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP_H +#define LWIP_HDR_PROT_ICMP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ +#define ICMP_AM 17 /* address mask request */ +#define ICMP_AMR 18 /* address mask reply */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is split to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Compatibility defines, old versions used to combine type and code to an u16_t */ +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp6.h new file mode 100644 index 0000000..36989f6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/icmp6.h @@ -0,0 +1,172 @@ +/** + * @file + * ICMP6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP6_H +#define LWIP_HDR_PROT_ICMP6_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP type */ +enum icmp6_type { + /** Destination unreachable */ + ICMP6_TYPE_DUR = 1, + /** Packet too big */ + ICMP6_TYPE_PTB = 2, + /** Time exceeded */ + ICMP6_TYPE_TE = 3, + /** Parameter problem */ + ICMP6_TYPE_PP = 4, + /** Private experimentation */ + ICMP6_TYPE_PE1 = 100, + /** Private experimentation */ + ICMP6_TYPE_PE2 = 101, + /** Reserved for expansion of error messages */ + ICMP6_TYPE_RSV_ERR = 127, + + /** Echo request */ + ICMP6_TYPE_EREQ = 128, + /** Echo reply */ + ICMP6_TYPE_EREP = 129, + /** Multicast listener query */ + ICMP6_TYPE_MLQ = 130, + /** Multicast listener report */ + ICMP6_TYPE_MLR = 131, + /** Multicast listener done */ + ICMP6_TYPE_MLD = 132, + /** Router solicitation */ + ICMP6_TYPE_RS = 133, + /** Router advertisement */ + ICMP6_TYPE_RA = 134, + /** Neighbor solicitation */ + ICMP6_TYPE_NS = 135, + /** Neighbor advertisement */ + ICMP6_TYPE_NA = 136, + /** Redirect */ + ICMP6_TYPE_RD = 137, + /** Multicast router advertisement */ + ICMP6_TYPE_MRA = 151, + /** Multicast router solicitation */ + ICMP6_TYPE_MRS = 152, + /** Multicast router termination */ + ICMP6_TYPE_MRT = 153, + /** Private experimentation */ + ICMP6_TYPE_PE3 = 200, + /** Private experimentation */ + ICMP6_TYPE_PE4 = 201, + /** Reserved for expansion of informational messages */ + ICMP6_TYPE_RSV_INF = 255 +}; + +/** ICMP destination unreachable codes */ +enum icmp6_dur_code { + /** No route to destination */ + ICMP6_DUR_NO_ROUTE = 0, + /** Communication with destination administratively prohibited */ + ICMP6_DUR_PROHIBITED = 1, + /** Beyond scope of source address */ + ICMP6_DUR_SCOPE = 2, + /** Address unreachable */ + ICMP6_DUR_ADDRESS = 3, + /** Port unreachable */ + ICMP6_DUR_PORT = 4, + /** Source address failed ingress/egress policy */ + ICMP6_DUR_POLICY = 5, + /** Reject route to destination */ + ICMP6_DUR_REJECT_ROUTE = 6 +}; + +/** ICMP time exceeded codes */ +enum icmp6_te_code { + /** Hop limit exceeded in transit */ + ICMP6_TE_HL = 0, + /** Fragment reassembly time exceeded */ + ICMP6_TE_FRAG = 1 +}; + +/** ICMP parameter code */ +enum icmp6_pp_code { + /** Erroneous header field encountered */ + ICMP6_PP_FIELD = 0, + /** Unrecognized next header type encountered */ + ICMP6_PP_HEADER = 1, + /** Unrecognized IPv6 option encountered */ + ICMP6_PP_OPTION = 2 +}; + +/** This is the standard ICMP6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t data); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define ICMP6_HLEN 8 + +/** This is the ICMP6 header adapted for echo req/resp. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ieee.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ieee.h new file mode 100644 index 0000000..abbb9e3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ieee.h @@ -0,0 +1,91 @@ +/** + * @file + * IEEE assigned numbers + * + * @defgroup ieee IEEE assigned numbers + * @ingroup infrastructure + */ + +/* + * Copyright (c) 2017 Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIP_HDR_PROT_IEEE_H +#define LWIP_HDR_PROT_IEEE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup ieee + * A list of often ethtypes (although lwIP does not use all of them). + */ +enum lwip_ieee_eth_type { + /** Internet protocol v4 */ + ETHTYPE_IP = 0x0800U, + /** Address resolution protocol */ + ETHTYPE_ARP = 0x0806U, + /** Wake on lan */ + ETHTYPE_WOL = 0x0842U, + /** RARP */ + ETHTYPE_RARP = 0x8035U, + /** Virtual local area network */ + ETHTYPE_VLAN = 0x8100U, + /** Internet protocol v6 */ + ETHTYPE_IPV6 = 0x86DDU, + /** PPP Over Ethernet Discovery Stage */ + ETHTYPE_PPPOEDISC = 0x8863U, + /** PPP Over Ethernet Session Stage */ + ETHTYPE_PPPOE = 0x8864U, + /** Jumbo Frames */ + ETHTYPE_JUMBO = 0x8870U, + /** Process field network */ + ETHTYPE_PROFINET = 0x8892U, + /** Ethernet for control automation technology */ + ETHTYPE_ETHERCAT = 0x88A4U, + /** Link layer discovery protocol */ + ETHTYPE_LLDP = 0x88CCU, + /** Serial real-time communication system */ + ETHTYPE_SERCOS = 0x88CDU, + /** Media redundancy protocol */ + ETHTYPE_MRP = 0x88E3U, + /** Precision time protocol */ + ETHTYPE_PTP = 0x88F7U, + /** Q-in-Q, 802.1ad */ + ETHTYPE_QINQ = 0x9100U +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IEEE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/igmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/igmp.h new file mode 100644 index 0000000..46b81a9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/igmp.h @@ -0,0 +1,90 @@ +/** + * @file + * IGMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IGMP_H +#define LWIP_HDR_PROT_IGMP_H + +#include "lwip/arch.h" +#include "lwip/prot/ip4.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * IGMP constants + */ +#define IGMP_TTL 1 +#define IGMP_MINLEN 8 +#define ROUTER_ALERT 0x9404U +#define ROUTER_ALERTLEN 4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY 0x11 /* Membership query */ +#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ + +/* Group membership states */ +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 + +/** + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FLD_8(u8_t igmp_msgtype); + PACK_STRUCT_FLD_8(u8_t igmp_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_checksum); + PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IGMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip.h new file mode 100644 index 0000000..223158f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip.h @@ -0,0 +1,59 @@ +/** + * @file + * IP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP_H +#define LWIP_HDR_PROT_IP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/** This operates on a void* by loading the first byte */ +#define IP_HDR_GET_VERSION(ptr) ((*(u8_t*)(ptr)) >> 4) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip4.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip4.h new file mode 100644 index 0000000..9347461 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip4.h @@ -0,0 +1,131 @@ +/** + * @file + * IPv4 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP4_H +#define LWIP_HDR_PROT_IP4_H + +#include "lwip/arch.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the packed version of ip4_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +typedef struct ip4_addr_packed ip4_addr_p_t; + +/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ +#define IP_HLEN 20 +/* Maximum size of the IPv4 header with options. */ +#define IP_HLEN_MAX 60 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/* The IPv4 header */ +struct ip_hdr { + /* version / header length */ + PACK_STRUCT_FLD_8(u8_t _v_hl); + /* type of service */ + PACK_STRUCT_FLD_8(u8_t _tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000U /* reserved fragment flag */ +#define IP_DF 0x4000U /* don't fragment flag */ +#define IP_MF 0x2000U /* more fragments flag */ +#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FLD_8(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FLD_8(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip4_addr_p_t src); + PACK_STRUCT_FLD_S(ip4_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Macros to get struct ip_hdr fields: */ +#define IPH_V(hdr) ((hdr)->_v_hl >> 4) +#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) +#define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4)) +#define IPH_TOS(hdr) ((hdr)->_tos) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_OFFSET_BYTES(hdr) ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U)) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +/* Macros to set struct ip_hdr fields: */ +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) +#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP4_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip6.h new file mode 100644 index 0000000..7df81ed --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/ip6.h @@ -0,0 +1,235 @@ +/** + * @file + * IPv6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP6_H +#define LWIP_HDR_PROT_IP6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP6_MIN_MTU_LENGTH 1280 + +/** This is the packed version of ip6_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_addr_packed { + PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +typedef struct ip6_addr_packed ip6_addr_p_t; + +#define IP6_HLEN 40 + +#define IP6_NEXTH_HOPBYHOP 0 +#define IP6_NEXTH_TCP 6 +#define IP6_NEXTH_UDP 17 +#define IP6_NEXTH_ENCAPS 41 +#define IP6_NEXTH_ROUTING 43 +#define IP6_NEXTH_FRAGMENT 44 +#define IP6_NEXTH_ICMP6 58 +#define IP6_NEXTH_NONE 59 +#define IP6_NEXTH_DESTOPTS 60 +#define IP6_NEXTH_UDPLITE 136 + +/** The IPv6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hdr { + /** version / traffic class / flow label */ + PACK_STRUCT_FIELD(u32_t _v_tc_fl); + /** payload length */ + PACK_STRUCT_FIELD(u16_t _plen); + /** next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /** hop limit */ + PACK_STRUCT_FLD_8(u8_t _hoplim); + /** source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip6_addr_p_t src); + PACK_STRUCT_FLD_S(ip6_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + +/* ipv6 extended options header */ +#define IP6_PAD1_OPTION 0 +#define IP6_PADN_OPTION 1 +#define IP6_ROUTER_ALERT_OPTION 5 +#define IP6_JUMBO_OPTION 194 +#define IP6_HOME_ADDRESS_OPTION 201 +#define IP6_ROUTER_ALERT_DLEN 2 +#define IP6_ROUTER_ALERT_VALUE_MLD 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_opt_hdr { + /* router alert option type */ + PACK_STRUCT_FLD_8(u8_t _opt_type); + /* router alert option data len */ + PACK_STRUCT_FLD_8(u8_t _opt_dlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_OPT_HLEN 2 +#define IP6_OPT_TYPE_ACTION(hdr) ((((hdr)->_opt_type) >> 6) & 0x3) +#define IP6_OPT_TYPE_CHANGE(hdr) ((((hdr)->_opt_type) >> 5) & 0x1) +#define IP6_OPT_TYPE(hdr) ((hdr)->_opt_type) +#define IP6_OPT_DLEN(hdr) ((hdr)->_opt_dlen) + +/* Hop-by-Hop header. */ +#define IP6_HBH_HLEN 2 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hbh_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* header length in 8-octet units */ + PACK_STRUCT_FLD_8(u8_t _hlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_HBH_NEXTH(hdr) ((hdr)->_nexth) + +/* Destination header. */ +#define IP6_DEST_HLEN 2 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_dest_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* header length in 8-octet units */ + PACK_STRUCT_FLD_8(u8_t _hlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_DEST_NEXTH(hdr) ((hdr)->_nexth) + +/* Routing header */ +#define IP6_ROUT_TYPE2 2 +#define IP6_ROUT_RPL 3 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_rout_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FLD_8(u8_t _hlen); + /* fragment offset */ + PACK_STRUCT_FIELD(u8_t _routing_type); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u8_t _segments_left); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_ROUT_NEXTH(hdr) ((hdr)->_nexth) +#define IP6_ROUT_TYPE(hdr) ((hdr)->_routing_type) +#define IP6_ROUT_SEG_LEFT(hdr) ((hdr)->_segments_left) + +/* Fragment header. */ +#define IP6_FRAG_HLEN 8 +#define IP6_FRAG_OFFSET_MASK 0xfff8 +#define IP6_FRAG_MORE_FLAG 0x0001 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_frag_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FLD_8(u8_t reserved); + /* fragment offset */ + PACK_STRUCT_FIELD(u16_t _fragment_offset); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u32_t _identification); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_FRAG_NEXTH(hdr) ((hdr)->_nexth) +#define IP6_FRAG_MBIT(hdr) (lwip_ntohs((hdr)->_fragment_offset) & 0x1) +#define IP6_FRAG_ID(hdr) (lwip_ntohl((hdr)->_identification)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/mld6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/mld6.h new file mode 100644 index 0000000..71f1dcb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/mld6.h @@ -0,0 +1,71 @@ +/** + * @file + * MLD6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_MLD6_H +#define LWIP_HDR_PROT_MLD6_H + +#include "lwip/arch.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MLD6_HBH_HLEN 8 +/** Multicast listener report/query/done message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mld_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t max_resp_delay); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t multicast_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_MLD6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/nd6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/nd6.h new file mode 100644 index 0000000..c270d07 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/nd6.h @@ -0,0 +1,274 @@ +/** + * @file + * ND6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ND6_H +#define LWIP_HDR_PROT_ND6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Neighbor solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ns_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Neighbor advertisement message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct na_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FLD_8(u8_t reserved[3]); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define ND6_FLAG_ROUTER (0x80) +#define ND6_FLAG_SOLICITED (0x40) +#define ND6_FLAG_OVERRIDE (0x20) + +/** Router solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rs_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Router advertisement message header. */ +#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) +#define ND6_RA_FLAG_OTHER_CONFIG (0x40) +#define ND6_RA_FLAG_HOME_AGENT (0x20) +#define ND6_RA_PREFERENCE_MASK (0x18) +#define ND6_RA_PREFERENCE_HIGH (0x08) +#define ND6_RA_PREFERENCE_MEDIUM (0x00) +#define ND6_RA_PREFERENCE_LOW (0x18) +#define ND6_RA_PREFERENCE_DISABLED (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ra_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t current_hop_limit); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u16_t router_lifetime); + PACK_STRUCT_FIELD(u32_t reachable_time); + PACK_STRUCT_FIELD(u32_t retrans_timer); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirect message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirect_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + PACK_STRUCT_FLD_S(ip6_addr_p_t destination_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Link-layer address option. */ +#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) +#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct lladdr_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t addr[NETIF_MAX_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Prefix information option. */ +#define ND6_OPTION_TYPE_PREFIX_INFO (0x03) +#define ND6_PREFIX_FLAG_ON_LINK (0x80) +#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) +#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) +#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct prefix_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u32_t valid_lifetime); + PACK_STRUCT_FIELD(u32_t preferred_lifetime); + PACK_STRUCT_FLD_8(u8_t reserved2[3]); + PACK_STRUCT_FLD_8(u8_t site_prefix_length); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirected header option. */ +#define ND6_OPTION_TYPE_REDIR_HDR (0x04) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirected_header_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t reserved[6]); + /* Portion of redirected packet follows. */ + /* PACK_STRUCT_FLD_8(u8_t redirected[8]); */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** MTU option. */ +#define ND6_OPTION_TYPE_MTU (0x05) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mtu_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t mtu); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Route information option. */ +#define ND6_OPTION_TYPE_ROUTE_INFO (24) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct route_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t preference); + PACK_STRUCT_FIELD(u32_t route_lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Recursive DNS Server Option. */ +#define ND6_OPTION_TYPE_RDNSS (25) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rdnss_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t rdnss_address[1]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_RDNSS_OPTION_BASE 8 /* size without addresses */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ND6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/tcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/tcp.h new file mode 100644 index 0000000..c1d7de1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/tcp.h @@ -0,0 +1,100 @@ +/** + * @file + * TCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_TCP_H +#define LWIP_HDR_PROT_TCP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* TCP header flags bits */ +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U +/* Valid TCP header flags */ +#define TCP_FLAGS 0x3fU + +#define TCP_MAX_OPTION_BYTES 40 + +#define TCPH_HDRLEN(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)) +#define TCPH_HDRLEN_BYTES(phdr) ((u8_t)(TCPH_HDRLEN(phdr) << 2)) +#define TCPH_FLAGS(phdr) ((u8_t)((lwip_ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS))) + +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | lwip_htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = (u16_t)(lwip_htons((u16_t)((len) << 12) | (flags))) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | lwip_htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~lwip_htons(flags)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_TCP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/udp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/udp.h new file mode 100644 index 0000000..664f19a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/prot/udp.h @@ -0,0 +1,68 @@ +/** + * @file + * UDP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_UDP_H +#define LWIP_HDR_PROT_UDP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_UDP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/raw.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/raw.h new file mode 100644 index 0000000..b129bd3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/raw.h @@ -0,0 +1,143 @@ +/** + * @file + * raw API (to be used from TCPIP thread)\n + * See also @ref raw_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_RAW_H +#define LWIP_HDR_RAW_H + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RAW_FLAGS_CONNECTED 0x01U +#define RAW_FLAGS_HDRINCL 0x02U +#define RAW_FLAGS_MULTICAST_LOOP 0x04U + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr); + +/** the RAW protocol control block */ +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + u8_t flags; + +#if LWIP_MULTICAST_TX_OPTIONS + /** outgoing network interface for multicast packets, by interface index (if nonzero) */ + u8_t mcast_ifindex; + /** TTL for outgoing multicast packets */ + u8_t mcast_ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +#if LWIP_IPV6 + /* fields for handling checksum computations as per RFC3542. */ + u16_t chksum_offset; + u8_t chksum_reqd; +#endif +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto); +struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); +void raw_remove (struct raw_pcb *pcb); +err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr); +void raw_bind_netif (struct raw_pcb *pcb, const struct netif *netif); +err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); +void raw_disconnect (struct raw_pcb *pcb); + +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); +err_t raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, struct netif *netif, const ip_addr_t *src_ip); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); + +#define raw_flags(pcb) ((pcb)->flags) +#define raw_setflags(pcb,f) ((pcb)->flags = (f)) + +#define raw_set_flags(pcb, set_flags) do { (pcb)->flags = (u8_t)((pcb)->flags | (set_flags)); } while(0) +#define raw_clear_flags(pcb, clr_flags) do { (pcb)->flags = (u8_t)((pcb)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) +#define raw_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) + +#define raw_init() /* Compatibility define, no init needed. */ + +/* for compatibility with older implementation */ +#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) + +#if LWIP_MULTICAST_TX_OPTIONS +#define raw_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) +#define raw_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) +#define raw_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) +#define raw_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* LWIP_HDR_RAW_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sio.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sio.h new file mode 100644 index 0000000..7643e19 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sio.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef SIO_H +#define SIO_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum); +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd); +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd); +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SIO_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/snmp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/snmp.h new file mode 100644 index 0000000..8704d0b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/snmp.h @@ -0,0 +1,213 @@ +/** + * @file + * SNMP support API for implementing netifs and statitics for MIB2 + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_H +#define LWIP_HDR_SNMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct udp_pcb; +struct netif; + +/** + * @defgroup netif_mib2 MIB2 statistics + * @ingroup netif + */ + +/* MIB2 statistics functions */ +#if MIB2_STATS /* don't build if not configured for use in lwipopts.h */ +/** + * @ingroup netif_mib2 + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +/** This macro has a precision of ~49 days because sys_now returns u32_t. \#define your own if you want ~490 days. */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) (*(ptrToVal) = (sys_now() / 10)) +#endif + +/** + * @ingroup netif_mib2 + * Increment stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_INC(n, x) do { ++(n)->mib2_counters.x; } while(0) +/** + * @ingroup netif_mib2 + * Add value to stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_ADD(n, x, val) do { (n)->mib2_counters.x += (val); } while(0) + +/** + * @ingroup netif_mib2 + * Init MIB2 statistic counters in netif + * @param netif Netif to init + * @param type one of enum @ref snmp_ifType + * @param speed your link speed here (units: bits per second) + */ +#define MIB2_INIT_NETIF(netif, type, speed) do { \ + (netif)->link_type = (type); \ + (netif)->link_speed = (speed);\ + (netif)->ts = 0; \ + (netif)->mib2_counters.ifinoctets = 0; \ + (netif)->mib2_counters.ifinucastpkts = 0; \ + (netif)->mib2_counters.ifinnucastpkts = 0; \ + (netif)->mib2_counters.ifindiscards = 0; \ + (netif)->mib2_counters.ifinerrors = 0; \ + (netif)->mib2_counters.ifinunknownprotos = 0; \ + (netif)->mib2_counters.ifoutoctets = 0; \ + (netif)->mib2_counters.ifoutucastpkts = 0; \ + (netif)->mib2_counters.ifoutnucastpkts = 0; \ + (netif)->mib2_counters.ifoutdiscards = 0; \ + (netif)->mib2_counters.ifouterrors = 0; } while(0) +#else /* MIB2_STATS */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) +#endif +#define MIB2_INIT_NETIF(netif, type, speed) +#define MIB2_STATS_NETIF_INC(n, x) +#define MIB2_STATS_NETIF_ADD(n, x, val) +#endif /* MIB2_STATS */ + +/* LWIP MIB2 callbacks */ +#if LWIP_MIB2_CALLBACKS /* don't build if not configured for use in lwipopts.h */ +/* network interface */ +void mib2_netif_added(struct netif *ni); +void mib2_netif_removed(struct netif *ni); + +#if LWIP_IPV4 && LWIP_ARP +/* ARP (for atTable and ipNetToMediaTable) */ +void mib2_add_arp_entry(struct netif *ni, ip4_addr_t *ip); +void mib2_remove_arp_entry(struct netif *ni, ip4_addr_t *ip); +#else /* LWIP_IPV4 && LWIP_ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) +#endif /* LWIP_IPV4 && LWIP_ARP */ + +/* IP */ +#if LWIP_IPV4 +void mib2_add_ip4(struct netif *ni); +void mib2_remove_ip4(struct netif *ni); +void mib2_add_route_ip4(u8_t dflt, struct netif *ni); +void mib2_remove_route_ip4(u8_t dflt, struct netif *ni); +#endif /* LWIP_IPV4 */ + +/* UDP */ +#if LWIP_UDP +void mib2_udp_bind(struct udp_pcb *pcb); +void mib2_udp_unbind(struct udp_pcb *pcb); +#endif /* LWIP_UDP */ + +#else /* LWIP_MIB2_CALLBACKS */ +/* LWIP_MIB2_CALLBACKS support not available */ +/* define everything to be empty */ + +/* network interface */ +#define mib2_netif_added(ni) +#define mib2_netif_removed(ni) + +/* ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) + +/* IP */ +#define mib2_add_ip4(ni) +#define mib2_remove_ip4(ni) +#define mib2_add_route_ip4(dflt, ni) +#define mib2_remove_route_ip4(dflt, ni) + +/* UDP */ +#define mib2_udp_bind(pcb) +#define mib2_udp_unbind(pcb) +#endif /* LWIP_MIB2_CALLBACKS */ + +/* for source-code compatibility reasons only, can be removed (not used internally) */ +#define NETIF_INIT_SNMP MIB2_INIT_NETIF +#define snmp_add_ifinoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifinoctets, value) +#define snmp_inc_ifinucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinucastpkts) +#define snmp_inc_ifinnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinnucastpkts) +#define snmp_inc_ifindiscards(ni) MIB2_STATS_NETIF_INC(ni, ifindiscards) +#define snmp_inc_ifinerrors(ni) MIB2_STATS_NETIF_INC(ni, ifinerrors) +#define snmp_inc_ifinunknownprotos(ni) MIB2_STATS_NETIF_INC(ni, ifinunknownprotos) +#define snmp_add_ifoutoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifoutoctets, value) +#define snmp_inc_ifoutucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutucastpkts) +#define snmp_inc_ifoutnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutnucastpkts) +#define snmp_inc_ifoutdiscards(ni) MIB2_STATS_NETIF_INC(ni, ifoutdiscards) +#define snmp_inc_ifouterrors(ni) MIB2_STATS_NETIF_INC(ni, ifouterrors) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SNMP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sockets.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sockets.h new file mode 100644 index 0000000..d70d36c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sockets.h @@ -0,0 +1,688 @@ +/** + * @file + * Socket API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef LWIP_HDR_SOCKETS_H +#define LWIP_HDR_SOCKETS_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/errno.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) +typedef u8_t sa_family_t; +#endif +/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) +typedef u16_t in_port_t; +#endif + +#if LWIP_IPV4 +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; +#define SIN_ZERO_LEN 8 + char sin_zero[SIN_ZERO_LEN]; +}; +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +struct sockaddr_in6 { + u8_t sin6_len; /* length of this structure */ + sa_family_t sin6_family; /* AF_INET6 */ + in_port_t sin6_port; /* Transport layer port # */ + u32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + u32_t sin6_scope_id; /* Set of interfaces for scope */ +}; +#endif /* LWIP_IPV6 */ + +struct sockaddr { + u8_t sa_len; + sa_family_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_storage { + u8_t s2_len; + sa_family_t ss_family; + char s2_data1[2]; + u32_t s2_data2[3]; +#if LWIP_IPV6 + u32_t s2_data3[3]; +#endif /* LWIP_IPV6 */ +}; + +/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) +typedef u32_t socklen_t; +#endif + +#if !defined IOV_MAX +#define IOV_MAX 0xFFFF +#elif IOV_MAX > 0xFFFF +#error "IOV_MAX larger than supported by LwIP" +#endif /* IOV_MAX */ + +#if !defined(iovec) +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +/* struct msghdr->msg_flags bit field values */ +#define MSG_TRUNC 0x04 +#define MSG_CTRUNC 0x08 + +/* RFC 3542, Section 20: Ancillary Data */ +struct cmsghdr { + socklen_t cmsg_len; /* number of bytes, including header */ + int cmsg_level; /* originating protocol */ + int cmsg_type; /* protocol-specific type */ +}; +/* Data section follows header and possible padding, typically referred to as + unsigned char cmsg_data[]; */ + +/* cmsg header/data alignment. NOTE: we align to native word size (double word +size on 16-bit arch) so structures are not placed at an unaligned address. +16-bit arch needs double word to ensure 32-bit alignment because socklen_t +could be 32 bits. If we ever have cmsg data with a 64-bit variable, alignment +will need to increase long long */ +#define ALIGN_H(size) (((size) + sizeof(long) - 1U) & ~(sizeof(long)-1U)) +#define ALIGN_D(size) ALIGN_H(size) + +#define CMSG_FIRSTHDR(mhdr) \ + ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ + (struct cmsghdr *)(mhdr)->msg_control : \ + (struct cmsghdr *)NULL) + +#define CMSG_NXTHDR(mhdr, cmsg) \ + (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ + (((u8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \ + + ALIGN_D(sizeof(struct cmsghdr)) > \ + (u8_t *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ + (struct cmsghdr *)NULL : \ + (struct cmsghdr *)((void*)((u8_t *)(cmsg) + \ + ALIGN_H((cmsg)->cmsg_len))))) + +#define CMSG_DATA(cmsg) ((void*)((u8_t *)(cmsg) + \ + ALIGN_D(sizeof(struct cmsghdr)))) + +#define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ + ALIGN_H(length)) + +#define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ + length) + +/* Set socket options argument */ +#define IFNAMSIZ NETIF_NAMESIZE +struct ifreq { + char ifr_name[IFNAMSIZ]; /* Interface name */ +}; + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + + +/* + * Additional options, not kept in so_options. + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_DONTLINGER ((int)(~SO_LINGER)) +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ +#define SO_BINDTODEVICE 0x100b /* bind to device */ + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time in seconds */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#if LWIP_IPV6 +#define AF_INET6 10 +#else /* LWIP_IPV6 */ +#define AF_INET6 AF_UNSPEC +#endif /* LWIP_IPV6 */ +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#if LWIP_IPV6 +#define IPPROTO_IPV6 41 +#define IPPROTO_ICMPV6 58 +#endif /* LWIP_IPV6 */ +#define IPPROTO_UDPLITE 136 +#define IPPROTO_RAW 255 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ +#define MSG_NOSIGNAL 0x20 /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_PKTINFO 8 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* + * Options for level IPPROTO_IPV6 + */ +#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ +#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_MULTICAST_TX_OPTIONS +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_IGMP +/* + * Options and types related to multicast membership + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +#if LWIP_IPV4 +struct in_pktinfo { + unsigned int ipi_ifindex; /* Interface index */ + struct in_addr ipi_addr; /* Destination (from header) address */ +}; +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6_MLD +/* + * Options and types related to IPv6 multicast membership + */ +#define IPV6_JOIN_GROUP 12 +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_LEAVE_GROUP 13 +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +typedef struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast addr */ + unsigned int ipv6mr_interface; /* interface index, or 0 */ +} ipv6_mreq; +#endif /* LWIP_IPV6_MLD */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) ((long)(IOC_VOID|((x)<<8)|(y))) + +#define _IOR(x,y,t) ((long)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) + +#define _IOW(x,y,t) ((long)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY O_NONBLOCK /* same as O_NONBLOCK, for compatibility */ +#endif +#ifndef O_RDONLY +#define O_RDONLY 2 +#endif +#ifndef O_WRONLY +#define O_WRONLY 4 +#endif +#ifndef O_RDWR +#define O_RDWR (O_RDONLY|O_WRONLY) +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +#undef FD_SETSIZE +/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +#define FD_SETSIZE MEMP_NUM_NETCONN +#define LWIP_SELECT_MAXNFDS (FD_SETSIZE + LWIP_SOCKET_OFFSET) +#define FDSETSAFESET(n, code) do { \ + if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ + code; }} while(0) +#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ + (code) : 0) +#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] | (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) +#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) +#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) + +typedef struct fd_set +{ + unsigned char fd_bits [(FD_SETSIZE+7)/8]; +} fd_set; + +#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) +#error "external FD_SETSIZE too small for number of sockets" +#else +#define LWIP_SELECT_MAXNFDS FD_SETSIZE +#endif /* FD_SET */ + +/* poll-related defines and types */ +/* @todo: find a better way to guard the definition of these defines and types if already defined */ +#if !defined(POLLIN) && !defined(POLLOUT) +#define POLLIN 0x1 +#define POLLOUT 0x2 +#define POLLERR 0x4 +#define POLLNVAL 0x8 +/* Below values are unimplemented */ +#define POLLRDNORM 0x10 +#define POLLRDBAND 0x20 +#define POLLPRI 0x40 +#define POLLWRNORM 0x80 +#define POLLWRBAND 0x100 +#define POLLHUP 0x200 +typedef unsigned int nfds_t; +struct pollfd +{ + int fd; + short events; + short revents; +}; +#endif + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +#define lwip_socket_init() /* Compatibility define, no init needed. */ +void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ + +#if LWIP_COMPAT_SOCKETS == 2 +/* This helps code parsers/code completion by not having the COMPAT functions as defines */ +#define lwip_accept accept +#define lwip_bind bind +#define lwip_shutdown shutdown +#define lwip_getpeername getpeername +#define lwip_getsockname getsockname +#define lwip_setsockopt setsockopt +#define lwip_getsockopt getsockopt +#define lwip_close closesocket +#define lwip_connect connect +#define lwip_listen listen +#define lwip_recv recv +#define lwip_recvmsg recvmsg +#define lwip_recvfrom recvfrom +#define lwip_send send +#define lwip_sendmsg sendmsg +#define lwip_sendto sendto +#define lwip_socket socket +#if LWIP_SOCKET_SELECT +#define lwip_select select +#endif +#if LWIP_SOCKET_POLL +#define lwip_poll poll +#endif +#define lwip_ioctl ioctlsocket +#define lwip_inet_ntop inet_ntop +#define lwip_inet_pton inet_pton + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define lwip_read read +#define lwip_readv readv +#define lwip_write write +#define lwip_writev writev +#undef lwip_close +#define lwip_close close +#define closesocket(s) close(s) +int fcntl(int s, int cmd, ...); +#undef lwip_ioctl +#define lwip_ioctl ioctl +#define ioctlsocket ioctl +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS == 2 */ + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); + int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +ssize_t lwip_recv(int s, void *mem, size_t len, int flags); +ssize_t lwip_read(int s, void *mem, size_t len); +ssize_t lwip_readv(int s, const struct iovec *iov, int iovcnt); +ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags); +ssize_t lwip_send(int s, const void *dataptr, size_t size, int flags); +ssize_t lwip_sendmsg(int s, const struct msghdr *message, int flags); +ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +ssize_t lwip_write(int s, const void *dataptr, size_t size); +ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); +#if LWIP_SOCKET_SELECT +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +#endif +#if LWIP_SOCKET_POLL +int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); +#endif +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); +const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); +int lwip_inet_pton(int af, const char *src, void *dst); + +#if LWIP_COMPAT_SOCKETS +#if LWIP_COMPAT_SOCKETS != 2 +/** @ingroup socket */ +#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) +/** @ingroup socket */ +#define bind(s,name,namelen) lwip_bind(s,name,namelen) +/** @ingroup socket */ +#define shutdown(s,how) lwip_shutdown(s,how) +/** @ingroup socket */ +#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) +/** @ingroup socket */ +#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) +/** @ingroup socket */ +#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define closesocket(s) lwip_close(s) +/** @ingroup socket */ +#define connect(s,name,namelen) lwip_connect(s,name,namelen) +/** @ingroup socket */ +#define listen(s,backlog) lwip_listen(s,backlog) +/** @ingroup socket */ +#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) +/** @ingroup socket */ +#define recvmsg(s,message,flags) lwip_recvmsg(s,message,flags) +/** @ingroup socket */ +#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) +/** @ingroup socket */ +#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) +/** @ingroup socket */ +#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) +/** @ingroup socket */ +#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) +/** @ingroup socket */ +#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) +#if LWIP_SOCKET_SELECT +/** @ingroup socket */ +#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) +#endif +#if LWIP_SOCKET_POLL +/** @ingroup socket */ +#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) +#endif +/** @ingroup socket */ +#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) +/** @ingroup socket */ +#define inet_ntop(af,src,dst,size) lwip_inet_ntop(af,src,dst,size) +/** @ingroup socket */ +#define inet_pton(af,src,dst) lwip_inet_pton(af,src,dst) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +/** @ingroup socket */ +#define read(s,mem,len) lwip_read(s,mem,len) +/** @ingroup socket */ +#define readv(s,iov,iovcnt) lwip_readv(s,iov,iovcnt) +/** @ingroup socket */ +#define write(s,dataptr,len) lwip_write(s,dataptr,len) +/** @ingroup socket */ +#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) +/** @ingroup socket */ +#define close(s) lwip_close(s) +/** @ingroup socket */ +#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) +/** @ingroup socket */ +#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS != 2 */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_HDR_SOCKETS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/stats.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/stats.h new file mode 100644 index 0000000..b570dba --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/stats.h @@ -0,0 +1,491 @@ +/** + * @file + * Statistics API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_STATS_H +#define LWIP_HDR_STATS_H + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +/** Protocol related stats */ +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +/** IGMP stats */ +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +/** Memory stats */ +struct stats_mem { +#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY + const char *name; +#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ + STAT_COUNTER err; + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER illegal; +}; + +/** System element stats */ +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +/** System stats */ +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +/** SNMP MIB2 stats */ +struct stats_mib2 { + /* IP */ + u32_t ipinhdrerrors; + u32_t ipinaddrerrors; + u32_t ipinunknownprotos; + u32_t ipindiscards; + u32_t ipindelivers; + u32_t ipoutrequests; + u32_t ipoutdiscards; + u32_t ipoutnoroutes; + u32_t ipreasmoks; + u32_t ipreasmfails; + u32_t ipfragoks; + u32_t ipfragfails; + u32_t ipfragcreates; + u32_t ipreasmreqds; + u32_t ipforwdatagrams; + u32_t ipinreceives; + + /* TCP */ + u32_t tcpactiveopens; + u32_t tcppassiveopens; + u32_t tcpattemptfails; + u32_t tcpestabresets; + u32_t tcpoutsegs; + u32_t tcpretranssegs; + u32_t tcpinsegs; + u32_t tcpinerrs; + u32_t tcpoutrsts; + + /* UDP */ + u32_t udpindatagrams; + u32_t udpnoports; + u32_t udpinerrors; + u32_t udpoutdatagrams; + + /* ICMP */ + u32_t icmpinmsgs; + u32_t icmpinerrors; + u32_t icmpindestunreachs; + u32_t icmpintimeexcds; + u32_t icmpinparmprobs; + u32_t icmpinsrcquenchs; + u32_t icmpinredirects; + u32_t icmpinechos; + u32_t icmpinechoreps; + u32_t icmpintimestamps; + u32_t icmpintimestampreps; + u32_t icmpinaddrmasks; + u32_t icmpinaddrmaskreps; + u32_t icmpoutmsgs; + u32_t icmpouterrors; + u32_t icmpoutdestunreachs; + u32_t icmpouttimeexcds; + u32_t icmpoutechos; /* can be incremented by user application ('ping') */ + u32_t icmpoutechoreps; +}; + +/** + * @ingroup netif_mib2 + * SNMP MIB2 interface stats + */ +struct stats_mib2_netif_ctrs { + /** The total number of octets received on the interface, including framing characters */ + u32_t ifinoctets; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * not addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinucastpkts; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinnucastpkts; + /** The number of inbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being deliverable to a higher-layer protocol. One possible + * reason for discarding such a packet could be to free up buffer space */ + u32_t ifindiscards; + /** For packet-oriented interfaces, the number of inbound packets that contained errors + * preventing them from being deliverable to a higher-layer protocol. For character- + * oriented or fixed-length interfaces, the number of inbound transmission units that + * contained errors preventing them from being deliverable to a higher-layer protocol. */ + u32_t ifinerrors; + /** For packet-oriented interfaces, the number of packets received via the interface which + * were discarded because of an unknown or unsupported protocol. For character-oriented + * or fixed-length interfaces that support protocol multiplexing the number of transmission + * units received via the interface which were discarded because of an unknown or unsupported + * protocol. For any interface that does not support protocol multiplexing, this counter will + * always be 0 */ + u32_t ifinunknownprotos; + /** The total number of octets transmitted out of the interface, including framing characters. */ + u32_t ifoutoctets; + /** The total number of packets that higher-level protocols requested be transmitted, and + * which were not addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutucastpkts; + /** The total number of packets that higher-level protocols requested be transmitted, and which + * were addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutnucastpkts; + /** The number of outbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being transmitted. One possible reason for discarding + * such a packet could be to free up buffer space. */ + u32_t ifoutdiscards; + /** For packet-oriented interfaces, the number of outbound packets that could not be transmitted + * because of errors. For character-oriented or fixed-length interfaces, the number of outbound + * transmission units that could not be transmitted because of errors. */ + u32_t ifouterrors; +}; + +/** lwIP stats container */ +struct stats_ { +#if LINK_STATS + /** Link level */ + struct stats_proto link; +#endif +#if ETHARP_STATS + /** ARP */ + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + /** Fragmentation */ + struct stats_proto ip_frag; +#endif +#if IP_STATS + /** IP */ + struct stats_proto ip; +#endif +#if ICMP_STATS + /** ICMP */ + struct stats_proto icmp; +#endif +#if IGMP_STATS + /** IGMP */ + struct stats_igmp igmp; +#endif +#if UDP_STATS + /** UDP */ + struct stats_proto udp; +#endif +#if TCP_STATS + /** TCP */ + struct stats_proto tcp; +#endif +#if MEM_STATS + /** Heap */ + struct stats_mem mem; +#endif +#if MEMP_STATS + /** Internal memory pools */ + struct stats_mem *memp[MEMP_MAX]; +#endif +#if SYS_STATS + /** System */ + struct stats_sys sys; +#endif +#if IP6_STATS + /** IPv6 */ + struct stats_proto ip6; +#endif +#if ICMP6_STATS + /** ICMP6 */ + struct stats_proto icmp6; +#endif +#if IP6_FRAG_STATS + /** IPv6 fragmentation */ + struct stats_proto ip6_frag; +#endif +#if MLD6_STATS + /** Multicast listener discovery */ + struct stats_igmp mld6; +#endif +#if ND6_STATS + /** Neighbor discovery */ + struct stats_proto nd6; +#endif +#if MIB2_STATS + /** SNMP MIB2 */ + struct stats_mib2 mib2; +#endif +}; + +/** Global variable containing lwIP internal statistics. Add this to your debugger's watchlist. */ +extern struct stats_ lwip_stats; + +/** Init statistics */ +void stats_init(void); + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y, type) do { lwip_stats.x.used = (type)(lwip_stats.x.used + y); \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#define STATS_GET(x) lwip_stats.x +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x, y, type) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP") +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y, mem_size_t) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x = (mem_size_t)((lwip_stats.mem.x) - (y)) +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + + #if MEMP_STATS +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i]->x) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(lwip_stats.memp[i], i) +#define MEMP_STATS_GET(x, i) STATS_GET(memp[i]->x) + #else +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_DISPLAY(i) +#define MEMP_STATS_GET(x, i) 0 +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1, STAT_COUNTER) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +#if IP6_STATS +#define IP6_STATS_INC(x) STATS_INC(x) +#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") +#else +#define IP6_STATS_INC(x) +#define IP6_STATS_DISPLAY() +#endif + +#if ICMP6_STATS +#define ICMP6_STATS_INC(x) STATS_INC(x) +#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") +#else +#define ICMP6_STATS_INC(x) +#define ICMP6_STATS_DISPLAY() +#endif + +#if IP6_FRAG_STATS +#define IP6_FRAG_STATS_INC(x) STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") +#else +#define IP6_FRAG_STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() +#endif + +#if MLD6_STATS +#define MLD6_STATS_INC(x) STATS_INC(x) +#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") +#else +#define MLD6_STATS_INC(x) +#define MLD6_STATS_DISPLAY() +#endif + +#if ND6_STATS +#define ND6_STATS_INC(x) STATS_INC(x) +#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") +#else +#define ND6_STATS_INC(x) +#define ND6_STATS_DISPLAY() +#endif + +#if MIB2_STATS +#define MIB2_STATS_INC(x) STATS_INC(x) +#else +#define MIB2_STATS_INC(x) +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +void stats_display_proto(struct stats_proto *proto, const char *name); +void stats_display_igmp(struct stats_igmp *igmp, const char *name); +void stats_display_mem(struct stats_mem *mem, const char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp, name) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_STATS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sys.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sys.h new file mode 100644 index 0000000..168e465 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/sys.h @@ -0,0 +1,560 @@ +/** + * @file + * OS abstraction layer + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#ifndef LWIP_HDR_SYS_H +#define LWIP_HDR_SYS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_sem_valid(s) 0 +#define sys_sem_valid_val(s) 0 +#define sys_sem_set_invalid(s) +#define sys_sem_set_invalid_val(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mutex_valid(mu) 0 +#define sys_mutex_set_invalid(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) +#define sys_mbox_valid(m) +#define sys_mbox_valid_val(m) +#define sys_mbox_set_invalid(m) +#define sys_mbox_set_invalid_val(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#ifndef LWIP_COMPAT_MUTEX +#define LWIP_COMPAT_MUTEX 0 +#endif + +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** + * @ingroup sys_mutex + * Create a new mutex. + * Note that mutexes are expected to not be taken recursively by the lwIP code, + * so both implementation types (recursive or non-recursive) should work. + * The mutex is allocated to the memory that 'mutex' + * points to (which can be both a pointer or the actual OS structure). + * If the mutex has been created, ERR_OK should be returned. Returning any + * other error will provide a hint what went wrong, but except for assertions, + * no real error handling is implemented. + * + * @param mutex pointer to the mutex to create + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Blocks the thread until the mutex can be grabbed. + * @param mutex the mutex to lock + */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Releases the mutex previously locked through 'sys_mutex_lock()'. + * @param mutex the mutex to unlock + */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Deallocates a mutex. + * @param mutex the mutex to delete + */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** + * @ingroup sys_mutex + * Returns 1 if the mutes is valid, 0 if it is not valid. + * When using pointers, a simple way is to check the pointer for != NULL. + * When directly using OS structures, implementing this may be more complex. + * This may also be a define, in which case the function is not prototyped. + */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** + * @ingroup sys_mutex + * Invalidate a mutex so that sys_mutex_valid() returns 0. + * ATTENTION: This does NOT mean that the mutex shall be deallocated: + * sys_mutex_free() is always called before calling this function! + * This may also be a define, in which case the function is not prototyped. + */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** + * @ingroup sys_sem + * Create a new semaphore + * Creates a new semaphore. The semaphore is allocated to the memory that 'sem' + * points to (which can be both a pointer or the actual OS structure). + * The "count" argument specifies the initial state of the semaphore (which is + * either 0 or 1). + * If the semaphore has been created, ERR_OK should be returned. Returning any + * other error will provide a hint what went wrong, but except for assertions, + * no real error handling is implemented. + * + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** + * @ingroup sys_sem + * Signals a semaphore + * @param sem the semaphore to signal + */ +void sys_sem_signal(sys_sem_t *sem); +/** + * @ingroup sys_sem + * Blocks the thread while waiting for the semaphore to be signaled. If the + * "timeout" argument is non-zero, the thread should only be blocked for the + * specified time (measured in milliseconds). If the "timeout" argument is zero, + * the thread should be blocked until the semaphore is signalled. + * + * The return value is SYS_ARCH_TIMEOUT if the semaphore wasn't signaled within + * the specified time or any other value if it was signaled (with or without + * waiting). + * Notice that lwIP implements a function with a similar name, + * sys_sem_wait(), that uses the sys_arch_sem_wait() function. + * + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return SYS_ARCH_TIMEOUT on timeout, any other value on success + */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** + * @ingroup sys_sem + * Deallocates a semaphore. + * @param sem semaphore to delete + */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** + * @ingroup sys_sem + * Returns 1 if the semaphore is valid, 0 if it is not valid. + * When using pointers, a simple way is to check the pointer for != NULL. + * When directly using OS structures, implementing this may be more complex. + * This may also be a define, in which case the function is not prototyped. + */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** + * @ingroup sys_sem + * Invalidate a semaphore so that sys_sem_valid() returns 0. + * ATTENTION: This does NOT mean that the semaphore shall be deallocated: + * sys_sem_free() is always called before calling this function! + * This may also be a define, in which case the function is not prototyped. + */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif +#ifndef sys_sem_valid_val +/** + * Same as sys_sem_valid() but taking a value, not a pointer + */ +#define sys_sem_valid_val(sem) sys_sem_valid(&(sem)) +#endif +#ifndef sys_sem_set_invalid_val +/** + * Same as sys_sem_set_invalid() but taking a value, not a pointer + */ +#define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem)) +#endif + +#ifndef sys_msleep +/** + * @ingroup sys_misc + * Sleep for specified number of ms + */ +void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ +#endif + +/* Mailbox functions. */ + +/** + * @ingroup sys_mbox + * Creates an empty mailbox for maximum "size" elements. Elements stored + * in mailboxes are pointers. You have to define macros "_MBOX_SIZE" + * in your lwipopts.h, or ignore this parameter in your implementation + * and use a default size. + * If the mailbox has been created, ERR_OK should be returned. Returning any + * other error will provide a hint what went wrong, but except for assertions, + * no real error handling is implemented. + * + * @param mbox pointer to the mbox to create + * @param size (minimum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** + * @ingroup sys_mbox + * Post a message to an mbox - may not fail + * -> blocks if full, only to be used from tasks NOT from ISR! + * + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Try to post a message to an mbox - may fail if full. + * Can be used from ISR (if the sys arch layer allows this). + * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. + * + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Try to post a message to an mbox - may fail if full. + * To be be used from ISR. + * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. + * + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Blocks the thread until a message arrives in the mailbox, but does + * not block the thread longer than "timeout" milliseconds (similar to + * the sys_arch_sem_wait() function). If "timeout" is 0, the thread should + * be blocked until a message arrives. The "msg" argument is a result + * parameter that is set by the function (i.e., by doing "*msg = + * ptr"). The "msg" parameter maybe NULL to indicate that the message + * should be dropped. + * The return values are the same as for the sys_arch_sem_wait() function: + * SYS_ARCH_TIMEOUT if there was a timeout, any other value if a messages + * is received. + * + * Note that a function with a similar name, sys_mbox_fetch(), is + * implemented by lwIP. + * + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) + * @return SYS_ARCH_TIMEOUT on timeout, any other value if a message has been received + */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** + * @ingroup sys_mbox + * This is similar to sys_arch_mbox_fetch, however if a message is not + * present in the mailbox, it immediately returns with the code + * SYS_MBOX_EMPTY. On success 0 is returned. + * To allow for efficient implementations, this can be defined as a + * function-like macro in sys_arch.h instead of a normal function. For + * example, a naive implementation could be: + * \#define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1) + * although this would introduce unnecessary delays. + * + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty + */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** + * For now, we map straight to sys_arch implementation. + */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** + * @ingroup sys_mbox + * Deallocates a mailbox. If there are messages still present in the + * mailbox when the mailbox is deallocated, it is an indication of a + * programming error in lwIP and the developer should be notified. + * + * @param mbox mbox to delete + */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** + * @ingroup sys_mbox + * Returns 1 if the mailbox is valid, 0 if it is not valid. + * When using pointers, a simple way is to check the pointer for != NULL. + * When directly using OS structures, implementing this may be more complex. + * This may also be a define, in which case the function is not prototyped. + */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** + * @ingroup sys_mbox + * Invalidate a mailbox so that sys_mbox_valid() returns 0. + * ATTENTION: This does NOT mean that the mailbox shall be deallocated: + * sys_mbox_free() is always called before calling this function! + * This may also be a define, in which case the function is not prototyped. + */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_valid_val +/** + * Same as sys_mbox_valid() but taking a value, not a pointer + */ +#define sys_mbox_valid_val(mbox) sys_mbox_valid(&(mbox)) +#endif +#ifndef sys_mbox_set_invalid_val +/** + * Same as sys_mbox_set_invalid() but taking a value, not a pointer + */ +#define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox)) +#endif + + +/** + * @ingroup sys_misc + * The only thread function: + * Starts a new thread named "name" with priority "prio" that will begin its + * execution in the function "thread()". The "arg" argument will be passed as an + * argument to the thread() function. The stack size to used for this thread is + * the "stacksize" parameter. The id of the new thread is returned. Both the id + * and the priority are system dependent. + * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) + * + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/** + * @ingroup sys_misc + * sys_init() must be called before anything else. + * Initialize the sys_arch layer. + */ +void sys_init(void); + +#ifndef sys_jiffies +/** + * Ticks/jiffies since power up. + */ +u32_t sys_jiffies(void); +#endif + +/** + * @ingroup sys_time + * Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. + * Don't care for wraparound, this is only used for time diffs. + * Not implementing this function means you cannot use some modules (e.g. TCP + * timestamps, internal timeouts for NO_SYS==1). + */ +u32_t sys_now(void); + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** + * @ingroup sys_prot + * SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** + * @ingroup sys_prot + * SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** + * @ingroup sys_prot + * SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + +#ifndef SYS_ARCH_LOCKED +#define SYS_ARCH_LOCKED(code) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + code; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_LOCKED */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SYS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcp.h new file mode 100644 index 0000000..daf7599 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcp.h @@ -0,0 +1,500 @@ +/** + * @file + * TCP API (to be used from TCPIP thread)\n + * See also @ref tcp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_H +#define LWIP_HDR_TCP_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcpbase.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; +struct tcp_pcb_listen; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) @todo! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +#if LWIP_WND_SCALE +#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) +#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) +#define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) +#else +#define RCV_WND_SCALE(pcb, wnd) (wnd) +#define SND_WND_SCALE(pcb, wnd) (wnd) +#define TCPWND16(x) (x) +#define TCP_WND_MAX(pcb) TCP_WND +#endif +/* Increments a tcpwnd_size_t and holds at max value rather than rollover */ +#define TCP_WND_INC(wnd, inc) do { \ + if ((tcpwnd_size_t)(wnd + inc) >= wnd) { \ + wnd = (tcpwnd_size_t)(wnd + inc); \ + } else { \ + wnd = (tcpwnd_size_t)-1; \ + } \ + } while(0) + +#if LWIP_TCP_SACK_OUT +/** SACK ranges to include in ACK packets. + * SACK entry is invalid if left==right. */ +struct tcp_sack_range { + /** Left edge of the SACK: the first acknowledged sequence number. */ + u32_t left; + /** Right edge of the SACK: the last acknowledged sequence number +1 (so first NOT acknowledged). */ + u32_t right; +}; +#endif /* LWIP_TCP_SACK_OUT */ + +/** Function prototype for deallocation of arguments. Called *just before* the + * pcb is freed, so don't expect to be able to do anything with this pcb! + * + * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) + * @param data pointer to the data (set via @ref tcp_ext_arg_set before) + */ +typedef void (*tcp_extarg_callback_pcb_destroyed_fn)(u8_t id, void *data); + +/** Function prototype to transition arguments from a listening pcb to an accepted pcb + * + * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) + * @param lpcb the listening pcb accepting a connection + * @param cpcb the newly allocated connection pcb + * @return ERR_OK if OK, any error if connection should be dropped + */ +typedef err_t (*tcp_extarg_callback_passive_open_fn)(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); + +/** A table of callback functions that is invoked for ext arguments */ +struct tcp_ext_arg_callbacks { + /** @ref tcp_extarg_callback_pcb_destroyed_fn */ + tcp_extarg_callback_pcb_destroyed_fn destroy; + /** @ref tcp_extarg_callback_passive_open_fn */ + tcp_extarg_callback_passive_open_fn passive_open; +}; + +#define LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID 0xFF + +#if LWIP_TCP_PCB_NUM_EXT_ARGS +/* This is the structure for ext args in tcp pcbs (used as array) */ +struct tcp_pcb_ext_args { + const struct tcp_ext_arg_callbacks *callbacks; + void *data; +}; +/* This is a helper define to prevent zero size arrays if disabled */ +#define TCP_PCB_EXTARGS struct tcp_pcb_ext_args ext_args[LWIP_TCP_PCB_NUM_EXT_ARGS]; +#else +#define TCP_PCB_EXTARGS +#endif + +typedef u16_t tcpflags_t; +#define TCP_ALLFLAGS 0xffffU + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + void *callback_arg; \ + TCP_PCB_EXTARGS \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + /* ports are in host byte order */ \ + u16_t local_port + + +/** the TCP protocol control block for listening pcbs */ +struct tcp_pcb_listen { +/** Common members of all PCB types */ + IP_PCB; +/** Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. */ + tcp_accept_fn accept; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + + +/** the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + tcpflags_t flags; +#define TF_ACK_DELAY 0x01U /* Delayed ACK. */ +#define TF_ACK_NOW 0x02U /* Immediate ACK. */ +#define TF_INFR 0x04U /* In fast recovery. */ +#define TF_CLOSEPEND 0x08U /* If this is set, tcp_close failed to enqueue the FIN (retried in tcp_tmr) */ +#define TF_RXCLOSED 0x10U /* rx closed by tcp_shutdown */ +#define TF_FIN 0x20U /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY 0x40U /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ +#if LWIP_WND_SCALE +#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */ +#endif +#if TCP_LISTEN_BACKLOG +#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */ +#endif +#if LWIP_TCP_TIMESTAMPS +#define TF_TIMESTAMP 0x0400U /* Timestamp option enabled */ +#endif +#define TF_RTO 0x0800U /* RTO timer has fired, in-flight data moved to unsent and being retransmitted */ +#if LWIP_TCP_SACK_OUT +#define TF_SACK 0x1000U /* Selective ACKs enabled */ +#endif + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + + /* Timers */ + u8_t polltmr, pollinterval; + u8_t last_timer; + u32_t tmr; + + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + tcpwnd_size_t rcv_wnd; /* receiver window available */ + tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + +#if LWIP_TCP_SACK_OUT + /* SACK ranges to include in ACK packets (entry is invalid if left==right) */ + struct tcp_sack_range rcv_sacks[LWIP_TCP_MAX_SACK_NUM]; +#define LWIP_TCP_SACK_VALID(pcb, idx) ((pcb)->rcv_sacks[idx].left != (pcb)->rcv_sacks[idx].right) +#endif /* LWIP_TCP_SACK_OUT */ + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @see "Congestion Avoidance and Control" by Van Jacobson and Karels */ + + s16_t rto; /* retransmission time-out (in ticks of TCP_SLOW_INTERVAL) */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u8_t dupacks; + u32_t lastack; /* Highest acknowledged seqno. */ + + /* congestion avoidance/control variables */ + tcpwnd_size_t cwnd; + tcpwnd_size_t ssthresh; + + /* first byte following last rto byte */ + u32_t rto_end; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + tcpwnd_size_t snd_wnd; /* sender window */ + tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ + + tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) + u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + tcpwnd_size_t bytes_acked; + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + struct tcp_pcb_listen* listener; +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u8_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + /* Number of persist probes */ + u8_t persist_probe; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; + +#if LWIP_WND_SCALE + u8_t snd_scale; + u8_t rcv_scale; +#endif +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void); +struct tcp_pcb * tcp_new_ip_type (u8_t type); + +void tcp_arg (struct tcp_pcb *pcb, void *arg); +#if LWIP_CALLBACK_API +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); +#endif /* LWIP_CALLBACK_API */ +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); + +#define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0) +#define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0) +#define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) + +#if LWIP_TCP_TIMESTAMPS +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#else /* LWIP_TCP_TIMESTAMPS */ +/** @ingroup tcp_raw */ +#define tcp_mss(pcb) ((pcb)->mss) +#endif /* LWIP_TCP_TIMESTAMPS */ +/** @ingroup tcp_raw */ +#define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) +/** @ingroup tcp_raw */ +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +/** @ingroup tcp_raw */ +#define tcp_nagle_disable(pcb) tcp_set_flags(pcb, TF_NODELAY) +/** @ingroup tcp_raw */ +#define tcp_nagle_enable(pcb) tcp_clear_flags(pcb, TF_NODELAY) +/** @ingroup tcp_raw */ +#define tcp_nagle_disabled(pcb) tcp_is_flag_set(pcb, TF_NODELAY) + +#if TCP_LISTEN_BACKLOG +#define tcp_backlog_set(pcb, new_backlog) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \ + ((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0) +void tcp_backlog_delayed(struct tcp_pcb* pcb); +void tcp_backlog_accepted(struct tcp_pcb* pcb); +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_backlog_set(pcb, new_backlog) +#define tcp_backlog_delayed(pcb) +#define tcp_backlog_accepted(pcb) +#endif /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) do { LWIP_UNUSED_ARG(pcb); } while(0) /* compatibility define, not needed any more */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len); +err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +void tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); +err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected); + +struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +/** @ingroup tcp_raw */ +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb); +err_t tcp_close (struct tcp_pcb *pcb); +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags); + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +err_t tcp_output (struct tcp_pcb *pcb); + +err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port); + +#define tcp_dbg_get_tcp_state(pcb) ((pcb)->state) + +/* for compatibility with older implementation */ +#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) + +#if LWIP_TCP_PCB_NUM_EXT_ARGS +u8_t tcp_ext_arg_alloc_id(void); +void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks); +void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg); +void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpbase.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpbase.h new file mode 100644 index 0000000..0023074 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpbase.h @@ -0,0 +1,88 @@ +/** + * @file + * Base TCP API definitions shared by TCP and ALTCP\n + * See also @ref tcp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPBASE_H +#define LWIP_HDR_TCPBASE_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_WND_SCALE +typedef u32_t tcpwnd_size_t; +#else +typedef u16_t tcpwnd_size_t; +#endif + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; +/* ATTENTION: this depends on state number ordering! */ +#define TCP_STATE_IS_CLOSING(state) ((state) >= FIN_WAIT_1) + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +const char* tcp_debug_state_str(enum tcp_state s); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCPBASE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpip.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpip.h new file mode 100644 index 0000000..0b8880a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/tcpip.h @@ -0,0 +1,113 @@ +/** + * @file + * Functions to sync with TCPIP thread + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_H +#define LWIP_HDR_TCPIP_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/timeouts.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +#if !defined LOCK_TCPIP_CORE || defined __DOXYGEN__ +/** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +/** Unlock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#endif /* LOCK_TCPIP_CORE */ +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +struct pbuf; +struct netif; + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +/* Forward declarations */ +struct tcpip_callback_msg; + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +err_t tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn); +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +err_t tcpip_try_callback(tcpip_callback_fn function, void *ctx); +err_t tcpip_callback(tcpip_callback_fn function, void *ctx); +/** @ingroup lwip_os + * @deprecated use tcpip_try_callback() or tcpip_callback() instead + */ +#define tcpip_callback_with_block(function, ctx, block) ((block != 0)? tcpip_callback(function, ctx) : tcpip_try_callback(function, ctx)) + +struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); +void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); +err_t tcpip_callbackmsg_trycallback(struct tcpip_callback_msg* msg); +err_t tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg* msg); + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + +#ifdef TCPIP_THREAD_TEST +int tcpip_thread_poll_one(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/timeouts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/timeouts.h new file mode 100644 index 0000000..b601f9e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/timeouts.h @@ -0,0 +1,128 @@ +/** + * @file + * Timer implementations + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_TIMEOUTS_H +#define LWIP_HDR_TIMEOUTS_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#if !NO_SYS +#include "lwip/sys.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Returned by sys_timeouts_sleeptime() to indicate there is no timer, so we + * can sleep forever. + */ +#define SYS_TIMEOUTS_SLEEPTIME_INFINITE 0xFFFFFFFF + +/** Function prototype for a stack-internal timer function that has to be + * called at a defined interval */ +typedef void (* lwip_cyclic_timer_handler)(void); + +/** This struct contains information about a stack-internal timer function + that has to be called at a defined interval */ +struct lwip_cyclic_timer { + u32_t interval_ms; + lwip_cyclic_timer_handler handler; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +/** This array contains all stack-internal cyclic timers. To get the number of + * timers, use lwip_num_cyclic_timers */ +extern const struct lwip_cyclic_timer lwip_cyclic_timers[]; +/** Array size of lwip_cyclic_timers[] */ +extern const int lwip_num_cyclic_timers; + +#if LWIP_TIMERS + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void); + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg); +void sys_restart_timeouts(void); +void sys_check_timeouts(void); +u32_t sys_timeouts_sleeptime(void); + +#if LWIP_TESTMODE +struct sys_timeo** sys_timeouts_get_next_timeout(void); +void lwip_cyclic_timer(void *arg); +#endif + +#endif /* LWIP_TIMERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_TIMEOUTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/udp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/udp.h new file mode 100644 index 0000000..b1c78e5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/lwip/udp.h @@ -0,0 +1,195 @@ +/** + * @file + * UDP API (to be used from TCPIP thread)\n + * See also @ref udp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_UDP_H +#define LWIP_HDR_UDP_H + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' might point into the pbuf 'p' so freeing this pbuf + * can make 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port); + +/** the UDP protocol control block */ +struct udp_pcb { +/** Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_MULTICAST_TX_OPTIONS +#if LWIP_IPV4 + /** outgoing network interface for multicast packets, by IPv4 address (if not 'any') */ + ip4_addr_t mcast_ip4; +#endif /* LWIP_IPV4 */ + /** outgoing network interface for multicast packets, by interface index (if nonzero) */ + u8_t mcast_ifindex; + /** TTL for outgoing multicast packets */ + u8_t mcast_ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for external reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void); +struct udp_pcb * udp_new_ip_type(u8_t type); +void udp_remove (struct udp_pcb *pcb); +err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +void udp_bind_netif (struct udp_pcb *pcb, const struct netif* netif); +err_t udp_connect (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +void udp_disconnect (struct udp_pcb *pcb); +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg); +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif); +err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, const ip_addr_t *src_ip); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port); +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum); +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum); +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum); +err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, + u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +#define udp_set_flags(pcb, set_flags) do { (pcb)->flags = (u8_t)((pcb)->flags | (set_flags)); } while(0) +#define udp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (u8_t)((pcb)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) +#define udp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp); + +void udp_init (void); + +/* for compatibility with older implementation */ +#define udp_new_ip6() udp_new_ip_type(IPADDR_TYPE_V6) + +#if LWIP_MULTICAST_TX_OPTIONS +#if LWIP_IPV4 +#define udp_set_multicast_netif_addr(pcb, ip4addr) ip4_addr_copy((pcb)->mcast_ip4, *(ip4addr)) +#define udp_get_multicast_netif_addr(pcb) (&(pcb)->mcast_ip4) +#endif /* LWIP_IPV4 */ +#define udp_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) +#define udp_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) +#define udp_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) +#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* LWIP_HDR_UDP_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif.h new file mode 100644 index 0000000..f4f8cf1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif.h @@ -0,0 +1,127 @@ +/** + * @file + * lwIP netif implementing an IEEE 802.1D MAC Bridge + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_NETIF_BRIDGEIF_H +#define LWIP_HDR_NETIF_BRIDGEIF_H + +#include "netif/bridgeif_opts.h" + +#include "lwip/err.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netif; + +#if (BRIDGEIF_MAX_PORTS < 0) || (BRIDGEIF_MAX_PORTS >= 64) +#error BRIDGEIF_MAX_PORTS must be [1..63] +#elif BRIDGEIF_MAX_PORTS < 8 +typedef u8_t bridgeif_portmask_t; +#elif BRIDGEIF_MAX_PORTS < 16 +typedef u16_t bridgeif_portmask_t; +#elif BRIDGEIF_MAX_PORTS < 32 +typedef u32_t bridgeif_portmask_t; +#elif BRIDGEIF_MAX_PORTS < 64 +typedef u64_t bridgeif_portmask_t; +#endif + +#define BR_FLOOD ((bridgeif_portmask_t)-1) + +/** @ingroup bridgeif + * Initialisation data for @ref bridgeif_init. + * An instance of this type must be passed as parameter 'state' to @ref netif_add + * when the bridge is added. + */ +typedef struct bridgeif_initdata_s { + /** MAC address of the bridge (cannot use the netif's addresses) */ + struct eth_addr ethaddr; + /** Maximum number of ports in the bridge (ports are stored in an array, this + influences memory allocated for netif->state of the bridge netif). */ + u8_t max_ports; + /** Maximum number of dynamic/learning entries in the bridge's forwarding database. + In the default implementation, this controls memory consumption only. */ + u16_t max_fdb_dynamic_entries; + /** Maximum number of static forwarding entries. Influences memory consumption! */ + u16_t max_fdb_static_entries; +} bridgeif_initdata_t; + +/** @ingroup bridgeif + * Use this for constant initialization of a bridgeif_initdat_t + * (ethaddr must be passed as ETH_ADDR()) + */ +#define BRIDGEIF_INITDATA1(max_ports, max_fdb_dynamic_entries, max_fdb_static_entries, ethaddr) {ethaddr, max_ports, max_fdb_dynamic_entries, max_fdb_static_entries} +/** @ingroup bridgeif + * Use this for constant initialization of a bridgeif_initdat_t + * (each byte of ethaddr must be passed) + */ +#define BRIDGEIF_INITDATA2(max_ports, max_fdb_dynamic_entries, max_fdb_static_entries, e0, e1, e2, e3, e4, e5) {{e0, e1, e2, e3, e4, e5}, max_ports, max_fdb_dynamic_entries, max_fdb_static_entries} + +err_t bridgeif_init(struct netif *netif); +err_t bridgeif_add_port(struct netif *bridgeif, struct netif *portif); +err_t bridgeif_fdb_add(struct netif *bridgeif, const struct eth_addr *addr, bridgeif_portmask_t ports); +err_t bridgeif_fdb_remove(struct netif *bridgeif, const struct eth_addr *addr); + +/* FDB interface, can be replaced by own implementation */ +void bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx); +bridgeif_portmask_t bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr); +void* bridgeif_fdb_init(u16_t max_fdb_entries); + +#if BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT +#ifndef BRIDGEIF_DECL_PROTECT +/* define bridgeif protection to sys_arch_protect... */ +#include "lwip/sys.h" +#define BRIDGEIF_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) +#define BRIDGEIF_READ_PROTECT(lev) SYS_ARCH_PROTECT(lev) +#define BRIDGEIF_READ_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) +#define BRIDGEIF_WRITE_PROTECT(lev) +#define BRIDGEIF_WRITE_UNPROTECT(lev) +#endif +#else /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ +#include "lwip/tcpip.h" +#define BRIDGEIF_DECL_PROTECT(lev) +#define BRIDGEIF_READ_PROTECT(lev) +#define BRIDGEIF_READ_UNPROTECT(lev) +#define BRIDGEIF_WRITE_PROTECT(lev) +#define BRIDGEIF_WRITE_UNPROTECT(lev) +#endif /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_BRIDGEIF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif_opts.h new file mode 100644 index 0000000..b85c301 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/bridgeif_opts.h @@ -0,0 +1,90 @@ +/** + * @file + * lwIP netif implementing an IEEE 802.1D MAC Bridge + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_NETIF_BRIDGEIF_OPTS_H +#define LWIP_HDR_NETIF_BRIDGEIF_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup bridgeif_opts Options + * @ingroup bridgeif + * @{ + */ + +/** BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT==1: set port netif's 'input' function + * to call directly into bridgeif code and on top of that, directly call into + * the selected forwarding port's 'linkoutput' function. + * This means that the bridgeif input/output path is protected from concurrent access + * but as well, *all* bridge port netif's drivers must correctly handle concurrent access! + * == 0: get into tcpip_thread for every input packet (no multithreading) + * ATTENTION: as ==0 relies on tcpip.h, the default depends on NO_SYS setting + */ +#ifndef BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT +#define BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT NO_SYS +#endif + +/** BRIDGEIF_MAX_PORTS: this is used to create a typedef used for forwarding + * bit-fields: the number of bits required is this + 1 (for the internal/cpu port) + * (63 is the maximum, resulting in an u64_t for the bit mask) + * ATTENTION: this controls the maximum number of the implementation only! + * The max. number of ports per bridge must still be passed via netif_add parameter! + */ +#ifndef BRIDGEIF_MAX_PORTS +#define BRIDGEIF_MAX_PORTS 7 +#endif + +/** BRIDGEIF_DEBUG: Enable generic debugging in bridgeif.c. */ +#ifndef BRIDGEIF_DEBUG +#define BRIDGEIF_DEBUG LWIP_DBG_OFF +#endif + +/** BRIDGEIF_DEBUG: Enable FDB debugging in bridgeif.c. */ +#ifndef BRIDGEIF_FDB_DEBUG +#define BRIDGEIF_FDB_DEBUG LWIP_DBG_OFF +#endif + +/** BRIDGEIF_DEBUG: Enable forwarding debugging in bridgeif.c. */ +#ifndef BRIDGEIF_FW_DEBUG +#define BRIDGEIF_FW_DEBUG LWIP_DBG_OFF +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_NETIF_BRIDGEIF_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/etharp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/etharp.h new file mode 100644 index 0000000..b536fd2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/etharp.h @@ -0,0 +1,3 @@ +/* ARP has been moved to core/ipv4, provide this #include for compatibility only */ +#include "lwip/etharp.h" +#include "netif/ethernet.h" diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ethernet.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ethernet.h new file mode 100644 index 0000000..49649cb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ethernet.h @@ -0,0 +1,77 @@ +/** + * @file + * Ethernet input function - handles INCOMING ethernet level traffic + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHERNET_H +#define LWIP_HDR_NETIF_ETHERNET_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ARP || LWIP_ETHERNET + +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + +err_t ethernet_input(struct pbuf *p, struct netif *netif); +err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type); + +extern const struct eth_addr ethbroadcast, ethzero; + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_ETHERNET_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ieee802154.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ieee802154.h new file mode 100644 index 0000000..54e019f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ieee802154.h @@ -0,0 +1,112 @@ +/** + * @file + * Definitions for IEEE 802.15.4 MAC frames + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_NETIF_IEEE802154_H +#define LWIP_HDR_NETIF_IEEE802154_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** General MAC frame format + * This shows the full featured header, mainly for documentation. + * Some fields are omitted or shortened to achieve frame compression. + */ +struct ieee_802154_hdr { + /** See IEEE_802154_FC_* defines */ + PACK_STRUCT_FIELD(u16_t frame_control); + /** Sequence number is omitted if IEEE_802154_FC_SEQNO_SUPPR is set in frame_control */ + PACK_STRUCT_FLD_8(u8_t sequence_number); + /** Destination PAN ID is omitted if Destination Addressing Mode is 0 */ + PACK_STRUCT_FIELD(u16_t destination_pan_id); + /** Destination Address is omitted if Destination Addressing Mode is 0 */ + PACK_STRUCT_FLD_8(u8_t destination_address[8]); + /** Source PAN ID is omitted if Source Addressing Mode is 0 + or if IEEE_802154_FC_PANID_COMPR is set in frame control*/ + PACK_STRUCT_FIELD(u16_t source_pan_id); + /** Source Address is omitted if Source Addressing Mode is 0 */ + PACK_STRUCT_FLD_8(u8_t source_address[8]); + /* The rest is variable */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Addressing modes (2 bits) */ +#define IEEE_802154_ADDR_MODE_NO_ADDR 0x00 /* PAN ID and address fields are not present */ +#define IEEE_802154_ADDR_MODE_RESERVED 0x01 /* Reserved */ +#define IEEE_802154_ADDR_MODE_SHORT 0x02 /* Address field contains a short address (16 bit) */ +#define IEEE_802154_ADDR_MODE_EXT 0x03 /* Address field contains an extended address (64 bit) */ + +/* IEEE 802.15.4 Frame Control definitions (2 bytes; see IEEE 802.15.4-2015 ch. 7.2.1) */ +#define IEEE_802154_FC_FT_MASK 0x0007 /* bits 0..2: Frame Type */ +#define IEEE_802154_FC_FT_BEACON 0x00 +#define IEEE_802154_FC_FT_DATA 0x01 +#define IEEE_802154_FC_FT_ACK 0x02 +#define IEEE_802154_FC_FT_MAC_CMD 0x03 +#define IEEE_802154_FC_FT_RESERVED 0x04 +#define IEEE_802154_FC_FT_MULTIPURPOSE 0x05 +#define IEEE_802154_FC_FT_FRAG 0x06 +#define IEEE_802154_FC_FT_EXT 0x07 +#define IEEE_802154_FC_SEC_EN 0x0008 /* bit 3: Security Enabled */ +#define IEEE_802154_FC_FRAME_PEND 0x0010 /* bit 4: Frame Pending */ +#define IEEE_802154_FC_ACK_REQ 0x0020 /* bit 5: AR (ACK required) */ +#define IEEE_802154_FC_PANID_COMPR 0x0040 /* bit 6: PAN ID Compression (src and dst are equal, src PAN ID omitted) */ +#define IEEE_802154_FC_RESERVED 0x0080 +#define IEEE_802154_FC_SEQNO_SUPPR 0x0100 /* bit 8: Sequence Number Suppression */ +#define IEEE_802154_FC_IE_PRESENT 0x0200 /* bit 9: IE Present */ +#define IEEE_802154_FC_DST_ADDR_MODE_MASK 0x0c00 /* bits 10..11: Destination Addressing Mode */ +#define IEEE_802154_FC_DST_ADDR_MODE_NO_ADDR (IEEE_802154_ADDR_MODE_NO_ADDR << 10) +#define IEEE_802154_FC_DST_ADDR_MODE_SHORT (IEEE_802154_ADDR_MODE_SHORT << 10) +#define IEEE_802154_FC_DST_ADDR_MODE_EXT (IEEE_802154_ADDR_MODE_EXT << 10) +#define IEEE_802154_FC_FRAME_VERSION_MASK 0x3000 /* bits 12..13: Frame Version */ +#define IEEE_802154_FC_FRAME_VERSION_GET(x) (((x) & IEEE_802154_FC_FRAME_VERSION_MASK) >> 12) +#define IEEE_802154_FC_SRC_ADDR_MODE_MASK 0xc000 /* bits 14..15: Source Addressing Mode */ +#define IEEE_802154_FC_SRC_ADDR_MODE_SHORT (IEEE_802154_ADDR_MODE_SHORT << 14) +#define IEEE_802154_FC_SRC_ADDR_MODE_EXT (IEEE_802154_ADDR_MODE_EXT << 14) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_IEEE802154_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6.h new file mode 100644 index 0000000..ecff24b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6.h @@ -0,0 +1,89 @@ +/** + * @file + * + * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + */ + +/* + * Copyright (c) 2015 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_H +#define LWIP_HDR_LOWPAN6_H + +#include "netif/lowpan6_opts.h" + +#if LWIP_IPV6 + +#include "netif/lowpan6_common.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period for reassembly */ +#define LOWPAN6_TMR_INTERVAL 1000 + +void lowpan6_tmr(void); + +err_t lowpan6_set_context(u8_t idx, const ip6_addr_t * context); +err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); + +#if LWIP_IPV4 +err_t lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4 */ +err_t lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); +err_t lowpan6_input(struct pbuf * p, struct netif *netif); +err_t lowpan6_if_init(struct netif *netif); + +/* pan_id in network byte order. */ +err_t lowpan6_set_pan_id(u16_t pan_id); + +u16_t lowpan6_calc_crc(const void *buf, u16_t len); + +#if !NO_SYS +err_t tcpip_6lowpan_input(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_LOWPAN6_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_ble.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_ble.h new file mode 100644 index 0000000..01896a7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_ble.h @@ -0,0 +1,78 @@ +/** + * @file + * 6LowPAN over BLE for IPv6 (RFC7668). + */ + +/* + * Copyright (c) 2017 Benjamin Aigner + * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Benjamin Aigner + * + * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c) + */ + +#ifndef LWIP_HDR_LOWPAN6_BLE_H +#define LWIP_HDR_LOWPAN6_BLE_H + +#include "netif/lowpan6_opts.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "netif/lowpan6_common.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t rfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); +err_t rfc7668_input(struct pbuf * p, struct netif *netif); +err_t rfc7668_set_local_addr_eui64(struct netif *netif, const u8_t *local_addr, size_t local_addr_len); +err_t rfc7668_set_local_addr_mac48(struct netif *netif, const u8_t *local_addr, size_t local_addr_len, int is_public_addr); +err_t rfc7668_set_peer_addr_eui64(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len); +err_t rfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len, int is_public_addr); +err_t rfc7668_set_context(u8_t index, const ip6_addr_t * context); +err_t rfc7668_if_init(struct netif *netif); + +#if !NO_SYS +err_t tcpip_rfc7668_input(struct pbuf *p, struct netif *inp); +#endif + +void ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr); +void eui64_to_ble_addr(uint8_t *dst, const uint8_t *src); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_LOWPAN6_BLE_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_common.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_common.h new file mode 100644 index 0000000..0dc13ab --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_common.h @@ -0,0 +1,82 @@ +/** + * @file + * + * Common 6LowPAN routines for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + */ + +/* + * Copyright (c) 2015 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_COMMON_H +#define LWIP_HDR_LOWPAN6_COMMON_H + +#include "netif/lowpan6_opts.h" + +#if LWIP_IPV6 /* don't build if IPv6 is disabled in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Helper define for a link layer address, which can be encoded as 0, 2 or 8 bytes */ +struct lowpan6_link_addr { + /* encoded length of the address */ + u8_t addr_len; + /* address bytes */ + u8_t addr[8]; +}; + +s8_t lowpan6_get_address_mode(const ip6_addr_t *ip6addr, const struct lowpan6_link_addr *mac_addr); + +#if LWIP_6LOWPAN_IPHC +err_t lowpan6_compress_headers(struct netif *netif, u8_t *inbuf, size_t inbuf_size, u8_t *outbuf, size_t outbuf_size, + u8_t *lowpan6_header_len_out, u8_t *hidden_header_len_out, ip6_addr_t *lowpan6_contexts, + const struct lowpan6_link_addr *src, const struct lowpan6_link_addr *dst); +struct pbuf *lowpan6_decompress(struct pbuf *p, u16_t datagram_size, ip6_addr_t *lowpan6_contexts, + struct lowpan6_link_addr *src, struct lowpan6_link_addr *dest); +#endif /* LWIP_6LOWPAN_IPHC */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_LOWPAN6_COMMON_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_opts.h new file mode 100644 index 0000000..17d46cd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/lowpan6_opts.h @@ -0,0 +1,122 @@ +/** + * @file + * 6LowPAN options list + */ + +/* + * Copyright (c) 2015 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_OPTS_H +#define LWIP_HDR_LOWPAN6_OPTS_H + +#include "lwip/opt.h" + +/** LWIP_6LOWPAN_NUM_CONTEXTS: define the number of compression + * contexts per netif type + */ +#ifndef LWIP_6LOWPAN_NUM_CONTEXTS +#define LWIP_6LOWPAN_NUM_CONTEXTS 10 +#endif + +/** LWIP_6LOWPAN_INFER_SHORT_ADDRESS: set this to 0 to disable creating + * short addresses for matching addresses (debug only) + */ +#ifndef LWIP_6LOWPAN_INFER_SHORT_ADDRESS +#define LWIP_6LOWPAN_INFER_SHORT_ADDRESS 1 +#endif + +/** LWIP_6LOWPAN_IPHC: set this to 0 to disable IP header compression as per + * RFC 6282 (which is mandatory for BLE) + */ +#ifndef LWIP_6LOWPAN_IPHC +#define LWIP_6LOWPAN_IPHC 1 +#endif + +/** Set this to 1 if your IEEE 802.15.4 interface can calculate and check the + * CRC in hardware. This means TX packets get 2 zero bytes added on transmission + * which are to be filled with the CRC. + */ +#ifndef LWIP_6LOWPAN_802154_HW_CRC +#define LWIP_6LOWPAN_802154_HW_CRC 0 +#endif + +/** If LWIP_6LOWPAN_802154_HW_CRC==0, this can override the default slow + * implementation of the CRC used for 6LoWPAN over IEEE 802.15.4 (which uses + * a shift register). + */ +#ifndef LWIP_6LOWPAN_CALC_CRC +#define LWIP_6LOWPAN_CALC_CRC(buf, len) lowpan6_calc_crc(buf, len) +#endif + +/** Debug level for 6LoWPAN in general */ +#ifndef LWIP_LOWPAN6_DEBUG +#define LWIP_LOWPAN6_DEBUG LWIP_DBG_OFF +#endif + +/** Debug level for 6LoWPAN over IEEE 802.15.4 */ +#ifndef LWIP_LOWPAN6_802154_DEBUG +#define LWIP_LOWPAN6_802154_DEBUG LWIP_DBG_OFF +#endif + +/** LWIP_LOWPAN6_IP_COMPRESSED_DEBUG: enable compressed IP frame + * output debugging + */ +#ifndef LWIP_LOWPAN6_IP_COMPRESSED_DEBUG +#define LWIP_LOWPAN6_IP_COMPRESSED_DEBUG LWIP_DBG_OFF +#endif + +/** LWIP_LOWPAN6_DECOMPRESSION_DEBUG: enable decompression debug output + */ +#ifndef LWIP_LOWPAN6_DECOMPRESSION_DEBUG +#define LWIP_LOWPAN6_DECOMPRESSION_DEBUG LWIP_DBG_OFF +#endif + +/** LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG: enable decompressed IP frame + * output debugging */ +#ifndef LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG +#define LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG LWIP_DBG_OFF +#endif + +/** LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS: + * Currently, the linux kernel driver for 6lowpan sets/clears a bit in + * the address, depending on the BD address (either public or not). + * Might not be RFC7668 conform, so you may select to do that (=1) or + * not (=0) */ +#ifndef LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS +#define LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS 1 +#endif + + +#endif /* LWIP_HDR_LOWPAN6_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ccp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ccp.h new file mode 100644 index 0000000..b228522 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ccp.h @@ -0,0 +1,164 @@ +/* + * ccp.h - Definitions for PPP Compression Control Protocol. + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ccp.h,v 1.12 2004/11/04 10:02:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CCP_H +#define CCP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * CCP codes. + */ + +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ + +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ + +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +#if BSDCOMPRESS_SUPPORT +/* + * Definitions for BSD-Compress. + */ + +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ +#endif /* BSDCOMPRESS_SUPPORT */ + +#if DEFLATE_SUPPORT +/* + * Definitions for Deflate. + */ + +#define CI_DEFLATE 26 /* config option for Deflate */ +#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 9 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + 8) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 +#endif /* DEFLATE_SUPPORT */ + +#if MPPE_SUPPORT +/* + * Definitions for MPPE. + */ + +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ +#endif /* MPPE_SUPPORT */ + +#if PREDICTOR_SUPPORT +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ +#endif /* PREDICTOR_SUPPORT */ + +typedef struct ccp_options { +#if DEFLATE_SUPPORT + unsigned int deflate :1; /* do Deflate? */ + unsigned int deflate_correct :1; /* use correct code for deflate? */ + unsigned int deflate_draft :1; /* use draft RFC code for deflate? */ +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + unsigned int bsd_compress :1; /* do BSD Compress? */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + unsigned int predictor_1 :1; /* do Predictor-1? */ + unsigned int predictor_2 :1; /* do Predictor-2? */ +#endif /* PREDICTOR_SUPPORT */ + +#if MPPE_SUPPORT + u8_t mppe; /* MPPE bitfield */ +#endif /* MPPE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + u_short bsd_bits; /* # bits/code for BSD Compress */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + u_short deflate_size; /* lg(window size) for Deflate */ +#endif /* DEFLATE_SUPPORT */ + u8_t method; /* code for chosen compression method */ +} ccp_options; + +extern const struct protent ccp_protent; + +void ccp_resetrequest(ppp_pcb *pcb); /* Issue a reset-request. */ + +#ifdef __cplusplus +} +#endif + +#endif /* CCP_H */ +#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-md5.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-md5.h new file mode 100644 index 0000000..eb0269f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-md5.h @@ -0,0 +1,36 @@ +/* + * chap-md5.h - New CHAP/MD5 implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +extern const struct chap_digest_type md5_digest; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-new.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-new.h new file mode 100644 index 0000000..2d8cd9c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap-new.h @@ -0,0 +1,200 @@ +/* + * chap-new.c - New CHAP implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAP_H +#define CHAP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * CHAP packets begin with a standard header with code, id, len (2 bytes). + */ +#define CHAP_HDRLEN 4 + +/* + * Values for the code field. + */ +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +/* + * CHAP digest codes. + */ +#define CHAP_MD5 5 +#if MSCHAP_SUPPORT +#define CHAP_MICROSOFT 0x80 +#define CHAP_MICROSOFT_V2 0x81 +#endif /* MSCHAP_SUPPORT */ + +/* + * Semi-arbitrary limits on challenge and response fields. + */ +#define MAX_CHALLENGE_LEN 64 +#define MAX_RESPONSE_LEN 64 + +/* + * These limits apply to challenge and response packets we send. + * The +4 is the +1 that we actually need rounded up. + */ +#define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) +#define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) + +/* bitmask of supported algorithms */ +#if MSCHAP_SUPPORT +#define MDTYPE_MICROSOFT_V2 0x1 +#define MDTYPE_MICROSOFT 0x2 +#endif /* MSCHAP_SUPPORT */ +#define MDTYPE_MD5 0x4 +#define MDTYPE_NONE 0 + +#if MSCHAP_SUPPORT +/* Return the digest alg. ID for the most preferred digest type. */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + ((mdtype) & MDTYPE_MICROSOFT_V2)? CHAP_MICROSOFT_V2: \ + ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Return the bit flag (lsb set) for our most preferred digest type. */ +#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype) + +/* Return the bit flag for a given digest algorithm ID. */ +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MICROSOFT_V2)? MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Can we do the requested digest? */ +#if MSCHAP_SUPPORT +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MICROSOFT_V2)? (mdtype) & MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* + * The code for each digest type has to supply one of these. + */ +struct chap_digest_type { + int code; + +#if PPP_SERVER + /* + * Note: challenge and response arguments below are formatted as + * a length byte followed by the actual challenge/response data. + */ + void (*generate_challenge)(ppp_pcb *pcb, unsigned char *challenge); + int (*verify_response)(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space); +#endif /* PPP_SERVER */ + void (*make_response)(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *priv); + int (*check_success)(ppp_pcb *pcb, unsigned char *pkt, int len, unsigned char *priv); + void (*handle_failure)(ppp_pcb *pcb, unsigned char *pkt, int len); +}; + +/* + * Each interface is described by chap structure. + */ +#if CHAP_SUPPORT +typedef struct chap_client_state { + u8_t flags; + const char *name; + const struct chap_digest_type *digest; + unsigned char priv[64]; /* private area for digest's use */ +} chap_client_state; + +#if PPP_SERVER +typedef struct chap_server_state { + u8_t flags; + u8_t id; + const char *name; + const struct chap_digest_type *digest; + int challenge_xmits; + int challenge_pktlen; + unsigned char challenge[CHAL_MAX_PKTLEN]; +} chap_server_state; +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* Hook for a plugin to validate CHAP challenge */ +extern int (*chap_verify_hook)(char *name, char *ourname, int id, + const struct chap_digest_type *digest, + unsigned char *challenge, unsigned char *response, + char *message, int message_space); +#endif /* UNUSED */ + +#if PPP_SERVER +/* Called by authentication code to start authenticating the peer. */ +extern void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code); +#endif /* PPP_SERVER */ + +/* Called by auth. code to start authenticating us to the peer. */ +extern void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code); + +/* Represents the CHAP protocol to the main pppd code */ +extern const struct protent chap_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* CHAP_H */ +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap_ms.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap_ms.h new file mode 100644 index 0000000..0795291 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/chap_ms.h @@ -0,0 +1,44 @@ +/* + * chap_ms.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: chap_ms.h,v 1.13 2004/11/15 22:13:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAPMS_INCLUDE +#define CHAPMS_INCLUDE + +extern const struct chap_digest_type chapms_digest; +extern const struct chap_digest_type chapms2_digest; + +#endif /* CHAPMS_INCLUDE */ + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eap.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eap.h new file mode 100644 index 0000000..3ee9aaf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eap.h @@ -0,0 +1,169 @@ +/* + * eap.h - Extensible Authentication Protocol for PPP (RFC 2284) + * + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Non-exclusive rights to redistribute, modify, translate, and use + * this software in source and binary forms, in whole or in part, is + * hereby granted, provided that the above copyright notice is + * duplicated in any source form, and that neither the name of the + * copyright holder nor the author is used to endorse or promote + * products derived from this software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Original version by James Carlson + * + * $Id: eap.h,v 1.2 2003/06/11 23:56:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_EAP_H +#define PPP_EAP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Packet header = Code, id, length. + */ +#define EAP_HEADERLEN 4 + + +/* EAP message codes. */ +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +/* EAP types */ +#define EAPT_IDENTITY 1 +#define EAPT_NOTIFICATION 2 +#define EAPT_NAK 3 /* (response only) */ +#define EAPT_MD5CHAP 4 +#define EAPT_OTP 5 /* One-Time Password; RFC 1938 */ +#define EAPT_TOKEN 6 /* Generic Token Card */ +/* 7 and 8 are unassigned. */ +#define EAPT_RSA 9 /* RSA Public Key Authentication */ +#define EAPT_DSS 10 /* DSS Unilateral */ +#define EAPT_KEA 11 /* KEA */ +#define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */ +#define EAPT_TLS 13 /* EAP-TLS */ +#define EAPT_DEFENDER 14 /* Defender Token (AXENT) */ +#define EAPT_W2K 15 /* Windows 2000 EAP */ +#define EAPT_ARCOT 16 /* Arcot Systems */ +#define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */ +#define EAPT_NOKIACARD 18 /* Nokia IP smart card */ +#define EAPT_SRP 19 /* Secure Remote Password */ +/* 20 is deprecated */ + +/* EAP SRP-SHA1 Subtypes */ +#define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */ +#define EAPSRP_CKEY 1 /* Response 1 - Client Key */ +#define EAPSRP_SKEY 2 /* Request 2 - Server Key */ +#define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */ +#define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */ +#define EAPSRP_ACK 3 /* Response 3 - final ack */ +#define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */ + +#define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */ + +#define SRP_PSEUDO_ID "pseudo_" +#define SRP_PSEUDO_LEN 7 + +#define MD5_SIGNATURE_SIZE 16 +#define EAP_MIN_CHALLENGE_LENGTH 17 +#define EAP_MAX_CHALLENGE_LENGTH 24 +#define EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH 3 /* 2^3-1 = 7, 17+7 = 24 */ + +#define EAP_STATES \ + "Initial", "Pending", "Closed", "Listen", "Identify", \ + "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" + +#define eap_client_active(pcb) ((pcb)->eap.es_client.ea_state == eapListen) +#if PPP_SERVER +#define eap_server_active(pcb) \ + ((pcb)->eap.es_server.ea_state >= eapIdentify && \ + (pcb)->eap.es_server.ea_state <= eapMD5Chall) +#endif /* PPP_SERVER */ + +/* + * Complete EAP state for one PPP session. + */ +enum eap_state_code { + eapInitial = 0, /* No EAP authentication yet requested */ + eapPending, /* Waiting for LCP (no timer) */ + eapClosed, /* Authentication not in use */ + eapListen, /* Client ready (and timer running) */ + eapIdentify, /* EAP Identify sent */ + eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ + eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ + eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ + eapMD5Chall, /* Sent MD5-Challenge */ + eapOpen, /* Completed authentication */ + eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ + eapBadAuth /* Failed authentication */ +}; + +struct eap_auth { + const char *ea_name; /* Our name */ + char ea_peer[MAXNAMELEN +1]; /* Peer's name */ + void *ea_session; /* Authentication library linkage */ + u_char *ea_skey; /* Shared encryption key */ + u_short ea_namelen; /* Length of our name */ + u_short ea_peerlen; /* Length of peer's name */ + enum eap_state_code ea_state; + u_char ea_id; /* Current id */ + u_char ea_requests; /* Number of Requests sent/received */ + u_char ea_responses; /* Number of Responses */ + u_char ea_type; /* One of EAPT_* */ + u32_t ea_keyflags; /* SRP shared key usage flags */ +}; + +#ifndef EAP_MAX_CHALLENGE_LENGTH +#define EAP_MAX_CHALLENGE_LENGTH 24 +#endif +typedef struct eap_state { + struct eap_auth es_client; /* Client (authenticatee) data */ +#if PPP_SERVER + struct eap_auth es_server; /* Server (authenticator) data */ +#endif /* PPP_SERVER */ + int es_savedtime; /* Saved timeout */ + int es_rechallenge; /* EAP rechallenge interval */ + int es_lwrechallenge; /* SRP lightweight rechallenge inter */ + u8_t es_usepseudo; /* Use SRP Pseudonym if offered one */ + int es_usedpseudo; /* Set if we already sent PN */ + int es_challen; /* Length of challenge string */ + u_char es_challenge[EAP_MAX_CHALLENGE_LENGTH]; +} eap_state; + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +#define EAP_DEFTRANSMITS 10 /* max # times to transmit */ +#define EAP_DEFREQTIME 20 /* Time to wait for peer request */ +#define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ +#endif /* moved to ppp_opts.h */ + +void eap_authwithpeer(ppp_pcb *pcb, const char *localname); +void eap_authpeer(ppp_pcb *pcb, const char *localname); + +extern const struct protent eap_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_EAP_H */ + +#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ecp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ecp.h new file mode 100644 index 0000000..d8808c3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ecp.h @@ -0,0 +1,62 @@ +/* + * ecp.h - Definitions for PPP Encryption Control Protocol. + * + * Copyright (c) 2002 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ecp.h,v 1.2 2003/01/10 07:12:36 fcusack Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef ECP_H +#define ECP_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ecp_options { + bool required; /* Is ECP required? */ + unsigned enctype; /* Encryption type */ +} ecp_options; + +extern fsm ecp_fsm[]; +extern ecp_options ecp_wantoptions[]; +extern ecp_options ecp_gotoptions[]; +extern ecp_options ecp_allowoptions[]; +extern ecp_options ecp_hisoptions[]; + +extern const struct protent ecp_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* ECP_H */ +#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eui64.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eui64.h new file mode 100644 index 0000000..5adeb48 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/eui64.h @@ -0,0 +1,102 @@ +/* + * eui64.h - EUI64 routines for IPv6CP. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: eui64.h,v 1.6 2002/12/04 23:03:32 paulus Exp $ +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef EUI64_H +#define EUI64_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * @todo: + * + * Maybe this should be done by processing struct in6_addr directly... + */ +typedef union +{ + u8_t e8[8]; + u16_t e16[4]; + u32_t e32[2]; +} eui64_t; + +#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0) +#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \ + ((e).e32[1] == (o).e32[1])) +#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0; + +#define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t)) + +#define eui64_magic(e) do { \ + (e).e32[0] = magic(); \ + (e).e32[1] = magic(); \ + (e).e8[0] &= ~2; \ + } while (0) +#define eui64_magic_nz(x) do { \ + eui64_magic(x); \ + } while (eui64_iszero(x)) +#define eui64_magic_ne(x, y) do { \ + eui64_magic(x); \ + } while (eui64_equals(x, y)) + +#define eui64_get(ll, cp) do { \ + eui64_copy((*cp), (ll)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_put(ll, cp) do { \ + eui64_copy((ll), (*cp)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_set32(e, l) do { \ + (e).e32[0] = 0; \ + (e).e32[1] = lwip_htonl(l); \ + } while (0) +#define eui64_setlo32(e, l) eui64_set32(e, l) + +char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ + +#ifdef __cplusplus +} +#endif + +#endif /* EUI64_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/fsm.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/fsm.h new file mode 100644 index 0000000..8dec700 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/fsm.h @@ -0,0 +1,182 @@ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: fsm.h,v 1.10 2004/11/13 02:28:15 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef FSM_H +#define FSM_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Packet header = Code, id, length. + */ +#define HEADERLEN 4 + + +/* + * CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ 1 /* Configuration Request */ +#define CONFACK 2 /* Configuration Ack */ +#define CONFNAK 3 /* Configuration Nak */ +#define CONFREJ 4 /* Configuration Reject */ +#define TERMREQ 5 /* Termination Request */ +#define TERMACK 6 /* Termination Ack */ +#define CODEREJ 7 /* Code Reject */ + + +/* + * Each FSM is described by an fsm structure and fsm callbacks. + */ +typedef struct fsm { + ppp_pcb *pcb; /* PPP Interface */ + const struct fsm_callbacks *callbacks; /* Callback routines */ + const char *term_reason; /* Reason for closing protocol */ + u8_t seen_ack; /* Have received valid Ack/Nak/Rej to Req */ + /* -- This is our only flag, we might use u_int :1 if we have more flags */ + u16_t protocol; /* Data Link Layer Protocol field value */ + u8_t state; /* State */ + u8_t flags; /* Contains option bits */ + u8_t id; /* Current id */ + u8_t reqid; /* Current request id */ + u8_t retransmits; /* Number of retransmissions left */ + u8_t nakloops; /* Number of nak loops since last ack */ + u8_t rnakloops; /* Number of naks received */ + u8_t maxnakloops; /* Maximum number of nak loops tolerated + (necessary because IPCP require a custom large max nak loops value) */ + u8_t term_reason_len; /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { + void (*resetci) /* Reset our Configuration Information */ + (fsm *); + int (*cilen) /* Length of our Configuration Information */ + (fsm *); + void (*addci) /* Add our Configuration Information */ + (fsm *, u_char *, int *); + int (*ackci) /* ACK our Configuration Information */ + (fsm *, u_char *, int); + int (*nakci) /* NAK our Configuration Information */ + (fsm *, u_char *, int, int); + int (*rejci) /* Reject our Configuration Information */ + (fsm *, u_char *, int); + int (*reqci) /* Request peer's Configuration Information */ + (fsm *, u_char *, int *, int); + void (*up) /* Called when fsm reaches PPP_FSM_OPENED state */ + (fsm *); + void (*down) /* Called when fsm leaves PPP_FSM_OPENED state */ + (fsm *); + void (*starting) /* Called when we want the lower layer */ + (fsm *); + void (*finished) /* Called when we don't want the lower layer */ + (fsm *); + void (*protreject) /* Called when Protocol-Reject received */ + (int); + void (*retransmit) /* Retransmission is necessary */ + (fsm *); + int (*extcode) /* Called when unknown code received */ + (fsm *, int, int, u_char *, int); + const char *proto_name; /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/* + * Link states. + */ +#define PPP_FSM_INITIAL 0 /* Down, hasn't been opened */ +#define PPP_FSM_STARTING 1 /* Down, been opened */ +#define PPP_FSM_CLOSED 2 /* Up, hasn't been opened */ +#define PPP_FSM_STOPPED 3 /* Open, waiting for down event */ +#define PPP_FSM_CLOSING 4 /* Terminating the connection, not open */ +#define PPP_FSM_STOPPING 5 /* Terminating, but open */ +#define PPP_FSM_REQSENT 6 /* We've sent a Config Request */ +#define PPP_FSM_ACKRCVD 7 /* We've received a Config Ack */ +#define PPP_FSM_ACKSENT 8 /* We've sent a Config Ack */ +#define PPP_FSM_OPENED 9 /* Connection available */ + + +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT 4 /* Wait for peer to speak first */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define DEFTIMEOUT 3 /* Timeout time in seconds */ +#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif /* moved to ppp_opts.h */ + + +/* + * Prototypes + */ +void fsm_init(fsm *f); +void fsm_lowerup(fsm *f); +void fsm_lowerdown(fsm *f); +void fsm_open(fsm *f); +void fsm_close(fsm *f, const char *reason); +void fsm_input(fsm *f, u_char *inpacket, int l); +void fsm_protreject(fsm *f); +void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen); + +#ifdef __cplusplus +} +#endif + +#endif /* FSM_H */ +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipcp.h new file mode 100644 index 0000000..32fdd1c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipcp.h @@ -0,0 +1,134 @@ +/* + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipcp.h,v 1.14 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPCP_H +#define IPCP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Options. + */ +#define CI_ADDRS 1 /* IP Addresses */ +#if VJ_SUPPORT +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* VJ_SUPPORT */ +#define CI_ADDR 3 + +#if LWIP_DNS +#define CI_MS_DNS1 129 /* Primary DNS value */ +#define CI_MS_DNS2 131 /* Secondary DNS value */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ +#define CI_MS_WINS1 130 /* Primary WINS value */ +#define CI_MS_WINS2 132 /* Secondary WINS value */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT +#define MAX_STATES 16 /* from slcompress.h */ + +#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ +#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ +#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ + /* maxslot and slot number compression) */ + +#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ +#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ + /* compression option*/ +#endif /* VJ_SUPPORT */ + +typedef struct ipcp_options { + unsigned int neg_addr :1; /* Negotiate IP Address? */ + unsigned int old_addrs :1; /* Use old (IP-Addresses) option? */ + unsigned int req_addr :1; /* Ask peer to send IP address? */ +#if 0 /* UNUSED */ + unsigned int default_route :1; /* Assign default route through interface? */ + unsigned int replace_default_route :1; /* Replace default route through interface? */ +#endif /* UNUSED */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp :1; /* Make proxy ARP entry for peer? */ +#endif /* UNUSED - PROXY ARP */ +#if VJ_SUPPORT + unsigned int neg_vj :1; /* Van Jacobson Compression? */ + unsigned int old_vj :1; /* use old (short) form of VJ option? */ + unsigned int cflag :1; +#endif /* VJ_SUPPORT */ + unsigned int accept_local :1; /* accept peer's value for ouraddr */ + unsigned int accept_remote :1; /* accept peer's value for hisaddr */ +#if LWIP_DNS + unsigned int req_dns1 :1; /* Ask peer to send primary DNS address? */ + unsigned int req_dns2 :1; /* Ask peer to send secondary DNS address? */ +#endif /* LWIP_DNS */ + + u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ +#if LWIP_DNS + u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT + u16_t vj_protocol; /* protocol value to use in VJ option */ + u8_t maxslotindex; /* values for RFC1332 VJ compression neg. */ +#endif /* VJ_SUPPORT */ +} ipcp_options; + +#if 0 /* UNUSED, already defined by lwIP */ +char *ip_ntoa (u32_t); +#endif /* UNUSED, already defined by lwIP */ + +extern const struct protent ipcp_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* IPCP_H */ +#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipv6cp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipv6cp.h new file mode 100644 index 0000000..9099973 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ipv6cp.h @@ -0,0 +1,191 @@ +/* + * ipv6cp.h - PPP IPV6 Control Protocol. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Original version, based on RFC2023 : + + Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt + Économique ayant pour membres BULL S.A. et l'INRIA). + + Ce logiciel informatique est disponible aux conditions + usuelles dans la recherche, c'est-à-dire qu'il peut + être utilisé, copié, modifié, distribué à l'unique + condition que ce texte soit conservé afin que + l'origine de ce logiciel soit reconnue. + + Le nom de l'Institut National de Recherche en Informatique + et en Automatique (INRIA), de l'IMAG, ou d'une personne morale + ou physique ayant participé à l'élaboration de ce logiciel ne peut + être utilisé sans son accord préalable explicite. + + Ce logiciel est fourni tel quel sans aucune garantie, + support ou responsabilité d'aucune sorte. + Ce logiciel est dérivé de sources d'origine + "University of California at Berkeley" et + "Digital Equipment Corporation" couvertes par des copyrights. + + L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) + est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National + Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant + sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + + This work has been done in the context of GIE DYADE (joint R & D venture + between BULL S.A. and INRIA). + + This software is available with usual "research" terms + with the aim of retain credits of the software. + Permission to use, copy, modify and distribute this software for any + purpose and without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies, + and the name of INRIA, IMAG, or any contributor not be used in advertising + or publicity pertaining to this material without the prior explicit + permission. The software is provided "as is" without any + warranties, support or liabilities of any kind. + This software is derived from source code from + "University of California at Berkeley" and + "Digital Equipment Corporation" protected by copyrights. + + Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) + is a federation of seven research units funded by the CNRS, National + Polytechnic Institute of Grenoble and University Joseph Fourier. + The research unit in Software, Systems, Networks (LSR) is member of IMAG. +*/ + +/* + * Derived from : + * + * + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipv6cp.h,v 1.7 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPV6CP_H +#define IPV6CP_H + +#include "eui64.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Options. + */ +#define CI_IFACEID 1 /* Interface Identifier */ +#ifdef IPV6CP_COMP +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* IPV6CP_COMP */ + +/* No compression types yet defined. + *#define IPV6CP_COMP 0x004f + */ +typedef struct ipv6cp_options { + unsigned int neg_ifaceid :1; /* Negotiate interface identifier? */ + unsigned int req_ifaceid :1; /* Ask peer to send interface identifier? */ + unsigned int accept_local :1; /* accept peer's value for iface id? */ + unsigned int opt_local :1; /* ourtoken set by option */ + unsigned int opt_remote :1; /* histoken set by option */ + unsigned int use_ip :1; /* use IP as interface identifier */ +#if 0 + unsigned int use_persistent :1; /* use uniquely persistent value for address */ +#endif +#ifdef IPV6CP_COMP + unsigned int neg_vj :1; /* Van Jacobson Compression? */ +#endif /* IPV6CP_COMP */ + +#ifdef IPV6CP_COMP + u_short vj_protocol; /* protocol value to use in VJ option */ +#endif /* IPV6CP_COMP */ + eui64_t ourid, hisid; /* Interface identifiers */ +} ipv6cp_options; + +extern const struct protent ipv6cp_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* IPV6CP_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/lcp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/lcp.h new file mode 100644 index 0000000..18ad1cb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/lcp.h @@ -0,0 +1,179 @@ +/* + * lcp.h - Link Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: lcp.h,v 1.20 2004/11/14 22:53:42 carlsonj Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef LCP_H +#define LCP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Options. + */ +#define CI_VENDOR 0 /* Vendor Specific */ +#define CI_MRU 1 /* Maximum Receive Unit */ +#define CI_ASYNCMAP 2 /* Async Control Character Map */ +#define CI_AUTHTYPE 3 /* Authentication Type */ +#define CI_QUALITY 4 /* Quality Protocol */ +#define CI_MAGICNUMBER 5 /* Magic Number */ +#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ +#define CI_FCSALTERN 9 /* FCS-Alternatives */ +#define CI_SDP 10 /* Self-Describing-Pad */ +#define CI_NUMBERED 11 /* Numbered-Mode */ +#define CI_CALLBACK 13 /* callback */ +#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF 18 /* short sequence numbers for multilink */ +#define CI_EPDISC 19 /* endpoint discriminator */ +#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ +#define CI_LDISC 23 /* Link-Discriminator */ +#define CI_LCPAUTH 24 /* LCP Authentication */ +#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ +#define CI_PREFELIS 26 /* Prefix Elision */ +#define CI_MPHDRFMT 27 /* MP Header Format */ +#define CI_I18N 28 /* Internationalization */ +#define CI_SDL 29 /* Simple Data Link */ + +/* + * LCP-specific packet types (code numbers). + */ +#define PROTREJ 8 /* Protocol Reject */ +#define ECHOREQ 9 /* Echo Request */ +#define ECHOREP 10 /* Echo Reply */ +#define DISCREQ 11 /* Discard Request */ +#define IDENTIF 12 /* Identification */ +#define TIMEREM 13 /* Time Remaining */ + +/* Value used as data for CI_CALLBACK option */ +#define CBCP_OPT 6 /* Use callback control protocol */ + +#if 0 /* moved to ppp_opts.h */ +#define DEFMRU 1500 /* Try for this */ +#define MINMRU 128 /* No MRUs below this */ +#define MAXMRU 16384 /* Normally limit MRU to this */ +#endif /* moved to ppp_opts.h */ + +/* An endpoint discriminator, used with multilink. */ +#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ +struct epdisc { + unsigned char class_; /* -- The word "class" is reserved in C++. */ + unsigned char length; + unsigned char value[MAX_ENDP_LEN]; +}; + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { + unsigned int passive :1; /* Don't die if we don't get a response */ + unsigned int silent :1; /* Wait for the other end to start first */ +#if 0 /* UNUSED */ + unsigned int restart :1; /* Restart vs. exit after close */ +#endif /* UNUSED */ + unsigned int neg_mru :1; /* Negotiate the MRU? */ + unsigned int neg_asyncmap :1; /* Negotiate the async map? */ +#if PAP_SUPPORT + unsigned int neg_upap :1; /* Ask for UPAP authentication? */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int neg_chap :1; /* Ask for CHAP authentication? */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int neg_eap :1; /* Ask for EAP authentication? */ +#endif /* EAP_SUPPORT */ + unsigned int neg_magicnumber :1; /* Ask for magic number? */ + unsigned int neg_pcompression :1; /* HDLC Protocol Field Compression? */ + unsigned int neg_accompression :1; /* HDLC Address/Control Field Compression? */ +#if LQR_SUPPORT + unsigned int neg_lqr :1; /* Negotiate use of Link Quality Reports */ +#endif /* LQR_SUPPORT */ + unsigned int neg_cbcp :1; /* Negotiate use of CBCP */ +#ifdef HAVE_MULTILINK + unsigned int neg_mrru :1; /* negotiate multilink MRRU */ +#endif /* HAVE_MULTILINK */ + unsigned int neg_ssnhf :1; /* negotiate short sequence numbers */ + unsigned int neg_endpoint :1; /* negotiate endpoint discriminator */ + + u16_t mru; /* Value of MRU */ +#ifdef HAVE_MULTILINK + u16_t mrru; /* Value of MRRU, and multilink enable */ +#endif /* MULTILINK */ +#if CHAP_SUPPORT + u8_t chap_mdtype; /* which MD types (hashing algorithm) */ +#endif /* CHAP_SUPPORT */ + u32_t asyncmap; /* Value of async map */ + u32_t magicnumber; + u8_t numloops; /* Number of loops during magic number neg. */ +#if LQR_SUPPORT + u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ +#endif /* LQR_SUPPORT */ + struct epdisc endpoint; /* endpoint discriminator */ +} lcp_options; + +void lcp_open(ppp_pcb *pcb); +void lcp_close(ppp_pcb *pcb, const char *reason); +void lcp_lowerup(ppp_pcb *pcb); +void lcp_lowerdown(ppp_pcb *pcb); +void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len); /* send protocol reject */ + +extern const struct protent lcp_protent; + +#if 0 /* moved to ppp_opts.h */ +/* Default number of times we receive our magic number from the peer + before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 +#endif /* moved to ppp_opts.h */ + +#ifdef __cplusplus +} +#endif + +#endif /* LCP_H */ +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/magic.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/magic.h new file mode 100644 index 0000000..a165e18 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/magic.h @@ -0,0 +1,130 @@ +/* + * magic.h - PPP Magic Number definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $ + */ +/***************************************************************************** +* randm.h - Random number generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-05-29 Guy Lancaster , Global Election Systems Inc. +* Extracted from avos. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MAGIC_H +#define MAGIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* + * Initialize the random number generator. + */ +void magic_init(void); + +/* + * Randomize our random seed value. To be called for truely random events + * such as user operations and network traffic. + */ +void magic_randomize(void); + +/* + * Return a new random number. + */ +u32_t magic(void); /* Returns the next magic number */ + +/* + * Fill buffer with random bytes + * + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using magic_churnrand(). + * Thus it's important to make sure that the results of this are not + * published directly because one could predict the next result to at + * least some degree. Also, it's important to get a good seed before + * the first use. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len); + +/* + * Return a new random number between 0 and (2^pow)-1 included. + */ +u32_t magic_pow(u8_t pow); + +#ifdef __cplusplus +} +#endif + +#endif /* MAGIC_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/mppe.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/mppe.h new file mode 100644 index 0000000..5de1128 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/mppe.h @@ -0,0 +1,181 @@ +/* + * mppe.h - Definitions for MPPE + * + * Copyright (c) 2008 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MPPE_H +#define MPPE_H + +#include "netif/ppp/pppcrypt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a lwip_htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + const u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) + +/* Shared MPPE padding between MSCHAP and MPPE */ +#define SHA1_PAD_SIZE 40 + +static const u8_t mppe_sha1_pad1[SHA1_PAD_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const u8_t mppe_sha1_pad2[SHA1_PAD_SIZE] = { + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 +}; + +/* + * State for an MPPE (de)compressor. + */ +typedef struct ppp_mppe_state { + lwip_arc4_context arc4; + u8_t master_key[MPPE_MAX_KEY_LEN]; + u8_t session_key[MPPE_MAX_KEY_LEN]; + u8_t keylen; /* key length in bytes */ + /* NB: 128-bit == 16, 40-bit == 8! + * If we want to support 56-bit, the unit has to change to bits + */ + u8_t bits; /* MPPE control bits */ + u16_t ccount; /* 12-bit coherency count (seqno) */ + u16_t sanity_errors; /* take down LCP if too many */ + unsigned int stateful :1; /* stateful mode flag */ + unsigned int discard :1; /* stateful mode packet loss flag */ +} ppp_mppe_state; + +void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key); +void mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options); +void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol); +void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb); + +#ifdef __cplusplus +} +#endif + +#endif /* MPPE_H */ +#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/arc4.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/arc4.h new file mode 100644 index 0000000..4af724c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/arc4.h @@ -0,0 +1,81 @@ +/** + * \file arc4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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 "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_ARC4 + +#ifndef LWIP_INCLUDED_POLARSSL_ARC4_H +#define LWIP_INCLUDED_POLARSSL_ARC4_H + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +arc4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be initialized + * \param key the secret key + * \param keylen length of the key + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param buf buffer to be processed + * \param buflen amount of data in buf + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/des.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/des.h new file mode 100644 index 0000000..e893890 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/des.h @@ -0,0 +1,92 @@ +/** + * \file des.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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 "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_DES + +#ifndef LWIP_INCLUDED_POLARSSL_DES_H +#define LWIP_INCLUDED_POLARSSL_DES_H + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< DES subkeys */ +} +des_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + */ +void des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_DES_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md4.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md4.h new file mode 100644 index 0000000..5704456 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md4.h @@ -0,0 +1,97 @@ +/** + * \file md4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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 "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD4 + +#ifndef LWIP_INCLUDED_POLARSSL_MD4_H +#define LWIP_INCLUDED_POLARSSL_MD4_H + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md5.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md5.h new file mode 100644 index 0000000..1244011 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/md5.h @@ -0,0 +1,96 @@ +/** + * \file md5.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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 "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD5 + +#ifndef LWIP_INCLUDED_POLARSSL_MD5_H +#define LWIP_INCLUDED_POLARSSL_MD5_H + +/** + * \brief MD5 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD5_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/sha1.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/sha1.h new file mode 100644 index 0000000..a4c53e0 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/polarssl/sha1.h @@ -0,0 +1,96 @@ +/** + * \file sha1.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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 "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_SHA1 + +#ifndef LWIP_INCLUDED_POLARSSL_SHA1_H +#define LWIP_INCLUDED_POLARSSL_SHA1_H + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp.h new file mode 100644 index 0000000..3d73c36 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp.h @@ -0,0 +1,698 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_H +#define PPP_H + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#if PPP_IPV6_SUPPORT +#include "lwip/ip6_addr.h" +#endif /* PPP_IPV6_SUPPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable non-working or rarely used PPP feature, so rarely that we don't want to bloat ppp_opts.h with them */ +#ifndef PPP_OPTIONS +#define PPP_OPTIONS 0 +#endif + +#ifndef PPP_NOTIFY +#define PPP_NOTIFY 0 +#endif + +#ifndef PPP_REMOTENAME +#define PPP_REMOTENAME 0 +#endif + +#ifndef PPP_IDLETIMELIMIT +#define PPP_IDLETIMELIMIT 0 +#endif + +#ifndef PPP_LCP_ADAPTIVE +#define PPP_LCP_ADAPTIVE 0 +#endif + +#ifndef PPP_MAXCONNECT +#define PPP_MAXCONNECT 0 +#endif + +#ifndef PPP_ALLOWED_ADDRS +#define PPP_ALLOWED_ADDRS 0 +#endif + +#ifndef PPP_PROTOCOLNAME +#define PPP_PROTOCOLNAME 0 +#endif + +#ifndef PPP_STATS_SUPPORT +#define PPP_STATS_SUPPORT 0 +#endif + +#ifndef DEFLATE_SUPPORT +#define DEFLATE_SUPPORT 0 +#endif + +#ifndef BSDCOMPRESS_SUPPORT +#define BSDCOMPRESS_SUPPORT 0 +#endif + +#ifndef PREDICTOR_SUPPORT +#define PREDICTOR_SUPPORT 0 +#endif + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ + +/* + * Values for phase. + */ +#define PPP_PHASE_DEAD 0 +#define PPP_PHASE_MASTER 1 +#define PPP_PHASE_HOLDOFF 2 +#define PPP_PHASE_INITIALIZE 3 +#define PPP_PHASE_SERIALCONN 4 +#define PPP_PHASE_DORMANT 5 +#define PPP_PHASE_ESTABLISH 6 +#define PPP_PHASE_AUTHENTICATE 7 +#define PPP_PHASE_CALLBACK 8 +#define PPP_PHASE_NETWORK 9 +#define PPP_PHASE_RUNNING 10 +#define PPP_PHASE_TERMINATE 11 +#define PPP_PHASE_DISCONNECT 12 + +/* Error codes. */ +#define PPPERR_NONE 0 /* No error. */ +#define PPPERR_PARAM 1 /* Invalid parameter. */ +#define PPPERR_OPEN 2 /* Unable to open PPP session. */ +#define PPPERR_DEVICE 3 /* Invalid I/O device for PPP. */ +#define PPPERR_ALLOC 4 /* Unable to allocate resources. */ +#define PPPERR_USER 5 /* User interrupt. */ +#define PPPERR_CONNECT 6 /* Connection lost. */ +#define PPPERR_AUTHFAIL 7 /* Failed authentication challenge. */ +#define PPPERR_PROTOCOL 8 /* Failed to meet protocol. */ +#define PPPERR_PEERDEAD 9 /* Connection timeout */ +#define PPPERR_IDLETIMEOUT 10 /* Idle Timeout */ +#define PPPERR_CONNECTTIME 11 /* Max connect time reached */ +#define PPPERR_LOOPBACK 12 /* Loopback detected */ + +/* Whether auth support is enabled at all */ +#define PPP_AUTH_SUPPORT (PAP_SUPPORT || CHAP_SUPPORT || EAP_SUPPORT) + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Other headers require ppp_pcb definition for prototypes, but ppp_pcb + * require some structure definition from other headers as well, we are + * fixing the dependency loop here by declaring the ppp_pcb type then + * by including headers containing necessary struct definition for ppp_pcb + */ +typedef struct ppp_pcb_s ppp_pcb; + +/* Type definitions for BSD code. */ +#ifndef __u_char_defined +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; +#endif + +#include "fsm.h" +#include "lcp.h" +#if CCP_SUPPORT +#include "ccp.h" +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT +#include "mppe.h" +#endif /* MPPE_SUPPORT */ +#if PPP_IPV4_SUPPORT +#include "ipcp.h" +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +#include "ipv6cp.h" +#endif /* PPP_IPV6_SUPPORT */ +#if PAP_SUPPORT +#include "upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "eap.h" +#endif /* EAP_SUPPORT */ +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ + +/* Link status callback function prototype */ +typedef void (*ppp_link_status_cb_fn)(ppp_pcb *pcb, int err_code, void *ctx); + +/* + * PPP configuration. + */ +typedef struct ppp_settings_s { + +#if PPP_SERVER && PPP_AUTH_SUPPORT + unsigned int auth_required :1; /* Peer is required to authenticate */ + unsigned int null_login :1; /* Username of "" and a password of "" are acceptable */ +#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ +#if PPP_REMOTENAME + unsigned int explicit_remote :1; /* remote_name specified with remotename opt */ +#endif /* PPP_REMOTENAME */ +#if PAP_SUPPORT + unsigned int refuse_pap :1; /* Don't proceed auth. with PAP */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int refuse_chap :1; /* Don't proceed auth. with CHAP */ +#endif /* CHAP_SUPPORT */ +#if MSCHAP_SUPPORT + unsigned int refuse_mschap :1; /* Don't proceed auth. with MS-CHAP */ + unsigned int refuse_mschap_v2 :1; /* Don't proceed auth. with MS-CHAPv2 */ +#endif /* MSCHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int refuse_eap :1; /* Don't proceed auth. with EAP */ +#endif /* EAP_SUPPORT */ +#if LWIP_DNS + unsigned int usepeerdns :1; /* Ask peer for DNS adds */ +#endif /* LWIP_DNS */ + unsigned int persist :1; /* Persist mode, always try to open the connection */ +#if PRINTPKT_SUPPORT + unsigned int hide_password :1; /* Hide password in dumped packets */ +#endif /* PRINTPKT_SUPPORT */ + unsigned int noremoteip :1; /* Let him have no IP address */ + unsigned int lax_recv :1; /* accept control chars in asyncmap */ + unsigned int noendpoint :1; /* don't send/accept endpoint discriminator */ +#if PPP_LCP_ADAPTIVE + unsigned int lcp_echo_adaptive :1; /* request echo only if the link was idle */ +#endif /* PPP_LCP_ADAPTIVE */ +#if MPPE_SUPPORT + unsigned int require_mppe :1; /* Require MPPE (Microsoft Point to Point Encryption) */ + unsigned int refuse_mppe_40 :1; /* Allow MPPE 40-bit mode? */ + unsigned int refuse_mppe_128 :1; /* Allow MPPE 128-bit mode? */ + unsigned int refuse_mppe_stateful :1; /* Allow MPPE stateful mode? */ +#endif /* MPPE_SUPPORT */ + + u16_t listen_time; /* time to listen first (ms), waiting for peer to send LCP packet */ + +#if PPP_IDLETIMELIMIT + u16_t idle_time_limit; /* Disconnect if idle for this many seconds */ +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT + u32_t maxconnect; /* Maximum connect time (seconds) */ +#endif /* PPP_MAXCONNECT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ + const char *user; /* Username for PAP */ + const char *passwd; /* Password for PAP, secret for CHAP */ +#if PPP_REMOTENAME + char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ +#endif /* PPP_REMOTENAME */ + +#if PAP_SUPPORT + u8_t pap_timeout_time; /* Timeout (seconds) for auth-req retrans. */ + u8_t pap_max_transmits; /* Number of auth-reqs sent */ +#if PPP_SERVER + u8_t pap_req_timeout; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* PAP_SUPPPORT */ + +#if CHAP_SUPPORT + u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ + u8_t chap_max_transmits; /* max # times to send challenge */ +#if PPP_SERVER + u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPPORT */ + +#if EAP_SUPPORT + u8_t eap_req_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_allow_req; /* Max Requests allowed */ +#if PPP_SERVER + u8_t eap_timeout_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_max_transmits; /* Max Requests allowed */ +#endif /* PPP_SERVER */ +#endif /* EAP_SUPPORT */ + +#endif /* PPP_AUTH_SUPPORT */ + + u8_t fsm_timeout_time; /* Timeout time in seconds */ + u8_t fsm_max_conf_req_transmits; /* Maximum Configure-Request transmissions */ + u8_t fsm_max_term_transmits; /* Maximum Terminate-Request transmissions */ + u8_t fsm_max_nak_loops; /* Maximum number of nak loops tolerated */ + + u8_t lcp_loopbackfail; /* Number of times we receive our magic number from the peer + before deciding the link is looped-back. */ + u8_t lcp_echo_interval; /* Interval between LCP echo-requests */ + u8_t lcp_echo_fails; /* Tolerance to unanswered echo-requests */ + +} ppp_settings; + +#if PPP_SERVER +struct ppp_addrs { +#if PPP_IPV4_SUPPORT + ip4_addr_t our_ipaddr, his_ipaddr, netmask; +#if LWIP_DNS + ip4_addr_t dns1, dns2; +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + ip6_addr_t our6_ipaddr, his6_ipaddr; +#endif /* PPP_IPV6_SUPPORT */ +}; +#endif /* PPP_SERVER */ + +/* + * PPP interface control block. + */ +struct ppp_pcb_s { + ppp_settings settings; + const struct link_callbacks *link_cb; + void *link_ctx_cb; + void (*link_status_cb)(ppp_pcb *pcb, int err_code, void *ctx); /* Status change callback */ +#if PPP_NOTIFY_PHASE + void (*notify_phase_cb)(ppp_pcb *pcb, u8_t phase, void *ctx); /* Notify phase callback */ +#endif /* PPP_NOTIFY_PHASE */ + void *ctx_cb; /* Callbacks optional pointer */ + struct netif *netif; /* PPP interface */ + u8_t phase; /* where the link is at */ + u8_t err_code; /* Code indicating why interface is down. */ + + /* flags */ +#if PPP_IPV4_SUPPORT + unsigned int ask_for_local :1; /* request our address from peer */ + unsigned int ipcp_is_open :1; /* haven't called np_finished() */ + unsigned int ipcp_is_up :1; /* have called ipcp_up() */ + unsigned int if4_up :1; /* True when the IPv4 interface is up. */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp_set :1; /* Have created proxy arp entry */ +#endif /* UNUSED - PROXY ARP */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + unsigned int ipv6cp_is_up :1; /* have called ip6cp_up() */ + unsigned int if6_up :1; /* True when the IPv6 interface is up. */ +#endif /* PPP_IPV6_SUPPORT */ + unsigned int lcp_echo_timer_running :1; /* set if a timer is running */ +#if VJ_SUPPORT + unsigned int vj_enabled :1; /* Flag indicating VJ compression enabled. */ +#endif /* VJ_SUPPORT */ +#if CCP_SUPPORT + unsigned int ccp_all_rejected :1; /* we rejected all peer's options */ +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT + unsigned int mppe_keys_set :1; /* Have the MPPE keys been set? */ +#endif /* MPPE_SUPPORT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ +#if PPP_SERVER && defined(HAVE_MULTILINK) + char peer_authname[MAXNAMELEN + 1]; /* The name by which the peer authenticated itself to us. */ +#endif /* PPP_SERVER && defined(HAVE_MULTILINK) */ + u16_t auth_pending; /* Records which authentication operations haven't completed yet. */ + u16_t auth_done; /* Records which authentication operations have been completed. */ + +#if PAP_SUPPORT + upap_state upap; /* PAP data */ +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + chap_client_state chap_client; /* CHAP client data */ +#if PPP_SERVER + chap_server_state chap_server; /* CHAP server data */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if EAP_SUPPORT + eap_state eap; /* EAP data */ +#endif /* EAP_SUPPORT */ +#endif /* PPP_AUTH_SUPPORT */ + + fsm lcp_fsm; /* LCP fsm structure */ + lcp_options lcp_wantoptions; /* Options that we want to request */ + lcp_options lcp_gotoptions; /* Options that peer ack'd */ + lcp_options lcp_allowoptions; /* Options we allow peer to request */ + lcp_options lcp_hisoptions; /* Options that we ack'd */ + u16_t peer_mru; /* currently negotiated peer MRU */ + u8_t lcp_echos_pending; /* Number of outstanding echo msgs */ + u8_t lcp_echo_number; /* ID number of next echo frame */ + + u8_t num_np_open; /* Number of network protocols which we have opened. */ + u8_t num_np_up; /* Number of network protocols which have come up. */ + +#if VJ_SUPPORT + struct vjcompress vj_comp; /* Van Jacobson compression header. */ +#endif /* VJ_SUPPORT */ + +#if CCP_SUPPORT + fsm ccp_fsm; /* CCP fsm structure */ + ccp_options ccp_wantoptions; /* what to request the peer to use */ + ccp_options ccp_gotoptions; /* what the peer agreed to do */ + ccp_options ccp_allowoptions; /* what we'll agree to do */ + ccp_options ccp_hisoptions; /* what we agreed to do */ + u8_t ccp_localstate; /* Local state (mainly for handling reset-reqs and reset-acks). */ + u8_t ccp_receive_method; /* Method chosen on receive path */ + u8_t ccp_transmit_method; /* Method chosen on transmit path */ +#if MPPE_SUPPORT + ppp_mppe_state mppe_comp; /* MPPE "compressor" structure */ + ppp_mppe_state mppe_decomp; /* MPPE "decompressor" structure */ +#endif /* MPPE_SUPPORT */ +#endif /* CCP_SUPPORT */ + +#if PPP_IPV4_SUPPORT + fsm ipcp_fsm; /* IPCP fsm structure */ + ipcp_options ipcp_wantoptions; /* Options that we want to request */ + ipcp_options ipcp_gotoptions; /* Options that peer ack'd */ + ipcp_options ipcp_allowoptions; /* Options we allow peer to request */ + ipcp_options ipcp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT + fsm ipv6cp_fsm; /* IPV6CP fsm structure */ + ipv6cp_options ipv6cp_wantoptions; /* Options that we want to request */ + ipv6cp_options ipv6cp_gotoptions; /* Options that peer ack'd */ + ipv6cp_options ipv6cp_allowoptions; /* Options we allow peer to request */ + ipv6cp_options ipv6cp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV6_SUPPORT */ +}; + +/************************ + *** PUBLIC FUNCTIONS *** + ************************/ + +/* + * WARNING: For multi-threads environment, all ppp_set_* functions most + * only be called while the PPP is in the dead phase (i.e. disconnected). + */ + +#if PPP_AUTH_SUPPORT +/* + * Set PPP authentication. + * + * Warning: Using PPPAUTHTYPE_ANY might have security consequences. + * RFC 1994 says: + * + * In practice, within or associated with each PPP server, there is a + * database which associates "user" names with authentication + * information ("secrets"). It is not anticipated that a particular + * named user would be authenticated by multiple methods. This would + * make the user vulnerable to attacks which negotiate the least secure + * method from among a set (such as PAP rather than CHAP). If the same + * secret was used, PAP would reveal the secret to be used later with + * CHAP. + * + * Instead, for each user name there should be an indication of exactly + * one method used to authenticate that user name. If a user needs to + * make use of different authentication methods under different + * circumstances, then distinct user names SHOULD be employed, each of + * which identifies exactly one authentication method. + * + * Default is none auth type, unset (NULL) user and passwd. + */ +#define PPPAUTHTYPE_NONE 0x00 +#define PPPAUTHTYPE_PAP 0x01 +#define PPPAUTHTYPE_CHAP 0x02 +#define PPPAUTHTYPE_MSCHAP 0x04 +#define PPPAUTHTYPE_MSCHAP_V2 0x08 +#define PPPAUTHTYPE_EAP 0x10 +#define PPPAUTHTYPE_ANY 0xff +void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd); + +/* + * If set, peer is required to authenticate. This is mostly necessary for PPP server support. + * + * Default is false. + */ +#define ppp_set_auth_required(ppp, boolval) (ppp->settings.auth_required = boolval) +#endif /* PPP_AUTH_SUPPORT */ + +#if PPP_IPV4_SUPPORT +/* + * Set PPP interface "our" and "his" IPv4 addresses. This is mostly necessary for PPP server + * support but it can also be used on a PPP link where each side choose its own IP address. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_ouraddr(ppp, addr) do { ppp->ipcp_wantoptions.ouraddr = ip4_addr_get_u32(addr); \ + ppp->ask_for_local = ppp->ipcp_wantoptions.ouraddr != 0; } while(0) +#define ppp_set_ipcp_hisaddr(ppp, addr) (ppp->ipcp_wantoptions.hisaddr = ip4_addr_get_u32(addr)) +#if LWIP_DNS +/* + * Set DNS server addresses that are sent if the peer asks for them. This is mostly necessary + * for PPP server support. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_dnsaddr(ppp, index, addr) (ppp->ipcp_allowoptions.dnsaddr[index] = ip4_addr_get_u32(addr)) + +/* + * If set, we ask the peer for up to 2 DNS server addresses. Received DNS server addresses are + * registered using the dns_setserver() function. + * + * Default is false. + */ +#define ppp_set_usepeerdns(ppp, boolval) (ppp->settings.usepeerdns = boolval) +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ + +#if MPPE_SUPPORT +/* Disable MPPE (Microsoft Point to Point Encryption). This parameter is exclusive. */ +#define PPP_MPPE_DISABLE 0x00 +/* Require the use of MPPE (Microsoft Point to Point Encryption). */ +#define PPP_MPPE_ENABLE 0x01 +/* Allow MPPE to use stateful mode. Stateless mode is still attempted first. */ +#define PPP_MPPE_ALLOW_STATEFUL 0x02 +/* Refuse the use of MPPE with 40-bit encryption. Conflict with PPP_MPPE_REFUSE_128. */ +#define PPP_MPPE_REFUSE_40 0x04 +/* Refuse the use of MPPE with 128-bit encryption. Conflict with PPP_MPPE_REFUSE_40. */ +#define PPP_MPPE_REFUSE_128 0x08 +/* + * Set MPPE configuration + * + * Default is disabled. + */ +void ppp_set_mppe(ppp_pcb *pcb, u8_t flags); +#endif /* MPPE_SUPPORT */ + +/* + * Wait for up to intval milliseconds for a valid PPP packet from the peer. + * At the end of this time, or when a valid PPP packet is received from the + * peer, we commence negotiation by sending our first LCP packet. + * + * Default is 0. + */ +#define ppp_set_listen_time(ppp, intval) (ppp->settings.listen_time = intval) + +/* + * If set, we will attempt to initiate a connection but if no reply is received from + * the peer, we will then just wait passively for a valid LCP packet from the peer. + * + * Default is false. + */ +#define ppp_set_passive(ppp, boolval) (ppp->lcp_wantoptions.passive = boolval) + +/* + * If set, we will not transmit LCP packets to initiate a connection until a valid + * LCP packet is received from the peer. This is what we usually call the server mode. + * + * Default is false. + */ +#define ppp_set_silent(ppp, boolval) (ppp->lcp_wantoptions.silent = boolval) + +/* + * If set, enable protocol field compression negotiation in both the receive and + * the transmit direction. + * + * Default is true. + */ +#define ppp_set_neg_pcomp(ppp, boolval) (ppp->lcp_wantoptions.neg_pcompression = \ + ppp->lcp_allowoptions.neg_pcompression = boolval) + +/* + * If set, enable Address/Control compression in both the receive and the transmit + * direction. + * + * Default is true. + */ +#define ppp_set_neg_accomp(ppp, boolval) (ppp->lcp_wantoptions.neg_accompression = \ + ppp->lcp_allowoptions.neg_accompression = boolval) + +/* + * If set, enable asyncmap negotiation. Otherwise forcing all control characters to + * be escaped for both the transmit and the receive direction. + * + * Default is true. + */ +#define ppp_set_neg_asyncmap(ppp, boolval) (ppp->lcp_wantoptions.neg_asyncmap = \ + ppp->lcp_allowoptions.neg_asyncmap = boolval) + +/* + * This option sets the Async-Control-Character-Map (ACCM) for this end of the link. + * The ACCM is a set of 32 bits, one for each of the ASCII control characters with + * values from 0 to 31, where a 1 bit indicates that the corresponding control + * character should not be used in PPP packets sent to this system. The map is + * an unsigned 32 bits integer where the least significant bit (00000001) represents + * character 0 and the most significant bit (80000000) represents character 31. + * We will then ask the peer to send these characters as a 2-byte escape sequence. + * + * Default is 0. + */ +#define ppp_set_asyncmap(ppp, intval) (ppp->lcp_wantoptions.asyncmap = intval) + +/* + * Set a PPP interface as the default network interface + * (used to output all packets for which no specific route is found). + */ +#define ppp_set_default(ppp) netif_set_default(ppp->netif) + +#if PPP_NOTIFY_PHASE +/* + * Set a PPP notify phase callback. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +typedef void (*ppp_notify_phase_cb_fn)(ppp_pcb *pcb, u8_t phase, void *ctx); +void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ + +/* + * Initiate a PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * Holdoff is the time to wait (in seconds) before initiating + * the connection. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff); + +#if PPP_SERVER +/* + * Listen for an incoming PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +/* + * Initiate the end of a PPP connection. + * Any outstanding packets in the queues are dropped. + * + * Setting nocarrier to 1 close the PPP connection without initiating the + * shutdown procedure. Always using nocarrier = 0 is still recommended, + * this is going to take a little longer time if your link is down, but + * is a safer choice for the PPP state machine. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_close(ppp_pcb *pcb, u8_t nocarrier); + +/* + * Release the control block. + * + * This can only be called if PPP is in the dead phase. + * + * You must use ppp_close() before if you wish to terminate + * an established PPP session. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_free(ppp_pcb *pcb); + +/* + * PPP IOCTL commands. + * + * Get the up status - 0 for down, non-zero for up. The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 0 + +/* + * Get the PPP error code. The argument must point to an int. + * Returns a PPPERR_* value. + */ +#define PPPCTLG_ERRCODE 1 + +/* + * Get the fd associated with a PPP over serial + */ +#define PPPCTLG_FD 2 + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. + */ +err_t ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +/* Get the PPP netif interface */ +#define ppp_netif(ppp) (ppp->netif) + +/* Set an lwIP-style status-callback for the selected PPP device */ +#define ppp_set_netif_statuscallback(ppp, status_cb) \ + netif_set_status_callback(ppp->netif, status_cb); + +/* Set an lwIP-style link-callback for the selected PPP device */ +#define ppp_set_netif_linkcallback(ppp, link_cb) \ + netif_set_link_callback(ppp->netif, link_cb); + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_impl.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_impl.h new file mode 100644 index 0000000..40843d5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_impl.h @@ -0,0 +1,722 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +#ifndef LWIP_HDR_PPP_IMPL_H +#define LWIP_HDR_PPP_IMPL_H + +#include "netif/ppp/ppp_opts.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifdef PPP_INCLUDE_SETTINGS_HEADER +#include "ppp_settings.h" +#endif + +#include /* formats */ +#include +#include +#include /* strtol() */ + +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/timeouts.h" + +#include "ppp.h" +#include "pppdebug.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Memory used for control packets. + * + * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we + * cannot figure out how much we are going to use before filling the buffer. + */ +#if PPP_USE_PBUF_RAM +#define PPP_CTRL_PBUF_TYPE PBUF_RAM +#define PPP_CTRL_PBUF_MAX_SIZE 512 +#else /* PPP_USE_PBUF_RAM */ +#define PPP_CTRL_PBUF_TYPE PBUF_POOL +#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE +#endif /* PPP_USE_PBUF_RAM */ + +/* + * The basic PPP frame. + */ +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#if 0 /* UNUSED */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#endif /* UNUSED */ +#if VJ_SUPPORT +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#endif /* VJ_SUPPORT */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_COMP 0xfd /* compressed packet */ +#endif /* CCP_SUPPORT */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#if 0 /* UNUSED */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#endif /* UNUSED */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#endif /* ECP_SUPPORT */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#if PAP_SUPPORT +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#endif /* LQR_SUPPORT */ +#if CHAP_SUPPORT +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#endif /* CBCP_SUPPORT */ +#if EAP_SUPPORT +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ +#endif /* EAP_SUPPORT */ + +/* + * The following struct gives the addresses of procedures to call + * for a particular lower link level protocol. + */ +struct link_callbacks { + /* Start a connection (e.g. Initiate discovery phase) */ + void (*connect) (ppp_pcb *pcb, void *ctx); +#if PPP_SERVER + /* Listen for an incoming connection (Passive mode) */ + void (*listen) (ppp_pcb *pcb, void *ctx); +#endif /* PPP_SERVER */ + /* End a connection (i.e. initiate disconnect phase) */ + void (*disconnect) (ppp_pcb *pcb, void *ctx); + /* Free lower protocol control block */ + err_t (*free) (ppp_pcb *pcb, void *ctx); + /* Write a pbuf to a ppp link, only used from PPP functions to send PPP packets. */ + err_t (*write)(ppp_pcb *pcb, void *ctx, struct pbuf *p); + /* Send a packet from lwIP core (IPv4 or IPv6) */ + err_t (*netif_output)(ppp_pcb *pcb, void *ctx, struct pbuf *p, u_short protocol); + /* configure the transmit-side characteristics of the PPP interface */ + void (*send_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); + /* confire the receive-side characteristics of the PPP interface */ + void (*recv_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); +}; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics. + */ +#if PPP_STATS_SUPPORT +struct pppstat { + unsigned int ppp_ibytes; /* bytes received */ + unsigned int ppp_ipackets; /* packets received */ + unsigned int ppp_ierrors; /* receive errors */ + unsigned int ppp_obytes; /* bytes sent */ + unsigned int ppp_opackets; /* packets sent */ + unsigned int ppp_oerrors; /* transmit errors */ +}; + +#if VJ_SUPPORT +struct vjstat { + unsigned int vjs_packets; /* outbound packets */ + unsigned int vjs_compressed; /* outbound compressed packets */ + unsigned int vjs_searches; /* searches for connection state */ + unsigned int vjs_misses; /* times couldn't find conn. state */ + unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ + unsigned int vjs_compressedin; /* inbound compressed packets */ + unsigned int vjs_errorin; /* inbound unknown type packets */ + unsigned int vjs_tossed; /* inbound packets tossed because of error */ +}; +#endif /* VJ_SUPPORT */ + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ +#if VJ_SUPPORT + struct vjstat vj; /* VJ header compression statistics */ +#endif /* VJ_SUPPORT */ +}; + +#if CCP_SUPPORT +struct compstat { + unsigned int unc_bytes; /* total uncompressed bytes */ + unsigned int unc_packets; /* total uncompressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned int comp_packets; /* compressed packets */ + unsigned int inc_bytes; /* incompressible bytes */ + unsigned int inc_packets; /* incompressible packets */ + unsigned int ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; +#endif /* CCP_SUPPORT */ + +#endif /* PPP_STATS_SUPPORT */ + +#if PPP_IDLETIMELIMIT +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; +#endif /* PPP_IDLETIMELIMIT */ + +/* values for epdisc.class */ +#define EPD_NULL 0 /* null discriminator, no data */ +#define EPD_LOCAL 1 +#define EPD_IP 2 +#define EPD_MAC 3 +#define EPD_MAGIC 4 +#define EPD_PHONENUM 5 + +/* + * Global variables. + */ +#ifdef HAVE_MULTILINK +extern u8_t multilink; /* enable multilink operation */ +extern u8_t doing_multilink; +extern u8_t multilink_master; +extern u8_t bundle_eof; +extern u8_t bundle_terminating; +#endif + +#ifdef MAXOCTETS +extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ +extern int maxoctets_dir; /* Direction : + 0 - in+out (default) + 1 - in + 2 - out + 3 - max(in,out) */ +extern int maxoctets_timeout; /* Timeout for check of octets limit */ +#define PPP_OCTETS_DIRECTION_SUM 0 +#define PPP_OCTETS_DIRECTION_IN 1 +#define PPP_OCTETS_DIRECTION_OUT 2 +#define PPP_OCTETS_DIRECTION_MAXOVERAL 3 +/* same as previos, but little different on RADIUS side */ +#define PPP_OCTETS_DIRECTION_MAXSESSION 4 +#endif + +/* Data input may be used by CCP and ECP, remove this entry + * from struct protent to save some flash + */ +#define PPP_DATAINPUT 0 + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { + u_short protocol; /* PPP protocol number */ + /* Initialization procedure */ + void (*init) (ppp_pcb *pcb); + /* Process a received packet */ + void (*input) (ppp_pcb *pcb, u_char *pkt, int len); + /* Process a received protocol-reject */ + void (*protrej) (ppp_pcb *pcb); + /* Lower layer has come up */ + void (*lowerup) (ppp_pcb *pcb); + /* Lower layer has gone down */ + void (*lowerdown) (ppp_pcb *pcb); + /* Open the protocol */ + void (*open) (ppp_pcb *pcb); + /* Close the protocol */ + void (*close) (ppp_pcb *pcb, const char *reason); +#if PRINTPKT_SUPPORT + /* Print a packet in readable form */ + int (*printpkt) (const u_char *pkt, int len, + void (*printer) (void *, const char *, ...), + void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + /* Process a received data packet */ + void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len); +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + const char *name; /* Text name of protocol */ + const char *data_name; /* Text name of corresponding data protocol */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + option_t *options; /* List of command-line options */ + /* Check requested options, assign defaults */ + void (*check_options) (void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + /* Configure interface for demand-dial */ + int (*demand_conf) (int unit); + /* Say whether to bring up link for this pkt */ + int (*active_pkt) (u_char *pkt, int len); +#endif /* DEMAND_SUPPORT */ +}; + +/* Table of pointers to supported protocols */ +extern const struct protent* const protocols[]; + + +/* Values for auth_pending, auth_done */ +#if PAP_SUPPORT +#define PAP_WITHPEER 0x1 +#define PAP_PEER 0x2 +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#define CHAP_WITHPEER 0x4 +#define CHAP_PEER 0x8 +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#define EAP_WITHPEER 0x10 +#define EAP_PEER 0x20 +#endif /* EAP_SUPPORT */ + +/* Values for auth_done only */ +#if CHAP_SUPPORT +#define CHAP_MD5_WITHPEER 0x40 +#define CHAP_MD5_PEER 0x80 +#if MSCHAP_SUPPORT +#define CHAP_MS_SHIFT 8 /* LSB position for MS auths */ +#define CHAP_MS_WITHPEER 0x100 +#define CHAP_MS_PEER 0x200 +#define CHAP_MS2_WITHPEER 0x400 +#define CHAP_MS2_PEER 0x800 +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ + +/* Supported CHAP protocols */ +#if CHAP_SUPPORT + +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) +#else /* MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MD5) +#endif /* MSCHAP_SUPPORT */ + +#else /* CHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_NONE) +#endif /* CHAP_SUPPORT */ + +#if PPP_STATS_SUPPORT +/* + * PPP statistics structure + */ +struct pppd_stats { + unsigned int bytes_in; + unsigned int bytes_out; + unsigned int pkts_in; + unsigned int pkts_out; +}; +#endif /* PPP_STATS_SUPPORT */ + + +/* + * PPP private functions + */ + + +/* + * Functions called from lwIP core. + */ + +/* initialize the PPP subsystem */ +int ppp_init(void); + +/* + * Functions called from PPP link protocols. + */ + +/* Create a new PPP control block */ +ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* Initiate LCP open request */ +void ppp_start(ppp_pcb *pcb); + +/* Called when link failed to setup */ +void ppp_link_failed(ppp_pcb *pcb); + +/* Called when link is normally down (i.e. it was asked to end) */ +void ppp_link_end(ppp_pcb *pcb); + +/* function called to process input packet */ +void ppp_input(ppp_pcb *pcb, struct pbuf *pb); + + +/* + * Functions called by PPP protocols. + */ + +/* function called by all PPP subsystems to send packets */ +err_t ppp_write(ppp_pcb *pcb, struct pbuf *p); + +/* functions called by auth.c link_terminated() */ +void ppp_link_terminated(ppp_pcb *pcb); + +void new_phase(ppp_pcb *pcb, int p); + +int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp); +int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp); + +#if PPP_IPV4_SUPPORT +int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask); +int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr); +#if 0 /* UNUSED - PROXY ARP */ +int sifproxyarp(ppp_pcb *pcb, u32_t his_adr); +int cifproxyarp(ppp_pcb *pcb, u32_t his_adr); +#endif /* UNUSED - PROXY ARP */ +#if LWIP_DNS +int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +#endif /* LWIP_DNS */ +#if VJ_SUPPORT +int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid); +#endif /* VJ_SUPPORT */ +int sifup(ppp_pcb *pcb); +int sifdown (ppp_pcb *pcb); +u32_t get_mask(u32_t addr); +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int sif6up(ppp_pcb *pcb); +int sif6down (ppp_pcb *pcb); +#endif /* PPP_IPV6_SUPPORT */ + +#if DEMAND_SUPPORT +int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); +#endif /* DEMAND_SUPPORt */ + +void netif_set_mtu(ppp_pcb *pcb, int mtu); +int netif_get_mtu(ppp_pcb *pcb); + +#if CCP_SUPPORT +#if 0 /* unused */ +int ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit); +#endif /* unused */ +void ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method); +void ccp_reset_comp(ppp_pcb *pcb); +void ccp_reset_decomp(ppp_pcb *pcb); +#if 0 /* unused */ +int ccp_fatal_error(ppp_pcb *pcb); +#endif /* unused */ +#endif /* CCP_SUPPORT */ + +#if PPP_IDLETIMELIMIT +int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip); +#endif /* PPP_IDLETIMELIMIT */ + +#if DEMAND_SUPPORT +int get_loop_output(void); +#endif /* DEMAND_SUPPORT */ + +/* Optional protocol names list, to make our messages a little more informative. */ +#if PPP_PROTOCOLNAME +const char * protocol_name(int proto); +#endif /* PPP_PROTOCOLNAME */ + +/* Optional stats support, to get some statistics on the PPP interface */ +#if PPP_STATS_SUPPORT +void print_link_stats(void); /* Print stats, if available */ +void reset_link_stats(int u); /* Reset (init) stats when link goes up */ +void update_link_stats(int u); /* Get stats at link termination */ +#endif /* PPP_STATS_SUPPORT */ + + + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ + (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ + *(cp)++ = (u_char) (c); \ +} +#define GETSHORT(s, cp) { \ + (s) = *(cp)++ << 8; \ + (s) |= *(cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s); \ +} +#define GETLONG(l, cp) { \ + (l) = *(cp)++ << 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; \ +} +#define PUTLONG(l, cp) { \ + *(cp)++ = (u_char) ((l) >> 24); \ + *(cp)++ = (u_char) ((l) >> 16); \ + *(cp)++ = (u_char) ((l) >> 8); \ + *(cp)++ = (u_char) (l); \ +} + +#define INCPTR(n, cp) ((cp) += (n)) +#define DECPTR(n, cp) ((cp) -= (n)) + +/* + * System dependent definitions for user-level 4.3BSD UNIX implementation. + */ +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) +#define TIMEOUTMS(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t), (f), (a)); } while(0) +#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) + +#define BZERO(s, n) memset(s, 0, n) +#define BCMP(s1, s2, l) memcmp(s1, s2, l) + +#define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } + +/* + * MAKEHEADER - Add Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/* Procedures exported from auth.c */ +void link_required(ppp_pcb *pcb); /* we are starting to use the link */ +void link_terminated(ppp_pcb *pcb); /* we are finished with the link */ +void link_down(ppp_pcb *pcb); /* the LCP layer has left the Opened state */ +void upper_layers_down(ppp_pcb *pcb); /* take all NCPs down */ +void link_established(ppp_pcb *pcb); /* the link is up; authenticate now */ +void start_networks(ppp_pcb *pcb); /* start all the network control protos */ +void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen); + /* check the user name and passwd against configuration */ +void auth_peer_fail(ppp_pcb *pcb, int protocol); + /* peer failed to authenticate itself */ +void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen); + /* peer successfully authenticated itself */ +#endif /* PPP_SERVER */ +void auth_withpeer_fail(ppp_pcb *pcb, int protocol); + /* we failed to authenticate ourselves */ +void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor); + /* we successfully authenticated ourselves */ +#endif /* PPP_AUTH_SUPPORT */ +void np_up(ppp_pcb *pcb, int proto); /* a network protocol has come up */ +void np_down(ppp_pcb *pcb, int proto); /* a network protocol has gone down */ +void np_finished(ppp_pcb *pcb, int proto); /* a network protocol no longer needs link */ +#if PPP_AUTH_SUPPORT +int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server); + /* get "secret" for chap */ +#endif /* PPP_AUTH_SUPPORT */ + +/* Procedures exported from ipcp.c */ +/* int parse_dotted_ip (char *, u32_t *); */ + +/* Procedures exported from demand.c */ +#if DEMAND_SUPPORT +void demand_conf (void); /* config interface(s) for demand-dial */ +void demand_block (void); /* set all NPs to queue up packets */ +void demand_unblock (void); /* set all NPs to pass packets */ +void demand_discard (void); /* set all NPs to discard packets */ +void demand_rexmit (int, u32_t); /* retransmit saved frames for an NP*/ +int loop_chars (unsigned char *, int); /* process chars from loopback */ +int loop_frame (unsigned char *, int); /* should we bring link up? */ +#endif /* DEMAND_SUPPORT */ + +/* Procedures exported from multilink.c */ +#ifdef HAVE_MULTILINK +void mp_check_options (void); /* Check multilink-related options */ +int mp_join_bundle (void); /* join our link to an appropriate bundle */ +void mp_exit_bundle (void); /* have disconnected our link from bundle */ +void mp_bundle_terminated (void); +char *epdisc_to_str (struct epdisc *); /* string from endpoint discrim. */ +int str_to_epdisc (struct epdisc *, char *); /* endpt disc. from str */ +#else +#define mp_bundle_terminated() /* nothing */ +#define mp_exit_bundle() /* nothing */ +#define doing_multilink 0 +#define multilink_master 0 +#endif + +/* Procedures exported from utils.c. */ +void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg); /* Format a string for output */ +int ppp_slprintf(char *buf, int buflen, const char *fmt, ...); /* sprintf++ */ +int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args); /* vsprintf++ */ +size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ +size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ +void ppp_dbglog(const char *fmt, ...); /* log a debug message */ +void ppp_info(const char *fmt, ...); /* log an informational message */ +void ppp_notice(const char *fmt, ...); /* log a notice-level message */ +void ppp_warn(const char *fmt, ...); /* log a warning message */ +void ppp_error(const char *fmt, ...); /* log an error message */ +void ppp_fatal(const char *fmt, ...); /* log an error message and die(1) */ +#if PRINTPKT_SUPPORT +void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); + /* dump packet to debug log if interesting */ +#endif /* PRINTPKT_SUPPORT */ + +/* + * Number of necessary timers analysis. + * + * PPP use at least one timer per each of its protocol, but not all protocols are + * active at the same time, thus the number of necessary timeouts is actually + * lower than enabled protocols. Here is the actual necessary timeouts based + * on code analysis. + * + * Note that many features analysed here are not working at all and are only + * there for a comprehensive analysis of necessary timers in order to prevent + * having to redo that each time we add a feature. + * + * Timer list + * + * | holdoff timeout + * | low level protocol timeout (PPPoE or PPPoL2P) + * | LCP delayed UP + * | LCP retransmit (FSM) + * | LCP Echo timer + * .| PAP or CHAP or EAP authentication + * . | ECP retransmit (FSM) + * . | CCP retransmit (FSM) when MPPE is enabled + * . | CCP retransmit (FSM) when MPPE is NOT enabled + * . | IPCP retransmit (FSM) + * . .| IP6CP retransmit (FSM) + * . . | Idle time limit + * . . | Max connect time + * . . | Max octets + * . . | CCP RACK timeout + * . . . + * PPP_PHASE_DEAD + * PPP_PHASE_HOLDOFF + * | . . . + * PPP_PHASE_INITIALIZE + * | . . . + * PPP_PHASE_ESTABLISH + * | . . . + * |. . . + * | . . + * PPP_PHASE_AUTHENTICATE + * | . . + * || . . + * PPP_PHASE_NETWORK + * | || . . + * | ||| . + * PPP_PHASE_RUNNING + * | .||||| + * | . |||| + * PPP_PHASE_TERMINATE + * | . |||| + * PPP_PHASE_NETWORK + * |. . + * PPP_PHASE_ESTABLISH + * PPP_PHASE_DISCONNECT + * PPP_PHASE_DEAD + * + * Alright, PPP basic retransmission and LCP Echo consume one timer. + * 1 + * + * If authentication is enabled one timer is necessary during authentication. + * 1 + PPP_AUTH_SUPPORT + * + * If ECP is enabled one timer is necessary before IPCP and/or IP6CP, one more + * is necessary if CCP is enabled (only with MPPE support but we don't care much + * up to this detail level). + * 1 + ECP_SUPPORT + CCP_SUPPORT + * + * If CCP is enabled it might consume a timer during IPCP or IP6CP, thus + * we might use IPCP, IP6CP and CCP timers simultaneously. + * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT + * + * When entering running phase, IPCP or IP6CP is still running. If idle time limit + * is enabled one more timer is necessary. Same for max connect time and max + * octets features. Furthermore CCP RACK might be used past this point. + * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT + * + * IPv4 or IPv6 must be enabled, therefore we don't need to take care the authentication + * and the CCP + ECP case, thus reducing overall complexity. + * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT) + * + * We don't support PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features + * and adding those defines to ppp_opts.h just for having the value always + * defined to 0 isn't worth it. + * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT) + * + * Thus, the following is enough for now. + * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT + */ + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_SUPPORT */ +#endif /* LWIP_HDR_PPP_IMPL_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_opts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_opts.h new file mode 100644 index 0000000..479a006 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/ppp_opts.h @@ -0,0 +1,617 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPP_OPTS_H +#define LWIP_PPP_OPTS_H + +#include "lwip/opt.h" + +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOE_SCNAME_SUPPORT==1: Enable PPP Over Ethernet Service Name and Concentrator Name support + */ +#ifndef PPPOE_SCNAME_SUPPORT +#define PPPOE_SCNAME_SUPPORT 0 +#endif + +/** + * PPPOL2TP_SUPPORT==1: Enable PPP Over L2TP + */ +#ifndef PPPOL2TP_SUPPORT +#define PPPOL2TP_SUPPORT 0 +#endif + +/** + * PPPOL2TP_AUTH_SUPPORT==1: Enable PPP Over L2TP Auth (enable MD5 support) + */ +#ifndef PPPOL2TP_AUTH_SUPPORT +#define PPPOL2TP_AUTH_SUPPORT PPPOL2TP_SUPPORT +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +/** + * LWIP_PPP_API==1: Enable PPP API (in pppapi.c) + */ +#ifndef LWIP_PPP_API +#define LWIP_PPP_API (PPP_SUPPORT && (NO_SYS == 0)) +#endif + +#if PPP_SUPPORT + +/** + * MEMP_NUM_PPP_PCB: the number of simultaneously active PPP + * connections (requires the PPP_SUPPORT option) + */ +#ifndef MEMP_NUM_PPP_PCB +#define MEMP_NUM_PPP_PCB 1 +#endif + +/** + * PPP_NUM_TIMEOUTS_PER_PCB: the number of sys_timeouts running in parallel per + * ppp_pcb. See the detailed explanation at the end of ppp_impl.h about simultaneous + * timers analysis. + */ +#ifndef PPP_NUM_TIMEOUTS_PER_PCB +#define PPP_NUM_TIMEOUTS_PER_PCB (1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT) +#endif + +/* The number of sys_timeouts required for the PPP module */ +#define PPP_NUM_TIMEOUTS (PPP_SUPPORT * PPP_NUM_TIMEOUTS_PER_PCB * MEMP_NUM_PPP_PCB) + +/** + * MEMP_NUM_PPPOS_INTERFACES: the number of concurrently active PPPoS + * interfaces (only used with PPPOS_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOS_INTERFACES +#define MEMP_NUM_PPPOS_INTERFACES MEMP_NUM_PPP_PCB +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPPOL2TP_INTERFACES: the number of concurrently active PPPoL2TP + * interfaces (only used with PPPOL2TP_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOL2TP_INTERFACES +#define MEMP_NUM_PPPOL2TP_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPP_API_MSG: Number of concurrent PPP API messages (in pppapi.c) + */ +#ifndef MEMP_NUM_PPP_API_MSG +#define MEMP_NUM_PPP_API_MSG 5 +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_INPROC_IRQ_SAFE==1 call pppos_input() using tcpip_callback(). + * + * Please read the "PPPoS input path" chapter in the PPP documentation about this option. + */ +#ifndef PPP_INPROC_IRQ_SAFE +#define PPP_INPROC_IRQ_SAFE 0 +#endif + +/** + * PRINTPKT_SUPPORT==1: Enable PPP print packet support + * + * Mandatory for debugging, it displays exchanged packet content in debug trace. + */ +#ifndef PRINTPKT_SUPPORT +#define PRINTPKT_SUPPORT 0 +#endif + +/** + * PPP_IPV4_SUPPORT==1: Enable PPP IPv4 support + */ +#ifndef PPP_IPV4_SUPPORT +#define PPP_IPV4_SUPPORT (LWIP_IPV4) +#endif + +/** + * PPP_IPV6_SUPPORT==1: Enable PPP IPv6 support + */ +#ifndef PPP_IPV6_SUPPORT +#define PPP_IPV6_SUPPORT (LWIP_IPV6) +#endif + +/** + * PPP_NOTIFY_PHASE==1: Support PPP notify phase support + * + * PPP notify phase support allows you to set a callback which is + * called on change of the internal PPP state machine. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +#ifndef PPP_NOTIFY_PHASE +#define PPP_NOTIFY_PHASE 0 +#endif + +/** + * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets. + * + * Memory allocated must be single buffered for PPP to works, it requires pbuf + * that are not going to be chained when allocated. This requires setting + * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. + * + * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous + * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. + */ +#ifndef PPP_USE_PBUF_RAM +#define PPP_USE_PBUF_RAM 0 +#endif + +/** + * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS + */ +#ifndef PPP_FCS_TABLE +#define PPP_FCS_TABLE 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif +#if MSCHAP_SUPPORT +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MSCHAP_SUPPORT */ + +/** + * EAP_SUPPORT==1: Support EAP. + */ +#ifndef EAP_SUPPORT +#define EAP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * MPPE_SUPPORT==1: Support MPPE. + */ +#ifndef MPPE_SUPPORT +#define MPPE_SUPPORT 0 +#endif +#if MPPE_SUPPORT +/* MPPE requires CCP support */ +#undef CCP_SUPPORT +#define CCP_SUPPORT 1 +/* MPPE requires MSCHAP support */ +#undef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 1 +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MPPE_SUPPORT */ + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * ECP_SUPPORT==1: Support ECP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef ECP_SUPPORT +#define ECP_SUPPORT 0 +#endif + +/** + * DEMAND_SUPPORT==1: Support dial on demand. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef DEMAND_SUPPORT +#define DEMAND_SUPPORT 0 +#endif + +/** + * LQR_SUPPORT==1: Support Link Quality Report. Do nothing except exchanging some LCP packets. + */ +#ifndef LQR_SUPPORT +#define LQR_SUPPORT 0 +#endif + +/** + * PPP_SERVER==1: Enable PPP server support (waiting for incoming PPP session). + * + * Currently only supported for PPPoS. + */ +#ifndef PPP_SERVER +#define PPP_SERVER 0 +#endif + +#if PPP_SERVER +/* + * PPP_OUR_NAME: Our name for authentication purposes + */ +#ifndef PPP_OUR_NAME +#define PPP_OUR_NAME "lwIP" +#endif +#endif /* PPP_SERVER */ + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 1 +#endif +/* VJ compression is only supported for TCP over IPv4 over PPPoS. */ +#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP +#undef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif /* !PPPOS_SUPPORT */ + +/** + * PPP_MD5_RANDM==1: Use MD5 for better randomness. + * Enabled by default if CHAP, EAP, or L2TP AUTH support is enabled. + */ +#ifndef PPP_MD5_RANDM +#define PPP_MD5_RANDM (CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT) +#endif + +/** + * PolarSSL embedded library + * + * + * lwIP contains some files fetched from the latest BSD release of + * the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption + * methods we need for lwIP PPP support. + * + * The PolarSSL files were cleaned to contain only the necessary struct + * fields and functions needed for lwIP. + * + * The PolarSSL API was not changed at all, so if you are already using + * PolarSSL you can choose to skip the compilation of the included PolarSSL + * library into lwIP. + * + * If you are not using the embedded copy you must include external + * libraries into your arch/cc.h port file. + * + * Beware of the stack requirements which can be a lot larger if you are not + * using our cleaned PolarSSL library. + */ + +/** + * LWIP_USE_EXTERNAL_POLARSSL: Use external PolarSSL library + */ +#ifndef LWIP_USE_EXTERNAL_POLARSSL +#define LWIP_USE_EXTERNAL_POLARSSL 0 +#endif + +/** + * LWIP_USE_EXTERNAL_MBEDTLS: Use external mbed TLS library + */ +#ifndef LWIP_USE_EXTERNAL_MBEDTLS +#define LWIP_USE_EXTERNAL_MBEDTLS 0 +#endif + +/* + * PPP Timeouts + */ + +/** + * FSM_DEFTIMEOUT: Timeout time in seconds + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 +#endif + +/** + * FSM_DEFMAXTERMREQS: Maximum Terminate-Request transmissions + */ +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 +#endif + +/** + * FSM_DEFMAXCONFREQS: Maximum Configure-Request transmissions + */ +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 +#endif + +/** + * FSM_DEFMAXNAKLOOPS: Maximum number of nak loops + */ +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 +#endif + +/** + * UPAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 +#endif + +/** + * UPAP_DEFTRANSMITS: Maximum number of auth-reqs to send + */ +#ifndef UPAP_DEFTRANSMITS +#define UPAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * UPAP_DEFREQTIME: Time to wait for auth-req from peer + */ +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 +#endif +#endif /* PPP_SERVER */ + +/** + * CHAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 +#endif + +/** + * CHAP_DEFTRANSMITS: max # times to send challenge + */ +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * CHAP_DEFRECHALLENGETIME: If this option is > 0, rechallenge the peer every n seconds + */ +#ifndef CHAP_DEFRECHALLENGETIME +#define CHAP_DEFRECHALLENGETIME 0 +#endif +#endif /* PPP_SERVER */ + +/** + * EAP_DEFREQTIME: Time to wait for peer request + */ +#ifndef EAP_DEFREQTIME +#define EAP_DEFREQTIME 6 +#endif + +/** + * EAP_DEFALLOWREQ: max # times to accept requests + */ +#ifndef EAP_DEFALLOWREQ +#define EAP_DEFALLOWREQ 10 +#endif + +#if PPP_SERVER +/** + * EAP_DEFTIMEOUT: Timeout (seconds) for rexmit + */ +#ifndef EAP_DEFTIMEOUT +#define EAP_DEFTIMEOUT 6 +#endif + +/** + * EAP_DEFTRANSMITS: max # times to transmit + */ +#ifndef EAP_DEFTRANSMITS +#define EAP_DEFTRANSMITS 10 +#endif +#endif /* PPP_SERVER */ + +/** + * LCP_DEFLOOPBACKFAIL: Default number of times we receive our magic number from the peer + * before deciding the link is looped-back. + */ +#ifndef LCP_DEFLOOPBACKFAIL +#define LCP_DEFLOOPBACKFAIL 10 +#endif + +/** + * LCP_ECHOINTERVAL: Interval in seconds between keepalive echo requests, 0 to disable. + */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/** + * LCP_MAXECHOFAILS: Number of unanswered echo requests before failure. + */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/** + * PPP_MAXIDLEFLAG: Max Xmit idle time (in ms) before resend flag char. + */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/** + * PPP Packet sizes + */ + +/** + * PPP_MRU: Default MRU + */ +#ifndef PPP_MRU +#define PPP_MRU 1500 +#endif + +/** + * PPP_DEFMRU: Default MRU to try + */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 1500 +#endif + +/** + * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384) + */ +#ifndef PPP_MAXMRU +#define PPP_MAXMRU 1500 +#endif + +/** + * PPP_MINMRU: No MRUs below this + */ +#ifndef PPP_MINMRU +#define PPP_MINMRU 128 +#endif + +/** + * PPPOL2TP_DEFMRU: Default MTU and MRU for L2TP + * Default = 1500 - PPPoE(6) - PPP Protocol(2) - IPv4 header(20) - UDP Header(8) + * - L2TP Header(6) - HDLC Header(2) - PPP Protocol(2) - MPPE Header(2) - PPP Protocol(2) + */ +#if PPPOL2TP_SUPPORT +#ifndef PPPOL2TP_DEFMRU +#define PPPOL2TP_DEFMRU 1450 +#endif +#endif /* PPPOL2TP_SUPPORT */ + +/** + * MAXNAMELEN: max length of hostname or name for auth + */ +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 +#endif + +/** + * MAXSECRETLEN: max length of password or secret + */ +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Build triggers for embedded PolarSSL + */ +#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS + +/* CHAP, EAP, L2TP AUTH and MD5 Random require MD5 support */ +#if CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#endif /* CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM */ + +#if MSCHAP_SUPPORT + +/* MSCHAP require MD4 support */ +#define LWIP_INCLUDED_POLARSSL_MD4 1 +/* MSCHAP require SHA1 support */ +#define LWIP_INCLUDED_POLARSSL_SHA1 1 +/* MSCHAP require DES support */ +#define LWIP_INCLUDED_POLARSSL_DES 1 + +/* MS-CHAP support is required for MPPE */ +#if MPPE_SUPPORT +/* MPPE require ARC4 support */ +#define LWIP_INCLUDED_POLARSSL_ARC4 1 +#endif /* MPPE_SUPPORT */ + +#endif /* MSCHAP_SUPPORT */ + +#endif /* !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* Default value if unset */ +#ifndef LWIP_INCLUDED_POLARSSL_MD4 +#define LWIP_INCLUDED_POLARSSL_MD4 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ +#ifndef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ +#ifndef LWIP_INCLUDED_POLARSSL_SHA1 +#define LWIP_INCLUDED_POLARSSL_SHA1 0 +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ +#ifndef LWIP_INCLUDED_POLARSSL_DES +#define LWIP_INCLUDED_POLARSSL_DES 0 +#endif /* LWIP_INCLUDED_POLARSSL_DES */ +#ifndef LWIP_INCLUDED_POLARSSL_ARC4 +#define LWIP_INCLUDED_POLARSSL_ARC4 0 +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ + +#endif /* PPP_SUPPORT */ + +/* Default value if unset */ +#ifndef PPP_NUM_TIMEOUTS +#define PPP_NUM_TIMEOUTS 0 +#endif /* PPP_NUM_TIMEOUTS */ + +#endif /* LWIP_PPP_OPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppapi.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppapi.h new file mode 100644 index 0000000..913d93f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppapi.h @@ -0,0 +1,137 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPPAPI_H +#define LWIP_PPPAPI_H + +#include "netif/ppp/ppp_opts.h" + +#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/priv/tcpip_priv.h" +#include "netif/ppp/ppp.h" +#if PPPOS_SUPPORT +#include "netif/ppp/pppos.h" +#endif /* PPPOS_SUPPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct pppapi_msg_msg { + ppp_pcb *ppp; + union { +#if PPP_NOTIFY_PHASE + struct { + ppp_notify_phase_cb_fn notify_phase_cb; + } setnotifyphasecb; +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT + struct { + struct netif *pppif; + pppos_output_cb_fn output_cb; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } serialcreate; +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT + struct { + struct netif *pppif; + struct netif *ethif; + const char *service_name; + const char *concentrator_name; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } ethernetcreate; +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT + struct { + struct netif *pppif; + struct netif *netif; + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; + u8_t secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } l2tpcreate; +#endif /* PPPOL2TP_SUPPORT */ + struct { + u16_t holdoff; + } connect; + struct { + u8_t nocarrier; + } close; + struct { + u8_t cmd; + void *arg; + } ioctl; + } msg; +}; + +struct pppapi_msg { + struct tcpip_api_call_data call; + struct pppapi_msg_msg msg; +}; + +/* API for application */ +err_t pppapi_set_default(ppp_pcb *pcb); +#if PPP_NOTIFY_PHASE +err_t pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT +ppp_pcb *pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT +ppp_pcb *pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, + const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, + void *ctx_cb); +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT +ppp_pcb *pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOL2TP_SUPPORT */ +err_t pppapi_connect(ppp_pcb *pcb, u16_t holdoff); +#if PPP_SERVER +err_t pppapi_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ +err_t pppapi_close(ppp_pcb *pcb, u8_t nocarrier); +err_t pppapi_free(ppp_pcb *pcb); +err_t pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PPP_API */ + +#endif /* LWIP_PPPAPI_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppcrypt.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppcrypt.h new file mode 100644 index 0000000..c0230bb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppcrypt.h @@ -0,0 +1,144 @@ +/* + * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 + * + * Extracted from chap_ms.c by James Carlson. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* This header file is included in all PPP modules needing hashes and/or ciphers */ + +#ifndef PPPCRYPT_H +#define PPPCRYPT_H + +/* + * If included PolarSSL copy is not used, user is expected to include + * external libraries in arch/cc.h (which is included by lwip/arch.h). + */ +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Map hashes and ciphers functions to PolarSSL + */ +#if !LWIP_USE_EXTERNAL_MBEDTLS + +#include "netif/ppp/polarssl/md4.h" +#define lwip_md4_context md4_context +#define lwip_md4_init(context) +#define lwip_md4_starts md4_starts +#define lwip_md4_update md4_update +#define lwip_md4_finish md4_finish +#define lwip_md4_free(context) + +#include "netif/ppp/polarssl/md5.h" +#define lwip_md5_context md5_context +#define lwip_md5_init(context) +#define lwip_md5_starts md5_starts +#define lwip_md5_update md5_update +#define lwip_md5_finish md5_finish +#define lwip_md5_free(context) + +#include "netif/ppp/polarssl/sha1.h" +#define lwip_sha1_context sha1_context +#define lwip_sha1_init(context) +#define lwip_sha1_starts sha1_starts +#define lwip_sha1_update sha1_update +#define lwip_sha1_finish sha1_finish +#define lwip_sha1_free(context) + +#include "netif/ppp/polarssl/des.h" +#define lwip_des_context des_context +#define lwip_des_init(context) +#define lwip_des_setkey_enc des_setkey_enc +#define lwip_des_crypt_ecb des_crypt_ecb +#define lwip_des_free(context) + +#include "netif/ppp/polarssl/arc4.h" +#define lwip_arc4_context arc4_context +#define lwip_arc4_init(context) +#define lwip_arc4_setup arc4_setup +#define lwip_arc4_crypt arc4_crypt +#define lwip_arc4_free(context) + +#endif /* !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* + * Map hashes and ciphers functions to mbed TLS + */ +#if LWIP_USE_EXTERNAL_MBEDTLS + +#define lwip_md4_context mbedtls_md4_context +#define lwip_md4_init mbedtls_md4_init +#define lwip_md4_starts mbedtls_md4_starts +#define lwip_md4_update mbedtls_md4_update +#define lwip_md4_finish mbedtls_md4_finish +#define lwip_md4_free mbedtls_md4_free + +#define lwip_md5_context mbedtls_md5_context +#define lwip_md5_init mbedtls_md5_init +#define lwip_md5_starts mbedtls_md5_starts +#define lwip_md5_update mbedtls_md5_update +#define lwip_md5_finish mbedtls_md5_finish +#define lwip_md5_free mbedtls_md5_free + +#define lwip_sha1_context mbedtls_sha1_context +#define lwip_sha1_init mbedtls_sha1_init +#define lwip_sha1_starts mbedtls_sha1_starts +#define lwip_sha1_update mbedtls_sha1_update +#define lwip_sha1_finish mbedtls_sha1_finish +#define lwip_sha1_free mbedtls_sha1_free + +#define lwip_des_context mbedtls_des_context +#define lwip_des_init mbedtls_des_init +#define lwip_des_setkey_enc mbedtls_des_setkey_enc +#define lwip_des_crypt_ecb mbedtls_des_crypt_ecb +#define lwip_des_free mbedtls_des_free + +#define lwip_arc4_context mbedtls_arc4_context +#define lwip_arc4_init mbedtls_arc4_init +#define lwip_arc4_setup mbedtls_arc4_setup +#define lwip_arc4_crypt(context, buffer, length) mbedtls_arc4_crypt(context, length, buffer, buffer) +#define lwip_arc4_free mbedtls_arc4_free + +#endif /* LWIP_USE_EXTERNAL_MBEDTLS */ + +void pppcrypt_56_to_64_bit_key(u_char *key, u_char *des_key); + +#ifdef __cplusplus +} +#endif + +#endif /* PPPCRYPT_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppdebug.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppdebug.h new file mode 100644 index 0000000..36ee4f9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppdebug.h @@ -0,0 +1,88 @@ +/***************************************************************************** +* pppdebug.h - System debugging utilities. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* portions Copyright (c) 2001 by Cognizant Pty Ltd. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY (please don't use tabs!) +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-07-29 Guy Lancaster , Global Election Systems Inc. +* Original. +* +***************************************************************************** +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPDEBUG_H +#define PPPDEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Trace levels. */ +#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_INFO (PPP_DEBUG) +#define LOG_DETAIL (PPP_DEBUG) +#define LOG_DEBUG (PPP_DEBUG) + +#if PPP_DEBUG + +#define MAINDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define SYSDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define FSMDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define LCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPV6CPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define UPAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define CHAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) + +#else /* PPP_DEBUG */ + +#define MAINDEBUG(a) +#define SYSDEBUG(a) +#define FSMDEBUG(a) +#define LCPDEBUG(a) +#define IPCPDEBUG(a) +#define IPV6CPDEBUG(a) +#define UPAPDEBUG(a) +#define CHAPDEBUG(a) +#define PPPDEBUG(a, b) + +#endif /* PPP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* PPPDEBUG_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppoe.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppoe.h new file mode 100644 index 0000000..8994d38 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppoe.h @@ -0,0 +1,187 @@ +/***************************************************************************** +* pppoe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "ppp.h" +#include "lwip/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { + PACK_STRUCT_FLD_8(u8_t vertype); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +/* passive */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif + +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + ppp_pcb *pcb; /* PPP PCB */ + + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + u8_t sc_state; /* discovery phase or session connected */ + +#if PPPOE_SCNAME_SUPPORT + const char *sc_service_name; /* if != NULL: requested name of service */ + const char *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_SCNAME_SUPPORT */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + u8_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + u8_t sc_hunique_len; /* length of host unique */ +#endif + u8_t sc_padi_retried; /* number of PADI retries already done */ + u8_t sc_padr_retried; /* number of PADR retries already done */ +}; + + +#define pppoe_init() /* compatibility define, no initialization needed */ + +ppp_pcb *pppoe_create(struct netif *pppif, + struct netif *ethif, + const char *service_name, const char *concentrator_name, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_OE_H */ + +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppol2tp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppol2tp.h new file mode 100644 index 0000000..1221ca1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppol2tp.h @@ -0,0 +1,209 @@ +/** + * @file + * Network Point to Point Protocol over Layer 2 Tunneling Protocol header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOL2TP_H +#define PPPOL2TP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Timeout */ +#define PPPOL2TP_CONTROL_TIMEOUT (5*1000) /* base for quick timeout calculation */ +#define PPPOL2TP_SLOW_RETRY (60*1000) /* persistent retry interval */ + +#define PPPOL2TP_MAXSCCRQ 4 /* retry SCCRQ four times (quickly) */ +#define PPPOL2TP_MAXICRQ 4 /* retry IRCQ four times */ +#define PPPOL2TP_MAXICCN 4 /* retry ICCN four times */ + +/* L2TP header flags */ +#define PPPOL2TP_HEADERFLAG_CONTROL 0x8000 +#define PPPOL2TP_HEADERFLAG_LENGTH 0x4000 +#define PPPOL2TP_HEADERFLAG_SEQUENCE 0x0800 +#define PPPOL2TP_HEADERFLAG_OFFSET 0x0200 +#define PPPOL2TP_HEADERFLAG_PRIORITY 0x0100 +#define PPPOL2TP_HEADERFLAG_VERSION 0x0002 + +/* Mandatory bits for control: Control, Length, Sequence, Version 2 */ +#define PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY (PPPOL2TP_HEADERFLAG_CONTROL|PPPOL2TP_HEADERFLAG_LENGTH|PPPOL2TP_HEADERFLAG_SEQUENCE|PPPOL2TP_HEADERFLAG_VERSION) +/* Forbidden bits for control: Offset, Priority */ +#define PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN (PPPOL2TP_HEADERFLAG_OFFSET|PPPOL2TP_HEADERFLAG_PRIORITY) + +/* Mandatory bits for data: Version 2 */ +#define PPPOL2TP_HEADERFLAG_DATA_MANDATORY (PPPOL2TP_HEADERFLAG_VERSION) + +/* AVP (Attribute Value Pair) header */ +#define PPPOL2TP_AVPHEADERFLAG_MANDATORY 0x8000 +#define PPPOL2TP_AVPHEADERFLAG_HIDDEN 0x4000 +#define PPPOL2TP_AVPHEADERFLAG_LENGTHMASK 0x03ff + +/* -- AVP - Message type */ +#define PPPOL2TP_AVPTYPE_MESSAGE 0 /* Message type */ + +/* Control Connection Management */ +#define PPPOL2TP_MESSAGETYPE_SCCRQ 1 /* Start Control Connection Request */ +#define PPPOL2TP_MESSAGETYPE_SCCRP 2 /* Start Control Connection Reply */ +#define PPPOL2TP_MESSAGETYPE_SCCCN 3 /* Start Control Connection Connected */ +#define PPPOL2TP_MESSAGETYPE_STOPCCN 4 /* Stop Control Connection Notification */ +#define PPPOL2TP_MESSAGETYPE_HELLO 6 /* Hello */ +/* Call Management */ +#define PPPOL2TP_MESSAGETYPE_OCRQ 7 /* Outgoing Call Request */ +#define PPPOL2TP_MESSAGETYPE_OCRP 8 /* Outgoing Call Reply */ +#define PPPOL2TP_MESSAGETYPE_OCCN 9 /* Outgoing Call Connected */ +#define PPPOL2TP_MESSAGETYPE_ICRQ 10 /* Incoming Call Request */ +#define PPPOL2TP_MESSAGETYPE_ICRP 11 /* Incoming Call Reply */ +#define PPPOL2TP_MESSAGETYPE_ICCN 12 /* Incoming Call Connected */ +#define PPPOL2TP_MESSAGETYPE_CDN 14 /* Call Disconnect Notify */ +/* Error reporting */ +#define PPPOL2TP_MESSAGETYPE_WEN 15 /* WAN Error Notify */ +/* PPP Session Control */ +#define PPPOL2TP_MESSAGETYPE_SLI 16 /* Set Link Info */ + +/* -- AVP - Result code */ +#define PPPOL2TP_AVPTYPE_RESULTCODE 1 /* Result code */ +#define PPPOL2TP_RESULTCODE 1 /* General request to clear control connection */ + +/* -- AVP - Protocol version (!= L2TP Header version) */ +#define PPPOL2TP_AVPTYPE_VERSION 2 +#define PPPOL2TP_VERSION 0x0100 /* L2TP Protocol version 1, revision 0 */ + +/* -- AVP - Framing capabilities */ +#define PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES 3 /* Bearer capabilities */ +#define PPPOL2TP_FRAMINGCAPABILITIES 0x00000003 /* Async + Sync framing */ + +/* -- AVP - Bearer capabilities */ +#define PPPOL2TP_AVPTYPE_BEARERCAPABILITIES 4 /* Bearer capabilities */ +#define PPPOL2TP_BEARERCAPABILITIES 0x00000003 /* Analog + Digital Access */ + +/* -- AVP - Tie breaker */ +#define PPPOL2TP_AVPTYPE_TIEBREAKER 5 + +/* -- AVP - Host name */ +#define PPPOL2TP_AVPTYPE_HOSTNAME 7 /* Host name */ +#define PPPOL2TP_HOSTNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Vendor name */ +#define PPPOL2TP_AVPTYPE_VENDORNAME 8 /* Vendor name */ +#define PPPOL2TP_VENDORNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Assign tunnel ID */ +#define PPPOL2TP_AVPTYPE_TUNNELID 9 /* Assign Tunnel ID */ + +/* -- AVP - Receive window size */ +#define PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE 10 /* Receive window size */ +#define PPPOL2TP_RECEIVEWINDOWSIZE 8 /* FIXME: make it configurable */ + +/* -- AVP - Challenge */ +#define PPPOL2TP_AVPTYPE_CHALLENGE 11 /* Challenge */ + +/* -- AVP - Cause code */ +#define PPPOL2TP_AVPTYPE_CAUSECODE 12 /* Cause code*/ + +/* -- AVP - Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE 13 /* Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE 16 + +/* -- AVP - Assign session ID */ +#define PPPOL2TP_AVPTYPE_SESSIONID 14 /* Assign Session ID */ + +/* -- AVP - Call serial number */ +#define PPPOL2TP_AVPTYPE_CALLSERIALNUMBER 15 /* Call Serial Number */ + +/* -- AVP - Framing type */ +#define PPPOL2TP_AVPTYPE_FRAMINGTYPE 19 /* Framing Type */ +#define PPPOL2TP_FRAMINGTYPE 0x00000001 /* Sync framing */ + +/* -- AVP - TX Connect Speed */ +#define PPPOL2TP_AVPTYPE_TXCONNECTSPEED 24 /* TX Connect Speed */ +#define PPPOL2TP_TXCONNECTSPEED 100000000 /* Connect speed: 100 Mbits/s */ + +/* L2TP Session state */ +#define PPPOL2TP_STATE_INITIAL 0 +#define PPPOL2TP_STATE_SCCRQ_SENT 1 +#define PPPOL2TP_STATE_ICRQ_SENT 2 +#define PPPOL2TP_STATE_ICCN_SENT 3 +#define PPPOL2TP_STATE_DATA 4 + +#define PPPOL2TP_OUTPUT_DATA_HEADER_LEN 6 /* Our data header len */ + +/* + * PPPoL2TP interface control block. + */ +typedef struct pppol2tp_pcb_s pppol2tp_pcb; +struct pppol2tp_pcb_s { + ppp_pcb *ppp; /* PPP PCB */ + u8_t phase; /* L2TP phase */ + struct udp_pcb *udp; /* UDP L2TP Socket */ + struct netif *netif; /* Output interface, used as a default route */ + ip_addr_t remote_ip; /* LNS IP Address */ + u16_t remote_port; /* LNS port */ +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; /* Secret string */ + u8_t secret_len; /* Secret string length */ + u8_t secret_rv[16]; /* Random vector */ + u8_t challenge_hash[16]; /* Challenge response */ + u8_t send_challenge; /* Boolean whether the next sent packet should contains a challenge response */ +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + u16_t tunnel_port; /* Tunnel port */ + u16_t our_ns; /* NS to peer */ + u16_t peer_nr; /* NR from peer */ + u16_t peer_ns; /* Expected NS from peer */ + u16_t source_tunnel_id; /* Tunnel ID assigned by peer */ + u16_t remote_tunnel_id; /* Tunnel ID assigned to peer */ + u16_t source_session_id; /* Session ID assigned by peer */ + u16_t remote_session_id; /* Session ID assigned to peer */ + + u8_t sccrq_retried; /* number of SCCRQ retries already done */ + u8_t icrq_retried; /* number of ICRQ retries already done */ + u8_t iccn_retried; /* number of ICCN retries already done */ +}; + + +/* Create a new L2TP session. */ +ppp_pcb *pppol2tp_create(struct netif *pppif, + struct netif *netif, const ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#ifdef __cplusplus +} +#endif + +#endif /* PPPOL2TP_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppos.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppos.h new file mode 100644 index 0000000..380a965 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/pppos.h @@ -0,0 +1,126 @@ +/** + * @file + * Network Point to Point Protocol over Serial header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOS_H +#define PPPOS_H + +#include "lwip/sys.h" + +#include "ppp.h" +#include "vj.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* PPP packet parser states. Current state indicates operation yet to be + * completed. */ +enum { + PDIDLE = 0, /* Idle state - waiting. */ + PDSTART, /* Process start flag. */ + PDADDRESS, /* Process address field. */ + PDCONTROL, /* Process control field. */ + PDPROTOCOL1, /* Process protocol field 1. */ + PDPROTOCOL2, /* Process protocol field 2. */ + PDDATA /* Process data byte. */ +}; + +/* PPPoS serial output callback function prototype */ +typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx); + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u8_t ext_accm[32]; + +/* + * PPPoS interface control block. + */ +typedef struct pppos_pcb_s pppos_pcb; +struct pppos_pcb_s { + /* -- below are data that will NOT be cleared between two sessions */ + ppp_pcb *ppp; /* PPP PCB */ + pppos_output_cb_fn output_cb; /* PPP serial output callback */ + + /* -- below are data that will be cleared between two sessions + * + * last_xmit must be the first member of cleared members, because it is + * used to know which part must not be cleared. + */ + u32_t last_xmit; /* Time of last transmission. */ + ext_accm out_accm; /* Async-Ctl-Char-Map for output. */ + + /* flags */ + unsigned int open :1; /* Set if PPPoS is open */ + unsigned int pcomp :1; /* Does peer accept protocol compression? */ + unsigned int accomp :1; /* Does peer accept addr/ctl compression? */ + + /* PPPoS rx */ + ext_accm in_accm; /* Async-Ctl-Char-Map for input. */ + struct pbuf *in_head, *in_tail; /* The input packet. */ + u16_t in_protocol; /* The input protocol code. */ + u16_t in_fcs; /* Input Frame Check Sequence value. */ + u8_t in_state; /* The input process state. */ + u8_t in_escaped; /* Escape next character. */ +}; + +/* Create a new PPPoS session. */ +ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +/* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */ +err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +/* PPP over Serial: this is the input function to be called for received data. */ +void pppos_input(ppp_pcb *ppp, u8_t* data, int len); + + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +err_t pppos_input_sys(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +#ifdef __cplusplus +} +#endif + +#endif /* PPPOS_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/upap.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/upap.h new file mode 100644 index 0000000..540d981 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/upap.h @@ -0,0 +1,131 @@ +/* + * upap.h - User/Password Authentication Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: upap.h,v 1.8 2002/12/04 23:03:33 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef UPAP_H +#define UPAP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN 4 + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + + +/* + * Client states. + */ +#define UPAPCS_INITIAL 0 /* Connection down */ +#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ +#define UPAPCS_OPEN 4 /* We've received an Ack */ +#define UPAPCS_BADAUTH 5 /* We've received a Nak */ + +/* + * Server states. + */ +#define UPAPSS_INITIAL 0 /* Connection down */ +#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ +#define UPAPSS_OPEN 4 /* We've sent an Ack */ +#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif /* moved to ppp_opts.h */ + +/* + * Each interface is described by upap structure. + */ +#if PAP_SUPPORT +typedef struct upap_state { + const char *us_user; /* User */ + u8_t us_userlen; /* User length */ + const char *us_passwd; /* Password */ + u8_t us_passwdlen; /* Password length */ + u8_t us_clientstate; /* Client state */ +#if PPP_SERVER + u8_t us_serverstate; /* Server state */ +#endif /* PPP_SERVER */ + u8_t us_id; /* Current id */ + u8_t us_transmits; /* Number of auth-reqs sent */ +} upap_state; +#endif /* PAP_SUPPORT */ + + +void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password); +#if PPP_SERVER +void upap_authpeer(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +extern const struct protent pap_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* UPAP_H */ +#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/vj.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/vj.h new file mode 100644 index 0000000..77d9976 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/ppp/vj.h @@ -0,0 +1,169 @@ +/* + * Definitions for tcp compression routines. + * + * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef VJ_H +#define VJ_H + +#include "lwip/ip.h" +#include "lwip/priv/tcp_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_SLOTS 16 /* must be > 2 and < 256 */ +#define MAX_HDR 128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP 0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP 0x80 +#define TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + struct cstate *cs_next; /* next most recently used state (xmit only) */ + u16_t cs_hlen; /* size of hdr (receive only) */ + u8_t cs_id; /* connection # associated with this state */ + u8_t cs_filler; + union { + char csu_hdr[MAX_HDR]; + struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ + } vjcs_u; +}; +#define cs_ip vjcs_u.csu_ip +#define cs_hdr vjcs_u.csu_hdr + + +struct vjstat { + u32_t vjs_packets; /* outbound packets */ + u32_t vjs_compressed; /* outbound compressed packets */ + u32_t vjs_searches; /* searches for connection state */ + u32_t vjs_misses; /* times couldn't find conn. state */ + u32_t vjs_uncompressedin; /* inbound uncompressed packets */ + u32_t vjs_compressedin; /* inbound compressed packets */ + u32_t vjs_errorin; /* inbound unknown type packets */ + u32_t vjs_tossed; /* inbound packets tossed because of error */ +}; + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct vjcompress { + struct cstate *last_cs; /* most recently used tstate */ + u8_t last_recv; /* last rcvd conn. id */ + u8_t last_xmit; /* last sent conn. id */ + u16_t flags; + u8_t maxSlotIndex; + u8_t compressSlot; /* Flag indicating OK to compress slot ID. */ +#if LINK_STATS + struct vjstat stats; +#endif + struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ + struct cstate rstate[MAX_SLOTS]; /* receive connection states */ +}; + +/* flag values */ +#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ + +extern void vj_compress_init (struct vjcompress *comp); +extern u8_t vj_compress_tcp (struct vjcompress *comp, struct pbuf **pb); +extern void vj_uncompress_err (struct vjcompress *comp); +extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); +extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp); + +#ifdef __cplusplus +} +#endif + +#endif /* VJ_H */ + +#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/slipif.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/slipif.h new file mode 100644 index 0000000..65ba31f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/slipif.h @@ -0,0 +1,87 @@ +/** + * @file + * + * SLIP netif API + */ + +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_SLIPIF_H +#define LWIP_HDR_NETIF_SLIPIF_H + +#include "lwip/opt.h" +#include "lwip/netif.h" + +/** Set this to 1 to start a thread that blocks reading on the serial line + * (using sio_read()). + */ +#ifndef SLIP_USE_RX_THREAD +#define SLIP_USE_RX_THREAD !NO_SYS +#endif + +/** Set this to 1 to enable functions to pass in RX bytes from ISR context. + * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled + * packets on a queue, which is fed into lwIP from slipif_poll(). + * If disabled, slipif_poll() polls the serial line (using sio_tryread()). + */ +#ifndef SLIP_RX_FROM_ISR +#define SLIP_RX_FROM_ISR 0 +#endif + +/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets + * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. + * If disabled, packets will be dropped if more than one packet is received. + */ +#ifndef SLIP_RX_QUEUE +#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +err_t slipif_init(struct netif * netif); +void slipif_poll(struct netif *netif); +#if SLIP_RX_FROM_ISR +void slipif_process_rxqueue(struct netif *netif); +void slipif_received_byte(struct netif *netif, u8_t data); +void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); +#endif /* SLIP_RX_FROM_ISR */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_SLIPIF_H */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/zepif.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/zepif.h new file mode 100644 index 0000000..2a801b4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/include/netif/zepif.h @@ -0,0 +1,81 @@ +/** + * @file + * + * A netif implementing the ZigBee Eencapsulation Protocol (ZEP). + * This is used to tunnel 6LowPAN over UDP. + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#ifndef LWIP_HDR_ZEPIF_H +#define LWIP_HDR_ZEPIF_H + +#include "lwip/opt.h" +#include "netif/lowpan6.h" + +#if LWIP_IPV6 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZEPIF_DEFAULT_UDP_PORT 17754 + +/** Pass this struct as 'state' to netif_add to control the behaviour + * of this netif. If NULL is passed, default behaviour is chosen */ +struct zepif_init { + /** The UDP port used to ZEP frames from (0 = default) */ + u16_t zep_src_udp_port; + /** The UDP port used to ZEP frames to (0 = default) */ + u16_t zep_dst_udp_port; + /** The IP address to sed ZEP frames from (NULL = ANY) */ + const ip_addr_t *zep_src_ip_addr; + /** The IP address to sed ZEP frames to (NULL = BROADCAST) */ + const ip_addr_t *zep_dst_ip_addr; + /** If != NULL, the udp pcb is bound to this netif */ + const struct netif *zep_netif; + /** MAC address of the 6LowPAN device */ + u8_t addr[6]; +}; + +err_t zepif_init(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_UDP */ + +#endif /* LWIP_HDR_ZEPIF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.c new file mode 100644 index 0000000..880f6ac --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.c @@ -0,0 +1,841 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/** + * @defgroup iperf Iperf server + * @ingroup apps + * + * This is a simple performance measuring client/server to check your bandwith using + * iPerf2 on a PC as server/client. + * It is currently a minimal implementation providing a TCP client/server only. + * + * @todo: + * - implement UDP mode + * - protect combined sessions handling (via 'related_master_state') against reallocation + * (this is a pointer address, currently, so if the same memory is allocated again, + * session pairs (tx/rx) can be confused on reallocation) + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + */ + +#include "lwiperf.h" + +#include "lwip/tcp.h" +#include "lwip/sys.h" + +#include + +/* Currently, only TCP is implemented */ +#if LWIP_TCP && LWIP_CALLBACK_API + +/** Specify the idle timeout (in seconds) after that the test fails */ +#ifndef LWIPERF_TCP_MAX_IDLE_SEC +#define LWIPERF_TCP_MAX_IDLE_SEC 10U +#endif +#if LWIPERF_TCP_MAX_IDLE_SEC > 255 +#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t +#endif + +/** Change this if you don't want to lwiperf to listen to any IP version */ +#ifndef LWIPERF_SERVER_IP_TYPE +#define LWIPERF_SERVER_IP_TYPE IPADDR_TYPE_ANY +#endif + +/* File internal memory allocation (struct lwiperf_*): this defaults to + the heap */ +#ifndef LWIPERF_ALLOC +#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type)) +#define LWIPERF_FREE(type, item) mem_free(item) +#endif + +/** If this is 1, check that received data has the correct format */ +#ifndef LWIPERF_CHECK_RX_DATA +#define LWIPERF_CHECK_RX_DATA 0 +#endif + +/** This is the Iperf settings struct sent from the client */ +typedef struct _lwiperf_settings { +#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000 +#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001 + u32_t flags; + u32_t num_threads; /* unused for now */ + u32_t remote_port; + u32_t buffer_len; /* unused for now */ + u32_t win_band; /* TCP window / UDP rate: unused for now */ + u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */ +} lwiperf_settings_t; + +/** Basic connection handle */ +struct _lwiperf_state_base; +typedef struct _lwiperf_state_base lwiperf_state_base_t; +struct _lwiperf_state_base { + /* linked list */ + lwiperf_state_base_t *next; + /* 1=tcp, 0=udp */ + u8_t tcp; + /* 1=server, 0=client */ + u8_t server; + /* master state used to abort sessions (e.g. listener, main client) */ + lwiperf_state_base_t *related_master_state; +}; + +/** Connection handle for a TCP iperf session */ +typedef struct _lwiperf_state_tcp { + lwiperf_state_base_t base; + struct tcp_pcb *server_pcb; + struct tcp_pcb *conn_pcb; + u32_t time_started; + lwiperf_report_fn report_fn; + void *report_arg; + u8_t poll_count; + u8_t next_num; + /* 1=start server when client is closed */ + u8_t client_tradeoff_mode; + u32_t bytes_transferred; + lwiperf_settings_t settings; + u8_t have_settings_buf; + u8_t specific_remote; + ip_addr_t remote_addr; +} lwiperf_state_tcp_t; + +/** List of active iperf sessions */ +static lwiperf_state_base_t *lwiperf_all_connections; +/** A const buffer to send from: we want to measure sending, not copying! */ +static const u8_t lwiperf_txbuf_const[1600] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', +}; + +static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb); +static void lwiperf_tcp_err(void *arg, err_t err); +static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void *report_arg, + lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state); + + +/** Add an iperf session to the 'active' list */ +static void +lwiperf_list_add(lwiperf_state_base_t *item) +{ + item->next = lwiperf_all_connections; + lwiperf_all_connections = item; +} + +/** Remove an iperf session from the 'active' list */ +static void +lwiperf_list_remove(lwiperf_state_base_t *item) +{ + lwiperf_state_base_t *prev = NULL; + lwiperf_state_base_t *iter; + for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) { + if (iter == item) { + if (prev == NULL) { + lwiperf_all_connections = iter->next; + } else { + prev->next = iter->next; + } + /* @debug: ensure this item is listed only once */ + for (iter = iter->next; iter != NULL; iter = iter->next) { + LWIP_ASSERT("duplicate entry", iter != item); + } + break; + } + } +} + +static lwiperf_state_base_t * +lwiperf_list_find(lwiperf_state_base_t *item) +{ + lwiperf_state_base_t *iter; + for (iter = lwiperf_all_connections; iter != NULL; iter = iter->next) { + if (iter == item) { + return item; + } + } + return NULL; +} + +/** Call the report function of an iperf tcp session */ +static void +lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type) +{ + if ((conn != NULL) && (conn->report_fn != NULL)) { + u32_t now, duration_ms, bandwidth_kbitpsec; + now = sys_now(); + duration_ms = now - conn->time_started; + if (duration_ms == 0) { + bandwidth_kbitpsec = 0; + } else { + bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U; + } + conn->report_fn(conn->report_arg, report_type, + &conn->conn_pcb->local_ip, conn->conn_pcb->local_port, + &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port, + conn->bytes_transferred, duration_ms, bandwidth_kbitpsec); + } +} + +/** Close an iperf tcp session */ +static void +lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type) +{ + err_t err; + + lwiperf_list_remove(&conn->base); + lwip_tcp_conn_report(conn, report_type); + if (conn->conn_pcb != NULL) { + tcp_arg(conn->conn_pcb, NULL); + tcp_poll(conn->conn_pcb, NULL, 0); + tcp_sent(conn->conn_pcb, NULL); + tcp_recv(conn->conn_pcb, NULL); + tcp_err(conn->conn_pcb, NULL); + err = tcp_close(conn->conn_pcb); + if (err != ERR_OK) { + /* don't want to wait for free memory here... */ + tcp_abort(conn->conn_pcb); + } + } else { + /* no conn pcb, this is the listener pcb */ + err = tcp_close(conn->server_pcb); + LWIP_ASSERT("error", err == ERR_OK); + } + LWIPERF_FREE(lwiperf_state_tcp_t, conn); +} + +/** Try to send more data on an iperf tcp session */ +static err_t +lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn) +{ + int send_more; + err_t err; + u16_t txlen; + u16_t txlen_max; + void *txptr; + u8_t apiflags; + + LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0)); + + do { + send_more = 0; + if (conn->settings.amount & PP_HTONL(0x80000000)) { + /* this session is time-limited */ + u32_t now = sys_now(); + u32_t diff_ms = now - conn->time_started; + u32_t time = (u32_t) - (s32_t)lwip_htonl(conn->settings.amount); + u32_t time_ms = time * 10; + if (diff_ms >= time_ms) { + /* time specified by the client is over -> close the connection */ + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); + return ERR_OK; + } + } else { + /* this session is byte-limited */ + u32_t amount_bytes = lwip_htonl(conn->settings.amount); + /* @todo: this can send up to 1*MSS more than requested... */ + if (amount_bytes >= conn->bytes_transferred) { + /* all requested bytes transferred -> close the connection */ + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); + return ERR_OK; + } + } + + if (conn->bytes_transferred < 24) { + /* transmit the settings a first time */ + txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred]; + txlen_max = (u16_t)(24 - conn->bytes_transferred); + apiflags = TCP_WRITE_FLAG_COPY; + } else if (conn->bytes_transferred < 48) { + /* transmit the settings a second time */ + txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred - 24]; + txlen_max = (u16_t)(48 - conn->bytes_transferred); + apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE; + send_more = 1; + } else { + /* transmit data */ + /* @todo: every x bytes, transmit the settings again */ + txptr = LWIP_CONST_CAST(void *, &lwiperf_txbuf_const[conn->bytes_transferred % 10]); + txlen_max = TCP_MSS; + if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */ + txlen_max = TCP_MSS - 24; + } + apiflags = 0; /* no copying needed */ + send_more = 1; + } + txlen = txlen_max; + do { + err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags); + if (err == ERR_MEM) { + txlen /= 2; + } + } while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2))); + + if (err == ERR_OK) { + conn->bytes_transferred += txlen; + } else { + send_more = 0; + } + } while (send_more); + + tcp_output(conn->conn_pcb); + return ERR_OK; +} + +/** TCP sent callback, try to send more data */ +static err_t +lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; + /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */ + LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + LWIP_UNUSED_ARG(len); + + conn->poll_count = 0; + + return lwiperf_tcp_client_send_more(conn); +} + +/** TCP connected callback (active connection), send data now */ +static err_t +lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; + LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + if (err != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); + return ERR_OK; + } + conn->poll_count = 0; + conn->time_started = sys_now(); + return lwiperf_tcp_client_send_more(conn); +} + +/** Start TCP connection back to the client (either parallel or after the + * receive test has finished. + */ +static err_t +lwiperf_tx_start_impl(const ip_addr_t *remote_ip, u16_t remote_port, lwiperf_settings_t *settings, lwiperf_report_fn report_fn, + void *report_arg, lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **new_conn) +{ + err_t err; + lwiperf_state_tcp_t *client_conn; + struct tcp_pcb *newpcb; + ip_addr_t remote_addr; + + LWIP_ASSERT("remote_ip != NULL", remote_ip != NULL); + LWIP_ASSERT("remote_ip != NULL", settings != NULL); + LWIP_ASSERT("new_conn != NULL", new_conn != NULL); + *new_conn = NULL; + + client_conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (client_conn == NULL) { + return ERR_MEM; + } + newpcb = tcp_new_ip_type(IP_GET_TYPE(remote_ip)); + if (newpcb == NULL) { + LWIPERF_FREE(lwiperf_state_tcp_t, client_conn); + return ERR_MEM; + } + memset(client_conn, 0, sizeof(lwiperf_state_tcp_t)); + client_conn->base.tcp = 1; + client_conn->base.related_master_state = related_master_state; + client_conn->conn_pcb = newpcb; + client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */ + client_conn->report_fn = report_fn; + client_conn->report_arg = report_arg; + client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */ + client_conn->bytes_transferred = 0; + memcpy(&client_conn->settings, settings, sizeof(*settings)); + client_conn->have_settings_buf = 1; + + tcp_arg(newpcb, client_conn); + tcp_sent(newpcb, lwiperf_tcp_client_sent); + tcp_poll(newpcb, lwiperf_tcp_poll, 2U); + tcp_err(newpcb, lwiperf_tcp_err); + + ip_addr_copy(remote_addr, *remote_ip); + + err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected); + if (err != ERR_OK) { + lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL); + return err; + } + lwiperf_list_add(&client_conn->base); + *new_conn = client_conn; + return ERR_OK; +} + +static err_t +lwiperf_tx_start_passive(lwiperf_state_tcp_t *conn) +{ + err_t ret; + lwiperf_state_tcp_t *new_conn = NULL; + u16_t remote_port = (u16_t)lwip_htonl(conn->settings.remote_port); + + ret = lwiperf_tx_start_impl(&conn->conn_pcb->remote_ip, remote_port, &conn->settings, conn->report_fn, conn->report_arg, + conn->base.related_master_state, &new_conn); + if (ret == ERR_OK) { + LWIP_ASSERT("new_conn != NULL", new_conn != NULL); + new_conn->settings.flags = 0; /* prevent the remote side starting back as client again */ + } + return ret; +} + +/** Receive data on an iperf tcp session */ +static err_t +lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + u8_t tmp; + u16_t tot_len; + u32_t packet_idx; + struct pbuf *q; + lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; + + LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + + if (err != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); + return ERR_OK; + } + if (p == NULL) { + /* connection closed -> test done */ + if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { + if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) == 0) { + /* client requested transmission after end of test */ + lwiperf_tx_start_passive(conn); + } + } + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); + return ERR_OK; + } + tot_len = p->tot_len; + + conn->poll_count = 0; + + if ((!conn->have_settings_buf) || ((conn->bytes_transferred - 24) % (1024 * 128) == 0)) { + /* wait for 24-byte header */ + if (p->tot_len < sizeof(lwiperf_settings_t)) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_OK; + } + if (!conn->have_settings_buf) { + if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); + pbuf_free(p); + return ERR_OK; + } + conn->have_settings_buf = 1; + if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { + if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) { + /* client requested parallel transmission test */ + err_t err2 = lwiperf_tx_start_passive(conn); + if (err2 != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); + pbuf_free(p); + return ERR_OK; + } + } + } + } else { + if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { + if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_OK; + } + } + } + conn->bytes_transferred += sizeof(lwiperf_settings_t); + if (conn->bytes_transferred <= 24) { + conn->time_started = sys_now(); + tcp_recved(tpcb, p->tot_len); + pbuf_free(p); + return ERR_OK; + } + conn->next_num = 4; /* 24 bytes received... */ + tmp = pbuf_remove_header(p, 24); + LWIP_ASSERT("pbuf_remove_header failed", tmp == 0); + LWIP_UNUSED_ARG(tmp); /* for LWIP_NOASSERT */ + } + + packet_idx = 0; + for (q = p; q != NULL; q = q->next) { +#if LWIPERF_CHECK_RX_DATA + const u8_t *payload = (const u8_t *)q->payload; + u16_t i; + for (i = 0; i < q->len; i++) { + u8_t val = payload[i]; + u8_t num = val - '0'; + if (num == conn->next_num) { + conn->next_num++; + if (conn->next_num == 10) { + conn->next_num = 0; + } + } else { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_OK; + } + } +#endif + packet_idx += q->len; + } + LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); + conn->bytes_transferred += packet_idx; + tcp_recved(tpcb, tot_len); + pbuf_free(p); + return ERR_OK; +} + +/** Error callback, iperf tcp session aborted */ +static void +lwiperf_tcp_err(void *arg, err_t err) +{ + lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; + LWIP_UNUSED_ARG(err); + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); +} + +/** TCP poll callback, try to send more data */ +static err_t +lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb) +{ + lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg; + LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); + return ERR_OK; /* lwiperf_tcp_close frees conn */ + } + + if (!conn->base.server) { + lwiperf_tcp_client_send_more(conn); + } + + return ERR_OK; +} + +/** This is called when a new client connects for an iperf tcp session */ +static err_t +lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + lwiperf_state_tcp_t *s, *conn; + if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { + return ERR_VAL; + } + + s = (lwiperf_state_tcp_t *)arg; + LWIP_ASSERT("invalid session", s->base.server); + LWIP_ASSERT("invalid listen pcb", s->server_pcb != NULL); + LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL); + if (s->specific_remote) { + LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL); + if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) { + /* this listener belongs to a client session, and this is not the correct remote */ + return ERR_VAL; + } + } else { + LWIP_ASSERT("s->base.related_master_state == NULL", s->base.related_master_state == NULL); + } + + conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (conn == NULL) { + return ERR_MEM; + } + memset(conn, 0, sizeof(lwiperf_state_tcp_t)); + conn->base.tcp = 1; + conn->base.server = 1; + conn->base.related_master_state = &s->base; + conn->conn_pcb = newpcb; + conn->time_started = sys_now(); + conn->report_fn = s->report_fn; + conn->report_arg = s->report_arg; + + /* setup the tcp rx connection */ + tcp_arg(newpcb, conn); + tcp_recv(newpcb, lwiperf_tcp_recv); + tcp_poll(newpcb, lwiperf_tcp_poll, 2U); + tcp_err(conn->conn_pcb, lwiperf_tcp_err); + + if (s->specific_remote) { + /* this listener belongs to a client, so make the client the master of the newly created connection */ + conn->base.related_master_state = s->base.related_master_state; + /* if dual mode or (tradeoff mode AND client is done): close the listener */ + if (!s->client_tradeoff_mode || !lwiperf_list_find(s->base.related_master_state)) { + /* prevent report when closing: this is expected */ + s->report_fn = NULL; + lwiperf_tcp_close(s, LWIPERF_TCP_ABORTED_LOCAL); + } + } + lwiperf_list_add(&conn->base); + return ERR_OK; +} + +/** + * @ingroup iperf + * Start a TCP iperf server on the default TCP port (5001) and listen for + * incoming connections from iperf clients. + * + * @returns a connection handle that can be used to abort the server + * by calling @ref lwiperf_abort() + */ +void * +lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg) +{ + return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT, + report_fn, report_arg); +} + +/** + * @ingroup iperf + * Start a TCP iperf server on a specific IP address and port and listen for + * incoming connections from iperf clients. + * + * @returns a connection handle that can be used to abort the server + * by calling @ref lwiperf_abort() + */ +void * +lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void *report_arg) +{ + err_t err; + lwiperf_state_tcp_t *state = NULL; + + err = lwiperf_start_tcp_server_impl(local_addr, local_port, report_fn, report_arg, + NULL, &state); + if (err == ERR_OK) { + return state; + } + return NULL; +} + +static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void *report_arg, + lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state) +{ + err_t err; + struct tcp_pcb *pcb; + lwiperf_state_tcp_t *s; + + LWIP_ASSERT_CORE_LOCKED(); + + LWIP_ASSERT("state != NULL", state != NULL); + + if (local_addr == NULL) { + return ERR_ARG; + } + + s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (s == NULL) { + return ERR_MEM; + } + memset(s, 0, sizeof(lwiperf_state_tcp_t)); + s->base.tcp = 1; + s->base.server = 1; + s->base.related_master_state = related_master_state; + s->report_fn = report_fn; + s->report_arg = report_arg; + + pcb = tcp_new_ip_type(LWIPERF_SERVER_IP_TYPE); + if (pcb == NULL) { + return ERR_MEM; + } + err = tcp_bind(pcb, local_addr, local_port); + if (err != ERR_OK) { + return err; + } + s->server_pcb = tcp_listen_with_backlog(pcb, 1); + if (s->server_pcb == NULL) { + if (pcb != NULL) { + tcp_close(pcb); + } + LWIPERF_FREE(lwiperf_state_tcp_t, s); + return ERR_MEM; + } + pcb = NULL; + + tcp_arg(s->server_pcb, s); + tcp_accept(s->server_pcb, lwiperf_tcp_accept); + + lwiperf_list_add(&s->base); + *state = s; + return ERR_OK; +} + +/** + * @ingroup iperf + * Start a TCP iperf client to the default TCP port (5001). + * + * @returns a connection handle that can be used to abort the client + * by calling @ref lwiperf_abort() + */ +void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr, + lwiperf_report_fn report_fn, void* report_arg) +{ + return lwiperf_start_tcp_client(remote_addr, LWIPERF_TCP_PORT_DEFAULT, LWIPERF_CLIENT, + report_fn, report_arg); +} + +/** + * @ingroup iperf + * Start a TCP iperf client to a specific IP address and port. + * + * @returns a connection handle that can be used to abort the client + * by calling @ref lwiperf_abort() + */ +void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port, + enum lwiperf_client_type type, lwiperf_report_fn report_fn, void* report_arg) +{ + err_t ret; + lwiperf_settings_t settings; + lwiperf_state_tcp_t *state = NULL; + + memset(&settings, 0, sizeof(settings)); + switch (type) { + case LWIPERF_CLIENT: + /* Unidirectional tx only test */ + settings.flags = 0; + break; + case LWIPERF_DUAL: + /* Do a bidirectional test simultaneously */ + settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW); + break; + case LWIPERF_TRADEOFF: + /* Do a bidirectional test individually */ + settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST); + break; + default: + /* invalid argument */ + return NULL; + } + settings.num_threads = htonl(1); + settings.remote_port = htonl(LWIPERF_TCP_PORT_DEFAULT); + /* TODO: implement passing duration/amount of bytes to transfer */ + settings.amount = htonl((u32_t)-1000); + + ret = lwiperf_tx_start_impl(remote_addr, remote_port, &settings, report_fn, report_arg, NULL, &state); + if (ret == ERR_OK) { + LWIP_ASSERT("state != NULL", state != NULL); + if (type != LWIPERF_CLIENT) { + /* start corresponding server now */ + lwiperf_state_tcp_t *server = NULL; + ret = lwiperf_start_tcp_server_impl(&state->conn_pcb->local_ip, LWIPERF_TCP_PORT_DEFAULT, + report_fn, report_arg, (lwiperf_state_base_t *)state, &server); + if (ret != ERR_OK) { + /* starting server failed, abort client */ + lwiperf_abort(state); + return NULL; + } + /* make this server accept one connection only */ + server->specific_remote = 1; + server->remote_addr = state->conn_pcb->remote_ip; + if (type == LWIPERF_TRADEOFF) { + /* tradeoff means that the remote host connects only after the client is done, + so keep the listen pcb open until the client is done */ + server->client_tradeoff_mode = 1; + } + } + return state; + } + return NULL; +} + +/** + * @ingroup iperf + * Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) + */ +void +lwiperf_abort(void *lwiperf_session) +{ + lwiperf_state_base_t *i, *dealloc, *last = NULL; + + LWIP_ASSERT_CORE_LOCKED(); + + for (i = lwiperf_all_connections; i != NULL; ) { + if ((i == lwiperf_session) || (i->related_master_state == lwiperf_session)) { + dealloc = i; + i = i->next; + if (last != NULL) { + last->next = i; + } + LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */ + } else { + last = i; + i = i->next; + } + } +} + +#endif /* LWIP_TCP && LWIP_CALLBACK_API */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.h new file mode 100644 index 0000000..cc86e7f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/lwiperf.h @@ -0,0 +1,100 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_LWIPERF_H +#define LWIP_HDR_APPS_LWIPERF_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIPERF_TCP_PORT_DEFAULT 5001 + +/** lwIPerf test results */ +enum lwiperf_report_type +{ + /** The server side test is done */ + LWIPERF_TCP_DONE_SERVER, + /** The client side test is done */ + LWIPERF_TCP_DONE_CLIENT, + /** Local error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL, + /** Data check error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, + /** Transmit error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_TXERROR, + /** Remote side aborted the test */ + LWIPERF_TCP_ABORTED_REMOTE +}; + +/** Control */ +enum lwiperf_client_type +{ + /** Unidirectional tx only test */ + LWIPERF_CLIENT, + /** Do a bidirectional test simultaneously */ + LWIPERF_DUAL, + /** Do a bidirectional test individually */ + LWIPERF_TRADEOFF +}; + +/** Prototype of a report function that is called when a session is finished. + This report function can show the test results. + @param report_type contains the test result */ +typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, + const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, + u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); + +void* lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port, + enum lwiperf_client_type type, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr, + lwiperf_report_fn report_fn, void* report_arg); + +void lwiperf_abort(void* lwiperf_session); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/FILES b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/FILES new file mode 100644 index 0000000..1ffd6f2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/FILES @@ -0,0 +1,23 @@ +This directory contains generic network interface device drivers that +do not contain any hardware or architecture specific code. The files +are: + +ethernet.c + Shared code for Ethernet based interfaces. + +lowpan6.c + A 6LoWPAN implementation as a netif. + +lowpan6_ble.c + A 6LoWPAN over Bluetooth Low Energy (BLE) implementation as netif, + according to RFC-7668. + +slipif.c + A generic implementation of the SLIP (Serial Line IP) + protocol. It requires a sio (serial I/O) module to work. + +ppp/ Point-to-Point Protocol stack + The lwIP PPP support is based from pppd (http://ppp.samba.org) with + huge changes to match code size and memory requirements for embedded + devices. Please read /doc/ppp.txt and ppp/PPPD_FOLLOWUP for a detailed + explanation. diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif.c new file mode 100644 index 0000000..8a97bce --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif.c @@ -0,0 +1,563 @@ +/** + * @file + * lwIP netif implementing an IEEE 802.1D MAC Bridge + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +/** + * @defgroup bridgeif IEEE 802.1D bridge + * @ingroup netifs + * This file implements an IEEE 802.1D bridge by using a multilayer netif approach + * (one hardware-independent netif for the bridge that uses hardware netifs for its ports). + * On transmit, the bridge selects the outgoing port(s). + * On receive, the port netif calls into the bridge (via its netif->input function) and + * the bridge selects the port(s) (and/or its netif->input function) to pass the received pbuf to. + * + * Usage: + * - add the port netifs just like you would when using them as dedicated netif without a bridge + * - only NETIF_FLAG_ETHARP/NETIF_FLAG_ETHERNET netifs are supported as bridge ports + * - add the bridge port netifs without IPv4 addresses (i.e. pass 'NULL, NULL, NULL') + * - don't add IPv6 addresses to the port netifs! + * - set up the bridge configuration in a global variable of type 'bridgeif_initdata_t' that contains + * - the MAC address of the bridge + * - some configuration options controlling the memory consumption (maximum number of ports + * and FDB entries) + * - e.g. for a bridge MAC address 00-01-02-03-04-05, 2 bridge ports, 1024 FDB entries + 16 static MAC entries: + * bridgeif_initdata_t mybridge_initdata = BRIDGEIF_INITDATA1(2, 1024, 16, ETH_ADDR(0, 1, 2, 3, 4, 5)); + * - add the bridge netif (with IPv4 config): + * struct netif bridge_netif; + * netif_add(&bridge_netif, &my_ip, &my_netmask, &my_gw, &mybridge_initdata, bridgeif_init, tcpip_input); + * NOTE: the passed 'input' function depends on BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT setting, + * which controls where the forwarding is done (netif low level input context vs. tcpip_thread) + * - set up all ports netifs and the bridge netif + * + * - When adding a port netif, NETIF_FLAG_ETHARP flag will be removed from a port + * to prevent ETHARP working on that port netif (we only want one IP per bridge not per port). + * - When adding a port netif, its input function is changed to call into the bridge. + * + * + * @todo: + * - compact static FDB entries (instead of walking the whole array) + * - add FDB query/read access + * - add FDB change callback (when learning or dropping auto-learned entries) + * - prefill FDB with MAC classes that should never be forwarded + * - multicast snooping? (and only forward group addresses to interested ports) + * - support removing ports + * - check SNMP integration + * - VLAN handling / trunk ports + * - priority handling? (although that largely depends on TX queue limitations and lwIP doesn't provide tx-done handling) + */ + +#include "netif/bridgeif.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/etharp.h" +#include "lwip/ethip6.h" +#include "lwip/snmp.h" +#include "lwip/timeouts.h" +#include + +#if LWIP_NUM_NETIF_CLIENT_DATA + +/* Define those to better describe your network interface. */ +#define IFNAME0 'b' +#define IFNAME1 'r' + +struct bridgeif_private_s; +typedef struct bridgeif_port_private_s { + struct bridgeif_private_s *bridge; + struct netif *port_netif; + u8_t port_num; +} bridgeif_port_t; + +typedef struct bridgeif_fdb_static_entry_s { + u8_t used; + bridgeif_portmask_t dst_ports; + struct eth_addr addr; +} bridgeif_fdb_static_entry_t; + +typedef struct bridgeif_private_s { + struct netif *netif; + struct eth_addr ethaddr; + u8_t max_ports; + u8_t num_ports; + bridgeif_port_t *ports; + u16_t max_fdbs_entries; + bridgeif_fdb_static_entry_t *fdbs; + u16_t max_fdbd_entries; + void *fdbd; +} bridgeif_private_t; + +/* netif data index to get the bridge on input */ +u8_t bridgeif_netif_client_id = 0xff; + +/** + * @ingroup bridgeif + * Add a static entry to the forwarding database. + * A static entry marks where frames to a specific eth address (unicast or group address) are + * forwarded. + * bits [0..(BRIDGEIF_MAX_PORTS-1)]: hw ports + * bit [BRIDGEIF_MAX_PORTS]: cpu port + * 0: drop + */ +err_t +bridgeif_fdb_add(struct netif *bridgeif, const struct eth_addr *addr, bridgeif_portmask_t ports) +{ + int i; + bridgeif_private_t *br; + BRIDGEIF_DECL_PROTECT(lev); + LWIP_ASSERT("invalid netif", bridgeif != NULL); + br = (bridgeif_private_t *)bridgeif->state; + LWIP_ASSERT("invalid state", br != NULL); + + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < br->max_fdbs_entries; i++) { + if (!br->fdbs[i].used) { + BRIDGEIF_WRITE_PROTECT(lev); + if (!br->fdbs[i].used) { + br->fdbs[i].used = 1; + br->fdbs[i].dst_ports = ports; + memcpy(&br->fdbs[i].addr, addr, sizeof(struct eth_addr)); + BRIDGEIF_WRITE_UNPROTECT(lev); + BRIDGEIF_READ_UNPROTECT(lev); + return ERR_OK; + } + BRIDGEIF_WRITE_UNPROTECT(lev); + } + } + BRIDGEIF_READ_UNPROTECT(lev); + return ERR_MEM; +} + +/** + * @ingroup bridgeif + * Remove a static entry from the forwarding database + */ +err_t +bridgeif_fdb_remove(struct netif *bridgeif, const struct eth_addr *addr) +{ + int i; + bridgeif_private_t *br; + BRIDGEIF_DECL_PROTECT(lev); + LWIP_ASSERT("invalid netif", bridgeif != NULL); + br = (bridgeif_private_t *)bridgeif->state; + LWIP_ASSERT("invalid state", br != NULL); + + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < br->max_fdbs_entries; i++) { + if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { + BRIDGEIF_WRITE_PROTECT(lev); + if (br->fdbs[i].used && !memcmp(&br->fdbs[i].addr, addr, sizeof(struct eth_addr))) { + memset(&br->fdbs[i], 0, sizeof(bridgeif_fdb_static_entry_t)); + BRIDGEIF_WRITE_UNPROTECT(lev); + BRIDGEIF_READ_UNPROTECT(lev); + return ERR_OK; + } + BRIDGEIF_WRITE_UNPROTECT(lev); + } + } + BRIDGEIF_READ_UNPROTECT(lev); + return ERR_VAL; +} + +/** Get the forwarding port(s) (as bit mask) for the specified destination mac address */ +static bridgeif_portmask_t +bridgeif_find_dst_ports(bridgeif_private_t *br, struct eth_addr *dst_addr) +{ + int i; + BRIDGEIF_DECL_PROTECT(lev); + BRIDGEIF_READ_PROTECT(lev); + /* first check for static entries */ + for (i = 0; i < br->max_fdbs_entries; i++) { + if (br->fdbs[i].used) { + if (!memcmp(&br->fdbs[i].addr, dst_addr, sizeof(struct eth_addr))) { + bridgeif_portmask_t ret = br->fdbs[i].dst_ports; + BRIDGEIF_READ_UNPROTECT(lev); + return ret; + } + } + } + if (dst_addr->addr[0] & 1) { + /* no match found: flood remaining group address */ + BRIDGEIF_READ_UNPROTECT(lev); + return BR_FLOOD; + } + BRIDGEIF_READ_UNPROTECT(lev); + /* no match found: check dynamic fdb for port or fall back to flooding */ + return bridgeif_fdb_get_dst_ports(br->fdbd, dst_addr); +} + +/** Helper function to see if a destination mac belongs to the bridge + * (bridge netif or one of the port netifs), in which case the frame + * is sent to the cpu only. + */ +static int +bridgeif_is_local_mac(bridgeif_private_t *br, struct eth_addr *addr) +{ + int i; + BRIDGEIF_DECL_PROTECT(lev); + if (!memcmp(br->netif->hwaddr, addr, sizeof(struct eth_addr))) { + return 1; + } + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < br->num_ports; i++) { + struct netif *portif = br->ports[i].port_netif; + if (portif != NULL) { + if (!memcmp(portif->hwaddr, addr, sizeof(struct eth_addr))) { + BRIDGEIF_READ_UNPROTECT(lev); + return 1; + } + } + } + BRIDGEIF_READ_UNPROTECT(lev); + return 0; +} + +/* Output helper function */ +static err_t +bridgeif_send_to_port(bridgeif_private_t *br, struct pbuf *p, u8_t dstport_idx) +{ + if (dstport_idx < BRIDGEIF_MAX_PORTS) { + /* possibly an external port */ + if (dstport_idx < br->max_ports) { + struct netif *portif = br->ports[dstport_idx].port_netif; + if ((portif != NULL) && (portif->linkoutput != NULL)) { + /* prevent sending out to rx port */ + if (netif_get_index(portif) != p->if_idx) { + if (netif_is_link_up(portif)) { + LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> flood(%p:%d) -> %d\n", (void *)p, p->if_idx, netif_get_index(portif))); + return portif->linkoutput(portif, p); + } + } + } + } + } else { + LWIP_ASSERT("invalid port index", dstport_idx == BRIDGEIF_MAX_PORTS); + } + return ERR_OK; +} + +/** Helper function to pass a pbuf to all ports marked in 'dstports' + */ +static err_t +bridgeif_send_to_ports(bridgeif_private_t *br, struct pbuf *p, bridgeif_portmask_t dstports) +{ + err_t err, ret_err = ERR_OK; + u8_t i; + bridgeif_portmask_t mask = 1; + BRIDGEIF_DECL_PROTECT(lev); + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < BRIDGEIF_MAX_PORTS; i++, mask = (bridgeif_portmask_t)(mask << 1)) { + if (dstports & mask) { + err = bridgeif_send_to_port(br, p, i); + if (err != ERR_OK) { + ret_err = err; + } + } + } + BRIDGEIF_READ_UNPROTECT(lev); + return ret_err; +} + +/** Output function of the application port of the bridge (the one with an ip address). + * The forwarding port(s) where this pbuf is sent on is/are automatically selected + * from the FDB. + */ +static err_t +bridgeif_output(struct netif *netif, struct pbuf *p) +{ + err_t err; + bridgeif_private_t *br = (bridgeif_private_t *)netif->state; + struct eth_addr *dst = (struct eth_addr *)(p->payload); + + bridgeif_portmask_t dstports = bridgeif_find_dst_ports(br, dst); + err = bridgeif_send_to_ports(br, p, dstports); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } else { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + /* increase ifoutdiscards or ifouterrors on error */ + + LINK_STATS_INC(link.xmit); + + return err; +} + +/** The actual bridge input function. Port netif's input is changed to call + * here. This function decides where the frame is forwarded. + */ +static err_t +bridgeif_input(struct pbuf *p, struct netif *netif) +{ + u8_t rx_idx; + bridgeif_portmask_t dstports; + struct eth_addr *src, *dst; + bridgeif_private_t *br; + bridgeif_port_t *port; + if (p == NULL || netif == NULL) { + return ERR_VAL; + } + port = (bridgeif_port_t *)netif_get_client_data(netif, bridgeif_netif_client_id); + LWIP_ASSERT("port data not set", port != NULL); + if (port == NULL || port->bridge == NULL) { + return ERR_VAL; + } + br = (bridgeif_private_t *)port->bridge; + rx_idx = netif_get_index(netif); + /* store receive index in pbuf */ + p->if_idx = rx_idx; + + dst = (struct eth_addr *)p->payload; + src = (struct eth_addr *)(((u8_t *)p->payload) + sizeof(struct eth_addr)); + + if ((src->addr[0] & 1) == 0) { + /* update src for all non-group addresses */ + bridgeif_fdb_update_src(br->fdbd, src, port->port_num); + } + + if (dst->addr[0] & 1) { + /* group address -> flood + cpu? */ + dstports = bridgeif_find_dst_ports(br, dst); + bridgeif_send_to_ports(br, p, dstports); + if (dstports & (1 << BRIDGEIF_MAX_PORTS)) { + /* we pass the reference to ->input or have to free it */ + LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); + if (br->netif->input(p, br->netif) != ERR_OK) { + pbuf_free(p); + } + } else { + /* all references done */ + pbuf_free(p); + } + /* always return ERR_OK here to prevent the caller freeing the pbuf */ + return ERR_OK; + } else { + /* is this for one of the local ports? */ + if (bridgeif_is_local_mac(br, dst)) { + /* yes, send to cpu port only */ + LWIP_DEBUGF(BRIDGEIF_FW_DEBUG, ("br -> input(%p)\n", (void *)p)); + return br->netif->input(p, br->netif); + } + + /* get dst port */ + dstports = bridgeif_find_dst_ports(br, dst); + bridgeif_send_to_ports(br, p, dstports); + /* no need to send to cpu, flooding is for external ports only */ + /* by this, we consumed the pbuf */ + pbuf_free(p); + /* always return ERR_OK here to prevent the caller freeing the pbuf */ + return ERR_OK; + } +} + +#if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT +/** Input function for port netifs used to synchronize into tcpip_thread. + */ +static err_t +bridgeif_tcpip_input(struct pbuf *p, struct netif *netif) +{ + return tcpip_inpkt(p, netif, bridgeif_input); +} +#endif /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ + +/** + * @ingroup bridgeif + * Initialization function passed to netif_add(). + * + * ATTENTION: A pointer to a @ref bridgeif_initdata_t must be passed as 'state' + * to @ref netif_add when adding the bridge. I supplies MAC address + * and controls memory allocation (number of ports, FDB size). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t +bridgeif_init(struct netif *netif) +{ + bridgeif_initdata_t *init_data; + bridgeif_private_t *br; + size_t alloc_len_sizet; + mem_size_t alloc_len; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("bridgeif needs an input callback", (netif->input != NULL)); +#if !BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT + if (netif->input == tcpip_input) { + LWIP_DEBUGF(BRIDGEIF_DEBUG | LWIP_DBG_ON, ("bridgeif does not need tcpip_input, use netif_input/ethernet_input instead")); + } +#endif + + if (bridgeif_netif_client_id == 0xFF) { + bridgeif_netif_client_id = netif_alloc_client_data_id(); + } + + init_data = (bridgeif_initdata_t *)netif->state; + LWIP_ASSERT("init_data != NULL", (init_data != NULL)); + LWIP_ASSERT("init_data->max_ports <= BRIDGEIF_MAX_PORTS", + init_data->max_ports <= BRIDGEIF_MAX_PORTS); + + alloc_len_sizet = sizeof(bridgeif_private_t) + (init_data->max_ports * sizeof(bridgeif_port_t) + (init_data->max_fdb_static_entries * sizeof(bridgeif_fdb_static_entry_t))); + alloc_len = (mem_size_t)alloc_len_sizet; + LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet); + LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_init: allocating %d bytes for private data\n", (int)alloc_len)); + br = (bridgeif_private_t *)mem_calloc(1, alloc_len); + if (br == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory\n")); + return ERR_MEM; + } + memcpy(&br->ethaddr, &init_data->ethaddr, sizeof(br->ethaddr)); + br->netif = netif; + + br->max_ports = init_data->max_ports; + br->ports = (bridgeif_port_t *)(br + 1); + + br->max_fdbs_entries = init_data->max_fdb_static_entries; + br->fdbs = (bridgeif_fdb_static_entry_t *)(((u8_t *)(br + 1)) + (init_data->max_ports * sizeof(bridgeif_port_t))); + + br->max_fdbd_entries = init_data->max_fdb_dynamic_entries; + br->fdbd = bridgeif_fdb_init(init_data->max_fdb_dynamic_entries); + if (br->fdbd == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("bridgeif_init: out of memory in fdb_init\n")); + mem_free(br); + return ERR_MEM; + } + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 0); + + netif->state = br; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = bridgeif_output; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETH_HWADDR_LEN; + + /* set MAC hardware address */ + memcpy(netif->hwaddr, &br->ethaddr, ETH_HWADDR_LEN); + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_LINK_UP; + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + return ERR_OK; +} + +/** + * @ingroup bridgeif + * Add a port to the bridge + */ +err_t +bridgeif_add_port(struct netif *bridgeif, struct netif *portif) +{ + bridgeif_private_t *br; + bridgeif_port_t *port; + + LWIP_ASSERT("bridgeif != NULL", bridgeif != NULL); + LWIP_ASSERT("bridgeif->state != NULL", bridgeif->state != NULL); + LWIP_ASSERT("portif != NULL", portif != NULL); + + if (!(portif->flags & NETIF_FLAG_ETHARP) || !(portif->flags & NETIF_FLAG_ETHERNET)) { + /* can only add ETHERNET/ETHARP interfaces */ + return ERR_VAL; + } + + br = (bridgeif_private_t *)bridgeif->state; + + if (br->num_ports >= br->max_ports) { + return ERR_VAL; + } + port = &br->ports[br->num_ports]; + port->port_netif = portif; + port->port_num = br->num_ports; + port->bridge = br; + br->num_ports++; + + /* let the port call us on input */ +#if BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT + portif->input = bridgeif_input; +#else + portif->input = bridgeif_tcpip_input; +#endif + /* store pointer to bridge in netif */ + netif_set_client_data(portif, bridgeif_netif_client_id, port); + /* remove ETHARP flag to prevent sending report events on netif-up */ + netif_clear_flags(portif, NETIF_FLAG_ETHARP); + + return ERR_OK; +} + +#endif /* LWIP_NUM_NETIF_CLIENT_DATA */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif_fdb.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif_fdb.c new file mode 100644 index 0000000..6739fc2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/bridgeif_fdb.c @@ -0,0 +1,212 @@ +/** + * @file + * lwIP netif implementing an FDB for IEEE 802.1D MAC Bridge + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +/** + * @defgroup bridgeif_fdb FDB example code + * @ingroup bridgeif + * This file implements an example for an FDB (Forwarding DataBase) + */ + +#include "netif/bridgeif.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/timeouts.h" +#include + +#define BRIDGEIF_AGE_TIMER_MS 1000 + +#define BR_FDB_TIMEOUT_SEC (60*5) /* 5 minutes FDB timeout */ + +typedef struct bridgeif_dfdb_entry_s { + u8_t used; + u8_t port; + u32_t ts; + struct eth_addr addr; +} bridgeif_dfdb_entry_t; + +typedef struct bridgeif_dfdb_s { + u16_t max_fdb_entries; + bridgeif_dfdb_entry_t *fdb; +} bridgeif_dfdb_t; + +/** + * @ingroup bridgeif_fdb + * A real simple and slow implementation of an auto-learning forwarding database that + * remembers known src mac addresses to know which port to send frames destined for that + * mac address. + * + * ATTENTION: This is meant as an example only, in real-world use, you should + * provide a better implementation :-) + */ +void +bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx) +{ + int i; + bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr; + BRIDGEIF_DECL_PROTECT(lev); + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < fdb->max_fdb_entries; i++) { + bridgeif_dfdb_entry_t *e = &fdb->fdb[i]; + if (e->used && e->ts) { + if (!memcmp(&e->addr, src_addr, sizeof(struct eth_addr))) { + LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: update src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n", + src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5], + port_idx, i)); + BRIDGEIF_WRITE_PROTECT(lev); + e->ts = BR_FDB_TIMEOUT_SEC; + e->port = port_idx; + BRIDGEIF_WRITE_UNPROTECT(lev); + BRIDGEIF_READ_UNPROTECT(lev); + return; + } + } + } + /* not found, allocate new entry from free */ + for (i = 0; i < fdb->max_fdb_entries; i++) { + bridgeif_dfdb_entry_t *e = &fdb->fdb[i]; + if (!e->used || !e->ts) { + BRIDGEIF_WRITE_PROTECT(lev); + /* check again when protected */ + if (!e->used || !e->ts) { + LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: create src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n", + src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5], + port_idx, i)); + memcpy(&e->addr, src_addr, sizeof(struct eth_addr)); + e->ts = BR_FDB_TIMEOUT_SEC; + e->port = port_idx; + e->used = 1; + BRIDGEIF_WRITE_UNPROTECT(lev); + BRIDGEIF_READ_UNPROTECT(lev); + return; + } + BRIDGEIF_WRITE_UNPROTECT(lev); + } + } + BRIDGEIF_READ_UNPROTECT(lev); + /* not found, no free entry -> flood */ +} + +/** + * @ingroup bridgeif_fdb + * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown + */ +bridgeif_portmask_t +bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr) +{ + int i; + bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr; + BRIDGEIF_DECL_PROTECT(lev); + BRIDGEIF_READ_PROTECT(lev); + for (i = 0; i < fdb->max_fdb_entries; i++) { + bridgeif_dfdb_entry_t *e = &fdb->fdb[i]; + if (e->used && e->ts) { + if (!memcmp(&e->addr, dst_addr, sizeof(struct eth_addr))) { + bridgeif_portmask_t ret = (bridgeif_portmask_t)(1 << e->port); + BRIDGEIF_READ_UNPROTECT(lev); + return ret; + } + } + } + BRIDGEIF_READ_UNPROTECT(lev); + return BR_FLOOD; +} + +/** + * @ingroup bridgeif_fdb + * Aging implementation of our simple fdb + */ +static void +bridgeif_fdb_age_one_second(void *fdb_ptr) +{ + int i; + bridgeif_dfdb_t *fdb; + BRIDGEIF_DECL_PROTECT(lev); + + fdb = (bridgeif_dfdb_t *)fdb_ptr; + BRIDGEIF_READ_PROTECT(lev); + + for (i = 0; i < fdb->max_fdb_entries; i++) { + bridgeif_dfdb_entry_t *e = &fdb->fdb[i]; + if (e->used && e->ts) { + BRIDGEIF_WRITE_PROTECT(lev); + /* check again when protected */ + if (e->used && e->ts) { + if (--e->ts == 0) { + e->used = 0; + } + } + BRIDGEIF_WRITE_UNPROTECT(lev); + } + } + BRIDGEIF_READ_UNPROTECT(lev); +} + +/** Timer callback for fdb aging, called once per second */ +static void +bridgeif_age_tmr(void *arg) +{ + bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)arg; + + LWIP_ASSERT("invalid arg", arg != NULL); + + bridgeif_fdb_age_one_second(fdb); + sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, arg); +} + +/** + * @ingroup bridgeif_fdb + * Init our simple fdb list + */ +void * +bridgeif_fdb_init(u16_t max_fdb_entries) +{ + bridgeif_dfdb_t *fdb; + size_t alloc_len_sizet = sizeof(bridgeif_dfdb_t) + (max_fdb_entries * sizeof(bridgeif_dfdb_entry_t)); + mem_size_t alloc_len = (mem_size_t)alloc_len_sizet; + LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet); + LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_fdb_init: allocating %d bytes for private FDB data\n", (int)alloc_len)); + fdb = (bridgeif_dfdb_t *)mem_calloc(1, alloc_len); + if (fdb == NULL) { + return NULL; + } + fdb->max_fdb_entries = max_fdb_entries; + fdb->fdb = (bridgeif_dfdb_entry_t *)(fdb + 1); + + sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, fdb); + + return fdb; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ethernet.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ethernet.c new file mode 100644 index 0000000..dd171e2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ethernet.c @@ -0,0 +1,321 @@ +/** + * @file + * Ethernet common functions + * + * @defgroup ethernet Ethernet + * @ingroup callbackstyle_api + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET + +#include "netif/ethernet.h" +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/etharp.h" +#include "lwip/ip.h" +#include "lwip/snmp.h" + +#include + +#include "netif/ppp/ppp_opts.h" +#if PPPOE_SUPPORT +#include "netif/ppp/pppoe.h" +#endif /* PPPOE_SUPPORT */ + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +const struct eth_addr ethbroadcast = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}}; + +/** + * @ingroup lwip_nosys + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access.\n + * Don't call directly, pass to netif_add() and call netif->input(). + * + * @param p the received packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + * + * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL + * @see ETHARP_SUPPORT_VLAN + * @see LWIP_HOOK_VLAN_CHECK + */ +err_t +ethernet_input(struct pbuf *p, struct netif *netif) +{ + struct eth_hdr *ethhdr; + u16_t type; +#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 + u16_t next_hdr_offset = SIZEOF_ETH_HDR; +#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ + + LWIP_ASSERT_CORE_LOCKED(); + + if (p->len <= SIZEOF_ETH_HDR) { + /* a packet with only an ethernet header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinerrors); + goto free_and_return; + } + + if (p->if_idx == NETIF_NO_INDEX) { + p->if_idx = netif_get_index(netif); + } + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = (struct eth_hdr *)p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", + (unsigned char)ethhdr->dest.addr[0], (unsigned char)ethhdr->dest.addr[1], (unsigned char)ethhdr->dest.addr[2], + (unsigned char)ethhdr->dest.addr[3], (unsigned char)ethhdr->dest.addr[4], (unsigned char)ethhdr->dest.addr[5], + (unsigned char)ethhdr->src.addr[0], (unsigned char)ethhdr->src.addr[1], (unsigned char)ethhdr->src.addr[2], + (unsigned char)ethhdr->src.addr[3], (unsigned char)ethhdr->src.addr[4], (unsigned char)ethhdr->src.addr[5], + lwip_htons(ethhdr->type))); + + type = ethhdr->type; +#if ETHARP_SUPPORT_VLAN + if (type == PP_HTONS(ETHTYPE_VLAN)) { + struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR); + next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; + if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { + /* a packet with only an ethernet/vlan header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinerrors); + goto free_and_return; + } +#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ +#ifdef LWIP_HOOK_VLAN_CHECK + if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { +#elif defined(ETHARP_VLAN_CHECK_FN) + if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { +#elif defined(ETHARP_VLAN_CHECK) + if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { +#endif + /* silently ignore this packet: not for our VLAN */ + pbuf_free(p); + return ERR_OK; + } +#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ + type = vlan->tpid; + } +#endif /* ETHARP_SUPPORT_VLAN */ + +#if LWIP_ARP_FILTER_NETIF + netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); +#endif /* LWIP_ARP_FILTER_NETIF*/ + + if (ethhdr->dest.addr[0] & 1) { + /* this might be a multicast or broadcast packet */ + if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { +#if LWIP_IPV4 + if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && + (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } +#endif /* LWIP_IPV4 */ + } +#if LWIP_IPV6 + else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && + (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } +#endif /* LWIP_IPV6 */ + else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { + /* mark the pbuf as link-layer broadcast */ + p->flags |= PBUF_FLAG_LLBCAST; + } + } + + switch (type) { +#if LWIP_IPV4 && LWIP_ARP + /* IP packet? */ + case PP_HTONS(ETHTYPE_IP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } + /* skip Ethernet header (min. size checked above) */ + if (pbuf_remove_header(p, next_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n", + p->tot_len, next_hdr_offset)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + goto free_and_return; + } else { + /* pass to IP layer */ + ip4_input(p, netif); + } + break; + + case PP_HTONS(ETHTYPE_ARP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } + /* skip Ethernet header (min. size checked above) */ + if (pbuf_remove_header(p, next_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n", + p->tot_len, next_hdr_offset)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + ETHARP_STATS_INC(etharp.lenerr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } else { + /* pass p to ARP module */ + etharp_input(p, netif); + } + break; +#endif /* LWIP_IPV4 && LWIP_ARP */ +#if PPPOE_SUPPORT + case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ + pppoe_disc_input(netif, p); + break; + + case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ + pppoe_data_input(netif, p); + break; +#endif /* PPPOE_SUPPORT */ + +#if LWIP_IPV6 + case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ + /* skip Ethernet header */ + if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n", + p->tot_len, next_hdr_offset)); + goto free_and_return; + } else { + /* pass to IPv6 layer */ + ip6_input(p, netif); + } + break; +#endif /* LWIP_IPV6 */ + + default: +#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL + if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { + break; + } +#endif + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); + goto free_and_return; + } + + /* This means the pbuf is freed or consumed, + so the caller doesn't have to free it again */ + return ERR_OK; + +free_and_return: + pbuf_free(p); + return ERR_OK; +} + +/** + * @ingroup ethernet + * Send an ethernet packet on the network using netif->linkoutput(). + * The ethernet header is filled in before sending. + * + * @see LWIP_HOOK_VLAN_SET + * + * @param netif the lwIP network interface on which to send the packet + * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. + * @param src the source MAC address to be copied into the ethernet header + * @param dst the destination MAC address to be copied into the ethernet header + * @param eth_type ethernet type (@ref lwip_ieee_eth_type) + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +err_t +ethernet_output(struct netif * netif, struct pbuf * p, + const struct eth_addr * src, const struct eth_addr * dst, + u16_t eth_type) { + struct eth_hdr *ethhdr; + u16_t eth_type_be = lwip_htons(eth_type); + +#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) + s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); + if (vlan_prio_vid >= 0) { + struct eth_vlan_hdr *vlanhdr; + + LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); + + if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { + goto pbuf_header_failed; + } + vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR); + vlanhdr->tpid = eth_type_be; + vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); + + eth_type_be = PP_HTONS(ETHTYPE_VLAN); + } else +#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ + { + if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) { + goto pbuf_header_failed; + } + } + + LWIP_ASSERT_CORE_LOCKED(); + + ethhdr = (struct eth_hdr *)p->payload; + ethhdr->type = eth_type_be; + SMEMCPY(ðhdr->dest, dst, ETH_HWADDR_LEN); + SMEMCPY(ðhdr->src, src, ETH_HWADDR_LEN); + + LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", + (netif->hwaddr_len == ETH_HWADDR_LEN)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_output: sending packet %p\n", (void *)p)); + + /* send the packet */ + return netif->linkoutput(netif, p); + +pbuf_header_failed: + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("ethernet_output: could not allocate room for header.\n")); + LINK_STATS_INC(link.lenerr); + return ERR_BUF; +} + +#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6.c new file mode 100644 index 0000000..5e6f009 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6.c @@ -0,0 +1,920 @@ +/** + * @file + * + * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + * + * This implementation aims to conform to IEEE 802.15.4(-2015), RFC 4944 and RFC 6282. + * @todo: RFC 6775. + */ + +/* + * Copyright (c) 2015 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/** + * @defgroup sixlowpan 6LoWPAN (RFC4944) + * @ingroup netifs + * 6LowPAN netif implementation + */ + +#include "netif/lowpan6.h" + +#if LWIP_IPV6 + +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" +#include "lwip/snmp.h" +#include "netif/ieee802154.h" + +#include + +#if LWIP_6LOWPAN_802154_HW_CRC +#define LWIP_6LOWPAN_DO_CALC_CRC(buf, len) 0 +#else +#define LWIP_6LOWPAN_DO_CALC_CRC(buf, len) LWIP_6LOWPAN_CALC_CRC(buf, len) +#endif + +/** This is a helper struct for reassembly of fragments + * (IEEE 802.15.4 limits to 127 bytes) + */ +struct lowpan6_reass_helper { + struct lowpan6_reass_helper *next_packet; + struct pbuf *reass; + struct pbuf *frags; + u8_t timer; + struct lowpan6_link_addr sender_addr; + u16_t datagram_size; + u16_t datagram_tag; +}; + +/** This struct keeps track of per-netif state */ +struct lowpan6_ieee802154_data { + /** fragment reassembly list */ + struct lowpan6_reass_helper *reass_list; +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + /** address context for compression */ + ip6_addr_t lowpan6_context[LWIP_6LOWPAN_NUM_CONTEXTS]; +#endif + /** Datagram Tag for fragmentation */ + u16_t tx_datagram_tag; + /** local PAN ID for IEEE 802.15.4 header */ + u16_t ieee_802154_pan_id; + /** Sequence Number for IEEE 802.15.4 transmission */ + u8_t tx_frame_seq_num; +}; + +/* Maximum frame size is 127 bytes minus CRC size */ +#define LOWPAN6_MAX_PAYLOAD (127 - 2) + +/** Currently, this state is global, since there's only one 6LoWPAN netif */ +static struct lowpan6_ieee802154_data lowpan6_data; + +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 +#define LWIP_6LOWPAN_CONTEXTS(netif) lowpan6_data.lowpan6_context +#else +#define LWIP_6LOWPAN_CONTEXTS(netif) NULL +#endif + +static const struct lowpan6_link_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS +static struct lowpan6_link_addr short_mac_addr = {2, {0, 0}}; +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +/* IEEE 802.15.4 specific functions: */ + +/** Write the IEEE 802.15.4 header that encapsulates the 6LoWPAN frame. + * Src and dst PAN IDs are filled with the ID set by @ref lowpan6_set_pan_id. + * + * Since the length is variable: + * @returns the header length + */ +static u8_t +lowpan6_write_iee802154_header(struct ieee_802154_hdr *hdr, const struct lowpan6_link_addr *src, + const struct lowpan6_link_addr *dst) +{ + u8_t ieee_header_len; + u8_t *buffer; + u8_t i; + u16_t fc; + + fc = IEEE_802154_FC_FT_DATA; /* send data packet (2003 frame version) */ + fc |= IEEE_802154_FC_PANID_COMPR; /* set PAN ID compression, for now src and dst PANs are equal */ + if (dst != &ieee_802154_broadcast) { + fc |= IEEE_802154_FC_ACK_REQ; /* data packet, no broadcast: ack required. */ + } + if (dst->addr_len == 2) { + fc |= IEEE_802154_FC_DST_ADDR_MODE_SHORT; + } else { + LWIP_ASSERT("invalid dst address length", dst->addr_len == 8); + fc |= IEEE_802154_FC_DST_ADDR_MODE_EXT; + } + if (src->addr_len == 2) { + fc |= IEEE_802154_FC_SRC_ADDR_MODE_SHORT; + } else { + LWIP_ASSERT("invalid src address length", src->addr_len == 8); + fc |= IEEE_802154_FC_SRC_ADDR_MODE_EXT; + } + hdr->frame_control = fc; + hdr->sequence_number = lowpan6_data.tx_frame_seq_num++; + hdr->destination_pan_id = lowpan6_data.ieee_802154_pan_id; /* pan id */ + + buffer = (u8_t *)hdr; + ieee_header_len = 5; + i = dst->addr_len; + /* reverse memcpy of dst addr */ + while (i-- > 0) { + buffer[ieee_header_len++] = dst->addr[i]; + } + /* Source PAN ID skipped due to PAN ID Compression */ + i = src->addr_len; + /* reverse memcpy of src addr */ + while (i-- > 0) { + buffer[ieee_header_len++] = src->addr[i]; + } + return ieee_header_len; +} + +/** Parse the IEEE 802.15.4 header from a pbuf. + * If successful, the header is hidden from the pbuf. + * + * PAN IDs and seuqence number are not checked + * + * @param p input pbuf, p->payload pointing at the IEEE 802.15.4 header + * @param src pointer to source address filled from the header + * @param dest pointer to destination address filled from the header + * @returns ERR_OK if successful + */ +static err_t +lowpan6_parse_iee802154_header(struct pbuf *p, struct lowpan6_link_addr *src, + struct lowpan6_link_addr *dest) +{ + u8_t *puc; + s8_t i; + u16_t frame_control, addr_mode; + u16_t datagram_offset; + + /* Parse IEEE 802.15.4 header */ + puc = (u8_t *)p->payload; + frame_control = puc[0] | (puc[1] << 8); + datagram_offset = 2; + if (frame_control & IEEE_802154_FC_SEQNO_SUPPR) { + if (IEEE_802154_FC_FRAME_VERSION_GET(frame_control) <= 1) { + /* sequence number suppressed, this is not valid for versions 0/1 */ + return ERR_VAL; + } + } else { + datagram_offset++; + } + datagram_offset += 2; /* Skip destination PAN ID */ + addr_mode = frame_control & IEEE_802154_FC_DST_ADDR_MODE_MASK; + if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_EXT) { + /* extended address (64 bit) */ + dest->addr_len = 8; + /* reverse memcpy: */ + for (i = 0; i < 8; i++) { + dest->addr[i] = puc[datagram_offset + 7 - i]; + } + datagram_offset += 8; + } else if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_SHORT) { + /* short address (16 bit) */ + dest->addr_len = 2; + /* reverse memcpy: */ + dest->addr[0] = puc[datagram_offset + 1]; + dest->addr[1] = puc[datagram_offset]; + datagram_offset += 2; + } else { + /* unsupported address mode (do we need "no address"?) */ + return ERR_VAL; + } + + if (!(frame_control & IEEE_802154_FC_PANID_COMPR)) { + /* No PAN ID compression, skip source PAN ID */ + datagram_offset += 2; + } + + addr_mode = frame_control & IEEE_802154_FC_SRC_ADDR_MODE_MASK; + if (addr_mode == IEEE_802154_FC_SRC_ADDR_MODE_EXT) { + /* extended address (64 bit) */ + src->addr_len = 8; + /* reverse memcpy: */ + for (i = 0; i < 8; i++) { + src->addr[i] = puc[datagram_offset + 7 - i]; + } + datagram_offset += 8; + } else if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_SHORT) { + /* short address (16 bit) */ + src->addr_len = 2; + src->addr[0] = puc[datagram_offset + 1]; + src->addr[1] = puc[datagram_offset]; + datagram_offset += 2; + } else { + /* unsupported address mode (do we need "no address"?) */ + return ERR_VAL; + } + + /* hide IEEE802.15.4 header. */ + if (pbuf_remove_header(p, datagram_offset)) { + return ERR_VAL; + } + return ERR_OK; +} + +/** Calculate the 16-bit CRC as required by IEEE 802.15.4 */ +u16_t +lowpan6_calc_crc(const void* buf, u16_t len) +{ +#define CCITT_POLY_16 0x8408U + u16_t i; + u8_t b; + u16_t crc = 0; + const u8_t* p = (const u8_t*)buf; + + for (i = 0; i < len; i++) { + u8_t data = *p; + for (b = 0U; b < 8U; b++) { + if (((data ^ crc) & 1) != 0) { + crc = (u16_t)((crc >> 1) ^ CCITT_POLY_16); + } else { + crc = (u16_t)(crc >> 1); + } + data = (u8_t)(data >> 1); + } + p++; + } + return crc; +} + +/* Fragmentation specific functions: */ + +static void +free_reass_datagram(struct lowpan6_reass_helper *lrh) +{ + if (lrh->reass) { + pbuf_free(lrh->reass); + } + if (lrh->frags) { + pbuf_free(lrh->frags); + } + mem_free(lrh); +} + +/** + * Removes a datagram from the reassembly queue. + **/ +static void +dequeue_datagram(struct lowpan6_reass_helper *lrh, struct lowpan6_reass_helper *prev) +{ + if (lowpan6_data.reass_list == lrh) { + lowpan6_data.reass_list = lowpan6_data.reass_list->next_packet; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", prev != NULL); + prev->next_packet = lrh->next_packet; + } +} + +/** + * Periodic timer for 6LowPAN functions: + * + * - Remove incomplete/old packets + */ +void +lowpan6_tmr(void) +{ + struct lowpan6_reass_helper *lrh, *lrh_next, *lrh_prev = NULL; + + lrh = lowpan6_data.reass_list; + while (lrh != NULL) { + lrh_next = lrh->next_packet; + if ((--lrh->timer) == 0) { + dequeue_datagram(lrh, lrh_prev); + free_reass_datagram(lrh); + } else { + lrh_prev = lrh; + } + lrh = lrh_next; + } +} + +/* + * Encapsulates data into IEEE 802.15.4 frames. + * Fragments an IPv6 datagram into 6LowPAN units, which fit into IEEE 802.15.4 frames. + * If configured, will compress IPv6 and or UDP headers. + * */ +static err_t +lowpan6_frag(struct netif *netif, struct pbuf *p, const struct lowpan6_link_addr *src, const struct lowpan6_link_addr *dst) +{ + struct pbuf *p_frag; + u16_t frag_len, remaining_len, max_data_len; + u8_t *buffer; + u8_t ieee_header_len; + u8_t lowpan6_header_len; + u8_t hidden_header_len; + u16_t crc; + u16_t datagram_offset; + err_t err = ERR_IF; + + LWIP_ASSERT("lowpan6_frag: netif->linkoutput not set", netif->linkoutput != NULL); + + /* We'll use a dedicated pbuf for building 6LowPAN fragments. */ + p_frag = pbuf_alloc(PBUF_RAW, 127, PBUF_RAM); + if (p_frag == NULL) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece", p_frag->len == p_frag->tot_len); + + /* Write IEEE 802.15.4 header. */ + buffer = (u8_t *)p_frag->payload; + ieee_header_len = lowpan6_write_iee802154_header((struct ieee_802154_hdr *)buffer, src, dst); + LWIP_ASSERT("ieee_header_len < p_frag->len", ieee_header_len < p_frag->len); + +#if LWIP_6LOWPAN_IPHC + /* Perform 6LowPAN IPv6 header compression according to RFC 6282 */ + /* do the header compression (this does NOT copy any non-compressed data) */ + err = lowpan6_compress_headers(netif, (u8_t *)p->payload, p->len, + &buffer[ieee_header_len], p_frag->len - ieee_header_len, &lowpan6_header_len, + &hidden_header_len, LWIP_6LOWPAN_CONTEXTS(netif), src, dst); + if (err != ERR_OK) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + pbuf_free(p_frag); + return err; + } + pbuf_remove_header(p, hidden_header_len); + +#else /* LWIP_6LOWPAN_IPHC */ + /* Send uncompressed IPv6 header with appropriate dispatch byte. */ + lowpan6_header_len = 1; + buffer[ieee_header_len] = 0x41; /* IPv6 dispatch */ +#endif /* LWIP_6LOWPAN_IPHC */ + + /* Calculate remaining packet length */ + remaining_len = p->tot_len; + + if (remaining_len > 0x7FF) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + /* datagram_size must fit into 11 bit */ + pbuf_free(p_frag); + return ERR_VAL; + } + + /* Fragment, or 1 packet? */ + max_data_len = LOWPAN6_MAX_PAYLOAD - ieee_header_len - lowpan6_header_len; + if (remaining_len > max_data_len) { + u16_t data_len; + /* We must move the 6LowPAN header to make room for the FRAG header. */ + memmove(&buffer[ieee_header_len + 4], &buffer[ieee_header_len], lowpan6_header_len); + + /* Now we need to fragment the packet. FRAG1 header first */ + buffer[ieee_header_len] = 0xc0 | (((p->tot_len + hidden_header_len) >> 8) & 0x7); + buffer[ieee_header_len + 1] = (p->tot_len + hidden_header_len) & 0xff; + + lowpan6_data.tx_datagram_tag++; + buffer[ieee_header_len + 2] = (lowpan6_data.tx_datagram_tag >> 8) & 0xff; + buffer[ieee_header_len + 3] = lowpan6_data.tx_datagram_tag & 0xff; + + /* Fragment follows. */ + data_len = (max_data_len - 4) & 0xf8; + frag_len = data_len + lowpan6_header_len; + + pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len + 4, frag_len - lowpan6_header_len, 0); + remaining_len -= frag_len - lowpan6_header_len; + /* datagram offset holds the offset before compression */ + datagram_offset = frag_len - lowpan6_header_len + hidden_header_len; + LWIP_ASSERT("datagram offset must be a multiple of 8", (datagram_offset & 7) == 0); + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = ieee_header_len + 4 + frag_len + 2; /* add 2 bytes for crc*/ + + /* 2 bytes CRC */ + crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); + pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + + while ((remaining_len > 0) && (err == ERR_OK)) { + struct ieee_802154_hdr *hdr = (struct ieee_802154_hdr *)buffer; + /* new frame, new seq num for ACK */ + hdr->sequence_number = lowpan6_data.tx_frame_seq_num++; + + buffer[ieee_header_len] |= 0x20; /* Change FRAG1 to FRAGN */ + + LWIP_ASSERT("datagram offset must be a multiple of 8", (datagram_offset & 7) == 0); + buffer[ieee_header_len + 4] = (u8_t)(datagram_offset >> 3); /* datagram offset in FRAGN header (datagram_offset is max. 11 bit) */ + + frag_len = (127 - ieee_header_len - 5 - 2) & 0xf8; + if (frag_len > remaining_len) { + frag_len = remaining_len; + } + + pbuf_copy_partial(p, buffer + ieee_header_len + 5, frag_len, p->tot_len - remaining_len); + remaining_len -= frag_len; + datagram_offset += frag_len; + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = frag_len + 5 + ieee_header_len + 2; + + /* 2 bytes CRC */ + crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); + pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + } + } else { + /* It fits in one frame. */ + frag_len = remaining_len; + + /* Copy IPv6 packet */ + pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len, frag_len, 0); + remaining_len = 0; + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = frag_len + lowpan6_header_len + ieee_header_len + 2; + LWIP_ASSERT("", p_frag->len <= 127); + + /* 2 bytes CRC */ + crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); + pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + } + + pbuf_free(p_frag); + + return err; +} + +/** + * @ingroup sixlowpan + * Set context + */ +err_t +lowpan6_set_context(u8_t idx, const ip6_addr_t *context) +{ +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) { + return ERR_ARG; + } + + IP6_ADDR_ZONECHECK(context); + + ip6_addr_set(&lowpan6_data.lowpan6_context[idx], context); + + return ERR_OK; +#else + LWIP_UNUSED_ARG(idx); + LWIP_UNUSED_ARG(context); + return ERR_ARG; +#endif +} + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS +/** + * @ingroup sixlowpan + * Set short address + */ +err_t +lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low) +{ + short_mac_addr.addr[0] = addr_high; + short_mac_addr.addr[1] = addr_low; + + return ERR_OK; +} +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +/* Create IEEE 802.15.4 address from netif address */ +static err_t +lowpan6_hwaddr_to_addr(struct netif *netif, struct lowpan6_link_addr *addr) +{ + addr->addr_len = 8; + if (netif->hwaddr_len == 8) { + LWIP_ERROR("NETIF_MAX_HWADDR_LEN >= 8 required", sizeof(netif->hwaddr) >= 8, return ERR_VAL;); + SMEMCPY(addr->addr, netif->hwaddr, 8); + } else if (netif->hwaddr_len == 6) { + /* Copy from MAC-48 */ + SMEMCPY(addr->addr, netif->hwaddr, 3); + addr->addr[3] = addr->addr[4] = 0xff; + SMEMCPY(&addr->addr[5], &netif->hwaddr[3], 3); + } else { + /* Invalid address length, don't know how to convert this */ + return ERR_VAL; + } + return ERR_OK; +} + +/** + * @ingroup sixlowpan + * Resolve and fill-in IEEE 802.15.4 address header for outgoing IPv6 packet. + * + * Perform Header Compression and fragment if necessary. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return err_t + */ +err_t +lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) +{ + err_t result; + const u8_t *hwaddr; + struct lowpan6_link_addr src, dest; +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + ip6_addr_t ip6_src; + struct ip6_hdr *ip6_hdr; +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + /* Check if we can compress source address (use aligned copy) */ + ip6_hdr = (struct ip6_hdr *)q->payload; + ip6_addr_copy_from_packed(ip6_src, ip6_hdr->src); + ip6_addr_assign_zone(&ip6_src, IP6_UNICAST, netif); + if (lowpan6_get_address_mode(&ip6_src, &short_mac_addr) == 3) { + src.addr_len = 2; + src.addr[0] = short_mac_addr.addr[0]; + src.addr[1] = short_mac_addr.addr[1]; + } else +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + { + result = lowpan6_hwaddr_to_addr(netif, &src); + if (result != ERR_OK) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return result; + } + } + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + /* We need to send to the broadcast address.*/ + return lowpan6_frag(netif, q, &src, &ieee_802154_broadcast); + } + + /* We have a unicast destination IP address */ + /* @todo anycast? */ + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + if (src.addr_len == 2) { + /* If source address was compressable to short_mac_addr, and dest has same subnet and + * is also compressable to 2-bytes, assume we can infer dest as a short address too. */ + dest.addr_len = 2; + dest.addr[0] = ((u8_t *)q->payload)[38]; + dest.addr[1] = ((u8_t *)q->payload)[39]; + if ((src.addr_len == 2) && (ip6_addr_netcmp_zoneless(&ip6_hdr->src, &ip6_hdr->dest)) && + (lowpan6_get_address_mode(ip6addr, &dest) == 3)) { + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + return lowpan6_frag(netif, q, &src, &dest); + } + } +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + + /* Ask ND6 what to do with the packet. */ + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); + if (result != ERR_OK) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return result; + } + + /* If no hardware address is returned, nd6 has queued the packet for later. */ + if (hwaddr == NULL) { + return ERR_OK; + } + + /* Send out the packet using the returned hardware address. */ + dest.addr_len = netif->hwaddr_len; + /* XXX: Inferring the length of the source address from the destination address + * is not correct for IEEE 802.15.4, but currently we don't get this information + * from the neighbor cache */ + SMEMCPY(dest.addr, hwaddr, netif->hwaddr_len); + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + return lowpan6_frag(netif, q, &src, &dest); +} +/** + * @ingroup sixlowpan + * NETIF input function: don't free the input pbuf when returning != ERR_OK! + */ +err_t +lowpan6_input(struct pbuf *p, struct netif *netif) +{ + u8_t *puc, b; + s8_t i; + struct lowpan6_link_addr src, dest; + u16_t datagram_size = 0; + u16_t datagram_offset, datagram_tag; + struct lowpan6_reass_helper *lrh, *lrh_next, *lrh_prev = NULL; + + if (p == NULL) { + return ERR_OK; + } + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + + if (p->len != p->tot_len) { + /* for now, this needs a pbuf in one piece */ + goto lowpan6_input_discard; + } + + if (lowpan6_parse_iee802154_header(p, &src, &dest) != ERR_OK) { + goto lowpan6_input_discard; + } + + /* Check dispatch. */ + puc = (u8_t *)p->payload; + + b = *puc; + if ((b & 0xf8) == 0xc0) { + /* FRAG1 dispatch. add this packet to reassembly list. */ + datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; + datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; + + /* check for duplicate */ + lrh = lowpan6_data.reass_list; + while (lrh != NULL) { + uint8_t discard = 0; + lrh_next = lrh->next_packet; + if ((lrh->sender_addr.addr_len == src.addr_len) && + (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0)) { + /* address match with packet in reassembly. */ + if ((datagram_tag == lrh->datagram_tag) && (datagram_size == lrh->datagram_size)) { + /* duplicate fragment. */ + goto lowpan6_input_discard; + } else { + /* We are receiving the start of a new datagram. Discard old one (incomplete). */ + discard = 1; + } + } + if (discard) { + dequeue_datagram(lrh, lrh_prev); + free_reass_datagram(lrh); + } else { + lrh_prev = lrh; + } + /* Check next datagram in queue. */ + lrh = lrh_next; + } + + pbuf_remove_header(p, 4); /* hide frag1 dispatch */ + + lrh = (struct lowpan6_reass_helper *) mem_malloc(sizeof(struct lowpan6_reass_helper)); + if (lrh == NULL) { + goto lowpan6_input_discard; + } + + lrh->sender_addr.addr_len = src.addr_len; + for (i = 0; i < src.addr_len; i++) { + lrh->sender_addr.addr[i] = src.addr[i]; + } + lrh->datagram_size = datagram_size; + lrh->datagram_tag = datagram_tag; + lrh->frags = NULL; + if (*(u8_t *)p->payload == 0x41) { + /* This is a complete IPv6 packet, just skip dispatch byte. */ + pbuf_remove_header(p, 1); /* hide dispatch byte. */ + lrh->reass = p; + } else if ((*(u8_t *)p->payload & 0xe0 ) == 0x60) { + lrh->reass = lowpan6_decompress(p, datagram_size, LWIP_6LOWPAN_CONTEXTS(netif), &src, &dest); + if (lrh->reass == NULL) { + /* decompression failed */ + mem_free(lrh); + goto lowpan6_input_discard; + } + } + /* TODO: handle the case where we already have FRAGN received */ + lrh->next_packet = lowpan6_data.reass_list; + lrh->timer = 2; + lowpan6_data.reass_list = lrh; + + return ERR_OK; + } else if ((b & 0xf8) == 0xe0) { + /* FRAGN dispatch, find packet being reassembled. */ + datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; + datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; + datagram_offset = (u16_t)puc[4] << 3; + pbuf_remove_header(p, 4); /* hide frag1 dispatch but keep datagram offset for reassembly */ + + for (lrh = lowpan6_data.reass_list; lrh != NULL; lrh_prev = lrh, lrh = lrh->next_packet) { + if ((lrh->sender_addr.addr_len == src.addr_len) && + (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0) && + (datagram_tag == lrh->datagram_tag) && + (datagram_size == lrh->datagram_size)) { + break; + } + } + if (lrh == NULL) { + /* rogue fragment */ + goto lowpan6_input_discard; + } + /* Insert new pbuf into list of fragments. Each fragment is a pbuf, + this only works for unchained pbufs. */ + LWIP_ASSERT("p->next == NULL", p->next == NULL); + if (lrh->reass != NULL) { + /* FRAG1 already received, check this offset against first len */ + if (datagram_offset < lrh->reass->len) { + /* fragment overlap, discard old fragments */ + dequeue_datagram(lrh, lrh_prev); + free_reass_datagram(lrh); + goto lowpan6_input_discard; + } + } + if (lrh->frags == NULL) { + /* first FRAGN */ + lrh->frags = p; + } else { + /* find the correct place to insert */ + struct pbuf *q, *last; + u16_t new_frag_len = p->len - 1; /* p->len includes datagram_offset byte */ + for (q = lrh->frags, last = NULL; q != NULL; last = q, q = q->next) { + u16_t q_datagram_offset = ((u8_t *)q->payload)[0] << 3; + u16_t q_frag_len = q->len - 1; + if (datagram_offset < q_datagram_offset) { + if (datagram_offset + new_frag_len > q_datagram_offset) { + /* overlap, discard old fragments */ + dequeue_datagram(lrh, lrh_prev); + free_reass_datagram(lrh); + goto lowpan6_input_discard; + } + /* insert here */ + break; + } else if (datagram_offset == q_datagram_offset) { + if (q_frag_len != new_frag_len) { + /* fragment mismatch, discard old fragments */ + dequeue_datagram(lrh, lrh_prev); + free_reass_datagram(lrh); + goto lowpan6_input_discard; + } + /* duplicate, ignore */ + pbuf_free(p); + return ERR_OK; + } + } + /* insert fragment */ + if (last == NULL) { + lrh->frags = p; + } else { + last->next = p; + p->next = q; + } + } + /* check if all fragments were received */ + if (lrh->reass) { + u16_t offset = lrh->reass->len; + struct pbuf *q; + for (q = lrh->frags; q != NULL; q = q->next) { + u16_t q_datagram_offset = ((u8_t *)q->payload)[0] << 3; + if (q_datagram_offset != offset) { + /* not complete, wait for more fragments */ + return ERR_OK; + } + offset += q->len - 1; + } + if (offset == datagram_size) { + /* all fragments received, combine pbufs */ + u16_t datagram_left = datagram_size - lrh->reass->len; + for (q = lrh->frags; q != NULL; q = q->next) { + /* hide datagram_offset byte now */ + pbuf_remove_header(q, 1); + q->tot_len = datagram_left; + datagram_left -= q->len; + } + LWIP_ASSERT("datagram_left == 0", datagram_left == 0); + q = lrh->reass; + q->tot_len = datagram_size; + q->next = lrh->frags; + lrh->frags = NULL; + lrh->reass = NULL; + dequeue_datagram(lrh, lrh_prev); + mem_free(lrh); + + /* @todo: distinguish unicast/multicast */ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + return ip6_input(q, netif); + } + } + /* pbuf enqueued, waiting for more fragments */ + return ERR_OK; + } else { + if (b == 0x41) { + /* This is a complete IPv6 packet, just skip dispatch byte. */ + pbuf_remove_header(p, 1); /* hide dispatch byte. */ + } else if ((b & 0xe0 ) == 0x60) { + /* IPv6 headers are compressed using IPHC. */ + p = lowpan6_decompress(p, datagram_size, LWIP_6LOWPAN_CONTEXTS(netif), &src, &dest); + if (p == NULL) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + return ERR_OK; + } + } else { + goto lowpan6_input_discard; + } + + /* @todo: distinguish unicast/multicast */ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + + return ip6_input(p, netif); + } +lowpan6_input_discard: + MIB2_STATS_NETIF_INC(netif, ifindiscards); + pbuf_free(p); + /* always return ERR_OK here to prevent the caller freeing the pbuf */ + return ERR_OK; +} + +/** + * @ingroup sixlowpan + */ +err_t +lowpan6_if_init(struct netif *netif) +{ + netif->name[0] = 'L'; + netif->name[1] = '6'; + netif->output_ip6 = lowpan6_output; + + MIB2_INIT_NETIF(netif, snmp_ifType_other, 0); + + /* maximum transfer unit */ + netif->mtu = IP6_MIN_MTU_LENGTH; + + /* broadcast capability */ + netif->flags = NETIF_FLAG_BROADCAST /* | NETIF_FLAG_LOWPAN6 */; + + return ERR_OK; +} + +/** + * @ingroup sixlowpan + * Set PAN ID + */ +err_t +lowpan6_set_pan_id(u16_t pan_id) +{ + lowpan6_data.ieee_802154_pan_id = pan_id; + + return ERR_OK; +} + +#if !NO_SYS +/** + * @ingroup sixlowpan + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the + * IEEE 802.15.4 header. + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_6lowpan_input(struct pbuf *p, struct netif *inp) +{ + return tcpip_inpkt(p, inp, lowpan6_input); +} +#endif /* !NO_SYS */ + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_ble.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_ble.c new file mode 100644 index 0000000..6de0ae3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_ble.c @@ -0,0 +1,447 @@ +/** + * @file + * 6LowPAN over BLE output for IPv6 (RFC7668). +*/ + +/* + * Copyright (c) 2017 Benjamin Aigner + * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: Benjamin Aigner + * + * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c) + */ + + +/** + * @defgroup rfc7668if 6LoWPAN over BLE (RFC7668) + * @ingroup netifs + * This file implements a RFC7668 implementation for 6LoWPAN over + * Bluetooth Low Energy. The specification is very similar to 6LoWPAN, + * so most of the code is re-used. + * Compared to 6LoWPAN, much functionality is already implemented in + * lower BLE layers (fragmenting, session management,...). + * + * Usage: + * - add this netif + * - don't add IPv4 addresses (no IPv4 support in RFC7668), pass 'NULL','NULL','NULL' + * - use the BLE to EUI64 conversation util to create an IPv6 link-local address from the BLE MAC (@ref ble_addr_to_eui64) + * - input function: @ref rfc7668_input + * - set the link output function, which transmits output data to an established L2CAP channel + * - If data arrives (HCI event "L2CAP_DATA_PACKET"): + * - allocate a @ref PBUF_RAW buffer + * - let the pbuf struct point to the incoming data or copy it to the buffer + * - call netif->input + * + * @todo: + * - further testing + * - support compression contexts + * - support multiple addresses + * - support multicast + * - support neighbor discovery + */ + + +#include "netif/lowpan6_ble.h" + +#if LWIP_IPV6 + +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" +#include "lwip/snmp.h" + +#include + +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 +/** context memory, containing IPv6 addresses */ +static ip6_addr_t rfc7668_context[LWIP_6LOWPAN_NUM_CONTEXTS]; +#else +#define rfc7668_context NULL +#endif + +static struct lowpan6_link_addr rfc7668_local_addr; +static struct lowpan6_link_addr rfc7668_peer_addr; + +/** + * @ingroup rfc7668if + * convert BT address to EUI64 addr + * + * This method converts a Bluetooth MAC address to an EUI64 address, + * which is used within IPv6 communication + * + * @param dst IPv6 destination space + * @param src BLE MAC address source + * @param public_addr If the LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS + * option is set, bit 0x02 will be set if param=0 (no public addr); cleared otherwise + * + * @see LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS + */ +void +ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr) +{ + /* according to RFC7668 ch 3.2.2. */ + memcpy(dst, src, 3); + dst[3] = 0xFF; + dst[4] = 0xFE; + memcpy(&dst[5], &src[3], 3); +#if LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS + if(public_addr) { + dst[0] &= ~0x02; + } else { + dst[0] |= 0x02; + } +#else + LWIP_UNUSED_ARG(public_addr); +#endif +} + +/** + * @ingroup rfc7668if + * convert EUI64 address to Bluetooth MAC addr + * + * This method converts an EUI64 address to a Bluetooth MAC address, + * + * @param dst BLE MAC address destination + * @param src IPv6 source + * + */ +void +eui64_to_ble_addr(uint8_t *dst, const uint8_t *src) +{ + /* according to RFC7668 ch 3.2.2. */ + memcpy(dst,src,3); + memcpy(&dst[3],&src[5],3); +} + +/** Set an address used for stateful compression. + * This expects an address of 6 or 8 bytes. + */ +static err_t +rfc7668_set_addr(struct lowpan6_link_addr *addr, const u8_t *in_addr, size_t in_addr_len, int is_mac_48, int is_public_addr) +{ + if ((in_addr == NULL) || (addr == NULL)) { + return ERR_VAL; + } + if (is_mac_48) { + if (in_addr_len != 6) { + return ERR_VAL; + } + addr->addr_len = 8; + ble_addr_to_eui64(addr->addr, in_addr, is_public_addr); + } else { + if (in_addr_len != 8) { + return ERR_VAL; + } + addr->addr_len = 8; + memcpy(addr->addr, in_addr, 8); + } + return ERR_OK; +} + + +/** Set the local address used for stateful compression. + * This expects an address of 8 bytes. + */ +err_t +rfc7668_set_local_addr_eui64(struct netif *netif, const u8_t *local_addr, size_t local_addr_len) +{ + /* netif not used for now, the address is stored globally... */ + LWIP_UNUSED_ARG(netif); + return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 0, 0); +} + +/** Set the local address used for stateful compression. + * This expects an address of 6 bytes. + */ +err_t +rfc7668_set_local_addr_mac48(struct netif *netif, const u8_t *local_addr, size_t local_addr_len, int is_public_addr) +{ + /* netif not used for now, the address is stored globally... */ + LWIP_UNUSED_ARG(netif); + return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 1, is_public_addr); +} + +/** Set the peer address used for stateful compression. + * This expects an address of 8 bytes. + */ +err_t +rfc7668_set_peer_addr_eui64(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len) +{ + /* netif not used for now, the address is stored globally... */ + LWIP_UNUSED_ARG(netif); + return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 0, 0); +} + +/** Set the peer address used for stateful compression. + * This expects an address of 6 bytes. + */ +err_t +rfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len, int is_public_addr) +{ + /* netif not used for now, the address is stored globally... */ + LWIP_UNUSED_ARG(netif); + return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 1, is_public_addr); +} + +/** Encapsulate IPv6 frames for BLE transmission + * + * This method implements the IPv6 header compression: + * *) According to RFC6282 + * *) See Figure 2, contains base format of bit positions + * *) Fragmentation not necessary (done at L2CAP layer of BLE) + * @note Currently the pbuf allocation uses 256 bytes. If longer packets are used (possible due to MTU=1480Bytes), increase it here! + * + * @param p Pbuf struct, containing the payload data + * @param netif Output network interface. Should be of RFC7668 type + * + * @return Same as netif->output. + */ +static err_t +rfc7668_compress(struct netif *netif, struct pbuf *p) +{ + struct pbuf *p_frag; + u16_t remaining_len; + u8_t *buffer; + u8_t lowpan6_header_len; + u8_t hidden_header_len; + err_t err; + + LWIP_ASSERT("lowpan6_frag: netif->linkoutput not set", netif->linkoutput != NULL); + +#if LWIP_6LOWPAN_IPHC + + /* We'll use a dedicated pbuf for building BLE fragments. + * We'll over-allocate it by the bytes saved for header compression. + */ + p_frag = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (p_frag == NULL) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece", p_frag->len == p_frag->tot_len); + + /* Write IP6 header (with IPHC). */ + buffer = (u8_t*)p_frag->payload; + + err = lowpan6_compress_headers(netif, (u8_t *)p->payload, p->len, buffer, p_frag->len, + &lowpan6_header_len, &hidden_header_len, rfc7668_context, &rfc7668_local_addr, &rfc7668_peer_addr); + if (err != ERR_OK) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + pbuf_free(p_frag); + return err; + } + pbuf_remove_header(p, hidden_header_len); + + /* Calculate remaining packet length */ + remaining_len = p->tot_len; + + /* Copy IPv6 packet */ + pbuf_copy_partial(p, buffer + lowpan6_header_len, remaining_len, 0); + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = remaining_len + lowpan6_header_len; + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG|LWIP_DBG_TRACE, ("rfc7668_output: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + + pbuf_free(p_frag); + + return err; +#else /* LWIP_6LOWPAN_IPHC */ + /* 6LoWPAN over BLE requires IPHC! */ + return ERR_IF; +#endif/* LWIP_6LOWPAN_IPHC */ +} + +/** + * @ingroup rfc7668if + * Set context id IPv6 address + * + * Store one IPv6 address to a given context id. + * + * @param idx Context id + * @param context IPv6 addr for this context + * + * @return ERR_OK (if everything is fine), ERR_ARG (if the context id is out of range), ERR_VAL (if contexts disabled) + */ +err_t +rfc7668_set_context(u8_t idx, const ip6_addr_t *context) +{ +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + /* check if the ID is possible */ + if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) { + return ERR_ARG; + } + /* copy IPv6 address to context storage */ + ip6_addr_set(&rfc7668_context[idx], context); + return ERR_OK; +#else + LWIP_UNUSED_ARG(idx); + LWIP_UNUSED_ARG(context); + return ERR_VAL; +#endif +} + +/** + * @ingroup rfc7668if + * Compress outgoing IPv6 packet and pass it on to netif->linkoutput + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return See rfc7668_compress + */ +err_t +rfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) +{ + /* dst ip6addr is not used here, we only have one peer */ + LWIP_UNUSED_ARG(ip6addr); + + return rfc7668_compress(netif, q); +} + +/** + * @ingroup rfc7668if + * Process a received raw payload from an L2CAP channel + * + * @param p the received packet, p->payload pointing to the + * IPv6 header (maybe compressed) + * @param netif the network interface on which the packet was received + * + * @return ERR_OK if everything was fine + */ +err_t +rfc7668_input(struct pbuf * p, struct netif *netif) +{ + u8_t * puc; + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + + /* Load first header byte */ + puc = (u8_t*)p->payload; + + /* no IP header compression */ + if (*puc == 0x41) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, removing dispatch: 0x%2x \n", *puc)); + /* This is a complete IPv6 packet, just skip header byte. */ + pbuf_remove_header(p, 1); + /* IPHC header compression */ + } else if ((*puc & 0xe0 )== 0x60) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, decompress dispatch: 0x%2x \n", *puc)); + /* IPv6 headers are compressed using IPHC. */ + p = lowpan6_decompress(p, 0, rfc7668_context, &rfc7668_peer_addr, &rfc7668_local_addr); + /* if no pbuf is returned, handle as discarded packet */ + if (p == NULL) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + return ERR_OK; + } + /* invalid header byte, discard */ + } else { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, discarding: 0x%2x \n", *puc)); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + pbuf_free(p); + return ERR_OK; + } + /* @todo: distinguish unicast/multicast */ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + +#if LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG + { + u16_t i; + LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("IPv6 payload:\n")); + for (i = 0; i < p->len; i++) { + if ((i%4)==0) { + LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\n")); + } + LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("%2X ", *((uint8_t *)p->payload+i))); + } + LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\np->len: %d\n", p->len)); + } +#endif + /* pass data to ip6_input */ + return ip6_input(p, netif); +} + +/** + * @ingroup rfc7668if + * Initialize the netif + * + * No flags are used (broadcast not possible, not ethernet, ...) + * The shortname for this netif is "BT" + * + * @param netif the network interface to be initialized as RFC7668 netif + * + * @return ERR_OK if everything went fine + */ +err_t +rfc7668_if_init(struct netif *netif) +{ + netif->name[0] = 'b'; + netif->name[1] = 't'; + /* local function as IPv6 output */ + netif->output_ip6 = rfc7668_output; + + MIB2_INIT_NETIF(netif, snmp_ifType_other, 0); + + /* maximum transfer unit, set according to RFC7668 ch2.4 */ + netif->mtu = IP6_MIN_MTU_LENGTH; + + /* no flags set (no broadcast, ethernet,...)*/ + netif->flags = 0; + + /* everything fine */ + return ERR_OK; +} + +#if !NO_SYS +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the + * IEEE 802.15.4 header. + * @param inp the network interface on which the packet was received + * + * @return see @ref tcpip_inpkt, same return values + */ +err_t +tcpip_rfc7668_input(struct pbuf *p, struct netif *inp) +{ + /* send data to upper layer, return the result */ + return tcpip_inpkt(p, inp, rfc7668_input); +} +#endif /* !NO_SYS */ + +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_common.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_common.c new file mode 100644 index 0000000..4db1ebb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/lowpan6_common.c @@ -0,0 +1,841 @@ +/** + * @file + * + * Common 6LowPAN routines for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + * + * This implementation aims to conform to IEEE 802.15.4(-2015), RFC 4944 and RFC 6282. + * @todo: RFC 6775. + */ + +/* + * Copyright (c) 2015 Inico Technologies 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/** + * @defgroup sixlowpan 6LoWPAN (RFC4944) + * @ingroup netifs + * 6LowPAN netif implementation + */ + +#include "netif/lowpan6_common.h" + +#if LWIP_IPV6 + +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/udp.h" + +#include + +/* Determine compression mode for unicast address. */ +s8_t +lowpan6_get_address_mode(const ip6_addr_t *ip6addr, const struct lowpan6_link_addr *mac_addr) +{ + if (mac_addr->addr_len == 2) { + if ((ip6addr->addr[2] == (u32_t)PP_HTONL(0x000000ff)) && + ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000))) { + if ((ip6addr->addr[3] & PP_HTONL(0x0000ffff)) == lwip_ntohl((mac_addr->addr[0] << 8) | mac_addr->addr[1])) { + return 3; + } + } + } else if (mac_addr->addr_len == 8) { + if ((ip6addr->addr[2] == lwip_ntohl(((mac_addr->addr[0] ^ 2) << 24) | (mac_addr->addr[1] << 16) | mac_addr->addr[2] << 8 | mac_addr->addr[3])) && + (ip6addr->addr[3] == lwip_ntohl((mac_addr->addr[4] << 24) | (mac_addr->addr[5] << 16) | mac_addr->addr[6] << 8 | mac_addr->addr[7]))) { + return 3; + } + } + + if ((ip6addr->addr[2] == PP_HTONL(0x000000ffUL)) && + ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000UL))) { + return 2; + } + + return 1; +} + +#if LWIP_6LOWPAN_IPHC + +/* Determine compression mode for multicast address. */ +static s8_t +lowpan6_get_address_mode_mc(const ip6_addr_t *ip6addr) +{ + if ((ip6addr->addr[0] == PP_HTONL(0xff020000)) && + (ip6addr->addr[1] == 0) && + (ip6addr->addr[2] == 0) && + ((ip6addr->addr[3] & PP_HTONL(0xffffff00)) == 0)) { + return 3; + } else if (((ip6addr->addr[0] & PP_HTONL(0xff00ffff)) == PP_HTONL(0xff000000)) && + (ip6addr->addr[1] == 0)) { + if ((ip6addr->addr[2] == 0) && + ((ip6addr->addr[3] & PP_HTONL(0xff000000)) == 0)) { + return 2; + } else if ((ip6addr->addr[2] & PP_HTONL(0xffffff00)) == 0) { + return 1; + } + } + + return 0; +} + +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 +static s8_t +lowpan6_context_lookup(const ip6_addr_t *lowpan6_contexts, const ip6_addr_t *ip6addr) +{ + s8_t i; + + for (i = 0; i < LWIP_6LOWPAN_NUM_CONTEXTS; i++) { + if (ip6_addr_netcmp(&lowpan6_contexts[i], ip6addr)) { + return i; + } + } + return -1; +} +#endif /* LWIP_6LOWPAN_NUM_CONTEXTS > 0 */ + +/* + * Compress IPv6 and/or UDP headers. + * */ +err_t +lowpan6_compress_headers(struct netif *netif, u8_t *inbuf, size_t inbuf_size, u8_t *outbuf, size_t outbuf_size, + u8_t *lowpan6_header_len_out, u8_t *hidden_header_len_out, ip6_addr_t *lowpan6_contexts, + const struct lowpan6_link_addr *src, const struct lowpan6_link_addr *dst) +{ + u8_t *buffer, *inptr; + u8_t lowpan6_header_len; + u8_t hidden_header_len = 0; + s8_t i; + struct ip6_hdr *ip6hdr; + ip_addr_t ip6src, ip6dst; + + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("inbuf != NULL", inbuf != NULL); + LWIP_ASSERT("outbuf != NULL", outbuf != NULL); + LWIP_ASSERT("lowpan6_header_len_out != NULL", lowpan6_header_len_out != NULL); + LWIP_ASSERT("hidden_header_len_out != NULL", hidden_header_len_out != NULL); + + /* Perform 6LowPAN IPv6 header compression according to RFC 6282 */ + buffer = outbuf; + inptr = inbuf; + + if (inbuf_size < IP6_HLEN) { + /* input buffer too short */ + return ERR_VAL; + } + if (outbuf_size < IP6_HLEN) { + /* output buffer too short for worst case */ + return ERR_MEM; + } + + /* Point to ip6 header and align copies of src/dest addresses. */ + ip6hdr = (struct ip6_hdr *)inptr; + ip_addr_copy_from_ip6_packed(ip6dst, ip6hdr->dest); + ip6_addr_assign_zone(ip_2_ip6(&ip6dst), IP6_UNKNOWN, netif); + ip_addr_copy_from_ip6_packed(ip6src, ip6hdr->src); + ip6_addr_assign_zone(ip_2_ip6(&ip6src), IP6_UNKNOWN, netif); + + /* Basic length of 6LowPAN header, set dispatch and clear fields. */ + lowpan6_header_len = 2; + buffer[0] = 0x60; + buffer[1] = 0; + + /* Determine whether there will be a Context Identifier Extension byte or not. + * If so, set it already. */ +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + buffer[2] = 0; + + i = lowpan6_context_lookup(lowpan6_contexts, ip_2_ip6(&ip6src)); + if (i >= 0) { + /* Stateful source address compression. */ + buffer[1] |= 0x40; + buffer[2] |= (i & 0x0f) << 4; + } + + i = lowpan6_context_lookup(lowpan6_contexts, ip_2_ip6(&ip6dst)); + if (i >= 0) { + /* Stateful destination address compression. */ + buffer[1] |= 0x04; + buffer[2] |= i & 0x0f; + } + + if (buffer[2] != 0x00) { + /* Context identifier extension byte is appended. */ + buffer[1] |= 0x80; + lowpan6_header_len++; + } +#else /* LWIP_6LOWPAN_NUM_CONTEXTS > 0 */ + LWIP_UNUSED_ARG(lowpan6_contexts); +#endif /* LWIP_6LOWPAN_NUM_CONTEXTS > 0 */ + + /* Determine TF field: Traffic Class, Flow Label */ + if (IP6H_FL(ip6hdr) == 0) { + /* Flow label is elided. */ + buffer[0] |= 0x10; + if (IP6H_TC(ip6hdr) == 0) { + /* Traffic class (ECN+DSCP) elided too. */ + buffer[0] |= 0x08; + } else { + /* Traffic class (ECN+DSCP) appended. */ + buffer[lowpan6_header_len++] = IP6H_TC(ip6hdr); + } + } else { + if (((IP6H_TC(ip6hdr) & 0x3f) == 0)) { + /* DSCP portion of Traffic Class is elided, ECN and FL are appended (3 bytes) */ + buffer[0] |= 0x08; + + buffer[lowpan6_header_len] = IP6H_TC(ip6hdr) & 0xc0; + buffer[lowpan6_header_len++] |= (IP6H_FL(ip6hdr) >> 16) & 0x0f; + buffer[lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; + buffer[lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; + } else { + /* Traffic class and flow label are appended (4 bytes) */ + buffer[lowpan6_header_len++] = IP6H_TC(ip6hdr); + buffer[lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 16) & 0x0f; + buffer[lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; + buffer[lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; + } + } + + /* Compress NH? + * Only if UDP for now. @todo support other NH compression. */ + if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { + buffer[0] |= 0x04; + } else { + /* append nexth. */ + buffer[lowpan6_header_len++] = IP6H_NEXTH(ip6hdr); + } + + /* Compress hop limit? */ + if (IP6H_HOPLIM(ip6hdr) == 255) { + buffer[0] |= 0x03; + } else if (IP6H_HOPLIM(ip6hdr) == 64) { + buffer[0] |= 0x02; + } else if (IP6H_HOPLIM(ip6hdr) == 1) { + buffer[0] |= 0x01; + } else { + /* append hop limit */ + buffer[lowpan6_header_len++] = IP6H_HOPLIM(ip6hdr); + } + + /* Compress source address */ + if (((buffer[1] & 0x40) != 0) || + (ip6_addr_islinklocal(ip_2_ip6(&ip6src)))) { + /* Context-based or link-local source address compression. */ + i = lowpan6_get_address_mode(ip_2_ip6(&ip6src), src); + buffer[1] |= (i & 0x03) << 4; + if (i == 1) { + MEMCPY(buffer + lowpan6_header_len, inptr + 16, 8); + lowpan6_header_len += 8; + } else if (i == 2) { + MEMCPY(buffer + lowpan6_header_len, inptr + 22, 2); + lowpan6_header_len += 2; + } + } else if (ip6_addr_isany(ip_2_ip6(&ip6src))) { + /* Special case: mark SAC and leave SAM=0 */ + buffer[1] |= 0x40; + } else { + /* Append full address. */ + MEMCPY(buffer + lowpan6_header_len, inptr + 8, 16); + lowpan6_header_len += 16; + } + + /* Compress destination address */ + if (ip6_addr_ismulticast(ip_2_ip6(&ip6dst))) { + /* @todo support stateful multicast address compression */ + + buffer[1] |= 0x08; + + i = lowpan6_get_address_mode_mc(ip_2_ip6(&ip6dst)); + buffer[1] |= i & 0x03; + if (i == 0) { + MEMCPY(buffer + lowpan6_header_len, inptr + 24, 16); + lowpan6_header_len += 16; + } else if (i == 1) { + buffer[lowpan6_header_len++] = inptr[25]; + MEMCPY(buffer + lowpan6_header_len, inptr + 35, 5); + lowpan6_header_len += 5; + } else if (i == 2) { + buffer[lowpan6_header_len++] = inptr[25]; + MEMCPY(buffer + lowpan6_header_len, inptr + 37, 3); + lowpan6_header_len += 3; + } else if (i == 3) { + buffer[lowpan6_header_len++] = (inptr)[39]; + } + } else if (((buffer[1] & 0x04) != 0) || + (ip6_addr_islinklocal(ip_2_ip6(&ip6dst)))) { + /* Context-based or link-local destination address compression. */ + i = lowpan6_get_address_mode(ip_2_ip6(&ip6dst), dst); + buffer[1] |= i & 0x03; + if (i == 1) { + MEMCPY(buffer + lowpan6_header_len, inptr + 32, 8); + lowpan6_header_len += 8; + } else if (i == 2) { + MEMCPY(buffer + lowpan6_header_len, inptr + 38, 2); + lowpan6_header_len += 2; + } + } else { + /* Append full address. */ + MEMCPY(buffer + lowpan6_header_len, inptr + 24, 16); + lowpan6_header_len += 16; + } + + /* Move to payload. */ + inptr += IP6_HLEN; + hidden_header_len += IP6_HLEN; + +#if LWIP_UDP + /* Compress UDP header? */ + if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { + /* @todo support optional checksum compression */ + + if (inbuf_size < IP6_HLEN + UDP_HLEN) { + /* input buffer too short */ + return ERR_VAL; + } + if (outbuf_size < (size_t)(hidden_header_len + 7)) { + /* output buffer too short for worst case */ + return ERR_MEM; + } + + buffer[lowpan6_header_len] = 0xf0; + + /* determine port compression mode. */ + if ((inptr[0] == 0xf0) && ((inptr[1] & 0xf0) == 0xb0) && + (inptr[2] == 0xf0) && ((inptr[3] & 0xf0) == 0xb0)) { + /* Compress source and dest ports. */ + buffer[lowpan6_header_len++] |= 0x03; + buffer[lowpan6_header_len++] = ((inptr[1] & 0x0f) << 4) | (inptr[3] & 0x0f); + } else if (inptr[0] == 0xf0) { + /* Compress source port. */ + buffer[lowpan6_header_len++] |= 0x02; + buffer[lowpan6_header_len++] = inptr[1]; + buffer[lowpan6_header_len++] = inptr[2]; + buffer[lowpan6_header_len++] = inptr[3]; + } else if (inptr[2] == 0xf0) { + /* Compress dest port. */ + buffer[lowpan6_header_len++] |= 0x01; + buffer[lowpan6_header_len++] = inptr[0]; + buffer[lowpan6_header_len++] = inptr[1]; + buffer[lowpan6_header_len++] = inptr[3]; + } else { + /* append full ports. */ + lowpan6_header_len++; + buffer[lowpan6_header_len++] = inptr[0]; + buffer[lowpan6_header_len++] = inptr[1]; + buffer[lowpan6_header_len++] = inptr[2]; + buffer[lowpan6_header_len++] = inptr[3]; + } + + /* elide length and copy checksum */ + buffer[lowpan6_header_len++] = inptr[6]; + buffer[lowpan6_header_len++] = inptr[7]; + + hidden_header_len += UDP_HLEN; + } +#endif /* LWIP_UDP */ + + *lowpan6_header_len_out = lowpan6_header_len; + *hidden_header_len_out = hidden_header_len; + + return ERR_OK; +} + +/** Decompress IPv6 and UDP headers compressed according to RFC 6282 + * + * @param lowpan6_buffer compressed headers, first byte is the dispatch byte + * @param lowpan6_bufsize size of lowpan6_buffer (may include data after headers) + * @param decomp_buffer buffer where the decompressed headers are stored + * @param decomp_bufsize size of decomp_buffer + * @param hdr_size_comp returns the size of the compressed headers (skip to get to data) + * @param hdr_size_decomp returns the size of the decompressed headers (IPv6 + UDP) + * @param datagram_size datagram size from fragments or 0 if unfragmented + * @param compressed_size compressed datagram size (for unfragmented rx) + * @param lowpan6_contexts context addresses + * @param src source address of the outer layer, used for address compression + * @param dest destination address of the outer layer, used for address compression + * @return ERR_OK if decompression succeeded, an error otherwise + */ +static err_t +lowpan6_decompress_hdr(u8_t *lowpan6_buffer, size_t lowpan6_bufsize, + u8_t *decomp_buffer, size_t decomp_bufsize, + u16_t *hdr_size_comp, u16_t *hdr_size_decomp, + u16_t datagram_size, u16_t compressed_size, + ip6_addr_t *lowpan6_contexts, + struct lowpan6_link_addr *src, struct lowpan6_link_addr *dest) +{ + u16_t lowpan6_offset; + struct ip6_hdr *ip6hdr; + s8_t i; + u32_t header_temp; + u16_t ip6_offset = IP6_HLEN; + + LWIP_ASSERT("lowpan6_buffer != NULL", lowpan6_buffer != NULL); + LWIP_ASSERT("decomp_buffer != NULL", decomp_buffer != NULL); + LWIP_ASSERT("src != NULL", src != NULL); + LWIP_ASSERT("dest != NULL", dest != NULL); + LWIP_ASSERT("hdr_size_comp != NULL", hdr_size_comp != NULL); + LWIP_ASSERT("dehdr_size_decompst != NULL", hdr_size_decomp != NULL); + + ip6hdr = (struct ip6_hdr *)decomp_buffer; + if (decomp_bufsize < IP6_HLEN) { + return ERR_MEM; + } + + /* output the full compressed packet, if set in @see lowpan6_opts.h */ +#if LWIP_LOWPAN6_IP_COMPRESSED_DEBUG + { + u16_t j; + LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("lowpan6_decompress_hdr: IP6 payload (compressed): \n")); + for (j = 0; j < lowpan6_bufsize; j++) { + if ((j % 4) == 0) { + LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("\n")); + } + LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("%2X ", lowpan6_buffer[j])); + } + LWIP_DEBUGF(LWIP_LOWPAN6_IP_COMPRESSED_DEBUG, ("\np->len: %d", lowpan6_bufsize)); + } +#endif + + /* offset for inline IP headers (RFC 6282 ch3)*/ + lowpan6_offset = 2; + /* if CID is set (context identifier), the context byte + * follows immediately after the header, so other IPHC fields are @+3 */ + if (lowpan6_buffer[1] & 0x80) { + lowpan6_offset++; + } + + /* Set IPv6 version, traffic class and flow label. (RFC6282, ch 3.1.1.)*/ + if ((lowpan6_buffer[0] & 0x18) == 0x00) { + header_temp = ((lowpan6_buffer[lowpan6_offset+1] & 0x0f) << 16) | \ + (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset+3]; + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("TF: 00, ECN: 0x%"X8_F", Flowlabel+DSCP: 0x%8"X32_F"\n", \ + lowpan6_buffer[lowpan6_offset],header_temp)); + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset], header_temp); + /* increase offset, processed 4 bytes here: + * TF=00: ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)*/ + lowpan6_offset += 4; + } else if ((lowpan6_buffer[0] & 0x18) == 0x08) { + header_temp = ((lowpan6_buffer[lowpan6_offset] & 0x0f) << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset+2]; + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("TF: 01, ECN: 0x%"X8_F", Flowlabel: 0x%2"X32_F", DSCP ignored\n", \ + lowpan6_buffer[lowpan6_offset] & 0xc0,header_temp)); + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset] & 0xc0, header_temp); + /* increase offset, processed 3 bytes here: + * TF=01: ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided.*/ + lowpan6_offset += 3; + } else if ((lowpan6_buffer[0] & 0x18) == 0x10) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("TF: 10, DCSP+ECN: 0x%"X8_F", Flowlabel ignored\n", lowpan6_buffer[lowpan6_offset])); + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset],0); + /* increase offset, processed 1 byte here: + * ECN + DSCP (1 byte), Flow Label is elided.*/ + lowpan6_offset += 1; + } else if ((lowpan6_buffer[0] & 0x18) == 0x18) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("TF: 11, DCSP/ECN & Flowlabel ignored\n")); + /* don't increase offset, no bytes processed here */ + IP6H_VTCFL_SET(ip6hdr, 6, 0, 0); + } + + /* Set Next Header (NH) */ + if ((lowpan6_buffer[0] & 0x04) == 0x00) { + /* 0: full next header byte carried inline (increase offset)*/ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("NH: 0x%2X\n", lowpan6_buffer[lowpan6_offset+1])); + IP6H_NEXTH_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); + } else { + /* 1: NH compression, LOWPAN_NHC (RFC6282, ch 4.1) */ + /* We should fill this later with NHC decoding */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("NH: skipped, later done with NHC\n")); + IP6H_NEXTH_SET(ip6hdr, 0); + } + + /* Set Hop Limit, either carried inline or 3 different hops (1,64,255) */ + if ((lowpan6_buffer[0] & 0x03) == 0x00) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Hops: full value: %d\n", lowpan6_buffer[lowpan6_offset+1])); + IP6H_HOPLIM_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); + } else if ((lowpan6_buffer[0] & 0x03) == 0x01) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Hops: compressed: 1\n")); + IP6H_HOPLIM_SET(ip6hdr, 1); + } else if ((lowpan6_buffer[0] & 0x03) == 0x02) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Hops: compressed: 64\n")); + IP6H_HOPLIM_SET(ip6hdr, 64); + } else if ((lowpan6_buffer[0] & 0x03) == 0x03) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Hops: compressed: 255\n")); + IP6H_HOPLIM_SET(ip6hdr, 255); + } + + /* Source address decoding. */ + if ((lowpan6_buffer[1] & 0x40) == 0x00) { + /* Source address compression (SAC) = 0 -> stateless compression */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAC == 0, no context byte\n")); + /* Stateless compression */ + if ((lowpan6_buffer[1] & 0x30) == 0x00) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 00, no src compression, fetching 128bits inline\n")); + /* copy full address, increase offset by 16 Bytes */ + MEMCPY(&ip6hdr->src.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x30) == 0x10) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 01, src compression, 64bits inline\n")); + /* set 64 bits to link local */ + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + /* copy 8 Bytes, increase offset */ + MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 10, src compression, 16bits inline\n")); + /* set 96 bits to link local */ + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + /* extract remaining 16bits from inline bytes, increase offset */ + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | + lowpan6_buffer[lowpan6_offset + 1]); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 11, src compression, 0bits inline, using other headers\n")); + /* no information avalaible, using other layers, see RFC6282 ch 3.2.2 */ + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + if (src->addr_len == 2) { + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); + } else if (src->addr_len == 8) { + ip6hdr->src.addr[2] = lwip_htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | + (src->addr[2] << 8) | src->addr[3]); + ip6hdr->src.addr[3] = lwip_htonl((src->addr[4] << 24) | (src->addr[5] << 16) | + (src->addr[6] << 8) | src->addr[7]); + } else { + /* invalid source address length */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Invalid source address length\n")); + return ERR_VAL; + } + } + } else { + /* Source address compression (SAC) = 1 -> stateful/context-based compression */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAC == 1, additional context byte\n")); + if ((lowpan6_buffer[1] & 0x30) == 0x00) { + /* SAM=00, address=> :: (ANY) */ + ip6hdr->src.addr[0] = 0; + ip6hdr->src.addr[1] = 0; + ip6hdr->src.addr[2] = 0; + ip6hdr->src.addr[3] = 0; + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 00, context compression, ANY (::)\n")); + } else { + /* Set prefix from context info */ + if (lowpan6_buffer[1] & 0x80) { + i = (lowpan6_buffer[2] >> 4) & 0x0f; + } else { + i = 0; + } + if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { + /* Error */ + return ERR_VAL; + } +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + ip6hdr->src.addr[0] = lowpan6_contexts[i].addr[0]; + ip6hdr->src.addr[1] = lowpan6_contexts[i].addr[1]; + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == xx, context compression found @%d: %8"X32_F", %8"X32_F"\n", (int)i, ip6hdr->src.addr[0], ip6hdr->src.addr[1])); +#else + LWIP_UNUSED_ARG(lowpan6_contexts); +#endif + } + + /* determine further address bits */ + if ((lowpan6_buffer[1] & 0x30) == 0x10) { + /* SAM=01, load additional 64bits */ + MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 01, context compression, 64bits inline\n")); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { + /* SAM=01, load additional 16bits */ + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset + 1]); + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 10, context compression, 16bits inline\n")); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { + /* SAM=11, address is fully elided, load from other layers */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("SAM == 11, context compression, 0bits inline, using other headers\n")); + if (src->addr_len == 2) { + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); + } else if (src->addr_len == 8) { + ip6hdr->src.addr[2] = lwip_htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | (src->addr[2] << 8) | src->addr[3]); + ip6hdr->src.addr[3] = lwip_htonl((src->addr[4] << 24) | (src->addr[5] << 16) | (src->addr[6] << 8) | src->addr[7]); + } else { + /* invalid source address length */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Invalid source address length\n")); + return ERR_VAL; + } + } + } + + /* Destination address decoding. */ + if (lowpan6_buffer[1] & 0x08) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("M=1: multicast\n")); + /* Multicast destination */ + if (lowpan6_buffer[1] & 0x04) { + LWIP_DEBUGF(LWIP_DBG_ON,("DAC == 1, context multicast: unsupported!!!\n")); + /* @todo support stateful multicast addressing */ + return ERR_VAL; + } + + if ((lowpan6_buffer[1] & 0x03) == 0x00) { + /* DAM = 00, copy full address (128bits) */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 00, no dst compression, fetching 128bits inline\n")); + MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { + /* DAM = 01, copy 4 bytes (32bits) */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 01, dst address form (48bits): ffXX::00XX:XXXX:XXXX\n")); + ip6hdr->dest.addr[0] = lwip_htonl(0xff000000UL | (lowpan6_buffer[lowpan6_offset++] << 16)); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = lwip_htonl(lowpan6_buffer[lowpan6_offset++]); + ip6hdr->dest.addr[3] = lwip_htonl((lowpan6_buffer[lowpan6_offset] << 24) | (lowpan6_buffer[lowpan6_offset + 1] << 16) | (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset + 3]); + lowpan6_offset += 4; + } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { + /* DAM = 10, copy 3 bytes (24bits) */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 10, dst address form (32bits): ffXX::00XX:XXXX\n")); + ip6hdr->dest.addr[0] = lwip_htonl(0xff000000UL | (lowpan6_buffer[lowpan6_offset++] << 16)); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = 0; + ip6hdr->dest.addr[3] = lwip_htonl((lowpan6_buffer[lowpan6_offset] << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { + /* DAM = 11, copy 1 byte (8bits) */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 11, dst address form (8bits): ff02::00XX\n")); + ip6hdr->dest.addr[0] = PP_HTONL(0xff020000UL); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = 0; + ip6hdr->dest.addr[3] = lwip_htonl(lowpan6_buffer[lowpan6_offset++]); + } + + } else { + /* no Multicast (M=0) */ + if (lowpan6_buffer[1] & 0x04) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAC == 1, stateful compression\n")); + /* Stateful destination compression */ + /* Set prefix from context info */ + if (lowpan6_buffer[1] & 0x80) { + i = lowpan6_buffer[2] & 0x0f; + } else { + i = 0; + } + if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { + /* Error */ + return ERR_VAL; + } +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + ip6hdr->dest.addr[0] = lowpan6_contexts[i].addr[0]; + ip6hdr->dest.addr[1] = lowpan6_contexts[i].addr[1]; +#endif + } else { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAC == 0, stateless compression, setting link local prefix\n")); + /* Link local address compression */ + ip6hdr->dest.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->dest.addr[1] = 0; + } + + /* M=0, DAC=0, determining destination address length via DAM=xx */ + if ((lowpan6_buffer[1] & 0x03) == 0x00) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 00, no dst compression, fetching 128bits inline")); + /* DAM=00, copy full address */ + MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 01, dst compression, 64bits inline\n")); + /* DAM=01, copy 64 inline bits, increase offset */ + MEMCPY(&ip6hdr->dest.addr[2], lowpan6_buffer + lowpan6_offset, 8); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("DAM == 01, dst compression, 16bits inline\n")); + /* DAM=10, copy 16 inline bits, increase offset */ + ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->dest.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset + 1]); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { + /* DAM=11, no bits available, use other headers (not done here) */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG,("DAM == 01, dst compression, 0bits inline, using other headers\n")); + if (dest->addr_len == 2) { + ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->dest.addr[3] = lwip_htonl(0xfe000000UL | (dest->addr[0] << 8) | dest->addr[1]); + } else if (dest->addr_len == 8) { + ip6hdr->dest.addr[2] = lwip_htonl(((dest->addr[0] ^ 2) << 24) | (dest->addr[1] << 16) | dest->addr[2] << 8 | dest->addr[3]); + ip6hdr->dest.addr[3] = lwip_htonl((dest->addr[4] << 24) | (dest->addr[5] << 16) | dest->addr[6] << 8 | dest->addr[7]); + } else { + /* invalid destination address length */ + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Invalid destination address length\n")); + return ERR_VAL; + } + } + } + + + /* Next Header Compression (NHC) decoding? */ + if (lowpan6_buffer[0] & 0x04) { + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("NHC decoding\n")); +#if LWIP_UDP + if ((lowpan6_buffer[lowpan6_offset] & 0xf8) == 0xf0) { + /* NHC: UDP */ + struct udp_hdr *udphdr; + LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("NHC: UDP\n")); + + /* UDP compression */ + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_UDP); + udphdr = (struct udp_hdr *)((u8_t *)decomp_buffer + ip6_offset); + if (decomp_bufsize < IP6_HLEN + UDP_HLEN) { + return ERR_MEM; + } + + /* Checksum decompression */ + if (lowpan6_buffer[lowpan6_offset] & 0x04) { + /* @todo support checksum decompress */ + LWIP_DEBUGF(LWIP_DBG_ON, ("NHC: UDP chechsum decompression UNSUPPORTED\n")); + return ERR_VAL; + } + + /* Decompress ports, according to RFC4944 */ + i = lowpan6_buffer[lowpan6_offset++] & 0x03; + if (i == 0) { + udphdr->src = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + udphdr->dest = lwip_htons(lowpan6_buffer[lowpan6_offset + 2] << 8 | lowpan6_buffer[lowpan6_offset + 3]); + lowpan6_offset += 4; + } else if (i == 0x01) { + udphdr->src = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + udphdr->dest = lwip_htons(0xf000 | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if (i == 0x02) { + udphdr->src = lwip_htons(0xf000 | lowpan6_buffer[lowpan6_offset]); + udphdr->dest = lwip_htons(lowpan6_buffer[lowpan6_offset + 1] << 8 | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if (i == 0x03) { + udphdr->src = lwip_htons(0xf0b0 | ((lowpan6_buffer[lowpan6_offset] >> 4) & 0x0f)); + udphdr->dest = lwip_htons(0xf0b0 | (lowpan6_buffer[lowpan6_offset] & 0x0f)); + lowpan6_offset += 1; + } + + udphdr->chksum = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + lowpan6_offset += 2; + ip6_offset += UDP_HLEN; + if (datagram_size == 0) { + datagram_size = compressed_size - lowpan6_offset + ip6_offset; + } + udphdr->len = lwip_htons(datagram_size - IP6_HLEN); + + } else +#endif /* LWIP_UDP */ + { + LWIP_DEBUGF(LWIP_DBG_ON,("NHC: unsupported protocol!\n")); + /* @todo support NHC other than UDP */ + return ERR_VAL; + } + } + if (datagram_size == 0) { + datagram_size = compressed_size - lowpan6_offset + ip6_offset; + } + /* Infer IPv6 payload length for header */ + IP6H_PLEN_SET(ip6hdr, datagram_size - IP6_HLEN); + + if (lowpan6_offset > lowpan6_bufsize) { + /* input buffer overflow */ + return ERR_VAL; + } + *hdr_size_comp = lowpan6_offset; + *hdr_size_decomp = ip6_offset; + + return ERR_OK; +} + +struct pbuf * +lowpan6_decompress(struct pbuf *p, u16_t datagram_size, ip6_addr_t *lowpan6_contexts, + struct lowpan6_link_addr *src, struct lowpan6_link_addr *dest) +{ + struct pbuf *q; + u16_t lowpan6_offset, ip6_offset; + err_t err; + +#if LWIP_UDP +#define UDP_HLEN_ALLOC UDP_HLEN +#else +#define UDP_HLEN_ALLOC 0 +#endif + + /* Allocate a buffer for decompression. This buffer will be too big and will be + trimmed once the final size is known. */ + q = pbuf_alloc(PBUF_IP, p->len + IP6_HLEN + UDP_HLEN_ALLOC, PBUF_POOL); + if (q == NULL) { + pbuf_free(p); + return NULL; + } + if (q->len < IP6_HLEN + UDP_HLEN_ALLOC) { + /* The headers need to fit into the first pbuf */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + /* Decompress the IPv6 (and possibly UDP) header(s) into the new pbuf */ + err = lowpan6_decompress_hdr((u8_t *)p->payload, p->len, (u8_t *)q->payload, q->len, + &lowpan6_offset, &ip6_offset, datagram_size, p->tot_len, lowpan6_contexts, src, dest); + if (err != ERR_OK) { + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + /* Now we copy leftover contents from p to q, so we have all L2 and L3 headers + (and L4?) in a single pbuf: */ + + /* Hide the compressed headers in p */ + pbuf_remove_header(p, lowpan6_offset); + /* Temporarily hide the headers in q... */ + pbuf_remove_header(q, ip6_offset); + /* ... copy the rest of p into q... */ + pbuf_copy(q, p); + /* ... and reveal the headers again... */ + pbuf_add_header_force(q, ip6_offset); + /* ... trim the pbuf to its correct size... */ + pbuf_realloc(q, ip6_offset + p->len); + /* ... and cat possibly remaining (data-only) pbufs */ + if (p->next != NULL) { + pbuf_cat(q, p->next); + } + /* the original (first) pbuf can now be freed */ + p->next = NULL; + pbuf_free(p); + + /* all done */ + return q; +} + +#endif /* LWIP_6LOWPAN_IPHC */ +#endif /* LWIP_IPV6 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/PPPD_FOLLOWUP b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/PPPD_FOLLOWUP new file mode 100644 index 0000000..c231982 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/PPPD_FOLLOWUP @@ -0,0 +1,473 @@ +The lwIP PPP support is based from pppd 2.4.5 (http://ppp.samba.org) with +huge changes to match code size and memory requirements for embedded devices. + +Anyway, pppd has a mature codebase for years and the average commit count +is getting low on their Git repository, meaning that we can follow what +is happening on their side and merge what is relevant for lwIP. + +So, here is the pppd follow up, so that we don't get away too far from pppd. + + +== Patch fetched from from pppd Debian packages == + +This has nothing to do with pppd, but we merged some good patch from +Debian and this is a good place to be. + +- LCP adaptive echo, so that we don't send LCP echo request if we + are receiving data from peer, can be enabled by setting PPP_LCP_ADAPTIVE + to true. + +- IPCP no/replace default route option, were added in the early stage of + the ppp port, but it wasn't really helpful and was disabled when adding + the new API ppp_set_default() call, which gives the lwIP user control over + which one is the default interface, it was actually a requirement if you + are doing PPP over PPP (i.e. PPPoL2TP, VPN link, over PPPoE, ADSL link). + +- using rp-pppoe pppd exits with EXIT_OK after receiving a timeout waiting + for PADO due to no modem attached, bug reported to pppd bug tracker, fixed + in Debian but not in the latest (at the time when the port were started) + pppd release. + + +== Commits on pppd == + +2010-03-06 - Document +ipv6 and ipv6cp-accept-local + e7537958aee79b3f653c601e903cb31d78fb7dcc + +Don't care. + + +2010-03-06 - Install pppol2tp plugins with sane permissions + 406215672cfadc03017341fe03802d1c7294b903 + +Don't care. + + +2010-03-07 - pppd: Terminate correctly if lcp_lowerup delayed calling + fsm_lowerup + 3eb9e810cfa515543655659b72dde30c54fea0a5 + +Merged 2012-05-17. + + +2010-03-07 - rp_pppoe: Copy acName and pppd_pppoe_service after option parsing + cab58617fd9d328029fffabc788020264b4fa91f + +Don't care, is a patch for pppd/plugins/rp-pppoe/plugin.c which is not part +of the port. + + +2010-08-23 - set and reset options to control environment variables + for scripts. + 2b6310fd24dba8e0fca8999916a162f0a1842a84 + +We can't fork processes in embedded, therefore all the pppd process run +feature is disabled in the port, so we don't care about the new +"environment variables" pppd feature. + + +2010-08-23 - Nit: use _exit when exec fails and restrict values to 0-255 + per POSIX. + 2b4ea140432eeba5a007c0d4e6236bd0e0c12ba4 + +Again, we are not running as a heavy process, so all exit() or _exit() calls +were removed. + + +2010-08-23 - Fix quote handling in configuration files to be more like shell + quoting. + 3089132cdf5b58dbdfc2daf08ec5c08eb47f8aca + +We are not parsing config file, all the filesystem I/O stuff were disabled +in our port. + + +2010-08-24 - rp-pppoe: allow MTU to be increased up to 1500 + fd1dcdf758418f040da3ed801ab001b5e46854e7 + +Only concern changes on RP-PPPoE plugin, which we don't use. + + +2010-09-11 - chat: Allow TIMEOUT value to come from environment variable + ae80bf833e48a6202f44a935a68083ae52ad3824 + +See 2b6310fd24dba8e0fca8999916a162f0a1842a84. + + +2011-03-05 - pppdump: Fix printfs with insufficient arguments + 7b8db569642c83ba3283745034f2e2c95e459423 + +pppdump is a ppp tool outside pppd source tree. + + +2012-05-06 - pppd: Don't unconditionally disable VJ compression under Linux + d8a66adf98a0e525cf38031b42098d539da6eeb6 + +Patch for sys-linux.c, which we don't use. + + +2012-05-20 - Remove old version of Linux if_pppol2tp.h + c41092dd4c49267f232f6cba3d31c6c68bfdf68d + +Not in the port. + + +2012-05-20 - pppd: Make MSCHAP-v2 cope better with packet loss + 08ef47ca532294eb428238c831616748940e24a2 + +This is an interesting patch. However it consumes much more memory for +MSCHAP and I am not sure if the benefit worth it. The PPP client can +always start the authentication again if it failed for whatever reason. + + +2012-05-20 - scripts: Make poff ignore extra arguments to pppd + 18f515f32c9f5723a9c2c912601e04335106534b + +Again, we are not running scripts. + + +2012-05-20 - rp-pppoe plugin: Print leading zeros in MAC address + f5dda0cfc220c4b52e26144096d729e27b30f0f7 + +Again, we are not using the RP-PPPoE plugin. + + +2012-05-20 - pppd: Notify IPv6 up/down as we do for IPv4 + 845cda8fa18939cf56e60b073f63a7efa65336fc + +This is just a patch that adds plugins hooks for IPv6, the plugin interface +was disabled because we don't have .so plugins in embedded. + + +2012-05-20 - pppd: Enable IPV6 by default and fix some warnings + 0b6118239615e98959f7e0b4e746bdd197533248 + +Change on Makefile for IPv6, warnings were already cleared during port. + + +2012-05-20 - contrib: Fix pppgetpass.gtk compilation + 80a8e2ce257ca12cce723519a0f20ea1d663b14a + +Change on Makefile, don't care. + + +2012-05-20 - pppd: Don't crash if crypt() returns NULL + 04c4348108d847e034dd91066cc6843f60d71731 + +We are using the PolarSSL DES implementation that does not return NULL. + + +2012-05-20 - pppd: Eliminate some warnings + c44ae5e6a7338c96eb463881fe709b2dfaffe568 + +Again, we are handling compilation warnings on our own. + + +2012-05-20 - rp-pppoe plugin: Import some fixes from rp-pppoe-3.10 + 1817d83e51a411044e730ba89ebdb0480e1c8cd4 + +Once more, we are not using the RP-PPPoE plugin. + + +2013-01-23 - pppd: Clarify circumstances where DNS1/DNS2 environment variables are set + cf2f5c9538b9400ade23446a194729b0a4113b3a + +Documentation only. + + +2013-02-03 - ppp: ignore unrecognised radiusclient configuration directives + 7f736dde0da3c19855997d9e67370e351e15e923 + +Radius plugin, not in the port. + + +2013-02-03 - pppd: Take out unused %r conversion completely + 356d8d558d844412119aa18c8e5a113bc6459c7b + +Merged 2014-04-15. + + +2013-02-03 - pppd: Arrange to use logwtmp from libutil on Linux + 9617a7eb137f4fee62799a677a9ecf8d834db3f5 + +Patch for sys-linux.c, which we don't use. + + +2013-02-03 - pppdump: Eliminate some compiler warnings + 3e3acf1ba2b3046c072a42c19164788a9e419bd1 + +pppdump is a ppp tool outside pppd source tree. + + +2013-02-03 - chat: Correct spelling errors in the man page + 8dea1b969d266ccbf6f3a8c5474eb6dcd8838e3b + +Documentation only. + + +2013-02-03 - pppd: Fix spelling errors in man page + 9e05a25d76b3f83096c661678010320df673df6b + +Documentation only. + + +2013-02-03 - plugins/passprompt: Fix potential out-of-bounds array reference + 8edb889b753056a691a3e4b217a110a35f9fdedb + +Plugin patch, we do not have plugins. + + +2013-02-03 - chat: Fix *roff errors in the man page + a7c3489eeaf44e83ce592143c7c8a5b5c29f4c48 + +Documentation only. + + +2013-03-02 - pppd: Fix man page description of case when remote IP address isn't known + 224841f4799f4f1e2e71bc490c54448d66740f4f + +Documentation only. + + +2013-03-02 - pppd: Add master_detach option + 398ed2585640d198c53e736ee5bbd67f7ce8168e + +Option for multilink support, we do not support multilink and this option +is about detaching from the terminal, which is out of the embedded scope. + + +2013-03-11 - pppd: Default exit status to EXIT_CONNECT_FAILED during connection phase + 225361d64ae737afdc8cb57579a2f33525461bc9 + +Commented out in our port, and already fixed by a previously applied Debian patch. + + +2013-03-11 - pppstats: Fix undefined macro in man page + d16a3985eade5280b8e171f5dd0670a91cba0d39 + +Documentation only. + + +2013-05-11 - plugins/radius: Handle bindaddr keyword in radiusclient.conf + d883b2dbafeed3ebd9d7a56ab1469373bd001a3b + +Radius plugin, not in the port. + + +2013-06-09 - pppoatm: Remove explicit loading of pppoatm kernel module + 52cd43a84bea524033b918b603698104f221bbb7 + +PPPoATM plugin, not in the port. + + +2013-06-09 - pppd: Fix segfault in update_db_entry() + 37476164f15a45015310b9d4b197c2d7db1f7f8f + +We do not use the samba db. + + +2013-06-09 - chat: Fix some text that was intended to be literal + cd9683676618adcee8add2c3cfa3382341b5a1f6 + +Documentation only. + + +2013-06-09 - README.pppoe: Minor semantic fix + b5b8898af6fd3d44e873cfc66810ace5f1f47e17 + +Documentation only. + + +2013-06-10 - radius: Handle additional attributes + 2f581cd986a56f2ec4a95abad4f8297a1b10d7e2 + +Radius plugin, not in the port. + + +2013-06-10 - chat, pppd: Use \e instead of \\ in man pages + 8d6942415d22f6ca4377340ca26e345c3f5fa5db + +Documentation only. + + +2014-01-02 - pppd: Don't crash if NULL pointer passed to vslprintf for %q or %v + 906814431bddeb2061825fa1ebad1a967b6d87a9 + +Merged 2014-04-15. + + +2014-01-02 - pppd: Accept IPCP ConfAck packets containing MS-WINS options + a243f217f1c6ac1aa7793806bc88590d077f490a + +Merged 2014-04-15. + + +2014-01-02 - config: Update Solaris compiler options and enable CHAPMS and IPV6 + 99c46caaed01b7edba87962aa52b77fad61bfd7b + +Solaris port, don't care. + + +2014-01-02 - Update README and patchlevel for 2.4.6 release + 4043750fca36e7e0eb90d702e048ad1da4929418 + +Just release stuff. + + +2014-02-18 - pppd: Add option "stop-bits" to set number of serial port stop bits. + ad993a20ee485f0d0e2ac4105221641b200da6e2 + +Low level serial port, not in the port. + + +2014-03-09 - pppd: Separate IPv6 handling for sifup/sifdown + b04d2dc6df5c6b5650fea44250d58757ee3dac4a + +Reimplemented. + + +2014-03-09 - pppol2tp: Connect up/down events to notifiers and add IPv6 ones + fafbe50251efc7d6b4a8be652d085316e112b34f + +Not in the port. + + +2014-03-09 - pppd: Add declarations to eliminate compile warnings + 50967962addebe15c7a7e63116ff46a0441dc464 + +We are handling compilation warnings on our own + + +2014-03-09 - pppd: Eliminate some unnecessary ifdefs + de8da14d845ee6db9236ccfddabf1d8ebf045ddb + +We mostly did that previously. Anyway, merged 2014-12-24. + + +2014-08-01 - radius: Fix realms-config-file option + 880a81be7c8e0fe8567227bc17a1bff3ea035943 + +Radius plugin, not in the port. + + +2014-08-01 - pppd: Eliminate potential integer overflow in option parsing + 7658e8257183f062dc01f87969c140707c7e52cb + +pppd config file parser, not in the port. + + +2014-08-01 - pppd: Eliminate memory leak with multiple instances of a string option + b94b7fbbaa0589aa6ec5fdc733aeb9ff294d2656 + +pppd config file parser, not in the port. + + +2014-08-01 - pppd: Fix a stack variable overflow in MSCHAP-v2 + 36733a891fb56594fcee580f667b33a64b990981 + +This fixes a bug introduced in 08ef47ca ("pppd: Make MSCHAP-v2 cope better with packet loss"). + +We didn't merge 08ef47ca ;-) + + +2014-08-01 - winbind plugin: Add -DMPPE=1 to eliminate compiler warnings + 2b05e22c62095e97dd0a97e4b5588402c2185071 + +Linux plugin, not in the port. + + +2014-08-09 - Update README and patchlevel for 2.4.7 release + 6e8eaa7a78b31cdab2edf140a9c8afdb02ffaca5 + +Just release stuff. + + +2014-08-10 - abort on errors in subdir builds + 5e90783d11a59268e05f4cfb29ce2343b13e8ab2 + +Linux Makefile, not in the port. + + +2014-06-03 - pppd: add support for defaultroute-metric option + 35e5a569c988b1ff865b02a24d9a727a00db4da9 + +Only necessary for Linux, lwIP does not support route metrics. + + +2014-12-13 - scripts: Avoid killing wrong pppd + 67811a647d399db5d188a242827760615a0f86b5 + +pppd helper script, not in the port. + + +2014-12-20 - pppd: Fix sign-extension when displaying bytes in octal + 5e8c3cb256a7e86e3572a82a75d51c6850efdbdc + +Merged 2016-07-02. + + +2015-03-01 - Suppress false error message on PPPoE disconnect + 219aac3b53d0827549377f1bfe22853ee52d4405 + +PPPoE plugin, not in the port. + + +2015-03-01 - Send PADT on PPPoE disconnect + cd2c14f998c57bbe6a01dc5854f2763c0d7f31fb + +PPPoE plugin, not in the port. And our PPPoE implementation already does +that: pppoe_disconnect() calls pppoe_send_padt(). + + +2015-08-14 - pppd: ipxcp: Prevent buffer overrun on remote router name + fe149de624f96629a7f46732055d8f718c74b856 + +We never ported IPX support. lwIP does not support IPX. + + +2015-03-25 - pppd: Fix ccp_options.mppe type + 234edab99a6bb250cc9ecd384cca27b0c8b475ce + +We found that while working on MPPE support in lwIP, that's our patch ;-) + + +2015-03-24 - pppd: Fix ccp_cilen calculated size if both deflate_correct and deflate_draft are enabled + 094cb8ae4c61db225e67fedadb4964f846dd0c27 + +We found that while working on MPPE support in lwIP, that's our patch ;-) + + +2015-08-14 - Merge branch 'master' of https://github.com/ncopa/ppp + 3a5c9a8fbc8970375cd881151d44e4b6fe249c6a + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'master' of git://github.com/vapier/ppp + 912e4fc6665aca188dced7ea7fdc663ce5a2dd24 + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'bug_fix' of git://github.com/radaiming/ppp + dfd33d7f526ecd7b39dd1bba8101260d02af5ebb + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'master' of git://github.com/pprindeville/ppp + aa4a985f6114d08cf4e47634fb6325da71016473 + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'no-error-on-already-closed' of git://github.com/farnz/ppp + 6edf252483b30dbcdcc5059f01831455365d5b6e + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'send-padt-on-disconnect' of git://github.com/farnz/ppp + 84684243d651f55f6df69d2a6707b52fbbe62bb9 + +Merge commit, we don't care. diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/auth.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/auth.c new file mode 100644 index 0000000..c8673ad --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/auth.c @@ -0,0 +1,2510 @@ +/* + * auth.c - PPP authentication and phase control. + * + * Copyright (c) 1993-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from main.c, which is: + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_PATH_LASTLOG) && defined(__linux__) +#include +#endif + +#include +#include +#include + +#ifdef HAS_SHADOW +#include +#ifndef PW_PPP +#define PW_PPP PW_LOGIN +#endif +#endif + +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#if CCP_SUPPORT +#include "netif/ppp/ccp.h" +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT +#include "netif/ppp/ecp.h" +#endif /* ECP_SUPPORT */ +#include "netif/ppp/ipcp.h" +#if PAP_SUPPORT +#include "netif/ppp/upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "netif/ppp/eap.h" +#endif /* EAP_SUPPORT */ +#if CBCP_SUPPORT +#include "netif/ppp/cbcp.h" +#endif + +#if 0 /* UNUSED */ +#include "session.h" +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* Bits in scan_authfile return value */ +#define NONWILD_SERVER 1 +#define NONWILD_CLIENT 2 + +#define ISWILD(word) (word[0] == '*' && word[1] == 0) +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* List of addresses which the peer may use. */ +static struct permitted_ip *addresses[NUM_PPP]; + +/* Wordlist giving addresses which the peer may use + without authenticating itself. */ +static struct wordlist *noauth_addrs; + +/* Remote telephone number, if available */ +char remote_number[MAXNAMELEN]; + +/* Wordlist giving remote telephone numbers which may connect. */ +static struct wordlist *permitted_numbers; + +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* Set if we require authentication only because we have a default route. */ +static bool default_auth; + +/* Hook to enable a plugin to control the idle time limit */ +int (*idle_time_hook) (struct ppp_idle *) = NULL; + +/* Hook for a plugin to say whether we can possibly authenticate any peer */ +int (*pap_check_hook) (void) = NULL; + +/* Hook for a plugin to check the PAP user and password */ +int (*pap_auth_hook) (char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts) = NULL; + +/* Hook for a plugin to know about the PAP user logout */ +void (*pap_logout_hook) (void) = NULL; + +/* Hook for a plugin to get the PAP password for authenticating us */ +int (*pap_passwd_hook) (char *user, char *passwd) = NULL; + +/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */ +int (*chap_check_hook) (void) = NULL; + +/* Hook for a plugin to get the CHAP password for authenticating us */ +int (*chap_passwd_hook) (char *user, char *passwd) = NULL; + +/* Hook for a plugin to say whether it is OK if the peer + refuses to authenticate. */ +int (*null_auth_hook) (struct wordlist **paddrs, + struct wordlist **popts) = NULL; + +int (*allowed_address_hook) (u32_t addr) = NULL; +#endif /* UNUSED */ + +#ifdef HAVE_MULTILINK +/* Hook for plugin to hear when an interface joins a multilink bundle */ +void (*multilink_join_hook) (void) = NULL; +#endif + +#if PPP_NOTIFY +/* A notifier for when the peer has authenticated itself, + and we are proceeding to the network phase. */ +struct notifier *auth_up_notifier = NULL; + +/* A notifier for when the link goes down. */ +struct notifier *link_down_notifier = NULL; +#endif /* PPP_NOTIFY */ + +/* + * Option variables. + */ +#if 0 /* MOVED TO ppp_settings */ +bool uselogin = 0; /* Use /etc/passwd for checking PAP */ +bool session_mgmt = 0; /* Do session management (login records) */ +bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ +bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ +bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ +bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */ +#if MSCHAP_SUPPORT +bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */ +bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */ +#else /* MSCHAP_SUPPORT */ +bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */ +bool refuse_mschap_v2 = 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */ +#endif /* MSCHAP_SUPPORT */ +bool usehostname = 0; /* Use hostname for our_name */ +bool auth_required = 0; /* Always require authentication from peer */ +bool allow_any_ip = 0; /* Allow peer to use any IP address */ +bool explicit_remote = 0; /* User specified explicit remote name */ +bool explicit_user = 0; /* Set if "user" option supplied */ +bool explicit_passwd = 0; /* Set if "password" option supplied */ +char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +static char *uafname; /* name of most recent +ua file */ + +extern char *crypt (const char *, const char *); +#endif /* UNUSED */ +/* Prototypes for procedures local to this file. */ + +static void network_phase(ppp_pcb *pcb); +#if PPP_IDLETIMELIMIT +static void check_idle(void *arg); +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT +static void connect_time_expired(void *arg); +#endif /* PPP_MAXCONNECT */ +#if 0 /* UNUSED */ +static int null_login (int); +/* static int get_pap_passwd (char *); */ +static int have_pap_secret (int *); +static int have_chap_secret (char *, char *, int, int *); +static int have_srp_secret (char *client, char *server, int need_ip, + int *lacks_ipp); +static int ip_addr_check (u32_t, struct permitted_ip *); +static int scan_authfile (FILE *, char *, char *, char *, + struct wordlist **, struct wordlist **, + char *, int); +static void free_wordlist (struct wordlist *); +static void set_allowed_addrs (int, struct wordlist *, struct wordlist *); +static int some_ip_ok (struct wordlist *); +static int setupapfile (char **); +static int privgroup (char **); +static int set_noauth_addr (char **); +static int set_permitted_number (char **); +static void check_access (FILE *, char *); +static int wordlist_count (struct wordlist *); +#endif /* UNUSED */ + +#ifdef MAXOCTETS +static void check_maxoctets (void *); +#endif + +#if PPP_OPTIONS +/* + * Authentication-related options. + */ +option_t auth_options[] = { + { "auth", o_bool, &auth_required, + "Require authentication from peer", OPT_PRIO | 1 }, + { "noauth", o_bool, &auth_required, + "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV, + &allow_any_ip }, + { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", + OPT_PRIOSUB | 1, &auth_required }, + { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required }, + { "require-chap", o_bool, &auth_required, + "Require CHAP authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, + &lcp_wantoptions[0].chap_mdtype }, + { "+chap", o_bool, &auth_required, + "Require CHAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, + &lcp_wantoptions[0].chap_mdtype }, +#if MSCHAP_SUPPORT + { "require-mschap", o_bool, &auth_required, + "Require MS-CHAP authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, + &lcp_wantoptions[0].chap_mdtype }, + { "+mschap", o_bool, &auth_required, + "Require MS-CHAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, + &lcp_wantoptions[0].chap_mdtype }, + { "require-mschap-v2", o_bool, &auth_required, + "Require MS-CHAPv2 authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, + &lcp_wantoptions[0].chap_mdtype }, + { "+mschap-v2", o_bool, &auth_required, + "Require MS-CHAPv2 authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, + &lcp_wantoptions[0].chap_mdtype }, +#endif /* MSCHAP_SUPPORT */ +#if 0 + { "refuse-pap", o_bool, &refuse_pap, + "Don't agree to auth to peer with PAP", 1 }, + { "-pap", o_bool, &refuse_pap, + "Don't allow PAP authentication with peer", OPT_ALIAS | 1 }, + { "refuse-chap", o_bool, &refuse_chap, + "Don't agree to auth to peer with CHAP", + OPT_A2CLRB | MDTYPE_MD5, + &lcp_allowoptions[0].chap_mdtype }, + { "-chap", o_bool, &refuse_chap, + "Don't allow CHAP authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5, + &lcp_allowoptions[0].chap_mdtype }, +#endif +#if MSCHAP_SUPPORT +#if 0 + { "refuse-mschap", o_bool, &refuse_mschap, + "Don't agree to auth to peer with MS-CHAP", + OPT_A2CLRB | MDTYPE_MICROSOFT, + &lcp_allowoptions[0].chap_mdtype }, + { "-mschap", o_bool, &refuse_mschap, + "Don't allow MS-CHAP authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT, + &lcp_allowoptions[0].chap_mdtype }, + { "refuse-mschap-v2", o_bool, &refuse_mschap_v2, + "Don't agree to auth to peer with MS-CHAPv2", + OPT_A2CLRB | MDTYPE_MICROSOFT_V2, + &lcp_allowoptions[0].chap_mdtype }, + { "-mschap-v2", o_bool, &refuse_mschap_v2, + "Don't allow MS-CHAPv2 authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2, + &lcp_allowoptions[0].chap_mdtype }, +#endif +#endif /* MSCHAP_SUPPORT*/ +#if EAP_SUPPORT + { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap, + "Require EAP authentication from peer", OPT_PRIOSUB | 1, + &auth_required }, +#if 0 + { "refuse-eap", o_bool, &refuse_eap, + "Don't agree to authenticate to peer with EAP", 1 }, +#endif +#endif /* EAP_SUPPORT */ + { "name", o_string, our_name, + "Set local name for authentication", + OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN }, + + { "+ua", o_special, (void *)setupapfile, + "Get PAP user and password from file", + OPT_PRIO | OPT_A2STRVAL, &uafname }, + +#if 0 + { "user", o_string, user, + "Set name for auth with peer", OPT_PRIO | OPT_STATIC, + &explicit_user, MAXNAMELEN }, + + { "password", o_string, passwd, + "Password for authenticating us to the peer", + OPT_PRIO | OPT_STATIC | OPT_HIDE, + &explicit_passwd, MAXSECRETLEN }, +#endif + + { "usehostname", o_bool, &usehostname, + "Must use hostname for authentication", 1 }, + + { "remotename", o_string, remote_name, + "Set remote name for authentication", OPT_PRIO | OPT_STATIC, + &explicit_remote, MAXNAMELEN }, + + { "login", o_bool, &uselogin, + "Use system password database for PAP", OPT_A2COPY | 1 , + &session_mgmt }, + { "enable-session", o_bool, &session_mgmt, + "Enable session accounting for remote peers", OPT_PRIV | 1 }, + + { "papcrypt", o_bool, &cryptpap, + "PAP passwords are encrypted", 1 }, + + { "privgroup", o_special, (void *)privgroup, + "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST }, + + { "allow-ip", o_special, (void *)set_noauth_addr, + "Set IP address(es) which can be used without authentication", + OPT_PRIV | OPT_A2LIST }, + + { "remotenumber", o_string, remote_number, + "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC, + NULL, MAXNAMELEN }, + + { "allow-number", o_special, (void *)set_permitted_number, + "Set telephone number(s) which are allowed to connect", + OPT_PRIV | OPT_A2LIST }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +#if 0 /* UNUSED */ +/* + * setupapfile - specifies UPAP info for authenticating with peer. + */ +static int +setupapfile(argv) + char **argv; +{ + FILE *ufile; + int l; + uid_t euid; + char u[MAXNAMELEN], p[MAXSECRETLEN]; + char *fname; + + lcp_allowoptions[0].neg_upap = 1; + + /* open user info file */ + fname = strdup(*argv); + if (fname == NULL) + novm("+ua file name"); + euid = geteuid(); + if (seteuid(getuid()) == -1) { + option_error("unable to reset uid before opening %s: %m", fname); + return 0; + } + ufile = fopen(fname, "r"); + if (seteuid(euid) == -1) + fatal("unable to regain privileges: %m"); + if (ufile == NULL) { + option_error("unable to open user login data file %s", fname); + return 0; + } + check_access(ufile, fname); + uafname = fname; + + /* get username */ + if (fgets(u, MAXNAMELEN - 1, ufile) == NULL + || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) { + fclose(ufile); + option_error("unable to read user login data file %s", fname); + return 0; + } + fclose(ufile); + + /* get rid of newlines */ + l = strlen(u); + if (l > 0 && u[l-1] == '\n') + u[l-1] = 0; + l = strlen(p); + if (l > 0 && p[l-1] == '\n') + p[l-1] = 0; + + if (override_value("user", option_priority, fname)) { + strlcpy(ppp_settings.user, u, sizeof(ppp_settings.user)); + explicit_user = 1; + } + if (override_value("passwd", option_priority, fname)) { + strlcpy(ppp_settings.passwd, p, sizeof(ppp_settings.passwd)); + explicit_passwd = 1; + } + + return (1); +} + +/* + * privgroup - allow members of the group to have privileged access. + */ +static int +privgroup(argv) + char **argv; +{ + struct group *g; + int i; + + g = getgrnam(*argv); + if (g == 0) { + option_error("group %s is unknown", *argv); + return 0; + } + for (i = 0; i < ngroups; ++i) { + if (groups[i] == g->gr_gid) { + privileged = 1; + break; + } + } + return 1; +} + + +/* + * set_noauth_addr - set address(es) that can be used without authentication. + * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. + */ +static int +set_noauth_addr(argv) + char **argv; +{ + char *addr = *argv; + int l = strlen(addr) + 1; + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); + if (wp == NULL) + novm("allow-ip argument"); + wp->word = (char *) (wp + 1); + wp->next = noauth_addrs; + MEMCPY(wp->word, addr, l); + noauth_addrs = wp; + return 1; +} + + +/* + * set_permitted_number - set remote telephone number(s) that may connect. + */ +static int +set_permitted_number(argv) + char **argv; +{ + char *number = *argv; + int l = strlen(number) + 1; + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); + if (wp == NULL) + novm("allow-number argument"); + wp->word = (char *) (wp + 1); + wp->next = permitted_numbers; + MEMCPY(wp->word, number, l); + permitted_numbers = wp; + return 1; +} +#endif + +/* + * An Open on LCP has requested a change from Dead to Establish phase. + */ +void link_required(ppp_pcb *pcb) { + LWIP_UNUSED_ARG(pcb); +} + +#if 0 +/* + * Bring the link up to the point of being able to do ppp. + */ +void start_link(unit) + int unit; +{ + ppp_pcb *pcb = &ppp_pcb_list[unit]; + char *msg; + + status = EXIT_NEGOTIATION_FAILED; + new_phase(pcb, PPP_PHASE_SERIALCONN); + + hungup = 0; + devfd = the_channel->connect(); + msg = "Connect script failed"; + if (devfd < 0) + goto fail; + + /* set up the serial device as a ppp interface */ + /* + * N.B. we used to do tdb_writelock/tdb_writeunlock around this + * (from establish_ppp to set_ifunit). However, we won't be + * doing the set_ifunit in multilink mode, which is the only time + * we need the atomicity that the tdb_writelock/tdb_writeunlock + * gives us. Thus we don't need the tdb_writelock/tdb_writeunlock. + */ + fd_ppp = the_channel->establish_ppp(devfd); + msg = "ppp establishment failed"; + if (fd_ppp < 0) { + status = EXIT_FATAL_ERROR; + goto disconnect; + } + + if (!demand && ifunit >= 0) + set_ifunit(1); + + /* + * Start opening the connection and wait for + * incoming events (reply, timeout, etc.). + */ + if (ifunit >= 0) + ppp_notice("Connect: %s <--> %s", ifname, ppp_devnam); + else + ppp_notice("Starting negotiation on %s", ppp_devnam); + add_fd(fd_ppp); + + new_phase(pcb, PPP_PHASE_ESTABLISH); + + lcp_lowerup(pcb); + return; + + disconnect: + new_phase(pcb, PPP_PHASE_DISCONNECT); + if (the_channel->disconnect) + the_channel->disconnect(); + + fail: + new_phase(pcb, PPP_PHASE_DEAD); + if (the_channel->cleanup) + (*the_channel->cleanup)(); +} +#endif + +/* + * LCP has terminated the link; go to the Dead phase and take the + * physical layer down. + */ +void link_terminated(ppp_pcb *pcb) { + if (pcb->phase == PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + || pcb->phase == PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + return; + new_phase(pcb, PPP_PHASE_DISCONNECT); + +#if 0 /* UNUSED */ + if (pap_logout_hook) { + pap_logout_hook(); + } + session_end(devnam); +#endif /* UNUSED */ + + if (!doing_multilink) { + ppp_notice("Connection terminated."); +#if PPP_STATS_SUPPORT + print_link_stats(); +#endif /* PPP_STATS_SUPPORT */ + } else + ppp_notice("Link terminated."); + + lcp_lowerdown(pcb); + + ppp_link_terminated(pcb); +#if 0 + /* + * Delete pid files before disestablishing ppp. Otherwise it + * can happen that another pppd gets the same unit and then + * we delete its pid file. + */ + if (!doing_multilink && !demand) + remove_pidfiles(); + + /* + * If we may want to bring the link up again, transfer + * the ppp unit back to the loopback. Set the + * real serial device back to its normal mode of operation. + */ + if (fd_ppp >= 0) { + remove_fd(fd_ppp); + clean_check(); + the_channel->disestablish_ppp(devfd); + if (doing_multilink) + mp_exit_bundle(); + fd_ppp = -1; + } + if (!hungup) + lcp_lowerdown(pcb); + if (!doing_multilink && !demand) + script_unsetenv("IFNAME"); + + /* + * Run disconnector script, if requested. + * XXX we may not be able to do this if the line has hung up! + */ + if (devfd >= 0 && the_channel->disconnect) { + the_channel->disconnect(); + devfd = -1; + } + if (the_channel->cleanup) + (*the_channel->cleanup)(); + + if (doing_multilink && multilink_master) { + if (!bundle_terminating) + new_phase(pcb, PPP_PHASE_MASTER); + else + mp_bundle_terminated(); + } else + new_phase(pcb, PPP_PHASE_DEAD); +#endif +} + +/* + * LCP has gone down; it will either die or try to re-establish. + */ +void link_down(ppp_pcb *pcb) { +#if PPP_NOTIFY + notify(link_down_notifier, 0); +#endif /* PPP_NOTIFY */ + + if (!doing_multilink) { + upper_layers_down(pcb); + if (pcb->phase != PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + && pcb->phase != PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + new_phase(pcb, PPP_PHASE_ESTABLISH); + } + /* XXX if doing_multilink, should do something to stop + network-layer traffic on the link */ +} + +void upper_layers_down(ppp_pcb *pcb) { + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) + (*protp->lowerdown)(pcb); + if (protp->protocol < 0xC000 && protp->close != NULL) + (*protp->close)(pcb, "LCP down"); + } + pcb->num_np_open = 0; + pcb->num_np_up = 0; +} + +/* + * The link is established. + * Proceed to the Dead, Authenticate or Network phase as appropriate. + */ +void link_established(ppp_pcb *pcb) { +#if PPP_AUTH_SUPPORT + int auth; +#if PPP_SERVER +#if PAP_SUPPORT + lcp_options *wo = &pcb->lcp_wantoptions; +#endif /* PAP_SUPPORT */ + lcp_options *go = &pcb->lcp_gotoptions; +#endif /* PPP_SERVER */ + lcp_options *ho = &pcb->lcp_hisoptions; +#endif /* PPP_AUTH_SUPPORT */ + int i; + const struct protent *protp; + + /* + * Tell higher-level protocols that LCP is up. + */ + if (!doing_multilink) { + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol != PPP_LCP + && protp->lowerup != NULL) + (*protp->lowerup)(pcb); + } + +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +#if PPP_ALLOWED_ADDRS + if (!auth_required && noauth_addrs != NULL) + set_allowed_addrs(unit, NULL, NULL); +#endif /* PPP_ALLOWED_ADDRS */ + + if (pcb->settings.auth_required && !(0 +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + )) { + +#if PPP_ALLOWED_ADDRS + /* + * We wanted the peer to authenticate itself, and it refused: + * if we have some address(es) it can use without auth, fine, + * otherwise treat it as though it authenticated with PAP using + * a username of "" and a password of "". If that's not OK, + * boot it out. + */ + if (noauth_addrs != NULL) { + set_allowed_addrs(unit, NULL, NULL); + } else +#endif /* PPP_ALLOWED_ADDRS */ + if (!pcb->settings.null_login +#if PAP_SUPPORT + || !wo->neg_upap +#endif /* PAP_SUPPORT */ + ) { + ppp_warn("peer refused to authenticate: terminating link"); +#if 0 /* UNUSED */ + status = EXIT_PEER_AUTH_FAILED; +#endif /* UNUSED */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "peer refused to authenticate"); + return; + } + } +#endif /* PPP_SERVER */ + + new_phase(pcb, PPP_PHASE_AUTHENTICATE); + auth = 0; +#if PPP_SERVER +#if EAP_SUPPORT + if (go->neg_eap) { + eap_authpeer(pcb, PPP_OUR_NAME); + auth |= EAP_PEER; + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (go->neg_chap) { + chap_auth_peer(pcb, PPP_OUR_NAME, CHAP_DIGEST(go->chap_mdtype)); + auth |= CHAP_PEER; + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if (go->neg_upap) { + upap_authpeer(pcb); + auth |= PAP_PEER; + } else +#endif /* PAP_SUPPORT */ + {} +#endif /* PPP_SERVER */ + +#if EAP_SUPPORT + if (ho->neg_eap) { + eap_authwithpeer(pcb, pcb->settings.user); + auth |= EAP_WITHPEER; + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (ho->neg_chap) { + chap_auth_with_peer(pcb, pcb->settings.user, CHAP_DIGEST(ho->chap_mdtype)); + auth |= CHAP_WITHPEER; + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if (ho->neg_upap) { + upap_authwithpeer(pcb, pcb->settings.user, pcb->settings.passwd); + auth |= PAP_WITHPEER; + } else +#endif /* PAP_SUPPORT */ + {} + + pcb->auth_pending = auth; + pcb->auth_done = 0; + + if (!auth) +#endif /* PPP_AUTH_SUPPORT */ + network_phase(pcb); +} + +/* + * Proceed to the network phase. + */ +static void network_phase(ppp_pcb *pcb) { +#if CBCP_SUPPORT + ppp_pcb *pcb = &ppp_pcb_list[unit]; +#endif +#if 0 /* UNUSED */ + lcp_options *go = &lcp_gotoptions[unit]; +#endif /* UNUSED */ + +#if 0 /* UNUSED */ + /* Log calling number. */ + if (*remote_number) + ppp_notice("peer from calling number %q authorized", remote_number); +#endif /* UNUSED */ + +#if PPP_NOTIFY + /* + * If the peer had to authenticate, notify it now. + */ + if (0 +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + ) { + notify(auth_up_notifier, 0); + } +#endif /* PPP_NOTIFY */ + +#if CBCP_SUPPORT + /* + * If we negotiated callback, do it now. + */ + if (go->neg_cbcp) { + new_phase(pcb, PPP_PHASE_CALLBACK); + (*cbcp_protent.open)(pcb); + return; + } +#endif + +#if PPP_OPTIONS + /* + * Process extra options from the secrets file + */ + if (extra_options) { + options_from_list(extra_options, 1); + free_wordlist(extra_options); + extra_options = 0; + } +#endif /* PPP_OPTIONS */ + start_networks(pcb); +} + +void start_networks(ppp_pcb *pcb) { +#if CCP_SUPPORT || ECP_SUPPORT + int i; + const struct protent *protp; +#endif /* CCP_SUPPORT || ECP_SUPPORT */ + + new_phase(pcb, PPP_PHASE_NETWORK); + +#ifdef HAVE_MULTILINK + if (multilink) { + if (mp_join_bundle()) { + if (multilink_join_hook) + (*multilink_join_hook)(); + if (updetach && !nodetach) + detach(); + return; + } + } +#endif /* HAVE_MULTILINK */ + +#ifdef PPP_FILTER + if (!demand) + set_filters(&pass_filter, &active_filter); +#endif +#if CCP_SUPPORT || ECP_SUPPORT + /* Start CCP and ECP */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if ( + (0 +#if ECP_SUPPORT + || protp->protocol == PPP_ECP +#endif /* ECP_SUPPORT */ +#if CCP_SUPPORT + || protp->protocol == PPP_CCP +#endif /* CCP_SUPPORT */ + ) + && protp->open != NULL) + (*protp->open)(pcb); +#endif /* CCP_SUPPORT || ECP_SUPPORT */ + + /* + * Bring up other network protocols iff encryption is not required. + */ + if (1 +#if ECP_SUPPORT + && !ecp_gotoptions[unit].required +#endif /* ECP_SUPPORT */ +#if MPPE_SUPPORT + && !pcb->ccp_gotoptions.mppe +#endif /* MPPE_SUPPORT */ + ) + continue_networks(pcb); +} + +void continue_networks(ppp_pcb *pcb) { + int i; + const struct protent *protp; + + /* + * Start the "real" network protocols. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol < 0xC000 +#if CCP_SUPPORT + && protp->protocol != PPP_CCP +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT + && protp->protocol != PPP_ECP +#endif /* ECP_SUPPORT */ + && protp->open != NULL) { + (*protp->open)(pcb); + ++pcb->num_np_open; + } + + if (pcb->num_np_open == 0) + /* nothing to do */ + lcp_close(pcb, "No network protocols running"); +} + +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +/* + * auth_check_passwd - Check the user name and passwd against configuration. + * + * returns: + * 0: Authentication failed. + * 1: Authentication succeeded. + * In either case, msg points to an appropriate message and msglen to the message len. + */ +int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen) { + int secretuserlen; + int secretpasswdlen; + + if (pcb->settings.user && pcb->settings.passwd) { + secretuserlen = (int)strlen(pcb->settings.user); + secretpasswdlen = (int)strlen(pcb->settings.passwd); + if (secretuserlen == userlen + && secretpasswdlen == passwdlen + && !memcmp(auser, pcb->settings.user, userlen) + && !memcmp(apasswd, pcb->settings.passwd, passwdlen) ) { + *msg = "Login ok"; + *msglen = sizeof("Login ok")-1; + return 1; + } + } + + *msg = "Login incorrect"; + *msglen = sizeof("Login incorrect")-1; + return 0; +} + +/* + * The peer has failed to authenticate himself using `protocol'. + */ +void auth_peer_fail(ppp_pcb *pcb, int protocol) { + LWIP_UNUSED_ARG(protocol); + /* + * Authentication failure: take the link down + */ +#if 0 /* UNUSED */ + status = EXIT_PEER_AUTH_FAILED; +#endif /* UNUSED */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "Authentication failed"); +} + +/* + * The peer has been successfully authenticated using `protocol'. + */ +void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen) { + int bit; +#ifndef HAVE_MULTILINK + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(namelen); +#endif /* HAVE_MULTILINK */ + + switch (protocol) { +#if CHAP_SUPPORT + case PPP_CHAP: + bit = CHAP_PEER; + switch (prot_flavor) { + case CHAP_MD5: + bit |= CHAP_MD5_PEER; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + bit |= CHAP_MS_PEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_PEER; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + break; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + case PPP_PAP: + bit = PAP_PEER; + break; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + bit = EAP_PEER; + break; +#endif /* EAP_SUPPORT */ + default: + ppp_warn("auth_peer_success: unknown protocol %x", protocol); + return; + } + +#ifdef HAVE_MULTILINK + /* + * Save the authenticated name of the peer for later. + */ + if (namelen > (int)sizeof(pcb->peer_authname) - 1) + namelen = (int)sizeof(pcb->peer_authname) - 1; + MEMCPY(pcb->peer_authname, name, namelen); + pcb->peer_authname[namelen] = 0; +#endif /* HAVE_MULTILINK */ +#if 0 /* UNUSED */ + script_setenv("PEERNAME", , 0); +#endif /* UNUSED */ + + /* Save the authentication method for later. */ + pcb->auth_done |= bit; + + /* + * If there is no more authentication still to be done, + * proceed to the network (or callback) phase. + */ + if ((pcb->auth_pending &= ~bit) == 0) + network_phase(pcb); +} +#endif /* PPP_SERVER */ + +/* + * We have failed to authenticate ourselves to the peer using `protocol'. + */ +void auth_withpeer_fail(ppp_pcb *pcb, int protocol) { + LWIP_UNUSED_ARG(protocol); + /* + * We've failed to authenticate ourselves to our peer. + * + * Some servers keep sending CHAP challenges, but there + * is no point in persisting without any way to get updated + * authentication secrets. + * + * He'll probably take the link down, and there's not much + * we can do except wait for that. + */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "Failed to authenticate ourselves to peer"); +} + +/* + * We have successfully authenticated ourselves with the peer using `protocol'. + */ +void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { + int bit; + const char *prot = ""; + + switch (protocol) { +#if CHAP_SUPPORT + case PPP_CHAP: + bit = CHAP_WITHPEER; + prot = "CHAP"; + switch (prot_flavor) { + case CHAP_MD5: + bit |= CHAP_MD5_WITHPEER; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + bit |= CHAP_MS_WITHPEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_WITHPEER; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + break; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + case PPP_PAP: + bit = PAP_WITHPEER; + prot = "PAP"; + break; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + bit = EAP_WITHPEER; + prot = "EAP"; + break; +#endif /* EAP_SUPPORT */ + default: + ppp_warn("auth_withpeer_success: unknown protocol %x", protocol); + bit = 0; + /* no break */ + } + + ppp_notice("%s authentication succeeded", prot); + + /* Save the authentication method for later. */ + pcb->auth_done |= bit; + + /* + * If there is no more authentication still being done, + * proceed to the network (or callback) phase. + */ + if ((pcb->auth_pending &= ~bit) == 0) + network_phase(pcb); +} +#endif /* PPP_AUTH_SUPPORT */ + + +/* + * np_up - a network protocol has come up. + */ +void np_up(ppp_pcb *pcb, int proto) { +#if PPP_IDLETIMELIMIT + int tlim; +#endif /* PPP_IDLETIMELIMIT */ + LWIP_UNUSED_ARG(proto); + + if (pcb->num_np_up == 0) { + /* + * At this point we consider that the link has come up successfully. + */ + new_phase(pcb, PPP_PHASE_RUNNING); + +#if PPP_IDLETIMELIMIT +#if 0 /* UNUSED */ + if (idle_time_hook != 0) + tlim = (*idle_time_hook)(NULL); + else +#endif /* UNUSED */ + tlim = pcb->settings.idle_time_limit; + if (tlim > 0) + TIMEOUT(check_idle, (void*)pcb, tlim); +#endif /* PPP_IDLETIMELIMIT */ + +#if PPP_MAXCONNECT + /* + * Set a timeout to close the connection once the maximum + * connect time has expired. + */ + if (pcb->settings.maxconnect > 0) + TIMEOUT(connect_time_expired, (void*)pcb, pcb->settings.maxconnect); +#endif /* PPP_MAXCONNECT */ + +#ifdef MAXOCTETS + if (maxoctets > 0) + TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); +#endif + +#if 0 /* Unused */ + /* + * Detach now, if the updetach option was given. + */ + if (updetach && !nodetach) + detach(); +#endif /* Unused */ + } + ++pcb->num_np_up; +} + +/* + * np_down - a network protocol has gone down. + */ +void np_down(ppp_pcb *pcb, int proto) { + LWIP_UNUSED_ARG(proto); + if (--pcb->num_np_up == 0) { +#if PPP_IDLETIMELIMIT + UNTIMEOUT(check_idle, (void*)pcb); +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT + UNTIMEOUT(connect_time_expired, NULL); +#endif /* PPP_MAXCONNECT */ +#ifdef MAXOCTETS + UNTIMEOUT(check_maxoctets, NULL); +#endif + new_phase(pcb, PPP_PHASE_NETWORK); + } +} + +/* + * np_finished - a network protocol has finished using the link. + */ +void np_finished(ppp_pcb *pcb, int proto) { + LWIP_UNUSED_ARG(proto); + if (--pcb->num_np_open <= 0) { + /* no further use for the link: shut up shop. */ + lcp_close(pcb, "No network protocols running"); + } +} + +#ifdef MAXOCTETS +static void +check_maxoctets(arg) + void *arg; +{ +#if PPP_STATS_SUPPORT + unsigned int used; + + update_link_stats(ifunit); + link_stats_valid=0; + + switch(maxoctets_dir) { + case PPP_OCTETS_DIRECTION_IN: + used = link_stats.bytes_in; + break; + case PPP_OCTETS_DIRECTION_OUT: + used = link_stats.bytes_out; + break; + case PPP_OCTETS_DIRECTION_MAXOVERAL: + case PPP_OCTETS_DIRECTION_MAXSESSION: + used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out; + break; + default: + used = link_stats.bytes_in+link_stats.bytes_out; + break; + } + if (used > maxoctets) { + ppp_notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); + status = EXIT_TRAFFIC_LIMIT; + lcp_close(pcb, "Traffic limit"); +#if 0 /* UNUSED */ + need_holdoff = 0; +#endif /* UNUSED */ + } else { + TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); + } +#endif /* PPP_STATS_SUPPORT */ +} +#endif /* MAXOCTETS */ + +#if PPP_IDLETIMELIMIT +/* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void check_idle(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + struct ppp_idle idle; + time_t itime; + int tlim; + + if (!get_idle_time(pcb, &idle)) + return; +#if 0 /* UNUSED */ + if (idle_time_hook != 0) { + tlim = idle_time_hook(&idle); + } else { +#endif /* UNUSED */ + itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); + tlim = pcb->settings.idle_time_limit - itime; +#if 0 /* UNUSED */ + } +#endif /* UNUSED */ + if (tlim <= 0) { + /* link is idle: shut it down. */ + ppp_notice("Terminating connection due to lack of activity."); + pcb->err_code = PPPERR_IDLETIMEOUT; + lcp_close(pcb, "Link inactive"); +#if 0 /* UNUSED */ + need_holdoff = 0; +#endif /* UNUSED */ + } else { + TIMEOUT(check_idle, (void*)pcb, tlim); + } +} +#endif /* PPP_IDLETIMELIMIT */ + +#if PPP_MAXCONNECT +/* + * connect_time_expired - log a message and close the connection. + */ +static void connect_time_expired(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + ppp_info("Connect time expired"); + pcb->err_code = PPPERR_CONNECTTIME; + lcp_close(pcb, "Connect time expired"); /* Close connection */ +} +#endif /* PPP_MAXCONNECT */ + +#if PPP_OPTIONS +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options() +{ + lcp_options *wo = &lcp_wantoptions[0]; + int can_auth; + int lacks_ip; + + /* Default our_name to hostname, and user to our_name */ + if (our_name[0] == 0 || usehostname) + strlcpy(our_name, hostname, sizeof(our_name)); + /* If a blank username was explicitly given as an option, trust + the user and don't use our_name */ + if (ppp_settings.user[0] == 0 && !explicit_user) + strlcpy(ppp_settings.user, our_name, sizeof(ppp_settings.user)); + + /* + * If we have a default route, require the peer to authenticate + * unless the noauth option was given or the real user is root. + */ + if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) { + auth_required = 1; + default_auth = 1; + } + +#if CHAP_SUPPORT + /* If we selected any CHAP flavors, we should probably negotiate it. :-) */ + if (wo->chap_mdtype) + wo->neg_chap = 1; +#endif /* CHAP_SUPPORT */ + + /* If authentication is required, ask peer for CHAP, PAP, or EAP. */ + if (auth_required) { + allow_any_ip = 0; + if (1 +#if CHAP_SUPPORT + && !wo->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + && !wo->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + && !wo->neg_eap +#endif /* EAP_SUPPORT */ + ) { +#if CHAP_SUPPORT + wo->neg_chap = CHAP_MDTYPE_SUPPORTED != MDTYPE_NONE; + wo->chap_mdtype = CHAP_MDTYPE_SUPPORTED; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + wo->neg_upap = 1; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + wo->neg_eap = 1; +#endif /* EAP_SUPPORT */ + } + } else { +#if CHAP_SUPPORT + wo->neg_chap = 0; + wo->chap_mdtype = MDTYPE_NONE; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + wo->neg_upap = 0; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + wo->neg_eap = 0; +#endif /* EAP_SUPPORT */ + } + + /* + * Check whether we have appropriate secrets to use + * to authenticate the peer. Note that EAP can authenticate by way + * of a CHAP-like exchanges as well as SRP. + */ + lacks_ip = 0; +#if PAP_SUPPORT + can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); +#else + can_auth = 0; +#endif /* PAP_SUPPORT */ + if (!can_auth && (0 +#if CHAP_SUPPORT + || wo->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || wo->neg_eap +#endif /* EAP_SUPPORT */ + )) { +#if CHAP_SUPPORT + can_auth = have_chap_secret((explicit_remote? remote_name: NULL), + our_name, 1, &lacks_ip); +#else + can_auth = 0; +#endif + } + if (!can_auth +#if EAP_SUPPORT + && wo->neg_eap +#endif /* EAP_SUPPORT */ + ) { + can_auth = have_srp_secret((explicit_remote? remote_name: NULL), + our_name, 1, &lacks_ip); + } + + if (auth_required && !can_auth && noauth_addrs == NULL) { + if (default_auth) { + option_error( +"By default the remote system is required to authenticate itself"); + option_error( +"(because this system has a default route to the internet)"); + } else if (explicit_remote) + option_error( +"The remote system (%s) is required to authenticate itself", + remote_name); + else + option_error( +"The remote system is required to authenticate itself"); + option_error( +"but I couldn't find any suitable secret (password) for it to use to do so."); + if (lacks_ip) + option_error( +"(None of the available passwords would let it use an IP address.)"); + + exit(1); + } + + /* + * Early check for remote number authorization. + */ + if (!auth_number()) { + ppp_warn("calling number %q is not authorized", remote_number); + exit(EXIT_CNID_AUTH_FAILED); + } +} +#endif /* PPP_OPTIONS */ + +#if 0 /* UNUSED */ +/* + * auth_reset - called when LCP is starting negotiations to recheck + * authentication options, i.e. whether we have appropriate secrets + * to use for authenticating ourselves and/or the peer. + */ +void +auth_reset(unit) + int unit; +{ + lcp_options *go = &lcp_gotoptions[unit]; + lcp_options *ao = &lcp_allowoptions[unit]; + int hadchap; + + hadchap = -1; + ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL)); + ao->neg_chap = (!refuse_chap || !refuse_mschap || !refuse_mschap_v2) + && (passwd[0] != 0 || + (hadchap = have_chap_secret(user, (explicit_remote? remote_name: + NULL), 0, NULL))); + ao->neg_eap = !refuse_eap && ( + passwd[0] != 0 || + (hadchap == 1 || (hadchap == -1 && have_chap_secret(user, + (explicit_remote? remote_name: NULL), 0, NULL))) || + have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)); + + hadchap = -1; + if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) + go->neg_upap = 0; + if (go->neg_chap) { + if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL), + our_name, 1, NULL))) + go->neg_chap = 0; + } + if (go->neg_eap && + (hadchap == 0 || (hadchap == -1 && + !have_chap_secret((explicit_remote? remote_name: NULL), our_name, + 1, NULL))) && + !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, + NULL)) + go->neg_eap = 0; +} + +/* + * check_passwd - Check the user name and passwd against the PAP secrets + * file. If requested, also check against the system password database, + * and login the user if OK. + * + * returns: + * UPAP_AUTHNAK: Authentication failed. + * UPAP_AUTHACK: Authentication succeeded. + * In either case, msg points to an appropriate message. + */ +int +check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) + int unit; + char *auser; + int userlen; + char *apasswd; + int passwdlen; + char **msg; +{ + return UPAP_AUTHNAK; + int ret; + char *filename; + FILE *f; + struct wordlist *addrs = NULL, *opts = NULL; + char passwd[256], user[256]; + char secret[MAXWORDLEN]; + static int attempts = 0; + + /* + * Make copies of apasswd and auser, then null-terminate them. + * If there are unprintable characters in the password, make + * them visible. + */ + slprintf(ppp_settings.passwd, sizeof(ppp_settings.passwd), "%.*v", passwdlen, apasswd); + slprintf(ppp_settings.user, sizeof(ppp_settings.user), "%.*v", userlen, auser); + *msg = ""; + + /* + * Check if a plugin wants to handle this. + */ + if (pap_auth_hook) { + ret = (*pap_auth_hook)(ppp_settings.user, ppp_settings.passwd, msg, &addrs, &opts); + if (ret >= 0) { + /* note: set_allowed_addrs() saves opts (but not addrs): + don't free it! */ + if (ret) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); + return ret? UPAP_AUTHACK: UPAP_AUTHNAK; + } + } + + /* + * Open the file of pap secrets and scan for a suitable secret + * for authenticating this user. + */ + filename = _PATH_UPAPFILE; + addrs = opts = NULL; + ret = UPAP_AUTHNAK; + f = fopen(filename, "r"); + if (f == NULL) { + ppp_error("Can't open PAP password file %s: %m", filename); + + } else { + check_access(f, filename); + if (scan_authfile(f, ppp_settings.user, our_name, secret, &addrs, &opts, filename, 0) < 0) { + ppp_warn("no PAP secret found for %s", user); + } else { + /* + * If the secret is "@login", it means to check + * the password against the login database. + */ + int login_secret = strcmp(secret, "@login") == 0; + ret = UPAP_AUTHACK; + if (uselogin || login_secret) { + /* login option or secret is @login */ + if (session_full(ppp_settings.user, ppp_settings.passwd, devnam, msg) == 0) { + ret = UPAP_AUTHNAK; + } + } else if (session_mgmt) { + if (session_check(ppp_settings.user, NULL, devnam, NULL) == 0) { + ppp_warn("Peer %q failed PAP Session verification", user); + ret = UPAP_AUTHNAK; + } + } + if (secret[0] != 0 && !login_secret) { + /* password given in pap-secrets - must match */ + if ((cryptpap || strcmp(ppp_settings.passwd, secret) != 0) + && strcmp(crypt(ppp_settings.passwd, secret), secret) != 0) + ret = UPAP_AUTHNAK; + } + } + fclose(f); + } + + if (ret == UPAP_AUTHNAK) { + if (**msg == 0) + *msg = "Login incorrect"; + /* + * XXX can we ever get here more than once?? + * Frustrate passwd stealer programs. + * Allow 10 tries, but start backing off after 3 (stolen from login). + * On 10'th, drop the connection. + */ + if (attempts++ >= 10) { + ppp_warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); + lcp_close(pcb, "login failed"); + } + if (attempts > 3) + sleep((u_int) (attempts - 3) * 5); + if (opts != NULL) + free_wordlist(opts); + + } else { + attempts = 0; /* Reset count */ + if (**msg == 0) + *msg = "Login ok"; + set_allowed_addrs(unit, addrs, opts); + } + + if (addrs != NULL) + free_wordlist(addrs); + BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); + BZERO(secret, sizeof(secret)); + + return ret; +} + +/* + * null_login - Check if a username of "" and a password of "" are + * acceptable, and iff so, set the list of acceptable IP addresses + * and return 1. + */ +static int +null_login(unit) + int unit; +{ + char *filename; + FILE *f; + int i, ret; + struct wordlist *addrs, *opts; + char secret[MAXWORDLEN]; + + /* + * Check if a plugin wants to handle this. + */ + ret = -1; + if (null_auth_hook) + ret = (*null_auth_hook)(&addrs, &opts); + + /* + * Open the file of pap secrets and scan for a suitable secret. + */ + if (ret <= 0) { + filename = _PATH_UPAPFILE; + addrs = NULL; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + check_access(f, filename); + + i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0); + ret = i >= 0 && secret[0] == 0; + BZERO(secret, sizeof(secret)); + fclose(f); + } + + if (ret) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + + return ret; +} + +/* + * get_pap_passwd - get a password for authenticating ourselves with + * our peer using PAP. Returns 1 on success, 0 if no suitable password + * could be found. + * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null). + */ +static int +get_pap_passwd(passwd) + char *passwd; +{ + char *filename; + FILE *f; + int ret; + char secret[MAXWORDLEN]; + + /* + * Check whether a plugin wants to supply this. + */ + if (pap_passwd_hook) { + ret = (*pap_passwd_hook)(ppp_settings,user, ppp_settings.passwd); + if (ret >= 0) + return ret; + } + + filename = _PATH_UPAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + check_access(f, filename); + ret = scan_authfile(f, user, + (remote_name[0]? remote_name: NULL), + secret, NULL, NULL, filename, 0); + fclose(f); + if (ret < 0) + return 0; + if (passwd != NULL) + strlcpy(passwd, secret, MAXSECRETLEN); + BZERO(secret, sizeof(secret)); + return 1; +} + +/* + * have_pap_secret - check whether we have a PAP file with any + * secrets that we could possibly use for authenticating the peer. + */ +static int +have_pap_secret(lacks_ipp) + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + /* let the plugin decide, if there is one */ + if (pap_check_hook) { + ret = (*pap_check_hook)(); + if (ret >= 0) + return ret; + } + + filename = _PATH_UPAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, + NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + +/* + * have_chap_secret - check whether we have a CHAP file with a + * secret that we could possibly use for authenticating `client' + * on `server'. Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_chap_secret(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + if (chap_check_hook) { + ret = (*chap_check_hook)(); + if (ret >= 0) { + return ret; + } + } + + filename = _PATH_CHAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + +/* + * have_srp_secret - check whether we have a SRP file with a + * secret that we could possibly use for authenticating `client' + * on `server'. Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_srp_secret(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + filename = _PATH_SRPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} +#endif /* UNUSED */ + +#if PPP_AUTH_SUPPORT +/* + * get_secret - open the CHAP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server) { + int len; + LWIP_UNUSED_ARG(server); + LWIP_UNUSED_ARG(am_server); + + if (!client || !client[0] || !pcb->settings.user || !pcb->settings.passwd || strcmp(client, pcb->settings.user)) { + return 0; + } + + len = (int)strlen(pcb->settings.passwd); + if (len > MAXSECRETLEN) { + ppp_error("Secret for %s on %s is too long", client, server); + len = MAXSECRETLEN; + } + + MEMCPY(secret, pcb->settings.passwd, len); + *secret_len = len; + return 1; + +#if 0 /* UNUSED */ + FILE *f; + int ret, len; + char *filename; + struct wordlist *addrs, *opts; + char secbuf[MAXWORDLEN]; + struct wordlist *addrs; + addrs = NULL; + + if (!am_server && ppp_settings.passwd[0] != 0) { + strlcpy(secbuf, ppp_settings.passwd, sizeof(secbuf)); + } else if (!am_server && chap_passwd_hook) { + if ( (*chap_passwd_hook)(client, secbuf) < 0) { + ppp_error("Unable to obtain CHAP password for %s on %s from plugin", + client, server); + return 0; + } + } else { + filename = _PATH_CHAPFILE; + addrs = NULL; + secbuf[0] = 0; + + f = fopen(filename, "r"); + if (f == NULL) { + ppp_error("Can't open chap secret file %s: %m", filename); + return 0; + } + check_access(f, filename); + + ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename, 0); + fclose(f); + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + } + + len = strlen(secbuf); + if (len > MAXSECRETLEN) { + ppp_error("Secret for %s on %s is too long", client, server); + len = MAXSECRETLEN; + } + MEMCPY(secret, secbuf, len); + BZERO(secbuf, sizeof(secbuf)); + *secret_len = len; + + return 1; +#endif /* UNUSED */ +} +#endif /* PPP_AUTH_SUPPORT */ + + +#if 0 /* UNUSED */ +/* + * get_srp_secret - open the SRP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int +get_srp_secret(unit, client, server, secret, am_server) + int unit; + char *client; + char *server; + char *secret; + int am_server; +{ + FILE *fp; + int ret; + char *filename; + struct wordlist *addrs, *opts; + + if (!am_server && ppp_settings.passwd[0] != '\0') { + strlcpy(secret, ppp_settings.passwd, MAXWORDLEN); + } else { + filename = _PATH_SRPFILE; + addrs = NULL; + + fp = fopen(filename, "r"); + if (fp == NULL) { + ppp_error("Can't open srp secret file %s: %m", filename); + return 0; + } + check_access(fp, filename); + + secret[0] = '\0'; + ret = scan_authfile(fp, client, server, secret, &addrs, &opts, + filename, am_server); + fclose(fp); + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != NULL) + free_wordlist(opts); + if (addrs != NULL) + free_wordlist(addrs); + } + + return 1; +} + +/* + * set_allowed_addrs() - set the list of allowed addresses. + * Also looks for `--' indicating options to apply for this peer + * and leaves the following words in extra_options. + */ +static void +set_allowed_addrs(unit, addrs, opts) + int unit; + struct wordlist *addrs; + struct wordlist *opts; +{ + int n; + struct wordlist *ap, **plink; + struct permitted_ip *ip; + char *ptr_word, *ptr_mask; + struct hostent *hp; + struct netent *np; + u32_t a, mask, ah, offset; + struct ipcp_options *wo = &ipcp_wantoptions[unit]; + u32_t suggested_ip = 0; + + if (addresses[unit] != NULL) + free(addresses[unit]); + addresses[unit] = NULL; + if (extra_options != NULL) + free_wordlist(extra_options); + extra_options = opts; + + /* + * Count the number of IP addresses given. + */ + n = wordlist_count(addrs) + wordlist_count(noauth_addrs); + if (n == 0) + return; + ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); + if (ip == 0) + return; + + /* temporarily append the noauth_addrs list to addrs */ + for (plink = &addrs; *plink != NULL; plink = &(*plink)->next) + ; + *plink = noauth_addrs; + + n = 0; + for (ap = addrs; ap != NULL; ap = ap->next) { + /* "-" means no addresses authorized, "*" means any address allowed */ + ptr_word = ap->word; + if (strcmp(ptr_word, "-") == 0) + break; + if (strcmp(ptr_word, "*") == 0) { + ip[n].permit = 1; + ip[n].base = ip[n].mask = 0; + ++n; + break; + } + + ip[n].permit = 1; + if (*ptr_word == '!') { + ip[n].permit = 0; + ++ptr_word; + } + + mask = ~ (u32_t) 0; + offset = 0; + ptr_mask = strchr (ptr_word, '/'); + if (ptr_mask != NULL) { + int bit_count; + char *endp; + + bit_count = (int) strtol (ptr_mask+1, &endp, 10); + if (bit_count <= 0 || bit_count > 32) { + ppp_warn("invalid address length %v in auth. address list", + ptr_mask+1); + continue; + } + bit_count = 32 - bit_count; /* # bits in host part */ + if (*endp == '+') { + offset = ifunit + 1; + ++endp; + } + if (*endp != 0) { + ppp_warn("invalid address length syntax: %v", ptr_mask+1); + continue; + } + *ptr_mask = '\0'; + mask <<= bit_count; + } + + hp = gethostbyname(ptr_word); + if (hp != NULL && hp->h_addrtype == AF_INET) { + a = *(u32_t *)hp->h_addr; + } else { + np = getnetbyname (ptr_word); + if (np != NULL && np->n_addrtype == AF_INET) { + a = lwip_htonl ((u32_t)np->n_net); + if (ptr_mask == NULL) { + /* calculate appropriate mask for net */ + ah = lwip_ntohl(a); + if (IN_CLASSA(ah)) + mask = IN_CLASSA_NET; + else if (IN_CLASSB(ah)) + mask = IN_CLASSB_NET; + else if (IN_CLASSC(ah)) + mask = IN_CLASSC_NET; + } + } else { + a = inet_addr (ptr_word); + } + } + + if (ptr_mask != NULL) + *ptr_mask = '/'; + + if (a == (u32_t)-1L) { + ppp_warn("unknown host %s in auth. address list", ap->word); + continue; + } + if (offset != 0) { + if (offset >= ~mask) { + ppp_warn("interface unit %d too large for subnet %v", + ifunit, ptr_word); + continue; + } + a = lwip_htonl((lwip_ntohl(a) & mask) + offset); + mask = ~(u32_t)0; + } + ip[n].mask = lwip_htonl(mask); + ip[n].base = a & ip[n].mask; + ++n; + if (~mask == 0 && suggested_ip == 0) + suggested_ip = a; + } + *plink = NULL; + + ip[n].permit = 0; /* make the last entry forbid all addresses */ + ip[n].base = 0; /* to terminate the list */ + ip[n].mask = 0; + + addresses[unit] = ip; + + /* + * If the address given for the peer isn't authorized, or if + * the user hasn't given one, AND there is an authorized address + * which is a single host, then use that if we find one. + */ + if (suggested_ip != 0 + && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) { + wo->hisaddr = suggested_ip; + /* + * Do we insist on this address? No, if there are other + * addresses authorized than the suggested one. + */ + if (n > 1) + wo->accept_remote = 1; + } +} + +/* + * auth_ip_addr - check whether the peer is authorized to use + * a given IP address. Returns 1 if authorized, 0 otherwise. + */ +int +auth_ip_addr(unit, addr) + int unit; + u32_t addr; +{ + int ok; + + /* don't allow loopback or multicast address */ + if (bad_ip_adrs(addr)) + return 0; + + if (allowed_address_hook) { + ok = allowed_address_hook(addr); + if (ok >= 0) return ok; + } + + if (addresses[unit] != NULL) { + ok = ip_addr_check(addr, addresses[unit]); + if (ok >= 0) + return ok; + } + + if (auth_required) + return 0; /* no addresses authorized */ + return allow_any_ip || privileged || !have_route_to(addr); +} + +static int +ip_addr_check(addr, addrs) + u32_t addr; + struct permitted_ip *addrs; +{ + for (; ; ++addrs) + if ((addr & addrs->mask) == addrs->base) + return addrs->permit; +} + +/* + * bad_ip_adrs - return 1 if the IP address is one we don't want + * to use, such as an address in the loopback net or a multicast address. + * addr is in network byte order. + */ +int +bad_ip_adrs(addr) + u32_t addr; +{ + addr = lwip_ntohl(addr); + return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET + || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + +/* + * some_ip_ok - check a wordlist to see if it authorizes any + * IP address(es). + */ +static int +some_ip_ok(addrs) + struct wordlist *addrs; +{ + for (; addrs != 0; addrs = addrs->next) { + if (addrs->word[0] == '-') + break; + if (addrs->word[0] != '!') + return 1; /* some IP address is allowed */ + } + return 0; +} + +/* + * auth_number - check whether the remote number is allowed to connect. + * Returns 1 if authorized, 0 otherwise. + */ +int +auth_number() +{ + struct wordlist *wp = permitted_numbers; + int l; + + /* Allow all if no authorization list. */ + if (!wp) + return 1; + + /* Allow if we have a match in the authorization list. */ + while (wp) { + /* trailing '*' wildcard */ + l = strlen(wp->word); + if ((wp->word)[l - 1] == '*') + l--; + if (!strncasecmp(wp->word, remote_number, l)) + return 1; + wp = wp->next; + } + + return 0; +} + +/* + * check_access - complain if a secret file has too-liberal permissions. + */ +static void +check_access(f, filename) + FILE *f; + char *filename; +{ + struct stat sbuf; + + if (fstat(fileno(f), &sbuf) < 0) { + ppp_warn("cannot stat secret file %s: %m", filename); + } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + ppp_warn("Warning - secret file %s has world and/or group access", + filename); + } +} + +/* + * scan_authfile - Scan an authorization file for a secret suitable + * for authenticating `client' on `server'. The return value is -1 + * if no secret is found, otherwise >= 0. The return value has + * NONWILD_CLIENT set if the secret didn't have "*" for the client, and + * NONWILD_SERVER set if the secret didn't have "*" for the server. + * Any following words on the line up to a "--" (i.e. address authorization + * info) are placed in a wordlist and returned in *addrs. Any + * following words (extra options) are placed in a wordlist and + * returned in *opts. + * We assume secret is NULL or points to MAXWORDLEN bytes of space. + * Flags are non-zero if we need two colons in the secret in order to + * match. + */ +static int +scan_authfile(f, client, server, secret, addrs, opts, filename, flags) + FILE *f; + char *client; + char *server; + char *secret; + struct wordlist **addrs; + struct wordlist **opts; + char *filename; + int flags; +{ + int newline, xxx; + int got_flag, best_flag; + FILE *sf; + struct wordlist *ap, *addr_list, *alist, **app; + char word[MAXWORDLEN]; + char atfile[MAXWORDLEN]; + char lsecret[MAXWORDLEN]; + char *cp; + + if (addrs != NULL) + *addrs = NULL; + if (opts != NULL) + *opts = NULL; + addr_list = NULL; + if (!getword(f, word, &newline, filename)) + return -1; /* file is empty??? */ + newline = 1; + best_flag = -1; + for (;;) { + /* + * Skip until we find a word at the start of a line. + */ + while (!newline && getword(f, word, &newline, filename)) + ; + if (!newline) + break; /* got to end of file */ + + /* + * Got a client - check if it's a match or a wildcard. + */ + got_flag = 0; + if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { + newline = 0; + continue; + } + if (!ISWILD(word)) + got_flag = NONWILD_CLIENT; + + /* + * Now get a server and check if it matches. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (!ISWILD(word)) { + if (server != NULL && strcmp(word, server) != 0) + continue; + got_flag |= NONWILD_SERVER; + } + + /* + * Got some sort of a match - see if it's better than what + * we have already. + */ + if (got_flag <= best_flag) + continue; + + /* + * Get the secret. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + /* + * SRP-SHA1 authenticator should never be reading secrets from + * a file. (Authenticatee may, though.) + */ + if (flags && ((cp = strchr(word, ':')) == NULL || + strchr(cp + 1, ':') == NULL)) + continue; + + if (secret != NULL) { + /* + * Special syntax: @/pathname means read secret from file. + */ + if (word[0] == '@' && word[1] == '/') { + strlcpy(atfile, word+1, sizeof(atfile)); + if ((sf = fopen(atfile, "r")) == NULL) { + ppp_warn("can't open indirect secret file %s", atfile); + continue; + } + check_access(sf, atfile); + if (!getword(sf, word, &xxx, atfile)) { + ppp_warn("no secret in indirect secret file %s", atfile); + fclose(sf); + continue; + } + fclose(sf); + } + strlcpy(lsecret, word, sizeof(lsecret)); + } + + /* + * Now read address authorization info and make a wordlist. + */ + app = &alist; + for (;;) { + if (!getword(f, word, &newline, filename) || newline) + break; + ap = (struct wordlist *) + malloc(sizeof(struct wordlist) + strlen(word) + 1); + if (ap == NULL) + novm("authorized addresses"); + ap->word = (char *) (ap + 1); + strcpy(ap->word, word); + *app = ap; + app = &ap->next; + } + *app = NULL; + + /* + * This is the best so far; remember it. + */ + best_flag = got_flag; + if (addr_list) + free_wordlist(addr_list); + addr_list = alist; + if (secret != NULL) + strlcpy(secret, lsecret, MAXWORDLEN); + + if (!newline) + break; + } + + /* scan for a -- word indicating the start of options */ + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) + if (strcmp(ap->word, "--") == 0) + break; + /* ap = start of options */ + if (ap != NULL) { + ap = ap->next; /* first option */ + free(*app); /* free the "--" word */ + *app = NULL; /* terminate addr list */ + } + if (opts != NULL) + *opts = ap; + else if (ap != NULL) + free_wordlist(ap); + if (addrs != NULL) + *addrs = addr_list; + else if (addr_list != NULL) + free_wordlist(addr_list); + + return best_flag; +} + +/* + * wordlist_count - return the number of items in a wordlist + */ +static int +wordlist_count(wp) + struct wordlist *wp; +{ + int n; + + for (n = 0; wp != NULL; wp = wp->next) + ++n; + return n; +} + +/* + * free_wordlist - release memory allocated for a wordlist. + */ +static void +free_wordlist(wp) + struct wordlist *wp; +{ + struct wordlist *next; + + while (wp != NULL) { + next = wp->next; + free(wp); + wp = next; + } +} +#endif /* UNUSED */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ccp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ccp.c new file mode 100644 index 0000000..f8519eb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ccp.c @@ -0,0 +1,1740 @@ +/* + * ccp.c - PPP Compression Control Protocol. + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ccp.h" + +#if MPPE_SUPPORT +#include "netif/ppp/lcp.h" /* lcp_close(), lcp_fsm */ +#include "netif/ppp/mppe.h" /* mppe_init() */ +#endif /* MPPE_SUPPORT */ + +/* + * Unfortunately there is a bug in zlib which means that using a + * size of 8 (window size = 256) for Deflate compression will cause + * buffer overruns and kernel crashes in the deflate module. + * Until this is fixed we only accept sizes in the range 9 .. 15. + * Thanks to James Carlson for pointing this out. + */ +#define DEFLATE_MIN_WORKS 9 + +/* + * Command-line options. + */ +#if PPP_OPTIONS +static int setbsdcomp (char **); +static int setdeflate (char **); +static char bsd_value[8]; +static char deflate_value[8]; + +/* + * Option variables. + */ +#if MPPE_SUPPORT +bool refuse_mppe_stateful = 1; /* Allow stateful mode? */ +#endif /* MPPE_SUPPORT */ + +static option_t ccp_option_list[] = { + { "noccp", o_bool, &ccp_protent.enabled_flag, + "Disable CCP negotiation" }, + { "-ccp", o_bool, &ccp_protent.enabled_flag, + "Disable CCP negotiation", OPT_ALIAS }, + + { "bsdcomp", o_special, (void *)setbsdcomp, + "Request BSD-Compress packet compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, + { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, + "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].bsd_compress }, + { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, + "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].bsd_compress }, + + { "deflate", o_special, (void *)setdeflate, + "request Deflate compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, + { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, + "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].deflate }, + { "-deflate", o_bool, &ccp_wantoptions[0].deflate, + "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].deflate }, + + { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, + "don't use draft deflate #", OPT_A2COPY, + &ccp_allowoptions[0].deflate_draft }, + + { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "request Predictor-1", OPT_PRIO | 1 }, + { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].predictor_1 }, + { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].predictor_1 }, + +#if MPPE_SUPPORT + /* MPPE options are symmetrical ... we only set wantoptions here */ + { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "+mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "nomppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_PRIO }, + { "-mppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, + + /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ + { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, + { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + + { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, + { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + + /* strange one; we always request stateless, but will we allow stateful? */ + { "mppe-stateful", o_bool, &refuse_mppe_stateful, + "allow MPPE stateful mode", OPT_PRIO }, + { "nomppe-stateful", o_bool, &refuse_mppe_stateful, + "disallow MPPE stateful mode", OPT_PRIO | 1 }, +#endif /* MPPE_SUPPORT */ + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ccp_init(ppp_pcb *pcb); +static void ccp_open(ppp_pcb *pcb); +static void ccp_close(ppp_pcb *pcb, const char *reason); +static void ccp_lowerup(ppp_pcb *pcb); +static void ccp_lowerdown(ppp_pcb *pcb); +static void ccp_input(ppp_pcb *pcb, u_char *pkt, int len); +static void ccp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT +static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len); +#endif /* PPP_DATAINPUT */ + +const struct protent ccp_protent = { + PPP_CCP, + ccp_init, + ccp_input, + ccp_protrej, + ccp_lowerup, + ccp_lowerdown, + ccp_open, + ccp_close, +#if PRINTPKT_SUPPORT + ccp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + ccp_datainput, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "CCP", + "Compressed", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ccp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +/* + * Callbacks for fsm code. + */ +static void ccp_resetci (fsm *); +static int ccp_cilen (fsm *); +static void ccp_addci (fsm *, u_char *, int *); +static int ccp_ackci (fsm *, u_char *, int); +static int ccp_nakci (fsm *, u_char *, int, int); +static int ccp_rejci (fsm *, u_char *, int); +static int ccp_reqci (fsm *, u_char *, int *, int); +static void ccp_up (fsm *); +static void ccp_down (fsm *); +static int ccp_extcode (fsm *, int, int, u_char *, int); +static void ccp_rack_timeout (void *); +static const char *method_name (ccp_options *, ccp_options *); + +static const fsm_callbacks ccp_callbacks = { + ccp_resetci, + ccp_cilen, + ccp_addci, + ccp_ackci, + ccp_nakci, + ccp_rejci, + ccp_reqci, + ccp_up, + ccp_down, + NULL, + NULL, + NULL, + NULL, + ccp_extcode, + "CCP" +}; + +/* + * Do we want / did we get any compression? + */ +static int ccp_anycompress(ccp_options *opt) { + return (0 +#if DEFLATE_SUPPORT + || (opt)->deflate +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + || (opt)->bsd_compress +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + || (opt)->predictor_1 || (opt)->predictor_2 +#endif /* PREDICTOR_SUPPORT */ +#if MPPE_SUPPORT + || (opt)->mppe +#endif /* MPPE_SUPPORT */ + ); +} + +/* + * Local state (mainly for handling reset-reqs and reset-acks). + */ +#define RACK_PENDING 1 /* waiting for reset-ack */ +#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ + +#define RACKTIMEOUT 1 /* second */ + +#if PPP_OPTIONS +/* + * Option parsing + */ +static int +setbsdcomp(argv) + char **argv; +{ + int rbits, abits; + char *str, *endp; + + str = *argv; + abits = rbits = strtol(str, &endp, 0); + if (endp != str && *endp == ',') { + str = endp + 1; + abits = strtol(str, &endp, 0); + } + if (*endp != 0 || endp == str) { + option_error("invalid parameter '%s' for bsdcomp option", *argv); + return 0; + } + if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) + || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { + option_error("bsdcomp option values must be 0 or %d .. %d", + BSD_MIN_BITS, BSD_MAX_BITS); + return 0; + } + if (rbits > 0) { + ccp_wantoptions[0].bsd_compress = 1; + ccp_wantoptions[0].bsd_bits = rbits; + } else + ccp_wantoptions[0].bsd_compress = 0; + if (abits > 0) { + ccp_allowoptions[0].bsd_compress = 1; + ccp_allowoptions[0].bsd_bits = abits; + } else + ccp_allowoptions[0].bsd_compress = 0; + ppp_slprintf(bsd_value, sizeof(bsd_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + + return 1; +} + +static int +setdeflate(argv) + char **argv; +{ + int rbits, abits; + char *str, *endp; + + str = *argv; + abits = rbits = strtol(str, &endp, 0); + if (endp != str && *endp == ',') { + str = endp + 1; + abits = strtol(str, &endp, 0); + } + if (*endp != 0 || endp == str) { + option_error("invalid parameter '%s' for deflate option", *argv); + return 0; + } + if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)) + || (abits != 0 && (abits < DEFLATE_MIN_SIZE + || abits > DEFLATE_MAX_SIZE))) { + option_error("deflate option values must be 0 or %d .. %d", + DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); + return 0; + } + if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { + if (rbits == DEFLATE_MIN_SIZE) + rbits = DEFLATE_MIN_WORKS; + if (abits == DEFLATE_MIN_SIZE) + abits = DEFLATE_MIN_WORKS; + warn("deflate option value of %d changed to %d to avoid zlib bug", + DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); + } + if (rbits > 0) { + ccp_wantoptions[0].deflate = 1; + ccp_wantoptions[0].deflate_size = rbits; + } else + ccp_wantoptions[0].deflate = 0; + if (abits > 0) { + ccp_allowoptions[0].deflate = 1; + ccp_allowoptions[0].deflate_size = abits; + } else + ccp_allowoptions[0].deflate = 0; + ppp_slprintf(deflate_value, sizeof(deflate_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + + return 1; +} +#endif /* PPP_OPTIONS */ + +/* + * ccp_init - initialize CCP. + */ +static void ccp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + + f->pcb = pcb; + f->protocol = PPP_CCP; + f->callbacks = &ccp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(go, 0, sizeof(*go)); + memset(ao, 0, sizeof(*ao)); + memset(ho, 0, sizeof(*ho)); +#endif /* 0 */ + +#if DEFLATE_SUPPORT + wo->deflate = 1; + wo->deflate_size = DEFLATE_MAX_SIZE; + wo->deflate_correct = 1; + wo->deflate_draft = 1; + ao->deflate = 1; + ao->deflate_size = DEFLATE_MAX_SIZE; + ao->deflate_correct = 1; + ao->deflate_draft = 1; +#endif /* DEFLATE_SUPPORT */ + +#if BSDCOMPRESS_SUPPORT + wo->bsd_compress = 1; + wo->bsd_bits = BSD_MAX_BITS; + ao->bsd_compress = 1; + ao->bsd_bits = BSD_MAX_BITS; +#endif /* BSDCOMPRESS_SUPPORT */ + +#if PREDICTOR_SUPPORT + ao->predictor_1 = 1; +#endif /* PREDICTOR_SUPPORT */ +} + +/* + * ccp_open - CCP is allowed to come up. + */ +static void ccp_open(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + ccp_options *go = &pcb->ccp_gotoptions; + + if (f->state != PPP_FSM_OPENED) + ccp_set(pcb, 1, 0, 0, 0); + + /* + * Find out which compressors the kernel supports before + * deciding whether to open in silent mode. + */ + ccp_resetci(f); + if (!ccp_anycompress(go)) + f->flags |= OPT_SILENT; + + fsm_open(f); +} + +/* + * ccp_close - Terminate CCP. + */ +static void ccp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->ccp_fsm; + ccp_set(pcb, 0, 0, 0, 0); + fsm_close(f, reason); +} + +/* + * ccp_lowerup - we may now transmit CCP packets. + */ +static void ccp_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + fsm_lowerup(f); +} + +/* + * ccp_lowerdown - we may not transmit CCP packets. + */ +static void ccp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + fsm_lowerdown(f); +} + +/* + * ccp_input - process a received CCP packet. + */ +static void ccp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->ccp_fsm; + ccp_options *go = &pcb->ccp_gotoptions; + int oldstate; + + /* + * Check for a terminate-request so we can print a message. + */ + oldstate = f->state; + fsm_input(f, p, len); + if (oldstate == PPP_FSM_OPENED && p[0] == TERMREQ && f->state != PPP_FSM_OPENED) { + ppp_notice("Compression disabled by peer."); +#if MPPE_SUPPORT + if (go->mppe) { + ppp_error("MPPE disabled, closing LCP"); + lcp_close(pcb, "MPPE disabled by peer"); + } +#endif /* MPPE_SUPPORT */ + } + + /* + * If we get a terminate-ack and we're not asking for compression, + * close CCP. + */ + if (oldstate == PPP_FSM_REQSENT && p[0] == TERMACK + && !ccp_anycompress(go)) + ccp_close(pcb, "No compression negotiated"); +} + +/* + * Handle a CCP-specific code. + */ +static int ccp_extcode(fsm *f, int code, int id, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(len); + + switch (code) { + case CCP_RESETREQ: + if (f->state != PPP_FSM_OPENED) + break; + ccp_reset_comp(pcb); + /* send a reset-ack, which the transmitter will see and + reset its compression state. */ + fsm_sdata(f, CCP_RESETACK, id, NULL, 0); + break; + + case CCP_RESETACK: + if ((pcb->ccp_localstate & RACK_PENDING) && id == f->reqid) { + pcb->ccp_localstate &= ~(RACK_PENDING | RREQ_REPEAT); + UNTIMEOUT(ccp_rack_timeout, f); + ccp_reset_decomp(pcb); + } + break; + + default: + return 0; + } + + return 1; +} + +/* + * ccp_protrej - peer doesn't talk CCP. + */ +static void ccp_protrej(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + + ccp_set(pcb, 0, 0, 0, 0); + fsm_lowerdown(f); + +#if MPPE_SUPPORT + if (go->mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } +#endif /* MPPE_SUPPORT */ + +} + +/* + * ccp_resetci - initialize at start of negotiation. + */ +static void ccp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options *wo = &pcb->ccp_wantoptions; +#if MPPE_SUPPORT + ccp_options *ao = &pcb->ccp_allowoptions; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT + u_char opt_buf[CCP_MAX_OPTION_LENGTH]; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT + int res; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ + +#if MPPE_SUPPORT + if (pcb->settings.require_mppe) { + wo->mppe = ao->mppe = + (pcb->settings.refuse_mppe_40 ? 0 : MPPE_OPT_40) + | (pcb->settings.refuse_mppe_128 ? 0 : MPPE_OPT_128); + } +#endif /* MPPE_SUPPORT */ + + *go = *wo; + pcb->ccp_all_rejected = 0; + +#if MPPE_SUPPORT + if (go->mppe) { + int auth_mschap_bits = pcb->auth_done; + int numbits; + + /* + * Start with a basic sanity check: mschap[v2] auth must be in + * exactly one direction. RFC 3079 says that the keys are + * 'derived from the credentials of the peer that initiated the call', + * however the PPP protocol doesn't have such a concept, and pppd + * cannot get this info externally. Instead we do the best we can. + * NB: If MPPE is required, all other compression opts are invalid. + * So, we return right away if we can't do it. + */ + + /* Leave only the mschap auth bits set */ + auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | + CHAP_MS2_WITHPEER | CHAP_MS2_PEER); + /* Count the mschap auths */ + auth_mschap_bits >>= CHAP_MS_SHIFT; + numbits = 0; + do { + numbits += auth_mschap_bits & 1; + auth_mschap_bits >>= 1; + } while (auth_mschap_bits); + if (numbits > 1) { + ppp_error("MPPE required, but auth done in both directions."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + if (!numbits) { + ppp_error("MPPE required, but MS-CHAP[v2] auth not performed."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* A plugin (eg radius) may not have obtained key material. */ + if (!pcb->mppe_keys_set) { + ppp_error("MPPE required, but keys are not available. " + "Possible plugin problem?"); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* LM auth not supported for MPPE */ + if (pcb->auth_done & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { + /* This might be noise */ + if (go->mppe & MPPE_OPT_40) { + ppp_notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); + go->mppe &= ~MPPE_OPT_40; + wo->mppe &= ~MPPE_OPT_40; + } + } + + /* Last check: can we actually negotiate something? */ + if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { + /* Could be misconfig, could be 40-bit disabled above. */ + ppp_error("MPPE required, but both 40-bit and 128-bit disabled."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* sync options */ + ao->mppe = go->mppe; + /* MPPE is not compatible with other compression types */ +#if BSDCOMPRESS_SUPPORT + ao->bsd_compress = go->bsd_compress = 0; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + ao->predictor_1 = go->predictor_1 = 0; + ao->predictor_2 = go->predictor_2 = 0; +#endif /* PREDICTOR_SUPPORT */ +#if DEFLATE_SUPPORT + ao->deflate = go->deflate = 0; +#endif /* DEFLATE_SUPPORT */ + } +#endif /* MPPE_SUPPORT */ + + /* + * Check whether the kernel knows about the various + * compression methods we might request. + */ +#if BSDCOMPRESS_SUPPORT + /* FIXME: we don't need to test if BSD compress is available + * if BSDCOMPRESS_SUPPORT is set, it is. + */ + if (go->bsd_compress) { + opt_buf[0] = CI_BSD_COMPRESS; + opt_buf[1] = CILEN_BSD_COMPRESS; + for (;;) { + if (go->bsd_bits < BSD_MIN_BITS) { + go->bsd_compress = 0; + break; + } + opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + res = ccp_test(pcb, opt_buf, CILEN_BSD_COMPRESS, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->bsd_compress = 0; + break; + } + go->bsd_bits--; + } + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + /* FIXME: we don't need to test if deflate is available + * if DEFLATE_SUPPORT is set, it is. + */ + if (go->deflate) { + if (go->deflate_correct) { + opt_buf[0] = CI_DEFLATE; + opt_buf[1] = CILEN_DEFLATE; + opt_buf[3] = DEFLATE_CHK_SEQUENCE; + for (;;) { + if (go->deflate_size < DEFLATE_MIN_WORKS) { + go->deflate_correct = 0; + break; + } + opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); + res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->deflate_correct = 0; + break; + } + go->deflate_size--; + } + } + if (go->deflate_draft) { + opt_buf[0] = CI_DEFLATE_DRAFT; + opt_buf[1] = CILEN_DEFLATE; + opt_buf[3] = DEFLATE_CHK_SEQUENCE; + for (;;) { + if (go->deflate_size < DEFLATE_MIN_WORKS) { + go->deflate_draft = 0; + break; + } + opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); + res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->deflate_draft = 0; + break; + } + go->deflate_size--; + } + } + if (!go->deflate_correct && !go->deflate_draft) + go->deflate = 0; + } +#endif /* DEFLATE_SUPPORT */ +#if PREDICTOR_SUPPORT + /* FIXME: we don't need to test if predictor is available, + * if PREDICTOR_SUPPORT is set, it is. + */ + if (go->predictor_1) { + opt_buf[0] = CI_PREDICTOR_1; + opt_buf[1] = CILEN_PREDICTOR_1; + if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_1, 0) <= 0) + go->predictor_1 = 0; + } + if (go->predictor_2) { + opt_buf[0] = CI_PREDICTOR_2; + opt_buf[1] = CILEN_PREDICTOR_2; + if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_2, 0) <= 0) + go->predictor_2 = 0; + } +#endif /* PREDICTOR_SUPPORT */ +} + +/* + * ccp_cilen - Return total length of our configuration info. + */ +static int ccp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + + return 0 +#if BSDCOMPRESS_SUPPORT + + (go->bsd_compress? CILEN_BSD_COMPRESS: 0) +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + + (go->deflate && go->deflate_correct? CILEN_DEFLATE: 0) + + (go->deflate && go->deflate_draft? CILEN_DEFLATE: 0) +#endif /* DEFLATE_SUPPORT */ +#if PREDICTOR_SUPPORT + + (go->predictor_1? CILEN_PREDICTOR_1: 0) + + (go->predictor_2? CILEN_PREDICTOR_2: 0) +#endif /* PREDICTOR_SUPPORT */ +#if MPPE_SUPPORT + + (go->mppe? CILEN_MPPE: 0) +#endif /* MPPE_SUPPORT */ + ; +} + +/* + * ccp_addci - put our requests in a packet. + */ +static void ccp_addci(fsm *f, u_char *p, int *lenp) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + u_char *p0 = p; + + /* + * Add the compression types that we can receive, in decreasing + * preference order. + */ +#if MPPE_SUPPORT + if (go->mppe) { + p[0] = CI_MPPE; + p[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &p[2]); + mppe_init(pcb, &pcb->mppe_decomp, go->mppe); + p += CILEN_MPPE; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate) { + if (go->deflate_correct) { + p[0] = CI_DEFLATE; + p[1] = CILEN_DEFLATE; + p[2] = DEFLATE_MAKE_OPT(go->deflate_size); + p[3] = DEFLATE_CHK_SEQUENCE; + p += CILEN_DEFLATE; + } + if (go->deflate_draft) { + p[0] = CI_DEFLATE_DRAFT; + p[1] = CILEN_DEFLATE; + p[2] = p[2 - CILEN_DEFLATE]; + p[3] = DEFLATE_CHK_SEQUENCE; + p += CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress) { + p[0] = CI_BSD_COMPRESS; + p[1] = CILEN_BSD_COMPRESS; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + p += CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + /* XXX Should Predictor 2 be preferable to Predictor 1? */ + if (go->predictor_1) { + p[0] = CI_PREDICTOR_1; + p[1] = CILEN_PREDICTOR_1; + p += CILEN_PREDICTOR_1; + } + if (go->predictor_2) { + p[0] = CI_PREDICTOR_2; + p[1] = CILEN_PREDICTOR_2; + p += CILEN_PREDICTOR_2; + } +#endif /* PREDICTOR_SUPPORT */ + + go->method = (p > p0)? p0[0]: 0; + + *lenp = p - p0; +} + +/* + * ccp_ackci - process a received configure-ack, and return + * 1 iff the packet was OK. + */ +static int ccp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; +#if BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT + u_char *p0 = p; +#endif /* BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ + +#if MPPE_SUPPORT + if (go->mppe) { + u_char opt_buf[CILEN_MPPE]; + + opt_buf[0] = CI_MPPE; + opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); + if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE)) + return 0; + p += CILEN_MPPE; + len -= CILEN_MPPE; + /* XXX Cope with first/fast ack */ + if (len == 0) + return 1; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate) { + if (len < CILEN_DEFLATE + || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) + || p[1] != CILEN_DEFLATE + || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + /* XXX Cope with first/fast ack */ + if (len == 0) + return 1; + if (go->deflate_correct && go->deflate_draft) { + if (len < CILEN_DEFLATE + || p[0] != CI_DEFLATE_DRAFT + || p[1] != CILEN_DEFLATE + || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress) { + if (len < CILEN_BSD_COMPRESS + || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS + || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) + return 0; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + if (go->predictor_1) { + if (len < CILEN_PREDICTOR_1 + || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1) + return 0; + p += CILEN_PREDICTOR_1; + len -= CILEN_PREDICTOR_1; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } + if (go->predictor_2) { + if (len < CILEN_PREDICTOR_2 + || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2) + return 0; + p += CILEN_PREDICTOR_2; + len -= CILEN_PREDICTOR_2; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } +#endif /* PREDICTOR_SUPPORT */ + + if (len != 0) + return 0; + return 1; +} + +/* + * ccp_nakci - process received configure-nak. + * Returns 1 iff the nak was OK. + */ +static int ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options no; /* options we've seen already */ + ccp_options try_; /* options to ask for next time */ + LWIP_UNUSED_ARG(treat_as_reject); +#if !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(len); +#endif /* !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ + + memset(&no, 0, sizeof(no)); + try_ = *go; + +#if MPPE_SUPPORT + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + no.mppe = 1; + /* + * Peer wants us to use a different strength or other setting. + * Fail if we aren't willing to use his suggestion. + */ + MPPE_CI_TO_OPTS(&p[2], try_.mppe); + if ((try_.mppe & MPPE_OPT_STATEFUL) && pcb->settings.refuse_mppe_stateful) { + ppp_error("Refusing MPPE stateful mode offered by peer"); + try_.mppe = 0; + } else if (((go->mppe | MPPE_OPT_STATEFUL) & try_.mppe) != try_.mppe) { + /* Peer must have set options we didn't request (suggest) */ + try_.mppe = 0; + } + + if (!try_.mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate && len >= CILEN_DEFLATE + && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) + && p[1] == CILEN_DEFLATE) { + no.deflate = 1; + /* + * Peer wants us to use a different code size or something. + * Stop asking for Deflate if we don't understand his suggestion. + */ + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL + || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS + || p[3] != DEFLATE_CHK_SEQUENCE) + try_.deflate = 0; + else if (DEFLATE_SIZE(p[2]) < go->deflate_size) + try_.deflate_size = DEFLATE_SIZE(p[2]); + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + if (go->deflate_correct && go->deflate_draft + && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT + && p[1] == CILEN_DEFLATE) { + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { + no.bsd_compress = 1; + /* + * Peer wants us to use a different number of bits + * or a different version. + */ + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) + try_.bsd_compress = 0; + else if (BSD_NBITS(p[2]) < go->bsd_bits) + try_.bsd_bits = BSD_NBITS(p[2]); + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ + + /* + * Predictor-1 and 2 have no options, so they can't be Naked. + * + * There may be remaining options but we ignore them. + */ + + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; +} + +/* + * ccp_rejci - reject some of our suggested compression methods. + */ +static int ccp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options try_; /* options to request next time */ + + try_ = *go; + + /* + * Cope with empty configure-rejects by ceasing to send + * configure-requests. + */ + if (len == 0 && pcb->ccp_all_rejected) + return -1; + +#if MPPE_SUPPORT + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + ppp_error("MPPE required but peer refused"); + lcp_close(pcb, "MPPE required but peer refused"); + p += CILEN_MPPE; + len -= CILEN_MPPE; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate_correct && len >= CILEN_DEFLATE + && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) { + if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; /* Rej is bad */ + try_.deflate_correct = 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + if (go->deflate_draft && len >= CILEN_DEFLATE + && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) { + if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; /* Rej is bad */ + try_.deflate_draft = 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + if (!try_.deflate_correct && !try_.deflate_draft) + try_.deflate = 0; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { + if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) + return 0; + try_.bsd_compress = 0; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + if (go->predictor_1 && len >= CILEN_PREDICTOR_1 + && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) { + try_.predictor_1 = 0; + p += CILEN_PREDICTOR_1; + len -= CILEN_PREDICTOR_1; + } + if (go->predictor_2 && len >= CILEN_PREDICTOR_2 + && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) { + try_.predictor_2 = 0; + p += CILEN_PREDICTOR_2; + len -= CILEN_PREDICTOR_2; + } +#endif /* PREDICTOR_SUPPORT */ + + if (len != 0) + return 0; + + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; +} + +/* + * ccp_reqci - processed a received configure-request. + * Returns CONFACK, CONFNAK or CONFREJ and the packet modified + * appropriately. + */ +static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { + ppp_pcb *pcb = f->pcb; + ccp_options *ho = &pcb->ccp_hisoptions; + ccp_options *ao = &pcb->ccp_allowoptions; + int ret, newret; +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT + int res; + int nb; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ + u_char *p0, *retp; + int len, clen, type; +#if MPPE_SUPPORT + u8_t rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */ + /* CI_MPPE, or due to other options? */ +#endif /* MPPE_SUPPORT */ + + ret = CONFACK; + retp = p0 = p; + len = *lenp; + + memset(ho, 0, sizeof(ccp_options)); + ho->method = (len > 0)? p[0]: 0; + + while (len > 0) { + newret = CONFACK; + if (len < 2 || p[1] < 2 || p[1] > len) { + /* length is bad */ + clen = len; + newret = CONFREJ; + + } else { + type = p[0]; + clen = p[1]; + + switch (type) { +#if MPPE_SUPPORT + case CI_MPPE: + if (!ao->mppe || clen != CILEN_MPPE) { + newret = CONFREJ; + break; + } + MPPE_CI_TO_OPTS(&p[2], ho->mppe); + + /* Nak if anything unsupported or unknown are set. */ + if (ho->mppe & MPPE_OPT_UNSUPPORTED) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNSUPPORTED; + } + if (ho->mppe & MPPE_OPT_UNKNOWN) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNKNOWN; + } + + /* Check state opt */ + if (ho->mppe & MPPE_OPT_STATEFUL) { + /* + * We can Nak and request stateless, but it's a + * lot easier to just assume the peer will request + * it if he can do it; stateful mode is bad over + * the Internet -- which is where we expect MPPE. + */ + if (pcb->settings.refuse_mppe_stateful) { + ppp_error("Refusing MPPE stateful mode offered by peer"); + newret = CONFREJ; + break; + } + } + + /* Find out which of {S,L} are set. */ + if ((ho->mppe & MPPE_OPT_128) + && (ho->mppe & MPPE_OPT_40)) { + /* Both are set, negotiate the strongest. */ + newret = CONFNAK; + if (ao->mppe & MPPE_OPT_128) + ho->mppe &= ~MPPE_OPT_40; + else if (ao->mppe & MPPE_OPT_40) + ho->mppe &= ~MPPE_OPT_128; + else { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_128) { + if (!(ao->mppe & MPPE_OPT_128)) { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_40) { + if (!(ao->mppe & MPPE_OPT_40)) { + newret = CONFREJ; + break; + } + } else { + /* Neither are set. */ + /* We cannot accept this. */ + newret = CONFNAK; + /* Give the peer our idea of what can be used, + so it can choose and confirm */ + ho->mppe = ao->mppe; + } + + /* rebuild the opts */ + MPPE_OPTS_TO_CI(ho->mppe, &p[2]); + if (newret == CONFACK) { + int mtu; + + mppe_init(pcb, &pcb->mppe_comp, ho->mppe); + /* + * We need to decrease the interface MTU by MPPE_PAD + * because MPPE frames **grow**. The kernel [must] + * allocate MPPE_PAD extra bytes in xmit buffers. + */ + mtu = netif_get_mtu(pcb); + if (mtu) + netif_set_mtu(pcb, mtu - MPPE_PAD); + else + newret = CONFREJ; + } + + /* + * We have accepted MPPE or are willing to negotiate + * MPPE parameters. A CONFREJ is due to subsequent + * (non-MPPE) processing. + */ + rej_for_ci_mppe = 0; + break; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (!ao->deflate || clen != CILEN_DEFLATE + || (!ao->deflate_correct && type == CI_DEFLATE) + || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) { + newret = CONFREJ; + break; + } + + ho->deflate = 1; + ho->deflate_size = nb = DEFLATE_SIZE(p[2]); + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL + || p[3] != DEFLATE_CHK_SEQUENCE + || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) { + newret = CONFNAK; + if (!dont_nak) { + p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); + p[3] = DEFLATE_CHK_SEQUENCE; + /* fall through to test this #bits below */ + } else + break; + } + + /* + * Check whether we can do Deflate with the window + * size they want. If the window is too big, reduce + * it until the kernel can cope and nak with that. + * We only check this for the first option. + */ + if (p == p0) { + for (;;) { + res = ccp_test(pcb, p, CILEN_DEFLATE, 1); + if (res > 0) + break; /* it's OK now */ + if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) { + newret = CONFREJ; + p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); + break; + } + newret = CONFNAK; + --nb; + p[2] = DEFLATE_MAKE_OPT(nb); + } + } + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { + newret = CONFREJ; + break; + } + + ho->bsd_compress = 1; + ho->bsd_bits = nb = BSD_NBITS(p[2]); + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION + || nb > ao->bsd_bits || nb < BSD_MIN_BITS) { + newret = CONFNAK; + if (!dont_nak) { + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits); + /* fall through to test this #bits below */ + } else + break; + } + + /* + * Check whether we can do BSD-Compress with the code + * size they want. If the code size is too big, reduce + * it until the kernel can cope and nak with that. + * We only check this for the first option. + */ + if (p == p0) { + for (;;) { + res = ccp_test(pcb, p, CILEN_BSD_COMPRESS, 1); + if (res > 0) + break; + if (res < 0 || nb == BSD_MIN_BITS || dont_nak) { + newret = CONFREJ; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, + ho->bsd_bits); + break; + } + newret = CONFNAK; + --nb; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); + } + } + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) { + newret = CONFREJ; + break; + } + + ho->predictor_1 = 1; + if (p == p0 + && ccp_test(pcb, p, CILEN_PREDICTOR_1, 1) <= 0) { + newret = CONFREJ; + } + break; + + case CI_PREDICTOR_2: + if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) { + newret = CONFREJ; + break; + } + + ho->predictor_2 = 1; + if (p == p0 + && ccp_test(pcb, p, CILEN_PREDICTOR_2, 1) <= 0) { + newret = CONFREJ; + } + break; +#endif /* PREDICTOR_SUPPORT */ + + default: + newret = CONFREJ; + } + } + + if (newret == CONFNAK && dont_nak) + newret = CONFREJ; + if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) { + /* we're returning this option */ + if (newret == CONFREJ && ret == CONFNAK) + retp = p0; + ret = newret; + if (p != retp) + MEMCPY(retp, p, clen); + retp += clen; + } + + p += clen; + len -= clen; + } + + if (ret != CONFACK) { + if (ret == CONFREJ && *lenp == retp - p0) + pcb->ccp_all_rejected = 1; + else + *lenp = retp - p0; + } +#if MPPE_SUPPORT + if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } +#endif /* MPPE_SUPPORT */ + return ret; +} + +/* + * Make a string name for a compression method (or 2). + */ +static const char *method_name(ccp_options *opt, ccp_options *opt2) { + static char result[64]; +#if !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT + LWIP_UNUSED_ARG(opt2); +#endif /* !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ + + if (!ccp_anycompress(opt)) + return "(none)"; + switch (opt->method) { +#if MPPE_SUPPORT + case CI_MPPE: + { + char *p = result; + char *q = result + sizeof(result); /* 1 past result */ + + ppp_slprintf(p, q - p, "MPPE "); + p += 5; + if (opt->mppe & MPPE_OPT_128) { + ppp_slprintf(p, q - p, "128-bit "); + p += 8; + } + if (opt->mppe & MPPE_OPT_40) { + ppp_slprintf(p, q - p, "40-bit "); + p += 7; + } + if (opt->mppe & MPPE_OPT_STATEFUL) + ppp_slprintf(p, q - p, "stateful"); + else + ppp_slprintf(p, q - p, "stateless"); + + break; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) + ppp_slprintf(result, sizeof(result), "Deflate%s (%d/%d)", + (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), + opt->deflate_size, opt2->deflate_size); + else + ppp_slprintf(result, sizeof(result), "Deflate%s (%d)", + (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), + opt->deflate_size); + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits) + ppp_slprintf(result, sizeof(result), "BSD-Compress (%d/%d)", + opt->bsd_bits, opt2->bsd_bits); + else + ppp_slprintf(result, sizeof(result), "BSD-Compress (%d)", + opt->bsd_bits); + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + return "Predictor 1"; + case CI_PREDICTOR_2: + return "Predictor 2"; +#endif /* PREDICTOR_SUPPORT */ + default: + ppp_slprintf(result, sizeof(result), "Method %d", opt->method); + } + return result; +} + +/* + * CCP has come up - inform the kernel driver and log a message. + */ +static void ccp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options *ho = &pcb->ccp_hisoptions; + char method1[64]; + + ccp_set(pcb, 1, 1, go->method, ho->method); + if (ccp_anycompress(go)) { + if (ccp_anycompress(ho)) { + if (go->method == ho->method) { + ppp_notice("%s compression enabled", method_name(go, ho)); + } else { + ppp_strlcpy(method1, method_name(go, NULL), sizeof(method1)); + ppp_notice("%s / %s compression enabled", + method1, method_name(ho, NULL)); + } + } else + ppp_notice("%s receive compression enabled", method_name(go, NULL)); + } else if (ccp_anycompress(ho)) + ppp_notice("%s transmit compression enabled", method_name(ho, NULL)); +#if MPPE_SUPPORT + if (go->mppe) { + continue_networks(pcb); /* Bring up IP et al */ + } +#endif /* MPPE_SUPPORT */ +} + +/* + * CCP has gone down - inform the kernel driver. + */ +static void ccp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + + if (pcb->ccp_localstate & RACK_PENDING) + UNTIMEOUT(ccp_rack_timeout, f); + pcb->ccp_localstate = 0; + ccp_set(pcb, 1, 0, 0, 0); +#if MPPE_SUPPORT + if (go->mppe) { + go->mppe = 0; + if (pcb->lcp_fsm.state == PPP_FSM_OPENED) { + /* If LCP is not already going down, make sure it does. */ + ppp_error("MPPE disabled"); + lcp_close(pcb, "MPPE disabled"); + } + } +#endif /* MPPE_SUPPORT */ +} + +#if PRINTPKT_SUPPORT +/* + * Print the contents of a CCP packet. + */ +static const char* const ccp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej", + NULL, NULL, NULL, NULL, NULL, NULL, + "ResetReq", "ResetAck", +}; + +static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { + const u_char *p0, *optend; + int code, id, len; + int optlen; + + p0 = p; + if (plen < HEADERLEN) + return 0; + code = p[0]; + id = p[1]; + len = (p[2] << 8) + p[3]; + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ccp_codenames) && ccp_codenames[code-1] != NULL) + printer(arg, " %s", ccp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + p += HEADERLEN; + + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print list of possible compression methods */ + while (len >= 2) { + code = p[0]; + optlen = p[1]; + if (optlen < 2 || optlen > len) + break; + printer(arg, " <"); + len -= optlen; + optend = p + optlen; + switch (code) { +#if MPPE_SUPPORT + case CI_MPPE: + if (optlen >= CILEN_MPPE) { + u_char mppe_opts; + + MPPE_CI_TO_OPTS(&p[2], mppe_opts); + printer(arg, "mppe %s %s %s %s %s %s%s", + (p[2] & MPPE_H_BIT)? "+H": "-H", + (p[5] & MPPE_M_BIT)? "+M": "-M", + (p[5] & MPPE_S_BIT)? "+S": "-S", + (p[5] & MPPE_L_BIT)? "+L": "-L", + (p[5] & MPPE_D_BIT)? "+D": "-D", + (p[5] & MPPE_C_BIT)? "+C": "-C", + (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": ""); + if (mppe_opts & MPPE_OPT_UNKNOWN) + printer(arg, " (%.2x %.2x %.2x %.2x)", + p[2], p[3], p[4], p[5]); + p += CILEN_MPPE; + } + break; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (optlen >= CILEN_DEFLATE) { + printer(arg, "deflate%s %d", + (code == CI_DEFLATE_DRAFT? "(old#)": ""), + DEFLATE_SIZE(p[2])); + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL) + printer(arg, " method %d", DEFLATE_METHOD(p[2])); + if (p[3] != DEFLATE_CHK_SEQUENCE) + printer(arg, " check %d", p[3]); + p += CILEN_DEFLATE; + } + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (optlen >= CILEN_BSD_COMPRESS) { + printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), + BSD_NBITS(p[2])); + p += CILEN_BSD_COMPRESS; + } + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + if (optlen >= CILEN_PREDICTOR_1) { + printer(arg, "predictor 1"); + p += CILEN_PREDICTOR_1; + } + break; + case CI_PREDICTOR_2: + if (optlen >= CILEN_PREDICTOR_2) { + printer(arg, "predictor 2"); + p += CILEN_PREDICTOR_2; + } + break; +#endif /* PREDICTOR_SUPPORT */ + default: + break; + } + while (p < optend) + printer(arg, " %.2x", *p++); + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* dump out the rest of the packet in hex */ + while (--len >= 0) + printer(arg, " %.2x", *p++); + + return p - p0; +} +#endif /* PRINTPKT_SUPPORT */ + +#if PPP_DATAINPUT +/* + * We have received a packet that the decompressor failed to + * decompress. Here we would expect to issue a reset-request, but + * Motorola has a patent on resetting the compressor as a result of + * detecting an error in the decompressed data after decompression. + * (See US patent 5,130,993; international patent publication number + * WO 91/10289; Australian patent 73296/91.) + * + * So we ask the kernel whether the error was detected after + * decompression; if it was, we take CCP down, thus disabling + * compression :-(, otherwise we issue the reset-request. + */ +static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len) { + fsm *f; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + LWIP_UNUSED_ARG(pkt); + LWIP_UNUSED_ARG(len); + + f = &pcb->ccp_fsm; + if (f->state == PPP_FSM_OPENED) { + if (ccp_fatal_error(pcb)) { + /* + * Disable compression by taking CCP down. + */ + ppp_error("Lost compression sync: disabling compression"); + ccp_close(pcb, "Lost compression sync"); +#if MPPE_SUPPORT + /* + * If we were doing MPPE, we must also take the link down. + */ + if (go->mppe) { + ppp_error("Too many MPPE errors, closing LCP"); + lcp_close(pcb, "Too many MPPE errors"); + } +#endif /* MPPE_SUPPORT */ + } else { + /* + * Send a reset-request to reset the peer's compressor. + * We don't do that if we are still waiting for an + * acknowledgement to a previous reset-request. + */ + if (!(pcb->ccp_localstate & RACK_PENDING)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate |= RACK_PENDING; + } else + pcb->ccp_localstate |= RREQ_REPEAT; + } + } +} +#endif /* PPP_DATAINPUT */ + +/* + * We have received a packet that the decompressor failed to + * decompress. Issue a reset-request. + */ +void ccp_resetrequest(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + + if (f->state != PPP_FSM_OPENED) + return; + + /* + * Send a reset-request to reset the peer's compressor. + * We don't do that if we are still waiting for an + * acknowledgement to a previous reset-request. + */ + if (!(pcb->ccp_localstate & RACK_PENDING)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate |= RACK_PENDING; + } else + pcb->ccp_localstate |= RREQ_REPEAT; +} + +/* + * Timeout waiting for reset-ack. + */ +static void ccp_rack_timeout(void *arg) { + fsm *f = (fsm*)arg; + ppp_pcb *pcb = f->pcb; + + if (f->state == PPP_FSM_OPENED && (pcb->ccp_localstate & RREQ_REPEAT)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate &= ~RREQ_REPEAT; + } else + pcb->ccp_localstate &= ~RACK_PENDING; +} + +#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-md5.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-md5.c new file mode 100644 index 0000000..88f069f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-md5.c @@ -0,0 +1,126 @@ +/* + * chap-md5.c - New CHAP/MD5 implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap-md5.h" +#include "netif/ppp/magic.h" +#include "netif/ppp/pppcrypt.h" + +#define MD5_HASH_SIZE 16 +#define MD5_MIN_CHALLENGE 17 +#define MD5_MAX_CHALLENGE 24 +#define MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE 3 /* 2^3-1 = 7, 17+7 = 24 */ + +#if PPP_SERVER +static void chap_md5_generate_challenge(ppp_pcb *pcb, unsigned char *cp) { + int clen; + LWIP_UNUSED_ARG(pcb); + + clen = MD5_MIN_CHALLENGE + magic_pow(MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE); + *cp++ = clen; + magic_random_bytes(cp, clen); +} + +static int chap_md5_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + lwip_md5_context ctx; + unsigned char idbyte = id; + unsigned char hash[MD5_HASH_SIZE]; + int challenge_len, response_len; + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(pcb); + + challenge_len = *challenge++; + response_len = *response++; + if (response_len == MD5_HASH_SIZE) { + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&ctx); + lwip_md5_starts(&ctx); + lwip_md5_update(&ctx, &idbyte, 1); + lwip_md5_update(&ctx, secret, secret_len); + lwip_md5_update(&ctx, challenge, challenge_len); + lwip_md5_finish(&ctx, hash); + lwip_md5_free(&ctx); + + /* Test if our hash matches the peer's response */ + if (memcmp(hash, response, MD5_HASH_SIZE) == 0) { + ppp_slprintf(message, message_space, "Access granted"); + return 1; + } + } + ppp_slprintf(message, message_space, "Access denied"); + return 0; +} +#endif /* PPP_SERVER */ + +static void chap_md5_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + lwip_md5_context ctx; + unsigned char idbyte = id; + int challenge_len = *challenge++; + LWIP_UNUSED_ARG(our_name); + LWIP_UNUSED_ARG(private_); + LWIP_UNUSED_ARG(pcb); + + lwip_md5_init(&ctx); + lwip_md5_starts(&ctx); + lwip_md5_update(&ctx, &idbyte, 1); + lwip_md5_update(&ctx, (const u_char *)secret, secret_len); + lwip_md5_update(&ctx, challenge, challenge_len); + lwip_md5_finish(&ctx, &response[1]); + lwip_md5_free(&ctx); + response[0] = MD5_HASH_SIZE; +} + +const struct chap_digest_type md5_digest = { + CHAP_MD5, /* code */ +#if PPP_SERVER + chap_md5_generate_challenge, + chap_md5_verify_response, +#endif /* PPP_SERVER */ + chap_md5_make_response, + NULL, /* check_success */ + NULL, /* handle_failure */ +}; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-new.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-new.c new file mode 100644 index 0000000..485122d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap-new.c @@ -0,0 +1,677 @@ +/* + * chap-new.c - New CHAP implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#if 0 /* UNUSED */ +#include "session.h" +#endif /* UNUSED */ + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap-md5.h" +#if MSCHAP_SUPPORT +#include "netif/ppp/chap_ms.h" +#endif +#include "netif/ppp/magic.h" + +#if 0 /* UNUSED */ +/* Hook for a plugin to validate CHAP challenge */ +int (*chap_verify_hook)(const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) = NULL; +#endif /* UNUSED */ + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t chap_option_list[] = { + { "chap-restart", o_int, &chap_timeout_time, + "Set timeout for CHAP", OPT_PRIO }, + { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits, + "Set max #xmits for challenge", OPT_PRIO }, + { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time, + "Set interval for rechallenge", OPT_PRIO }, + { NULL } +}; +#endif /* PPP_OPTIONS */ + + +/* Values for flags in chap_client_state and chap_server_state */ +#define LOWERUP 1 +#define AUTH_STARTED 2 +#define AUTH_DONE 4 +#define AUTH_FAILED 8 +#define TIMEOUT_PENDING 0x10 +#define CHALLENGE_VALID 0x20 + +/* + * Prototypes. + */ +static void chap_init(ppp_pcb *pcb); +static void chap_lowerup(ppp_pcb *pcb); +static void chap_lowerdown(ppp_pcb *pcb); +#if PPP_SERVER +static void chap_timeout(void *arg); +static void chap_generate_challenge(ppp_pcb *pcb); +static void chap_handle_response(ppp_pcb *pcb, int code, + unsigned char *pkt, int len); +static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space); +#endif /* PPP_SERVER */ +static void chap_respond(ppp_pcb *pcb, int id, + unsigned char *pkt, int len); +static void chap_handle_status(ppp_pcb *pcb, int code, int id, + unsigned char *pkt, int len); +static void chap_protrej(ppp_pcb *pcb); +static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen); +#if PRINTPKT_SUPPORT +static int chap_print_pkt(const unsigned char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +/* List of digest types that we know about */ +static const struct chap_digest_type* const chap_digests[] = { + &md5_digest, +#if MSCHAP_SUPPORT + &chapms_digest, + &chapms2_digest, +#endif /* MSCHAP_SUPPORT */ + NULL +}; + +/* + * chap_init - reset to initial state. + */ +static void chap_init(ppp_pcb *pcb) { + LWIP_UNUSED_ARG(pcb); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(&pcb->chap_client, 0, sizeof(chap_client_state)); +#if PPP_SERVER + memset(&pcb->chap_server, 0, sizeof(chap_server_state)); +#endif /* PPP_SERVER */ +#endif /* 0 */ +} + +/* + * chap_lowerup - we can start doing stuff now. + */ +static void chap_lowerup(ppp_pcb *pcb) { + + pcb->chap_client.flags |= LOWERUP; +#if PPP_SERVER + pcb->chap_server.flags |= LOWERUP; + if (pcb->chap_server.flags & AUTH_STARTED) + chap_timeout(pcb); +#endif /* PPP_SERVER */ +} + +static void chap_lowerdown(ppp_pcb *pcb) { + + pcb->chap_client.flags = 0; +#if PPP_SERVER + if (pcb->chap_server.flags & TIMEOUT_PENDING) + UNTIMEOUT(chap_timeout, pcb); + pcb->chap_server.flags = 0; +#endif /* PPP_SERVER */ +} + +#if PPP_SERVER +/* + * chap_auth_peer - Start authenticating the peer. + * If the lower layer is already up, we start sending challenges, + * otherwise we wait for the lower layer to come up. + */ +void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { + const struct chap_digest_type *dp; + int i; + + if (pcb->chap_server.flags & AUTH_STARTED) { + ppp_error("CHAP: peer authentication already started!"); + return; + } + for (i = 0; (dp = chap_digests[i]) != NULL; ++i) + if (dp->code == digest_code) + break; + if (dp == NULL) + ppp_fatal("CHAP digest 0x%x requested but not available", + digest_code); + + pcb->chap_server.digest = dp; + pcb->chap_server.name = our_name; + /* Start with a random ID value */ + pcb->chap_server.id = magic(); + pcb->chap_server.flags |= AUTH_STARTED; + if (pcb->chap_server.flags & LOWERUP) + chap_timeout(pcb); +} +#endif /* PPP_SERVER */ + +/* + * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. + * There isn't much to do until we receive a challenge. + */ +void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { + const struct chap_digest_type *dp; + int i; + + if(NULL == our_name) + return; + + if (pcb->chap_client.flags & AUTH_STARTED) { + ppp_error("CHAP: authentication with peer already started!"); + return; + } + for (i = 0; (dp = chap_digests[i]) != NULL; ++i) + if (dp->code == digest_code) + break; + + if (dp == NULL) + ppp_fatal("CHAP digest 0x%x requested but not available", + digest_code); + + pcb->chap_client.digest = dp; + pcb->chap_client.name = our_name; + pcb->chap_client.flags |= AUTH_STARTED; +} + +#if PPP_SERVER +/* + * chap_timeout - It's time to send another challenge to the peer. + * This could be either a retransmission of a previous challenge, + * or a new challenge to start re-authentication. + */ +static void chap_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + struct pbuf *p; + + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) { + pcb->chap_server.challenge_xmits = 0; + chap_generate_challenge(pcb); + pcb->chap_server.flags |= CHALLENGE_VALID; + } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) { + pcb->chap_server.flags &= ~CHALLENGE_VALID; + pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED; + auth_peer_fail(pcb, PPP_CHAP); + return; + } + + p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen); + ppp_write(pcb, p); + ++pcb->chap_server.challenge_xmits; + pcb->chap_server.flags |= TIMEOUT_PENDING; + TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time); +} + +/* + * chap_generate_challenge - generate a challenge string and format + * the challenge packet in pcb->chap_server.challenge_pkt. + */ +static void chap_generate_challenge(ppp_pcb *pcb) { + int clen = 1, nlen, len; + unsigned char *p; + + p = pcb->chap_server.challenge; + MAKEHEADER(p, PPP_CHAP); + p += CHAP_HDRLEN; + pcb->chap_server.digest->generate_challenge(pcb, p); + clen = *p; + nlen = strlen(pcb->chap_server.name); + memcpy(p + 1 + clen, pcb->chap_server.name, nlen); + + len = CHAP_HDRLEN + 1 + clen + nlen; + pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len; + + p = pcb->chap_server.challenge + PPP_HDRLEN; + p[0] = CHAP_CHALLENGE; + p[1] = ++pcb->chap_server.id; + p[2] = len >> 8; + p[3] = len; +} + +/* + * chap_handle_response - check the response to our challenge. + */ +static void chap_handle_response(ppp_pcb *pcb, int id, + unsigned char *pkt, int len) { + int response_len, ok, mlen; + const unsigned char *response; + unsigned char *outp; + struct pbuf *p; + const char *name = NULL; /* initialized to shut gcc up */ +#if 0 /* UNUSED */ + int (*verifier)(const char *, const char *, int, const struct chap_digest_type *, + const unsigned char *, const unsigned char *, char *, int); +#endif /* UNUSED */ + char rname[MAXNAMELEN+1]; + char message[256]; + + if ((pcb->chap_server.flags & LOWERUP) == 0) + return; + if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2) + return; + if (pcb->chap_server.flags & CHALLENGE_VALID) { + response = pkt; + GETCHAR(response_len, pkt); + len -= response_len + 1; /* length of name */ + name = (char *)pkt + response_len; + if (len < 0) + return; + + if (pcb->chap_server.flags & TIMEOUT_PENDING) { + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + UNTIMEOUT(chap_timeout, pcb); + } +#if PPP_REMOTENAME + if (pcb->settings.explicit_remote) { + name = pcb->remote_name; + } else +#endif /* PPP_REMOTENAME */ + { + /* Null terminate and clean remote name. */ + ppp_slprintf(rname, sizeof(rname), "%.*v", len, name); + name = rname; + } + +#if 0 /* UNUSED */ + if (chap_verify_hook) + verifier = chap_verify_hook; + else + verifier = chap_verify_response; + ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest, + pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, + response, pcb->chap_server.message, sizeof(pcb->chap_server.message)); +#endif /* UNUSED */ + ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest, + pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, + response, message, sizeof(message)); +#if 0 /* UNUSED */ + if (!ok || !auth_number()) { +#endif /* UNUSED */ + if (!ok) { + pcb->chap_server.flags |= AUTH_FAILED; + ppp_warn("Peer %q failed CHAP authentication", name); + } + } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) + return; + + /* send the response */ + mlen = strlen(message); + len = CHAP_HDRLEN + mlen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (unsigned char *)p->payload; + MAKEHEADER(outp, PPP_CHAP); + + outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; + outp[1] = id; + outp[2] = len >> 8; + outp[3] = len; + if (mlen > 0) + memcpy(outp + CHAP_HDRLEN, message, mlen); + ppp_write(pcb, p); + + if (pcb->chap_server.flags & CHALLENGE_VALID) { + pcb->chap_server.flags &= ~CHALLENGE_VALID; + if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) { + +#if 0 /* UNUSED */ + /* + * Auth is OK, so now we need to check session restrictions + * to ensure everything is OK, but only if we used a + * plugin, and only if we're configured to check. This + * allows us to do PAM checks on PPP servers that + * authenticate against ActiveDirectory, and use AD for + * account info (like when using Winbind integrated with + * PAM). + */ + if (session_mgmt && + session_check(name, NULL, devnam, NULL) == 0) { + pcb->chap_server.flags |= AUTH_FAILED; + ppp_warn("Peer %q failed CHAP Session verification", name); + } +#endif /* UNUSED */ + + } + if (pcb->chap_server.flags & AUTH_FAILED) { + auth_peer_fail(pcb, PPP_CHAP); + } else { + if ((pcb->chap_server.flags & AUTH_DONE) == 0) + auth_peer_success(pcb, PPP_CHAP, + pcb->chap_server.digest->code, + name, strlen(name)); + if (pcb->settings.chap_rechallenge_time) { + pcb->chap_server.flags |= TIMEOUT_PENDING; + TIMEOUT(chap_timeout, pcb, + pcb->settings.chap_rechallenge_time); + } + } + pcb->chap_server.flags |= AUTH_DONE; + } +} + +/* + * chap_verify_response - check whether the peer's response matches + * what we think it should be. Returns 1 if it does (authentication + * succeeded), or 0 if it doesn't. + */ +static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + int ok; + unsigned char secret[MAXSECRETLEN]; + int secret_len; + + /* Get the secret that the peer is supposed to know */ + if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { + ppp_error("No CHAP secret found for authenticating %q", name); + return 0; + } + ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, + response, message, message_space); + memset(secret, 0, sizeof(secret)); + + return ok; +} +#endif /* PPP_SERVER */ + +/* + * chap_respond - Generate and send a response to a challenge. + */ +static void chap_respond(ppp_pcb *pcb, int id, + unsigned char *pkt, int len) { + int clen, nlen; + int secret_len; + struct pbuf *p; + u_char *outp; + char rname[MAXNAMELEN+1]; + char secret[MAXSECRETLEN+1]; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) + return; /* not ready */ + if (len < 2 || len < pkt[0] + 1) + return; /* too short */ + clen = pkt[0]; + nlen = len - (clen + 1); + + /* Null terminate and clean remote name. */ + ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); + +#if PPP_REMOTENAME + /* Microsoft doesn't send their name back in the PPP packet */ + if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0)) + strlcpy(rname, pcb->settings.remote_name, sizeof(rname)); +#endif /* PPP_REMOTENAME */ + + /* get secret for authenticating ourselves with the specified host */ + if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { + secret_len = 0; /* assume null secret if can't find one */ + ppp_warn("No CHAP secret found for authenticating us to %q", rname); + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_CHAP); + outp += CHAP_HDRLEN; + + pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt, + secret, secret_len, pcb->chap_client.priv); + memset(secret, 0, secret_len); + + clen = *outp; + nlen = strlen(pcb->chap_client.name); + memcpy(outp + clen + 1, pcb->chap_client.name, nlen); + + outp = (u_char*)p->payload + PPP_HDRLEN; + len = CHAP_HDRLEN + clen + 1 + nlen; + outp[0] = CHAP_RESPONSE; + outp[1] = id; + outp[2] = len >> 8; + outp[3] = len; + + pbuf_realloc(p, PPP_HDRLEN + len); + ppp_write(pcb, p); +} + +static void chap_handle_status(ppp_pcb *pcb, int code, int id, + unsigned char *pkt, int len) { + const char *msg = NULL; + LWIP_UNUSED_ARG(id); + + if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) + != (AUTH_STARTED|LOWERUP)) + return; + pcb->chap_client.flags |= AUTH_DONE; + + if (code == CHAP_SUCCESS) { + /* used for MS-CHAP v2 mutual auth, yuck */ + if (pcb->chap_client.digest->check_success != NULL) { + if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv)) + code = CHAP_FAILURE; + } else + msg = "CHAP authentication succeeded"; + } else { + if (pcb->chap_client.digest->handle_failure != NULL) + (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len); + else + msg = "CHAP authentication failed"; + } + if (msg) { + if (len > 0) + ppp_info("%s: %.*v", msg, len, pkt); + else + ppp_info("%s", msg); + } + if (code == CHAP_SUCCESS) + auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); + else { + pcb->chap_client.flags |= AUTH_FAILED; + ppp_error("CHAP authentication failed"); + auth_withpeer_fail(pcb, PPP_CHAP); + } +} + +static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) { + unsigned char code, id; + int len; + + if (pktlen < CHAP_HDRLEN) + return; + GETCHAR(code, pkt); + GETCHAR(id, pkt); + GETSHORT(len, pkt); + if (len < CHAP_HDRLEN || len > pktlen) + return; + len -= CHAP_HDRLEN; + + switch (code) { + case CHAP_CHALLENGE: + chap_respond(pcb, id, pkt, len); + break; +#if PPP_SERVER + case CHAP_RESPONSE: + chap_handle_response(pcb, id, pkt, len); + break; +#endif /* PPP_SERVER */ + case CHAP_FAILURE: + case CHAP_SUCCESS: + chap_handle_status(pcb, code, id, pkt, len); + break; + default: + break; + } +} + +static void chap_protrej(ppp_pcb *pcb) { + +#if PPP_SERVER + if (pcb->chap_server.flags & TIMEOUT_PENDING) { + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + UNTIMEOUT(chap_timeout, pcb); + } + if (pcb->chap_server.flags & AUTH_STARTED) { + pcb->chap_server.flags = 0; + auth_peer_fail(pcb, PPP_CHAP); + } +#endif /* PPP_SERVER */ + if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { + pcb->chap_client.flags &= ~AUTH_STARTED; + ppp_error("CHAP authentication failed due to protocol-reject"); + auth_withpeer_fail(pcb, PPP_CHAP); + } +} + +#if PRINTPKT_SUPPORT +/* + * chap_print_pkt - print the contents of a CHAP packet. + */ +static const char* const chap_code_names[] = { + "Challenge", "Response", "Success", "Failure" +}; + +static int chap_print_pkt(const unsigned char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len; + int clen, nlen; + unsigned char x; + + if (plen < CHAP_HDRLEN) + return 0; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < CHAP_HDRLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names)) + printer(arg, " %s", chap_code_names[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= CHAP_HDRLEN; + switch (code) { + case CHAP_CHALLENGE: + case CHAP_RESPONSE: + if (len < 1) + break; + clen = p[0]; + if (len < clen + 1) + break; + ++p; + nlen = len - clen - 1; + printer(arg, " <"); + for (; clen > 0; --clen) { + GETCHAR(x, p); + printer(arg, "%.2x", x); + } + printer(arg, ">, name = "); + ppp_print_string(p, nlen, printer, arg); + break; + case CHAP_FAILURE: + case CHAP_SUCCESS: + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + break; + default: + for (clen = len; clen > 0; --clen) { + GETCHAR(x, p); + printer(arg, " %.2x", x); + } + /* no break */ + } + + return len + CHAP_HDRLEN; +} +#endif /* PRINTPKT_SUPPORT */ + +const struct protent chap_protent = { + PPP_CHAP, + chap_init, + chap_input, + chap_protrej, + chap_lowerup, + chap_lowerdown, + NULL, /* open */ + NULL, /* close */ +#if PRINTPKT_SUPPORT + chap_print_pkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* datainput */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "CHAP", /* name */ + NULL, /* data_name */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + chap_option_list, + NULL, /* check_options */ +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap_ms.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap_ms.c new file mode 100644 index 0000000..5a989c9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/chap_ms.c @@ -0,0 +1,962 @@ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 + * + * Implemented LANManager type password response to MS-CHAP challenges. + * Now pppd provides both NT style and LANMan style blocks, and the + * prefered is set by option "ms-lanman". Default is to use NT. + * The hash text (StdText) was taken from Win95 RASAPI32.DLL. + * + * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 + */ + +/* + * Modifications by Frank Cusack, frank@google.com, March 2002. + * + * Implemented MS-CHAPv2 functionality, heavily based on sample + * implementation in RFC 2759. Implemented MPPE functionality, + * heavily based on sample implementation in RFC 3079. + * + * Copyright (c) 2002 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap_ms.h" +#include "netif/ppp/pppcrypt.h" +#include "netif/ppp/magic.h" +#if MPPE_SUPPORT +#include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */ +#endif /* MPPE_SUPPORT */ + +#define SHA1_SIGNATURE_SIZE 20 +#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */ +#define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */ + +#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ +#define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ +#define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */ + /* as ASCII */ + +/* Error codes for MS-CHAP failure messages. */ +#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646 +#define MS_CHAP_ERROR_ACCT_DISABLED 647 +#define MS_CHAP_ERROR_PASSWD_EXPIRED 648 +#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649 +#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691 +#define MS_CHAP_ERROR_CHANGING_PASSWORD 709 + +/* + * Offsets within the response field for MS-CHAP + */ +#define MS_CHAP_LANMANRESP 0 +#define MS_CHAP_LANMANRESP_LEN 24 +#define MS_CHAP_NTRESP 24 +#define MS_CHAP_NTRESP_LEN 24 +#define MS_CHAP_USENT 48 + +/* + * Offsets within the response field for MS-CHAP2 + */ +#define MS_CHAP2_PEER_CHALLENGE 0 +#define MS_CHAP2_PEER_CHAL_LEN 16 +#define MS_CHAP2_RESERVED_LEN 8 +#define MS_CHAP2_NTRESP 24 +#define MS_CHAP2_NTRESP_LEN 24 +#define MS_CHAP2_FLAGS 48 + +#if MPPE_SUPPORT +#if 0 /* UNUSED */ +/* These values are the RADIUS attribute values--see RFC 2548. */ +#define MPPE_ENC_POL_ENC_ALLOWED 1 +#define MPPE_ENC_POL_ENC_REQUIRED 2 +#define MPPE_ENC_TYPES_RC4_40 2 +#define MPPE_ENC_TYPES_RC4_128 4 + +/* used by plugins (using above values) */ +extern void set_mppe_enc_types(int, int); +#endif /* UNUSED */ +#endif /* MPPE_SUPPORT */ + +/* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ +#define MS_CHAP2_AUTHENTICATEE 0 +#define MS_CHAP2_AUTHENTICATOR 1 + +static void ascii2unicode (const char[], int, u_char[]); +static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); +static void ChallengeResponse (const u_char *, const u_char *, u_char[24]); +static void ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]); +static void ChapMS_NT (const u_char *, const char *, int, u_char[24]); +static void ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int, + u_char[24]); +static void GenerateAuthenticatorResponsePlain + (const char*, int, u_char[24], const u_char[16], const u_char *, + const char *, u_char[41]); +#ifdef MSLANMAN +static void ChapMS_LANMan (u_char *, char *, int, u_char *); +#endif + +static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]); + +#if MPPE_SUPPORT +static void Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int); +static void SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int); +#endif /* MPPE_SUPPORT */ + +static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *); +static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int, + u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int); + +#ifdef MSLANMAN +bool ms_lanman = 0; /* Use LanMan password instead of NT */ + /* Has meaning only with MS-CHAP challenges */ +#endif + +#if MPPE_SUPPORT +#ifdef DEBUGMPPEKEY +/* For MPPE debug */ +/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ +static char *mschap_challenge = NULL; +/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ +static char *mschap2_peer_challenge = NULL; +#endif + +#include "netif/ppp/fsm.h" /* Need to poke MPPE options */ +#include "netif/ppp/ccp.h" +#endif /* MPPE_SUPPORT */ + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t chapms_option_list[] = { +#ifdef MSLANMAN + { "ms-lanman", o_bool, &ms_lanman, + "Use LanMan passwd when using MS-CHAP", 1 }, +#endif +#ifdef DEBUGMPPEKEY + { "mschap-challenge", o_string, &mschap_challenge, + "specify CHAP challenge" }, + { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, + "specify CHAP peer challenge" }, +#endif + { NULL } +}; +#endif /* PPP_OPTIONS */ + +#if PPP_SERVER +/* + * chapms_generate_challenge - generate a challenge for MS-CHAP. + * For MS-CHAP the challenge length is fixed at 8 bytes. + * The length goes in challenge[0] and the actual challenge starts + * at challenge[1]. + */ +static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { + LWIP_UNUSED_ARG(pcb); + + *challenge++ = 8; +#ifdef DEBUGMPPEKEY + if (mschap_challenge && strlen(mschap_challenge) == 8) + memcpy(challenge, mschap_challenge, 8); + else +#endif + magic_random_bytes(challenge, 8); +} + +static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { + LWIP_UNUSED_ARG(pcb); + + *challenge++ = 16; +#ifdef DEBUGMPPEKEY + if (mschap_challenge && strlen(mschap_challenge) == 16) + memcpy(challenge, mschap_challenge, 16); + else +#endif + magic_random_bytes(challenge, 16); +} + +static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + unsigned char md[MS_CHAP_RESPONSE_LEN]; + int diff; + int challenge_len, response_len; + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(name); + + challenge_len = *challenge++; /* skip length, is 8 */ + response_len = *response++; + if (response_len != MS_CHAP_RESPONSE_LEN) + goto bad; + +#ifndef MSLANMAN + if (!response[MS_CHAP_USENT]) { + /* Should really propagate this into the error packet. */ + ppp_notice("Peer request for LANMAN auth not supported"); + goto bad; + } +#endif + + /* Generate the expected response. */ + ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md); + +#ifdef MSLANMAN + /* Determine which part of response to verify against */ + if (!response[MS_CHAP_USENT]) + diff = memcmp(&response[MS_CHAP_LANMANRESP], + &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN); + else +#endif + diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP], + MS_CHAP_NTRESP_LEN); + + if (diff == 0) { + ppp_slprintf(message, message_space, "Access granted"); + return 1; + } + + bad: + /* See comments below for MS-CHAP V2 */ + ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", + challenge_len, challenge); + return 0; +} + +static int chapms2_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + unsigned char md[MS_CHAP2_RESPONSE_LEN]; + char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; + int challenge_len, response_len; + LWIP_UNUSED_ARG(id); + + challenge_len = *challenge++; /* skip length, is 16 */ + response_len = *response++; + if (response_len != MS_CHAP2_RESPONSE_LEN) + goto bad; /* not even the right length */ + + /* Generate the expected response and our mutual auth. */ + ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name, + (const char *)secret, secret_len, md, + (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); + + /* compare MDs and send the appropriate status */ + /* + * Per RFC 2759, success message must be formatted as + * "S= M=" + * where + * is the Authenticator Response (mutual auth) + * is a text message + * + * However, some versions of Windows (win98 tested) do not know + * about the M= part (required per RFC 2759) and flag + * it as an error (reported incorrectly as an encryption error + * to the user). Since the RFC requires it, and it can be + * useful information, we supply it if the peer is a conforming + * system. Luckily (?), win98 sets the Flags field to 0x04 + * (contrary to RFC requirements) so we can use that to + * distinguish between conforming and non-conforming systems. + * + * Special thanks to Alex Swiridov for + * help debugging this. + */ + if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP], + MS_CHAP2_NTRESP_LEN) == 0) { + if (response[MS_CHAP2_FLAGS]) + ppp_slprintf(message, message_space, "S=%s", saresponse); + else + ppp_slprintf(message, message_space, "S=%s M=%s", + saresponse, "Access granted"); + return 1; + } + + bad: + /* + * Failure message must be formatted as + * "E=e R=r C=c V=v M=m" + * where + * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) + * r = retry (we use 1, ok to retry) + * c = challenge to use for next response, we reuse previous + * v = Change Password version supported, we use 0 + * m = text message + * + * The M=m part is only for MS-CHAPv2. Neither win2k nor + * win98 (others untested) display the message to the user anyway. + * They also both ignore the E=e code. + * + * Note that it's safe to reuse the same challenge as we don't + * actually accept another response based on the error message + * (and no clients try to resend a response anyway). + * + * Basically, this whole bit is useless code, even the small + * implementation here is only because of overspecification. + */ + ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", + challenge_len, challenge, "Access denied"); + return 0; +} +#endif /* PPP_SERVER */ + +static void chapms_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(our_name); + LWIP_UNUSED_ARG(private_); + challenge++; /* skip length, should be 8 */ + *response++ = MS_CHAP_RESPONSE_LEN; + ChapMS(pcb, challenge, secret, secret_len, response); +} + +static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + LWIP_UNUSED_ARG(id); + challenge++; /* skip length, should be 16 */ + *response++ = MS_CHAP2_RESPONSE_LEN; + ChapMS2(pcb, challenge, +#ifdef DEBUGMPPEKEY + mschap2_peer_challenge, +#else + NULL, +#endif + our_name, secret, secret_len, response, private_, + MS_CHAP2_AUTHENTICATEE); +} + +static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) { + LWIP_UNUSED_ARG(pcb); + + if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || + strncmp((char *)msg, "S=", 2) != 0) { + /* Packet does not start with "S=" */ + ppp_error("MS-CHAPv2 Success packet is badly formed."); + return 0; + } + msg += 2; + len -= 2; + if (len < MS_AUTH_RESPONSE_LENGTH + || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) { + /* Authenticator Response did not match expected. */ + ppp_error("MS-CHAPv2 mutual authentication failed."); + return 0; + } + /* Authenticator Response matches. */ + msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ + len -= MS_AUTH_RESPONSE_LENGTH; + if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { + msg += 3; /* Eat the delimiter */ + } else if (len) { + /* Packet has extra text which does not begin " M=" */ + ppp_error("MS-CHAPv2 Success packet is badly formed."); + return 0; + } + return 1; +} + +static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) { + int err; + const char *p; + char msg[64]; + LWIP_UNUSED_ARG(pcb); + + /* We want a null-terminated string for strxxx(). */ + len = LWIP_MIN(len, 63); + MEMCPY(msg, inp, len); + msg[len] = 0; + p = msg; + + /* + * Deal with MS-CHAP formatted failure messages; just print the + * M= part (if any). For MS-CHAP we're not really supposed + * to use M=, but it shouldn't hurt. See + * chapms[2]_verify_response. + */ + if (!strncmp(p, "E=", 2)) + err = strtol(p+2, NULL, 10); /* Remember the error code. */ + else + goto print_msg; /* Message is badly formatted. */ + + if (len && ((p = strstr(p, " M=")) != NULL)) { + /* M= field found. */ + p += 3; + } else { + /* No M=; use the error code. */ + switch (err) { + case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: + p = "E=646 Restricted logon hours"; + break; + + case MS_CHAP_ERROR_ACCT_DISABLED: + p = "E=647 Account disabled"; + break; + + case MS_CHAP_ERROR_PASSWD_EXPIRED: + p = "E=648 Password expired"; + break; + + case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: + p = "E=649 No dialin permission"; + break; + + case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: + p = "E=691 Authentication failure"; + break; + + case MS_CHAP_ERROR_CHANGING_PASSWORD: + /* Should never see this, we don't support Change Password. */ + p = "E=709 Error changing password"; + break; + + default: + ppp_error("Unknown MS-CHAP authentication failure: %.*v", + len, inp); + return; + } + } +print_msg: + if (p != NULL) + ppp_error("MS-CHAP authentication failed: %v", p); +} + +static void ChallengeResponse(const u_char *challenge, + const u_char PasswordHash[MD4_SIGNATURE_SIZE], + u_char response[24]) { + u_char ZPasswordHash[21]; + lwip_des_context des; + u_char des_key[8]; + + BZERO(ZPasswordHash, sizeof(ZPasswordHash)); + MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE); + +#if 0 + dbglog("ChallengeResponse - ZPasswordHash %.*B", + sizeof(ZPasswordHash), ZPasswordHash); +#endif + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +0); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +8); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +16); + lwip_des_free(&des); + +#if 0 + dbglog("ChallengeResponse - response %.24B", response); +#endif +} + +static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge, + const char *username, u_char Challenge[8]) { + lwip_sha1_context sha1Context; + u_char sha1Hash[SHA1_SIGNATURE_SIZE]; + const char *user; + + /* remove domain from "domain\username" */ + if ((user = strrchr(username, '\\')) != NULL) + ++user; + else + user = username; + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PeerChallenge, 16); + lwip_sha1_update(&sha1Context, rchallenge, 16); + lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user)); + lwip_sha1_finish(&sha1Context, sha1Hash); + lwip_sha1_free(&sha1Context); + + MEMCPY(Challenge, sha1Hash, 8); +} + +/* + * Convert the ASCII version of the password to Unicode. + * This implicitly supports 8-bit ISO8859/1 characters. + * This gives us the little-endian representation, which + * is assumed by all M$ CHAP RFCs. (Unicode byte ordering + * is machine-dependent.) + */ +static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) { + int i; + + BZERO(unicode, ascii_len * 2); + for (i = 0; i < ascii_len; i++) + unicode[i * 2] = (u_char) ascii[i]; +} + +static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) { + lwip_md4_context md4Context; + + lwip_md4_init(&md4Context); + lwip_md4_starts(&md4Context); + lwip_md4_update(&md4Context, secret, secret_len); + lwip_md4_finish(&md4Context, hash); + lwip_md4_free(&md4Context); +} + +static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len, + u_char NTResponse[24]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(rchallenge, PasswordHash, NTResponse); +} + +static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username, + const char *secret, int secret_len, u_char NTResponse[24]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char Challenge[8]; + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(Challenge, PasswordHash, NTResponse); +} + +#ifdef MSLANMAN +static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ + +static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, + unsigned char *response) { + int i; + u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + lwip_des_context des; + u_char des_key[8]; + + /* LANMan password is case insensitive */ + BZERO(UcasePassword, sizeof(UcasePassword)); + for (i = 0; i < secret_len; i++) + UcasePassword[i] = (u_char)toupper(secret[i]); + + pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, StdText, PasswordHash +0); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, StdText, PasswordHash +8); + lwip_des_free(&des); + + ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); +} +#endif + + +static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { + /* + * "Magic" constants used in response generation, from RFC 2759. + */ + static const u_char Magic1[39] = /* "Magic server to client signing constant" */ + { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; + static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ + { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E }; + + int i; + lwip_sha1_context sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; + u_char Challenge[8]; + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, NTResponse, 24); + lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, Digest, sizeof(Digest)); + lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge)); + lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2)); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + /* Convert to ASCII hex string. */ + for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++) + sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); +} + + +static void GenerateAuthenticatorResponsePlain( + const char *secret, int secret_len, + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), + PasswordHashHash); + + GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, + rchallenge, username, authResponse); +} + + +#if MPPE_SUPPORT +/* + * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) + */ +static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + lwip_sha1_context sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, rchallenge, 8); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + /* Same key in both directions. */ + mppe_set_key(pcb, &pcb->mppe_comp, Digest); + mppe_set_key(pcb, &pcb->mppe_decomp, Digest); + + pcb->mppe_keys_set = 1; +} + +/* + * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) + */ +static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + lwip_sha1_context sha1Context; + u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + const u_char *s; + + /* "This is the MPPE Master Key" */ + static const u_char Magic1[27] = + { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; + /* "On the client side, this is the send key; " + "on the server side, it is the receive key." */ + static const u_char Magic2[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + /* "On the client side, this is the receive key; " + "on the server side, it is the send key." */ + static const u_char Magic3[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, NTResponse, 24); + lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); + lwip_sha1_finish(&sha1Context, MasterKey); + lwip_sha1_free(&sha1Context); + + /* + * generate send key + */ + if (IsServer) + s = Magic3; + else + s = Magic2; + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, MasterKey, 16); + lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1Context, s, 84); + lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + mppe_set_key(pcb, &pcb->mppe_comp, Digest); + + /* + * generate recv key + */ + if (IsServer) + s = Magic2; + else + s = Magic3; + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, MasterKey, 16); + lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1Context, s, 84); + lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + mppe_set_key(pcb, &pcb->mppe_decomp, Digest); + + pcb->mppe_keys_set = 1; +} + +#endif /* MPPE_SUPPORT */ + + +static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len, + unsigned char *response) { +#if !MPPE_SUPPORT + LWIP_UNUSED_ARG(pcb); +#endif /* !MPPE_SUPPORT */ + BZERO(response, MS_CHAP_RESPONSE_LEN); + + ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); + +#ifdef MSLANMAN + ChapMS_LANMan(rchallenge, secret, secret_len, + &response[MS_CHAP_LANMANRESP]); + + /* preferred method is set by option */ + response[MS_CHAP_USENT] = !ms_lanman; +#else + response[MS_CHAP_USENT] = 1; +#endif + +#if MPPE_SUPPORT + Set_Start_Key(pcb, rchallenge, secret, secret_len); +#endif /* MPPE_SUPPORT */ +} + + +/* + * If PeerChallenge is NULL, one is generated and the PeerChallenge + * field of response is filled in. Call this way when generating a response. + * If PeerChallenge is supplied, it is copied into the PeerChallenge field. + * Call this way when verifying a response (or debugging). + * Do not call with PeerChallenge = response. + * + * The PeerChallenge field of response is then used for calculation of the + * Authenticator Response. + */ +static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge, + const char *user, const char *secret, int secret_len, unsigned char *response, + u_char authResponse[], int authenticator) { + /* ARGSUSED */ + LWIP_UNUSED_ARG(authenticator); +#if !MPPE_SUPPORT + LWIP_UNUSED_ARG(pcb); +#endif /* !MPPE_SUPPORT */ + + BZERO(response, MS_CHAP2_RESPONSE_LEN); + + /* Generate the Peer-Challenge if requested, or copy it if supplied. */ + if (!PeerChallenge) + magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN); + else + MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge, + MS_CHAP2_PEER_CHAL_LEN); + + /* Generate the NT-Response */ + ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, + secret, secret_len, &response[MS_CHAP2_NTRESP]); + + /* Generate the Authenticator Response. */ + GenerateAuthenticatorResponsePlain(secret, secret_len, + &response[MS_CHAP2_NTRESP], + &response[MS_CHAP2_PEER_CHALLENGE], + rchallenge, user, authResponse); + +#if MPPE_SUPPORT + SetMasterKeys(pcb, secret, secret_len, + &response[MS_CHAP2_NTRESP], authenticator); +#endif /* MPPE_SUPPORT */ +} + +#if 0 /* UNUSED */ +#if MPPE_SUPPORT +/* + * Set MPPE options from plugins. + */ +void set_mppe_enc_types(int policy, int types) { + /* Early exit for unknown policies. */ + if (policy != MPPE_ENC_POL_ENC_ALLOWED || + policy != MPPE_ENC_POL_ENC_REQUIRED) + return; + + /* Don't modify MPPE if it's optional and wasn't already configured. */ + if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) + return; + + /* + * Disable undesirable encryption types. Note that we don't ENABLE + * any encryption types, to avoid overriding manual configuration. + */ + switch(types) { + case MPPE_ENC_TYPES_RC4_40: + ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ + break; + case MPPE_ENC_TYPES_RC4_128: + ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ + break; + default: + break; + } +} +#endif /* MPPE_SUPPORT */ +#endif /* UNUSED */ + +const struct chap_digest_type chapms_digest = { + CHAP_MICROSOFT, /* code */ +#if PPP_SERVER + chapms_generate_challenge, + chapms_verify_response, +#endif /* PPP_SERVER */ + chapms_make_response, + NULL, /* check_success */ + chapms_handle_failure, +}; + +const struct chap_digest_type chapms2_digest = { + CHAP_MICROSOFT_V2, /* code */ +#if PPP_SERVER + chapms2_generate_challenge, + chapms2_verify_response, +#endif /* PPP_SERVER */ + chapms2_make_response, + chapms2_check_success, + chapms_handle_failure, +}; + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/demand.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/demand.c new file mode 100644 index 0000000..26c6c30 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/demand.c @@ -0,0 +1,465 @@ +/* + * demand.c - Support routines for demand-dialling. + * + * Copyright (c) 1996-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && DEMAND_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PPP_FILTER +#include +#endif + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/lcp.h" + +char *frame; +int framelen; +int framemax; +int escape_flag; +int flush_flag; +int fcs; + +struct packet { + int length; + struct packet *next; + unsigned char data[1]; +}; + +struct packet *pend_q; +struct packet *pend_qtail; + +static int active_packet (unsigned char *, int); + +/* + * demand_conf - configure the interface for doing dial-on-demand. + */ +void +demand_conf() +{ + int i; + const struct protent *protp; + +/* framemax = lcp_allowoptions[0].mru; + if (framemax < PPP_MRU) */ + framemax = PPP_MRU; + framemax += PPP_HDRLEN + PPP_FCSLEN; + frame = malloc(framemax); + if (frame == NULL) + novm("demand frame"); + framelen = 0; + pend_q = NULL; + escape_flag = 0; + flush_flag = 0; + fcs = PPP_INITFCS; + + netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU)); + if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0) + fatal("Couldn't set up demand-dialled PPP interface: %m"); + +#ifdef PPP_FILTER + set_filters(&pass_filter, &active_filter); +#endif + + /* + * Call the demand_conf procedure for each protocol that's got one. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + ((*protp->demand_conf)(pcb)); +/* FIXME: find a way to die() here */ +#if 0 + if (!((*protp->demand_conf)(pcb))) + die(1); +#endif +} + + +/* + * demand_block - set each network protocol to block further packets. + */ +void +demand_block() +{ + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE); + get_loop_output(); +} + +/* + * demand_discard - set each network protocol to discard packets + * with an error. + */ +void +demand_discard() +{ + struct packet *pkt, *nextpkt; + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR); + get_loop_output(); + + /* discard all saved packets */ + for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { + nextpkt = pkt->next; + free(pkt); + } + pend_q = NULL; + framelen = 0; + flush_flag = 0; + escape_flag = 0; + fcs = PPP_INITFCS; +} + +/* + * demand_unblock - set each enabled network protocol to pass packets. + */ +void +demand_unblock() +{ + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS); +} + +/* + * FCS lookup table as calculated by genfcstab. + */ +static u_short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* + * loop_chars - process characters received from the loopback. + * Calls loop_frame when a complete frame has been accumulated. + * Return value is 1 if we need to bring up the link, 0 otherwise. + */ +int +loop_chars(p, n) + unsigned char *p; + int n; +{ + int c, rv; + + rv = 0; + +/* check for synchronous connection... */ + + if ( (p[0] == 0xFF) && (p[1] == 0x03) ) { + rv = loop_frame(p,n); + return rv; + } + + for (; n > 0; --n) { + c = *p++; + if (c == PPP_FLAG) { + if (!escape_flag && !flush_flag + && framelen > 2 && fcs == PPP_GOODFCS) { + framelen -= 2; + if (loop_frame((unsigned char *)frame, framelen)) + rv = 1; + } + framelen = 0; + flush_flag = 0; + escape_flag = 0; + fcs = PPP_INITFCS; + continue; + } + if (flush_flag) + continue; + if (escape_flag) { + c ^= PPP_TRANS; + escape_flag = 0; + } else if (c == PPP_ESCAPE) { + escape_flag = 1; + continue; + } + if (framelen >= framemax) { + flush_flag = 1; + continue; + } + frame[framelen++] = c; + fcs = PPP_FCS(fcs, c); + } + return rv; +} + +/* + * loop_frame - given a frame obtained from the loopback, + * decide whether to bring up the link or not, and, if we want + * to transmit this frame later, put it on the pending queue. + * Return value is 1 if we need to bring up the link, 0 otherwise. + * We assume that the kernel driver has already applied the + * pass_filter, so we won't get packets it rejected. + * We apply the active_filter to see if we want this packet to + * bring up the link. + */ +int +loop_frame(frame, len) + unsigned char *frame; + int len; +{ + struct packet *pkt; + + /* dbglog("from loop: %P", frame, len); */ + if (len < PPP_HDRLEN) + return 0; + if ((PPP_PROTOCOL(frame) & 0x8000) != 0) + return 0; /* shouldn't get any of these anyway */ + if (!active_packet(frame, len)) + return 0; + + pkt = (struct packet *) malloc(sizeof(struct packet) + len); + if (pkt != NULL) { + pkt->length = len; + pkt->next = NULL; + memcpy(pkt->data, frame, len); + if (pend_q == NULL) + pend_q = pkt; + else + pend_qtail->next = pkt; + pend_qtail = pkt; + } + return 1; +} + +/* + * demand_rexmit - Resend all those frames which we got via the + * loopback, now that the real serial link is up. + */ +void +demand_rexmit(proto, newip) + int proto; + u32_t newip; +{ + struct packet *pkt, *prev, *nextpkt; + unsigned short checksum; + unsigned short pkt_checksum = 0; + unsigned iphdr; + struct timeval tv; + char cv = 0; + char ipstr[16]; + + prev = NULL; + pkt = pend_q; + pend_q = NULL; + tv.tv_sec = 1; + tv.tv_usec = 0; + select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */ + for (; pkt != NULL; pkt = nextpkt) { + nextpkt = pkt->next; + if (PPP_PROTOCOL(pkt->data) == proto) { + if ( (proto == PPP_IP) && newip ) { + /* Get old checksum */ + + iphdr = (pkt->data[4] & 15) << 2; + checksum = *((unsigned short *) (pkt->data+14)); + if (checksum == 0xFFFF) { + checksum = 0; + } + + + if (pkt->data[13] == 17) { + pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr)); + if (pkt_checksum) { + cv = 1; + if (pkt_checksum == 0xFFFF) { + pkt_checksum = 0; + } + } + else { + cv = 0; + } + } + + if (pkt->data[13] == 6) { + pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr)); + cv = 1; + if (pkt_checksum == 0xFFFF) { + pkt_checksum = 0; + } + } + + /* Delete old Source-IP-Address */ + checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + /* Change Source-IP-Address */ + * ((u32_t *) (pkt->data + 16)) = newip; + + /* Add new Source-IP-Address */ + checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + /* Write new checksum */ + if (!checksum) { + checksum = 0xFFFF; + } + *((unsigned short *) (pkt->data+14)) = checksum; + if (pkt->data[13] == 6) { + *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum; + } + if (cv && (pkt->data[13] == 17) ) { + *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum; + } + + /* Log Packet */ + strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16)))); + if (pkt->data[13] == 1) { + syslog(LOG_INFO,"Open ICMP %s -> %s\n", + ipstr, + inet_ntoa(*( (struct in_addr *) (pkt->data+20)))); + } else { + syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n", + pkt->data[13] == 6 ? "TCP" : "UDP", + ipstr, + ntohs(*( (short *) (pkt->data+iphdr+4))), + inet_ntoa(*( (struct in_addr *) (pkt->data+20))), + ntohs(*( (short *) (pkt->data+iphdr+6)))); + } + } + output(pcb, pkt->data, pkt->length); + free(pkt); + } else { + if (prev == NULL) + pend_q = pkt; + else + prev->next = pkt; + prev = pkt; + } + } + pend_qtail = prev; + if (prev != NULL) + prev->next = NULL; +} + +/* + * Scan a packet to decide whether it is an "active" packet, + * that is, whether it is worth bringing up the link for. + */ +static int +active_packet(p, len) + unsigned char *p; + int len; +{ + int proto, i; + const struct protent *protp; + + if (len < PPP_HDRLEN) + return 0; + proto = PPP_PROTOCOL(p); +#ifdef PPP_FILTER + p[0] = 1; /* outbound packet indicator */ + if ((pass_filter.bf_len != 0 + && bpf_filter(pass_filter.bf_insns, p, len, len) == 0) + || (active_filter.bf_len != 0 + && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) { + p[0] = 0xff; + return 0; + } + p[0] = 0xff; +#endif + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { + if (protp->active_pkt == NULL) + return 1; + return (*protp->active_pkt)(p, len); + } + } + return 0; /* not a supported protocol !!?? */ +} + +#endif /* PPP_SUPPORT && DEMAND_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eap.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eap.c new file mode 100644 index 0000000..8fb5636 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eap.c @@ -0,0 +1,2423 @@ +/* + * eap.c - Extensible Authentication Protocol for PPP (RFC 2284) + * + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Non-exclusive rights to redistribute, modify, translate, and use + * this software in source and binary forms, in whole or in part, is + * hereby granted, provided that the above copyright notice is + * duplicated in any source form, and that neither the name of the + * copyright holder nor the author is used to endorse or promote + * products derived from this software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Original version by James Carlson + * + * This implementation of EAP supports MD5-Challenge and SRP-SHA1 + * authentication styles. Note that support of MD5-Challenge is a + * requirement of RFC 2284, and that it's essentially just a + * reimplementation of regular RFC 1994 CHAP using EAP messages. + * + * As an authenticator ("server"), there are multiple phases for each + * style. In the first phase of each style, the unauthenticated peer + * name is queried using the EAP Identity request type. If the + * "remotename" option is used, then this phase is skipped, because + * the peer's name is presumed to be known. + * + * For MD5-Challenge, there are two phases, and the second phase + * consists of sending the challenge itself and handling the + * associated response. + * + * For SRP-SHA1, there are four phases. The second sends 's', 'N', + * and 'g'. The reply contains 'A'. The third sends 'B', and the + * reply contains 'M1'. The forth sends the 'M2' value. + * + * As an authenticatee ("client"), there's just a single phase -- + * responding to the queries generated by the peer. EAP is an + * authenticator-driven protocol. + * + * Based on draft-ietf-pppext-eap-srp-03.txt. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/eap.h" +#include "netif/ppp/magic.h" +#include "netif/ppp/pppcrypt.h" + +#ifdef USE_SRP +#include +#include +#include +#endif /* USE_SRP */ + +#ifndef SHA_DIGESTSIZE +#define SHA_DIGESTSIZE 20 +#endif + +#ifdef USE_SRP +static char *pn_secret = NULL; /* Pseudonym generating secret */ +#endif + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t eap_option_list[] = { + { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, + "Set retransmit timeout for EAP Requests (server)" }, + { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, + "Set max number of EAP Requests sent (server)" }, + { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, + "Set time limit for peer EAP authentication" }, + { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, + "Set max number of EAP Requests allows (client)" }, + { "eap-interval", o_int, &eap_states[0].es_rechallenge, + "Set interval for EAP rechallenge" }, +#ifdef USE_SRP + { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, + "Set interval for SRP lightweight rechallenge" }, + { "srp-pn-secret", o_string, &pn_secret, + "Long term pseudonym generation secret" }, + { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, + "Use pseudonym if offered one by server", 1 }, +#endif + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points. + */ +static void eap_init(ppp_pcb *pcb); +static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen); +static void eap_protrej(ppp_pcb *pcb); +static void eap_lowerup(ppp_pcb *pcb); +static void eap_lowerdown(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int eap_printpkt(const u_char *inp, int inlen, + void (*)(void *arg, const char *fmt, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent eap_protent = { + PPP_EAP, /* protocol number */ + eap_init, /* initialization procedure */ + eap_input, /* process a received packet */ + eap_protrej, /* process a received protocol-reject */ + eap_lowerup, /* lower layer has gone up */ + eap_lowerdown, /* lower layer has gone down */ + NULL, /* open the protocol */ + NULL, /* close the protocol */ +#if PRINTPKT_SUPPORT + eap_printpkt, /* print a packet in readable form */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* process a received data packet */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "EAP", /* text name of protocol */ + NULL, /* text name of corresponding data protocol */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + eap_option_list, /* list of command-line options */ + NULL, /* check requested options; assign defaults */ +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, /* configure interface for demand-dial */ + NULL /* say whether to bring up link for this pkt */ +#endif /* DEMAND_SUPPORT */ +}; + +#ifdef USE_SRP +/* + * A well-known 2048 bit modulus. + */ +static const u_char wkmodulus[] = { + 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, + 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, + 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, + 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, + 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, + 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, + 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, + 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, + 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, + 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, + 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, + 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, + 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, + 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, + 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, + 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, + 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, + 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, + 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, + 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, + 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, + 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, + 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, + 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, + 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, + 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, + 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, + 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, + 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, + 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, + 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, + 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 +}; +#endif + +#if PPP_SERVER +/* Local forward declarations. */ +static void eap_server_timeout(void *arg); +#endif /* PPP_SERVER */ + +/* + * Convert EAP state code to printable string for debug. + */ +static const char * eap_state_name(enum eap_state_code esc) +{ + static const char *state_names[] = { EAP_STATES }; + + return (state_names[(int)esc]); +} + +/* + * eap_init - Initialize state for an EAP user. This is currently + * called once by main() during start-up. + */ +static void eap_init(ppp_pcb *pcb) { + + BZERO(&pcb->eap, sizeof(eap_state)); +#if PPP_SERVER + pcb->eap.es_server.ea_id = magic(); +#endif /* PPP_SERVER */ +} + +/* + * eap_client_timeout - Give up waiting for the peer to send any + * Request messages. + */ +static void eap_client_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (!eap_client_active(pcb)) + return; + + ppp_error("EAP: timeout waiting for Request from peer"); + auth_withpeer_fail(pcb, PPP_EAP); + pcb->eap.es_client.ea_state = eapBadAuth; +} + +/* + * eap_authwithpeer - Authenticate to our peer (behave as client). + * + * Start client state and wait for requests. This is called only + * after eap_lowerup. + */ +void eap_authwithpeer(ppp_pcb *pcb, const char *localname) { + + if(NULL == localname) + return; + + /* Save the peer name we're given */ + pcb->eap.es_client.ea_name = localname; + pcb->eap.es_client.ea_namelen = strlen(localname); + + pcb->eap.es_client.ea_state = eapListen; + + /* + * Start a timer so that if the other end just goes + * silent, we don't sit here waiting forever. + */ + if (pcb->settings.eap_req_time > 0) + TIMEOUT(eap_client_timeout, pcb, + pcb->settings.eap_req_time); +} + +#if PPP_SERVER +/* + * Format a standard EAP Failure message and send it to the peer. + * (Server operation) + */ +static void eap_send_failure(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_FAILURE, outp); + pcb->eap.es_server.ea_id++; + PUTCHAR(pcb->eap.es_server.ea_id, outp); + PUTSHORT(EAP_HEADERLEN, outp); + + ppp_write(pcb, p); + + pcb->eap.es_server.ea_state = eapBadAuth; + auth_peer_fail(pcb, PPP_EAP); +} + +/* + * Format a standard EAP Success message and send it to the peer. + * (Server operation) + */ +static void eap_send_success(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_SUCCESS, outp); + pcb->eap.es_server.ea_id++; + PUTCHAR(pcb->eap.es_server.ea_id, outp); + PUTSHORT(EAP_HEADERLEN, outp); + + ppp_write(pcb, p); + + auth_peer_success(pcb, PPP_EAP, 0, + pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); +} +#endif /* PPP_SERVER */ + +#ifdef USE_SRP +/* + * Set DES key according to pseudonym-generating secret and current + * date. + */ +static bool +pncrypt_setkey(int timeoffs) +{ + struct tm *tp; + char tbuf[9]; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + time_t reftime; + + if (pn_secret == NULL) + return (0); + reftime = time(NULL) + timeoffs; + tp = localtime(&reftime); + SHA1Init(&ctxt); + SHA1Update(&ctxt, pn_secret, strlen(pn_secret)); + strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); + SHA1Update(&ctxt, tbuf, strlen(tbuf)); + SHA1Final(dig, &ctxt); + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + return (DesSetkey(dig)); +} + +static char base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +struct b64state { + u32_t bs_bits; + int bs_offs; +}; + +static int +b64enc(bs, inp, inlen, outp) +struct b64state *bs; +u_char *inp; +int inlen; +u_char *outp; +{ + int outlen = 0; + + while (inlen > 0) { + bs->bs_bits = (bs->bs_bits << 8) | *inp++; + inlen--; + bs->bs_offs += 8; + if (bs->bs_offs >= 24) { + *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; + *outp++ = base64[bs->bs_bits & 0x3F]; + outlen += 4; + bs->bs_offs = 0; + bs->bs_bits = 0; + } + } + return (outlen); +} + +static int +b64flush(bs, outp) +struct b64state *bs; +u_char *outp; +{ + int outlen = 0; + + if (bs->bs_offs == 8) { + *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; + *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; + outlen = 2; + } else if (bs->bs_offs == 16) { + *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; + *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; + outlen = 3; + } + bs->bs_offs = 0; + bs->bs_bits = 0; + return (outlen); +} + +static int +b64dec(bs, inp, inlen, outp) +struct b64state *bs; +u_char *inp; +int inlen; +u_char *outp; +{ + int outlen = 0; + char *cp; + + while (inlen > 0) { + if ((cp = strchr(base64, *inp++)) == NULL) + break; + bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); + inlen--; + bs->bs_offs += 6; + if (bs->bs_offs >= 8) { + *outp++ = bs->bs_bits >> (bs->bs_offs - 8); + outlen++; + bs->bs_offs -= 8; + } + } + return (outlen); +} +#endif /* USE_SRP */ + +#if PPP_SERVER +/* + * Assume that current waiting server state is complete and figure + * next state to use based on available authentication data. 'status' + * indicates if there was an error in handling the last query. It is + * 0 for success and non-zero for failure. + */ +static void eap_figure_next_state(ppp_pcb *pcb, int status) { +#ifdef USE_SRP + unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp; + struct t_pw tpw; + struct t_confent *tce, mytce; + char *cp, *cp2; + struct t_server *ts; + int id, i, plen, toffs; + u_char vals[2]; + struct b64state bs; +#endif /* USE_SRP */ + + pcb->settings.eap_timeout_time = pcb->eap.es_savedtime; + switch (pcb->eap.es_server.ea_state) { + case eapBadAuth: + return; + + case eapIdentify: +#ifdef USE_SRP + /* Discard any previous session. */ + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0) { + pcb->eap.es_server.ea_state = eapBadAuth; + break; + } +#ifdef USE_SRP + /* If we've got a pseudonym, try to decode to real name. */ + if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN && + strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID, + SRP_PSEUDO_LEN) == 0 && + (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < + sizeof (secbuf)) { + BZERO(&bs, sizeof (bs)); + plen = b64dec(&bs, + pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN, + pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN, + secbuf); + toffs = 0; + for (i = 0; i < 5; i++) { + pncrypt_setkey(toffs); + toffs -= 86400; + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + if (!DesDecrypt(secbuf, clear)) { + ppp_dbglog("no DES here; cannot decode " + "pseudonym"); + return; + } + id = *(unsigned char *)clear; + if (id + 1 <= plen && id + 9 > plen) + break; + } + if (plen % 8 == 0 && i < 5) { + /* + * Note that this is always shorter than the + * original stored string, so there's no need + * to realloc. + */ + if ((i = plen = *(unsigned char *)clear) > 7) + i = 7; + pcb->eap.es_server.ea_peerlen = plen; + dp = (unsigned char *)pcb->eap.es_server.ea_peer; + MEMCPY(dp, clear + 1, i); + plen -= i; + dp += i; + sp = secbuf + 8; + while (plen > 0) { + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesDecrypt(sp, dp); + sp += 8; + dp += 8; + plen -= 8; + } + pcb->eap.es_server.ea_peer[ + pcb->eap.es_server.ea_peerlen] = '\0'; + ppp_dbglog("decoded pseudonym to \"%.*q\"", + pcb->eap.es_server.ea_peerlen, + pcb->eap.es_server.ea_peer); + } else { + ppp_dbglog("failed to decode real name"); + /* Stay in eapIdentfy state; requery */ + break; + } + } + /* Look up user in secrets database. */ + if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) { + /* Set up default in case SRP entry is bad */ + pcb->eap.es_server.ea_state = eapMD5Chall; + /* Get t_confent based on index in srp-secrets */ + id = strtol((char *)secbuf, &cp, 10); + if (*cp++ != ':' || id < 0) + break; + if (id == 0) { + mytce.index = 0; + mytce.modulus.data = (u_char *)wkmodulus; + mytce.modulus.len = sizeof (wkmodulus); + mytce.generator.data = (u_char *)"\002"; + mytce.generator.len = 1; + tce = &mytce; + } else if ((tce = gettcid(id)) != NULL) { + /* + * Client will have to verify this modulus/ + * generator combination, and that will take + * a while. Lengthen the timeout here. + */ + if (pcb->settings.eap_timeout_time > 0 && + pcb->settings.eap_timeout_time < 30) + pcb->settings.eap_timeout_time = 30; + } else { + break; + } + if ((cp2 = strchr(cp, ':')) == NULL) + break; + *cp2++ = '\0'; + tpw.pebuf.name = pcb->eap.es_server.ea_peer; + tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, + cp); + tpw.pebuf.password.data = tpw.pwbuf; + tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, + cp2); + tpw.pebuf.salt.data = tpw.saltbuf; + if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) + break; + pcb->eap.es_server.ea_session = (void *)ts; + pcb->eap.es_server.ea_state = eapSRP1; + vals[0] = pcb->eap.es_server.ea_id + 1; + vals[1] = EAPT_SRP; + t_serveraddexdata(ts, vals, 2); + /* Generate B; must call before t_servergetkey() */ + t_servergenexp(ts); + break; + } +#endif /* USE_SRP */ + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + + case eapSRP1: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status == 1) { + pcb->eap.es_server.ea_state = eapMD5Chall; + } else if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapSRP2; + } + break; + + case eapSRP2: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapSRP3; + } + break; + + case eapSRP3: + case eapSRP4: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapOpen; + } + break; + + case eapMD5Chall: + if (status != 0) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapOpen; + } + break; + + default: + pcb->eap.es_server.ea_state = eapBadAuth; + break; + } + if (pcb->eap.es_server.ea_state == eapBadAuth) + eap_send_failure(pcb); +} + +/* + * Format an EAP Request message and send it to the peer. Message + * type depends on current state. (Server operation) + */ +static void eap_send_request(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + u_char *lenloc; + int outlen; + int len; + const char *str; +#ifdef USE_SRP + struct t_server *ts; + u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; + int i, j; + struct b64state b64; + SHA1_CTX ctxt; +#endif /* USE_SRP */ + + /* Handle both initial auth and restart */ + if (pcb->eap.es_server.ea_state < eapIdentify && + pcb->eap.es_server.ea_state != eapInitial) { + pcb->eap.es_server.ea_state = eapIdentify; +#if PPP_REMOTENAME + if (pcb->settings.explicit_remote && pcb->remote_name) { + /* + * If we already know the peer's + * unauthenticated name, then there's no + * reason to ask. Go to next state instead. + */ + int len = (int)strlen(pcb->remote_name); + if (len > MAXNAMELEN) { + len = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len); + pcb->eap.es_server.ea_peer[len] = '\0'; + pcb->eap.es_server.ea_peerlen = len; + eap_figure_next_state(pcb, 0); + } +#endif /* PPP_REMOTENAME */ + } + + if (pcb->settings.eap_max_transmits > 0 && + pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) { + if (pcb->eap.es_server.ea_responses > 0) + ppp_error("EAP: too many Requests sent"); + else + ppp_error("EAP: no response to Requests"); + eap_send_failure(pcb); + return; + } + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(pcb->eap.es_server.ea_id, outp); + lenloc = outp; + INCPTR(2, outp); + + switch (pcb->eap.es_server.ea_state) { + case eapIdentify: + PUTCHAR(EAPT_IDENTITY, outp); + str = "Name"; + len = strlen(str); + MEMCPY(outp, str, len); + INCPTR(len, outp); + break; + + case eapMD5Chall: + PUTCHAR(EAPT_MD5CHAP, outp); + /* + * pick a random challenge length between + * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH + */ + pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + + magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); + PUTCHAR(pcb->eap.es_challen, outp); + magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); + MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); + INCPTR(pcb->eap.es_challen, outp); + MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); + INCPTR(pcb->eap.es_server.ea_namelen, outp); + break; + +#ifdef USE_SRP + case eapSRP1: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_CHALLENGE, outp); + + PUTCHAR(pcb->eap.es_server.ea_namelen, outp); + MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); + INCPTR(pcb->eap.es_server.ea_namelen, outp); + + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + PUTCHAR(ts->s.len, outp); + MEMCPY(outp, ts->s.data, ts->s.len); + INCPTR(ts->s.len, outp); + + if (ts->g.len == 1 && ts->g.data[0] == 2) { + PUTCHAR(0, outp); + } else { + PUTCHAR(ts->g.len, outp); + MEMCPY(outp, ts->g.data, ts->g.len); + INCPTR(ts->g.len, outp); + } + + if (ts->n.len != sizeof (wkmodulus) || + BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) { + MEMCPY(outp, ts->n.data, ts->n.len); + INCPTR(ts->n.len, outp); + } + break; + + case eapSRP2: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_SKEY, outp); + + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + MEMCPY(outp, ts->B.data, ts->B.len); + INCPTR(ts->B.len, outp); + break; + + case eapSRP3: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_SVALIDATOR, outp); + PUTLONG(SRPVAL_EBIT, outp); + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE); + INCPTR(SHA_DIGESTSIZE, outp); + + if (pncrypt_setkey(0)) { + /* Generate pseudonym */ + optr = outp; + cp = (unsigned char *)pcb->eap.es_server.ea_peer; + if ((j = i = pcb->eap.es_server.ea_peerlen) > 7) + j = 7; + clear[0] = i; + MEMCPY(clear + 1, cp, j); + i -= j; + cp += j; + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + if (!DesEncrypt(clear, cipher)) { + ppp_dbglog("no DES here; not generating pseudonym"); + break; + } + BZERO(&b64, sizeof (b64)); + outp++; /* space for pseudonym length */ + outp += b64enc(&b64, cipher, 8, outp); + while (i >= 8) { + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesEncrypt(cp, cipher); + outp += b64enc(&b64, cipher, 8, outp); + cp += 8; + i -= 8; + } + if (i > 0) { + MEMCPY(clear, cp, i); + cp += i; + magic_random_bytes(cp, 8-i); + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesEncrypt(clear, cipher); + outp += b64enc(&b64, cipher, 8, outp); + } + outp += b64flush(&b64, outp); + + /* Set length and pad out to next 20 octet boundary */ + i = outp - optr - 1; + *optr = i; + i %= SHA_DIGESTSIZE; + if (i != 0) { + magic_random_bytes(outp, SHA_DIGESTSIZE-i); + INCPTR(SHA_DIGESTSIZE-i, outp); + } + + /* Obscure the pseudonym with SHA1 hash */ + SHA1Init(&ctxt); + SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_peerlen); + while (optr < outp) { + SHA1Final(dig, &ctxt); + cp = dig; + while (cp < dig + SHA_DIGESTSIZE) + *optr++ ^= *cp++; + SHA1Init(&ctxt); + SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, optr - SHA_DIGESTSIZE, + SHA_DIGESTSIZE); + } + } + break; + + case eapSRP4: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_LWRECHALLENGE, outp); + pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + + magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); + magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); + MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); + INCPTR(pcb->eap.es_challen, outp); + break; +#endif /* USE_SRP */ + + default: + return; + } + + outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + pbuf_realloc(p, outlen + PPP_HDRLEN); + ppp_write(pcb, p); + + pcb->eap.es_server.ea_requests++; + + if (pcb->settings.eap_timeout_time > 0) + TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time); +} + +/* + * eap_authpeer - Authenticate our peer (behave as server). + * + * Start server state and send first request. This is called only + * after eap_lowerup. + */ +void eap_authpeer(ppp_pcb *pcb, const char *localname) { + + /* Save the name we're given. */ + pcb->eap.es_server.ea_name = localname; + pcb->eap.es_server.ea_namelen = strlen(localname); + + pcb->eap.es_savedtime = pcb->settings.eap_timeout_time; + + /* Lower layer up yet? */ + if (pcb->eap.es_server.ea_state == eapInitial || + pcb->eap.es_server.ea_state == eapPending) { + pcb->eap.es_server.ea_state = eapPending; + return; + } + + pcb->eap.es_server.ea_state = eapPending; + + /* ID number not updated here intentionally; hashed into M1 */ + eap_send_request(pcb); +} + +/* + * eap_server_timeout - Retransmission timer for sending Requests + * expired. + */ +static void eap_server_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (!eap_server_active(pcb)) + return; + + /* EAP ID number must not change on timeout. */ + eap_send_request(pcb); +} + +/* + * When it's time to send rechallenge the peer, this timeout is + * called. Once the rechallenge is successful, the response handler + * will restart the timer. If it fails, then the link is dropped. + */ +static void eap_rechallenge(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->eap.es_server.ea_state != eapOpen && + pcb->eap.es_server.ea_state != eapSRP4) + return; + + pcb->eap.es_server.ea_requests = 0; + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); +} + +static void srp_lwrechallenge(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->eap.es_server.ea_state != eapOpen || + pcb->eap.es_server.ea_type != EAPT_SRP) + return; + + pcb->eap.es_server.ea_requests = 0; + pcb->eap.es_server.ea_state = eapSRP4; + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); +} +#endif /* PPP_SERVER */ + +/* + * eap_lowerup - The lower layer is now up. + * + * This is called before either eap_authpeer or eap_authwithpeer. See + * link_established() in auth.c. All that's necessary here is to + * return to closed state so that those two routines will do the right + * thing. + */ +static void eap_lowerup(ppp_pcb *pcb) { + pcb->eap.es_client.ea_state = eapClosed; +#if PPP_SERVER + pcb->eap.es_server.ea_state = eapClosed; +#endif /* PPP_SERVER */ +} + +/* + * eap_lowerdown - The lower layer is now down. + * + * Cancel all timeouts and return to initial state. + */ +static void eap_lowerdown(ppp_pcb *pcb) { + + if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } +#if PPP_SERVER + if (eap_server_active(pcb)) { + if (pcb->settings.eap_timeout_time > 0) { + UNTIMEOUT(eap_server_timeout, pcb); + } + } else { + if ((pcb->eap.es_server.ea_state == eapOpen || + pcb->eap.es_server.ea_state == eapSRP4) && + pcb->eap.es_rechallenge > 0) { + UNTIMEOUT(eap_rechallenge, (void *)pcb); + } + if (pcb->eap.es_server.ea_state == eapOpen && + pcb->eap.es_lwrechallenge > 0) { + UNTIMEOUT(srp_lwrechallenge, (void *)pcb); + } + } + + pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial; + pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0; +#endif /* PPP_SERVER */ +} + +/* + * eap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen. If it does, it represents authentication + * failure. + */ +static void eap_protrej(ppp_pcb *pcb) { + + if (eap_client_active(pcb)) { + ppp_error("EAP authentication failed due to Protocol-Reject"); + auth_withpeer_fail(pcb, PPP_EAP); + } +#if PPP_SERVER + if (eap_server_active(pcb)) { + ppp_error("EAP authentication of peer failed on Protocol-Reject"); + auth_peer_fail(pcb, PPP_EAP); + } +#endif /* PPP_SERVER */ + eap_lowerdown(pcb); +} + +/* + * Format and send a regular EAP Response message. + */ +static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(typenum, outp); + if (lenstr > 0) { + MEMCPY(outp, str, lenstr); + } + + ppp_write(pcb, p); +} + +/* + * Format and send an MD5-Challenge EAP Response message. + */ +static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE + + namelen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_MD5CHAP, outp); + PUTCHAR(MD5_SIGNATURE_SIZE, outp); + MEMCPY(outp, hash, MD5_SIGNATURE_SIZE); + INCPTR(MD5_SIGNATURE_SIZE, outp); + if (namelen > 0) { + MEMCPY(outp, name, namelen); + } + + ppp_write(pcb, p); +} + +#ifdef USE_SRP +/* + * Format and send a SRP EAP Response message. + */ +static void +eap_srp_response(esp, id, subtypenum, str, lenstr) +eap_state *esp; +u_char id; +u_char subtypenum; +u_char *str; +int lenstr; +{ + ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(subtypenum, outp); + if (lenstr > 0) { + MEMCPY(outp, str, lenstr); + } + + ppp_write(pcb, p); +} + +/* + * Format and send a SRP EAP Client Validator Response message. + */ +static void +eap_srpval_response(esp, id, flags, str) +eap_state *esp; +u_char id; +u32_t flags; +u_char *str; +{ + ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) + + SHA_DIGESTSIZE; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_CVALIDATOR, outp); + PUTLONG(flags, outp); + MEMCPY(outp, str, SHA_DIGESTSIZE); + + ppp_write(pcb, p); +} +#endif /* USE_SRP */ + +static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_NAK, outp); + PUTCHAR(type, outp); + + ppp_write(pcb, p); +} + +#ifdef USE_SRP +static char * +name_of_pn_file() +{ + char *user, *path, *file; + struct passwd *pw; + size_t pl; + static bool pnlogged = 0; + + pw = getpwuid(getuid()); + if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) { + errno = EINVAL; + return (NULL); + } + file = _PATH_PSEUDONYM; + pl = strlen(user) + strlen(file) + 2; + path = malloc(pl); + if (path == NULL) + return (NULL); + (void) slprintf(path, pl, "%s/%s", user, file); + if (!pnlogged) { + ppp_dbglog("pseudonym file: %s", path); + pnlogged = 1; + } + return (path); +} + +static int +open_pn_file(modebits) +mode_t modebits; +{ + char *path; + int fd, err; + + if ((path = name_of_pn_file()) == NULL) + return (-1); + fd = open(path, modebits, S_IRUSR | S_IWUSR); + err = errno; + free(path); + errno = err; + return (fd); +} + +static void +remove_pn_file() +{ + char *path; + + if ((path = name_of_pn_file()) != NULL) { + (void) unlink(path); + (void) free(path); + } +} + +static void +write_pseudonym(esp, inp, len, id) +eap_state *esp; +u_char *inp; +int len, id; +{ + u_char val; + u_char *datp, *digp; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + int dsize, fd, olen = len; + + /* + * Do the decoding by working backwards. This eliminates the need + * to save the decoded output in a separate buffer. + */ + val = id; + while (len > 0) { + if ((dsize = len % SHA_DIGESTSIZE) == 0) + dsize = SHA_DIGESTSIZE; + len -= dsize; + datp = inp + len; + SHA1Init(&ctxt); + SHA1Update(&ctxt, &val, 1); + SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN); + if (len > 0) { + SHA1Update(&ctxt, datp, SHA_DIGESTSIZE); + } else { + SHA1Update(&ctxt, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + } + SHA1Final(dig, &ctxt); + for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++) + *datp++ ^= *digp; + } + + /* Now check that the result is sane */ + if (olen <= 0 || *inp + 1 > olen) { + ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); + return; + } + + /* Save it away */ + fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + ppp_dbglog("EAP: error saving pseudonym: %m"); + return; + } + len = write(fd, inp + 1, *inp); + if (close(fd) != -1 && len == *inp) { + ppp_dbglog("EAP: saved pseudonym"); + pcb->eap.es_usedpseudo = 0; + } else { + ppp_dbglog("EAP: failed to save pseudonym"); + remove_pn_file(); + } +} +#endif /* USE_SRP */ + +/* + * eap_request - Receive EAP Request message (client mode). + */ +static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char typenum; + u_char vallen; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[MAXNAMELEN]; + lwip_md5_context mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_SRP + struct t_client *tc; + struct t_num sval, gval, Nval, *Ap, Bval; + u_char vals[2]; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + int fd; +#endif /* USE_SRP */ + + /* + * Note: we update es_client.ea_id *only if* a Response + * message is being generated. Otherwise, we leave it the + * same for duplicate detection purposes. + */ + + pcb->eap.es_client.ea_requests++; + if (pcb->settings.eap_allow_req != 0 && + pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) { + ppp_info("EAP: received too many Request messages"); + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + auth_withpeer_fail(pcb, PPP_EAP); + return; + } + + if (len <= 0) { + ppp_error("EAP: empty Request message discarded"); + return; + } + + GETCHAR(typenum, inp); + len--; + + switch (typenum) { + case EAPT_IDENTITY: + if (len > 0) + ppp_info("EAP: Identity prompt \"%.*q\"", len, inp); +#ifdef USE_SRP + if (pcb->eap.es_usepseudo && + (pcb->eap.es_usedpseudo == 0 || + (pcb->eap.es_usedpseudo == 1 && + id == pcb->eap.es_client.ea_id))) { + pcb->eap.es_usedpseudo = 1; + /* Try to get a pseudonym */ + if ((fd = open_pn_file(O_RDONLY)) >= 0) { + strcpy(rhostname, SRP_PSEUDO_ID); + len = read(fd, rhostname + SRP_PSEUDO_LEN, + sizeof (rhostname) - SRP_PSEUDO_LEN); + /* XXX NAI unsupported */ + if (len > 0) { + eap_send_response(pcb, id, typenum, + rhostname, len + SRP_PSEUDO_LEN); + } + (void) close(fd); + if (len > 0) + break; + } + } + /* Stop using pseudonym now. */ + if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) { + remove_pn_file(); + pcb->eap.es_usedpseudo = 2; + } +#endif /* USE_SRP */ + eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + break; + + case EAPT_NOTIFICATION: + if (len > 0) + ppp_info("EAP: Notification \"%.*q\"", len, inp); + eap_send_response(pcb, id, typenum, NULL, 0); + break; + + case EAPT_NAK: + /* + * Avoid the temptation to send Response Nak in reply + * to Request Nak here. It can only lead to trouble. + */ + ppp_warn("EAP: unexpected Nak in Request; ignored"); + /* Return because we're waiting for something real. */ + return; + + case EAPT_MD5CHAP: + if (len < 1) { + ppp_error("EAP: received MD5-Challenge with no data"); + /* Bogus request; wait for something real. */ + return; + } + GETCHAR(vallen, inp); + len--; + if (vallen < 8 || vallen > len) { + ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)", + vallen, len); + /* Try something better. */ + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + + /* Not so likely to happen. */ + if (vallen >= len + sizeof (rhostname)) { + ppp_dbglog("EAP: trimming really long peer name down"); + MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); + rhostname[sizeof (rhostname) - 1] = '\0'; + } else { + MEMCPY(rhostname, inp + vallen, len - vallen); + rhostname[len - vallen] = '\0'; + } + +#if PPP_REMOTENAME + /* In case the remote doesn't give us his name. */ + if (pcb->settings.explicit_remote || + (pcb->settings.remote_name[0] != '\0' && vallen == len)) + strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname)); +#endif /* PPP_REMOTENAME */ + + /* + * Get the secret for authenticating ourselves with + * the specified host. + */ + if (!get_secret(pcb, pcb->eap.es_client.ea_name, + rhostname, secret, &secret_len, 0)) { + ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname); + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + lwip_md5_init(&mdContext); + lwip_md5_starts(&mdContext); + typenum = id; + lwip_md5_update(&mdContext, &typenum, 1); + lwip_md5_update(&mdContext, (u_char *)secret, secret_len); + BZERO(secret, sizeof (secret)); + lwip_md5_update(&mdContext, inp, vallen); + lwip_md5_finish(&mdContext, hash); + lwip_md5_free(&mdContext); + eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + break; + +#ifdef USE_SRP + case EAPT_SRP: + if (len < 1) { + ppp_error("EAP: received empty SRP Request"); + /* Bogus request; wait for something real. */ + return; + } + + /* Get subtype */ + GETCHAR(vallen, inp); + len--; + switch (vallen) { + case EAPSRP_CHALLENGE: + tc = NULL; + if (pcb->eap.es_client.ea_session != NULL) { + tc = (struct t_client *)pcb->eap.es_client. + ea_session; + /* + * If this is a new challenge, then start + * over with a new client session context. + * Otherwise, just resend last response. + */ + if (id != pcb->eap.es_client.ea_id) { + t_clientclose(tc); + pcb->eap.es_client.ea_session = NULL; + tc = NULL; + } + } + /* No session key just yet */ + pcb->eap.es_client.ea_skey = NULL; + if (tc == NULL) { + int rhostnamelen; + + GETCHAR(vallen, inp); + len--; + if (vallen >= len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (name)"); + /* Ignore badly-formed messages */ + return; + } + MEMCPY(rhostname, inp, vallen); + rhostname[vallen] = '\0'; + INCPTR(vallen, inp); + len -= vallen; + + /* + * In case the remote doesn't give us his name, + * use configured name. + */ + if (explicit_remote || + (remote_name[0] != '\0' && vallen == 0)) { + strlcpy(rhostname, remote_name, + sizeof (rhostname)); + } + + rhostnamelen = (int)strlen(rhostname); + if (rhostnamelen > MAXNAMELEN) { + rhostnamelen = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen); + pcb->eap.es_client.ea_peer[rhostnamelen] = '\0'; + pcb->eap.es_client.ea_peerlen = rhostnamelen; + + GETCHAR(vallen, inp); + len--; + if (vallen >= len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (s)"); + /* Ignore badly-formed messages */ + return; + } + sval.data = inp; + sval.len = vallen; + INCPTR(vallen, inp); + len -= vallen; + + GETCHAR(vallen, inp); + len--; + if (vallen > len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (g)"); + /* Ignore badly-formed messages */ + return; + } + /* If no generator present, then use value 2 */ + if (vallen == 0) { + gval.data = (u_char *)"\002"; + gval.len = 1; + } else { + gval.data = inp; + gval.len = vallen; + } + INCPTR(vallen, inp); + len -= vallen; + + /* + * If no modulus present, then use well-known + * value. + */ + if (len == 0) { + Nval.data = (u_char *)wkmodulus; + Nval.len = sizeof (wkmodulus); + } else { + Nval.data = inp; + Nval.len = len; + } + tc = t_clientopen(pcb->eap.es_client.ea_name, + &Nval, &gval, &sval); + if (tc == NULL) { + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + pcb->eap.es_client.ea_session = (void *)tc; + + /* Add Challenge ID & type to verifier */ + vals[0] = id; + vals[1] = EAPT_SRP; + t_clientaddexdata(tc, vals, 2); + } + Ap = t_clientgenexp(tc); + eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data, + Ap->len); + break; + + case EAPSRP_SKEY: + tc = (struct t_client *)pcb->eap.es_client.ea_session; + if (tc == NULL) { + ppp_warn("EAP: peer sent Subtype 2 without 1"); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + if (pcb->eap.es_client.ea_skey != NULL) { + /* + * ID number should not change here. Warn + * if it does (but otherwise ignore). + */ + if (id != pcb->eap.es_client.ea_id) { + ppp_warn("EAP: ID changed from %d to %d " + "in SRP Subtype 2 rexmit", + pcb->eap.es_client.ea_id, id); + } + } else { + if (get_srp_secret(pcb->eap.es_unit, + pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_peer, secret, 0) == 0) { + /* + * Can't work with this peer because + * the secret is missing. Just give + * up. + */ + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + Bval.data = inp; + Bval.len = len; + t_clientpasswd(tc, secret); + BZERO(secret, sizeof (secret)); + pcb->eap.es_client.ea_skey = + t_clientgetkey(tc, &Bval); + if (pcb->eap.es_client.ea_skey == NULL) { + /* Server is rogue; stop now */ + ppp_error("EAP: SRP server is rogue"); + goto client_failure; + } + } + eap_srpval_response(esp, id, SRPVAL_EBIT, + t_clientresponse(tc)); + break; + + case EAPSRP_SVALIDATOR: + tc = (struct t_client *)pcb->eap.es_client.ea_session; + if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) { + ppp_warn("EAP: peer sent Subtype 3 without 1/2"); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + /* + * If we're already open, then this ought to be a + * duplicate. Otherwise, check that the server is + * who we think it is. + */ + if (pcb->eap.es_client.ea_state == eapOpen) { + if (id != pcb->eap.es_client.ea_id) { + ppp_warn("EAP: ID changed from %d to %d " + "in SRP Subtype 3 rexmit", + pcb->eap.es_client.ea_id, id); + } + } else { + len -= sizeof (u32_t) + SHA_DIGESTSIZE; + if (len < 0 || t_clientverify(tc, inp + + sizeof (u32_t)) != 0) { + ppp_error("EAP: SRP server verification " + "failed"); + goto client_failure; + } + GETLONG(pcb->eap.es_client.ea_keyflags, inp); + /* Save pseudonym if user wants it. */ + if (len > 0 && pcb->eap.es_usepseudo) { + INCPTR(SHA_DIGESTSIZE, inp); + write_pseudonym(esp, inp, len, id); + } + } + /* + * We've verified our peer. We're now mostly done, + * except for waiting on the regular EAP Success + * message. + */ + eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0); + break; + + case EAPSRP_LWRECHALLENGE: + if (len < 4) { + ppp_warn("EAP: malformed Lightweight rechallenge"); + return; + } + SHA1Init(&ctxt); + vals[0] = id; + SHA1Update(&ctxt, vals, 1); + SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, inp, len); + SHA1Update(&ctxt, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + SHA1Final(dig, &ctxt); + eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, + SHA_DIGESTSIZE); + break; + + default: + ppp_error("EAP: unknown SRP Subtype %d", vallen); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + break; +#endif /* USE_SRP */ + + default: + ppp_info("EAP: unknown authentication type %d; Naking", typenum); + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + TIMEOUT(eap_client_timeout, pcb, + pcb->settings.eap_req_time); + } + return; + +#ifdef USE_SRP +client_failure: + pcb->eap.es_client.ea_state = eapBadAuth; + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, (void *)esp); + } + pcb->eap.es_client.ea_session = NULL; + t_clientclose(tc); + auth_withpeer_fail(pcb, PPP_EAP); +#endif /* USE_SRP */ +} + +#if PPP_SERVER +/* + * eap_response - Receive EAP Response message (server mode). + */ +static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char typenum; + u_char vallen; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[MAXNAMELEN]; + lwip_md5_context mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_SRP + struct t_server *ts; + struct t_num A; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; +#endif /* USE_SRP */ + + if (pcb->eap.es_server.ea_id != id) { + ppp_dbglog("EAP: discarding Response %d; expected ID %d", id, + pcb->eap.es_server.ea_id); + return; + } + + pcb->eap.es_server.ea_responses++; + + if (len <= 0) { + ppp_error("EAP: empty Response message discarded"); + return; + } + + GETCHAR(typenum, inp); + len--; + + switch (typenum) { + case EAPT_IDENTITY: + if (pcb->eap.es_server.ea_state != eapIdentify) { + ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len, + inp); + break; + } + ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp); + if (len > MAXNAMELEN) { + len = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_server.ea_peer, inp, len); + pcb->eap.es_server.ea_peer[len] = '\0'; + pcb->eap.es_server.ea_peerlen = len; + eap_figure_next_state(pcb, 0); + break; + + case EAPT_NOTIFICATION: + ppp_dbglog("EAP unexpected Notification; response discarded"); + break; + + case EAPT_NAK: + if (len < 1) { + ppp_info("EAP: Nak Response with no suggested protocol"); + eap_figure_next_state(pcb, 1); + break; + } + + GETCHAR(vallen, inp); + len--; + + if ( +#if PPP_REMOTENAME + !pcb->explicit_remote && +#endif /* PPP_REMOTENAME */ + pcb->eap.es_server.ea_state == eapIdentify){ + /* Peer cannot Nak Identify Request */ + eap_figure_next_state(pcb, 1); + break; + } + + switch (vallen) { + case EAPT_SRP: + /* Run through SRP validator selection again. */ + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + break; + + case EAPT_MD5CHAP: + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + + default: + ppp_dbglog("EAP: peer requesting unknown Type %d", vallen); + switch (pcb->eap.es_server.ea_state) { + case eapSRP1: + case eapSRP2: + case eapSRP3: + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + case eapMD5Chall: + case eapSRP4: + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + break; + default: + break; + } + break; + } + break; + + case EAPT_MD5CHAP: + if (pcb->eap.es_server.ea_state != eapMD5Chall) { + ppp_error("EAP: unexpected MD5-Response"); + eap_figure_next_state(pcb, 1); + break; + } + if (len < 1) { + ppp_error("EAP: received MD5-Response with no data"); + eap_figure_next_state(pcb, 1); + break; + } + GETCHAR(vallen, inp); + len--; + if (vallen != 16 || vallen > len) { + ppp_error("EAP: MD5-Response with bad length %d", vallen); + eap_figure_next_state(pcb, 1); + break; + } + + /* Not so likely to happen. */ + if (vallen >= len + sizeof (rhostname)) { + ppp_dbglog("EAP: trimming really long peer name down"); + MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); + rhostname[sizeof (rhostname) - 1] = '\0'; + } else { + MEMCPY(rhostname, inp + vallen, len - vallen); + rhostname[len - vallen] = '\0'; + } + +#if PPP_REMOTENAME + /* In case the remote doesn't give us his name. */ + if (explicit_remote || + (remote_name[0] != '\0' && vallen == len)) + strlcpy(rhostname, remote_name, sizeof (rhostname)); +#endif /* PPP_REMOTENAME */ + + /* + * Get the secret for authenticating the specified + * host. + */ + if (!get_secret(pcb, rhostname, + pcb->eap.es_server.ea_name, secret, &secret_len, 1)) { + ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname); + eap_send_failure(pcb); + break; + } + lwip_md5_init(&mdContext); + lwip_md5_starts(&mdContext); + lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1); + lwip_md5_update(&mdContext, (u_char *)secret, secret_len); + BZERO(secret, sizeof (secret)); + lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen); + lwip_md5_finish(&mdContext, hash); + lwip_md5_free(&mdContext); + if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) { + eap_send_failure(pcb); + break; + } + pcb->eap.es_server.ea_type = EAPT_MD5CHAP; + eap_send_success(pcb); + eap_figure_next_state(pcb, 0); + if (pcb->eap.es_rechallenge != 0) + TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge); + break; + +#ifdef USE_SRP + case EAPT_SRP: + if (len < 1) { + ppp_error("EAP: empty SRP Response"); + eap_figure_next_state(pcb, 1); + break; + } + GETCHAR(typenum, inp); + len--; + switch (typenum) { + case EAPSRP_CKEY: + if (pcb->eap.es_server.ea_state != eapSRP1) { + ppp_error("EAP: unexpected SRP Subtype 1 Response"); + eap_figure_next_state(pcb, 1); + break; + } + A.data = inp; + A.len = len; + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A); + if (pcb->eap.es_server.ea_skey == NULL) { + /* Client's A value is bogus; terminate now */ + ppp_error("EAP: bogus A value from client"); + eap_send_failure(pcb); + } else { + eap_figure_next_state(pcb, 0); + } + break; + + case EAPSRP_CVALIDATOR: + if (pcb->eap.es_server.ea_state != eapSRP2) { + ppp_error("EAP: unexpected SRP Subtype 2 Response"); + eap_figure_next_state(pcb, 1); + break; + } + if (len < sizeof (u32_t) + SHA_DIGESTSIZE) { + ppp_error("EAP: M1 length %d < %d", len, + sizeof (u32_t) + SHA_DIGESTSIZE); + eap_figure_next_state(pcb, 1); + break; + } + GETLONG(pcb->eap.es_server.ea_keyflags, inp); + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + if (t_serververify(ts, inp)) { + ppp_info("EAP: unable to validate client identity"); + eap_send_failure(pcb); + break; + } + eap_figure_next_state(pcb, 0); + break; + + case EAPSRP_ACK: + if (pcb->eap.es_server.ea_state != eapSRP3) { + ppp_error("EAP: unexpected SRP Subtype 3 Response"); + eap_send_failure(esp); + break; + } + pcb->eap.es_server.ea_type = EAPT_SRP; + eap_send_success(pcb, esp); + eap_figure_next_state(pcb, 0); + if (pcb->eap.es_rechallenge != 0) + TIMEOUT(eap_rechallenge, pcb, + pcb->eap.es_rechallenge); + if (pcb->eap.es_lwrechallenge != 0) + TIMEOUT(srp_lwrechallenge, pcb, + pcb->eap.es_lwrechallenge); + break; + + case EAPSRP_LWRECHALLENGE: + if (pcb->eap.es_server.ea_state != eapSRP4) { + ppp_info("EAP: unexpected SRP Subtype 4 Response"); + return; + } + if (len != SHA_DIGESTSIZE) { + ppp_error("EAP: bad Lightweight rechallenge " + "response"); + return; + } + SHA1Init(&ctxt); + vallen = id; + SHA1Update(&ctxt, &vallen, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen); + SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_peerlen); + SHA1Final(dig, &ctxt); + if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { + ppp_error("EAP: failed Lightweight rechallenge"); + eap_send_failure(pcb); + break; + } + pcb->eap.es_server.ea_state = eapOpen; + if (pcb->eap.es_lwrechallenge != 0) + TIMEOUT(srp_lwrechallenge, esp, + pcb->eap.es_lwrechallenge); + break; + } + break; +#endif /* USE_SRP */ + + default: + /* This can't happen. */ + ppp_error("EAP: unknown Response type %d; ignored", typenum); + return; + } + + if (pcb->settings.eap_timeout_time > 0) { + UNTIMEOUT(eap_server_timeout, pcb); + } + + if (pcb->eap.es_server.ea_state != eapBadAuth && + pcb->eap.es_server.ea_state != eapOpen) { + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); + } +} +#endif /* PPP_SERVER */ + +/* + * eap_success - Receive EAP Success message (client mode). + */ +static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { + LWIP_UNUSED_ARG(id); + + if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) { + ppp_dbglog("EAP unexpected success message in state %s (%d)", + eap_state_name(pcb->eap.es_client.ea_state), + pcb->eap.es_client.ea_state); + return; + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + + if (len > 0) { + /* This is odd. The spec doesn't allow for this. */ + PRINTMSG(inp, len); + } + + pcb->eap.es_client.ea_state = eapOpen; + auth_withpeer_success(pcb, PPP_EAP, 0); +} + +/* + * eap_failure - Receive EAP Failure message (client mode). + */ +static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { + LWIP_UNUSED_ARG(id); + + if (!eap_client_active(pcb)) { + ppp_dbglog("EAP unexpected failure message in state %s (%d)", + eap_state_name(pcb->eap.es_client.ea_state), + pcb->eap.es_client.ea_state); + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + + if (len > 0) { + /* This is odd. The spec doesn't allow for this. */ + PRINTMSG(inp, len); + } + + pcb->eap.es_client.ea_state = eapBadAuth; + + ppp_error("EAP: peer reports authentication failure"); + auth_withpeer_fail(pcb, PPP_EAP); +} + +/* + * eap_input - Handle received EAP message. + */ +static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { + u_char code, id; + int len; + + /* + * Parse header (code, id and length). If packet too short, + * drop it. + */ + if (inlen < EAP_HEADERLEN) { + ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < EAP_HEADERLEN || len > inlen) { + ppp_error("EAP: packet has illegal length field %d (%d..%d)", len, + EAP_HEADERLEN, inlen); + return; + } + len -= EAP_HEADERLEN; + + /* Dispatch based on message code */ + switch (code) { + case EAP_REQUEST: + eap_request(pcb, inp, id, len); + break; + +#if PPP_SERVER + case EAP_RESPONSE: + eap_response(pcb, inp, id, len); + break; +#endif /* PPP_SERVER */ + + case EAP_SUCCESS: + eap_success(pcb, inp, id, len); + break; + + case EAP_FAILURE: + eap_failure(pcb, inp, id, len); + break; + + default: /* XXX Need code reject */ + /* Note: it's not legal to send EAP Nak here. */ + ppp_warn("EAP: unknown code %d received", code); + break; + } +} + +#if PRINTPKT_SUPPORT +/* + * eap_printpkt - print the contents of an EAP packet. + */ +static const char* const eap_codenames[] = { + "Request", "Response", "Success", "Failure" +}; + +static const char* const eap_typenames[] = { + "Identity", "Notification", "Nak", "MD5-Challenge", + "OTP", "Generic-Token", NULL, NULL, + "RSA", "DSS", "KEA", "KEA-Validate", + "TLS", "Defender", "Windows 2000", "Arcot", + "Cisco", "Nokia", "SRP" +}; + +static int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, rtype, vallen; + const u_char *pstart; + u32_t uval; + + if (inlen < EAP_HEADERLEN) + return (0); + pstart = inp; + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < EAP_HEADERLEN || len > inlen) + return (0); + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames)) + printer(arg, " %s", eap_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= EAP_HEADERLEN; + switch (code) { + case EAP_REQUEST: + if (len < 1) { + printer(arg, " "); + break; + } + GETCHAR(rtype, inp); + len--; + if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " %s", eap_typenames[rtype-1]); + else + printer(arg, " type=0x%x", rtype); + switch (rtype) { + case EAPT_IDENTITY: + case EAPT_NOTIFICATION: + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_MD5CHAP: + if (len <= 0) + break; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_SRP: + if (len < 3) + goto truncated; + GETCHAR(vallen, inp); + len--; + printer(arg, "-%d", vallen); + switch (vallen) { + case EAPSRP_CHALLENGE: + GETCHAR(vallen, inp); + len--; + if (vallen >= len) + goto truncated; + if (vallen > 0) { + printer(arg, " "); + } else { + printer(arg, " "); + } + INCPTR(vallen, inp); + len -= vallen; + GETCHAR(vallen, inp); + len--; + if (vallen >= len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + if (vallen == 0) { + printer(arg, " "); + } else { + printer(arg, " ", vallen, inp); + } + INCPTR(vallen, inp); + len -= vallen; + if (len == 0) { + printer(arg, " "); + } else { + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPSRP_SKEY: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_SVALIDATOR: + if (len < (int)sizeof (u32_t)) + break; + GETLONG(uval, inp); + len -= sizeof (u32_t); + if (uval & SRPVAL_EBIT) { + printer(arg, " E"); + uval &= ~SRPVAL_EBIT; + } + if (uval != 0) { + printer(arg, " f<%X>", uval); + } + if ((vallen = len) > SHA_DIGESTSIZE) + vallen = SHA_DIGESTSIZE; + printer(arg, " ", len, inp, + len < SHA_DIGESTSIZE ? "?" : ""); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPSRP_LWRECHALLENGE: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + default: + break; + } + break; + default: + break; + } + break; + + case EAP_RESPONSE: + if (len < 1) + break; + GETCHAR(rtype, inp); + len--; + if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " %s", eap_typenames[rtype-1]); + else + printer(arg, " type=0x%x", rtype); + switch (rtype) { + case EAPT_IDENTITY: + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPT_NAK: + if (len <= 0) { + printer(arg, " "); + break; + } + GETCHAR(rtype, inp); + len--; + printer(arg, " = 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " (%s)", eap_typenames[rtype-1]); + printer(arg, ">"); + break; + + case EAPT_MD5CHAP: + if (len <= 0) { + printer(arg, " "); + break; + } + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_SRP: + if (len < 1) + goto truncated; + GETCHAR(vallen, inp); + len--; + printer(arg, "-%d", vallen); + switch (vallen) { + case EAPSRP_CKEY: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_CVALIDATOR: + if (len < (int)sizeof (u32_t)) + break; + GETLONG(uval, inp); + len -= sizeof (u32_t); + if (uval & SRPVAL_EBIT) { + printer(arg, " E"); + uval &= ~SRPVAL_EBIT; + } + if (uval != 0) { + printer(arg, " f<%X>", uval); + } + printer(arg, " ", len, inp, + len == SHA_DIGESTSIZE ? "" : "?"); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_ACK: + break; + + case EAPSRP_LWRECHALLENGE: + printer(arg, " ", len, inp, + len == SHA_DIGESTSIZE ? "" : "?"); + if ((vallen = len) > SHA_DIGESTSIZE) + vallen = SHA_DIGESTSIZE; + INCPTR(vallen, inp); + len -= vallen; + break; + default: + break; + } + break; + default: + break; + } + break; + + case EAP_SUCCESS: /* No payload expected for these! */ + case EAP_FAILURE: + default: + break; + + truncated: + printer(arg, " "); + break; + } + + if (len > 8) + printer(arg, "%8B...", inp); + else if (len > 0) + printer(arg, "%.*B", len, inp); + INCPTR(len, inp); + + return (inp - pstart); +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ecp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ecp.c new file mode 100644 index 0000000..4d84f60 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ecp.c @@ -0,0 +1,191 @@ +/* + * ecp.c - PPP Encryption Control Protocol. + * + * Copyright (c) 2002 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from ccp.c, which is: + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ecp.h" + +#if PPP_OPTIONS +static option_t ecp_option_list[] = { + { "noecp", o_bool, &ecp_protent.enabled_flag, + "Disable ECP negotiation" }, + { "-ecp", o_bool, &ecp_protent.enabled_flag, + "Disable ECP negotiation", OPT_ALIAS }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ecp_init (int unit); +/* +static void ecp_open (int unit); +static void ecp_close (int unit, char *); +static void ecp_lowerup (int unit); +static void ecp_lowerdown (int); +static void ecp_input (int unit, u_char *pkt, int len); +static void ecp_protrej (int unit); +*/ +#if PRINTPKT_SUPPORT +static int ecp_printpkt (const u_char *pkt, int len, + void (*printer) (void *, char *, ...), + void *arg); +#endif /* PRINTPKT_SUPPORT */ +/* +static void ecp_datainput (int unit, u_char *pkt, int len); +*/ + +const struct protent ecp_protent = { + PPP_ECP, + ecp_init, + NULL, /* ecp_input, */ + NULL, /* ecp_protrej, */ + NULL, /* ecp_lowerup, */ + NULL, /* ecp_lowerdown, */ + NULL, /* ecp_open, */ + NULL, /* ecp_close, */ +#if PRINTPKT_SUPPORT + ecp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* ecp_datainput, */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "ECP", + "Encrypted", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ecp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +fsm ecp_fsm[NUM_PPP]; +ecp_options ecp_wantoptions[NUM_PPP]; /* what to request the peer to use */ +ecp_options ecp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ +ecp_options ecp_allowoptions[NUM_PPP]; /* what we'll agree to do */ +ecp_options ecp_hisoptions[NUM_PPP]; /* what we agreed to do */ + +static const fsm_callbacks ecp_callbacks = { + NULL, /* ecp_resetci, */ + NULL, /* ecp_cilen, */ + NULL, /* ecp_addci, */ + NULL, /* ecp_ackci, */ + NULL, /* ecp_nakci, */ + NULL, /* ecp_rejci, */ + NULL, /* ecp_reqci, */ + NULL, /* ecp_up, */ + NULL, /* ecp_down, */ + NULL, + NULL, + NULL, + NULL, + NULL, /* ecp_extcode, */ + "ECP" +}; + +/* + * ecp_init - initialize ECP. + */ +static void +ecp_init(unit) + int unit; +{ + fsm *f = &ecp_fsm[unit]; + + f->unit = unit; + f->protocol = PPP_ECP; + f->callbacks = &ecp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(&ecp_wantoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_gotoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_allowoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_hisoptions[unit], 0, sizeof(ecp_options)); +#endif /* 0 */ + +} + + +#if PRINTPKT_SUPPORT +static int +ecp_printpkt(p, plen, printer, arg) + const u_char *p; + int plen; + void (*printer) (void *, char *, ...); + void *arg; +{ + return 0; +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eui64.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eui64.c new file mode 100644 index 0000000..01493bc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/eui64.c @@ -0,0 +1,56 @@ +/* + * eui64.c - EUI64 routines for IPv6CP. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: eui64.c,v 1.6 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/eui64.h" + +/* + * eui64_ntoa - Make an ascii representation of an interface identifier + */ +char *eui64_ntoa(eui64_t e) { + static char buf[20]; + + sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x", + e.e8[0], e.e8[1], e.e8[2], e.e8[3], + e.e8[4], e.e8[5], e.e8[6], e.e8[7]); + return buf; +} + +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/fsm.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/fsm.c new file mode 100644 index 0000000..b1f08af --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/fsm.c @@ -0,0 +1,799 @@ +/* + * fsm.c - {Link, IP} Control Protocol Finite State Machine. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + * Randomize fsm id on link/init. + * Deal with variable outgoing MTU. + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" + +static void fsm_timeout (void *); +static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len); +static void fsm_rconfack(fsm *f, int id, u_char *inp, int len); +static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len); +static void fsm_rtermreq(fsm *f, int id, u_char *p, int len); +static void fsm_rtermack(fsm *f); +static void fsm_rcoderej(fsm *f, u_char *inp, int len); +static void fsm_sconfreq(fsm *f, int retransmit); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + +/* + * fsm_init - Initialize fsm. + * + * Initialize fsm state. + */ +void fsm_init(fsm *f) { + ppp_pcb *pcb = f->pcb; + f->state = PPP_FSM_INITIAL; + f->flags = 0; + f->id = 0; /* XXX Start with random id? */ + f->maxnakloops = pcb->settings.fsm_max_nak_loops; + f->term_reason_len = 0; +} + + +/* + * fsm_lowerup - The lower layer is up. + */ +void fsm_lowerup(fsm *f) { + switch( f->state ){ + case PPP_FSM_INITIAL: + f->state = PPP_FSM_CLOSED; + break; + + case PPP_FSM_STARTING: + if( f->flags & OPT_SILENT ) + f->state = PPP_FSM_STOPPED; + else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + } + break; + + default: + FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_lowerdown - The lower layer is down. + * + * Cancel all timeouts and inform upper layers. + */ +void fsm_lowerdown(fsm *f) { + switch( f->state ){ + case PPP_FSM_CLOSED: + f->state = PPP_FSM_INITIAL; + break; + + case PPP_FSM_STOPPED: + f->state = PPP_FSM_STARTING; + if( f->callbacks->starting ) + (*f->callbacks->starting)(f); + break; + + case PPP_FSM_CLOSING: + f->state = PPP_FSM_INITIAL; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case PPP_FSM_STOPPING: + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + f->state = PPP_FSM_STARTING; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case PPP_FSM_OPENED: + if( f->callbacks->down ) + (*f->callbacks->down)(f); + f->state = PPP_FSM_STARTING; + break; + + default: + FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_open - Link is allowed to come up. + */ +void fsm_open(fsm *f) { + switch( f->state ){ + case PPP_FSM_INITIAL: + f->state = PPP_FSM_STARTING; + if( f->callbacks->starting ) + (*f->callbacks->starting)(f); + break; + + case PPP_FSM_CLOSED: + if( f->flags & OPT_SILENT ) + f->state = PPP_FSM_STOPPED; + else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + } + break; + + case PPP_FSM_CLOSING: + f->state = PPP_FSM_STOPPING; + /* fall through */ + /* no break */ + case PPP_FSM_STOPPED: + case PPP_FSM_OPENED: + if( f->flags & OPT_RESTART ){ + fsm_lowerdown(f); + fsm_lowerup(f); + } + break; + default: + break; + } +} + +/* + * terminate_layer - Start process of shutting down the FSM + * + * Cancel any timeout running, notify upper layers we're done, and + * send a terminate-request message as configured. + */ +static void terminate_layer(fsm *f, int nextstate) { + ppp_pcb *pcb = f->pcb; + + if( f->state != PPP_FSM_OPENED ) + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + else if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers we're down */ + + /* Init restart counter and send Terminate-Request */ + f->retransmits = pcb->settings.fsm_max_term_transmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (const u_char *) f->term_reason, f->term_reason_len); + + if (f->retransmits == 0) { + /* + * User asked for no terminate requests at all; just close it. + * We've already fired off one Terminate-Request just to be nice + * to the peer, but we're not going to wait for a reply. + */ + f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + return; + } + + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + --f->retransmits; + + f->state = nextstate; +} + +/* + * fsm_close - Start closing connection. + * + * Cancel timeouts and either initiate close or possibly go directly to + * the PPP_FSM_CLOSED state. + */ +void fsm_close(fsm *f, const char *reason) { + f->term_reason = reason; + f->term_reason_len = (reason == NULL? 0: (u8_t)LWIP_MIN(strlen(reason), 0xFF) ); + switch( f->state ){ + case PPP_FSM_STARTING: + f->state = PPP_FSM_INITIAL; + break; + case PPP_FSM_STOPPED: + f->state = PPP_FSM_CLOSED; + break; + case PPP_FSM_STOPPING: + f->state = PPP_FSM_CLOSING; + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + case PPP_FSM_OPENED: + terminate_layer(f, PPP_FSM_CLOSING); + break; + default: + break; + } +} + + +/* + * fsm_timeout - Timeout expired. + */ +static void fsm_timeout(void *arg) { + fsm *f = (fsm *) arg; + ppp_pcb *pcb = f->pcb; + + switch (f->state) { + case PPP_FSM_CLOSING: + case PPP_FSM_STOPPING: + if( f->retransmits <= 0 ){ + /* + * We've waited for an ack long enough. Peer probably heard us. + */ + f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + } else { + /* Send Terminate-Request */ + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (const u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + --f->retransmits; + } + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + if (f->retransmits <= 0) { + ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f)); + f->state = PPP_FSM_STOPPED; + if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) + (*f->callbacks->finished)(f); + + } else { + /* Retransmit the configure-request */ + if (f->callbacks->retransmit) + (*f->callbacks->retransmit)(f); + fsm_sconfreq(f, 1); /* Re-send Configure-Request */ + if( f->state == PPP_FSM_ACKRCVD ) + f->state = PPP_FSM_REQSENT; + } + break; + + default: + FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_input - Input packet. + */ +void fsm_input(fsm *f, u_char *inpacket, int l) { + u_char *inp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (l < HEADERLEN) { + FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < HEADERLEN) { + FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); + return; + } + if (len > l) { + FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); + return; + } + len -= HEADERLEN; /* subtract header length */ + + if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ + FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", + f->protocol, f->state)); + return; + } + + /* + * Action depends on code. + */ + switch (code) { + case CONFREQ: + fsm_rconfreq(f, id, inp, len); + break; + + case CONFACK: + fsm_rconfack(f, id, inp, len); + break; + + case CONFNAK: + case CONFREJ: + fsm_rconfnakrej(f, code, id, inp, len); + break; + + case TERMREQ: + fsm_rtermreq(f, id, inp, len); + break; + + case TERMACK: + fsm_rtermack(f); + break; + + case CODEREJ: + fsm_rcoderej(f, inp, len); + break; + + default: + if( !f->callbacks->extcode + || !(*f->callbacks->extcode)(f, code, id, inp, len) ) + fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); + break; + } +} + + +/* + * fsm_rconfreq - Receive Configure-Request. + */ +static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { + int code, reject_if_disagree; + + switch( f->state ){ + case PPP_FSM_CLOSED: + /* Go away, we're closed */ + fsm_sdata(f, TERMACK, id, NULL, 0); + return; + case PPP_FSM_CLOSING: + case PPP_FSM_STOPPING: + return; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_STOPPED: + /* Negotiation started by our peer */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } + + /* + * Pass the requested configuration options + * to protocol-specific code for checking. + */ + if (f->callbacks->reqci){ /* Check CI */ + reject_if_disagree = (f->nakloops >= f->maxnakloops); + code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); + } else if (len) + code = CONFREJ; /* Reject all CI */ + else + code = CONFACK; + + /* send the Ack, Nak or Rej to the peer */ + fsm_sdata(f, code, id, inp, len); + + if (code == CONFACK) { + if (f->state == PPP_FSM_ACKRCVD) { + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = PPP_FSM_OPENED; + if (f->callbacks->up) + (*f->callbacks->up)(f); /* Inform upper layers */ + } else + f->state = PPP_FSM_ACKSENT; + f->nakloops = 0; + + } else { + /* we sent CONFACK or CONFREJ */ + if (f->state != PPP_FSM_ACKRCVD) + f->state = PPP_FSM_REQSENT; + if( code == CONFNAK ) + ++f->nakloops; + } +} + + +/* + * fsm_rconfack - Receive Configure-Ack. + */ +static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + + if (id != f->reqid || f->seen_ack) /* Expected id? */ + return; /* Nope, toss... */ + if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): + (len == 0)) ){ + /* Ack is bad - ignore it */ + ppp_error("Received bad configure-ack: %P", inp, len); + return; + } + f->seen_ack = 1; + f->rnakloops = 0; + + switch (f->state) { + case PPP_FSM_CLOSED: + case PPP_FSM_STOPPED: + fsm_sdata(f, TERMACK, id, NULL, 0); + break; + + case PPP_FSM_REQSENT: + f->state = PPP_FSM_ACKRCVD; + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + break; + + case PPP_FSM_ACKRCVD: + /* Huh? an extra valid Ack? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = PPP_FSM_OPENED; + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + if (f->callbacks->up) + (*f->callbacks->up)(f); /* Inform upper layers */ + break; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + */ +static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { + int ret; + int treat_as_reject; + + if (id != f->reqid || f->seen_ack) /* Expected id? */ + return; /* Nope, toss... */ + + if (code == CONFNAK) { + ++f->rnakloops; + treat_as_reject = (f->rnakloops >= f->maxnakloops); + if (f->callbacks->nakci == NULL + || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { + ppp_error("Received bad configure-nak: %P", inp, len); + return; + } + } else { + f->rnakloops = 0; + if (f->callbacks->rejci == NULL + || !(ret = f->callbacks->rejci(f, inp, len))) { + ppp_error("Received bad configure-rej: %P", inp, len); + return; + } + } + + f->seen_ack = 1; + + switch (f->state) { + case PPP_FSM_CLOSED: + case PPP_FSM_STOPPED: + fsm_sdata(f, TERMACK, id, NULL, 0); + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKSENT: + /* They didn't agree to what we wanted - try another request */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + if (ret < 0) + f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ + else + fsm_sconfreq(f, 0); /* Send Configure-Request */ + break; + + case PPP_FSM_ACKRCVD: + /* Got a Nak/reject when we had already had an Ack?? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rtermreq - Receive Terminate-Req. + */ +static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + + switch (f->state) { + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + f->state = PPP_FSM_REQSENT; /* Start over but keep trying */ + break; + + case PPP_FSM_OPENED: + if (len > 0) { + ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); + } else + ppp_info("%s terminated by peer", PROTO_NAME(f)); + f->retransmits = 0; + f->state = PPP_FSM_STOPPING; + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + break; + default: + break; + } + + fsm_sdata(f, TERMACK, id, NULL, 0); +} + + +/* + * fsm_rtermack - Receive Terminate-Ack. + */ +static void fsm_rtermack(fsm *f) { + switch (f->state) { + case PPP_FSM_CLOSING: + UNTIMEOUT(fsm_timeout, f); + f->state = PPP_FSM_CLOSED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + case PPP_FSM_STOPPING: + UNTIMEOUT(fsm_timeout, f); + f->state = PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_ACKRCVD: + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_OPENED: + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rcoderej - Receive an Code-Reject. + */ +static void fsm_rcoderej(fsm *f, u_char *inp, int len) { + u_char code, id; + + if (len < HEADERLEN) { + FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); + + if( f->state == PPP_FSM_ACKRCVD ) + f->state = PPP_FSM_REQSENT; +} + + +/* + * fsm_protreject - Peer doesn't speak this protocol. + * + * Treat this as a catastrophic error (RXJ-). + */ +void fsm_protreject(fsm *f) { + switch( f->state ){ + case PPP_FSM_CLOSING: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + /* no break */ + case PPP_FSM_CLOSED: + f->state = PPP_FSM_CLOSED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_STOPPING: + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + /* no break */ + case PPP_FSM_STOPPED: + f->state = PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_OPENED: + terminate_layer(f, PPP_FSM_STOPPING); + break; + + default: + FSMDEBUG(("%s: Protocol-reject event in state %d!", + PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_sconfreq - Send a Configure-Request. + */ +static void fsm_sconfreq(fsm *f, int retransmit) { + ppp_pcb *pcb = f->pcb; + struct pbuf *p; + u_char *outp; + int cilen; + + if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){ + /* Not currently negotiating - reset options */ + if( f->callbacks->resetci ) + (*f->callbacks->resetci)(f); + f->nakloops = 0; + f->rnakloops = 0; + } + + if( !retransmit ){ + /* New request - reset retransmission counter, use new ID */ + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + f->reqid = ++f->id; + } + + f->seen_ack = 0; + + /* + * Make up the request packet + */ + if( f->callbacks->cilen && f->callbacks->addci ){ + cilen = (*f->callbacks->cilen)(f); + if( cilen > pcb->peer_mru - HEADERLEN ) + cilen = pcb->peer_mru - HEADERLEN; + } else + cilen = 0; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + /* send the request to our peer */ + outp = (u_char*)p->payload; + MAKEHEADER(outp, f->protocol); + PUTCHAR(CONFREQ, outp); + PUTCHAR(f->reqid, outp); + PUTSHORT(cilen + HEADERLEN, outp); + if (cilen != 0) { + (*f->callbacks->addci)(f, outp, &cilen); + LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN); + } + + ppp_write(pcb, p); + + /* start the retransmit timer */ + --f->retransmits; + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); +} + + +/* + * fsm_sdata - Send some data. + * + * Used for all packets sent to our peer by this module. + */ +void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) { + ppp_pcb *pcb = f->pcb; + struct pbuf *p; + u_char *outp; + int outlen; + + /* Adjust length to be smaller than MTU */ + if (datalen > pcb->peer_mru - HEADERLEN) + datalen = pcb->peer_mru - HEADERLEN; + outlen = datalen + HEADERLEN; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ + MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); + MAKEHEADER(outp, f->protocol); + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + ppp_write(pcb, p); +} + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipcp.c new file mode 100644 index 0000000..b7c766e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipcp.c @@ -0,0 +1,2418 @@ +/* + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" + +#if 0 /* UNUSED */ +/* global vars */ +u32_t netmask = 0; /* IP netmask to set on interface */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ +#endif /* UNUSED */ + +#if 0 /* moved to ppp_settings */ +bool noremoteip = 0; /* Let him have no IP address */ +#endif /* moved to ppp_setting */ + +#if 0 /* UNUSED */ +/* Hook for a plugin to know when IP protocol has come up */ +void (*ip_up_hook) (void) = NULL; + +/* Hook for a plugin to know when IP protocol has come down */ +void (*ip_down_hook) (void) = NULL; + +/* Hook for a plugin to choose the remote IP address */ +void (*ip_choose_hook) (u32_t *) = NULL; +#endif /* UNUSED */ + +#if PPP_NOTIFY +/* Notifiers for when IPCP goes up and down */ +struct notifier *ip_up_notifier = NULL; +struct notifier *ip_down_notifier = NULL; +#endif /* PPP_NOTIFY */ + +/* local vars */ +#if 0 /* moved to ppp_pcb */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ +static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ +static int ipcp_is_up; /* have called np_up() */ +static int ipcp_is_open; /* haven't called np_finished() */ +static bool ask_for_local; /* request our address from peer */ +#endif /* moved to ppp_pcb */ +#if 0 /* UNUSED */ +static char vj_value[8]; /* string form of vj option value */ +static char netmask_str[20]; /* string form of netmask value */ +#endif /* UNUSED */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipcp_resetci(fsm *f); /* Reset our CI */ +static int ipcp_cilen(fsm *f); /* Return length of our CI */ +static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ +static int ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */ +static int ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ +static void ipcp_up(fsm *f); /* We're UP */ +static void ipcp_down(fsm *f); /* We're DOWN */ +static void ipcp_finished(fsm *f); /* Don't need lower layer */ + +static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ + ipcp_resetci, /* Reset our Configuration Information */ + ipcp_cilen, /* Length of our Configuration Information */ + ipcp_addci, /* Add our Configuration Information */ + ipcp_ackci, /* ACK our Configuration Information */ + ipcp_nakci, /* NAK our Configuration Information */ + ipcp_rejci, /* Reject our Configuration Information */ + ipcp_reqci, /* Request peer's Configuration Information */ + ipcp_up, /* Called when fsm reaches OPENED state */ + ipcp_down, /* Called when fsm leaves OPENED state */ + NULL, /* Called when we want the lower layer up */ + ipcp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPCP" /* String name of protocol */ +}; + +/* + * Command-line options. + */ +#if PPP_OPTIONS +static int setvjslots (char **); +static int setdnsaddr (char **); +static int setwinsaddr (char **); +static int setnetmask (char **); +int setipaddr (char *, char **, int); + +static void printipaddr (option_t *, void (*)(void *, char *,...),void *); + +static option_t ipcp_option_list[] = { + { "noip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP" }, + { "-ip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP", OPT_ALIAS }, + + { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, + { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, + &ipcp_allowoptions[0].neg_vj }, + + { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_A2CLR, + &ipcp_allowoptions[0].cflag }, + { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, + &ipcp_allowoptions[0].cflag }, + + { "vj-max-slots", o_special, (void *)setvjslots, + "Set maximum VJ header slots", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, + + { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, + "Accept peer's address for us", 1 }, + { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, + "Accept peer's address for it", 1 }, + + { "ipparam", o_string, &ipparam, + "Set ip script parameter", OPT_PRIO }, + + { "noipdefault", o_bool, &disable_defaultip, + "Don't use name for default IP adrs", 1 }, + + { "ms-dns", 1, (void *)setdnsaddr, + "DNS address for the peer's use" }, + { "ms-wins", 1, (void *)setwinsaddr, + "Nameserver for SMB over TCP/IP for peer" }, + + { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, + "Set timeout for IPCP", OPT_PRIO }, + { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, + "Set max #xmits for term-reqs", OPT_PRIO }, + { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, + "Set max #xmits for conf-reqs", OPT_PRIO }, + { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, + "Set max #conf-naks for IPCP", OPT_PRIO }, + + { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, + "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, + { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_A2CLR, + &ipcp_wantoptions[0].default_route }, + { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, + &ipcp_wantoptions[0].default_route }, + + { "replacedefaultroute", o_bool, + &ipcp_wantoptions[0].replace_default_route, + "Replace default route", 1 + }, + { "noreplacedefaultroute", o_bool, + &ipcp_allowoptions[0].replace_default_route, + "Never replace default route", OPT_A2COPY, + &ipcp_wantoptions[0].replace_default_route }, + { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, + "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, + { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, + "disable proxyarp option", OPT_A2CLR, + &ipcp_wantoptions[0].proxy_arp }, + { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, + "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, + &ipcp_wantoptions[0].proxy_arp }, + + { "usepeerdns", o_bool, &usepeerdns, + "Ask peer for DNS address(es)", 1 }, + + { "netmask", o_special, (void *)setnetmask, + "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, + + { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, + "Disable old-style IP-Addresses usage", OPT_A2CLR, + &ipcp_allowoptions[0].old_addrs }, + { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, + "Disable IP-Address usage", OPT_A2CLR, + &ipcp_allowoptions[0].neg_addr }, + + { "noremoteip", o_bool, &noremoteip, + "Allow peer to have no IP address", 1 }, + + { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr, + "Don't send our IP address to peer", OPT_A2CLR, + &ipcp_wantoptions[0].old_addrs}, + + { "IP addresses", o_wild, (void *) &setipaddr, + "set local and remote IP addresses", + OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ipcp_init(ppp_pcb *pcb); +static void ipcp_open(ppp_pcb *pcb); +static void ipcp_close(ppp_pcb *pcb, const char *reason); +static void ipcp_lowerup(ppp_pcb *pcb); +static void ipcp_lowerdown(ppp_pcb *pcb); +static void ipcp_input(ppp_pcb *pcb, u_char *p, int len); +static void ipcp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int ipcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS +static void ip_check_options (void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT +static int ip_demand_conf (int); +static int ip_active_pkt (u_char *, int); +#endif /* DEMAND_SUPPORT */ +#if 0 /* UNUSED */ +static void create_resolv (u32_t, u32_t); +#endif /* UNUSED */ + +const struct protent ipcp_protent = { + PPP_IPCP, + ipcp_init, + ipcp_input, + ipcp_protrej, + ipcp_lowerup, + ipcp_lowerdown, + ipcp_open, + ipcp_close, +#if PRINTPKT_SUPPORT + ipcp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "IPCP", + "IP", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ipcp_option_list, + ip_check_options, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + ip_demand_conf, + ip_active_pkt +#endif /* DEMAND_SUPPORT */ +}; + +static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute); + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID 2 +#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ +#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ +#define CILEN_ADDR 6 /* new-style single address option */ +#define CILEN_ADDRS 10 /* old-style dual address option */ + + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED, already defined by lwIP */ +/* + * Make a string representation of a network IP address. + */ +char * +ip_ntoa(ipaddr) +u32_t ipaddr; +{ + static char b[64]; + + slprintf(b, sizeof(b), "%I", ipaddr); + return b; +} +#endif /* UNUSED, already defined by lwIP */ + +/* + * Option parsing. + */ +#if PPP_OPTIONS +/* + * setvjslots - set maximum number of connection slots for VJ compression + */ +static int +setvjslots(argv) + char **argv; +{ + int value; + + if (!int_option(*argv, &value)) + return 0; + + if (value < 2 || value > 16) { + option_error("vj-max-slots value must be between 2 and 16"); + return 0; + } + ipcp_wantoptions [0].maxslotindex = + ipcp_allowoptions[0].maxslotindex = value - 1; + slprintf(vj_value, sizeof(vj_value), "%d", value); + return 1; +} + +/* + * setdnsaddr - set the dns address(es) + */ +static int +setdnsaddr(argv) + char **argv; +{ + u32_t dns; + struct hostent *hp; + + dns = inet_addr(*argv); + if (dns == (u32_t) -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-dns option", + *argv); + return 0; + } + dns = *(u32_t *)hp->h_addr; + } + + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].dnsaddr[1] == 0) + ipcp_allowoptions[0].dnsaddr[0] = dns; + else + ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; + + /* always set the secondary address value. */ + ipcp_allowoptions[0].dnsaddr[1] = dns; + + return (1); +} + +/* + * setwinsaddr - set the wins address(es) + * This is primrarly used with the Samba package under UNIX or for pointing + * the caller to the existing WINS server on a Windows NT platform. + */ +static int +setwinsaddr(argv) + char **argv; +{ + u32_t wins; + struct hostent *hp; + + wins = inet_addr(*argv); + if (wins == (u32_t) -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-wins option", + *argv); + return 0; + } + wins = *(u32_t *)hp->h_addr; + } + + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].winsaddr[1] == 0) + ipcp_allowoptions[0].winsaddr[0] = wins; + else + ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; + + /* always set the secondary address value. */ + ipcp_allowoptions[0].winsaddr[1] = wins; + + return (1); +} + +/* + * setipaddr - Set the IP address + * If doit is 0, the call is to check whether this option is + * potentially an IP address specification. + * Not static so that plugins can call it to set the addresses + */ +int +setipaddr(arg, argv, doit) + char *arg; + char **argv; + int doit; +{ + struct hostent *hp; + char *colon; + u32_t local, remote; + ipcp_options *wo = &ipcp_wantoptions[0]; + static int prio_local = 0, prio_remote = 0; + + /* + * IP address pair separated by ":". + */ + if ((colon = strchr(arg, ':')) == NULL) + return 0; + if (!doit) + return 1; + + /* + * If colon first character, then no local addr. + */ + if (colon != arg && option_priority >= prio_local) { + *colon = '\0'; + if ((local = inet_addr(arg)) == (u32_t) -1) { + if ((hp = gethostbyname(arg)) == NULL) { + option_error("unknown host: %s", arg); + return 0; + } + local = *(u32_t *)hp->h_addr; + } + if (bad_ip_adrs(local)) { + option_error("bad local IP address %s", ip_ntoa(local)); + return 0; + } + if (local != 0) + wo->ouraddr = local; + *colon = ':'; + prio_local = option_priority; + } + + /* + * If colon last character, then no remote addr. + */ + if (*++colon != '\0' && option_priority >= prio_remote) { + if ((remote = inet_addr(colon)) == (u32_t) -1) { + if ((hp = gethostbyname(colon)) == NULL) { + option_error("unknown host: %s", colon); + return 0; + } + remote = *(u32_t *)hp->h_addr; + if (remote_name[0] == 0) + strlcpy(remote_name, colon, sizeof(remote_name)); + } + if (bad_ip_adrs(remote)) { + option_error("bad remote IP address %s", ip_ntoa(remote)); + return 0; + } + if (remote != 0) + wo->hisaddr = remote; + prio_remote = option_priority; + } + + return 1; +} + +static void +printipaddr(opt, printer, arg) + option_t *opt; + void (*printer) (void *, char *, ...); + void *arg; +{ + ipcp_options *wo = &ipcp_wantoptions[0]; + + if (wo->ouraddr != 0) + printer(arg, "%I", wo->ouraddr); + printer(arg, ":"); + if (wo->hisaddr != 0) + printer(arg, "%I", wo->hisaddr); +} + +/* + * setnetmask - set the netmask to be used on the interface. + */ +static int +setnetmask(argv) + char **argv; +{ + u32_t mask; + int n; + char *p; + + /* + * Unfortunately, if we use inet_addr, we can't tell whether + * a result of all 1s is an error or a valid 255.255.255.255. + */ + p = *argv; + n = parse_dotted_ip(p, &mask); + + mask = lwip_htonl(mask); + + if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { + option_error("invalid netmask value '%s'", *argv); + return 0; + } + + netmask = mask; + slprintf(netmask_str, sizeof(netmask_str), "%I", mask); + + return (1); +} + +int +parse_dotted_ip(p, vp) + char *p; + u32_t *vp; +{ + int n; + u32_t v, b; + char *endp, *p0 = p; + + v = 0; + for (n = 3;; --n) { + b = strtoul(p, &endp, 0); + if (endp == p) + return 0; + if (b > 255) { + if (n < 3) + return 0; + /* accept e.g. 0xffffff00 */ + *vp = b; + return endp - p0; + } + v |= b << (n * 8); + p = endp; + if (n == 0) + break; + if (*p != '.') + return 0; + ++p; + } + *vp = v; + return p - p0; +} +#endif /* PPP_OPTIONS */ + +/* + * ipcp_init - Initialize IPCP. + */ +static void ipcp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_IPCP; + f->callbacks = &ipcp_callbacks; + fsm_init(f); + + /* + * Some 3G modems use repeated IPCP NAKs as a way of stalling + * until they can contact a server on the network, so we increase + * the default number of NAKs we accept before we start treating + * them as rejects. + */ + f->maxnakloops = 100; + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); +#endif /* 0 */ + + wo->neg_addr = wo->old_addrs = 1; +#if VJ_SUPPORT + wo->neg_vj = 1; + wo->vj_protocol = IPCP_VJ_COMP; + wo->maxslotindex = MAX_STATES - 1; /* really max index */ + wo->cflag = 1; +#endif /* VJ_SUPPORT */ + +#if 0 /* UNUSED */ + /* wanting default route by default */ + wo->default_route = 1; +#endif /* UNUSED */ + + ao->neg_addr = ao->old_addrs = 1; +#if VJ_SUPPORT + /* max slots and slot-id compression are currently hardwired in */ + /* ppp_if.c to 16 and 1, this needs to be changed (among other */ + /* things) gmc */ + + ao->neg_vj = 1; + ao->maxslotindex = MAX_STATES - 1; + ao->cflag = 1; +#endif /* #if VJ_SUPPORT */ + +#if 0 /* UNUSED */ + /* + * XXX These control whether the user may use the proxyarp + * and defaultroute options. + */ + ao->proxy_arp = 1; + ao->default_route = 1; +#endif /* UNUSED */ +} + + +/* + * ipcp_open - IPCP is allowed to come up. + */ +static void ipcp_open(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_open(f); + pcb->ipcp_is_open = 1; +} + + +/* + * ipcp_close - Take IPCP down. + */ +static void ipcp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->ipcp_fsm; + fsm_close(f, reason); +} + + +/* + * ipcp_lowerup - The lower layer is up. + */ +static void ipcp_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerup(f); +} + + +/* + * ipcp_lowerdown - The lower layer is down. + */ +static void ipcp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerdown(f); +} + + +/* + * ipcp_input - Input IPCP packet. + */ +static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->ipcp_fsm; + fsm_input(f, p, len); +} + + +/* + * ipcp_protrej - A Protocol-Reject was received for IPCP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void ipcp_protrej(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerdown(f); +} + + +/* + * ipcp_resetci - Reset our CI. + * Called by fsm_sconfreq, Send Configure Request. + */ +static void ipcp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + + wo->req_addr = (wo->neg_addr || wo->old_addrs) && + (ao->neg_addr || ao->old_addrs); + if (wo->ouraddr == 0) + wo->accept_local = 1; + if (wo->hisaddr == 0) + wo->accept_remote = 1; +#if LWIP_DNS + wo->req_dns1 = wo->req_dns2 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */ +#endif /* LWIP_DNS */ + *go = *wo; + if (!pcb->ask_for_local) + go->ouraddr = 0; +#if 0 /* UNUSED */ + if (ip_choose_hook) { + ip_choose_hook(&wo->hisaddr); + if (wo->hisaddr) { + wo->accept_remote = 0; + } + } +#endif /* UNUSED */ + BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options)); +} + + +/* + * ipcp_cilen - Return length of our CI. + * Called by fsm_sconfreq, Send Configure Request. + */ +static int ipcp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; +#if VJ_SUPPORT + ipcp_options *wo = &pcb->ipcp_wantoptions; +#endif /* VJ_SUPPORT */ + ipcp_options *ho = &pcb->ipcp_hisoptions; + +#define LENCIADDRS(neg) (neg ? CILEN_ADDRS : 0) +#if VJ_SUPPORT +#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) +#endif /* VJ_SUPPORT */ +#define LENCIADDR(neg) (neg ? CILEN_ADDR : 0) +#if LWIP_DNS +#define LENCIDNS(neg) LENCIADDR(neg) +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ +#define LENCIWINS(neg) LENCIADDR(neg) +#endif /* UNUSED - WINS */ + + /* + * First see if we want to change our options to the old + * forms because we have received old forms from the peer. + */ + if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs) + go->neg_addr = 0; + +#if VJ_SUPPORT + if (wo->neg_vj && !go->neg_vj && !go->old_vj) { + /* try an older style of VJ negotiation */ + /* use the old style only if the peer did */ + if (ho->neg_vj && ho->old_vj) { + go->neg_vj = 1; + go->old_vj = 1; + go->vj_protocol = ho->vj_protocol; + } + } +#endif /* VJ_SUPPORT */ + + return (LENCIADDRS(!go->neg_addr && go->old_addrs) + +#if VJ_SUPPORT + LENCIVJ(go->neg_vj, go->old_vj) + +#endif /* VJ_SUPPORT */ + LENCIADDR(go->neg_addr) + +#if LWIP_DNS + LENCIDNS(go->req_dns1) + + LENCIDNS(go->req_dns2) + +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + LENCIWINS(go->winsaddr[0]) + + LENCIWINS(go->winsaddr[1]) + +#endif /* UNUSED - WINS */ + 0); +} + + +/* + * ipcp_addci - Add our desired CIs to a packet. + * Called by fsm_sconfreq, Send Configure Request. + */ +static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + int len = *lenp; + +#define ADDCIADDRS(opt, neg, val1, val2) \ + if (neg) { \ + if (len >= CILEN_ADDRS) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDRS, ucp); \ + l = lwip_ntohl(val1); \ + PUTLONG(l, ucp); \ + l = lwip_ntohl(val2); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDRS; \ + } else \ + go->old_addrs = 0; \ + } + +#if VJ_SUPPORT +#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ + if (neg) { \ + int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ + if (len >= vjlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(vjlen, ucp); \ + PUTSHORT(val, ucp); \ + if (!old) { \ + PUTCHAR(maxslotindex, ucp); \ + PUTCHAR(cflag, ucp); \ + } \ + len -= vjlen; \ + } else \ + neg = 0; \ + } +#endif /* VJ_SUPPORT */ + +#define ADDCIADDR(opt, neg, val) \ + if (neg) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(val); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + neg = 0; \ + } + +#if LWIP_DNS +#define ADDCIDNS(opt, neg, addr) \ + if (neg) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(addr); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + neg = 0; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define ADDCIWINS(opt, addr) \ + if (addr) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(addr); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + addr = 0; \ + } +#endif /* UNUSED - WINS */ + + ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, + go->hisaddr); + +#if VJ_SUPPORT + ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); + +#if LWIP_DNS + ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + *lenp -= len; +} + + +/* + * ipcp_ackci - Ack our CIs. + * Called by fsm_rconfack, Receive Configure ACK. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int ipcp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_short cilen, citype; + u32_t cilong; +#if VJ_SUPPORT + u_short cishort; + u_char cimaxslotindex, cicflag; +#endif /* VJ_SUPPORT */ + + /* + * CIs must be in exactly the same order that we sent... + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ + +#define ACKCIADDRS(opt, neg, val1, val2) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDRS) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDRS || \ + citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val1 != cilong) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val2 != cilong) \ + goto bad; \ + } + +#if VJ_SUPPORT +#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ + if (neg) { \ + int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ + if ((len -= vjlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != vjlen || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + if (!old) { \ + GETCHAR(cimaxslotindex, p); \ + if (cimaxslotindex != maxslotindex) \ + goto bad; \ + GETCHAR(cicflag, p); \ + if (cicflag != cflag) \ + goto bad; \ + } \ + } +#endif /* VJ_SUPPORT */ + +#define ACKCIADDR(opt, neg, val) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || \ + citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val != cilong) \ + goto bad; \ + } + +#if LWIP_DNS +#define ACKCIDNS(opt, neg, addr) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (addr != cilong) \ + goto bad; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define ACKCIWINS(opt, addr) \ + if (addr) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (addr != cilong) \ + goto bad; \ + } +#endif /* UNUSED - WINS */ + + ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, + go->hisaddr); + +#if VJ_SUPPORT + ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); + +#if LWIP_DNS + ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); + +bad: + IPCPDEBUG(("ipcp_ackci: received bad Ack!")); + return (0); +} + +/* + * ipcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPCP is in the OPENED state. + * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_char citype, cilen, *next; +#if VJ_SUPPORT + u_char cimaxslotindex, cicflag; + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t ciaddr1, ciaddr2, l; +#if LWIP_DNS + u32_t cidnsaddr; +#endif /* LWIP_DNS */ + ipcp_options no; /* options we've seen Naks for */ + ipcp_options try_; /* options to request next time */ + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIADDRS(opt, neg, code) \ + if ((neg) && \ + (cilen = p[1]) == CILEN_ADDRS && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciaddr1 = lwip_htonl(l); \ + GETLONG(l, p); \ + ciaddr2 = lwip_htonl(l); \ + no.old_addrs = 1; \ + code \ + } + +#if VJ_SUPPORT +#define NAKCIVJ(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#endif /* VJ_SUPPORT */ + +#define NAKCIADDR(opt, neg, code) \ + if (go->neg && \ + (cilen = p[1]) == CILEN_ADDR && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciaddr1 = lwip_htonl(l); \ + no.neg = 1; \ + code \ + } + +#if LWIP_DNS +#define NAKCIDNS(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cidnsaddr = lwip_htonl(l); \ + no.neg = 1; \ + code \ + } +#endif /* LWIP_DNS */ + + /* + * Accept the peer's idea of {our,his} address, if different + * from our idea, only if the accept_{local,remote} flag is set. + */ + NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, + if (treat_as_reject) { + try_.old_addrs = 0; + } else { + if (go->accept_local && ciaddr1) { + /* take his idea of our address */ + try_.ouraddr = ciaddr1; + } + if (go->accept_remote && ciaddr2) { + /* take his idea of his address */ + try_.hisaddr = ciaddr2; + } + } + ); + +#if VJ_SUPPORT + /* + * Accept the peer's value of maxslotindex provided that it + * is less than what we asked for. Turn off slot-ID compression + * if the peer wants. Send old-style compress-type option if + * the peer wants. + */ + NAKCIVJ(CI_COMPRESSTYPE, neg_vj, + if (treat_as_reject) { + try_.neg_vj = 0; + } else if (cilen == CILEN_VJ) { + GETCHAR(cimaxslotindex, p); + GETCHAR(cicflag, p); + if (cishort == IPCP_VJ_COMP) { + try_.old_vj = 0; + if (cimaxslotindex < go->maxslotindex) + try_.maxslotindex = cimaxslotindex; + if (!cicflag) + try_.cflag = 0; + } else { + try_.neg_vj = 0; + } + } else { + if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { + try_.old_vj = 1; + try_.vj_protocol = cishort; + } else { + try_.neg_vj = 0; + } + } + ); +#endif /* VJ_SUPPORT */ + + NAKCIADDR(CI_ADDR, neg_addr, + if (treat_as_reject) { + try_.neg_addr = 0; + try_.old_addrs = 0; + } else if (go->accept_local && ciaddr1) { + /* take his idea of our address */ + try_.ouraddr = ciaddr1; + } + ); + +#if LWIP_DNS + NAKCIDNS(CI_MS_DNS1, req_dns1, + if (treat_as_reject) { + try_.req_dns1 = 0; + } else { + try_.dnsaddr[0] = cidnsaddr; + } + ); + + NAKCIDNS(CI_MS_DNS2, req_dns2, + if (treat_as_reject) { + try_.req_dns2 = 0; + } else { + try_.dnsaddr[1] = cidnsaddr; + } + ); +#endif /* #if LWIP_DNS */ + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If they want to negotiate about IP addresses, we comply. + * If they want us to ask for compression, we refuse. + * If they want us to ask for ms-dns, we do that, since some + * peers get huffy if we don't. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) + goto bad; + next = p + cilen - 2; + + switch (citype) { +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (go->neg_vj || no.neg_vj || + (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) + goto bad; + no.neg_vj = 1; + break; +#endif /* VJ_SUPPORT */ + case CI_ADDRS: + if ((!go->neg_addr && go->old_addrs) || no.old_addrs + || cilen != CILEN_ADDRS) + goto bad; + try_.neg_addr = 0; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1 && go->accept_local) + try_.ouraddr = ciaddr1; + GETLONG(l, p); + ciaddr2 = lwip_htonl(l); + if (ciaddr2 && go->accept_remote) + try_.hisaddr = ciaddr2; + no.old_addrs = 1; + break; + case CI_ADDR: + if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) + goto bad; + try_.old_addrs = 0; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1 && go->accept_local) + try_.ouraddr = ciaddr1; + if (try_.ouraddr != 0) + try_.neg_addr = 1; + no.neg_addr = 1; + break; +#if LWIP_DNS + case CI_MS_DNS1: + if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + try_.dnsaddr[0] = lwip_htonl(l); + try_.req_dns1 = 1; + no.req_dns1 = 1; + break; + case CI_MS_DNS2: + if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + try_.dnsaddr[1] = lwip_htonl(l); + try_.req_dns2 = 1; + no.req_dns2 = 1; + break; +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + if (cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1) + try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1; + break; +#endif /* UNUSED - WINS */ + default: + break; + } + p = next; + } + + /* + * OK, the Nak is good. Now we can update state. + * If there are any remaining options, we ignore them. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; + +bad: + IPCPDEBUG(("ipcp_nakci: received bad Nak!")); + return 0; +} + + +/* + * ipcp_rejci - Reject some of our CIs. + * Callback from fsm_rconfnakrej. + */ +static int ipcp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_char cilen; +#if VJ_SUPPORT + u_char cimaxslotindex, ciflag; + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t cilong; + ipcp_options try_; /* options to request next time */ + + try_ = *go; + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIADDRS(opt, neg, val1, val2) \ + if ((neg) && \ + (cilen = p[1]) == CILEN_ADDRS && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val1) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val2) \ + goto bad; \ + try_.old_addrs = 0; \ + } + +#if VJ_SUPPORT +#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ + if (go->neg && \ + p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ + len >= p[1] && \ + p[0] == opt) { \ + len -= p[1]; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + if (!old) { \ + GETCHAR(cimaxslotindex, p); \ + if (cimaxslotindex != maxslot) \ + goto bad; \ + GETCHAR(ciflag, p); \ + if (ciflag != cflag) \ + goto bad; \ + } \ + try_.neg = 0; \ + } +#endif /* VJ_SUPPORT */ + +#define REJCIADDR(opt, neg, val) \ + if (go->neg && \ + (cilen = p[1]) == CILEN_ADDR && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } + +#if LWIP_DNS +#define REJCIDNS(opt, neg, dnsaddr) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != dnsaddr) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define REJCIWINS(opt, addr) \ + if (addr && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != addr) \ + goto bad; \ + try_.winsaddr[opt == CI_MS_WINS2] = 0; \ + } +#endif /* UNUSED - WINS */ + + REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, + go->ouraddr, go->hisaddr); + +#if VJ_SUPPORT + REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + REJCIADDR(CI_ADDR, neg_addr, go->ouraddr); + +#if LWIP_DNS + REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + + REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + IPCPDEBUG(("ipcp_rejci: received bad Reject!")); + return 0; +} + + +/* + * ipcp_reqci - Check the peer's requested CIs and send appropriate response. + * Callback from fsm_rconfreq, Receive Configure Request + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * len = Length of requested CIs + */ +static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ +#if VJ_SUPPORT + u_short cishort; /* Parsed short value */ +#endif /* VJ_SUPPORT */ + u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *ucp = inp; /* Pointer to current output char */ + int l = *len; /* Length left */ +#if VJ_SUPPORT + u_char maxslotindex, cflag; +#endif /* VJ_SUPPORT */ +#if LWIP_DNS + int d; +#endif /* LWIP_DNS */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + IPCPDEBUG(("ipcp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_ADDRS: + if (!ao->old_addrs || ho->neg_addr || + cilen != CILEN_ADDRS) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = lwip_htonl(tl); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * If neither we nor he knows his address, reject the option. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + /* + * If he doesn't know our address, or if we both have our address + * but disagree about it, then NAK it with our idea. + */ + GETLONG(tl, p); /* Parse desination address (ours) */ + ciaddr2 = lwip_htonl(tl); + if (ciaddr2 != wo->ouraddr) { + if (ciaddr2 == 0 || !wo->accept_local) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->ouraddr); + PUTLONG(tl, p); + } + } else { + wo->ouraddr = ciaddr2; /* accept peer's idea */ + } + } + + ho->old_addrs = 1; + ho->hisaddr = ciaddr1; + ho->ouraddr = ciaddr2; + break; + + case CI_ADDR: + if (!ao->neg_addr || ho->old_addrs || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = lwip_htonl(tl); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * Don't ACK an address of 0.0.0.0 - reject it instead. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + ho->neg_addr = 1; + ho->hisaddr = ciaddr1; + break; + +#if LWIP_DNS + case CI_MS_DNS1: + case CI_MS_DNS2: + /* Microsoft primary or secondary DNS request */ + d = citype == CI_MS_DNS2; + + /* If we do not have a DNS address then we cannot send it */ + if (ao->dnsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (lwip_htonl(tl) != ao->dnsaddr[d]) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(ao->dnsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + /* Microsoft primary or secondary WINS request */ + d = citype == CI_MS_WINS2; + + /* If we do not have a DNS address then we cannot send it */ + if (ao->winsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (lwip_htonl(tl) != ao->winsaddr[d]) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(ao->winsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (!ao->neg_vj || + (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + if (!(cishort == IPCP_VJ_COMP || + (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { + orc = CONFREJ; + break; + } + + ho->neg_vj = 1; + ho->vj_protocol = cishort; + if (cilen == CILEN_VJ) { + GETCHAR(maxslotindex, p); + if (maxslotindex > ao->maxslotindex) { + orc = CONFNAK; + if (!reject_if_disagree){ + DECPTR(1, p); + PUTCHAR(ao->maxslotindex, p); + } + } + GETCHAR(cflag, p); + if (cflag && !ao->cflag) { + orc = CONFNAK; + if (!reject_if_disagree){ + DECPTR(1, p); + PUTCHAR(wo->cflag, p); + } + } + ho->maxslotindex = maxslotindex; + ho->cflag = cflag; + } else { + ho->old_vj = 1; + ho->maxslotindex = MAX_STATES - 1; + ho->cflag = 1; + } + break; +#endif /* VJ_SUPPORT */ + + default: + orc = CONFREJ; + break; + } +endswitch: + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree) /* Getting fed up with sending NAKs? */ + orc = CONFREJ; /* Get tough if so */ + else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + if (rc == CONFACK) { /* Ack'd all prior CIs? */ + rc = CONFNAK; /* Not anymore... */ + ucp = inp; /* Backup */ + } + } + } + + if (orc == CONFREJ && /* Reject this CI */ + rc != CONFREJ) { /* but no prior ones? */ + rc = CONFREJ; + ucp = inp; /* Backup */ + } + + /* Need to move CI? */ + if (ucp != cip) + MEMCPY(ucp, cip, cilen); /* Move it */ + + /* Update output pointer */ + INCPTR(cilen, ucp); + } + + /* + * If we aren't rejecting this packet, and we want to negotiate + * their address, and they didn't send their address, then we + * send a NAK with a CI_ADDR option appended. We assume the + * input buffer is long enough that we can append the extra + * option safely. + */ + if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && + wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) { + if (rc == CONFACK) { + rc = CONFNAK; + ucp = inp; /* reset pointer */ + wo->req_addr = 0; /* don't ask again */ + } + PUTCHAR(CI_ADDR, ucp); + PUTCHAR(CILEN_ADDR, ucp); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, ucp); + } + + *len = ucp - inp; /* Compute output length */ + IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +#if 0 /* UNUSED */ +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options() +{ + struct hostent *hp; + u32_t local; + ipcp_options *wo = &ipcp_wantoptions[0]; + + /* + * Default our local IP address based on our hostname. + * If local IP address already given, don't bother. + */ + if (wo->ouraddr == 0 && !disable_defaultip) { + /* + * Look up our hostname (possibly with domain name appended) + * and take the first IP address as our local IP address. + * If there isn't an IP address for our hostname, too bad. + */ + wo->accept_local = 1; /* don't insist on this default value */ + if ((hp = gethostbyname(hostname)) != NULL) { + local = *(u32_t *)hp->h_addr; + if (local != 0 && !bad_ip_adrs(local)) + wo->ouraddr = local; + } + } + ask_for_local = wo->ouraddr != 0 || !disable_defaultip; +} +#endif /* UNUSED */ + +#if DEMAND_SUPPORT +/* + * ip_demand_conf - configure the interface as though + * IPCP were up, for use with dial-on-demand. + */ +static int +ip_demand_conf(u) + int u; +{ + ppp_pcb *pcb = &ppp_pcb_list[u]; + ipcp_options *wo = &ipcp_wantoptions[u]; + + if (wo->hisaddr == 0 && !pcb->settings.noremoteip) { + /* make up an arbitrary address for the peer */ + wo->hisaddr = lwip_htonl(0x0a707070 + ifunit); + wo->accept_remote = 1; + } + if (wo->ouraddr == 0) { + /* make up an arbitrary address for us */ + wo->ouraddr = lwip_htonl(0x0a404040 + ifunit); + wo->accept_local = 1; + ask_for_local = 0; /* don't tell the peer this address */ + } + if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr))) + return 0; + if (!sifup(pcb)) + return 0; + if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE)) + return 0; +#if 0 /* UNUSED */ + if (wo->default_route) + if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr, + wo->replace_default_route)) + default_route_set[u] = 1; +#endif /* UNUSED */ +#if 0 /* UNUSED - PROXY ARP */ + if (wo->proxy_arp) + if (sifproxyarp(pcb, wo->hisaddr)) + proxy_arp_set[u] = 1; +#endif /* UNUSED - PROXY ARP */ + + ppp_notice("local IP address %I", wo->ouraddr); + if (wo->hisaddr) + ppp_notice("remote IP address %I", wo->hisaddr); + + return 1; +} +#endif /* DEMAND_SUPPORT */ + +/* + * ipcp_up - IPCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ +static void ipcp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + u32_t mask; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + ipcp_options *wo = &pcb->ipcp_wantoptions; + + IPCPDEBUG(("ipcp: up")); + + /* + * We must have a non-zero IP address for both ends of the link. + */ + if (!ho->neg_addr && !ho->old_addrs) + ho->hisaddr = wo->hisaddr; + + if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) + && wo->ouraddr != 0) { + ppp_error("Peer refused to agree to our IP address"); + ipcp_close(f->pcb, "Refused our IP address"); + return; + } + if (go->ouraddr == 0) { + ppp_error("Could not determine local IP address"); + ipcp_close(f->pcb, "Could not determine local IP address"); + return; + } + if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { + ho->hisaddr = lwip_htonl(0x0a404040); + ppp_warn("Could not determine remote IP address: defaulting to %I", + ho->hisaddr); + } +#if 0 /* UNUSED */ + script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); + if (ho->hisaddr != 0) + script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); +#endif /* UNUSED */ + +#if LWIP_DNS + if (!go->req_dns1) + go->dnsaddr[0] = 0; + if (!go->req_dns2) + go->dnsaddr[1] = 0; +#if 0 /* UNUSED */ + if (go->dnsaddr[0]) + script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); + if (go->dnsaddr[1]) + script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); +#endif /* UNUSED */ + if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { + sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); +#if 0 /* UNUSED */ + script_setenv("USEPEERDNS", "1", 0); + create_resolv(go->dnsaddr[0], go->dnsaddr[1]); +#endif /* UNUSED */ + } +#endif /* LWIP_DNS */ + + /* + * Check that the peer is allowed to use the IP address it wants. + */ + if (ho->hisaddr != 0) { + u32_t addr = lwip_ntohl(ho->hisaddr); + if ((addr >> IP_CLASSA_NSHIFT) == IP_LOOPBACKNET + || IP_MULTICAST(addr) || IP_BADCLASS(addr) + /* + * For now, consider that PPP in server mode with peer required + * to authenticate must provide the peer IP address, reject any + * IP address wanted by peer different than the one we wanted. + */ +#if PPP_SERVER && PPP_AUTH_SUPPORT + || (pcb->settings.auth_required && wo->hisaddr != ho->hisaddr) +#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ + ) { + ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ipcp_close(pcb, "Unauthorized remote IP address"); + return; + } + } +#if 0 /* Unused */ + /* Upstream checking code */ + if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { + ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ipcp_close(f->unit, "Unauthorized remote IP address"); + return; + } +#endif /* Unused */ + +#if VJ_SUPPORT + /* set tcp compression */ + sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex); +#endif /* VJ_SUPPORT */ + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, the interface is already + * configured, so we put out any saved-up packets, then set the + * interface to pass IP packets. + */ + if (demand) { + if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { + ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, + wo->replace_default_route); + if (go->ouraddr != wo->ouraddr) { + ppp_warn("Local IP address changed to %I", go->ouraddr); + script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); + wo->ouraddr = go->ouraddr; + } else + script_unsetenv("OLDIPLOCAL"); + if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { + ppp_warn("Remote IP address changed to %I", ho->hisaddr); + script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); + wo->hisaddr = ho->hisaddr; + } else + script_unsetenv("OLDIPREMOTE"); + + /* Set the interface to the new addresses */ + mask = get_mask(go->ouraddr); + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + + /* assign a default route through the interface if required */ + if (ipcp_wantoptions[f->unit].default_route) + if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) + default_route_set[f->unit] = 1; + +#if 0 /* UNUSED - PROXY ARP */ + /* Make a proxy ARP entry if requested. */ + if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp) + if (sifproxyarp(pcb, ho->hisaddr)) + proxy_arp_set[f->unit] = 1; +#endif /* UNUSED - PROXY ARP */ + + } + demand_rexmit(PPP_IP,go->ouraddr); + sifnpmode(pcb, PPP_IP, NPMODE_PASS); + + } else +#endif /* DEMAND_SUPPORT */ + { + /* + * Set IP addresses and (if specified) netmask. + */ + mask = get_mask(go->ouraddr); + +#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->pcb, "Interface configuration failed"); + return; + } +#endif + + /* bring the interface up for IP */ + if (!sifup(pcb)) { +#if PPP_DEBUG + ppp_warn("Interface failed to come up"); +#endif /* PPP_DEBUG */ + ipcp_close(f->pcb, "Interface configuration failed"); + return; + } + +#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->unit, "Interface configuration failed"); + return; + } +#endif +#if DEMAND_SUPPORT + sifnpmode(pcb, PPP_IP, NPMODE_PASS); +#endif /* DEMAND_SUPPORT */ + +#if 0 /* UNUSED */ + /* assign a default route through the interface if required */ + if (wo->default_route) + if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) + pcb->default_route_set = 1; +#endif /* UNUSED */ + +#if 0 /* UNUSED - PROXY ARP */ + /* Make a proxy ARP entry if requested. */ + if (ho->hisaddr != 0 && wo->proxy_arp) + if (sifproxyarp(pcb, ho->hisaddr)) + pcb->proxy_arp_set = 1; +#endif /* UNUSED - PROXY ARP */ + + wo->ouraddr = go->ouraddr; + + ppp_notice("local IP address %I", go->ouraddr); + if (ho->hisaddr != 0) + ppp_notice("remote IP address %I", ho->hisaddr); +#if LWIP_DNS + if (go->dnsaddr[0]) + ppp_notice("primary DNS address %I", go->dnsaddr[0]); + if (go->dnsaddr[1]) + ppp_notice("secondary DNS address %I", go->dnsaddr[1]); +#endif /* LWIP_DNS */ + } + +#if PPP_STATS_SUPPORT + reset_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ + + np_up(pcb, PPP_IP); + pcb->ipcp_is_up = 1; + +#if PPP_NOTIFY + notify(ip_up_notifier, 0); +#endif /* PPP_NOTIFY */ +#if 0 /* UNUSED */ + if (ip_up_hook) + ip_up_hook(); +#endif /* UNUSED */ +} + + +/* + * ipcp_down - IPCP has gone DOWN. + * + * Take the IP network interface down, clear its addresses + * and delete routes through it. + */ +static void ipcp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + + IPCPDEBUG(("ipcp: down")); +#if PPP_STATS_SUPPORT + /* XXX a bit IPv4-centric here, we only need to get the stats + * before the interface is marked down. */ + /* XXX more correct: we must get the stats before running the notifiers, + * at least for the radius plugin */ + update_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ +#if PPP_NOTIFY + notify(ip_down_notifier, 0); +#endif /* PPP_NOTIFY */ +#if 0 /* UNUSED */ + if (ip_down_hook) + ip_down_hook(); +#endif /* UNUSED */ + if (pcb->ipcp_is_up) { + pcb->ipcp_is_up = 0; + np_down(pcb, PPP_IP); + } +#if VJ_SUPPORT + sifvjcomp(pcb, 0, 0, 0); +#endif /* VJ_SUPPORT */ + +#if PPP_STATS_SUPPORT + print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), + * because print_link_stats() sets link_stats_valid + * to 0 (zero) */ +#endif /* PPP_STATS_SUPPORT */ + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, set the interface + * to queue up outgoing packets (for now). + */ + if (demand) { + sifnpmode(pcb, PPP_IP, NPMODE_QUEUE); + } else +#endif /* DEMAND_SUPPORT */ + { +#if DEMAND_SUPPORT + sifnpmode(pcb, PPP_IP, NPMODE_DROP); +#endif /* DEMAND_SUPPORT */ + sifdown(pcb); + ipcp_clear_addrs(pcb, go->ouraddr, + ho->hisaddr, 0); +#if LWIP_DNS + cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); +#endif /* LWIP_DNS */ + } +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, + * proxy arp entries, etc. + */ +static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) { + LWIP_UNUSED_ARG(replacedefaultroute); + +#if 0 /* UNUSED - PROXY ARP */ + if (pcb->proxy_arp_set) { + cifproxyarp(pcb, hisaddr); + pcb->proxy_arp_set = 0; + } +#endif /* UNUSED - PROXY ARP */ +#if 0 /* UNUSED */ + /* If replacedefaultroute, sifdefaultroute will be called soon + * with replacedefaultroute set and that will overwrite the current + * default route. This is the case only when doing demand, otherwise + * during demand, this cifdefaultroute would restore the old default + * route which is not what we want in this case. In the non-demand + * case, we'll delete the default route and restore the old if there + * is one saved by an sifdefaultroute with replacedefaultroute. + */ + if (!replacedefaultroute && pcb->default_route_set) { + cifdefaultroute(pcb, ouraddr, hisaddr); + pcb->default_route_set = 0; + } +#endif /* UNUSED */ + cifaddr(pcb, ouraddr, hisaddr); +} + + +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void ipcp_finished(fsm *f) { + ppp_pcb *pcb = f->pcb; + if (pcb->ipcp_is_open) { + pcb->ipcp_is_open = 0; + np_finished(pcb, PPP_IP); + } +} + + +#if 0 /* UNUSED */ +/* + * create_resolv - create the replacement resolv.conf file + */ +static void +create_resolv(peerdns1, peerdns2) + u32_t peerdns1, peerdns2; +{ + +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ipcp_printpkt - print the contents of an IPCP packet. + */ +static const char* const ipcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +static int ipcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, olen; + const u_char *pstart, *optend; +#if VJ_SUPPORT + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipcp_codenames)) + printer(arg, " %s", ipcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case CI_ADDRS: + if (olen == CILEN_ADDRS) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addrs %I", lwip_htonl(cilong)); + GETLONG(cilong, p); + printer(arg, " %I", lwip_htonl(cilong)); + } + break; +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (olen >= CILEN_COMPRESS) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "compress "); + switch (cishort) { + case IPCP_VJ_COMP: + printer(arg, "VJ"); + break; + case IPCP_VJ_COMP_OLD: + printer(arg, "old-VJ"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; +#endif /* VJ_SUPPORT */ + case CI_ADDR: + if (olen == CILEN_ADDR) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addr %I", lwip_htonl(cilong)); + } + break; +#if LWIP_DNS + case CI_MS_DNS1: + case CI_MS_DNS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2), + htonl(cilong)); + break; +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-wins %I", lwip_htonl(cilong)); + break; +#endif /* UNUSED - WINS */ + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * ip_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP_HDRLEN 20 /* bytes */ +#define IP_OFFMASK 0x1fff +#ifndef IPPROTO_TCP +#define IPPROTO_TCP 6 +#endif +#define TCP_HDRLEN 20 +#define TH_FIN 0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define net_short(x) (((x)[0] << 8) + (x)[1]) +#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) +#define get_ipoff(x) net_short((unsigned char *)(x) + 6) +#define get_ipproto(x) (((unsigned char *)(x))[9]) +#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int +ip_active_pkt(pkt, len) + u_char *pkt; + int len; +{ + u_char *tcp; + int hlen; + + len -= PPP_HDRLEN; + pkt += PPP_HDRLEN; + if (len < IP_HDRLEN) + return 0; + if ((get_ipoff(pkt) & IP_OFFMASK) != 0) + return 0; + if (get_ipproto(pkt) != IPPROTO_TCP) + return 1; + hlen = get_iphl(pkt) * 4; + if (len < hlen + TCP_HDRLEN) + return 0; + tcp = pkt + hlen; + if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) + return 0; + return 1; +} +#endif /* DEMAND_SUPPORT */ + +#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipv6cp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipv6cp.c new file mode 100644 index 0000000..11c18df --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ipv6cp.c @@ -0,0 +1,1533 @@ +/* + * ipv6cp.c - PPP IPV6 Control Protocol. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Original version, based on RFC2023 : + + Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt + Économique ayant pour membres BULL S.A. et l'INRIA). + + Ce logiciel informatique est disponible aux conditions + usuelles dans la recherche, c'est-à-dire qu'il peut + être utilisé, copié, modifié, distribué à l'unique + condition que ce texte soit conservé afin que + l'origine de ce logiciel soit reconnue. + + Le nom de l'Institut National de Recherche en Informatique + et en Automatique (INRIA), de l'IMAG, ou d'une personne morale + ou physique ayant participé à l'élaboration de ce logiciel ne peut + être utilisé sans son accord préalable explicite. + + Ce logiciel est fourni tel quel sans aucune garantie, + support ou responsabilité d'aucune sorte. + Ce logiciel est dérivé de sources d'origine + "University of California at Berkeley" et + "Digital Equipment Corporation" couvertes par des copyrights. + + L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) + est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National + Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant + sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + + This work has been done in the context of GIE DYADE (joint R & D venture + between BULL S.A. and INRIA). + + This software is available with usual "research" terms + with the aim of retain credits of the software. + Permission to use, copy, modify and distribute this software for any + purpose and without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies, + and the name of INRIA, IMAG, or any contributor not be used in advertising + or publicity pertaining to this material without the prior explicit + permission. The software is provided "as is" without any + warranties, support or liabilities of any kind. + This software is derived from source code from + "University of California at Berkeley" and + "Digital Equipment Corporation" protected by copyrights. + + Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) + is a federation of seven research units funded by the CNRS, National + Polytechnic Institute of Grenoble and University Joseph Fourier. + The research unit in Software, Systems, Networks (LSR) is member of IMAG. +*/ + +/* + * Derived from : + * + * + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ + */ + +/* + * @todo: + * + * Proxy Neighbour Discovery. + * + * Better defines for selecting the ordering of + * interface up / set address. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/ipv6cp.h" +#include "netif/ppp/magic.h" + +/* global vars */ +#if 0 /* UNUSED */ +int no_ifaceid_neg = 0; +#endif /* UNUSED */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipv6cp_resetci(fsm *f); /* Reset our CI */ +static int ipv6cp_cilen(fsm *f); /* Return length of our CI */ +static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ +static int ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ +static int ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ +static void ipv6cp_up(fsm *f); /* We're UP */ +static void ipv6cp_down(fsm *f); /* We're DOWN */ +static void ipv6cp_finished(fsm *f); /* Don't need lower layer */ + +static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ + ipv6cp_resetci, /* Reset our Configuration Information */ + ipv6cp_cilen, /* Length of our Configuration Information */ + ipv6cp_addci, /* Add our Configuration Information */ + ipv6cp_ackci, /* ACK our Configuration Information */ + ipv6cp_nakci, /* NAK our Configuration Information */ + ipv6cp_rejci, /* Reject our Configuration Information */ + ipv6cp_reqci, /* Request peer's Configuration Information */ + ipv6cp_up, /* Called when fsm reaches OPENED state */ + ipv6cp_down, /* Called when fsm leaves OPENED state */ + NULL, /* Called when we want the lower layer up */ + ipv6cp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPV6CP" /* String name of protocol */ +}; + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static int setifaceid(char **arg)); +static void printifaceid(option_t *, + void (*)(void *, char *, ...), void *)); + +static option_t ipv6cp_option_list[] = { + { "ipv6", o_special, (void *)setifaceid, + "Set interface identifiers for IPV6", + OPT_A2PRINTER, (void *)printifaceid }, + + { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, + { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, + { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, + + { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local, + "Accept peer's interface identifier for us", 1 }, + + { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, + "Use (default) IPv4 address as interface identifier", 1 }, + + { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, + "Use uniquely-available persistent value for link local address", 1 }, + + { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, + "Set timeout for IPv6CP", OPT_PRIO }, + { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, + "Set max #xmits for term-reqs", OPT_PRIO }, + { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, + "Set max #xmits for conf-reqs", OPT_PRIO }, + { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, + "Set max #conf-naks for IPv6CP", OPT_PRIO }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ipv6cp_init(ppp_pcb *pcb); +static void ipv6cp_open(ppp_pcb *pcb); +static void ipv6cp_close(ppp_pcb *pcb, const char *reason); +static void ipv6cp_lowerup(ppp_pcb *pcb); +static void ipv6cp_lowerdown(ppp_pcb *pcb); +static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len); +static void ipv6cp_protrej(ppp_pcb *pcb); +#if PPP_OPTIONS +static void ipv6_check_options(void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT +static int ipv6_demand_conf(int u); +#endif /* DEMAND_SUPPORT */ +#if PRINTPKT_SUPPORT +static int ipv6cp_printpkt(const u_char *p, int plen, + void (*printer)(void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if DEMAND_SUPPORT +static int ipv6_active_pkt(u_char *pkt, int len); +#endif /* DEMAND_SUPPORT */ + +const struct protent ipv6cp_protent = { + PPP_IPV6CP, + ipv6cp_init, + ipv6cp_input, + ipv6cp_protrej, + ipv6cp_lowerup, + ipv6cp_lowerdown, + ipv6cp_open, + ipv6cp_close, +#if PRINTPKT_SUPPORT + ipv6cp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "IPV6CP", + "IPV6", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ipv6cp_option_list, + ipv6_check_options, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + ipv6_demand_conf, + ipv6_active_pkt +#endif /* DEMAND_SUPPORT */ +}; + +static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid); +#if 0 /* UNUSED */ +static void ipv6cp_script(char *)); +static void ipv6cp_script_done(void *)); +#endif /* UNUSED */ + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID 2 +#define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ +#define CILEN_IFACEID 10 /* RFC2472, interface identifier */ + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED */ +/* + * This state variable is used to ensure that we don't + * run an ipcp-up/down script while one is already running. + */ +static enum script_state { + s_down, + s_up, +} ipv6cp_script_state; +static pid_t ipv6cp_script_pid; +#endif /* UNUSED */ + +static char *llv6_ntoa(eui64_t ifaceid); + +#if PPP_OPTIONS +/* + * setifaceid - set the interface identifiers manually + */ +static int +setifaceid(argv) + char **argv; +{ + char *comma, *arg, c; + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + struct in6_addr addr; + static int prio_local, prio_remote; + +#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ + (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) + + arg = *argv; + if ((comma = strchr(arg, ',')) == NULL) + comma = arg + strlen(arg); + + /* + * If comma first character, then no local identifier + */ + if (comma != arg) { + c = *comma; + *comma = '\0'; + + if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { + option_error("Illegal interface identifier (local): %s", arg); + return 0; + } + + if (option_priority >= prio_local) { + eui64_copy(addr.s6_addr32[2], wo->ourid); + wo->opt_local = 1; + prio_local = option_priority; + } + *comma = c; + } + + /* + * If comma last character, the no remote identifier + */ + if (*comma != 0 && *++comma != '\0') { + if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { + option_error("Illegal interface identifier (remote): %s", comma); + return 0; + } + if (option_priority >= prio_remote) { + eui64_copy(addr.s6_addr32[2], wo->hisid); + wo->opt_remote = 1; + prio_remote = option_priority; + } + } + + if (override_value("+ipv6", option_priority, option_source)) + ipv6cp_protent.enabled_flag = 1; + return 1; +} + +static void +printifaceid(opt, printer, arg) + option_t *opt; + void (*printer)(void *, char *, ...)); + void *arg; +{ + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + + if (wo->opt_local) + printer(arg, "%s", llv6_ntoa(wo->ourid)); + printer(arg, ","); + if (wo->opt_remote) + printer(arg, "%s", llv6_ntoa(wo->hisid)); +} +#endif /* PPP_OPTIONS */ + +/* + * Make a string representation of a network address. + */ +static char * +llv6_ntoa(eui64_t ifaceid) +{ + static char b[26]; + + sprintf(b, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ifaceid.e8[0], ifaceid.e8[1], ifaceid.e8[2], ifaceid.e8[3], + ifaceid.e8[4], ifaceid.e8[5], ifaceid.e8[6], ifaceid.e8[7]); + + return b; +} + + +/* + * ipv6cp_init - Initialize IPV6CP. + */ +static void ipv6cp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ipv6cp_fsm; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_IPV6CP; + f->callbacks = &ipv6cp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); +#endif /* 0 */ + + wo->accept_local = 1; + wo->neg_ifaceid = 1; + ao->neg_ifaceid = 1; + +#ifdef IPV6CP_COMP + wo->neg_vj = 1; + ao->neg_vj = 1; + wo->vj_protocol = IPV6CP_COMP; +#endif + +} + + +/* + * ipv6cp_open - IPV6CP is allowed to come up. + */ +static void ipv6cp_open(ppp_pcb *pcb) { + fsm_open(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_close - Take IPV6CP down. + */ +static void ipv6cp_close(ppp_pcb *pcb, const char *reason) { + fsm_close(&pcb->ipv6cp_fsm, reason); +} + + +/* + * ipv6cp_lowerup - The lower layer is up. + */ +static void ipv6cp_lowerup(ppp_pcb *pcb) { + fsm_lowerup(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_lowerdown - The lower layer is down. + */ +static void ipv6cp_lowerdown(ppp_pcb *pcb) { + fsm_lowerdown(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_input - Input IPV6CP packet. + */ +static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm_input(&pcb->ipv6cp_fsm, p, len); +} + + +/* + * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void ipv6cp_protrej(ppp_pcb *pcb) { + fsm_lowerdown(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_resetci - Reset our CI. + */ +static void ipv6cp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + + wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; + + if (!wo->opt_local) { + eui64_magic_nz(wo->ourid); + } + + *go = *wo; + eui64_zero(go->hisid); /* last proposed interface identifier */ +} + + +/* + * ipv6cp_cilen - Return length of our CI. + */ +static int ipv6cp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + +#ifdef IPV6CP_COMP +#define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) +#endif /* IPV6CP_COMP */ +#define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) + + return (LENCIIFACEID(go->neg_ifaceid) + +#ifdef IPV6CP_COMP + LENCIVJ(go->neg_vj) + +#endif /* IPV6CP_COMP */ + 0); +} + + +/* + * ipv6cp_addci - Add our desired CIs to a packet. + */ +static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + int len = *lenp; + +#ifdef IPV6CP_COMP +#define ADDCIVJ(opt, neg, val) \ + if (neg) { \ + int vjlen = CILEN_COMPRESS; \ + if (len >= vjlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(vjlen, ucp); \ + PUTSHORT(val, ucp); \ + len -= vjlen; \ + } else \ + neg = 0; \ + } +#endif /* IPV6CP_COMP */ + +#define ADDCIIFACEID(opt, neg, val1) \ + if (neg) { \ + int idlen = CILEN_IFACEID; \ + if (len >= idlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(idlen, ucp); \ + eui64_put(val1, ucp); \ + len -= idlen; \ + } else \ + neg = 0; \ + } + + ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + *lenp -= len; +} + + +/* + * ipv6cp_ackci - Ack our CIs. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int ipv6cp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_short cilen, citype; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + + /* + * CIs must be in exactly the same order that we sent... + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ + +#ifdef IPV6CP_COMP +#define ACKCIVJ(opt, neg, val) \ + if (neg) { \ + int vjlen = CILEN_COMPRESS; \ + if ((len -= vjlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != vjlen || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + } +#endif /* IPV6CP_COMP */ + +#define ACKCIIFACEID(opt, neg, val1) \ + if (neg) { \ + int idlen = CILEN_IFACEID; \ + if ((len -= idlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != idlen || \ + citype != opt) \ + goto bad; \ + eui64_get(ifaceid, p); \ + if (! eui64_equals(val1, ifaceid)) \ + goto bad; \ + } + + ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); + +bad: + IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); + return (0); +} + +/* + * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPV6CP is in the OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char citype, cilen, *next; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + ipv6cp_options no; /* options we've seen Naks for */ + ipv6cp_options try_; /* options to request next time */ + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIIFACEID(opt, neg, code) \ + if (go->neg && \ + len >= (cilen = CILEN_IFACEID) && \ + p[1] == cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + eui64_get(ifaceid, p); \ + no.neg = 1; \ + code \ + } + +#ifdef IPV6CP_COMP +#define NAKCIVJ(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_COMPRESS) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#endif /* IPV6CP_COMP */ + + /* + * Accept the peer's idea of {our,his} interface identifier, if different + * from our idea, only if the accept_{local,remote} flag is set. + */ + NAKCIIFACEID(CI_IFACEID, neg_ifaceid, + if (treat_as_reject) { + try_.neg_ifaceid = 0; + } else if (go->accept_local) { + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->hisid)) /* bad luck */ + eui64_magic(ifaceid); + try_.ourid = ifaceid; + IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); + } + ); + +#ifdef IPV6CP_COMP + NAKCIVJ(CI_COMPRESSTYPE, neg_vj, + { + if (cishort == IPV6CP_COMP && !treat_as_reject) { + try_.vj_protocol = cishort; + } else { + try_.neg_vj = 0; + } + } + ); +#endif /* IPV6CP_COMP */ + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If they want to negotiate about interface identifier, we comply. + * If they want us to ask for compression, we refuse. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) + goto bad; + next = p + cilen - 2; + + switch (citype) { +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + if (go->neg_vj || no.neg_vj || + (cilen != CILEN_COMPRESS)) + goto bad; + no.neg_vj = 1; + break; +#endif /* IPV6CP_COMP */ + case CI_IFACEID: + if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) + goto bad; + try_.neg_ifaceid = 1; + eui64_get(ifaceid, p); + if (go->accept_local) { + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->hisid)) /* bad luck */ + eui64_magic(ifaceid); + try_.ourid = ifaceid; + } + no.neg_ifaceid = 1; + break; + default: + break; + } + p = next; + } + + /* If there is still anything left, this packet is bad. */ + if (len != 0) + goto bad; + + /* + * OK, the Nak is good. Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; + +bad: + IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); + return 0; +} + + +/* + * ipv6cp_rejci - Reject some of our CIs. + */ +static int ipv6cp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char cilen; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + ipv6cp_options try_; /* options to request next time */ + + try_ = *go; + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIIFACEID(opt, neg, val1) \ + if (go->neg && \ + len >= (cilen = CILEN_IFACEID) && \ + p[1] == cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + eui64_get(ifaceid, p); \ + /* Check rejected value. */ \ + if (! eui64_equals(ifaceid, val1)) \ + goto bad; \ + try_.neg = 0; \ + } + +#ifdef IPV6CP_COMP +#define REJCIVJ(opt, neg, val) \ + if (go->neg && \ + p[1] == CILEN_COMPRESS && \ + len >= p[1] && \ + p[0] == opt) { \ + len -= p[1]; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* IPV6CP_COMP */ + + REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); + return 0; +} + + +/* + * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * len = Length of requested CIs + * + */ +static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ +#ifdef IPV6CP_COMP + u_short cishort; /* Parsed short value */ +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; /* Parsed interface identifier */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *ucp = inp; /* Pointer to current output char */ + int l = *len; /* Length left */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_IFACEID: + IPV6CPDEBUG(("ipv6cp: received interface identifier ")); + + if (!ao->neg_ifaceid || + cilen != CILEN_IFACEID) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no interface identifier, or if we both have same + * identifier then NAK it with new idea. + * In particular, if we don't know his identifier, but he does, + * then accept it. + */ + eui64_get(ifaceid, p); + IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); + if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { + orc = CONFREJ; /* Reject CI */ + break; + } + if (!eui64_iszero(wo->hisid) && + !eui64_equals(ifaceid, wo->hisid) && + eui64_iszero(go->hisid)) { + + orc = CONFNAK; + ifaceid = wo->hisid; + go->hisid = ifaceid; + DECPTR(sizeof(ifaceid), p); + eui64_put(ifaceid, p); + } else + if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { + orc = CONFNAK; + if (eui64_iszero(go->hisid)) /* first time, try option */ + ifaceid = wo->hisid; + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->ourid)) /* bad luck */ + eui64_magic(ifaceid); + go->hisid = ifaceid; + DECPTR(sizeof(ifaceid), p); + eui64_put(ifaceid, p); + } + + ho->neg_ifaceid = 1; + ho->hisid = ifaceid; + break; + +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); + if (!ao->neg_vj || + (cilen != CILEN_COMPRESS)) { + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + IPV6CPDEBUG(("(%d)", cishort)); + + if (!(cishort == IPV6CP_COMP)) { + orc = CONFREJ; + break; + } + + ho->neg_vj = 1; + ho->vj_protocol = cishort; + break; +#endif /* IPV6CP_COMP */ + + default: + orc = CONFREJ; + break; + } + +endswitch: + IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); + + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree) /* Getting fed up with sending NAKs? */ + orc = CONFREJ; /* Get tough if so */ + else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + if (rc == CONFACK) { /* Ack'd all prior CIs? */ + rc = CONFNAK; /* Not anymore... */ + ucp = inp; /* Backup */ + } + } + } + + if (orc == CONFREJ && /* Reject this CI */ + rc != CONFREJ) { /* but no prior ones? */ + rc = CONFREJ; + ucp = inp; /* Backup */ + } + + /* Need to move CI? */ + if (ucp != cip) + MEMCPY(ucp, cip, cilen); /* Move it */ + + /* Update output pointer */ + INCPTR(cilen, ucp); + } + + /* + * If we aren't rejecting this packet, and we want to negotiate + * their identifier and they didn't send their identifier, then we + * send a NAK with a CI_IFACEID option appended. We assume the + * input buffer is long enough that we can append the extra + * option safely. + */ + if (rc != CONFREJ && !ho->neg_ifaceid && + wo->req_ifaceid && !reject_if_disagree) { + if (rc == CONFACK) { + rc = CONFNAK; + ucp = inp; /* reset pointer */ + wo->req_ifaceid = 0; /* don't ask again */ + } + PUTCHAR(CI_IFACEID, ucp); + PUTCHAR(CILEN_IFACEID, ucp); + eui64_put(wo->hisid, ucp); + } + + *len = ucp - inp; /* Compute output length */ + IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); + return (rc); /* Return final code */ +} + +#if PPP_OPTIONS +/* + * ipv6_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void ipv6_check_options() { + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + + if (!ipv6cp_protent.enabled_flag) + return; + + /* + * Persistent link-local id is only used when user has not explicitly + * configure/hard-code the id + */ + if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { + + /* + * On systems where there are no Ethernet interfaces used, there + * may be other ways to obtain a persistent id. Right now, it + * will fall back to using magic [see eui64_magic] below when + * an EUI-48 from MAC address can't be obtained. Other possibilities + * include obtaining EEPROM serial numbers, or some other unique + * yet persistent number. On Sparc platforms, this is possible, + * but too bad there's no standards yet for x86 machines. + */ + if (ether_to_eui64(&wo->ourid)) { + wo->opt_local = 1; + } + } + + if (!wo->opt_local) { /* init interface identifier */ + if (wo->use_ip && eui64_iszero(wo->ourid)) { + eui64_setlo32(wo->ourid, lwip_ntohl(ipcp_wantoptions[0].ouraddr)); + if (!eui64_iszero(wo->ourid)) + wo->opt_local = 1; + } + + while (eui64_iszero(wo->ourid)) + eui64_magic(wo->ourid); + } + + if (!wo->opt_remote) { + if (wo->use_ip && eui64_iszero(wo->hisid)) { + eui64_setlo32(wo->hisid, lwip_ntohl(ipcp_wantoptions[0].hisaddr)); + if (!eui64_iszero(wo->hisid)) + wo->opt_remote = 1; + } + } + + if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { + option_error("local/remote LL address required for demand-dialling\n"); + exit(1); + } +} +#endif /* PPP_OPTIONS */ + +#if DEMAND_SUPPORT +/* + * ipv6_demand_conf - configure the interface as though + * IPV6CP were up, for use with dial-on-demand. + */ +static int ipv6_demand_conf(int u) { + ipv6cp_options *wo = &ipv6cp_wantoptions[u]; + + if (!sif6up(u)) + return 0; + + if (!sif6addr(u, wo->ourid, wo->hisid)) + return 0; + + if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) + return 0; + + ppp_notice("ipv6_demand_conf"); + ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); + ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); + + return 1; +} +#endif /* DEMAND_SUPPORT */ + + +/* + * ipv6cp_up - IPV6CP has come UP. + * + * Configure the IPv6 network interface appropriately and bring it up. + */ +static void ipv6cp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + + IPV6CPDEBUG(("ipv6cp: up")); + + /* + * We must have a non-zero LL address for both ends of the link. + */ + if (!ho->neg_ifaceid) + ho->hisid = wo->hisid; + +#if 0 /* UNUSED */ + if(!no_ifaceid_neg) { +#endif /* UNUSED */ + if (eui64_iszero(ho->hisid)) { + ppp_error("Could not determine remote LL address"); + ipv6cp_close(f->pcb, "Could not determine remote LL address"); + return; + } + if (eui64_iszero(go->ourid)) { + ppp_error("Could not determine local LL address"); + ipv6cp_close(f->pcb, "Could not determine local LL address"); + return; + } + if (eui64_equals(go->ourid, ho->hisid)) { + ppp_error("local and remote LL addresses are equal"); + ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); + return; + } +#if 0 /* UNUSED */ + } +#endif /* UNUSED */ +#if 0 /* UNUSED */ + script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); + script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); +#endif /* UNUSED */ + +#ifdef IPV6CP_COMP + /* set tcp compression */ + sif6comp(f->unit, ho->neg_vj); +#endif + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, the interface is already + * configured, so we put out any saved-up packets, then set the + * interface to pass IPv6 packets. + */ + if (demand) { + if (! eui64_equals(go->ourid, wo->ourid) || + ! eui64_equals(ho->hisid, wo->hisid)) { + if (! eui64_equals(go->ourid, wo->ourid)) + warn("Local LL address changed to %s", + llv6_ntoa(go->ourid)); + if (! eui64_equals(ho->hisid, wo->hisid)) + warn("Remote LL address changed to %s", + llv6_ntoa(ho->hisid)); + ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); + + /* Set the interface to the new addresses */ + if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { + if (debug) + warn("sif6addr failed"); + ipv6cp_close(f->unit, "Interface configuration failed"); + return; + } + + } + demand_rexmit(PPP_IPV6); + sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); + + } else +#endif /* DEMAND_SUPPORT */ + { + /* + * Set LL addresses + */ + if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { + PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); + ipv6cp_close(f->pcb, "Interface configuration failed"); + return; + } + + /* bring the interface up for IPv6 */ + if (!sif6up(f->pcb)) { + PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)")); + ipv6cp_close(f->pcb, "Interface configuration failed"); + return; + } +#if DEMAND_SUPPORT + sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); +#endif /* DEMAND_SUPPORT */ + + ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); + ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); + } + + np_up(f->pcb, PPP_IPV6); + pcb->ipv6cp_is_up = 1; + +#if 0 /* UNUSED */ + /* + * Execute the ipv6-up script, like this: + * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL + */ + if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { + ipv6cp_script_state = s_up; + ipv6cp_script(_PATH_IPV6UP); + } +#endif /* UNUSED */ +} + + +/* + * ipv6cp_down - IPV6CP has gone DOWN. + * + * Take the IPv6 network interface down, clear its addresses + * and delete routes through it. + */ +static void ipv6cp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + + IPV6CPDEBUG(("ipv6cp: down")); +#if PPP_STATS_SUPPORT + update_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ + if (pcb->ipv6cp_is_up) { + pcb->ipv6cp_is_up = 0; + np_down(f->pcb, PPP_IPV6); + } +#ifdef IPV6CP_COMP + sif6comp(f->unit, 0); +#endif + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, set the interface + * to queue up outgoing packets (for now). + */ + if (demand) { + sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); + } else +#endif /* DEMAND_SUPPORT */ + { +#if DEMAND_SUPPORT + sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); +#endif /* DEMAND_SUPPORT */ + ipv6cp_clear_addrs(f->pcb, + go->ourid, + ho->hisid); + sif6down(f->pcb); + } + +#if 0 /* UNUSED */ + /* Execute the ipv6-down script */ + if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { + ipv6cp_script_state = s_down; + ipv6cp_script(_PATH_IPV6DOWN); + } +#endif /* UNUSED */ +} + + +/* + * ipv6cp_clear_addrs() - clear the interface addresses, routes, + * proxy neighbour discovery entries, etc. + */ +static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { + cif6addr(pcb, ourid, hisid); +} + + +/* + * ipv6cp_finished - possibly shut down the lower layers. + */ +static void ipv6cp_finished(fsm *f) { + np_finished(f->pcb, PPP_IPV6); +} + + +#if 0 /* UNUSED */ +/* + * ipv6cp_script_done - called when the ipv6-up or ipv6-down script + * has finished. + */ +static void +ipv6cp_script_done(arg) + void *arg; +{ + ipv6cp_script_pid = 0; + switch (ipv6cp_script_state) { + case s_up: + if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { + ipv6cp_script_state = s_down; + ipv6cp_script(_PATH_IPV6DOWN); + } + break; + case s_down: + if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { + ipv6cp_script_state = s_up; + ipv6cp_script(_PATH_IPV6UP); + } + break; + } +} + + +/* + * ipv6cp_script - Execute a script with arguments + * interface-name tty-name speed local-LL remote-LL. + */ +static void +ipv6cp_script(script) + char *script; +{ + char strspeed[32], strlocal[32], strremote[32]; + char *argv[8]; + + sprintf(strspeed, "%d", baud_rate); + strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); + strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); + + argv[0] = script; + argv[1] = ifname; + argv[2] = devnam; + argv[3] = strspeed; + argv[4] = strlocal; + argv[5] = strremote; + argv[6] = ipparam; + argv[7] = NULL; + + ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, + NULL, 0); +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ipv6cp_printpkt - print the contents of an IPV6CP packet. + */ +static const char* const ipv6cp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +static int ipv6cp_printpkt(const u_char *p, int plen, + void (*printer)(void *, const char *, ...), void *arg) { + int code, id, len, olen; + const u_char *pstart, *optend; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames)) + printer(arg, " %s", ipv6cp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + if (olen >= CILEN_COMPRESS) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "compress "); + printer(arg, "0x%x", cishort); + } + break; +#endif /* IPV6CP_COMP */ + case CI_IFACEID: + if (olen == CILEN_IFACEID) { + p += 2; + eui64_get(ifaceid, p); + printer(arg, "addr %s", llv6_ntoa(ifaceid)); + } + break; + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP6_HDRLEN 40 /* bytes */ +#define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ +#define TCP_HDRLEN 20 +#define TH_FIN 0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define get_ip6nh(x) (((unsigned char *)(x))[6]) +#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int ipv6_active_pkt(u_char *pkt, int len) { + u_char *tcp; + + len -= PPP_HDRLEN; + pkt += PPP_HDRLEN; + if (len < IP6_HDRLEN) + return 0; + if (get_ip6nh(pkt) == IP6_NHDR_FRAG) + return 0; + if (get_ip6nh(pkt) != IPPROTO_TCP) + return 1; + if (len < IP6_HDRLEN + TCP_HDRLEN) + return 0; + tcp = pkt + IP6_HDRLEN; + if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) + return 0; + return 1; +} +#endif /* DEMAND_SUPPORT */ + +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/lcp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/lcp.c new file mode 100644 index 0000000..90ed183 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/lcp.c @@ -0,0 +1,2790 @@ +/* + * lcp.c - PPP Link Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#include "netif/ppp/magic.h" + +/* + * When the link comes up we want to be able to wait for a short while, + * or until seeing some input from the peer, before starting to send + * configure-requests. We do this by delaying the fsm_lowerup call. + */ +/* steal a bit in fsm flags word */ +#define DELAYED_UP 0x80 + +static void lcp_delayed_up(void *arg); + +/* + * LCP-related command-line options. + */ +#if 0 /* UNUSED */ +int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ +int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* options */ +static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ +static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +#if PPP_LCP_ADAPTIVE +bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ +#endif +bool lax_recv = 0; /* accept control chars in asyncmap */ +bool noendpoint = 0; /* don't send/accept endpoint discriminator */ +#endif /* UNUSED */ + +#if PPP_OPTIONS +static int noopt (char **); +#endif /* PPP_OPTIONS */ + +#ifdef HAVE_MULTILINK +static int setendpoint (char **); +static void printendpoint (option_t *, void (*)(void *, char *, ...), + void *); +#endif /* HAVE_MULTILINK */ + +#if PPP_OPTIONS +static option_t lcp_option_list[] = { + /* LCP options */ + { "-all", o_special_noarg, (void *)noopt, + "Don't request/allow any LCP options" }, + + { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression, + "Disable address/control compression", + OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, + { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression, + "Disable address/control compression", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, + + { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, + "Set asyncmap (for received packets)", + OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, + { "-as", o_uint32, &lcp_wantoptions[0].asyncmap, + "Set asyncmap (for received packets)", + OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, + { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, + "Disable asyncmap negotiation", + OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, + &lcp_allowoptions[0].neg_asyncmap }, + { "-am", o_uint32, &lcp_wantoptions[0].asyncmap, + "Disable asyncmap negotiation", + OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, + &lcp_allowoptions[0].neg_asyncmap }, + + { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber, + "Disable magic number negotiation (looped-back line detection)", + OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, + { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber, + "Disable magic number negotiation (looped-back line detection)", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, + + { "mru", o_int, &lcp_wantoptions[0].mru, + "Set MRU (maximum received packet size) for negotiation", + OPT_PRIO, &lcp_wantoptions[0].neg_mru }, + { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru, + "Disable MRU negotiation (use default 1500)", + OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, + { "-mru", o_bool, &lcp_wantoptions[0].neg_mru, + "Disable MRU negotiation (use default 1500)", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, + + { "mtu", o_int, &lcp_allowoptions[0].mru, + "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, + + { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression, + "Disable protocol field compression", + OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, + { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression, + "Disable protocol field compression", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, + + { "passive", o_bool, &lcp_wantoptions[0].passive, + "Set passive mode", 1 }, + { "-p", o_bool, &lcp_wantoptions[0].passive, + "Set passive mode", OPT_ALIAS | 1 }, + + { "silent", o_bool, &lcp_wantoptions[0].silent, + "Set silent mode", 1 }, + + { "lcp-echo-failure", o_int, &lcp_echo_fails, + "Set number of consecutive echo failures to indicate link failure", + OPT_PRIO }, + { "lcp-echo-interval", o_int, &lcp_echo_interval, + "Set time in seconds between LCP echo requests", OPT_PRIO }, +#if PPP_LCP_ADAPTIVE + { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, + "Suppress LCP echo requests if traffic was received", 1 }, +#endif + { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, + "Set time in seconds between LCP retransmissions", OPT_PRIO }, + { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, + "Set maximum number of LCP terminate-request transmissions", OPT_PRIO }, + { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits, + "Set maximum number of LCP configure-request transmissions", OPT_PRIO }, + { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops, + "Set limit on number of LCP configure-naks", OPT_PRIO }, + + { "receive-all", o_bool, &lax_recv, + "Accept all received control characters", 1 }, + +#ifdef HAVE_MULTILINK + { "mrru", o_int, &lcp_wantoptions[0].mrru, + "Maximum received packet size for multilink bundle", + OPT_PRIO, &lcp_wantoptions[0].neg_mrru }, + + { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Use short sequence numbers in multilink headers", + OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf }, + { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Don't use short sequence numbers in multilink headers", + OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf }, + + { "endpoint", o_special, (void *) setendpoint, + "Endpoint discriminator for multilink", + OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint }, +#endif /* HAVE_MULTILINK */ + + { "noendpoint", o_bool, &noendpoint, + "Don't send or accept multilink endpoint discriminator", 1 }, + + {NULL} +}; +#endif /* PPP_OPTIONS */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void lcp_resetci(fsm *f); /* Reset our CI */ +static int lcp_cilen(fsm *f); /* Return length of our CI */ +static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */ +static int lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ +static int lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */ +static void lcp_up(fsm *f); /* We're UP */ +static void lcp_down(fsm *f); /* We're DOWN */ +static void lcp_starting (fsm *); /* We need lower layer up */ +static void lcp_finished (fsm *); /* We need lower layer down */ +static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len); +static void lcp_rprotrej(fsm *f, u_char *inp, int len); + +/* + * routines to send LCP echos to peer + */ + +static void lcp_echo_lowerup(ppp_pcb *pcb); +static void lcp_echo_lowerdown(ppp_pcb *pcb); +static void LcpEchoTimeout(void *arg); +static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len); +static void LcpSendEchoRequest(fsm *f); +static void LcpLinkFailure(fsm *f); +static void LcpEchoCheck(fsm *f); + +static const fsm_callbacks lcp_callbacks = { /* LCP callback routines */ + lcp_resetci, /* Reset our Configuration Information */ + lcp_cilen, /* Length of our Configuration Information */ + lcp_addci, /* Add our Configuration Information */ + lcp_ackci, /* ACK our Configuration Information */ + lcp_nakci, /* NAK our Configuration Information */ + lcp_rejci, /* Reject our Configuration Information */ + lcp_reqci, /* Request peer's Configuration Information */ + lcp_up, /* Called when fsm reaches OPENED state */ + lcp_down, /* Called when fsm leaves OPENED state */ + lcp_starting, /* Called when we want the lower layer up */ + lcp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + lcp_extcode, /* Called to handle LCP-specific codes */ + "LCP" /* String name of protocol */ +}; + +/* + * Protocol entry points. + * Some of these are called directly. + */ + +static void lcp_init(ppp_pcb *pcb); +static void lcp_input(ppp_pcb *pcb, u_char *p, int len); +static void lcp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int lcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent lcp_protent = { + PPP_LCP, + lcp_init, + lcp_input, + lcp_protrej, + lcp_lowerup, + lcp_lowerdown, + lcp_open, + lcp_close, +#if PRINTPKT_SUPPORT + lcp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "LCP", + NULL, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + lcp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID 2 +#define CILEN_CHAR 3 +#define CILEN_SHORT 4 /* CILEN_VOID + 2 */ +#if CHAP_SUPPORT +#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */ +#endif /* CHAP_SUPPORT */ +#define CILEN_LONG 6 /* CILEN_VOID + 4 */ +#if LQR_SUPPORT +#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */ +#endif /* LQR_SUPPORT */ +#define CILEN_CBCP 3 + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if PPP_OPTIONS +/* + * noopt - Disable all options (why?). + */ +static int +noopt(argv) + char **argv; +{ + BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); + BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); + + return (1); +} +#endif /* PPP_OPTIONS */ + +#ifdef HAVE_MULTILINK +static int +setendpoint(argv) + char **argv; +{ + if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) { + lcp_wantoptions[0].neg_endpoint = 1; + return 1; + } + option_error("Can't parse '%s' as an endpoint discriminator", *argv); + return 0; +} + +static void +printendpoint(opt, printer, arg) + option_t *opt; + void (*printer) (void *, char *, ...); + void *arg; +{ + printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint)); +} +#endif /* HAVE_MULTILINK */ + +/* + * lcp_init - Initialize LCP. + */ +static void lcp_init(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_LCP; + f->callbacks = &lcp_callbacks; + + fsm_init(f); + + BZERO(wo, sizeof(*wo)); + wo->neg_mru = 1; + wo->mru = PPP_DEFMRU; + wo->neg_asyncmap = 1; + wo->neg_magicnumber = 1; + wo->neg_pcompression = 1; + wo->neg_accompression = 1; + + BZERO(ao, sizeof(*ao)); + ao->neg_mru = 1; + ao->mru = PPP_MAXMRU; + ao->neg_asyncmap = 1; +#if CHAP_SUPPORT + ao->neg_chap = 1; + ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + ao->neg_upap = 1; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + ao->neg_eap = 1; +#endif /* EAP_SUPPORT */ + ao->neg_magicnumber = 1; + ao->neg_pcompression = 1; + ao->neg_accompression = 1; + ao->neg_endpoint = 1; +} + + +/* + * lcp_open - LCP is allowed to come up. + */ +void lcp_open(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + lcp_options *wo = &pcb->lcp_wantoptions; + + f->flags &= ~(OPT_PASSIVE | OPT_SILENT); + if (wo->passive) + f->flags |= OPT_PASSIVE; + if (wo->silent) + f->flags |= OPT_SILENT; + fsm_open(f); +} + + +/* + * lcp_close - Take LCP down. + */ +void lcp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->lcp_fsm; + int oldstate; + + if (pcb->phase != PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + && pcb->phase != PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + new_phase(pcb, PPP_PHASE_TERMINATE); + + if (f->flags & DELAYED_UP) { + UNTIMEOUT(lcp_delayed_up, f); + f->state = PPP_FSM_STOPPED; + } + oldstate = f->state; + + fsm_close(f, reason); + if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) { + /* + * This action is not strictly according to the FSM in RFC1548, + * but it does mean that the program terminates if you do a + * lcp_close() when a connection hasn't been established + * because we are in passive/silent mode or because we have + * delayed the fsm_lowerup() call and it hasn't happened yet. + */ + f->flags &= ~DELAYED_UP; + lcp_finished(f); + } +} + + +/* + * lcp_lowerup - The lower layer is up. + */ +void lcp_lowerup(ppp_pcb *pcb) { + lcp_options *wo = &pcb->lcp_wantoptions; + fsm *f = &pcb->lcp_fsm; + /* + * Don't use A/C or protocol compression on transmission, + * but accept A/C and protocol compressed packets + * if we are going to ask for A/C and protocol compression. + */ + if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff), + wo->neg_pcompression, wo->neg_accompression) < 0) + return; + pcb->peer_mru = PPP_MRU; + + if (pcb->settings.listen_time != 0) { + f->flags |= DELAYED_UP; + TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time); + } else + fsm_lowerup(f); +} + + +/* + * lcp_lowerdown - The lower layer is down. + */ +void lcp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + UNTIMEOUT(lcp_delayed_up, f); + } else + fsm_lowerdown(f); +} + + +/* + * lcp_delayed_up - Bring the lower layer up now. + */ +static void lcp_delayed_up(void *arg) { + fsm *f = (fsm*)arg; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + fsm_lowerup(f); + } +} + + +/* + * lcp_input - Input LCP packet. + */ +static void lcp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->lcp_fsm; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + UNTIMEOUT(lcp_delayed_up, f); + fsm_lowerup(f); + } + fsm_input(f, p, len); +} + +/* + * lcp_extcode - Handle a LCP-specific code. + */ +static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char *magp; + + switch( code ){ + case PROTREJ: + lcp_rprotrej(f, inp, len); + break; + + case ECHOREQ: + if (f->state != PPP_FSM_OPENED) + break; + magp = inp; + PUTLONG(go->magicnumber, magp); + fsm_sdata(f, ECHOREP, id, inp, len); + break; + + case ECHOREP: + lcp_received_echo_reply(f, id, inp, len); + break; + + case DISCREQ: + case IDENTIF: + case TIMEREM: + break; + + default: + return 0; + } + return 1; +} + + +/* + * lcp_rprotrej - Receive an Protocol-Reject. + * + * Figure out which protocol is rejected and inform it. + */ +static void lcp_rprotrej(fsm *f, u_char *inp, int len) { + int i; + const struct protent *protp; + u_short prot; +#if PPP_PROTOCOLNAME + const char *pname; +#endif /* PPP_PROTOCOLNAME */ + + if (len < 2) { + LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); + return; + } + + GETSHORT(prot, inp); + + /* + * Protocol-Reject packets received in any state other than the LCP + * OPENED state SHOULD be silently discarded. + */ + if( f->state != PPP_FSM_OPENED ){ + LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state)); + return; + } + +#if PPP_PROTOCOLNAME + pname = protocol_name(prot); +#endif /* PPP_PROTOCOLNAME */ + + /* + * Upcall the proper Protocol-Reject routine. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol == prot) { +#if PPP_PROTOCOLNAME + if (pname != NULL) + ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname, + prot); + else +#endif /* PPP_PROTOCOLNAME */ + ppp_dbglog("Protocol-Reject for 0x%x received", prot); + (*protp->protrej)(f->pcb); + return; + } + +#if PPP_PROTOCOLNAME + if (pname != NULL) + ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, + prot); + else +#endif /* #if PPP_PROTOCOLNAME */ + ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot); +} + + +/* + * lcp_protrej - A Protocol-Reject was received. + */ +/*ARGSUSED*/ +static void lcp_protrej(ppp_pcb *pcb) { + /* + * Can't reject LCP! + */ + ppp_error("Received Protocol-Reject for LCP!"); + fsm_protreject(&pcb->lcp_fsm); +} + + +/* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->lcp_fsm; + /* + * Send back the protocol and the information field of the + * rejected packet. We only get here if LCP is in the OPENED state. + */ +#if 0 + p += 2; + len -= 2; +#endif + + fsm_sdata(f, PROTREJ, ++f->id, + p, len); +} + + +/* + * lcp_resetci - Reset our CI. + */ +static void lcp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + +#if PPP_AUTH_SUPPORT + + /* note: default value is true for allow options */ + if (pcb->settings.user && pcb->settings.passwd) { +#if PAP_SUPPORT + if (pcb->settings.refuse_pap) { + ao->neg_upap = 0; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (pcb->settings.refuse_chap) { + ao->chap_mdtype &= ~MDTYPE_MD5; + } +#if MSCHAP_SUPPORT + if (pcb->settings.refuse_mschap) { + ao->chap_mdtype &= ~MDTYPE_MICROSOFT; + } + if (pcb->settings.refuse_mschap_v2) { + ao->chap_mdtype &= ~MDTYPE_MICROSOFT_V2; + } +#endif /* MSCHAP_SUPPORT */ + ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (pcb->settings.refuse_eap) { + ao->neg_eap = 0; + } +#endif /* EAP_SUPPORT */ + +#if PPP_SERVER + /* note: default value is false for wanted options */ + if (pcb->settings.auth_required) { +#if PAP_SUPPORT + if (!pcb->settings.refuse_pap) { + wo->neg_upap = 1; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (!pcb->settings.refuse_chap) { + wo->chap_mdtype |= MDTYPE_MD5; + } +#if MSCHAP_SUPPORT + if (!pcb->settings.refuse_mschap) { + wo->chap_mdtype |= MDTYPE_MICROSOFT; + } + if (!pcb->settings.refuse_mschap_v2) { + wo->chap_mdtype |= MDTYPE_MICROSOFT_V2; + } +#endif /* MSCHAP_SUPPORT */ + wo->neg_chap = (wo->chap_mdtype != MDTYPE_NONE); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (!pcb->settings.refuse_eap) { + wo->neg_eap = 1; + } +#endif /* EAP_SUPPORT */ + } +#endif /* PPP_SERVER */ + + } else { +#if PAP_SUPPORT + ao->neg_upap = 0; +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + ao->neg_chap = 0; + ao->chap_mdtype = MDTYPE_NONE; +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + ao->neg_eap = 0; +#endif /* EAP_SUPPORT */ + } + + PPPDEBUG(LOG_DEBUG, ("ppp: auth protocols:")); +#if PAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" PAP=%d", ao->neg_upap)); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" CHAP=%d CHAP_MD5=%d", ao->neg_chap, !!(ao->chap_mdtype&MDTYPE_MD5))); +#if MSCHAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" CHAP_MS=%d CHAP_MS2=%d", !!(ao->chap_mdtype&MDTYPE_MICROSOFT), !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2))); +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" EAP=%d", ao->neg_eap)); +#endif /* EAP_SUPPORT */ + PPPDEBUG(LOG_DEBUG, ("\n")); + +#endif /* PPP_AUTH_SUPPORT */ + + wo->magicnumber = magic(); + wo->numloops = 0; + *go = *wo; +#ifdef HAVE_MULTILINK + if (!multilink) { + go->neg_mrru = 0; +#endif /* HAVE_MULTILINK */ + go->neg_ssnhf = 0; + go->neg_endpoint = 0; +#ifdef HAVE_MULTILINK + } +#endif /* HAVE_MULTILINK */ + if (pcb->settings.noendpoint) + ao->neg_endpoint = 0; + pcb->peer_mru = PPP_MRU; +#if 0 /* UNUSED */ + auth_reset(pcb); +#endif /* UNUSED */ +} + + +/* + * lcp_cilen - Return length of our CI. + */ +static int lcp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + +#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) +#if CHAP_SUPPORT +#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) +#endif /* CHAP_SUPPORT */ +#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) +#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) +#if LQR_SUPPORT +#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) +#endif /* LQR_SUPPORT */ +#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) + /* + * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will + * accept more than one. We prefer EAP first, then CHAP, then + * PAP. + */ + return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + + LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + +#if EAP_SUPPORT + LENCISHORT(go->neg_eap) + +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + LENCICHAP(!go->neg_eap && go->neg_chap) + +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + LENCICHAP(go->neg_chap) + +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) + +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + LENCISHORT(!go->neg_eap && go->neg_upap) + +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + LENCISHORT(!go->neg_chap && go->neg_upap) + +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + LENCISHORT(go->neg_upap) + +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + LENCILQR(go->neg_lqr) + +#endif /* LQR_SUPPORT */ + LENCICBCP(go->neg_cbcp) + + LENCILONG(go->neg_magicnumber) + + LENCIVOID(go->neg_pcompression) + + LENCIVOID(go->neg_accompression) + +#ifdef HAVE_MULTILINK + LENCISHORT(go->neg_mrru) + +#endif /* HAVE_MULTILINK */ + LENCIVOID(go->neg_ssnhf) + + (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0)); +} + + +/* + * lcp_addci - Add our desired CIs to a packet. + */ +static void lcp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char *start_ucp = ucp; + +#define ADDCIVOID(opt, neg) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_VOID, ucp); \ + } +#define ADDCISHORT(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_SHORT, ucp); \ + PUTSHORT(val, ucp); \ + } +#if CHAP_SUPPORT +#define ADDCICHAP(opt, neg, val) \ + if (neg) { \ + PUTCHAR((opt), ucp); \ + PUTCHAR(CILEN_CHAP, ucp); \ + PUTSHORT(PPP_CHAP, ucp); \ + PUTCHAR((CHAP_DIGEST(val)), ucp); \ + } +#endif /* CHAP_SUPPORT */ +#define ADDCILONG(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LONG, ucp); \ + PUTLONG(val, ucp); \ + } +#if LQR_SUPPORT +#define ADDCILQR(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LQR, ucp); \ + PUTSHORT(PPP_LQR, ucp); \ + PUTLONG(val, ucp); \ + } +#endif /* LQR_SUPPORT */ +#define ADDCICHAR(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR, ucp); \ + PUTCHAR(val, ucp); \ + } +#define ADDCIENDP(opt, neg, class, val, len) \ + if (neg) { \ + int i; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR + len, ucp); \ + PUTCHAR(class, ucp); \ + for (i = 0; i < len; ++i) \ + PUTCHAR(val[i], ucp); \ + } + + ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, + go->asyncmap); +#if EAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); + ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); + ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); + ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); +#ifdef HAVE_MULTILINK + ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru); +#endif + ADDCIVOID(CI_SSNHF, go->neg_ssnhf); + ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + if (ucp - start_ucp != *lenp) { + /* this should never happen, because peer_mtu should be 1500 */ + ppp_error("Bug in lcp_addci: wrong length"); + } +} + + +/* + * lcp_ackci - Ack our CIs. + * This should not modify any state if the Ack is bad. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int lcp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char cilen, citype, cichar; + u_short cishort; + u32_t cilong; + + /* + * CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define ACKCIVOID(opt, neg) \ + if (neg) { \ + if ((len -= CILEN_VOID) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_VOID || \ + citype != opt) \ + goto bad; \ + } +#define ACKCISHORT(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_SHORT) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_SHORT || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + } +#define ACKCICHAR(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_CHAR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAR || \ + citype != opt) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != val) \ + goto bad; \ + } +#if CHAP_SUPPORT +#define ACKCICHAP(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_CHAP) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAP || \ + citype != (opt)) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != PPP_CHAP) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != (CHAP_DIGEST(val))) \ + goto bad; \ + } +#endif /* CHAP_SUPPORT */ +#define ACKCILONG(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_LONG) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_LONG || \ + citype != opt) \ + goto bad; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + goto bad; \ + } +#if LQR_SUPPORT +#define ACKCILQR(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_LQR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_LQR || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != PPP_LQR) \ + goto bad; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + goto bad; \ + } +#endif /* LQR_SUPPORT */ +#define ACKCIENDP(opt, neg, class, val, vlen) \ + if (neg) { \ + int i; \ + if ((len -= CILEN_CHAR + vlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAR + vlen || \ + citype != opt) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != class) \ + goto bad; \ + for (i = 0; i < vlen; ++i) { \ + GETCHAR(cichar, p); \ + if (cichar != val[i]) \ + goto bad; \ + } \ + } + + ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, + go->asyncmap); +#if EAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); + ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); + ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); + ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); +#ifdef HAVE_MULTILINK + ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru); +#endif /* HAVE_MULTILINK */ + ACKCIVOID(CI_SSNHF, go->neg_ssnhf); + ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); +bad: + LCPDEBUG(("lcp_acki: received bad Ack!")); + return (0); +} + + +/* + * lcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if LCP is in the OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *wo = &pcb->lcp_wantoptions; + u_char citype, cichar, *next; + u_short cishort; + u32_t cilong; + lcp_options no; /* options we've seen Naks for */ + lcp_options try_; /* options to request next time */ + int looped_back = 0; + int cilen; + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIVOID(opt, neg) \ + if (go->neg && \ + len >= CILEN_VOID && \ + p[1] == CILEN_VOID && \ + p[0] == opt) { \ + len -= CILEN_VOID; \ + INCPTR(CILEN_VOID, p); \ + no.neg = 1; \ + try_.neg = 0; \ + } +#if CHAP_SUPPORT +#define NAKCICHAP(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + no.neg = 1; \ + code \ + } +#endif /* CHAP_SUPPORT */ +#define NAKCICHAR(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_CHAR && \ + p[1] == CILEN_CHAR && \ + p[0] == opt) { \ + len -= CILEN_CHAR; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + no.neg = 1; \ + code \ + } +#define NAKCISHORT(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_SHORT && \ + p[1] == CILEN_SHORT && \ + p[0] == opt) { \ + len -= CILEN_SHORT; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#define NAKCILONG(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_LONG && \ + p[1] == CILEN_LONG && \ + p[0] == opt) { \ + len -= CILEN_LONG; \ + INCPTR(2, p); \ + GETLONG(cilong, p); \ + no.neg = 1; \ + code \ + } +#if LQR_SUPPORT +#define NAKCILQR(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_LQR && \ + p[1] == CILEN_LQR && \ + p[0] == opt) { \ + len -= CILEN_LQR; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETLONG(cilong, p); \ + no.neg = 1; \ + code \ + } +#endif /* LQR_SUPPORT */ +#define NAKCIENDP(opt, neg) \ + if (go->neg && \ + len >= CILEN_CHAR && \ + p[0] == opt && \ + p[1] >= CILEN_CHAR && \ + p[1] <= len) { \ + len -= p[1]; \ + INCPTR(p[1], p); \ + no.neg = 1; \ + try_.neg = 0; \ + } + + /* + * NOTE! There must be no assignments to individual fields of *go in + * the code below. Any such assignment is a BUG! + */ + /* + * We don't care if they want to send us smaller packets than + * we want. Therefore, accept any MRU less than what we asked for, + * but then ignore the new value when setting the MRU in the kernel. + * If they send us a bigger MRU than what we asked, accept it, up to + * the limit of the default MRU we'd get if we didn't negotiate. + */ + if (go->neg_mru && go->mru != PPP_DEFMRU) { + NAKCISHORT(CI_MRU, neg_mru, + if (cishort <= wo->mru || cishort <= PPP_DEFMRU) + try_.mru = cishort; + ); + } + + /* + * Add any characters they want to our (receive-side) asyncmap. + */ + if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) { + NAKCILONG(CI_ASYNCMAP, neg_asyncmap, + try_.asyncmap = go->asyncmap | cilong; + ); + } + + /* + * If they've nak'd our authentication-protocol, check whether + * they are proposing a different protocol, or a different + * hash algorithm for CHAP. + */ + if ((0 +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + ) + && len >= CILEN_SHORT + && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { + cilen = p[1]; + len -= cilen; +#if CHAP_SUPPORT + no.neg_chap = go->neg_chap; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + no.neg_upap = go->neg_upap; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + no.neg_eap = go->neg_eap; +#endif /* EAP_SUPPORT */ + INCPTR(2, p); + GETSHORT(cishort, p); + +#if PAP_SUPPORT + if (cishort == PPP_PAP && cilen == CILEN_SHORT) { +#if EAP_SUPPORT + /* If we were asking for EAP, then we need to stop that. */ + if (go->neg_eap) + try_.neg_eap = 0; + else +#endif /* EAP_SUPPORT */ + +#if CHAP_SUPPORT + /* If we were asking for CHAP, then we need to stop that. */ + if (go->neg_chap) + try_.neg_chap = 0; + else +#endif /* CHAP_SUPPORT */ + + /* + * If we weren't asking for CHAP or EAP, then we were asking for + * PAP, in which case this Nak is bad. + */ + goto bad; + } else +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { + GETCHAR(cichar, p); +#if EAP_SUPPORT + /* Stop asking for EAP, if we were. */ + if (go->neg_eap) { + try_.neg_eap = 0; + /* Try to set up to use their suggestion, if possible */ + if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) + try_.chap_mdtype = CHAP_MDTYPE_D(cichar); + } else +#endif /* EAP_SUPPORT */ + if (go->neg_chap) { + /* + * We were asking for our preferred algorithm, they must + * want something different. + */ + if (cichar != CHAP_DIGEST(go->chap_mdtype)) { + if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) { + /* Use their suggestion if we support it ... */ + try_.chap_mdtype = CHAP_MDTYPE_D(cichar); + } else { + /* ... otherwise, try our next-preferred algorithm. */ + try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype)); + if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */ + try_.neg_chap = 0; + } + } else { + /* + * Whoops, they Nak'd our algorithm of choice + * but then suggested it back to us. + */ + goto bad; + } + } else { + /* + * Stop asking for PAP if we were asking for it. + */ +#if PAP_SUPPORT + try_.neg_upap = 0; +#endif /* PAP_SUPPORT */ + } + + } else +#endif /* CHAP_SUPPORT */ + { + +#if EAP_SUPPORT + /* + * If we were asking for EAP, and they're Conf-Naking EAP, + * well, that's just strange. Nobody should do that. + */ + if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap) + ppp_dbglog("Unexpected Conf-Nak for EAP"); + + /* + * We don't recognize what they're suggesting. + * Stop asking for what we were asking for. + */ + if (go->neg_eap) + try_.neg_eap = 0; + else +#endif /* EAP_SUPPORT */ + +#if CHAP_SUPPORT + if (go->neg_chap) + try_.neg_chap = 0; + else +#endif /* CHAP_SUPPORT */ + +#if PAP_SUPPORT + if(1) + try_.neg_upap = 0; + else +#endif /* PAP_SUPPORT */ + {} + + p += cilen - CILEN_SHORT; + } + } + +#if LQR_SUPPORT + /* + * If they can't cope with our link quality protocol, we'll have + * to stop asking for LQR. We haven't got any other protocol. + * If they Nak the reporting period, take their value XXX ? + */ + NAKCILQR(CI_QUALITY, neg_lqr, + if (cishort != PPP_LQR) + try_.neg_lqr = 0; + else + try_.lqr_period = cilong; + ); +#endif /* LQR_SUPPORT */ + + /* + * Only implementing CBCP...not the rest of the callback options + */ + NAKCICHAR(CI_CALLBACK, neg_cbcp, + try_.neg_cbcp = 0; + (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */ + ); + + /* + * Check for a looped-back line. + */ + NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, + try_.magicnumber = magic(); + looped_back = 1; + ); + + /* + * Peer shouldn't send Nak for protocol compression or + * address/control compression requests; they should send + * a Reject instead. If they send a Nak, treat it as a Reject. + */ + NAKCIVOID(CI_PCOMPRESSION, neg_pcompression); + NAKCIVOID(CI_ACCOMPRESSION, neg_accompression); + +#ifdef HAVE_MULTILINK + /* + * Nak for MRRU option - accept their value if it is smaller + * than the one we want. + */ + if (go->neg_mrru) { + NAKCISHORT(CI_MRRU, neg_mrru, + if (treat_as_reject) + try_.neg_mrru = 0; + else if (cishort <= wo->mrru) + try_.mrru = cishort; + ); + } +#else /* HAVE_MULTILINK */ + LWIP_UNUSED_ARG(treat_as_reject); +#endif /* HAVE_MULTILINK */ + + /* + * Nak for short sequence numbers shouldn't be sent, treat it + * like a reject. + */ + NAKCIVOID(CI_SSNHF, neg_ssnhf); + + /* + * Nak of the endpoint discriminator option is not permitted, + * treat it like a reject. + */ + NAKCIENDP(CI_EPDISC, neg_endpoint); + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If we see an option that we requested, or one we've already seen + * in this packet, then this packet is bad. + * If we wanted to respond by starting to negotiate on the requested + * option(s), we could, but we don't, because except for the + * authentication type and quality protocol, if we are not negotiating + * an option, it is because we were told not to. + * For the authentication type, the Nak from the peer means + * `let me authenticate myself with you' which is a bit pointless. + * For the quality protocol, the Nak means `ask me to send you quality + * reports', but if we didn't ask for them, we don't want them. + * An option we don't recognize represents the peer asking to + * negotiate some option we don't support, so ignore it. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if (cilen < CILEN_VOID || (len -= cilen) < 0) + goto bad; + next = p + cilen - 2; + + switch (citype) { + case CI_MRU: + if ((go->neg_mru && go->mru != PPP_DEFMRU) + || no.neg_mru || cilen != CILEN_SHORT) + goto bad; + GETSHORT(cishort, p); + if (cishort < PPP_DEFMRU) { + try_.neg_mru = 1; + try_.mru = cishort; + } + break; + case CI_ASYNCMAP: + if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + || no.neg_asyncmap || cilen != CILEN_LONG) + goto bad; + break; + case CI_AUTHTYPE: + if (0 +#if CHAP_SUPPORT + || go->neg_chap || no.neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap || no.neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap || no.neg_eap +#endif /* EAP_SUPPORT */ + ) + goto bad; + break; + case CI_MAGICNUMBER: + if (go->neg_magicnumber || no.neg_magicnumber || + cilen != CILEN_LONG) + goto bad; + break; + case CI_PCOMPRESSION: + if (go->neg_pcompression || no.neg_pcompression + || cilen != CILEN_VOID) + goto bad; + break; + case CI_ACCOMPRESSION: + if (go->neg_accompression || no.neg_accompression + || cilen != CILEN_VOID) + goto bad; + break; +#if LQR_SUPPORT + case CI_QUALITY: + if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) + goto bad; + break; +#endif /* LQR_SUPPORT */ +#ifdef HAVE_MULTILINK + case CI_MRRU: + if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT) + goto bad; + break; +#endif /* HAVE_MULTILINK */ + case CI_SSNHF: + if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID) + goto bad; + try_.neg_ssnhf = 1; + break; + case CI_EPDISC: + if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR) + goto bad; + break; + default: + break; + } + p = next; + } + + /* + * OK, the Nak is good. Now we can update state. + * If there are any options left we ignore them. + */ + if (f->state != PPP_FSM_OPENED) { + if (looped_back) { + if (++try_.numloops >= pcb->settings.lcp_loopbackfail) { + ppp_notice("Serial line is looped back."); + pcb->err_code = PPPERR_LOOPBACK; + lcp_close(f->pcb, "Loopback detected"); + } + } else + try_.numloops = 0; + *go = try_; + } + + return 1; + +bad: + LCPDEBUG(("lcp_nakci: received bad Nak!")); + return 0; +} + + +/* + * lcp_rejci - Peer has Rejected some of our CIs. + * This should not modify any state if the Reject is bad + * or if LCP is in the OPENED state. + * + * Returns: + * 0 - Reject was bad. + * 1 - Reject was good. + */ +static int lcp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char cichar; + u_short cishort; + u32_t cilong; + lcp_options try_; /* options to request next time */ + + try_ = *go; + + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIVOID(opt, neg) \ + if (go->neg && \ + len >= CILEN_VOID && \ + p[1] == CILEN_VOID && \ + p[0] == opt) { \ + len -= CILEN_VOID; \ + INCPTR(CILEN_VOID, p); \ + try_.neg = 0; \ + } +#define REJCISHORT(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_SHORT && \ + p[1] == CILEN_SHORT && \ + p[0] == opt) { \ + len -= CILEN_SHORT; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + try_.neg = 0; \ + } + +#if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_eap = try_.neg_upap = 0; \ + } +#endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */ + +#if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_upap = 0; \ + } +#endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */ + +#if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_eap = 0; \ + } +#endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */ + +#if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */ + +#define REJCILONG(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_LONG && \ + p[1] == CILEN_LONG && \ + p[0] == opt) { \ + len -= CILEN_LONG; \ + INCPTR(2, p); \ + GETLONG(cilong, p); \ + /* Check rejected value. */ \ + if (cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } +#if LQR_SUPPORT +#define REJCILQR(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_LQR && \ + p[1] == CILEN_LQR && \ + p[0] == opt) { \ + len -= CILEN_LQR; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETLONG(cilong, p); \ + /* Check rejected value. */ \ + if (cishort != PPP_LQR || cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* LQR_SUPPORT */ +#define REJCICBCP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CBCP && \ + p[1] == CILEN_CBCP && \ + p[0] == opt) { \ + len -= CILEN_CBCP; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if (cichar != val) \ + goto bad; \ + try_.neg = 0; \ + } +#define REJCIENDP(opt, neg, class, val, vlen) \ + if (go->neg && \ + len >= CILEN_CHAR + vlen && \ + p[0] == opt && \ + p[1] == CILEN_CHAR + vlen) { \ + int i; \ + len -= CILEN_CHAR + vlen; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + if (cichar != class) \ + goto bad; \ + for (i = 0; i < vlen; ++i) { \ + GETCHAR(cichar, p); \ + if (cichar != val[i]) \ + goto bad; \ + } \ + try_.neg = 0; \ + } + + REJCISHORT(CI_MRU, neg_mru, go->mru); + REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); +#if EAP_SUPPORT + REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP); + if (!go->neg_eap) { +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype); + if (!go->neg_chap) { +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + } +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + } +#endif /* EAP_SUPPORT */ +#if LQR_SUPPORT + REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); + REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); + REJCIVOID(CI_PCOMPRESSION, neg_pcompression); + REJCIVOID(CI_ACCOMPRESSION, neg_accompression); +#ifdef HAVE_MULTILINK + REJCISHORT(CI_MRRU, neg_mrru, go->mrru); +#endif /* HAVE_MULTILINK */ + REJCIVOID(CI_SSNHF, neg_ssnhf); + REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + LCPDEBUG(("lcp_rejci: received bad Reject!")); + return 0; +} + + +/* + * lcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * lenp = Length of requested CIs + */ +static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ho = &pcb->lcp_hisoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + int cilen, citype, cichar; /* Parsed len, type, char value */ + u_short cishort; /* Parsed short value */ + u32_t cilong; /* Parse long value */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *rejp; /* Pointer to next char in reject frame */ + struct pbuf *nakp; /* Nak buffer */ + u_char *nakoutp; /* Pointer to next char in Nak frame */ + int l = *lenp; /* Length left */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + if(NULL == nakp) + return 0; + if(nakp->tot_len != nakp->len) { + pbuf_free(nakp); + return 0; + } + + nakoutp = (u_char*)nakp->payload; + rejp = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + LCPDEBUG(("lcp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + citype = 0; + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_MRU: + if (!ao->neg_mru || /* Allow option? */ + cilen != CILEN_SHORT) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETSHORT(cishort, p); /* Parse MRU */ + + /* + * He must be able to receive at least our minimum. + * No need to check a maximum. If he sends a large number, + * we'll just ignore it. + */ + if (cishort < PPP_MINMRU) { + orc = CONFNAK; /* Nak CI */ + PUTCHAR(CI_MRU, nakoutp); + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_MINMRU, nakoutp); /* Give him a hint */ + break; + } + ho->neg_mru = 1; /* Remember he sent MRU */ + ho->mru = cishort; /* And remember value */ + break; + + case CI_ASYNCMAP: + if (!ao->neg_asyncmap || + cilen != CILEN_LONG) { + orc = CONFREJ; + break; + } + GETLONG(cilong, p); + + /* + * Asyncmap must have set at least the bits + * which are set in lcp_allowoptions[unit].asyncmap. + */ + if ((ao->asyncmap & ~cilong) != 0) { + orc = CONFNAK; + PUTCHAR(CI_ASYNCMAP, nakoutp); + PUTCHAR(CILEN_LONG, nakoutp); + PUTLONG(ao->asyncmap | cilong, nakoutp); + break; + } + ho->neg_asyncmap = 1; + ho->asyncmap = cilong; + break; + + case CI_AUTHTYPE: + if (cilen < CILEN_SHORT || + !(0 +#if PAP_SUPPORT + || ao->neg_upap +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || ao->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || ao->neg_eap +#endif /* EAP_SUPPORT */ + )) { + /* + * Reject the option if we're not willing to authenticate. + */ + ppp_dbglog("No auth is possible"); + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + /* + * Authtype must be PAP, CHAP, or EAP. + * + * Note: if more than one of ao->neg_upap, ao->neg_chap, and + * ao->neg_eap are set, and the peer sends a Configure-Request + * with two or more authenticate-protocol requests, then we will + * reject the second request. + * Whether we end up doing CHAP, UPAP, or EAP depends then on + * the ordering of the CIs in the peer's Configure-Request. + */ + +#if PAP_SUPPORT + if (cishort == PPP_PAP) { + /* we've already accepted CHAP or EAP */ + if (0 +#if CHAP_SUPPORT + || ho->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || ho->neg_eap +#endif /* EAP_SUPPORT */ + || cilen != CILEN_SHORT) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_upap) { /* we don't want to do PAP */ + orc = CONFNAK; /* NAK it and suggest CHAP or EAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_EAP, nakoutp); + } else { +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + } +#endif /* EAP_SUPPORT */ + break; + } + ho->neg_upap = 1; + break; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (cishort == PPP_CHAP) { + /* we've already accepted PAP or EAP */ + if ( +#if PAP_SUPPORT + ho->neg_upap || +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + ho->neg_eap || +#endif /* EAP_SUPPORT */ + cilen != CILEN_CHAP) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_chap) { /* we don't want to do CHAP */ + orc = CONFNAK; /* NAK it and suggest EAP or PAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); + PUTCHAR(CILEN_SHORT, nakoutp); +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTSHORT(PPP_EAP, nakoutp); + } else +#endif /* EAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTSHORT(PPP_PAP, nakoutp); + } + else +#endif /* PAP_SUPPORT */ + {} + break; + } + GETCHAR(cichar, p); /* get digest type */ + if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) { + /* + * We can't/won't do the requested type, + * suggest something else. + */ + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakoutp); + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + break; + } + ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */ + ho->neg_chap = 1; + break; + } +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (cishort == PPP_EAP) { + /* we've already accepted CHAP or PAP */ + if ( +#if CHAP_SUPPORT + ho->neg_chap || +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + ho->neg_upap || +#endif /* PAP_SUPPORT */ + cilen != CILEN_SHORT) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_eap) { /* we don't want to do EAP */ + orc = CONFNAK; /* NAK it and suggest CHAP or PAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); +#if CHAP_SUPPORT + if (ao->neg_chap) { + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_PAP, nakoutp); + } else +#endif /* PAP_SUPPORT */ + {} + break; + } + ho->neg_eap = 1; + break; + } +#endif /* EAP_SUPPORT */ + + /* + * We don't recognize the protocol they're asking for. + * Nak it with something we're willing to do. + * (At this point we know ao->neg_upap || ao->neg_chap || + * ao->neg_eap.) + */ + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakoutp); + +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_EAP, nakoutp); + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (ao->neg_chap) { + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_PAP, nakoutp); + } else +#endif /* PAP_SUPPORT */ + {} + break; + +#if LQR_SUPPORT + case CI_QUALITY: + if (!ao->neg_lqr || + cilen != CILEN_LQR) { + orc = CONFREJ; + break; + } + + GETSHORT(cishort, p); + GETLONG(cilong, p); + + /* + * Check the protocol and the reporting period. + * XXX When should we Nak this, and what with? + */ + if (cishort != PPP_LQR) { + orc = CONFNAK; + PUTCHAR(CI_QUALITY, nakoutp); + PUTCHAR(CILEN_LQR, nakoutp); + PUTSHORT(PPP_LQR, nakoutp); + PUTLONG(ao->lqr_period, nakoutp); + break; + } + break; +#endif /* LQR_SUPPORT */ + + case CI_MAGICNUMBER: + if (!(ao->neg_magicnumber || go->neg_magicnumber) || + cilen != CILEN_LONG) { + orc = CONFREJ; + break; + } + GETLONG(cilong, p); + + /* + * He must have a different magic number. + */ + if (go->neg_magicnumber && + cilong == go->magicnumber) { + cilong = magic(); /* Don't put magic() inside macro! */ + orc = CONFNAK; + PUTCHAR(CI_MAGICNUMBER, nakoutp); + PUTCHAR(CILEN_LONG, nakoutp); + PUTLONG(cilong, nakoutp); + break; + } + ho->neg_magicnumber = 1; + ho->magicnumber = cilong; + break; + + + case CI_PCOMPRESSION: + if (!ao->neg_pcompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_pcompression = 1; + break; + + case CI_ACCOMPRESSION: + if (!ao->neg_accompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_accompression = 1; + break; + +#ifdef HAVE_MULTILINK + case CI_MRRU: + if (!ao->neg_mrru + || !multilink + || cilen != CILEN_SHORT) { + orc = CONFREJ; + break; + } + + GETSHORT(cishort, p); + /* possibly should insist on a minimum/maximum MRRU here */ + ho->neg_mrru = 1; + ho->mrru = cishort; + break; +#endif /* HAVE_MULTILINK */ + + case CI_SSNHF: + if (!ao->neg_ssnhf +#ifdef HAVE_MULTILINK + || !multilink +#endif /* HAVE_MULTILINK */ + || cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_ssnhf = 1; + break; + + case CI_EPDISC: + if (!ao->neg_endpoint || + cilen < CILEN_CHAR || + cilen > CILEN_CHAR + MAX_ENDP_LEN) { + orc = CONFREJ; + break; + } + GETCHAR(cichar, p); + cilen -= CILEN_CHAR; + ho->neg_endpoint = 1; + ho->endpoint.class_ = cichar; + ho->endpoint.length = cilen; + MEMCPY(ho->endpoint.value, p, cilen); + INCPTR(cilen, p); + break; + + default: + LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype)); + orc = CONFREJ; + break; + } + +endswitch: + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree /* Getting fed up with sending NAKs? */ + && citype != CI_MAGICNUMBER) { + orc = CONFREJ; /* Get tough if so */ + } else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + rc = CONFNAK; + } + } + if (orc == CONFREJ) { /* Reject this CI */ + rc = CONFREJ; + if (cip != rejp) /* Need to move rejected CI? */ + MEMCPY(rejp, cip, cilen); /* Move it */ + INCPTR(cilen, rejp); /* Update output pointer */ + } + } + + /* + * If we wanted to send additional NAKs (for unsent CIs), the + * code would go here. The extra NAKs would go at *nakoutp. + * At present there are no cases where we want to ask the + * peer to negotiate an option. + */ + + switch (rc) { + case CONFACK: + *lenp = next - inp; + break; + case CONFNAK: + /* + * Copy the Nak'd options from the nak buffer to the caller's buffer. + */ + *lenp = nakoutp - (u_char*)nakp->payload; + MEMCPY(inp, nakp->payload, *lenp); + break; + case CONFREJ: + *lenp = rejp - inp; + break; + default: + break; + } + + pbuf_free(nakp); + LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +/* + * lcp_up - LCP has come UP. + */ +static void lcp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *ho = &pcb->lcp_hisoptions; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + int mtu, mru; + + if (!go->neg_magicnumber) + go->magicnumber = 0; + if (!ho->neg_magicnumber) + ho->magicnumber = 0; + + /* + * Set our MTU to the smaller of the MTU we wanted and + * the MRU our peer wanted. If we negotiated an MRU, + * set our MRU to the larger of value we wanted and + * the value we got in the negotiation. + * Note on the MTU: the link MTU can be the MRU the peer wanted, + * the interface MTU is set to the lowest of that, the + * MTU we want to use, and our link MRU. + */ + mtu = ho->neg_mru? ho->mru: PPP_MRU; + mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU; +#ifdef HAVE_MULTILINK + if (!(multilink && go->neg_mrru && ho->neg_mrru)) +#endif /* HAVE_MULTILINK */ + netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); + ppp_send_config(pcb, mtu, + (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), + ho->neg_pcompression, ho->neg_accompression); + ppp_recv_config(pcb, mru, + (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff), + go->neg_pcompression, go->neg_accompression); + + if (ho->neg_mru) + pcb->peer_mru = ho->mru; + + lcp_echo_lowerup(f->pcb); /* Enable echo messages */ + + link_established(pcb); +} + + +/* + * lcp_down - LCP has gone DOWN. + * + * Alert other protocols. + */ +static void lcp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + + lcp_echo_lowerdown(f->pcb); + + link_down(pcb); + + ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0); + ppp_recv_config(pcb, PPP_MRU, + (go->neg_asyncmap? go->asyncmap: 0xffffffff), + go->neg_pcompression, go->neg_accompression); + pcb->peer_mru = PPP_MRU; +} + + +/* + * lcp_starting - LCP needs the lower layer up. + */ +static void lcp_starting(fsm *f) { + ppp_pcb *pcb = f->pcb; + link_required(pcb); +} + + +/* + * lcp_finished - LCP has finished with the lower layer. + */ +static void lcp_finished(fsm *f) { + ppp_pcb *pcb = f->pcb; + link_terminated(pcb); +} + + +#if PRINTPKT_SUPPORT +/* + * lcp_printpkt - print the contents of an LCP packet. + */ +static const char* const lcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej", "ProtRej", + "EchoReq", "EchoRep", "DiscReq", "Ident", + "TimeRem" +}; + +static int lcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, olen, i; + const u_char *pstart, *optend; + u_short cishort; + u32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(lcp_codenames)) + printer(arg, " %s", lcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case CI_MRU: + if (olen == CILEN_SHORT) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "mru %d", cishort); + } + break; + case CI_ASYNCMAP: + if (olen == CILEN_LONG) { + p += 2; + GETLONG(cilong, p); + printer(arg, "asyncmap 0x%x", cilong); + } + break; + case CI_AUTHTYPE: + if (olen >= CILEN_SHORT) { + p += 2; + printer(arg, "auth "); + GETSHORT(cishort, p); + switch (cishort) { +#if PAP_SUPPORT + case PPP_PAP: + printer(arg, "pap"); + break; +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + case PPP_CHAP: + printer(arg, "chap"); + if (p < optend) { + switch (*p) { + case CHAP_MD5: + printer(arg, " MD5"); + ++p; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + printer(arg, " MS"); + ++p; + break; + + case CHAP_MICROSOFT_V2: + printer(arg, " MS-v2"); + ++p; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + } + break; +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + printer(arg, "eap"); + break; +#endif /* EAP_SUPPORT */ + default: + printer(arg, "0x%x", cishort); + } + } + break; +#if LQR_SUPPORT + case CI_QUALITY: + if (olen >= CILEN_SHORT) { + p += 2; + printer(arg, "quality "); + GETSHORT(cishort, p); + switch (cishort) { + case PPP_LQR: + printer(arg, "lqr"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; +#endif /* LQR_SUPPORT */ + case CI_CALLBACK: + if (olen >= CILEN_CHAR) { + p += 2; + printer(arg, "callback "); + GETCHAR(cishort, p); + switch (cishort) { + case CBCP_OPT: + printer(arg, "CBCP"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; + case CI_MAGICNUMBER: + if (olen == CILEN_LONG) { + p += 2; + GETLONG(cilong, p); + printer(arg, "magic 0x%x", cilong); + } + break; + case CI_PCOMPRESSION: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "pcomp"); + } + break; + case CI_ACCOMPRESSION: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "accomp"); + } + break; + case CI_MRRU: + if (olen == CILEN_SHORT) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "mrru %d", cishort); + } + break; + case CI_SSNHF: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "ssnhf"); + } + break; + case CI_EPDISC: +#ifdef HAVE_MULTILINK + if (olen >= CILEN_CHAR) { + struct epdisc epd; + p += 2; + GETCHAR(epd.class, p); + epd.length = olen - CILEN_CHAR; + if (epd.length > MAX_ENDP_LEN) + epd.length = MAX_ENDP_LEN; + if (epd.length > 0) { + MEMCPY(epd.value, p, epd.length); + p += epd.length; + } + printer(arg, "endpoint [%s]", epdisc_to_str(&epd)); + } +#else + printer(arg, "endpoint"); +#endif + break; + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + + case ECHOREQ: + case ECHOREP: + case DISCREQ: + if (len >= 4) { + GETLONG(cilong, p); + printer(arg, " magic=0x%x", cilong); + len -= 4; + } + break; + + case IDENTIF: + case TIMEREM: + if (len >= 4) { + GETLONG(cilong, p); + printer(arg, " magic=0x%x", cilong); + len -= 4; + } + if (code == TIMEREM) { + if (len < 4) + break; + GETLONG(cilong, p); + printer(arg, " seconds=%u", cilong); + len -= 4; + } + if (len > 0) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (i = 0; i < len && i < 32; ++i) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + if (i < len) { + printer(arg, " ..."); + p += len - i; + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +/* + * Time to shut down the link because there is nothing out there. + */ + +static void LcpLinkFailure(fsm *f) { + ppp_pcb *pcb = f->pcb; + if (f->state == PPP_FSM_OPENED) { + ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending); + ppp_notice("Serial link appears to be disconnected."); + pcb->err_code = PPPERR_PEERDEAD; + lcp_close(pcb, "Peer not responding"); + } +} + +/* + * Timer expired for the LCP echo requests from this process. + */ + +static void LcpEchoCheck(fsm *f) { + ppp_pcb *pcb = f->pcb; + + LcpSendEchoRequest (f); + if (f->state != PPP_FSM_OPENED) + return; + + /* + * Start the timer for the next interval. + */ + if (pcb->lcp_echo_timer_running) + ppp_warn("assertion lcp_echo_timer_running==0 failed"); + TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval); + pcb->lcp_echo_timer_running = 1; +} + +/* + * LcpEchoTimeout - Timer expired on the LCP echo + */ + +static void LcpEchoTimeout(void *arg) { + fsm *f = (fsm*)arg; + ppp_pcb *pcb = f->pcb; + if (pcb->lcp_echo_timer_running != 0) { + pcb->lcp_echo_timer_running = 0; + LcpEchoCheck ((fsm *) arg); + } +} + +/* + * LcpEchoReply - LCP has received a reply to the echo + */ + +static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u32_t magic_val; + LWIP_UNUSED_ARG(id); + + /* Check the magic number - don't count replies from ourselves. */ + if (len < 4) { + ppp_dbglog("lcp: received short Echo-Reply, length %d", len); + return; + } + GETLONG(magic_val, inp); + if (go->neg_magicnumber + && magic_val == go->magicnumber) { + ppp_warn("appear to have received our own echo-reply!"); + return; + } + + /* Reset the number of outstanding echo frames */ + pcb->lcp_echos_pending = 0; +} + +/* + * LcpSendEchoRequest - Send an echo request frame to the peer + */ + +static void LcpSendEchoRequest(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u32_t lcp_magic; + u_char pkt[4], *pktp; + + /* + * Detect the failure of the peer at this point. + */ + if (pcb->settings.lcp_echo_fails != 0) { + if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) { + LcpLinkFailure(f); + pcb->lcp_echos_pending = 0; + } + } + +#if PPP_LCP_ADAPTIVE + /* + * If adaptive echos have been enabled, only send the echo request if + * no traffic was received since the last one. + */ + if (pcb->settings.lcp_echo_adaptive) { + static unsigned int last_pkts_in = 0; + +#if PPP_STATS_SUPPORT + update_link_stats(f->unit); + link_stats_valid = 0; +#endif /* PPP_STATS_SUPPORT */ + + if (link_stats.pkts_in != last_pkts_in) { + last_pkts_in = link_stats.pkts_in; + return; + } + } +#endif + + /* + * Make and send the echo request frame. + */ + if (f->state == PPP_FSM_OPENED) { + lcp_magic = go->magicnumber; + pktp = pkt; + PUTLONG(lcp_magic, pktp); + fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt); + ++pcb->lcp_echos_pending; + } +} + +/* + * lcp_echo_lowerup - Start the timer for the LCP frame + */ + +static void lcp_echo_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + /* Clear the parameters for generating echo frames */ + pcb->lcp_echos_pending = 0; + pcb->lcp_echo_number = 0; + pcb->lcp_echo_timer_running = 0; + + /* If a timeout interval is specified then start the timer */ + if (pcb->settings.lcp_echo_interval != 0) + LcpEchoCheck (f); +} + +/* + * lcp_echo_lowerdown - Stop the timer for the LCP frame + */ + +static void lcp_echo_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + if (pcb->lcp_echo_timer_running != 0) { + UNTIMEOUT (LcpEchoTimeout, f); + pcb->lcp_echo_timer_running = 0; + } +} + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/magic.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/magic.c new file mode 100644 index 0000000..d0d87c5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/magic.c @@ -0,0 +1,294 @@ +/* + * magic.c - PPP Magic Number routines. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/***************************************************************************** +* randm.c - Random number generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-06-03 Guy Lancaster , Global Election Systems Inc. +* Extracted from avos. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/magic.h" + +#if PPP_MD5_RANDM /* Using MD5 for better randomness if enabled */ + +#include "netif/ppp/pppcrypt.h" + +#define MD5_HASH_SIZE 16 +static char magic_randpool[MD5_HASH_SIZE]; /* Pool of randomness. */ +static long magic_randcount; /* Pseudo-random incrementer */ +static u32_t magic_randomseed; /* Seed used for random number generation. */ + +/* + * Churn the randomness pool on a random event. Call this early and often + * on random and semi-random system events to build randomness in time for + * usage. For randomly timed events, pass a null pointer and a zero length + * and this will use the system timer and other sources to add randomness. + * If new random data is available, pass a pointer to that and it will be + * included. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + */ +static void magic_churnrand(char *rand_data, u32_t rand_len) { + lwip_md5_context md5_ctx; + + /* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: %u@%P\n", rand_len, rand_data)); */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); + if (rand_data) { + lwip_md5_update(&md5_ctx, (u_char *)rand_data, rand_len); + } else { + struct { + /* INCLUDE fields for any system sources of randomness */ + u32_t jiffies; +#ifdef LWIP_RAND + u32_t rand; +#endif /* LWIP_RAND */ + } sys_data; + magic_randomseed += sys_jiffies(); + sys_data.jiffies = magic_randomseed; +#ifdef LWIP_RAND + sys_data.rand = LWIP_RAND(); +#endif /* LWIP_RAND */ + /* Load sys_data fields here. */ + lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data)); + } + lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool); + lwip_md5_free(&md5_ctx); +/* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: -> 0\n")); */ +} + +/* + * Initialize the random number generator. + */ +void magic_init(void) { + magic_churnrand(NULL, 0); +} + +/* + * Randomize our random seed value. + */ +void magic_randomize(void) { + magic_churnrand(NULL, 0); +} + +/* + * magic_random_bytes - Fill a buffer with random bytes. + * + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using magic_churnrand(). + * Note: It's important that there be sufficient randomness in magic_randpool + * before this is called for otherwise the range of the result may be + * narrow enough to make a search feasible. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + * + * XXX Why does he not just call magic_churnrand() for each block? Probably + * so that you don't ever publish the seed which could possibly help + * predict future values. + * XXX Why don't we preserve md5 between blocks and just update it with + * magic_randcount each time? Probably there is a weakness but I wish that + * it was documented. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len) { + lwip_md5_context md5_ctx; + u_char tmp[MD5_HASH_SIZE]; + u32_t n; + + while (buf_len > 0) { + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); + lwip_md5_update(&md5_ctx, (u_char *)&magic_randcount, sizeof(magic_randcount)); + lwip_md5_finish(&md5_ctx, tmp); + lwip_md5_free(&md5_ctx); + magic_randcount++; + n = LWIP_MIN(buf_len, MD5_HASH_SIZE); + MEMCPY(buf, tmp, n); + buf += n; + buf_len -= n; + } +} + +/* + * Return a new random number. + */ +u32_t magic(void) { + u32_t new_rand; + + magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand)); + + return new_rand; +} + +#else /* PPP_MD5_RANDM */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +#ifndef LWIP_RAND +static int magic_randomized; /* Set when truely randomized. */ +#endif /* LWIP_RAND */ +static u32_t magic_randomseed; /* Seed used for random number generation. */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ + +/* + * Initialize the random number generator. + * + * Here we attempt to compute a random number seed but even if + * it isn't random, we'll randomize it later. + * + * The current method uses the fields from the real time clock, + * the idle process counter, the millisecond counter, and the + * hardware timer tick counter. When this is invoked + * in startup(), then the idle counter and timer values may + * repeat after each boot and the real time clock may not be + * operational. Thus we call it again on the first random + * event. + */ +void magic_init(void) { + magic_randomseed += sys_jiffies(); +#ifndef LWIP_RAND + /* Initialize the Borland random number generator. */ + srand((unsigned)magic_randomseed); +#endif /* LWIP_RAND */ +} + +/* + * magic_init - Initialize the magic number generator. + * + * Randomize our random seed value. Here we use the fact that + * this function is called at *truely random* times by the polling + * and network functions. Here we only get 16 bits of new random + * value but we use the previous value to randomize the other 16 + * bits. + */ +void magic_randomize(void) { +#ifndef LWIP_RAND + if (!magic_randomized) { + magic_randomized = !0; + magic_init(); + /* The initialization function also updates the seed. */ + } else { +#endif /* LWIP_RAND */ + magic_randomseed += sys_jiffies(); +#ifndef LWIP_RAND + } +#endif /* LWIP_RAND */ +} + +/* + * Return a new random number. + * + * Here we use the Borland rand() function to supply a pseudo random + * number which we make truely random by combining it with our own + * seed which is randomized by truely random events. + * Thus the numbers will be truely random unless there have been no + * operator or network events in which case it will be pseudo random + * seeded by the real time clock. + */ +u32_t magic(void) { +#ifdef LWIP_RAND + return LWIP_RAND() + magic_randomseed; +#else /* LWIP_RAND */ + return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed; +#endif /* LWIP_RAND */ +} + +/* + * magic_random_bytes - Fill a buffer with random bytes. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len) { + u32_t new_rand, n; + + while (buf_len > 0) { + new_rand = magic(); + n = LWIP_MIN(buf_len, sizeof(new_rand)); + MEMCPY(buf, &new_rand, n); + buf += n; + buf_len -= n; + } +} +#endif /* PPP_MD5_RANDM */ + +/* + * Return a new random number between 0 and (2^pow)-1 included. + */ +u32_t magic_pow(u8_t pow) { + return magic() & ~(~0UL<. + * Copyright (c) 2002,2003,2004 Google, Inc. + * All rights reserved. + * + * License: + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. + * + * Changelog: + * 08/12/05 - Matt Domsch + * Only need extra skb padding on transmit, not receive. + * 06/18/04 - Matt Domsch , Oleg Makarenko + * Use Linux kernel 2.6 arc4 and sha1 routines rather than + * providing our own. + * 2/15/04 - TS: added #include and testing for Kernel + * version before using + * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are + * deprecated in 2.6 + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "lwip/err.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/ccp.h" +#include "netif/ppp/mppe.h" +#include "netif/ppp/pppdebug.h" +#include "netif/ppp/pppcrypt.h" + +#define SHA1_SIGNATURE_SIZE 20 + +/* ppp_mppe_state.bits definitions */ +#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ +#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ +#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ +#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ + +#define MPPE_BIT_FLUSHED MPPE_BIT_A +#define MPPE_BIT_ENCRYPTED MPPE_BIT_D + +#define MPPE_BITS(p) ((p)[0] & 0xf0) +#define MPPE_CCOUNT(p) ((((p)[0] & 0x0f) << 8) + (p)[1]) +#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ + +#define MPPE_OVHD 2 /* MPPE overhead/packet */ +#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ + +/* + * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. + * Well, not what's written there, but rather what they meant. + */ +static void mppe_rekey(ppp_mppe_state * state, int initial_key) +{ + lwip_sha1_context sha1_ctx; + u8_t sha1_digest[SHA1_SIGNATURE_SIZE]; + + /* + * Key Derivation, from RFC 3078, RFC 3079. + * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. + */ + lwip_sha1_init(&sha1_ctx); + lwip_sha1_starts(&sha1_ctx); + lwip_sha1_update(&sha1_ctx, state->master_key, state->keylen); + lwip_sha1_update(&sha1_ctx, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1_ctx, state->session_key, state->keylen); + lwip_sha1_update(&sha1_ctx, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1_ctx, sha1_digest); + lwip_sha1_free(&sha1_ctx); + MEMCPY(state->session_key, sha1_digest, state->keylen); + + if (!initial_key) { + lwip_arc4_init(&state->arc4); + lwip_arc4_setup(&state->arc4, sha1_digest, state->keylen); + lwip_arc4_crypt(&state->arc4, state->session_key, state->keylen); + lwip_arc4_free(&state->arc4); + } + if (state->keylen == 8) { + /* See RFC 3078 */ + state->session_key[0] = 0xd1; + state->session_key[1] = 0x26; + state->session_key[2] = 0x9e; + } + lwip_arc4_init(&state->arc4); + lwip_arc4_setup(&state->arc4, state->session_key, state->keylen); +} + +/* + * Set key, used by MSCHAP before mppe_init() is actually called by CCP so we + * don't have to keep multiple copies of keys. + */ +void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key) { + LWIP_UNUSED_ARG(pcb); + MEMCPY(state->master_key, key, MPPE_MAX_KEY_LEN); +} + +/* + * Initialize (de)compressor state. + */ +void +mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options) +{ +#if PPP_DEBUG + const u8_t *debugstr = (const u8_t*)"mppe_comp_init"; + if (&pcb->mppe_decomp == state) { + debugstr = (const u8_t*)"mppe_decomp_init"; + } +#endif /* PPP_DEBUG */ + + /* Save keys. */ + MEMCPY(state->session_key, state->master_key, sizeof(state->master_key)); + + if (options & MPPE_OPT_128) + state->keylen = 16; + else if (options & MPPE_OPT_40) + state->keylen = 8; + else { + PPPDEBUG(LOG_DEBUG, ("%s[%d]: unknown key length\n", debugstr, + pcb->netif->num)); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + return; + } + if (options & MPPE_OPT_STATEFUL) + state->stateful = 1; + + /* Generate the initial session key. */ + mppe_rekey(state, 1); + +#if PPP_DEBUG + { + int i; + char mkey[sizeof(state->master_key) * 2 + 1]; + char skey[sizeof(state->session_key) * 2 + 1]; + + PPPDEBUG(LOG_DEBUG, ("%s[%d]: initialized with %d-bit %s mode\n", + debugstr, pcb->netif->num, (state->keylen == 16) ? 128 : 40, + (state->stateful) ? "stateful" : "stateless")); + + for (i = 0; i < (int)sizeof(state->master_key); i++) + sprintf(mkey + i * 2, "%02x", state->master_key[i]); + for (i = 0; i < (int)sizeof(state->session_key); i++) + sprintf(skey + i * 2, "%02x", state->session_key[i]); + PPPDEBUG(LOG_DEBUG, + ("%s[%d]: keys: master: %s initial session: %s\n", + debugstr, pcb->netif->num, mkey, skey)); + } +#endif /* PPP_DEBUG */ + + /* + * Initialize the coherency count. The initial value is not specified + * in RFC 3078, but we can make a reasonable assumption that it will + * start at 0. Setting it to the max here makes the comp/decomp code + * do the right thing (determined through experiment). + */ + state->ccount = MPPE_CCOUNT_SPACE - 1; + + /* + * Note that even though we have initialized the key table, we don't + * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. + */ + state->bits = MPPE_BIT_ENCRYPTED; +} + +/* + * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), + * tell the compressor to rekey. Note that we MUST NOT rekey for + * every CCP Reset-Request; we only rekey on the next xmit packet. + * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. + * So, rekeying for every CCP Reset-Request is broken as the peer will not + * know how many times we've rekeyed. (If we rekey and THEN get another + * CCP Reset-Request, we must rekey again.) + */ +void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state) +{ + LWIP_UNUSED_ARG(pcb); + state->bits |= MPPE_BIT_FLUSHED; +} + +/* + * Compress (encrypt) a packet. + * It's strange to call this a compressor, since the output is always + * MPPE_OVHD + 2 bytes larger than the input. + */ +err_t +mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol) +{ + struct pbuf *n, *np; + u8_t *pl; + err_t err; + + LWIP_UNUSED_ARG(pcb); + + /* TCP stack requires that we don't change the packet payload, therefore we copy + * the whole packet before encryption. + */ + np = pbuf_alloc(PBUF_RAW, MPPE_OVHD + sizeof(protocol) + (*pb)->tot_len, PBUF_RAM); + if (!np) { + return ERR_MEM; + } + + /* Hide MPPE header + protocol */ + pbuf_remove_header(np, MPPE_OVHD + sizeof(protocol)); + + if ((err = pbuf_copy(np, *pb)) != ERR_OK) { + pbuf_free(np); + return err; + } + + /* Reveal MPPE header + protocol */ + pbuf_add_header(np, MPPE_OVHD + sizeof(protocol)); + + *pb = np; + pl = (u8_t*)np->payload; + + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: ccount %d\n", pcb->netif->num, state->ccount)); + /* FIXME: use PUT* macros */ + pl[0] = state->ccount>>8; + pl[1] = state->ccount; + + if (!state->stateful || /* stateless mode */ + ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ + (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ + /* We must rekey */ + if (state->stateful) { + PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: rekeying\n", pcb->netif->num)); + } + mppe_rekey(state, 0); + state->bits |= MPPE_BIT_FLUSHED; + } + pl[0] |= state->bits; + state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ + pl += MPPE_OVHD; + + /* Add protocol */ + /* FIXME: add PFC support */ + pl[0] = protocol >> 8; + pl[1] = protocol; + + /* Hide MPPE header */ + pbuf_remove_header(np, MPPE_OVHD); + + /* Encrypt packet */ + for (n = np; n != NULL; n = n->next) { + lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); + if (n->tot_len == n->len) { + break; + } + } + + /* Reveal MPPE header */ + pbuf_add_header(np, MPPE_OVHD); + + return ERR_OK; +} + +/* + * We received a CCP Reset-Ack. Just ignore it. + */ +void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(state); + return; +} + +/* + * Decompress (decrypt) an MPPE packet. + */ +err_t +mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb) +{ + struct pbuf *n0 = *pb, *n; + u8_t *pl; + u16_t ccount; + u8_t flushed; + + /* MPPE Header */ + if (n0->len < MPPE_OVHD) { + PPPDEBUG(LOG_DEBUG, + ("mppe_decompress[%d]: short pkt (%d)\n", + pcb->netif->num, n0->len)); + state->sanity_errors += 100; + goto sanity_error; + } + + pl = (u8_t*)n0->payload; + flushed = MPPE_BITS(pl) & MPPE_BIT_FLUSHED; + ccount = MPPE_CCOUNT(pl); + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ccount %d\n", + pcb->netif->num, ccount)); + + /* sanity checks -- terminate with extreme prejudice */ + if (!(MPPE_BITS(pl) & MPPE_BIT_ENCRYPTED)) { + PPPDEBUG(LOG_DEBUG, + ("mppe_decompress[%d]: ENCRYPTED bit not set!\n", + pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + if (!state->stateful && !flushed) { + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set in " + "stateless mode!\n", pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set on " + "flag packet!\n", pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + + /* + * Check the coherency count. + */ + + if (!state->stateful) { + /* Discard late packet */ + if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE > MPPE_CCOUNT_SPACE / 2) { + state->sanity_errors++; + goto sanity_error; + } + + /* RFC 3078, sec 8.1. Rekey for every packet. */ + while (state->ccount != ccount) { + mppe_rekey(state, 0); + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + } + } else { + /* RFC 3078, sec 8.2. */ + if (!state->discard) { + /* normal state */ + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (ccount != state->ccount) { + /* + * (ccount > state->ccount) + * Packet loss detected, enter the discard state. + * Signal the peer to rekey (by sending a CCP Reset-Request). + */ + state->discard = 1; + ccp_resetrequest(pcb); + return ERR_BUF; + } + } else { + /* discard state */ + if (!flushed) { + /* ccp.c will be silent (no additional CCP Reset-Requests). */ + return ERR_BUF; + } else { + /* Rekey for every missed "flag" packet. */ + while ((ccount & ~0xff) != + (state->ccount & ~0xff)) { + mppe_rekey(state, 0); + state->ccount = + (state->ccount + + 256) % MPPE_CCOUNT_SPACE; + } + + /* reset */ + state->discard = 0; + state->ccount = ccount; + /* + * Another problem with RFC 3078 here. It implies that the + * peer need not send a Reset-Ack packet. But RFC 1962 + * requires it. Hopefully, M$ does send a Reset-Ack; even + * though it isn't required for MPPE synchronization, it is + * required to reset CCP state. + */ + } + } + if (flushed) + mppe_rekey(state, 0); + } + + /* Hide MPPE header */ + pbuf_remove_header(n0, MPPE_OVHD); + + /* Decrypt the packet. */ + for (n = n0; n != NULL; n = n->next) { + lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); + if (n->tot_len == n->len) { + break; + } + } + + /* good packet credit */ + state->sanity_errors >>= 1; + + return ERR_OK; + +sanity_error: + if (state->sanity_errors >= SANITY_MAX) { + /* + * Take LCP down if the peer is sending too many bogons. + * We don't want to do this for a single or just a few + * instances since it could just be due to packet corruption. + */ + lcp_close(pcb, "Too many MPPE errors"); + } + return ERR_BUF; +} + +#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/multilink.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/multilink.c new file mode 100644 index 0000000..62014e8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/multilink.c @@ -0,0 +1,609 @@ +/* + * multilink.c - support routines for multilink. + * + * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */ + +/* Multilink support + * + * Multilink uses Samba TDB (Trivial Database Library), which + * we cannot port, because it needs a filesystem. + * + * We have to choose between doing a memory-shared TDB-clone, + * or dropping multilink support at all. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/tdb.h" + +bool endpoint_specified; /* user gave explicit endpoint discriminator */ +char *bundle_id; /* identifier for our bundle */ +char *blinks_id; /* key for the list of links */ +bool doing_multilink; /* multilink was enabled and agreed to */ +bool multilink_master; /* we own the multilink bundle */ + +extern TDB_CONTEXT *pppdb; +extern char db_key[]; + +static void make_bundle_links (int append); +static void remove_bundle_link (void); +static void iterate_bundle_links (void (*func) (char *)); + +static int get_default_epdisc (struct epdisc *); +static int parse_num (char *str, const char *key, int *valp); +static int owns_unit (TDB_DATA pid, int unit); + +#define set_ip_epdisc(ep, addr) do { \ + ep->length = 4; \ + ep->value[0] = addr >> 24; \ + ep->value[1] = addr >> 16; \ + ep->value[2] = addr >> 8; \ + ep->value[3] = addr; \ +} while (0) + +#define LOCAL_IP_ADDR(addr) \ + (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \ + || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \ + || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */ + +#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH) + +void +mp_check_options() +{ + lcp_options *wo = &lcp_wantoptions[0]; + lcp_options *ao = &lcp_allowoptions[0]; + + doing_multilink = 0; + if (!multilink) + return; + /* if we're doing multilink, we have to negotiate MRRU */ + if (!wo->neg_mrru) { + /* mrru not specified, default to mru */ + wo->mrru = wo->mru; + wo->neg_mrru = 1; + } + ao->mrru = ao->mru; + ao->neg_mrru = 1; + + if (!wo->neg_endpoint && !noendpoint) { + /* get a default endpoint value */ + wo->neg_endpoint = get_default_epdisc(&wo->endpoint); + } +} + +/* + * Make a new bundle or join us to an existing bundle + * if we are doing multilink. + */ +int +mp_join_bundle() +{ + lcp_options *go = &lcp_gotoptions[0]; + lcp_options *ho = &lcp_hisoptions[0]; + lcp_options *ao = &lcp_allowoptions[0]; + int unit, pppd_pid; + int l, mtu; + char *p; + TDB_DATA key, pid, rec; + + if (doing_multilink) { + /* have previously joined a bundle */ + if (!go->neg_mrru || !ho->neg_mrru) { + notice("oops, didn't get multilink on renegotiation"); + lcp_close(pcb, "multilink required"); + return 0; + } + /* XXX should check the peer_authname and ho->endpoint + are the same as previously */ + return 0; + } + + if (!go->neg_mrru || !ho->neg_mrru) { + /* not doing multilink */ + if (go->neg_mrru) + notice("oops, multilink negotiated only for receive"); + mtu = ho->neg_mru? ho->mru: PPP_MRU; + if (mtu > ao->mru) + mtu = ao->mru; + if (demand) { + /* already have a bundle */ + cfg_bundle(0, 0, 0, 0); + netif_set_mtu(pcb, mtu); + return 0; + } + make_new_bundle(0, 0, 0, 0); + set_ifunit(1); + netif_set_mtu(pcb, mtu); + return 0; + } + + doing_multilink = 1; + + /* + * Find the appropriate bundle or join a new one. + * First we make up a name for the bundle. + * The length estimate is worst-case assuming every + * character has to be quoted. + */ + l = 4 * strlen(peer_authname) + 10; + if (ho->neg_endpoint) + l += 3 * ho->endpoint.length + 8; + if (bundle_name) + l += 3 * strlen(bundle_name) + 2; + bundle_id = malloc(l); + if (bundle_id == 0) + novm("bundle identifier"); + + p = bundle_id; + p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); + if (ho->neg_endpoint || bundle_name) + *p++ = '/'; + if (ho->neg_endpoint) + p += slprintf(p, bundle_id+l-p, "%s", + epdisc_to_str(&ho->endpoint)); + if (bundle_name) + p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); + + /* Make the key for the list of links belonging to the bundle */ + l = p - bundle_id; + blinks_id = malloc(l + 7); + if (blinks_id == NULL) + novm("bundle links key"); + slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); + + /* + * For demand mode, we only need to configure the bundle + * and attach the link. + */ + mtu = LWIP_MIN(ho->mrru, ao->mru); + if (demand) { + cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); + netif_set_mtu(pcb, mtu); + script_setenv("BUNDLE", bundle_id + 7, 1); + return 0; + } + + /* + * Check if the bundle ID is already in the database. + */ + unit = -1; + lock_db(); + key.dptr = bundle_id; + key.dsize = p - bundle_id; + pid = tdb_fetch(pppdb, key); + if (pid.dptr != NULL) { + /* bundle ID exists, see if the pppd record exists */ + rec = tdb_fetch(pppdb, pid); + if (rec.dptr != NULL && rec.dsize > 0) { + /* make sure the string is null-terminated */ + rec.dptr[rec.dsize-1] = 0; + /* parse the interface number */ + parse_num(rec.dptr, "IFNAME=ppp", &unit); + /* check the pid value */ + if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) + || !process_exists(pppd_pid) + || !owns_unit(pid, unit)) + unit = -1; + free(rec.dptr); + } + free(pid.dptr); + } + + if (unit >= 0) { + /* attach to existing unit */ + if (bundle_attach(unit)) { + set_ifunit(0); + script_setenv("BUNDLE", bundle_id + 7, 0); + make_bundle_links(1); + unlock_db(); + info("Link attached to %s", ifname); + return 1; + } + /* attach failed because bundle doesn't exist */ + } + + /* we have to make a new bundle */ + make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); + set_ifunit(1); + netif_set_mtu(pcb, mtu); + script_setenv("BUNDLE", bundle_id + 7, 1); + make_bundle_links(pcb); + unlock_db(); + info("New bundle %s created", ifname); + multilink_master = 1; + return 0; +} + +void mp_exit_bundle() +{ + lock_db(); + remove_bundle_link(); + unlock_db(); +} + +static void sendhup(char *str) +{ + int pid; + + if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) { + if (debug) + dbglog("sending SIGHUP to process %d", pid); + kill(pid, SIGHUP); + } +} + +void mp_bundle_terminated() +{ + TDB_DATA key; + + bundle_terminating = 1; + upper_layers_down(pcb); + notice("Connection terminated."); +#if PPP_STATS_SUPPORT + print_link_stats(); +#endif /* PPP_STATS_SUPPORT */ + if (!demand) { + remove_pidfiles(); + script_unsetenv("IFNAME"); + } + + lock_db(); + destroy_bundle(); + iterate_bundle_links(sendhup); + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + tdb_delete(pppdb, key); + unlock_db(); + + new_phase(PPP_PHASE_DEAD); + + doing_multilink = 0; + multilink_master = 0; +} + +static void make_bundle_links(int append) +{ + TDB_DATA key, rec; + char *p; + char entry[32]; + int l; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + slprintf(entry, sizeof(entry), "%s;", db_key); + p = entry; + if (append) { + rec = tdb_fetch(pppdb, key); + if (rec.dptr != NULL && rec.dsize > 0) { + rec.dptr[rec.dsize-1] = 0; + if (strstr(rec.dptr, db_key) != NULL) { + /* already in there? strange */ + warn("link entry already exists in tdb"); + return; + } + l = rec.dsize + strlen(entry); + p = malloc(l); + if (p == NULL) + novm("bundle link list"); + slprintf(p, l, "%s%s", rec.dptr, entry); + } else { + warn("bundle link list not found"); + } + if (rec.dptr != NULL) + free(rec.dptr); + } + rec.dptr = p; + rec.dsize = strlen(p) + 1; + if (tdb_store(pppdb, key, rec, TDB_REPLACE)) + error("couldn't %s bundle link list", + append? "update": "create"); + if (p != entry) + free(p); +} + +static void remove_bundle_link() +{ + TDB_DATA key, rec; + char entry[32]; + char *p, *q; + int l; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + slprintf(entry, sizeof(entry), "%s;", db_key); + + rec = tdb_fetch(pppdb, key); + if (rec.dptr == NULL || rec.dsize <= 0) { + if (rec.dptr != NULL) + free(rec.dptr); + return; + } + rec.dptr[rec.dsize-1] = 0; + p = strstr(rec.dptr, entry); + if (p != NULL) { + q = p + strlen(entry); + l = strlen(q) + 1; + memmove(p, q, l); + rec.dsize = p - rec.dptr + l; + if (tdb_store(pppdb, key, rec, TDB_REPLACE)) + error("couldn't update bundle link list (removal)"); + } + free(rec.dptr); +} + +static void iterate_bundle_links(void (*func)(char *)) +{ + TDB_DATA key, rec, pp; + char *p, *q; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + rec = tdb_fetch(pppdb, key); + if (rec.dptr == NULL || rec.dsize <= 0) { + error("bundle link list not found (iterating list)"); + if (rec.dptr != NULL) + free(rec.dptr); + return; + } + p = rec.dptr; + p[rec.dsize-1] = 0; + while ((q = strchr(p, ';')) != NULL) { + *q = 0; + key.dptr = p; + key.dsize = q - p; + pp = tdb_fetch(pppdb, key); + if (pp.dptr != NULL && pp.dsize > 0) { + pp.dptr[pp.dsize-1] = 0; + func(pp.dptr); + } + if (pp.dptr != NULL) + free(pp.dptr); + p = q + 1; + } + free(rec.dptr); +} + +static int +parse_num(str, key, valp) + char *str; + const char *key; + int *valp; +{ + char *p, *endp; + int i; + + p = strstr(str, key); + if (p != 0) { + p += strlen(key); + i = strtol(p, &endp, 10); + if (endp != p && (*endp == 0 || *endp == ';')) { + *valp = i; + return 1; + } + } + return 0; +} + +/* + * Check whether the pppd identified by `key' still owns ppp unit `unit'. + */ +static int +owns_unit(key, unit) + TDB_DATA key; + int unit; +{ + char ifkey[32]; + TDB_DATA kd, vd; + int ret = 0; + + slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); + kd.dptr = ifkey; + kd.dsize = strlen(ifkey); + vd = tdb_fetch(pppdb, kd); + if (vd.dptr != NULL) { + ret = vd.dsize == key.dsize + && memcmp(vd.dptr, key.dptr, vd.dsize) == 0; + free(vd.dptr); + } + return ret; +} + +static int +get_default_epdisc(ep) + struct epdisc *ep; +{ + char *p; + struct hostent *hp; + u32_t addr; + + /* First try for an ethernet MAC address */ + p = get_first_ethernet(); + if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) { + ep->class = EPD_MAC; + ep->length = 6; + return 1; + } + + /* see if our hostname corresponds to a reasonable IP address */ + hp = gethostbyname(hostname); + if (hp != NULL) { + addr = *(u32_t *)hp->h_addr; + if (!bad_ip_adrs(addr)) { + addr = lwip_ntohl(addr); + if (!LOCAL_IP_ADDR(addr)) { + ep->class = EPD_IP; + set_ip_epdisc(ep, addr); + return 1; + } + } + } + + return 0; +} + +/* + * epdisc_to_str - make a printable string from an endpoint discriminator. + */ + +static char *endp_class_names[] = { + "null", "local", "IP", "MAC", "magic", "phone" +}; + +char * +epdisc_to_str(ep) + struct epdisc *ep; +{ + static char str[MAX_ENDP_LEN*3+8]; + u_char *p = ep->value; + int i, mask = 0; + char *q, c, c2; + + if (ep->class == EPD_NULL && ep->length == 0) + return "null"; + if (ep->class == EPD_IP && ep->length == 4) { + u32_t addr; + + GETLONG(addr, p); + slprintf(str, sizeof(str), "IP:%I", lwip_htonl(addr)); + return str; + } + + c = ':'; + c2 = '.'; + if (ep->class == EPD_MAC && ep->length == 6) + c2 = ':'; + else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) + mask = 3; + q = str; + if (ep->class <= EPD_PHONENUM) + q += slprintf(q, sizeof(str)-1, "%s", + endp_class_names[ep->class]); + else + q += slprintf(q, sizeof(str)-1, "%d", ep->class); + c = ':'; + for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { + if ((i & mask) == 0) { + *q++ = c; + c = c2; + } + q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); + } + return str; +} + +static int hexc_val(int c) +{ + if (c >= 'a') + return c - 'a' + 10; + if (c >= 'A') + return c - 'A' + 10; + return c - '0'; +} + +int +str_to_epdisc(ep, str) + struct epdisc *ep; + char *str; +{ + int i, l; + char *p, *endp; + + for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) { + int sl = strlen(endp_class_names[i]); + if (strncasecmp(str, endp_class_names[i], sl) == 0) { + str += sl; + break; + } + } + if (i > EPD_PHONENUM) { + /* not a class name, try a decimal class number */ + i = strtol(str, &endp, 10); + if (endp == str) + return 0; /* can't parse class number */ + str = endp; + } + ep->class = i; + if (*str == 0) { + ep->length = 0; + return 1; + } + if (*str != ':' && *str != '.') + return 0; + ++str; + + if (i == EPD_IP) { + u32_t addr; + i = parse_dotted_ip(str, &addr); + if (i == 0 || str[i] != 0) + return 0; + set_ip_epdisc(ep, addr); + return 1; + } + if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) { + ep->length = 6; + return 1; + } + + p = str; + for (l = 0; l < MAX_ENDP_LEN; ++l) { + if (*str == 0) + break; + if (p <= str) + for (p = str; isxdigit(*p); ++p) + ; + i = p - str; + if (i == 0) + return 0; + ep->value[l] = hexc_val(*str++); + if ((i & 1) == 0) + ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); + if (*str == ':' || *str == '.') + ++str; + } + if (*str != 0 || (ep->class == EPD_MAC && l != 6)) + return 0; + ep->length = l; + return 1; +} + +#endif /* PPP_SUPPORT && HAVE_MULTILINK */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/README b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/README new file mode 100644 index 0000000..3fdf159 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/README @@ -0,0 +1,22 @@ +About PolarSSL files into lwIP PPP support +------------------------------------------ + +This folder contains some files fetched from the latest BSD release of +the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption +methods we need for lwIP PPP support. + +The PolarSSL files were cleaned to contain only the necessary struct +fields and functions needed for lwIP. + +The PolarSSL API was not changed at all, so if you are already using +PolarSSL you can choose to skip the compilation of the included PolarSSL +library into lwIP. + +If you are not using the embedded copy you must include external +libraries into your arch/cc.h port file. + +Beware of the stack requirements which can be a lot larger if you are not +using our cleaned PolarSSL library. + + +PolarSSL project website: http://polarssl.org/ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/arc4.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/arc4.c new file mode 100644 index 0000000..6e17ec4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/arc4.c @@ -0,0 +1,101 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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. + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_ARC4 + +#include "netif/ppp/polarssl/arc4.h" +/* + * ARC4 key schedule + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ) +{ + int i, j, k, a; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ) +{ + int i, x, y, a, b; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < buflen; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + buf[i] = (unsigned char) + ( buf[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/des.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/des.c new file mode 100644 index 0000000..9a89d00 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/des.c @@ -0,0 +1,422 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES + +#include "netif/ppp/polarssl/des.h" + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const unsigned long SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const unsigned long SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const unsigned long SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const unsigned long SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const unsigned long SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const unsigned long SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const unsigned long SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const unsigned long SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const unsigned long LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const unsigned long RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } + +static void des_setkey( unsigned long SK[32], unsigned char key[8] ) +{ + int i; + unsigned long X, Y, T; + + GET_ULONG_BE( X, key, 0 ); + GET_ULONG_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ) +{ + des_setkey( ctx->sk, key ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } +} + +/* + * DES-ECB block encryption/decryption + */ +void des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + unsigned long X, Y, T, *SK; + + SK = ctx->sk; + + GET_ULONG_BE( X, input, 0 ); + GET_ULONG_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_ULONG_BE( Y, output, 0 ); + PUT_ULONG_BE( X, output, 4 ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md4.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md4.c new file mode 100644 index 0000000..b1701a0 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md4.c @@ -0,0 +1,281 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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. + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 + +#include "netif/ppp/polarssl/md4.h" + +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD4 context setup + */ +void md4_starts( md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md4_process( md4_context *ctx, const unsigned char data[64] ) +{ + unsigned long X[16], A, B, C, D; + + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD4 process buffer + */ +void md4_update( md4_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md4_update( ctx, md4_padding, padn ); + md4_update( ctx, msglen, 8 ); + + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); +} + +/* + * output = MD4( input buffer ) + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ) +{ + md4_context ctx; + + md4_starts( &ctx ); + md4_update( &ctx, input, ilen ); + md4_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md5.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md5.c new file mode 100644 index 0000000..1ec4d81 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/md5.c @@ -0,0 +1,300 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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. + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 + +#include "netif/ppp/polarssl/md5.h" + +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD5 context setup + */ +void md5_starts( md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md5_process( md5_context *ctx, const unsigned char data[64] ) +{ + unsigned long X[16], A, B, C, D; + + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +void md5_update( md5_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char md5_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md5_update( ctx, md5_padding, padn ); + md5_update( ctx, msglen, 8 ); + + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); +} + +/* + * output = MD5( input buffer ) + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ) +{ + md5_context ctx; + + md5_starts( &ctx ); + md5_update( &ctx, input, ilen ); + md5_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/sha1.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/sha1.c new file mode 100644 index 0000000..c2192ea --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/polarssl/sha1.c @@ -0,0 +1,335 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * 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 names of PolarSSL or XySSL 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. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 + +#include "netif/ppp/polarssl/sha1.h" + +#include + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-1 context setup + */ +void sha1_starts( sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +static void sha1_process( sha1_context *ctx, const unsigned char data[64] ) +{ + unsigned long temp, W[16], A, B, C, D, E; + + GET_ULONG_BE( W[ 0], data, 0 ); + GET_ULONG_BE( W[ 1], data, 4 ); + GET_ULONG_BE( W[ 2], data, 8 ); + GET_ULONG_BE( W[ 3], data, 12 ); + GET_ULONG_BE( W[ 4], data, 16 ); + GET_ULONG_BE( W[ 5], data, 20 ); + GET_ULONG_BE( W[ 6], data, 24 ); + GET_ULONG_BE( W[ 7], data, 28 ); + GET_ULONG_BE( W[ 8], data, 32 ); + GET_ULONG_BE( W[ 9], data, 36 ); + GET_ULONG_BE( W[10], data, 40 ); + GET_ULONG_BE( W[11], data, 44 ); + GET_ULONG_BE( W[12], data, 48 ); + GET_ULONG_BE( W[13], data, 52 ); + GET_ULONG_BE( W[14], data, 56 ); + GET_ULONG_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ + W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_BE( high, msglen, 0 ); + PUT_ULONG_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha1_update( ctx, sha1_padding, padn ); + sha1_update( ctx, msglen, 8 ); + + PUT_ULONG_BE( ctx->state[0], output, 0 ); + PUT_ULONG_BE( ctx->state[1], output, 4 ); + PUT_ULONG_BE( ctx->state[2], output, 8 ); + PUT_ULONG_BE( ctx->state[3], output, 12 ); + PUT_ULONG_BE( ctx->state[4], output, 16 ); +} + +/* + * output = SHA-1( input buffer ) + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_starts( &ctx ); + sha1_update( &ctx, input, ilen ); + sha1_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ppp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ppp.c new file mode 100644 index 0000000..be58553 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/ppp.c @@ -0,0 +1,1631 @@ +/***************************************************************************** +* ppp.c - Network Point to Point Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original. +*****************************************************************************/ + +/* + * ppp_defs.h - PPP definitions. + * + * if_pppvar.h - private structures and declarations for PPP. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * @defgroup ppp PPP + * @ingroup netifs + * @verbinclude "ppp.txt" + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/tcpip.h" +#include "lwip/api.h" +#include "lwip/snmp.h" +#include "lwip/ip4.h" /* for ip4_input() */ +#if PPP_IPV6_SUPPORT +#include "lwip/ip6.h" /* for ip6_input() */ +#endif /* PPP_IPV6_SUPPORT */ +#include "lwip/dns.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppos.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/magic.h" + +#if PAP_SUPPORT +#include "netif/ppp/upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "netif/ppp/eap.h" +#endif /* EAP_SUPPORT */ +#if CCP_SUPPORT +#include "netif/ppp/ccp.h" +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT +#include "netif/ppp/mppe.h" +#endif /* MPPE_SUPPORT */ +#if ECP_SUPPORT +#include "netif/ppp/ecp.h" +#endif /* EAP_SUPPORT */ +#if VJ_SUPPORT +#include "netif/ppp/vj.h" +#endif /* VJ_SUPPORT */ +#if PPP_IPV4_SUPPORT +#include "netif/ppp/ipcp.h" +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +#include "netif/ppp/ipv6cp.h" +#endif /* PPP_IPV6_SUPPORT */ + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* Memory pools */ +#if PPPOS_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOS_PCB); +#endif +#if PPPOE_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOE_IF); +#endif +#if PPPOL2TP_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOL2TP_PCB); +#endif +#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL_PROTOTYPE(PPPAPI_MSG); +#endif +LWIP_MEMPOOL_DECLARE(PPP_PCB, MEMP_NUM_PPP_PCB, sizeof(ppp_pcb), "PPP_PCB") + +/* FIXME: add stats per PPP session */ +#if PPP_STATS_SUPPORT +static struct timeval start_time; /* Time when link was started. */ +static struct pppd_stats old_link_stats; +struct pppd_stats link_stats; +unsigned link_connect_time; +int link_stats_valid; +#endif /* PPP_STATS_SUPPORT */ + +/* + * PPP Data Link Layer "protocol" table. + * One entry per supported protocol. + * The last entry must be NULL. + */ +const struct protent* const protocols[] = { + &lcp_protent, +#if PAP_SUPPORT + &pap_protent, +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + &chap_protent, +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT + &cbcp_protent, +#endif /* CBCP_SUPPORT */ +#if PPP_IPV4_SUPPORT + &ipcp_protent, +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + &ipv6cp_protent, +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT + &ccp_protent, +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT + &ecp_protent, +#endif /* ECP_SUPPORT */ +#ifdef AT_CHANGE + &atcp_protent, +#endif /* AT_CHANGE */ +#if EAP_SUPPORT + &eap_protent, +#endif /* EAP_SUPPORT */ + NULL +}; + +/* Prototypes for procedures local to this file. */ +static void ppp_do_connect(void *arg); +static err_t ppp_netif_init_cb(struct netif *netif); +#if PPP_IPV4_SUPPORT +static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr); +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr); +#endif /* PPP_IPV6_SUPPORT */ +static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol); + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +#if PPP_AUTH_SUPPORT +void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd) { + LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD", pcb->phase == PPP_PHASE_DEAD); + +#if PAP_SUPPORT + pcb->settings.refuse_pap = !(authtype & PPPAUTHTYPE_PAP); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + pcb->settings.refuse_chap = !(authtype & PPPAUTHTYPE_CHAP); +#if MSCHAP_SUPPORT + pcb->settings.refuse_mschap = !(authtype & PPPAUTHTYPE_MSCHAP); + pcb->settings.refuse_mschap_v2 = !(authtype & PPPAUTHTYPE_MSCHAP_V2); +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + pcb->settings.refuse_eap = !(authtype & PPPAUTHTYPE_EAP); +#endif /* EAP_SUPPORT */ + pcb->settings.user = user; + pcb->settings.passwd = passwd; +} +#endif /* PPP_AUTH_SUPPORT */ + +#if MPPE_SUPPORT +/* Set MPPE configuration */ +void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) { + LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD", pcb->phase == PPP_PHASE_DEAD); + + if (flags == PPP_MPPE_DISABLE) { + pcb->settings.require_mppe = 0; + return; + } + + pcb->settings.require_mppe = 1; + pcb->settings.refuse_mppe_stateful = !(flags & PPP_MPPE_ALLOW_STATEFUL); + pcb->settings.refuse_mppe_40 = !!(flags & PPP_MPPE_REFUSE_40); + pcb->settings.refuse_mppe_128 = !!(flags & PPP_MPPE_REFUSE_128); +} +#endif /* MPPE_SUPPORT */ + +#if PPP_NOTIFY_PHASE +void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { + pcb->notify_phase_cb = notify_phase_cb; + notify_phase_cb(pcb, pcb->phase, pcb->ctx_cb); +} +#endif /* PPP_NOTIFY_PHASE */ + +/* + * Initiate a PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * Holdoff is the time to wait (in seconds) before initiating + * the connection. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff) { + LWIP_ASSERT_CORE_LOCKED(); + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_ALREADY; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_connect[%d]: holdoff=%d\n", pcb->netif->num, holdoff)); + + magic_randomize(); + + if (holdoff == 0) { + ppp_do_connect(pcb); + return ERR_OK; + } + + new_phase(pcb, PPP_PHASE_HOLDOFF); + sys_timeout((u32_t)(holdoff*1000), ppp_do_connect, pcb); + return ERR_OK; +} + +#if PPP_SERVER +/* + * Listen for an incoming PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_listen(ppp_pcb *pcb) { + LWIP_ASSERT_CORE_LOCKED(); + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_ALREADY; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_listen[%d]\n", pcb->netif->num)); + + magic_randomize(); + + if (pcb->link_cb->listen) { + new_phase(pcb, PPP_PHASE_INITIALIZE); + pcb->link_cb->listen(pcb, pcb->link_ctx_cb); + return ERR_OK; + } + return ERR_IF; +} +#endif /* PPP_SERVER */ + +/* + * Initiate the end of a PPP connection. + * Any outstanding packets in the queues are dropped. + * + * Setting nocarrier to 1 close the PPP connection without initiating the + * shutdown procedure. Always using nocarrier = 0 is still recommended, + * this is going to take a little longer time if your link is down, but + * is a safer choice for the PPP state machine. + * + * Return 0 on success, an error code on failure. + */ +err_t +ppp_close(ppp_pcb *pcb, u8_t nocarrier) +{ + LWIP_ASSERT_CORE_LOCKED(); + + pcb->err_code = PPPERR_USER; + + /* holdoff phase, cancel the reconnection */ + if (pcb->phase == PPP_PHASE_HOLDOFF) { + sys_untimeout(ppp_do_connect, pcb); + new_phase(pcb, PPP_PHASE_DEAD); + } + + /* dead phase, nothing to do, call the status callback to be consistent */ + if (pcb->phase == PPP_PHASE_DEAD) { + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return ERR_OK; + } + + /* Already terminating, nothing to do */ + if (pcb->phase >= PPP_PHASE_TERMINATE) { + return ERR_INPROGRESS; + } + + /* LCP not open, close link protocol */ + if (pcb->phase < PPP_PHASE_ESTABLISH) { + new_phase(pcb, PPP_PHASE_DISCONNECT); + ppp_link_terminated(pcb); + return ERR_OK; + } + + /* + * Only accept carrier lost signal on the stable running phase in order + * to prevent changing the PPP phase FSM in transition phases. + * + * Always using nocarrier = 0 is still recommended, this is going to + * take a little longer time, but is a safer choice from FSM point of view. + */ + if (nocarrier && pcb->phase == PPP_PHASE_RUNNING) { + PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: carrier lost -> lcp_lowerdown\n", pcb->netif->num)); + lcp_lowerdown(pcb); + /* forced link termination, this will force link protocol to disconnect. */ + link_terminated(pcb); + return ERR_OK; + } + + /* Disconnect */ + PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: kill_link -> lcp_close\n", pcb->netif->num)); + /* LCP soft close request. */ + lcp_close(pcb, "User request"); + return ERR_OK; +} + +/* + * Release the control block. + * + * This can only be called if PPP is in the dead phase. + * + * You must use ppp_close() before if you wish to terminate + * an established PPP session. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_free(ppp_pcb *pcb) { + err_t err; + LWIP_ASSERT_CORE_LOCKED(); + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_CONN; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_free[%d]\n", pcb->netif->num)); + + netif_remove(pcb->netif); + + err = pcb->link_cb->free(pcb, pcb->link_ctx_cb); + + LWIP_MEMPOOL_FREE(PPP_PCB, pcb); + return err; +} + +/* Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. */ +err_t +ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg) +{ + LWIP_ASSERT_CORE_LOCKED(); + if (pcb == NULL) { + return ERR_VAL; + } + + switch(cmd) { + case PPPCTLG_UPSTATUS: /* Get the PPP up status. */ + if (!arg) { + goto fail; + } + *(int *)arg = (int)(0 +#if PPP_IPV4_SUPPORT + || pcb->if4_up +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || pcb->if6_up +#endif /* PPP_IPV6_SUPPORT */ + ); + return ERR_OK; + + case PPPCTLG_ERRCODE: /* Get the PPP error code. */ + if (!arg) { + goto fail; + } + *(int *)arg = (int)(pcb->err_code); + return ERR_OK; + + default: + goto fail; + } + +fail: + return ERR_VAL; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +static void ppp_do_connect(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); + + new_phase(pcb, PPP_PHASE_INITIALIZE); + pcb->link_cb->connect(pcb, pcb->link_ctx_cb); +} + +/* + * ppp_netif_init_cb - netif init callback + */ +static err_t ppp_netif_init_cb(struct netif *netif) { + netif->name[0] = 'p'; + netif->name[1] = 'p'; +#if PPP_IPV4_SUPPORT + netif->output = ppp_netif_output_ip4; +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + netif->output_ip6 = ppp_netif_output_ip6; +#endif /* PPP_IPV6_SUPPORT */ + netif->flags = NETIF_FLAG_UP; +#if LWIP_NETIF_HOSTNAME + /* @todo: Initialize interface hostname */ + /* netif_set_hostname(netif, "lwip"); */ +#endif /* LWIP_NETIF_HOSTNAME */ + return ERR_OK; +} + +#if PPP_IPV4_SUPPORT +/* + * Send an IPv4 packet on the given connection. + */ +static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr) { + LWIP_UNUSED_ARG(ipaddr); + return ppp_netif_output(netif, pb, PPP_IP); +} +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +/* + * Send an IPv6 packet on the given connection. + */ +static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr) { + LWIP_UNUSED_ARG(ipaddr); + return ppp_netif_output(netif, pb, PPP_IPV6); +} +#endif /* PPP_IPV6_SUPPORT */ + +static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol) { + ppp_pcb *pcb = (ppp_pcb*)netif->state; + err_t err; + struct pbuf *fpb = NULL; + + /* Check that the link is up. */ + if (0 +#if PPP_IPV4_SUPPORT + || (protocol == PPP_IP && !pcb->if4_up) +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || (protocol == PPP_IPV6 && !pcb->if6_up) +#endif /* PPP_IPV6_SUPPORT */ + ) { + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: link not up\n", pcb->netif->num)); + goto err_rte_drop; + } + +#if MPPE_SUPPORT + /* If MPPE is required, refuse any IP packet until we are able to crypt them. */ + if (pcb->settings.require_mppe && pcb->ccp_transmit_method != CI_MPPE) { + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: MPPE required, not up\n", pcb->netif->num)); + goto err_rte_drop; + } +#endif /* MPPE_SUPPORT */ + +#if VJ_SUPPORT + /* + * Attempt Van Jacobson header compression if VJ is configured and + * this is an IP packet. + */ + if (protocol == PPP_IP && pcb->vj_enabled) { + switch (vj_compress_tcp(&pcb->vj_comp, &pb)) { + case TYPE_IP: + /* No change... + protocol = PPP_IP; */ + break; + case TYPE_COMPRESSED_TCP: + /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_VJC_COMP; + break; + case TYPE_UNCOMPRESSED_TCP: + /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_VJC_UNCOMP; + break; + default: + PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: bad IP packet\n", pcb->netif->num)); + LINK_STATS_INC(link.proterr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pcb->netif, ifoutdiscards); + return ERR_VAL; + } + } +#endif /* VJ_SUPPORT */ + +#if CCP_SUPPORT + switch (pcb->ccp_transmit_method) { + case 0: + break; /* Don't compress */ +#if MPPE_SUPPORT + case CI_MPPE: + if ((err = mppe_compress(pcb, &pcb->mppe_comp, &pb, protocol)) != ERR_OK) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + goto err; + } + /* if VJ compressor returned a new allocated pbuf, free it */ + if (fpb) { + pbuf_free(fpb); + } + /* mppe_compress() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_COMP; + break; +#endif /* MPPE_SUPPORT */ + default: + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: bad CCP transmit method\n", pcb->netif->num)); + goto err_rte_drop; /* Cannot really happen, we only negotiate what we are able to do */ + } +#endif /* CCP_SUPPORT */ + + err = pcb->link_cb->netif_output(pcb, pcb->link_ctx_cb, pb, protocol); + goto err; + +err_rte_drop: + err = ERR_RTE; + LINK_STATS_INC(link.rterr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); +err: + if (fpb) { + pbuf_free(fpb); + } + return err; +} + +/************************************/ +/*** PRIVATE FUNCTION DEFINITIONS ***/ +/************************************/ + +/* Initialize the PPP subsystem. */ +int ppp_init(void) +{ +#if PPPOS_SUPPORT + LWIP_MEMPOOL_INIT(PPPOS_PCB); +#endif +#if PPPOE_SUPPORT + LWIP_MEMPOOL_INIT(PPPOE_IF); +#endif +#if PPPOL2TP_SUPPORT + LWIP_MEMPOOL_INIT(PPPOL2TP_PCB); +#endif +#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE + LWIP_MEMPOOL_INIT(PPPAPI_MSG); +#endif + + LWIP_MEMPOOL_INIT(PPP_PCB); + + /* + * Initialize magic number generator now so that protocols may + * use magic numbers in initialization. + */ + magic_init(); + + return 0; +} + +/* + * Create a new PPP control block. + * + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. + * + * Return a new PPP connection control block pointer + * on success or a null pointer on failure. + */ +ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { + ppp_pcb *pcb; + const struct protent *protp; + int i; + + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + if (link_status_cb == NULL) { + return NULL; + } + + pcb = (ppp_pcb*)LWIP_MEMPOOL_ALLOC(PPP_PCB); + if (pcb == NULL) { + return NULL; + } + + memset(pcb, 0, sizeof(ppp_pcb)); + + /* default configuration */ +#if PAP_SUPPORT + pcb->settings.pap_timeout_time = UPAP_DEFTIMEOUT; + pcb->settings.pap_max_transmits = UPAP_DEFTRANSMITS; +#if PPP_SERVER + pcb->settings.pap_req_timeout = UPAP_DEFREQTIME; +#endif /* PPP_SERVER */ +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT; + pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS; +#if PPP_SERVER + pcb->settings.chap_rechallenge_time = CHAP_DEFRECHALLENGETIME; +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPPORT */ + +#if EAP_SUPPORT + pcb->settings.eap_req_time = EAP_DEFREQTIME; + pcb->settings.eap_allow_req = EAP_DEFALLOWREQ; +#if PPP_SERVER + pcb->settings.eap_timeout_time = EAP_DEFTIMEOUT; + pcb->settings.eap_max_transmits = EAP_DEFTRANSMITS; +#endif /* PPP_SERVER */ +#endif /* EAP_SUPPORT */ + + pcb->settings.lcp_loopbackfail = LCP_DEFLOOPBACKFAIL; + pcb->settings.lcp_echo_interval = LCP_ECHOINTERVAL; + pcb->settings.lcp_echo_fails = LCP_MAXECHOFAILS; + + pcb->settings.fsm_timeout_time = FSM_DEFTIMEOUT; + pcb->settings.fsm_max_conf_req_transmits = FSM_DEFMAXCONFREQS; + pcb->settings.fsm_max_term_transmits = FSM_DEFMAXTERMREQS; + pcb->settings.fsm_max_nak_loops = FSM_DEFMAXNAKLOOPS; + + pcb->netif = pppif; + MIB2_INIT_NETIF(pppif, snmp_ifType_ppp, 0); + if (!netif_add(pcb->netif, +#if LWIP_IPV4 + IP4_ADDR_ANY4, IP4_ADDR_BROADCAST, IP4_ADDR_ANY4, +#endif /* LWIP_IPV4 */ + (void *)pcb, ppp_netif_init_cb, NULL)) { + LWIP_MEMPOOL_FREE(PPP_PCB, pcb); + PPPDEBUG(LOG_ERR, ("ppp_new: netif_add failed\n")); + return NULL; + } + + pcb->link_cb = callbacks; + pcb->link_ctx_cb = link_ctx_cb; + pcb->link_status_cb = link_status_cb; + pcb->ctx_cb = ctx_cb; + + /* + * Initialize each protocol. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + (*protp->init)(pcb); + } + + new_phase(pcb, PPP_PHASE_DEAD); + return pcb; +} + +/** Initiate LCP open request */ +void ppp_start(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]\n", pcb->netif->num)); + + /* Clean data not taken care by anything else, mostly shared data. */ +#if PPP_STATS_SUPPORT + link_stats_valid = 0; +#endif /* PPP_STATS_SUPPORT */ +#if MPPE_SUPPORT + pcb->mppe_keys_set = 0; + memset(&pcb->mppe_comp, 0, sizeof(pcb->mppe_comp)); + memset(&pcb->mppe_decomp, 0, sizeof(pcb->mppe_decomp)); +#endif /* MPPE_SUPPORT */ +#if VJ_SUPPORT + vj_compress_init(&pcb->vj_comp); +#endif /* VJ_SUPPORT */ + + /* Start protocol */ + new_phase(pcb, PPP_PHASE_ESTABLISH); + lcp_open(pcb); + lcp_lowerup(pcb); + PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]: finished\n", pcb->netif->num)); +} + +/** Called when link failed to setup */ +void ppp_link_failed(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_failed[%d]\n", pcb->netif->num)); + new_phase(pcb, PPP_PHASE_DEAD); + pcb->err_code = PPPERR_OPEN; + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); +} + +/** Called when link is normally down (i.e. it was asked to end) */ +void ppp_link_end(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_end[%d]\n", pcb->netif->num)); + new_phase(pcb, PPP_PHASE_DEAD); + if (pcb->err_code == PPPERR_NONE) { + pcb->err_code = PPPERR_CONNECT; + } + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); +} + +/* + * Pass the processed input packet to the appropriate handler. + * This function and all handlers run in the context of the tcpip_thread + */ +void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { + u16_t protocol; +#if PPP_DEBUG && PPP_PROTOCOLNAME + const char *pname; +#endif /* PPP_DEBUG && PPP_PROTOCOLNAME */ + + magic_randomize(); + + if (pb->len < 2) { + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: packet too short\n", pcb->netif->num)); + goto drop; + } + protocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; + +#if PRINTPKT_SUPPORT + ppp_dump_packet(pcb, "rcvd", (unsigned char *)pb->payload, pb->len); +#endif /* PRINTPKT_SUPPORT */ + + pbuf_remove_header(pb, sizeof(protocol)); + + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_INC(pcb->netif, ifinucastpkts); + MIB2_STATS_NETIF_ADD(pcb->netif, ifinoctets, pb->tot_len); + + /* + * Toss all non-LCP packets unless LCP is OPEN. + */ + if (protocol != PPP_LCP && pcb->lcp_fsm.state != PPP_FSM_OPENED) { + ppp_dbglog("Discarded non-LCP packet when LCP not open"); + goto drop; + } + + /* + * Until we get past the authentication phase, toss all packets + * except LCP, LQR and authentication packets. + */ + if (pcb->phase <= PPP_PHASE_AUTHENTICATE + && !(protocol == PPP_LCP +#if LQR_SUPPORT + || protocol == PPP_LQR +#endif /* LQR_SUPPORT */ +#if PAP_SUPPORT + || protocol == PPP_PAP +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || protocol == PPP_CHAP +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || protocol == PPP_EAP +#endif /* EAP_SUPPORT */ + )) { + ppp_dbglog("discarding proto 0x%x in phase %d", protocol, pcb->phase); + goto drop; + } + +#if CCP_SUPPORT +#if MPPE_SUPPORT + /* + * MPPE is required and unencrypted data has arrived (this + * should never happen!). We should probably drop the link if + * the protocol is in the range of what should be encrypted. + * At the least, we drop this packet. + */ + if (pcb->settings.require_mppe && protocol != PPP_COMP && protocol < 0x8000) { + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: MPPE required, received unencrypted data!\n", pcb->netif->num)); + goto drop; + } +#endif /* MPPE_SUPPORT */ + + if (protocol == PPP_COMP) { + u8_t *pl; + + switch (pcb->ccp_receive_method) { +#if MPPE_SUPPORT + case CI_MPPE: + if (mppe_decompress(pcb, &pcb->mppe_decomp, &pb) != ERR_OK) { + goto drop; + } + break; +#endif /* MPPE_SUPPORT */ + default: + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: bad CCP receive method\n", pcb->netif->num)); + goto drop; /* Cannot really happen, we only negotiate what we are able to do */ + } + + /* Assume no PFC */ + if (pb->len < 2) { + goto drop; + } + + /* Extract and hide protocol (do PFC decompression if necessary) */ + pl = (u8_t*)pb->payload; + if (pl[0] & 0x01) { + protocol = pl[0]; + pbuf_remove_header(pb, 1); + } else { + protocol = (pl[0] << 8) | pl[1]; + pbuf_remove_header(pb, 2); + } + } +#endif /* CCP_SUPPORT */ + + switch(protocol) { + +#if PPP_IPV4_SUPPORT + case PPP_IP: /* Internet Protocol */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + ip4_input(pb, pcb->netif); + return; +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT + case PPP_IPV6: /* Internet Protocol Version 6 */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip6 in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + ip6_input(pb, pcb->netif); + return; +#endif /* PPP_IPV6_SUPPORT */ + +#if VJ_SUPPORT + case PPP_VJC_COMP: /* VJ compressed TCP */ + /* + * Clip off the VJ header and prepend the rebuilt TCP/IP header and + * pass the result to IP. + */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_comp in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + if (pcb->vj_enabled && vj_uncompress_tcp(&pb, &pcb->vj_comp) >= 0) { + ip4_input(pb, pcb->netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ compressed\n", pcb->netif->num)); + break; + + case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ + /* + * Process the TCP/IP header for VJ header compression and then pass + * the packet to IP. + */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_un in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + if (pcb->vj_enabled && vj_uncompress_uncomp(pb, &pcb->vj_comp) >= 0) { + ip4_input(pb, pcb->netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ uncompressed\n", pcb->netif->num)); + break; +#endif /* VJ_SUPPORT */ + + default: { + int i; + const struct protent *protp; + + /* + * Upcall the proper protocol input routine. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol == protocol) { + pb = pbuf_coalesce(pb, PBUF_RAW); + (*protp->input)(pcb, (u8_t*)pb->payload, pb->len); + goto out; + } +#if 0 /* UNUSED + * + * This is actually a (hacked?) way for the Linux kernel to pass a data + * packet to pppd. pppd in normal condition only do signaling + * (LCP, PAP, CHAP, IPCP, ...) and does not handle any data packet at all. + * + * We don't even need this interface, which is only there because of PPP + * interface limitation between Linux kernel and pppd. For MPPE, which uses + * CCP to negotiate although it is not really a (de)compressor, we added + * ccp_resetrequest() in CCP and MPPE input data flow is calling either + * ccp_resetrequest() or lcp_close() if the issue is, respectively, non-fatal + * or fatal, this is what ccp_datainput() really do. + */ + if (protocol == (protp->protocol & ~0x8000) + && protp->datainput != NULL) { + (*protp->datainput)(pcb, pb->payload, pb->len); + goto out; + } +#endif /* UNUSED */ + } + +#if PPP_DEBUG +#if PPP_PROTOCOLNAME + pname = protocol_name(protocol); + if (pname != NULL) { + ppp_warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); + } else +#endif /* PPP_PROTOCOLNAME */ + ppp_warn("Unsupported protocol 0x%x received", protocol); +#endif /* PPP_DEBUG */ + if (pbuf_add_header(pb, sizeof(protocol))) { + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_add_header failed)\n", pcb->netif->num)); + goto drop; + } + lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len); + } + break; + } + +drop: + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pcb->netif, ifindiscards); + +out: + pbuf_free(pb); +} + +/* + * Write a pbuf to a ppp link, only used from PPP functions + * to send PPP packets. + * + * IPv4 and IPv6 packets from lwIP are sent, respectively, + * with ppp_netif_output_ip4() and ppp_netif_output_ip6() + * functions (which are callbacks of the netif PPP interface). + */ +err_t ppp_write(ppp_pcb *pcb, struct pbuf *p) { +#if PRINTPKT_SUPPORT + ppp_dump_packet(pcb, "sent", (unsigned char *)p->payload+2, p->len-2); +#endif /* PRINTPKT_SUPPORT */ + return pcb->link_cb->write(pcb, pcb->link_ctx_cb, p); +} + +void ppp_link_terminated(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]\n", pcb->netif->num)); + pcb->link_cb->disconnect(pcb, pcb->link_ctx_cb); + PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]: finished.\n", pcb->netif->num)); +} + + +/************************************************************************ + * Functions called by various PPP subsystems to configure + * the PPP interface or change the PPP phase. + */ + +/* + * new_phase - signal the start of a new phase of pppd's operation. + */ +void new_phase(ppp_pcb *pcb, int p) { + pcb->phase = p; + PPPDEBUG(LOG_DEBUG, ("ppp phase changed[%d]: phase=%d\n", pcb->netif->num, pcb->phase)); +#if PPP_NOTIFY_PHASE + if (pcb->notify_phase_cb != NULL) { + pcb->notify_phase_cb(pcb, p, pcb->ctx_cb); + } +#endif /* PPP_NOTIFY_PHASE */ +} + +/* + * ppp_send_config - configure the transmit-side characteristics of + * the ppp interface. + */ +int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { + LWIP_UNUSED_ARG(mtu); + /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */ + + if (pcb->link_cb->send_config) { + pcb->link_cb->send_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); + } + + PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num) ); + return 0; +} + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. + */ +int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) { + LWIP_UNUSED_ARG(mru); + + if (pcb->link_cb->recv_config) { + pcb->link_cb->recv_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); + } + + PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num)); + return 0; +} + +#if PPP_IPV4_SUPPORT +/* + * sifaddr - Config the interface IP addresses and netmask. + */ +int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask) { + ip4_addr_t ip, nm, gw; + + ip4_addr_set_u32(&ip, our_adr); + ip4_addr_set_u32(&nm, netmask); + ip4_addr_set_u32(&gw, his_adr); + netif_set_addr(pcb->netif, &ip, &nm, &gw); + return 1; +} + +/******************************************************************** + * + * cifaddr - Clear the interface IP addresses, and delete routes + * through the interface if possible. + */ +int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr) { + LWIP_UNUSED_ARG(our_adr); + LWIP_UNUSED_ARG(his_adr); + + netif_set_addr(pcb->netif, IP4_ADDR_ANY4, IP4_ADDR_BROADCAST, IP4_ADDR_ANY4); + return 1; +} + +#if 0 /* UNUSED - PROXY ARP */ +/******************************************************************** + * + * sifproxyarp - Make a proxy ARP entry for the peer. + */ + +int sifproxyarp(ppp_pcb *pcb, u32_t his_adr) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(his_adr); + return 0; +} + +/******************************************************************** + * + * cifproxyarp - Delete the proxy ARP entry for the peer. + */ + +int cifproxyarp(ppp_pcb *pcb, u32_t his_adr) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(his_adr); + return 0; +} +#endif /* UNUSED - PROXY ARP */ + +#if LWIP_DNS +/* + * sdns - Config the DNS servers + */ +int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { + ip_addr_t ns; + LWIP_UNUSED_ARG(pcb); + + ip_addr_set_ip4_u32_val(ns, ns1); + dns_setserver(0, &ns); + ip_addr_set_ip4_u32_val(ns, ns2); + dns_setserver(1, &ns); + return 1; +} + +/******************************************************************** + * + * cdns - Clear the DNS servers + */ +int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { + const ip_addr_t *nsa; + ip_addr_t nsb; + LWIP_UNUSED_ARG(pcb); + + nsa = dns_getserver(0); + ip_addr_set_ip4_u32_val(nsb, ns1); + if (ip_addr_cmp(nsa, &nsb)) { + dns_setserver(0, IP_ADDR_ANY); + } + nsa = dns_getserver(1); + ip_addr_set_ip4_u32_val(nsb, ns2); + if (ip_addr_cmp(nsa, &nsb)) { + dns_setserver(1, IP_ADDR_ANY); + } + return 1; +} +#endif /* LWIP_DNS */ + +#if VJ_SUPPORT +/******************************************************************** + * + * sifvjcomp - config tcp header compression + */ +int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid) { + pcb->vj_enabled = vjcomp; + pcb->vj_comp.compressSlot = cidcomp; + pcb->vj_comp.maxSlotIndex = maxcid; + PPPDEBUG(LOG_INFO, ("sifvjcomp[%d]: VJ compress enable=%d slot=%d max slot=%d\n", + pcb->netif->num, vjcomp, cidcomp, maxcid)); + return 0; +} +#endif /* VJ_SUPPORT */ + +/* + * sifup - Config the interface up and enable IP packets to pass. + */ +int sifup(ppp_pcb *pcb) { + pcb->if4_up = 1; + pcb->err_code = PPPERR_NONE; + netif_set_link_up(pcb->netif); + + PPPDEBUG(LOG_DEBUG, ("sifup[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return 1; +} + +/******************************************************************** + * + * sifdown - Disable the indicated protocol and config the interface + * down if there are no remaining protocols. + */ +int sifdown(ppp_pcb *pcb) { + + pcb->if4_up = 0; + + if (1 +#if PPP_IPV6_SUPPORT + /* set the interface down if IPv6 is down as well */ + && !pcb->if6_up +#endif /* PPP_IPV6_SUPPORT */ + ) { + /* make sure the netif link callback is called */ + netif_set_link_down(pcb->netif); + } + PPPDEBUG(LOG_DEBUG, ("sifdown[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + return 1; +} + +/******************************************************************** + * + * Return user specified netmask, modified by any mask we might determine + * for address `addr' (in network byte order). + * Here we scan through the system's list of interfaces, looking for + * any non-point-to-point interfaces which might appear to be on the same + * network as `addr'. If we find any, we OR in their netmask to the + * user-specified netmask. + */ +u32_t get_mask(u32_t addr) { +#if 0 + u32_t mask, nmask; + + addr = lwip_htonl(addr); + if (IP_CLASSA(addr)) { /* determine network mask for address class */ + nmask = IP_CLASSA_NET; + } else if (IP_CLASSB(addr)) { + nmask = IP_CLASSB_NET; + } else { + nmask = IP_CLASSC_NET; + } + + /* class D nets are disallowed by bad_ip_adrs */ + mask = PP_HTONL(0xffffff00UL) | lwip_htonl(nmask); + + /* XXX + * Scan through the system's network interfaces. + * Get each netmask and OR them into our mask. + */ + /* return mask; */ + return mask; +#endif /* 0 */ + LWIP_UNUSED_ARG(addr); + return IPADDR_BROADCAST; +} +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +#define IN6_LLADDR_FROM_EUI64(ip6, eui64) do { \ + ip6.addr[0] = PP_HTONL(0xfe800000); \ + ip6.addr[1] = 0; \ + eui64_copy(eui64, ip6.addr[2]); \ + } while (0) + +/******************************************************************** + * + * sif6addr - Config the interface with an IPv6 link-local address + */ +int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { + ip6_addr_t ip6; + LWIP_UNUSED_ARG(his_eui64); + + IN6_LLADDR_FROM_EUI64(ip6, our_eui64); + netif_ip6_addr_set(pcb->netif, 0, &ip6); + netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_PREFERRED); + /* FIXME: should we add an IPv6 static neighbor using his_eui64 ? */ + return 1; +} + +/******************************************************************** + * + * cif6addr - Remove IPv6 address from interface + */ +int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { + LWIP_UNUSED_ARG(our_eui64); + LWIP_UNUSED_ARG(his_eui64); + + netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_INVALID); + netif_ip6_addr_set(pcb->netif, 0, IP6_ADDR_ANY6); + return 1; +} + +/* + * sif6up - Config the interface up and enable IPv6 packets to pass. + */ +int sif6up(ppp_pcb *pcb) { + + pcb->if6_up = 1; + pcb->err_code = PPPERR_NONE; + netif_set_link_up(pcb->netif); + + PPPDEBUG(LOG_DEBUG, ("sif6up[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return 1; +} + +/******************************************************************** + * + * sif6down - Disable the indicated protocol and config the interface + * down if there are no remaining protocols. + */ +int sif6down(ppp_pcb *pcb) { + + pcb->if6_up = 0; + + if (1 +#if PPP_IPV4_SUPPORT + /* set the interface down if IPv4 is down as well */ + && !pcb->if4_up +#endif /* PPP_IPV4_SUPPORT */ + ) { + /* make sure the netif link callback is called */ + netif_set_link_down(pcb->netif); + } + PPPDEBUG(LOG_DEBUG, ("sif6down[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + return 1; +} +#endif /* PPP_IPV6_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(proto); + LWIP_UNUSED_ARG(mode); + return 0; +} +#endif /* DEMAND_SUPPORT */ + +/* + * netif_set_mtu - set the MTU on the PPP network interface. + */ +void netif_set_mtu(ppp_pcb *pcb, int mtu) { + + pcb->netif->mtu = mtu; + PPPDEBUG(LOG_INFO, ("netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu)); +} + +/* + * netif_get_mtu - get PPP interface MTU + */ +int netif_get_mtu(ppp_pcb *pcb) { + + return pcb->netif->mtu; +} + +#if CCP_SUPPORT +#if 0 /* unused */ +/* + * ccp_test - whether a given compression method is acceptable for use. + */ +int +ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(opt_ptr); + LWIP_UNUSED_ARG(opt_len); + LWIP_UNUSED_ARG(for_transmit); + return -1; +} +#endif /* unused */ + +/* + * ccp_set - inform about the current state of CCP. + */ +void +ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method) +{ + LWIP_UNUSED_ARG(isopen); + LWIP_UNUSED_ARG(isup); + pcb->ccp_receive_method = receive_method; + pcb->ccp_transmit_method = transmit_method; + PPPDEBUG(LOG_DEBUG, ("ccp_set[%d]: is_open=%d, is_up=%d, receive_method=%u, transmit_method=%u\n", + pcb->netif->num, isopen, isup, receive_method, transmit_method)); +} + +void +ccp_reset_comp(ppp_pcb *pcb) +{ + switch (pcb->ccp_transmit_method) { +#if MPPE_SUPPORT + case CI_MPPE: + mppe_comp_reset(pcb, &pcb->mppe_comp); + break; +#endif /* MPPE_SUPPORT */ + default: + break; + } +} + +void +ccp_reset_decomp(ppp_pcb *pcb) +{ + switch (pcb->ccp_receive_method) { +#if MPPE_SUPPORT + case CI_MPPE: + mppe_decomp_reset(pcb, &pcb->mppe_decomp); + break; +#endif /* MPPE_SUPPORT */ + default: + break; + } +} + +#if 0 /* unused */ +/* + * ccp_fatal_error - returns 1 if decompression was disabled as a + * result of an error detected after decompression of a packet, + * 0 otherwise. This is necessary because of patent nonsense. + */ +int +ccp_fatal_error(ppp_pcb *pcb) +{ + LWIP_UNUSED_ARG(pcb); + return 1; +} +#endif /* unused */ +#endif /* CCP_SUPPORT */ + +#if PPP_IDLETIMELIMIT +/******************************************************************** + * + * get_idle_time - return how long the link has been idle. + */ +int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip) { + /* FIXME: add idle time support and make it optional */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(ip); + return 1; +} +#endif /* PPP_IDLETIMELIMIT */ + +#if DEMAND_SUPPORT +/******************************************************************** + * + * get_loop_output - get outgoing packets from the ppp device, + * and detect when we want to bring the real link up. + * Return value is 1 if we need to bring up the link, 0 otherwise. + */ +int get_loop_output(void) { + return 0; +} +#endif /* DEMAND_SUPPORT */ + +#if PPP_PROTOCOLNAME +/* List of protocol names, to make our messages a little more informative. */ +struct protocol_list { + u_short proto; + const char *name; +} const protocol_list[] = { + { 0x21, "IP" }, + { 0x23, "OSI Network Layer" }, + { 0x25, "Xerox NS IDP" }, + { 0x27, "DECnet Phase IV" }, + { 0x29, "Appletalk" }, + { 0x2b, "Novell IPX" }, + { 0x2d, "VJ compressed TCP/IP" }, + { 0x2f, "VJ uncompressed TCP/IP" }, + { 0x31, "Bridging PDU" }, + { 0x33, "Stream Protocol ST-II" }, + { 0x35, "Banyan Vines" }, + { 0x39, "AppleTalk EDDP" }, + { 0x3b, "AppleTalk SmartBuffered" }, + { 0x3d, "Multi-Link" }, + { 0x3f, "NETBIOS Framing" }, + { 0x41, "Cisco Systems" }, + { 0x43, "Ascom Timeplex" }, + { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, + { 0x47, "DCA Remote Lan" }, + { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, + { 0x4b, "SNA over 802.2" }, + { 0x4d, "SNA" }, + { 0x4f, "IP6 Header Compression" }, + { 0x51, "KNX Bridging Data" }, + { 0x53, "Encryption" }, + { 0x55, "Individual Link Encryption" }, + { 0x57, "IPv6" }, + { 0x59, "PPP Muxing" }, + { 0x5b, "Vendor-Specific Network Protocol" }, + { 0x61, "RTP IPHC Full Header" }, + { 0x63, "RTP IPHC Compressed TCP" }, + { 0x65, "RTP IPHC Compressed non-TCP" }, + { 0x67, "RTP IPHC Compressed UDP 8" }, + { 0x69, "RTP IPHC Compressed RTP 8" }, + { 0x6f, "Stampede Bridging" }, + { 0x73, "MP+" }, + { 0xc1, "NTCITS IPI" }, + { 0xfb, "single-link compression" }, + { 0xfd, "Compressed Datagram" }, + { 0x0201, "802.1d Hello Packets" }, + { 0x0203, "IBM Source Routing BPDU" }, + { 0x0205, "DEC LANBridge100 Spanning Tree" }, + { 0x0207, "Cisco Discovery Protocol" }, + { 0x0209, "Netcs Twin Routing" }, + { 0x020b, "STP - Scheduled Transfer Protocol" }, + { 0x020d, "EDP - Extreme Discovery Protocol" }, + { 0x0211, "Optical Supervisory Channel Protocol" }, + { 0x0213, "Optical Supervisory Channel Protocol" }, + { 0x0231, "Luxcom" }, + { 0x0233, "Sigma Network Systems" }, + { 0x0235, "Apple Client Server Protocol" }, + { 0x0281, "MPLS Unicast" }, + { 0x0283, "MPLS Multicast" }, + { 0x0285, "IEEE p1284.4 standard - data packets" }, + { 0x0287, "ETSI TETRA Network Protocol Type 1" }, + { 0x0289, "Multichannel Flow Treatment Protocol" }, + { 0x2063, "RTP IPHC Compressed TCP No Delta" }, + { 0x2065, "RTP IPHC Context State" }, + { 0x2067, "RTP IPHC Compressed UDP 16" }, + { 0x2069, "RTP IPHC Compressed RTP 16" }, + { 0x4001, "Cray Communications Control Protocol" }, + { 0x4003, "CDPD Mobile Network Registration Protocol" }, + { 0x4005, "Expand accelerator protocol" }, + { 0x4007, "ODSICP NCP" }, + { 0x4009, "DOCSIS DLL" }, + { 0x400B, "Cetacean Network Detection Protocol" }, + { 0x4021, "Stacker LZS" }, + { 0x4023, "RefTek Protocol" }, + { 0x4025, "Fibre Channel" }, + { 0x4027, "EMIT Protocols" }, + { 0x405b, "Vendor-Specific Protocol (VSP)" }, + { 0x8021, "Internet Protocol Control Protocol" }, + { 0x8023, "OSI Network Layer Control Protocol" }, + { 0x8025, "Xerox NS IDP Control Protocol" }, + { 0x8027, "DECnet Phase IV Control Protocol" }, + { 0x8029, "Appletalk Control Protocol" }, + { 0x802b, "Novell IPX Control Protocol" }, + { 0x8031, "Bridging NCP" }, + { 0x8033, "Stream Protocol Control Protocol" }, + { 0x8035, "Banyan Vines Control Protocol" }, + { 0x803d, "Multi-Link Control Protocol" }, + { 0x803f, "NETBIOS Framing Control Protocol" }, + { 0x8041, "Cisco Systems Control Protocol" }, + { 0x8043, "Ascom Timeplex" }, + { 0x8045, "Fujitsu LBLB Control Protocol" }, + { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, + { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, + { 0x804b, "SNA over 802.2 Control Protocol" }, + { 0x804d, "SNA Control Protocol" }, + { 0x804f, "IP6 Header Compression Control Protocol" }, + { 0x8051, "KNX Bridging Control Protocol" }, + { 0x8053, "Encryption Control Protocol" }, + { 0x8055, "Individual Link Encryption Control Protocol" }, + { 0x8057, "IPv6 Control Protocol" }, + { 0x8059, "PPP Muxing Control Protocol" }, + { 0x805b, "Vendor-Specific Network Control Protocol (VSNCP)" }, + { 0x806f, "Stampede Bridging Control Protocol" }, + { 0x8073, "MP+ Control Protocol" }, + { 0x80c1, "NTCITS IPI Control Protocol" }, + { 0x80fb, "Single Link Compression Control Protocol" }, + { 0x80fd, "Compression Control Protocol" }, + { 0x8207, "Cisco Discovery Protocol Control" }, + { 0x8209, "Netcs Twin Routing" }, + { 0x820b, "STP - Control Protocol" }, + { 0x820d, "EDPCP - Extreme Discovery Protocol Ctrl Prtcl" }, + { 0x8235, "Apple Client Server Protocol Control" }, + { 0x8281, "MPLSCP" }, + { 0x8285, "IEEE p1284.4 standard - Protocol Control" }, + { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, + { 0x8289, "Multichannel Flow Treatment Protocol" }, + { 0xc021, "Link Control Protocol" }, + { 0xc023, "Password Authentication Protocol" }, + { 0xc025, "Link Quality Report" }, + { 0xc027, "Shiva Password Authentication Protocol" }, + { 0xc029, "CallBack Control Protocol (CBCP)" }, + { 0xc02b, "BACP Bandwidth Allocation Control Protocol" }, + { 0xc02d, "BAP" }, + { 0xc05b, "Vendor-Specific Authentication Protocol (VSAP)" }, + { 0xc081, "Container Control Protocol" }, + { 0xc223, "Challenge Handshake Authentication Protocol" }, + { 0xc225, "RSA Authentication Protocol" }, + { 0xc227, "Extensible Authentication Protocol" }, + { 0xc229, "Mitsubishi Security Info Exch Ptcl (SIEP)" }, + { 0xc26f, "Stampede Bridging Authorization Protocol" }, + { 0xc281, "Proprietary Authentication Protocol" }, + { 0xc283, "Proprietary Authentication Protocol" }, + { 0xc481, "Proprietary Node ID Authentication Protocol" }, + { 0, NULL }, +}; + +/* + * protocol_name - find a name for a PPP protocol. + */ +const char * protocol_name(int proto) { + const struct protocol_list *lp; + + for (lp = protocol_list; lp->proto != 0; ++lp) { + if (proto == lp->proto) { + return lp->name; + } + } + return NULL; +} +#endif /* PPP_PROTOCOLNAME */ + +#if PPP_STATS_SUPPORT + +/* ---- Note on PPP Stats support ---- + * + * The one willing link stats support should add the get_ppp_stats() + * to fetch statistics from lwIP. + */ + +/* + * reset_link_stats - "reset" stats when link goes up. + */ +void reset_link_stats(int u) { + if (!get_ppp_stats(u, &old_link_stats)) { + return; + } + gettimeofday(&start_time, NULL); +} + +/* + * update_link_stats - get stats at link termination. + */ +void update_link_stats(int u) { + struct timeval now; + char numbuf[32]; + + if (!get_ppp_stats(u, &link_stats) || gettimeofday(&now, NULL) < 0) { + return; + } + link_connect_time = now.tv_sec - start_time.tv_sec; + link_stats_valid = 1; + + link_stats.bytes_in -= old_link_stats.bytes_in; + link_stats.bytes_out -= old_link_stats.bytes_out; + link_stats.pkts_in -= old_link_stats.pkts_in; + link_stats.pkts_out -= old_link_stats.pkts_out; +} + +void print_link_stats() { + /* + * Print connect time and statistics. + */ + if (link_stats_valid) { + int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ + info("Connect time %d.%d minutes.", t/10, t%10); + info("Sent %u bytes, received %u bytes.", link_stats.bytes_out, link_stats.bytes_in); + link_stats_valid = 0; + } +} +#endif /* PPP_STATS_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppapi.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppapi.c new file mode 100644 index 0000000..947f7ba --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppapi.c @@ -0,0 +1,427 @@ +/** + * @file + * Point To Point Protocol Sequential API module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" + +#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/pppapi.h" +#include "lwip/priv/tcpip_priv.h" +#include "netif/ppp/pppoe.h" +#include "netif/ppp/pppol2tp.h" +#include "netif/ppp/pppos.h" + +#if LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL_DECLARE(PPPAPI_MSG, MEMP_NUM_PPP_API_MSG, sizeof(struct pppapi_msg), "PPPAPI_MSG") +#endif + +#define PPPAPI_VAR_REF(name) API_VAR_REF(name) +#define PPPAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct pppapi_msg, name) +#define PPPAPI_VAR_ALLOC(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, ERR_MEM) +#define PPPAPI_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, NULL) +#define PPPAPI_VAR_FREE(name) API_VAR_FREE_POOL(PPPAPI_MSG, name) + +/** + * Call ppp_set_default() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_set_default(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + ppp_set_default(msg->msg.ppp); + return ERR_OK; +} + +/** + * Call ppp_set_default() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_set_default(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_set_default, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +#if PPP_NOTIFY_PHASE +/** + * Call ppp_set_notify_phase_callback() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_set_notify_phase_callback(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + ppp_set_notify_phase_callback(msg->msg.ppp, msg->msg.msg.setnotifyphasecb.notify_phase_cb); + return ERR_OK; +} + +/** + * Call ppp_set_notify_phase_callback() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.setnotifyphasecb.notify_phase_cb = notify_phase_cb; + err = tcpip_api_call(pppapi_do_ppp_set_notify_phase_callback, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} +#endif /* PPP_NOTIFY_PHASE */ + + +#if PPPOS_SUPPORT +/** + * Call pppos_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppos_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppos_create(msg->msg.msg.serialcreate.pppif, msg->msg.msg.serialcreate.output_cb, + msg->msg.msg.serialcreate.link_status_cb, msg->msg.msg.serialcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppos_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.output_cb = output_cb; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppos_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOS_SUPPORT */ + + +#if PPPOE_SUPPORT +/** + * Call pppoe_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppoe_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppoe_create(msg->msg.msg.ethernetcreate.pppif, msg->msg.msg.ethernetcreate.ethif, + msg->msg.msg.ethernetcreate.service_name, msg->msg.msg.ethernetcreate.concentrator_name, + msg->msg.msg.ethernetcreate.link_status_cb, msg->msg.msg.ethernetcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppoe_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, + const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, + void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ethif = ethif; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.service_name = service_name; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.concentrator_name = concentrator_name; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppoe_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOE_SUPPORT */ + + +#if PPPOL2TP_SUPPORT +/** + * Call pppol2tp_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppol2tp_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppol2tp_create(msg->msg.msg.l2tpcreate.pppif, + msg->msg.msg.l2tpcreate.netif, API_EXPR_REF(msg->msg.msg.l2tpcreate.ipaddr), msg->msg.msg.l2tpcreate.port, +#if PPPOL2TP_AUTH_SUPPORT + msg->msg.msg.l2tpcreate.secret, + msg->msg.msg.l2tpcreate.secret_len, +#else /* PPPOL2TP_AUTH_SUPPORT */ + NULL, + 0, +#endif /* PPPOL2TP_AUTH_SUPPORT */ + msg->msg.msg.l2tpcreate.link_status_cb, msg->msg.msg.l2tpcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppol2tp_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); +#if !PPPOL2TP_AUTH_SUPPORT + LWIP_UNUSED_ARG(secret); + LWIP_UNUSED_ARG(secret_len); +#endif /* !PPPOL2TP_AUTH_SUPPORT */ + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.netif = netif; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ipaddr = PPPAPI_VAR_REF(ipaddr); + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.port = port; +#if PPPOL2TP_AUTH_SUPPORT + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret = secret; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppol2tp_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOL2TP_SUPPORT */ + + +/** + * Call ppp_connect() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_connect(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_connect(msg->msg.ppp, msg->msg.msg.connect.holdoff); +} + +/** + * Call ppp_connect() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_connect(ppp_pcb *pcb, u16_t holdoff) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.connect.holdoff = holdoff; + err = tcpip_api_call(pppapi_do_ppp_connect, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +#if PPP_SERVER +/** + * Call ppp_listen() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_listen(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_listen(msg->msg.ppp); +} + +/** + * Call ppp_listen() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_listen(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_listen, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} +#endif /* PPP_SERVER */ + + +/** + * Call ppp_close() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_close(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_close(msg->msg.ppp, msg->msg.msg.close.nocarrier); +} + +/** + * Call ppp_close() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_close(ppp_pcb *pcb, u8_t nocarrier) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.close.nocarrier = nocarrier; + err = tcpip_api_call(pppapi_do_ppp_close, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +/** + * Call ppp_free() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_free(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_free(msg->msg.ppp); +} + +/** + * Call ppp_free() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_free(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_free, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +/** + * Call ppp_ioctl() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_ioctl(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_ioctl(msg->msg.ppp, msg->msg.msg.ioctl.cmd, msg->msg.msg.ioctl.arg); +} + +/** + * Call ppp_ioctl() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.ioctl.cmd = cmd; + PPPAPI_VAR_REF(msg).msg.msg.ioctl.arg = arg; + err = tcpip_api_call(pppapi_do_ppp_ioctl, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + +#endif /* LWIP_PPP_API */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppcrypt.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppcrypt.c new file mode 100644 index 0000000..82d78c1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppcrypt.c @@ -0,0 +1,66 @@ +/* + * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 + * + * Extracted from chap_ms.c by James Carlson. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not necessary */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/pppcrypt.h" + + +static u_char pppcrypt_get_7bits(u_char *input, int startBit) { + unsigned int word; + + word = (unsigned)input[startBit / 8] << 8; + word |= (unsigned)input[startBit / 8 + 1]; + + word >>= 15 - (startBit % 8 + 7); + + return word & 0xFE; +} + +/* IN 56 bit DES key missing parity bits + * OUT 64 bit DES key with parity bits added + */ +void pppcrypt_56_to_64_bit_key(u_char *key, u_char * des_key) { + des_key[0] = pppcrypt_get_7bits(key, 0); + des_key[1] = pppcrypt_get_7bits(key, 7); + des_key[2] = pppcrypt_get_7bits(key, 14); + des_key[3] = pppcrypt_get_7bits(key, 21); + des_key[4] = pppcrypt_get_7bits(key, 28); + des_key[5] = pppcrypt_get_7bits(key, 35); + des_key[6] = pppcrypt_get_7bits(key, 42); + des_key[7] = pppcrypt_get_7bits(key, 49); +} + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppoe.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppoe.c new file mode 100644 index 0000000..971b36b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppoe.c @@ -0,0 +1,1198 @@ +/***************************************************************************** +* pppoe.c - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "lwip/timeouts.h" +#include "lwip/memp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include "netif/ethernet.h" +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/pppoe.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") + +/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ +#define PPPOE_ADD_16(PTR, VAL) \ + *(PTR)++ = (u8_t)((VAL) / 256); \ + *(PTR)++ = (u8_t)((VAL) % 256) + +/* Add a complete PPPoE header to the buffer pointed to by PTR */ +#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ + *(PTR)++ = PPPOE_VERTYPE; \ + *(PTR)++ = (CODE); \ + PPPOE_ADD_16(PTR, SESS); \ + PPPOE_ADD_16(PTR, LEN) + +#define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */ +#define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */ +#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ +#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ + +#ifdef PPPOE_SERVER +#error "PPPOE_SERVER is not yet supported under lwIP!" +/* from if_spppsubr.c */ +#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ +#endif + +#define PPPOE_ERRORSTRING_LEN 64 + + +/* callbacks called from PPP core */ +static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); +static void pppoe_connect(ppp_pcb *ppp, void *ctx); +static void pppoe_disconnect(ppp_pcb *ppp, void *ctx); +static err_t pppoe_destroy(ppp_pcb *ppp, void *ctx); + +/* management routines */ +static void pppoe_abort_connect(struct pppoe_softc *); +#if 0 /* UNUSED */ +static void pppoe_clear_softc(struct pppoe_softc *, const char *); +#endif /* UNUSED */ + +/* internal timeout handling */ +static void pppoe_timeout(void *); + +/* sending actual protocol controll packets */ +static err_t pppoe_send_padi(struct pppoe_softc *); +static err_t pppoe_send_padr(struct pppoe_softc *); +#ifdef PPPOE_SERVER +static err_t pppoe_send_pado(struct pppoe_softc *); +static err_t pppoe_send_pads(struct pppoe_softc *); +#endif +static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); + +/* internal helper functions */ +static err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); +static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif); +static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif); + +/** linked list of created pppoe interfaces */ +static struct pppoe_softc *pppoe_softc_list; + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppoe_callbacks = { + pppoe_connect, +#if PPP_SERVER + NULL, +#endif /* PPP_SERVER */ + pppoe_disconnect, + pppoe_destroy, + pppoe_write, + pppoe_netif_output, + NULL, + NULL +}; + +/* + * Create a new PPP Over Ethernet (PPPoE) connection. + * + * Return 0 on success, an error code on failure. + */ +ppp_pcb *pppoe_create(struct netif *pppif, + struct netif *ethif, + const char *service_name, const char *concentrator_name, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb *ppp; + struct pppoe_softc *sc; +#if !PPPOE_SCNAME_SUPPORT + LWIP_UNUSED_ARG(service_name); + LWIP_UNUSED_ARG(concentrator_name); +#endif /* !PPPOE_SCNAME_SUPPORT */ + LWIP_ASSERT_CORE_LOCKED(); + + sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF); + if (sc == NULL) { + return NULL; + } + + ppp = ppp_new(pppif, &pppoe_callbacks, sc, link_status_cb, ctx_cb); + if (ppp == NULL) { + LWIP_MEMPOOL_FREE(PPPOE_IF, sc); + return NULL; + } + + memset(sc, 0, sizeof(struct pppoe_softc)); + sc->pcb = ppp; + sc->sc_ethif = ethif; +#if PPPOE_SCNAME_SUPPORT + sc->sc_service_name = service_name; + sc->sc_concentrator_name = concentrator_name; +#endif /* PPPOE_SCNAME_SUPPORT */ + /* put the new interface at the head of the list */ + sc->next = pppoe_softc_list; + pppoe_softc_list = sc; + return ppp; +} + +/* Called by PPP core */ +static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pbuf *ph; /* Ethernet + PPPoE header */ + err_t ret; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* skip address & flags */ + pbuf_remove_header(p, 2); + + ph = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); + if(!ph) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + pbuf_remove_header(ph, PPPOE_HEADERLEN); /* hide PPPoE header */ + pbuf_cat(ph, p); +#if MIB2_STATS + tot_len = ph->tot_len; +#endif /* MIB2_STATS */ + + ret = pppoe_xmit(sc, ph); + if (ret != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ret; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Called by PPP core */ +static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pbuf *pb; + u8_t *pl; + err_t err; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_LINK, PPPOE_HEADERLEN + sizeof(protocol), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + pbuf_remove_header(pb, PPPOE_HEADERLEN); + + pl = (u8_t*)pb->payload; + PUTSHORT(protocol, pl); + + pbuf_chain(pb, p); +#if MIB2_STATS + tot_len = pb->tot_len; +#endif /* MIB2_STATS */ + + if( (err = pppoe_xmit(sc, pb)) != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return err; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +static err_t +pppoe_destroy(ppp_pcb *ppp, void *ctx) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pppoe_softc **copp, *freep; + LWIP_UNUSED_ARG(ppp); + + sys_untimeout(pppoe_timeout, sc); + + /* remove interface from list */ + for (copp = &pppoe_softc_list; (freep = *copp); copp = &freep->next) { + if (freep == sc) { + *copp = freep->next; + break; + } + } + LWIP_MEMPOOL_FREE(PPPOE_IF, sc); + + return ERR_OK; +} + +/* + * Find the interface handling the specified session. + * Note: O(number of sessions open), this is a client-side only, mean + * and lean implementation, so number of open sessions typically should + * be 1. + */ +static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) { + struct pppoe_softc *sc; + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc->sc_state == PPPOE_STATE_SESSION + && sc->sc_session == session + && sc->sc_ethif == rcvif) { + return sc; + } + } + return NULL; +} + +/* Check host unique token passed and return appropriate softc pointer, + * or NULL if token is bogus. */ +static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { + struct pppoe_softc *sc, *t; + + if (len != sizeof sc) { + return NULL; + } + MEMCPY(&t, token, len); + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc == t) { + break; + } + } + + if (sc == NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); + return NULL; + } + + /* should be safe to access *sc now */ + if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state)); + return NULL; + } + if (sc->sc_ethif != rcvif) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + return NULL; + } + return sc; +} + +/* analyze and handle a single received packet while not in session state */ +void +pppoe_disc_input(struct netif *netif, struct pbuf *pb) +{ + u16_t tag, len, off; + u16_t session, plen; + struct pppoe_softc *sc; +#if PPP_DEBUG + const char *err_msg = NULL; +#endif /* PPP_DEBUG */ + u8_t *ac_cookie; + u16_t ac_cookie_len; +#ifdef PPPOE_SERVER + u8_t *hunique; + size_t hunique_len; +#endif + struct pppoehdr *ph; + struct pppoetag pt; + int err; + struct eth_hdr *ethhdr; + + /* don't do anything if there is not a single PPPoE instance */ + if (pppoe_softc_list == NULL) { + pbuf_free(pb); + return; + } + + pb = pbuf_coalesce(pb, PBUF_RAW); + + ethhdr = (struct eth_hdr *)pb->payload; + + ac_cookie = NULL; + ac_cookie_len = 0; +#ifdef PPPOE_SERVER + hunique = NULL; + hunique_len = 0; +#endif + session = 0; + off = sizeof(struct eth_hdr) + sizeof(struct pppoehdr); + if (pb->len < off) { + PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len)); + goto done; + } + + ph = (struct pppoehdr *) (ethhdr + 1); + if (ph->vertype != PPPOE_VERTYPE) { + PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype)); + goto done; + } + session = lwip_ntohs(ph->session); + plen = lwip_ntohs(ph->plen); + + if (plen > (pb->len - off)) { + PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n", + pb->len - off, plen)); + goto done; + } + if(pb->tot_len == pb->len) { + u16_t framelen = off + plen; + if (framelen < pb->len) { + /* ignore trailing garbage */ + pb->tot_len = pb->len = framelen; + } + } + tag = 0; + len = 0; + sc = NULL; + while (off + sizeof(pt) <= pb->len) { + MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); + tag = lwip_ntohs(pt.tag); + len = lwip_ntohs(pt.len); + if (off + sizeof(pt) + len > pb->len) { + PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len)); + goto done; + } + switch (tag) { + case PPPOE_TAG_EOL: + goto breakbreak; + case PPPOE_TAG_SNAME: + break; /* ignored */ + case PPPOE_TAG_ACNAME: + break; /* ignored */ + case PPPOE_TAG_HUNIQUE: + if (sc != NULL) { + break; + } +#ifdef PPPOE_SERVER + hunique = (u8_t*)pb->payload + off + sizeof(pt); + hunique_len = len; +#endif + sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); + break; + case PPPOE_TAG_ACCOOKIE: + if (ac_cookie == NULL) { + if (len > PPPOE_MAX_AC_COOKIE_LEN) { + PPPDEBUG(LOG_DEBUG, ("pppoe: AC cookie is too long: len = %d, max = %d\n", len, PPPOE_MAX_AC_COOKIE_LEN)); + goto done; + } + ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); + ac_cookie_len = len; + } + break; +#if PPP_DEBUG + case PPPOE_TAG_SNAME_ERR: + err_msg = "SERVICE NAME ERROR"; + break; + case PPPOE_TAG_ACSYS_ERR: + err_msg = "AC SYSTEM ERROR"; + break; + case PPPOE_TAG_GENERIC_ERR: + err_msg = "GENERIC ERROR"; + break; +#endif /* PPP_DEBUG */ + default: + break; + } +#if PPP_DEBUG + if (err_msg != NULL) { + char error_tmp[PPPOE_ERRORSTRING_LEN]; + u16_t error_len = LWIP_MIN(len, sizeof(error_tmp)-1); + strncpy(error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); + error_tmp[error_len] = '\0'; + if (sc) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": %s: %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err_msg, error_tmp)); + } else { + PPPDEBUG(LOG_DEBUG, ("pppoe: %s: %s\n", err_msg, error_tmp)); + } + } +#endif /* PPP_DEBUG */ + off += sizeof(pt) + len; + } + +breakbreak:; + switch (ph->code) { + case PPPOE_CODE_PADI: +#ifdef PPPOE_SERVER + /* + * got service name, concentrator name, and/or host unique. + * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. + */ + if (LIST_EMPTY(&pppoe_softc_list)) { + goto done; + } + LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { + continue; + } + if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { + continue; + } + if (sc->sc_state == PPPOE_STATE_INITIAL) { + break; + } + } + if (sc == NULL) { + /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */ + goto done; + } + if (hunique) { + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + } + sc->sc_hunique = mem_malloc(hunique_len); + if (sc->sc_hunique == NULL) { + goto done; + } + sc->sc_hunique_len = hunique_len; + MEMCPY(sc->sc_hunique, hunique, hunique_len); + } + MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); + sc->sc_state = PPPOE_STATE_PADO_SENT; + pppoe_send_pado(sc); + break; +#endif /* PPPOE_SERVER */ + case PPPOE_CODE_PADR: +#ifdef PPPOE_SERVER + /* + * get sc from ac_cookie if IFF_PASSIVE + */ + if (ac_cookie == NULL) { + /* be quiet if there is not a single pppoe instance */ + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n")); + goto done; + } + sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); + if (sc == NULL) { + /* be quiet if there is not a single pppoe instance */ + if (!LIST_EMPTY(&pppoe_softc_list)) { + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n")); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADO_SENT) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + goto done; + } + if (hunique) { + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + } + sc->sc_hunique = mem_malloc(hunique_len); + if (sc->sc_hunique == NULL) { + goto done; + } + sc->sc_hunique_len = hunique_len; + MEMCPY(sc->sc_hunique, hunique, hunique_len); + } + pppoe_send_pads(sc); + sc->sc_state = PPPOE_STATE_SESSION; + ppp_start(sc->pcb); /* notify upper layers */ + break; +#else + /* ignore, we are no access concentrator */ + goto done; +#endif /* PPPOE_SERVER */ + case PPPOE_CODE_PADO: + if (sc == NULL) { + /* be quiet if there is not a single pppoe instance */ + if (pppoe_softc_list != NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n")); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADI_SENT) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + goto done; + } + if (ac_cookie) { + sc->sc_ac_cookie_len = ac_cookie_len; + MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); + } + MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); + sys_untimeout(pppoe_timeout, sc); + sc->sc_padr_retried = 0; + sc->sc_state = PPPOE_STATE_PADR_SENT; + if ((err = pppoe_send_padr(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + break; + case PPPOE_CODE_PADS: + if (sc == NULL) { + goto done; + } + sc->sc_session = session; + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); + sc->sc_state = PPPOE_STATE_SESSION; + ppp_start(sc->pcb); /* notify upper layers */ + break; + case PPPOE_CODE_PADT: + /* Don't disconnect here, we let the LCP Echo/Reply find the fact + * that PPP session is down. Asking the PPP stack to end the session + * require strict checking about the PPP phase to prevent endless + * disconnection loops. + */ +#if 0 /* UNUSED */ + if (sc == NULL) { /* PADT frames are rarely sent with a hunique tag, this is actually almost always true */ + goto done; + } + pppoe_clear_softc(sc, "received PADT"); +#endif /* UNUSED */ + break; + default: + if(sc) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, + (u16_t)ph->code, session)); + } else { + PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session)); + } + break; + } + +done: + pbuf_free(pb); + return; +} + +void +pppoe_data_input(struct netif *netif, struct pbuf *pb) +{ + u16_t session, plen; + struct pppoe_softc *sc; + struct pppoehdr *ph; +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + u8_t shost[ETHER_ADDR_LEN]; +#endif + +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); +#endif + if (pbuf_remove_header(pb, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header failed\n")); + LINK_STATS_INC(link.lenerr); + goto drop; + } + + if (pb->len < sizeof(*ph)) { + PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n")); + goto drop; + } + ph = (struct pppoehdr *)pb->payload; + + if (ph->vertype != PPPOE_VERTYPE) { + PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype)); + goto drop; + } + if (ph->code != 0) { + goto drop; + } + + session = lwip_ntohs(ph->session); + sc = pppoe_find_softc_by_session(session, netif); + if (sc == NULL) { +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session)); + pppoe_send_padt(netif, session, shost); +#endif + goto drop; + } + + plen = lwip_ntohs(ph->plen); + + if (pbuf_remove_header(pb, PPPOE_HEADERLEN) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header PPPOE_HEADERLEN failed\n")); + LINK_STATS_INC(link.lenerr); + goto drop; + } + + PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, + pb->len, plen)); + + if (pb->tot_len < plen) { + goto drop; + } + + /* Dispatch the packet thereby consuming it. */ + ppp_input(sc->pcb, pb); + return; + +drop: + pbuf_free(pb); +} + +static err_t +pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) +{ + struct eth_hdr *ethhdr; + u16_t etype; + err_t res; + + /* make room for Ethernet header - should not fail */ + if (pbuf_add_header(pb, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + ethhdr = (struct eth_hdr *)pb->payload; + etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; + ethhdr->type = lwip_htons(etype); + MEMCPY(ðhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); + MEMCPY(ðhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr)); + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, + sc->sc_state, sc->sc_session, + sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], + pb->tot_len)); + + res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); + + pbuf_free(pb); + + return res; +} + +static err_t +pppoe_send_padi(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + int len; +#if PPPOE_SCNAME_SUPPORT + int l1 = 0, l2 = 0; /* XXX: gcc */ +#endif /* PPPOE_SCNAME_SUPPORT */ + + /* calculate length of frame (excluding ethernet header + pppoe header) */ + len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ +#if PPPOE_SCNAME_SUPPORT + if (sc->sc_service_name != NULL) { + l1 = (int)strlen(sc->sc_service_name); + len += l1; + } + if (sc->sc_concentrator_name != NULL) { + l2 = (int)strlen(sc->sc_concentrator_name); + len += 2 + 2 + l2; + } +#endif /* PPPOE_SCNAME_SUPPORT */ + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#if PPPOE_SCNAME_SUPPORT + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else +#endif /* PPPOE_SCNAME_SUPPORT */ + { + PPPOE_ADD_16(p, 0); + } +#if PPPOE_SCNAME_SUPPORT + if (sc->sc_concentrator_name != NULL) { + PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); + PPPOE_ADD_16(p, l2); + MEMCPY(p, sc->sc_concentrator_name, l2); + p += l2; + } +#endif /* PPPOE_SCNAME_SUPPORT */ + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof sc); + + /* send pkt */ + return pppoe_output(sc, pb); +} + +static void +pppoe_timeout(void *arg) +{ + u32_t retry_wait; + int err; + struct pppoe_softc *sc = (struct pppoe_softc*)arg; + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + + switch (sc->sc_state) { + case PPPOE_STATE_PADI_SENT: + /* + * We have two basic ways of retrying: + * - Quick retry mode: try a few times in short sequence + * - Slow retry mode: we already had a connection successfully + * established and will try infinitely (without user + * intervention) + * We only enter slow retry mode if IFF_LINK1 (aka autodial) + * is not set. + */ + if (sc->sc_padi_retried < 0xff) { + sc->sc_padi_retried++; + } + if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { +#if 0 + if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { + /* slow retry mode */ + retry_wait = PPPOE_SLOW_RETRY; + } else +#endif + { + pppoe_abort_connect(sc); + return; + } + } + /* initialize for quick retry mode */ + retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); + if ((err = pppoe_send_padi(sc)) != 0) { + sc->sc_padi_retried--; + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(retry_wait, pppoe_timeout, sc); + break; + + case PPPOE_STATE_PADR_SENT: + sc->sc_padr_retried++; + if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + sc->sc_state = PPPOE_STATE_PADI_SENT; + sc->sc_padr_retried = 0; + if ((err = pppoe_send_padi(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); + return; + } + if ((err = pppoe_send_padr(sc)) != 0) { + sc->sc_padr_retried--; + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + break; + default: + return; /* all done, work in peace */ + } +} + +/* Start a connection (i.e. initiate discovery phase) */ +static void +pppoe_connect(ppp_pcb *ppp, void *ctx) +{ + err_t err; + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + lcp_options *lcp_wo; + lcp_options *lcp_ao; +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_options *ipcp_wo; + ipcp_options *ipcp_ao; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + sc->sc_session = 0; + sc->sc_ac_cookie_len = 0; + sc->sc_padi_retried = 0; + sc->sc_padr_retried = 0; + /* changed to real address later */ + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +#ifdef PPPOE_SERVER + /* wait PADI if IFF_PASSIVE */ + if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { + return 0; + } +#endif + + lcp_wo = &ppp->lcp_wantoptions; + lcp_wo->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ + lcp_wo->neg_asyncmap = 0; + lcp_wo->neg_pcompression = 0; + lcp_wo->neg_accompression = 0; + lcp_wo->passive = 0; + lcp_wo->silent = 0; + + lcp_ao = &ppp->lcp_allowoptions; + lcp_ao->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ + lcp_ao->neg_asyncmap = 0; + lcp_ao->neg_pcompression = 0; + lcp_ao->neg_accompression = 0; + +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_wo = &ppp->ipcp_wantoptions; + ipcp_wo->neg_vj = 0; + ipcp_wo->old_vj = 0; + + ipcp_ao = &ppp->ipcp_allowoptions; + ipcp_ao->neg_vj = 0; + ipcp_ao->old_vj = 0; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + /* save state, in case we fail to send PADI */ + sc->sc_state = PPPOE_STATE_PADI_SENT; + if ((err = pppoe_send_padi(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); +} + +/* disconnect */ +static void +pppoe_disconnect(ppp_pcb *ppp, void *ctx) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + if (sc->sc_state == PPPOE_STATE_SESSION) { + pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); + } + + /* stop any timer, disconnect can be called while initiating is in progress */ + sys_untimeout(pppoe_timeout, sc); + sc->sc_state = PPPOE_STATE_INITIAL; +#ifdef PPPOE_SERVER + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + sc->sc_hunique = NULL; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ + } + sc->sc_hunique_len = 0; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ +#endif + ppp_link_end(ppp); /* notify upper layers */ + return; +} + +/* Connection attempt aborted */ +static void +pppoe_abort_connect(struct pppoe_softc *sc) +{ + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + sc->sc_state = PPPOE_STATE_INITIAL; + ppp_link_failed(sc->pcb); /* notify upper layers */ +} + +/* Send a PADR packet */ +static err_t +pppoe_send_padr(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; +#if PPPOE_SCNAME_SUPPORT + size_t l1 = 0; /* XXX: gcc */ +#endif /* PPPOE_SCNAME_SUPPORT */ + + len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ +#if PPPOE_SCNAME_SUPPORT + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } +#endif /* PPPOE_SCNAME_SUPPORT */ + if (sc->sc_ac_cookie_len > 0) { + len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ + } + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#if PPPOE_SCNAME_SUPPORT + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else +#endif /* PPPOE_SCNAME_SUPPORT */ + { + PPPOE_ADD_16(p, 0); + } + if (sc->sc_ac_cookie_len > 0) { + PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); + PPPOE_ADD_16(p, sc->sc_ac_cookie_len); + MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); + p += sc->sc_ac_cookie_len; + } + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof sc); + + return pppoe_output(sc, pb); +} + +/* send a PADT packet */ +static err_t +pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) +{ + struct pbuf *pb; + struct eth_hdr *ethhdr; + err_t res; + u8_t *p; + + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + if (pbuf_add_header(pb, sizeof(struct eth_hdr))) { + PPPDEBUG(LOG_ERR, ("pppoe: pppoe_send_padt: could not allocate room for PPPoE header\n")); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + ethhdr = (struct eth_hdr *)pb->payload; + ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); + MEMCPY(ðhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); + MEMCPY(ðhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr)); + + p = (u8_t*)(ethhdr + 1); + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); + + res = outgoing_if->linkoutput(outgoing_if, pb); + + pbuf_free(pb); + + return res; +} + +#ifdef PPPOE_SERVER +static err_t +pppoe_send_pado(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; + + /* calc length */ + len = 0; + /* include ac_cookie */ + len += 2 + 2 + sizeof(sc); + /* include hunique */ + len += 2 + 2 + sc->sc_hunique_len; + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); + PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof(sc)); + p += sizeof(sc); + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sc->sc_hunique_len); + MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); + return pppoe_output(sc, pb); +} + +static err_t +pppoe_send_pads(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len, l1 = 0; /* XXX: gcc */ + + sc->sc_session = mono_time.tv_sec % 0xff + 1; + /* calc length */ + len = 0; + /* include hunique */ + len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else { + PPPOE_ADD_16(p, 0); + } + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sc->sc_hunique_len); + MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); + return pppoe_output(sc, pb); +} +#endif + +static err_t +pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) +{ + u8_t *p; + size_t len; + + len = pb->tot_len; + + /* make room for PPPoE header - should not fail */ + if (pbuf_add_header(pb, PPPOE_HEADERLEN) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); + + return pppoe_output(sc, pb); +} + +#if 0 /*def PFIL_HOOKS*/ +static int +pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) +{ + struct pppoe_softc *sc; + int s; + + if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { + return 0; + } + + LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + if (sc->sc_ethif != ifp) { + continue; + } + if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { + sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + } + sc->sc_ethif = NULL; + pppoe_clear_softc(sc, "ethernet interface detached"); + } + + return 0; +} +#endif + +#if 0 /* UNUSED */ +static void +pppoe_clear_softc(struct pppoe_softc *sc, const char *message) +{ + LWIP_UNUSED_ARG(message); + + /* stop timer */ + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + sc->sc_state = PPPOE_STATE_INITIAL; + ppp_link_end(sc->pcb); /* notify upper layers - /!\ dangerous /!\ - see pppoe_disc_input() */ +} +#endif /* UNUSED */ +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppol2tp.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppol2tp.c new file mode 100644 index 0000000..4c4557f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppol2tp.c @@ -0,0 +1,1159 @@ +/** + * @file + * Network Point to Point Protocol over Layer 2 Tunneling Protocol program file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/* + * L2TP Support status: + * + * Supported: + * - L2TPv2 (PPP over L2TP, a.k.a. UDP tunnels) + * - LAC + * + * Not supported: + * - LNS (require PPP server support) + * - L2TPv3 ethernet pseudowires + * - L2TPv3 VLAN pseudowire + * - L2TPv3 PPP pseudowires + * - L2TPv3 IP encapsulation + * - L2TPv3 IP pseudowire + * - L2TP tunnel switching - http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 + * - Multiple tunnels per UDP socket, as well as multiple sessions per tunnel + * - Hidden AVPs + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/memp.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/snmp.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/pppol2tp.h" +#include "netif/ppp/pppcrypt.h" +#include "netif/ppp/magic.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOL2TP_PCB, MEMP_NUM_PPPOL2TP_INTERFACES, sizeof(pppol2tp_pcb), "PPPOL2TP_PCB") + +/* callbacks called from PPP core */ +static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); +static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx); /* Destroy a L2TP control block */ +static void pppol2tp_connect(ppp_pcb *ppp, void *ctx); /* Be a LAC, connect to a LNS. */ +static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx); /* Disconnect */ + + /* Prototypes for procedures local to this file. */ +static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr); +static void pppol2tp_timeout(void *arg); +static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); +static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp); +static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns, u16_t nr); +static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb); +static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb); + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppol2tp_callbacks = { + pppol2tp_connect, +#if PPP_SERVER + NULL, +#endif /* PPP_SERVER */ + pppol2tp_disconnect, + pppol2tp_destroy, + pppol2tp_write, + pppol2tp_netif_output, + NULL, + NULL +}; + + +/* Create a new L2TP session. */ +ppp_pcb *pppol2tp_create(struct netif *pppif, + struct netif *netif, const ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { + ppp_pcb *ppp; + pppol2tp_pcb *l2tp; + struct udp_pcb *udp; +#if !PPPOL2TP_AUTH_SUPPORT + LWIP_UNUSED_ARG(secret); + LWIP_UNUSED_ARG(secret_len); +#endif /* !PPPOL2TP_AUTH_SUPPORT */ + + if (ipaddr == NULL) { + goto ipaddr_check_failed; + } + + l2tp = (pppol2tp_pcb *)LWIP_MEMPOOL_ALLOC(PPPOL2TP_PCB); + if (l2tp == NULL) { + goto memp_malloc_l2tp_failed; + } + + udp = udp_new_ip_type(IP_GET_TYPE(ipaddr)); + if (udp == NULL) { + goto udp_new_failed; + } + udp_recv(udp, pppol2tp_input, l2tp); + + ppp = ppp_new(pppif, &pppol2tp_callbacks, l2tp, link_status_cb, ctx_cb); + if (ppp == NULL) { + goto ppp_new_failed; + } + + memset(l2tp, 0, sizeof(pppol2tp_pcb)); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + l2tp->ppp = ppp; + l2tp->udp = udp; + l2tp->netif = netif; + ip_addr_copy(l2tp->remote_ip, *ipaddr); + l2tp->remote_port = port; +#if PPPOL2TP_AUTH_SUPPORT + l2tp->secret = secret; + l2tp->secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return ppp; + +ppp_new_failed: + udp_remove(udp); +udp_new_failed: + LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); +memp_malloc_l2tp_failed: +ipaddr_check_failed: + return NULL; +} + +/* Called by PPP core */ +static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + struct pbuf *ph; /* UDP + L2TP header */ + err_t ret; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); + if(!ph) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + pbuf_remove_header(ph, PPPOL2TP_OUTPUT_DATA_HEADER_LEN); /* hide L2TP header */ + pbuf_cat(ph, p); +#if MIB2_STATS + tot_len = ph->tot_len; +#endif /* MIB2_STATS */ + + ret = pppol2tp_xmit(l2tp, ph); + if (ret != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ret; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Called by PPP core */ +static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + struct pbuf *pb; + u8_t *pl; + err_t err; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_TRANSPORT, PPPOL2TP_OUTPUT_DATA_HEADER_LEN + sizeof(protocol), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + pbuf_remove_header(pb, PPPOL2TP_OUTPUT_DATA_HEADER_LEN); + + pl = (u8_t*)pb->payload; + PUTSHORT(protocol, pl); + + pbuf_chain(pb, p); +#if MIB2_STATS + tot_len = pb->tot_len; +#endif /* MIB2_STATS */ + + if( (err = pppol2tp_xmit(l2tp, pb)) != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return err; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Destroy a L2TP control block */ +static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + + sys_untimeout(pppol2tp_timeout, l2tp); + udp_remove(l2tp->udp); + LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); + return ERR_OK; +} + +/* Be a LAC, connect to a LNS. */ +static void pppol2tp_connect(ppp_pcb *ppp, void *ctx) { + err_t err; + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + lcp_options *lcp_wo; + lcp_options *lcp_ao; +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_options *ipcp_wo; + ipcp_options *ipcp_ao; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + l2tp->tunnel_port = l2tp->remote_port; + l2tp->our_ns = 0; + l2tp->peer_nr = 0; + l2tp->peer_ns = 0; + l2tp->source_tunnel_id = 0; + l2tp->remote_tunnel_id = 0; + l2tp->source_session_id = 0; + l2tp->remote_session_id = 0; + /* l2tp->*_retried are cleared when used */ + + lcp_wo = &ppp->lcp_wantoptions; + lcp_wo->mru = PPPOL2TP_DEFMRU; + lcp_wo->neg_asyncmap = 0; + lcp_wo->neg_pcompression = 0; + lcp_wo->neg_accompression = 0; + lcp_wo->passive = 0; + lcp_wo->silent = 0; + + lcp_ao = &ppp->lcp_allowoptions; + lcp_ao->mru = PPPOL2TP_DEFMRU; + lcp_ao->neg_asyncmap = 0; + lcp_ao->neg_pcompression = 0; + lcp_ao->neg_accompression = 0; + +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_wo = &ppp->ipcp_wantoptions; + ipcp_wo->neg_vj = 0; + ipcp_wo->old_vj = 0; + + ipcp_ao = &ppp->ipcp_allowoptions; + ipcp_ao->neg_vj = 0; + ipcp_ao->old_vj = 0; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + /* Listen to a random source port, we need to do that instead of using udp_connect() + * because the L2TP LNS might answer with its own random source port (!= 1701) + */ +#if LWIP_IPV6 + if (IP_IS_V6_VAL(l2tp->udp->local_ip)) { + udp_bind(l2tp->udp, IP6_ADDR_ANY, 0); + } else +#endif /* LWIP_IPV6 */ + udp_bind(l2tp->udp, IP_ADDR_ANY, 0); + +#if PPPOL2TP_AUTH_SUPPORT + /* Generate random vector */ + if (l2tp->secret != NULL) { + magic_random_bytes(l2tp->secret_rv, sizeof(l2tp->secret_rv)); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + do { + l2tp->remote_tunnel_id = magic(); + } while(l2tp->remote_tunnel_id == 0); + /* save state, in case we fail to send SCCRQ */ + l2tp->sccrq_retried = 0; + l2tp->phase = PPPOL2TP_STATE_SCCRQ_SENT; + if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); +} + +/* Disconnect */ +static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + + l2tp->our_ns++; + pppol2tp_send_stopccn(l2tp, l2tp->our_ns); + + /* stop any timer, disconnect can be called while initiating is in progress */ + sys_untimeout(pppol2tp_timeout, l2tp); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + ppp_link_end(ppp); /* notify upper layers */ +} + +/* UDP Callback for incoming IPv4 L2TP frames */ +static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; + u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; + u8_t *inp; + LWIP_UNUSED_ARG(pcb); + + /* we can't unbound a UDP pcb, thus we can still receive UDP frames after the link is closed */ + if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { + goto free_and_return; + } + + if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { + goto free_and_return; + } + + /* discard packet if port mismatch, but only if we received a SCCRP */ + if (l2tp->phase > PPPOL2TP_STATE_SCCRQ_SENT && l2tp->tunnel_port != port) { + goto free_and_return; + } + + /* printf("-----------\nL2TP INPUT, %d\n", p->len); */ + + /* L2TP header */ + if (p->len < sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id) ) { + goto packet_too_short; + } + + inp = (u8_t*)p->payload; + GETSHORT(hflags, inp); + + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { + /* check mandatory flags for a control packet */ + if ( (hflags & PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY) != PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for control packet not set\n")); + goto free_and_return; + } + /* check forbidden flags for a control packet */ + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: forbidden header flags for control packet found\n")); + goto free_and_return; + } + } else { + /* check mandatory flags for a data packet */ + if ( (hflags & PPPOL2TP_HEADERFLAG_DATA_MANDATORY) != PPPOL2TP_HEADERFLAG_DATA_MANDATORY) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for data packet not set\n")); + goto free_and_return; + } + } + + /* Expected header size */ + hlen = sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id); + if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { + hlen += sizeof(len); + } + if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { + hlen += sizeof(ns) + sizeof(nr); + } + if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { + hlen += sizeof(offset); + } + if (p->len < hlen) { + goto packet_too_short; + } + + if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { + GETSHORT(len, inp); + if (p->len < len || len < hlen) { + goto packet_too_short; + } + } + GETSHORT(tunnel_id, inp); + GETSHORT(session_id, inp); + if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { + GETSHORT(ns, inp); + GETSHORT(nr, inp); + } + if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { + GETSHORT(offset, inp) + if (offset > 4096) { /* don't be fooled with large offset which might overflow hlen */ + PPPDEBUG(LOG_DEBUG, ("pppol2tp: strange packet received, offset=%d\n", offset)); + goto free_and_return; + } + hlen += offset; + if (p->len < hlen) { + goto packet_too_short; + } + INCPTR(offset, inp); + } + + /* printf("HLEN = %d\n", hlen); */ + + /* skip L2TP header */ + if (pbuf_remove_header(p, hlen) != 0) { + goto free_and_return; + } + + /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ + PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", + len, tunnel_id, session_id, ns, nr)); + + /* Control packet */ + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { + pppol2tp_dispatch_control_packet(l2tp, port, p, ns, nr); + goto free_and_return; + } + + /* Data packet */ + if(l2tp->phase != PPPOL2TP_STATE_DATA) { + goto free_and_return; + } + if(tunnel_id != l2tp->remote_tunnel_id) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: tunnel ID mismatch, assigned=%d, received=%d\n", l2tp->remote_tunnel_id, tunnel_id)); + goto free_and_return; + } + if(session_id != l2tp->remote_session_id) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: session ID mismatch, assigned=%d, received=%d\n", l2tp->remote_session_id, session_id)); + goto free_and_return; + } + /* + * skip address & flags if necessary + * + * RFC 2661 does not specify whether the PPP frame in the L2TP payload should + * have a HDLC header or not. We handle both cases for compatibility. + */ + if (p->len >= 2) { + GETSHORT(hflags, inp); + if (hflags == 0xff03) { + pbuf_remove_header(p, 2); + } + } + /* Dispatch the packet thereby consuming it. */ + ppp_input(l2tp->ppp, p); + return; + +packet_too_short: + PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); +free_and_return: + pbuf_free(p); +} + +/* L2TP Control packet entry point */ +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr) { + u8_t *inp; + u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; + err_t err; +#if PPPOL2TP_AUTH_SUPPORT + lwip_md5_context md5_ctx; + u8_t md5_hash[16]; + u8_t challenge_id = 0; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + /* printf("L2TP CTRL INPUT, ns=%d, nr=%d, len=%d\n", ns, nr, p->len); */ + + /* Drop unexpected packet */ + if (ns != l2tp->peer_ns) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: drop unexpected packet: received NS=%d, expected NS=%d\n", ns, l2tp->peer_ns)); + /* + * In order to ensure that all messages are acknowledged properly + * (particularly in the case of a lost ZLB ACK message), receipt + * of duplicate messages MUST be acknowledged. + * + * In this very special case we Ack a packet we previously received. + * Therefore our NS is the NR we just received. And our NR is the + * NS we just received plus one. + */ + if ((s16_t)(ns - l2tp->peer_ns) < 0) { + pppol2tp_send_zlb(l2tp, nr, ns+1); + } + return; + } + + l2tp->peer_nr = nr; + + /* Handle the special case of the ICCN acknowledge */ + if (l2tp->phase == PPPOL2TP_STATE_ICCN_SENT && (s16_t)(l2tp->peer_nr - l2tp->our_ns) > 0) { + l2tp->phase = PPPOL2TP_STATE_DATA; + sys_untimeout(pppol2tp_timeout, l2tp); + ppp_start(l2tp->ppp); /* notify upper layers */ + } + + /* ZLB packets */ + if (p->tot_len == 0) { + return; + } + /* A ZLB packet does not consume a NS slot thus we don't record the NS value for ZLB packets */ + l2tp->peer_ns = ns+1; + + p = pbuf_coalesce(p, PBUF_RAW); + inp = (u8_t*)p->payload; + /* Decode AVPs */ + while (p->len > 0) { + if (p->len < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype) ) { + goto packet_too_short; + } + GETSHORT(avpflags, inp); + avplen = avpflags & PPPOL2TP_AVPHEADERFLAG_LENGTHMASK; + /* printf("AVPLEN = %d\n", avplen); */ + if (p->len < avplen || avplen < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) { + goto packet_too_short; + } + GETSHORT(vendorid, inp); + GETSHORT(attributetype, inp); + avplen -= sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype); + + /* Message type must be the first AVP */ + if (messagetype == 0) { + if (attributetype != 0 || vendorid != 0 || avplen != sizeof(messagetype) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: message type must be the first AVP\n")); + return; + } + GETSHORT(messagetype, inp); + /* printf("Message type = %d\n", messagetype); */ + switch(messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + /* Only accept SCCRP packet if we sent a SCCRQ */ + if (l2tp->phase != PPPOL2TP_STATE_SCCRQ_SENT) { + goto send_zlb; + } + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + /* Only accept ICRP packet if we sent a IRCQ */ + if (l2tp->phase != PPPOL2TP_STATE_ICRQ_SENT) { + goto send_zlb; + } + break; + /* Stop Control Connection Notification */ + case PPPOL2TP_MESSAGETYPE_STOPCCN: + pppol2tp_send_zlb(l2tp, l2tp->our_ns+1, l2tp->peer_ns); /* Ack the StopCCN before we switch to down state */ + if (l2tp->phase < PPPOL2TP_STATE_DATA) { + pppol2tp_abort_connect(l2tp); + } else if (l2tp->phase == PPPOL2TP_STATE_DATA) { + /* Don't disconnect here, we let the LCP Echo/Reply find the fact + * that PPP session is down. Asking the PPP stack to end the session + * require strict checking about the PPP phase to prevent endless + * disconnection loops. + */ + } + return; + default: + break; + } + goto nextavp; + } + + /* Skip proprietary L2TP extensions */ + if (vendorid != 0) { + goto skipavp; + } + + switch (messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + switch (attributetype) { + case PPPOL2TP_AVPTYPE_TUNNELID: + if (avplen != sizeof(l2tp->source_tunnel_id) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign tunnel ID length check failed\n")); + return; + } + GETSHORT(l2tp->source_tunnel_id, inp); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned tunnel ID %"U16_F"\n", l2tp->source_tunnel_id)); + goto nextavp; +#if PPPOL2TP_AUTH_SUPPORT + case PPPOL2TP_AVPTYPE_CHALLENGE: + if (avplen == 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Challenge length check failed\n")); + return; + } + if (l2tp->secret == NULL) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge from peer and no secret key available\n")); + pppol2tp_abort_connect(l2tp); + return; + } + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + challenge_id = PPPOL2TP_MESSAGETYPE_SCCCN; + lwip_md5_update(&md5_ctx, &challenge_id, 1); + lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); + lwip_md5_update(&md5_ctx, inp, avplen); + lwip_md5_finish(&md5_ctx, l2tp->challenge_hash); + lwip_md5_free(&md5_ctx); + l2tp->send_challenge = 1; + goto skipavp; + case PPPOL2TP_AVPTYPE_CHALLENGERESPONSE: + if (avplen != PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Challenge Response length check failed\n")); + return; + } + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + challenge_id = PPPOL2TP_MESSAGETYPE_SCCRP; + lwip_md5_update(&md5_ctx, &challenge_id, 1); + lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); + lwip_md5_update(&md5_ctx, l2tp->secret_rv, sizeof(l2tp->secret_rv)); + lwip_md5_finish(&md5_ctx, md5_hash); + lwip_md5_free(&md5_ctx); + if ( memcmp(inp, md5_hash, sizeof(md5_hash)) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge response from peer and secret key do not match\n")); + pppol2tp_abort_connect(l2tp); + return; + } + goto skipavp; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + default: + break; + } + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + switch (attributetype) { + case PPPOL2TP_AVPTYPE_SESSIONID: + if (avplen != sizeof(l2tp->source_session_id) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign session ID length check failed\n")); + return; + } + GETSHORT(l2tp->source_session_id, inp); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned session ID %"U16_F"\n", l2tp->source_session_id)); + goto nextavp; + default: + break; + } + break; + default: + break; + } + +skipavp: + INCPTR(avplen, inp); +nextavp: + /* printf("AVP Found, vendor=%d, attribute=%d, len=%d\n", vendorid, attributetype, avplen); */ + /* next AVP */ + if (pbuf_remove_header(p, avplen + sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) != 0) { + return; + } + } + + switch(messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + do { + l2tp->remote_session_id = magic(); + } while(l2tp->remote_session_id == 0); + l2tp->tunnel_port = port; /* LNS server might have chosen its own local port */ + l2tp->icrq_retried = 0; + l2tp->phase = PPPOL2TP_STATE_ICRQ_SENT; + l2tp->our_ns++; + if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + l2tp->our_ns++; + if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_untimeout(pppol2tp_timeout, l2tp); + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + l2tp->iccn_retried = 0; + l2tp->phase = PPPOL2TP_STATE_ICCN_SENT; + l2tp->our_ns++; + if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_untimeout(pppol2tp_timeout, l2tp); + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + /* Unhandled packet, send ZLB ACK */ + default: + goto send_zlb; + } + return; + +send_zlb: + pppol2tp_send_zlb(l2tp, l2tp->our_ns+1, l2tp->peer_ns); + return; +packet_too_short: + PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); +} + +/* L2TP Timeout handler */ +static void pppol2tp_timeout(void *arg) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; + err_t err; + u32_t retry_wait; + + PPPDEBUG(LOG_DEBUG, ("pppol2tp: timeout\n")); + + switch (l2tp->phase) { + case PPPOL2TP_STATE_SCCRQ_SENT: + /* backoff wait */ + if (l2tp->sccrq_retried < 0xff) { + l2tp->sccrq_retried++; + } + if (!l2tp->ppp->settings.persist && l2tp->sccrq_retried >= PPPOL2TP_MAXSCCRQ) { + pppol2tp_abort_connect(l2tp); + return; + } + retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); + if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { + l2tp->sccrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(retry_wait, pppol2tp_timeout, l2tp); + break; + + case PPPOL2TP_STATE_ICRQ_SENT: + l2tp->icrq_retried++; + if (l2tp->icrq_retried >= PPPOL2TP_MAXICRQ) { + pppol2tp_abort_connect(l2tp); + return; + } + PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); + if ((s16_t)(l2tp->peer_nr - l2tp->our_ns) < 0) { /* the SCCCN was not acknowledged */ + if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { + l2tp->icrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + } + } + if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { + l2tp->icrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + + case PPPOL2TP_STATE_ICCN_SENT: + l2tp->iccn_retried++; + if (l2tp->iccn_retried >= PPPOL2TP_MAXICCN) { + pppol2tp_abort_connect(l2tp); + return; + } + PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); + if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { + l2tp->iccn_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); + LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + + default: + return; /* all done, work in peace */ + } +} + +/* Connection attempt aborted */ +static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: could not establish connection\n")); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + ppp_link_failed(l2tp->ppp); /* notify upper layers */ +} + +/* Initiate a new tunnel */ +static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +8 +10 +10 +6+sizeof(PPPOL2TP_HOSTNAME)-1 +6+sizeof(PPPOL2TP_VENDORNAME)-1 +8 +8; +#if PPPOL2TP_AUTH_SUPPORT + if (l2tp->secret != NULL) { + len += 6 + sizeof(l2tp->secret_rv); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(0, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(0, p); /* NS Sequence number - to peer */ + PUTSHORT(0, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCRQ, p); /* Attribute value: Message type: SCCRQ */ + + /* AVP - L2TP Version */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_VERSION, p); /* Attribute type: Version */ + PUTSHORT(PPPOL2TP_VERSION, p); /* Attribute value: L2TP Version */ + + /* AVP - Framing capabilities */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES, p); /* Attribute type: Framing capabilities */ + PUTLONG(PPPOL2TP_FRAMINGCAPABILITIES, p); /* Attribute value: Framing capabilities */ + + /* AVP - Bearer capabilities */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_BEARERCAPABILITIES, p); /* Attribute type: Bearer capabilities */ + PUTLONG(PPPOL2TP_BEARERCAPABILITIES, p); /* Attribute value: Bearer capabilities */ + + /* AVP - Host name */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6+sizeof(PPPOL2TP_HOSTNAME)-1, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_HOSTNAME, p); /* Attribute type: Hostname */ + MEMCPY(p, PPPOL2TP_HOSTNAME, sizeof(PPPOL2TP_HOSTNAME)-1); /* Attribute value: Hostname */ + INCPTR(sizeof(PPPOL2TP_HOSTNAME)-1, p); + + /* AVP - Vendor name */ + PUTSHORT(6+sizeof(PPPOL2TP_VENDORNAME)-1, p); /* len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_VENDORNAME, p); /* Attribute type: Vendor name */ + MEMCPY(p, PPPOL2TP_VENDORNAME, sizeof(PPPOL2TP_VENDORNAME)-1); /* Attribute value: Vendor name */ + INCPTR(sizeof(PPPOL2TP_VENDORNAME)-1, p); + + /* AVP - Assign tunnel ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ + PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ + + /* AVP - Receive window size */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE, p); /* Attribute type: Receive window size */ + PUTSHORT(PPPOL2TP_RECEIVEWINDOWSIZE, p); /* Attribute value: Receive window size */ + +#if PPPOL2TP_AUTH_SUPPORT + /* AVP - Challenge */ + if (l2tp->secret != NULL) { + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->secret_rv), p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGE, p); /* Attribute type: Challenge */ + MEMCPY(p, l2tp->secret_rv, sizeof(l2tp->secret_rv)); /* Attribute value: Random vector */ + INCPTR(sizeof(l2tp->secret_rv), p); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Complete tunnel establishment */ +static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8; +#if PPPOL2TP_AUTH_SUPPORT + if (l2tp->send_challenge) { + len += 6 + sizeof(l2tp->challenge_hash); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCCN, p); /* Attribute value: Message type: SCCCN */ + +#if PPPOL2TP_AUTH_SUPPORT + /* AVP - Challenge response */ + if (l2tp->send_challenge) { + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->challenge_hash), p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGERESPONSE, p); /* Attribute type: Challenge response */ + MEMCPY(p, l2tp->challenge_hash, sizeof(l2tp->challenge_hash)); /* Attribute value: Computed challenge */ + INCPTR(sizeof(l2tp->challenge_hash), p); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Initiate a new session */ +static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + u32_t serialnumber; + + /* calculate UDP packet length */ + len = 12 +8 +8 +10; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_ICRQ, p); /* Attribute value: Message type: ICRQ */ + + /* AVP - Assign session ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_SESSIONID, p); /* Attribute type: Session ID */ + PUTSHORT(l2tp->remote_session_id, p); /* Attribute value: Session ID */ + + /* AVP - Call Serial Number */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CALLSERIALNUMBER, p); /* Attribute type: Serial number */ + serialnumber = magic(); + PUTLONG(serialnumber, p); /* Attribute value: Serial number */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Complete tunnel establishment */ +static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +10 +10; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(l2tp->source_session_id, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_ICCN, p); /* Attribute value: Message type: ICCN */ + + /* AVP - Framing type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGTYPE, p); /* Attribute type: Framing type */ + PUTLONG(PPPOL2TP_FRAMINGTYPE, p); /* Attribute value: Framing type */ + + /* AVP - TX Connect speed */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TXCONNECTSPEED, p); /* Attribute type: TX Connect speed */ + PUTLONG(PPPOL2TP_TXCONNECTSPEED, p); /* Attribute value: TX Connect speed */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Send a ZLB ACK packet */ +static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns, u16_t nr) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(nr, p); /* NR Sequence number - expected for peer */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Send a StopCCN packet */ +static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +8 +8; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_STOPCCN, p); /* Attribute value: Message type: StopCCN */ + + /* AVP - Assign tunnel ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ + PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ + + /* AVP - Result code */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_RESULTCODE, p); /* Attribute type: Result code */ + PUTSHORT(PPPOL2TP_RESULTCODE, p); /* Attribute value: Result code */ + + return pppol2tp_udp_send(l2tp, pb); +} + +static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { + u8_t *p; + + /* make room for L2TP header - should not fail */ + if (pbuf_add_header(pb, PPPOL2TP_OUTPUT_DATA_HEADER_LEN) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppol2tp: pppol2tp_pcb: could not allocate room for L2TP header\n")); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + + p = (u8_t*)pb->payload; + PUTSHORT(PPPOL2TP_HEADERFLAG_DATA_MANDATORY, p); + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(l2tp->source_session_id, p); /* Session Id */ + + return pppol2tp_udp_send(l2tp, pb); +} + +static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb) { + err_t err; + if (l2tp->netif) { + err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port, l2tp->netif); + } else { + err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port); + } + pbuf_free(pb); + return err; +} + +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppos.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppos.c new file mode 100644 index 0000000..dff0255 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/pppos.c @@ -0,0 +1,895 @@ +/** + * @file + * Network Point to Point Protocol over Serial file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "lwip/arch.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/api.h" +#include "lwip/ip4.h" /* for ip4_input() */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppos.h" +#include "netif/ppp/vj.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB") + +/* callbacks called from PPP core */ +static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol); +static void pppos_connect(ppp_pcb *ppp, void *ctx); +#if PPP_SERVER +static void pppos_listen(ppp_pcb *ppp, void *ctx); +#endif /* PPP_SERVER */ +static void pppos_disconnect(ppp_pcb *ppp, void *ctx); +static err_t pppos_destroy(ppp_pcb *ppp, void *ctx); +static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); +static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); + +/* Prototypes for procedures local to this file. */ +#if PPP_INPROC_IRQ_SAFE +static void pppos_input_callback(void *arg); +#endif /* PPP_INPROC_IRQ_SAFE */ +static void pppos_input_free_current_packet(pppos_pcb *pppos); +static void pppos_input_drop(pppos_pcb *pppos); +static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs); +static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs); + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppos_callbacks = { + pppos_connect, +#if PPP_SERVER + pppos_listen, +#endif /* PPP_SERVER */ + pppos_disconnect, + pppos_destroy, + pppos_write, + pppos_netif_output, + pppos_send_config, + pppos_recv_config +}; + +/* PPP's Asynchronous-Control-Character-Map. The mask array is used + * to select the specific bit for a character. */ +#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07)) + +#if PPP_FCS_TABLE +/* + * FCS lookup table as calculated by genfcstab. + */ +static const u16_t fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) +#else /* PPP_FCS_TABLE */ +/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */ +#define PPP_FCS_POLYNOMIAL 0x8408 +static u16_t +ppp_get_fcs(u8_t byte) +{ + unsigned int octet; + int bit; + octet = byte; + for (bit = 8; bit-- > 0; ) { + octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1); + } + return octet & 0xffff; +} +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff)) +#endif /* PPP_FCS_TABLE */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ + +#if PPP_INPROC_IRQ_SAFE +#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) +#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev) +#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) +#else +#define PPPOS_DECL_PROTECT(lev) +#define PPPOS_PROTECT(lev) +#define PPPOS_UNPROTECT(lev) +#endif /* PPP_INPROC_IRQ_SAFE */ + + +/* + * Create a new PPP connection using the given serial I/O device. + * + * Return 0 on success, an error code on failure. + */ +ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + pppos_pcb *pppos; + ppp_pcb *ppp; + LWIP_ASSERT_CORE_LOCKED(); + + pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB); + if (pppos == NULL) { + return NULL; + } + + ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb); + if (ppp == NULL) { + LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); + return NULL; + } + + memset(pppos, 0, sizeof(pppos_pcb)); + pppos->ppp = ppp; + pppos->output_cb = output_cb; + return ppp; +} + +/* Called by PPP core */ +static err_t +pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + u8_t *s; + struct pbuf *nb; + u16_t n; + u16_t fcs_out; + err_t err; + LWIP_UNUSED_ARG(ppp); + + /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf + gets freed by 'pppos_output_last' before this function returns and thus + cannot starve rx. */ + nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (nb == NULL) { + PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + /* Set nb->tot_len to actual payload length */ + nb->tot_len = p->len; + + /* If the link has been idle, we'll send a fresh flag character to + * flush any noise. */ + err = ERR_OK; + if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + } + + /* Load output buffer. */ + fcs_out = PPP_INITFCS; + s = (u8_t*)p->payload; + n = p->len; + while (n-- > 0) { + err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); + } + + err = pppos_output_last(pppos, err, nb, &fcs_out); + if (err == ERR_OK) { + PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len)); + } else { + PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len)); + } + pbuf_free(p); + return err; +} + +/* Called by PPP core */ +static err_t +pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + struct pbuf *nb, *p; + u16_t fcs_out; + err_t err; + LWIP_UNUSED_ARG(ppp); + + /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf + gets freed by 'pppos_output_last' before this function returns and thus + cannot starve rx. */ + nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (nb == NULL) { + PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + /* Set nb->tot_len to actual payload length */ + nb->tot_len = pb->tot_len; + + /* If the link has been idle, we'll send a fresh flag character to + * flush any noise. */ + err = ERR_OK; + if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + } + + fcs_out = PPP_INITFCS; + if (!pppos->accomp) { + err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out); + err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out); + } + if (!pppos->pcomp || protocol > 0xFF) { + err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out); + } + err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out); + + /* Load packet. */ + for(p = pb; p; p = p->next) { + u16_t n = p->len; + u8_t *s = (u8_t*)p->payload; + + while (n-- > 0) { + err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); + } + } + + err = pppos_output_last(pppos, err, nb, &fcs_out); + if (err == ERR_OK) { + PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); + } else { + PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); + } + return err; +} + +static void +pppos_connect(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left over from last session? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + /* reset PPPoS control block to its initial state */ + memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); + + /* + * Default the in and out accm so that escape and flag characters + * are always escaped. + */ + pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ + pppos->out_accm[15] = 0x60; + PPPOS_PROTECT(lev); + pppos->open = 1; + PPPOS_UNPROTECT(lev); + + /* + * Start the connection and handle incoming events (packet or timeout). + */ + PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num)); + ppp_start(ppp); /* notify upper layers */ +} + +#if PPP_SERVER +static void +pppos_listen(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left over from last session? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + /* reset PPPoS control block to its initial state */ + memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); + + /* + * Default the in and out accm so that escape and flag characters + * are always escaped. + */ + pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ + pppos->out_accm[15] = 0x60; + PPPOS_PROTECT(lev); + pppos->open = 1; + PPPOS_UNPROTECT(lev); + + /* + * Wait for something to happen. + */ + PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num)); + ppp_start(ppp); /* notify upper layers */ +} +#endif /* PPP_SERVER */ + +static void +pppos_disconnect(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + + PPPOS_PROTECT(lev); + pppos->open = 0; + PPPOS_UNPROTECT(lev); + + /* If PPP_INPROC_IRQ_SAFE is used we cannot call + * pppos_input_free_current_packet() here because + * rx IRQ might still call pppos_input(). + */ +#if !PPP_INPROC_IRQ_SAFE + /* input pbuf left ? */ + pppos_input_free_current_packet(pppos); +#endif /* !PPP_INPROC_IRQ_SAFE */ + + ppp_link_end(ppp); /* notify upper layers */ +} + +static err_t +pppos_destroy(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left ? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); + return ERR_OK; +} + +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. + * + * This is one of the only functions that may be called outside of the TCPIP thread! + * + * @param ppp PPP descriptor index, returned by pppos_create() + * @param s received data + * @param l length of received data + */ +err_t +pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l) +{ + struct pbuf *p; + err_t err; + + p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL); + if (!p) { + return ERR_MEM; + } + pbuf_take(p, s, l); + + err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys); + if (err != ERR_OK) { + pbuf_free(p); + } + return err; +} + +/* called from TCPIP thread */ +err_t pppos_input_sys(struct pbuf *p, struct netif *inp) { + ppp_pcb *ppp = (ppp_pcb*)inp->state; + struct pbuf *n; + LWIP_ASSERT_CORE_LOCKED(); + + for (n = p; n; n = n->next) { + pppos_input(ppp, (u8_t*)n->payload, n->len); + } + pbuf_free(p); + return ERR_OK; +} +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +/** PPPoS input helper struct, must be packed since it is stored + * to pbuf->payload, which might be unaligned. */ +#if PPP_INPROC_IRQ_SAFE +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppos_input_header { + PACK_STRUCT_FIELD(ppp_pcb *ppp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#endif /* PPP_INPROC_IRQ_SAFE */ + +/** Pass received raw characters to PPPoS to be decoded. + * + * @param ppp PPP descriptor index, returned by pppos_create() + * @param s received data + * @param l length of received data + */ +void +pppos_input(ppp_pcb *ppp, u8_t *s, int l) +{ + pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; + struct pbuf *next_pbuf; + u8_t cur_char; + u8_t escaped; + PPPOS_DECL_PROTECT(lev); +#if !PPP_INPROC_IRQ_SAFE + LWIP_ASSERT_CORE_LOCKED(); +#endif + + PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l)); + while (l-- > 0) { + cur_char = *s++; + + PPPOS_PROTECT(lev); + /* ppp_input can disconnect the interface, we need to abort to prevent a memory + * leak if there are remaining bytes because pppos_connect and pppos_listen + * functions expect input buffer to be free. Furthermore there are no real + * reason to continue reading bytes if we are disconnected. + */ + if (!pppos->open) { + PPPOS_UNPROTECT(lev); + return; + } + escaped = ESCAPE_P(pppos->in_accm, cur_char); + PPPOS_UNPROTECT(lev); + /* Handle special characters. */ + if (escaped) { + /* Check for escape sequences. */ + /* XXX Note that this does not handle an escaped 0x5d character which + * would appear as an escape character. Since this is an ASCII ']' + * and there is no reason that I know of to escape it, I won't complicate + * the code to handle this case. GLL */ + if (cur_char == PPP_ESCAPE) { + pppos->in_escaped = 1; + /* Check for the flag character. */ + } else if (cur_char == PPP_FLAG) { + /* If this is just an extra flag character, ignore it. */ + if (pppos->in_state <= PDADDRESS) { + /* ignore it */; + /* If we haven't received the packet header, drop what has come in. */ + } else if (pppos->in_state < PDDATA) { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Dropping incomplete packet %d\n", + ppp->netif->num, pppos->in_state)); + LINK_STATS_INC(link.lenerr); + pppos_input_drop(pppos); + /* If the fcs is invalid, drop the packet. */ + } else if (pppos->in_fcs != PPP_GOODFCS) { + PPPDEBUG(LOG_INFO, + ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", + ppp->netif->num, pppos->in_fcs, pppos->in_protocol)); + /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ + LINK_STATS_INC(link.chkerr); + pppos_input_drop(pppos); + /* Otherwise it's a good packet so pass it on. */ + } else { + struct pbuf *inp; + /* Trim off the checksum. */ + if(pppos->in_tail->len > 2) { + pppos->in_tail->len -= 2; + + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + } + } else { + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + } + + pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2); + } + + /* Dispatch the packet thereby consuming it. */ + inp = pppos->in_head; + /* Packet consumed, release our references. */ + pppos->in_head = NULL; + pppos->in_tail = NULL; +#if IP_FORWARD || LWIP_IPV6_FORWARD + /* hide the room for Ethernet forwarding header */ + pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN); +#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ +#if PPP_INPROC_IRQ_SAFE + if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) { + PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num)); + pbuf_free(inp); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); + } +#else /* PPP_INPROC_IRQ_SAFE */ + ppp_input(ppp, inp); +#endif /* PPP_INPROC_IRQ_SAFE */ + } + + /* Prepare for a new packet. */ + pppos->in_fcs = PPP_INITFCS; + pppos->in_state = PDADDRESS; + pppos->in_escaped = 0; + /* Other characters are usually control characters that may have + * been inserted by the physical layer so here we just drop them. */ + } else { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char)); + } + /* Process other characters. */ + } else { + /* Unencode escaped characters. */ + if (pppos->in_escaped) { + pppos->in_escaped = 0; + cur_char ^= PPP_TRANS; + } + + /* Process character relative to current state. */ + switch(pppos->in_state) { + case PDIDLE: /* Idle state - waiting. */ + /* Drop the character if it's not 0xff + * we would have processed a flag character above. */ + if (cur_char != PPP_ALLSTATIONS) { + break; + } + /* no break */ + /* Fall through */ + + case PDSTART: /* Process start flag. */ + /* Prepare for a new packet. */ + pppos->in_fcs = PPP_INITFCS; + /* no break */ + /* Fall through */ + + case PDADDRESS: /* Process address field. */ + if (cur_char == PPP_ALLSTATIONS) { + pppos->in_state = PDCONTROL; + break; + } + /* no break */ + + /* Else assume compressed address and control fields so + * fall through to get the protocol... */ + /* Fall through */ + case PDCONTROL: /* Process control field. */ + /* If we don't get a valid control code, restart. */ + if (cur_char == PPP_UI) { + pppos->in_state = PDPROTOCOL1; + break; + } + /* no break */ + +#if 0 + else { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char)); + pppos->in_state = PDSTART; + } +#endif + /* Fall through */ + + case PDPROTOCOL1: /* Process protocol field 1. */ + /* If the lower bit is set, this is the end of the protocol + * field. */ + if (cur_char & 1) { + pppos->in_protocol = cur_char; + pppos->in_state = PDDATA; + } else { + pppos->in_protocol = (u16_t)cur_char << 8; + pppos->in_state = PDPROTOCOL2; + } + break; + case PDPROTOCOL2: /* Process protocol field 2. */ + pppos->in_protocol |= cur_char; + pppos->in_state = PDDATA; + break; + case PDDATA: /* Process data byte. */ + /* Make space to receive processed data. */ + if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) { + u16_t pbuf_alloc_len; + if (pppos->in_tail != NULL) { + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + /* give up the in_tail reference now */ + pppos->in_tail = NULL; + } + } + /* If we haven't started a packet, we need a packet header. */ + pbuf_alloc_len = 0; +#if IP_FORWARD || LWIP_IPV6_FORWARD + /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN + * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header + * space to be forwarded (to Ethernet for example). + */ + if (pppos->in_head == NULL) { + pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; + } +#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ + next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL); + if (next_pbuf == NULL) { + /* No free buffers. Drop the input packet and let the + * higher layers deal with it. Continue processing + * the received pbuf chain in case a new packet starts. */ + PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + pppos_input_drop(pppos); + pppos->in_state = PDSTART; /* Wait for flag sequence. */ + break; + } + if (pppos->in_head == NULL) { + u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len; +#if PPP_INPROC_IRQ_SAFE + ((struct pppos_input_header*)payload)->ppp = ppp; + payload += sizeof(struct pppos_input_header); + next_pbuf->len += sizeof(struct pppos_input_header); +#endif /* PPP_INPROC_IRQ_SAFE */ + next_pbuf->len += sizeof(pppos->in_protocol); + *(payload++) = pppos->in_protocol >> 8; + *(payload) = pppos->in_protocol & 0xFF; + pppos->in_head = next_pbuf; + } + pppos->in_tail = next_pbuf; + } + /* Load character into buffer. */ + ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char; + break; + default: + break; + } + + /* update the frame check sequence number. */ + pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char); + } + } /* while (l-- > 0), all bytes processed */ +} + +#if PPP_INPROC_IRQ_SAFE +/* PPPoS input callback using one input pointer + */ +static void pppos_input_callback(void *arg) { + struct pbuf *pb = (struct pbuf*)arg; + ppp_pcb *ppp; + + ppp = ((struct pppos_input_header*)pb->payload)->ppp; + if(pbuf_remove_header(pb, sizeof(struct pppos_input_header))) { + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + goto drop; + } + + /* Dispatch the packet thereby consuming it. */ + ppp_input(ppp, pb); + return; + +drop: + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); + pbuf_free(pb); +} +#endif /* PPP_INPROC_IRQ_SAFE */ + +static void +pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) +{ + int i; + pppos_pcb *pppos = (pppos_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + + pppos->pcomp = pcomp; + pppos->accomp = accomp; + + /* Load the ACCM bits for the 32 control codes. */ + for (i = 0; i < 32/8; i++) { + pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF); + } + + PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n", + pppos->ppp->netif->num, + pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3])); +} + +static void +pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) +{ + int i; + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + LWIP_UNUSED_ARG(ppp); + LWIP_UNUSED_ARG(pcomp); + LWIP_UNUSED_ARG(accomp); + + /* Load the ACCM bits for the 32 control codes. */ + PPPOS_PROTECT(lev); + for (i = 0; i < 32 / 8; i++) { + pppos->in_accm[i] = (u8_t)(accm >> (i * 8)); + } + PPPOS_UNPROTECT(lev); + + PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n", + pppos->ppp->netif->num, + pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3])); +} + +/* + * Drop the input packet. + */ +static void +pppos_input_free_current_packet(pppos_pcb *pppos) +{ + if (pppos->in_head != NULL) { + if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) { + pbuf_free(pppos->in_tail); + } + pbuf_free(pppos->in_head); + pppos->in_head = NULL; + } + pppos->in_tail = NULL; +} + +/* + * Drop the input packet and increase error counters. + */ +static void +pppos_input_drop(pppos_pcb *pppos) +{ + if (pppos->in_head != NULL) { +#if 0 + PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload)); +#endif + PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head)); + } + pppos_input_free_current_packet(pppos); +#if VJ_SUPPORT + vj_uncompress_err(&pppos->ppp->vj_comp); +#endif /* VJ_SUPPORT */ + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards); +} + +/* + * pppos_output_append - append given character to end of given pbuf. + * If out_accm is not 0 and the character needs to be escaped, do so. + * If pbuf is full, send the pbuf and reuse it. + * Return the current pbuf. + */ +static err_t +pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs) +{ + if (err != ERR_OK) { + return err; + } + + /* Make sure there is room for the character and an escape code. + * Sure we don't quite fill the buffer if the character doesn't + * get escaped but is one character worth complicating this? */ + if ((PBUF_POOL_BUFSIZE - nb->len) < 2) { + u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb); + if (l != nb->len) { + return ERR_IF; + } + nb->len = 0; + } + + /* Update FCS before checking for special characters. */ + if (fcs) { + *fcs = PPP_FCS(*fcs, c); + } + + /* Copy to output buffer escaping special characters. */ + if (accm && ESCAPE_P(pppos->out_accm, c)) { + *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE; + *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS; + } else { + *((u8_t*)nb->payload + nb->len++) = c; + } + + return ERR_OK; +} + +static err_t +pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs) +{ + ppp_pcb *ppp = pppos->ppp; + + /* Add FCS and trailing flag. */ + err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL); + err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL); + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + + if (err != ERR_OK) { + goto failed; + } + + /* Send remaining buffer if not empty */ + if (nb->len > 0) { + u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb); + if (l != nb->len) { + err = ERR_IF; + goto failed; + } + } + + pppos->last_xmit = sys_now(); + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + pbuf_free(nb); + return ERR_OK; + +failed: + pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */ + LINK_STATS_INC(link.err); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(nb); + return err; +} + +#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/upap.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/upap.c new file mode 100644 index 0000000..3b2399d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/upap.c @@ -0,0 +1,677 @@ +/* + * upap.c - User/Password Authentication Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/upap.h" + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t pap_option_list[] = { + { "hide-password", o_bool, &hide_password, + "Don't output passwords to log", OPT_PRIO | 1 }, + { "show-password", o_bool, &hide_password, + "Show password string in debug log messages", OPT_PRIOSUB | 0 }, + + { "pap-restart", o_int, &upap[0].us_timeouttime, + "Set retransmit timeout for PAP", OPT_PRIO }, + { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, + "Set max number of transmissions for auth-reqs", OPT_PRIO }, + { "pap-timeout", o_int, &upap[0].us_reqtimeout, + "Set time limit for peer PAP authentication", OPT_PRIO }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points. + */ +static void upap_init(ppp_pcb *pcb); +static void upap_lowerup(ppp_pcb *pcb); +static void upap_lowerdown(ppp_pcb *pcb); +static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l); +static void upap_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent pap_protent = { + PPP_PAP, + upap_init, + upap_input, + upap_protrej, + upap_lowerup, + upap_lowerdown, + NULL, + NULL, +#if PRINTPKT_SUPPORT + upap_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "PAP", + NULL, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + pap_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +static void upap_timeout(void *arg); +#if PPP_SERVER +static void upap_reqtimeout(void *arg); +static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len); +#endif /* PPP_SERVER */ +static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len); +static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len); +static void upap_sauthreq(ppp_pcb *pcb); +#if PPP_SERVER +static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen); +#endif /* PPP_SERVER */ + + +/* + * upap_init - Initialize a UPAP unit. + */ +static void upap_init(ppp_pcb *pcb) { + pcb->upap.us_user = NULL; + pcb->upap.us_userlen = 0; + pcb->upap.us_passwd = NULL; + pcb->upap.us_passwdlen = 0; + pcb->upap.us_clientstate = UPAPCS_INITIAL; +#if PPP_SERVER + pcb->upap.us_serverstate = UPAPSS_INITIAL; +#endif /* PPP_SERVER */ + pcb->upap.us_id = 0; +} + + +/* + * upap_authwithpeer - Authenticate us with our peer (start client). + * + * Set new state and send authenticate's. + */ +void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) { + + if(!user || !password) + return; + + /* Save the username and password we're given */ + pcb->upap.us_user = user; + pcb->upap.us_userlen = (u8_t)LWIP_MIN(strlen(user), 0xff); + pcb->upap.us_passwd = password; + pcb->upap.us_passwdlen = (u8_t)LWIP_MIN(strlen(password), 0xff); + pcb->upap.us_transmits = 0; + + /* Lower layer up yet? */ + if (pcb->upap.us_clientstate == UPAPCS_INITIAL || + pcb->upap.us_clientstate == UPAPCS_PENDING) { + pcb->upap.us_clientstate = UPAPCS_PENDING; + return; + } + + upap_sauthreq(pcb); /* Start protocol */ +} + +#if PPP_SERVER +/* + * upap_authpeer - Authenticate our peer (start server). + * + * Set new state. + */ +void upap_authpeer(ppp_pcb *pcb) { + + /* Lower layer up yet? */ + if (pcb->upap.us_serverstate == UPAPSS_INITIAL || + pcb->upap.us_serverstate == UPAPSS_PENDING) { + pcb->upap.us_serverstate = UPAPSS_PENDING; + return; + } + + pcb->upap.us_serverstate = UPAPSS_LISTEN; + if (pcb->settings.pap_req_timeout > 0) + TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); +} +#endif /* PPP_SERVER */ + +/* + * upap_timeout - Retransmission timer for sending auth-reqs expired. + */ +static void upap_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) + return; + + if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) { + /* give up in disgust */ + ppp_error("No response to PAP authenticate-requests"); + pcb->upap.us_clientstate = UPAPCS_BADAUTH; + auth_withpeer_fail(pcb, PPP_PAP); + return; + } + + upap_sauthreq(pcb); /* Send Authenticate-Request */ +} + + +#if PPP_SERVER +/* + * upap_reqtimeout - Give up waiting for the peer to send an auth-req. + */ +static void upap_reqtimeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->upap.us_serverstate != UPAPSS_LISTEN) + return; /* huh?? */ + + auth_peer_fail(pcb, PPP_PAP); + pcb->upap.us_serverstate = UPAPSS_BADAUTH; +} +#endif /* PPP_SERVER */ + + +/* + * upap_lowerup - The lower layer is up. + * + * Start authenticating if pending. + */ +static void upap_lowerup(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_INITIAL) + pcb->upap.us_clientstate = UPAPCS_CLOSED; + else if (pcb->upap.us_clientstate == UPAPCS_PENDING) { + upap_sauthreq(pcb); /* send an auth-request */ + } + +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_INITIAL) + pcb->upap.us_serverstate = UPAPSS_CLOSED; + else if (pcb->upap.us_serverstate == UPAPSS_PENDING) { + pcb->upap.us_serverstate = UPAPSS_LISTEN; + if (pcb->settings.pap_req_timeout > 0) + TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); + } +#endif /* PPP_SERVER */ +} + + +/* + * upap_lowerdown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void upap_lowerdown(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ + UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */ +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0) + UNTIMEOUT(upap_reqtimeout, pcb); +#endif /* PPP_SERVER */ + + pcb->upap.us_clientstate = UPAPCS_INITIAL; +#if PPP_SERVER + pcb->upap.us_serverstate = UPAPSS_INITIAL; +#endif /* PPP_SERVER */ +} + + +/* + * upap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen. In any case, pretend lower layer went down. + */ +static void upap_protrej(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) { + ppp_error("PAP authentication failed due to protocol-reject"); + auth_withpeer_fail(pcb, PPP_PAP); + } +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_LISTEN) { + ppp_error("PAP authentication of peer failed (protocol-reject)"); + auth_peer_fail(pcb, PPP_PAP); + } +#endif /* PPP_SERVER */ + upap_lowerdown(pcb); +} + + +/* + * upap_input - Input UPAP packet. + */ +static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) { + u_char *inp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (l < UPAP_HEADERLEN) { + UPAPDEBUG(("pap_input: rcvd short header.")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < UPAP_HEADERLEN) { + UPAPDEBUG(("pap_input: rcvd illegal length.")); + return; + } + if (len > l) { + UPAPDEBUG(("pap_input: rcvd short packet.")); + return; + } + len -= UPAP_HEADERLEN; + + /* + * Action depends on code. + */ + switch (code) { + case UPAP_AUTHREQ: +#if PPP_SERVER + upap_rauthreq(pcb, inp, id, len); +#endif /* PPP_SERVER */ + break; + + case UPAP_AUTHACK: + upap_rauthack(pcb, inp, id, len); + break; + + case UPAP_AUTHNAK: + upap_rauthnak(pcb, inp, id, len); + break; + + default: /* XXX Need code reject */ + break; + } +} + +#if PPP_SERVER +/* + * upap_rauth - Receive Authenticate. + */ +static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char ruserlen, rpasswdlen; + char *ruser; + char *rpasswd; + char rhostname[256]; + int retcode; + const char *msg; + int msglen; + + if (pcb->upap.us_serverstate < UPAPSS_LISTEN) + return; + + /* + * If we receive a duplicate authenticate-request, we are + * supposed to return the same status as for the first request. + */ + if (pcb->upap.us_serverstate == UPAPSS_OPEN) { + upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ + return; + } + if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) { + upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ + return; + } + + /* + * Parse user/passwd. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + GETCHAR(ruserlen, inp); + len -= sizeof (u_char) + ruserlen + sizeof (u_char); + if (len < 0) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + ruser = (char *) inp; + INCPTR(ruserlen, inp); + GETCHAR(rpasswdlen, inp); + if (len < rpasswdlen) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + + rpasswd = (char *) inp; + + /* + * Check the username and password given. + */ + retcode = UPAP_AUTHNAK; + if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) { + retcode = UPAP_AUTHACK; + } + BZERO(rpasswd, rpasswdlen); + +#if 0 /* UNUSED */ + /* + * Check remote number authorization. A plugin may have filled in + * the remote number or added an allowed number, and rather than + * return an authenticate failure, is leaving it for us to verify. + */ + if (retcode == UPAP_AUTHACK) { + if (!auth_number()) { + /* We do not want to leak info about the pap result. */ + retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */ + warn("calling number %q is not authorized", remote_number); + } + } + + msglen = strlen(msg); + if (msglen > 255) + msglen = 255; +#endif /* UNUSED */ + + upap_sresp(pcb, retcode, id, msg, msglen); + + /* Null terminate and clean remote name. */ + ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser); + + if (retcode == UPAP_AUTHACK) { + pcb->upap.us_serverstate = UPAPSS_OPEN; + ppp_notice("PAP peer authentication succeeded for %q", rhostname); + auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen); + } else { + pcb->upap.us_serverstate = UPAPSS_BADAUTH; + ppp_warn("PAP peer authentication failed for %q", rhostname); + auth_peer_fail(pcb, PPP_PAP); + } + + if (pcb->settings.pap_req_timeout > 0) + UNTIMEOUT(upap_reqtimeout, pcb); +} +#endif /* PPP_SERVER */ + +/* + * upap_rauthack - Receive Authenticate-Ack. + */ +static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char msglen; + char *msg; + LWIP_UNUSED_ARG(id); + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ + return; + + /* + * Parse message. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauthack: ignoring missing msg-length.")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(("pap_rauthack: rcvd short packet.")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + + pcb->upap.us_clientstate = UPAPCS_OPEN; + + auth_withpeer_success(pcb, PPP_PAP, 0); +} + + +/* + * upap_rauthnak - Receive Authenticate-Nak. + */ +static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char msglen; + char *msg; + LWIP_UNUSED_ARG(id); + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ + return; + + /* + * Parse message. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length.")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(("pap_rauthnak: rcvd short packet.")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + + pcb->upap.us_clientstate = UPAPCS_BADAUTH; + + ppp_error("PAP authentication failed"); + auth_withpeer_fail(pcb, PPP_PAP); +} + + +/* + * upap_sauthreq - Send an Authenticate-Request. + */ +static void upap_sauthreq(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + + pcb->upap.us_userlen + pcb->upap.us_passwdlen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(UPAP_AUTHREQ, outp); + PUTCHAR(++pcb->upap.us_id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(pcb->upap.us_userlen, outp); + MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen); + INCPTR(pcb->upap.us_userlen, outp); + PUTCHAR(pcb->upap.us_passwdlen, outp); + MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen); + + ppp_write(pcb, p); + + TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time); + ++pcb->upap.us_transmits; + pcb->upap.us_clientstate = UPAPCS_AUTHREQ; +} + +#if PPP_SERVER +/* + * upap_sresp - Send a response (ack or nak). + */ +static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) { + struct pbuf *p; + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(msglen, outp); + MEMCPY(outp, msg, msglen); + + ppp_write(pcb, p); +} +#endif /* PPP_SERVER */ + +#if PRINTPKT_SUPPORT +/* + * upap_printpkt - print the contents of a PAP packet. + */ +static const char* const upap_codenames[] = { + "AuthReq", "AuthAck", "AuthNak" +}; + +static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len; + int mlen, ulen, wlen; + const u_char *user, *pwd, *msg; + const u_char *pstart; + + if (plen < UPAP_HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < UPAP_HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames)) + printer(arg, " %s", upap_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= UPAP_HEADERLEN; + switch (code) { + case UPAP_AUTHREQ: + if (len < 1) + break; + ulen = p[0]; + if (len < ulen + 2) + break; + wlen = p[ulen + 1]; + if (len < ulen + wlen + 2) + break; + user = (const u_char *) (p + 1); + pwd = (const u_char *) (p + ulen + 2); + p += ulen + wlen + 2; + len -= ulen + wlen + 2; + printer(arg, " user="); + ppp_print_string(user, ulen, printer, arg); + printer(arg, " password="); +/* FIXME: require ppp_pcb struct as printpkt() argument */ +#if 0 + if (!pcb->settings.hide_password) +#endif + ppp_print_string(pwd, wlen, printer, arg); +#if 0 + else + printer(arg, ""); +#endif + break; + case UPAP_AUTHACK: + case UPAP_AUTHNAK: + if (len < 1) + break; + mlen = p[0]; + if (len < mlen + 1) + break; + msg = (const u_char *) (p + 1); + p += mlen + 1; + len -= mlen + 1; + printer(arg, " "); + ppp_print_string(msg, mlen, printer, arg); + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/utils.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/utils.c new file mode 100644 index 0000000..f1366da --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/utils.c @@ -0,0 +1,957 @@ +/* + * utils.c - various utility functions used in pppd. + * + * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SVR4 +#include +#endif +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" + +#if defined(SUNOS4) +extern char *strerror(); +#endif + +static void ppp_logit(int level, const char *fmt, va_list args); +static void ppp_log_write(int level, char *buf); +#if PRINTPKT_SUPPORT +static void ppp_vslp_printer(void *arg, const char *fmt, ...); +static void ppp_format_packet(const u_char *p, int len, + void (*printer) (void *, const char *, ...), void *arg); + +struct buffer_info { + char *ptr; + int len; +}; +#endif /* PRINTPKT_SUPPORT */ + +/* + * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +size_t ppp_strlcpy(char *dest, const char *src, size_t len) { + size_t ret = strlen(src); + + if (len != 0) { + if (ret < len) + strcpy(dest, src); + else { + strncpy(dest, src, len - 1); + dest[len-1] = 0; + } + } + return ret; +} + +/* + * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +size_t ppp_strlcat(char *dest, const char *src, size_t len) { + size_t dlen = strlen(dest); + + return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0)); +} + + +/* + * ppp_slprintf - format a message into a buffer. Like sprintf except we + * also specify the length of the output buffer, and we handle + * %m (error message), %v (visible string), + * %q (quoted string), %t (current time) and %I (IP address) formats. + * Doesn't do floating-point formats. + * Returns the number of chars put into buf. + */ +int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) { + va_list args; + int n; + + va_start(args, fmt); + n = ppp_vslprintf(buf, buflen, fmt, args); + va_end(args); + return n; +} + +/* + * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args. + */ +#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) + +int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) { + int c, i, n; + int width, prec, fillch; + int base, len, neg, quoted; + unsigned long val = 0; + const char *f; + char *str, *buf0; + const unsigned char *p; + char num[32]; +#if 0 /* need port */ + time_t t; +#endif /* need port */ + u32_t ip; + static char hexchars[] = "0123456789abcdef"; +#if PRINTPKT_SUPPORT + struct buffer_info bufinfo; +#endif /* PRINTPKT_SUPPORT */ + + buf0 = buf; + --buflen; + while (buflen > 0) { + for (f = fmt; *f != '%' && *f != 0; ++f) + ; + if (f > fmt) { + len = f - fmt; + if (len > buflen) + len = buflen; + memcpy(buf, fmt, len); + buf += len; + buflen -= len; + fmt = f; + } + if (*fmt == 0) + break; + c = *++fmt; + width = 0; + prec = -1; + fillch = ' '; + if (c == '0') { + fillch = '0'; + c = *++fmt; + } + if (c == '*') { + width = va_arg(args, int); + c = *++fmt; + } else { + while (lwip_isdigit(c)) { + width = width * 10 + c - '0'; + c = *++fmt; + } + } + if (c == '.') { + c = *++fmt; + if (c == '*') { + prec = va_arg(args, int); + c = *++fmt; + } else { + prec = 0; + while (lwip_isdigit(c)) { + prec = prec * 10 + c - '0'; + c = *++fmt; + } + } + } + str = 0; + base = 0; + neg = 0; + ++fmt; + switch (c) { + case 'l': + c = *fmt++; + switch (c) { + case 'd': + val = va_arg(args, long); + if ((long)val < 0) { + neg = 1; + val = (unsigned long)-(long)val; + } + base = 10; + break; + case 'u': + val = va_arg(args, unsigned long); + base = 10; + break; + default: + OUTCHAR('%'); + OUTCHAR('l'); + --fmt; /* so %lz outputs %lz etc. */ + continue; + } + break; + case 'd': + i = va_arg(args, int); + if (i < 0) { + neg = 1; + val = -i; + } else + val = i; + base = 10; + break; + case 'u': + val = va_arg(args, unsigned int); + base = 10; + break; + case 'o': + val = va_arg(args, unsigned int); + base = 8; + break; + case 'x': + case 'X': + val = va_arg(args, unsigned int); + base = 16; + break; +#if 0 /* unused (and wrong on LLP64 systems) */ + case 'p': + val = (unsigned long) va_arg(args, void *); + base = 16; + neg = 2; + break; +#endif /* unused (and wrong on LLP64 systems) */ + case 's': + str = va_arg(args, char *); + break; + case 'c': + num[0] = va_arg(args, int); + num[1] = 0; + str = num; + break; +#if 0 /* do we always have strerror() in embedded ? */ + case 'm': + str = strerror(errno); + break; +#endif /* do we always have strerror() in embedded ? */ + case 'I': + ip = va_arg(args, u32_t); + ip = lwip_ntohl(ip); + ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, + (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + str = num; + break; +#if 0 /* need port */ + case 't': + time(&t); + str = ctime(&t); + str += 4; /* chop off the day name */ + str[15] = 0; /* chop off year and newline */ + break; +#endif /* need port */ + case 'v': /* "visible" string */ + case 'q': /* quoted string */ + quoted = c == 'q'; + p = va_arg(args, unsigned char *); + if (p == NULL) + p = (const unsigned char *)""; + if (fillch == '0' && prec >= 0) { + n = prec; + } else { + n = strlen((const char *)p); + if (prec >= 0 && n > prec) + n = prec; + } + while (n > 0 && buflen > 0) { + c = *p++; + --n; + if (!quoted && c >= 0x80) { + OUTCHAR('M'); + OUTCHAR('-'); + c -= 0x80; + } + if (quoted && (c == '"' || c == '\\')) + OUTCHAR('\\'); + if (c < 0x20 || (0x7f <= c && c < 0xa0)) { + if (quoted) { + OUTCHAR('\\'); + switch (c) { + case '\t': OUTCHAR('t'); break; + case '\n': OUTCHAR('n'); break; + case '\b': OUTCHAR('b'); break; + case '\f': OUTCHAR('f'); break; + default: + OUTCHAR('x'); + OUTCHAR(hexchars[c >> 4]); + OUTCHAR(hexchars[c & 0xf]); + } + } else { + if (c == '\t') + OUTCHAR(c); + else { + OUTCHAR('^'); + OUTCHAR(c ^ 0x40); + } + } + } else + OUTCHAR(c); + } + continue; +#if PRINTPKT_SUPPORT + case 'P': /* print PPP packet */ + bufinfo.ptr = buf; + bufinfo.len = buflen + 1; + p = va_arg(args, unsigned char *); + n = va_arg(args, int); + ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo); + buf = bufinfo.ptr; + buflen = bufinfo.len - 1; + continue; +#endif /* PRINTPKT_SUPPORT */ + case 'B': + p = va_arg(args, unsigned char *); + for (n = prec; n > 0; --n) { + c = *p++; + if (fillch == ' ') + OUTCHAR(' '); + OUTCHAR(hexchars[(c >> 4) & 0xf]); + OUTCHAR(hexchars[c & 0xf]); + } + continue; + default: + *buf++ = '%'; + if (c != '%') + --fmt; /* so %z outputs %z etc. */ + --buflen; + continue; + } + if (base != 0) { + str = num + sizeof(num); + *--str = 0; + while (str > num + neg) { + *--str = hexchars[val % base]; + val = val / base; + if (--prec <= 0 && val == 0) + break; + } + switch (neg) { + case 1: + *--str = '-'; + break; + case 2: + *--str = 'x'; + *--str = '0'; + break; + default: + break; + } + len = num + sizeof(num) - 1 - str; + } else { + len = strlen(str); + if (prec >= 0 && len > prec) + len = prec; + } + if (width > 0) { + if (width > buflen) + width = buflen; + if ((n = width - len) > 0) { + buflen -= n; + for (; n > 0; --n) + *buf++ = fillch; + } + } + if (len > buflen) + len = buflen; + memcpy(buf, str, len); + buf += len; + buflen -= len; + } + *buf = 0; + return buf - buf0; +} + +#if PRINTPKT_SUPPORT +/* + * vslp_printer - used in processing a %P format + */ +static void ppp_vslp_printer(void *arg, const char *fmt, ...) { + int n; + va_list pvar; + struct buffer_info *bi; + + va_start(pvar, fmt); + bi = (struct buffer_info *) arg; + n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar); + va_end(pvar); + + bi->ptr += n; + bi->len -= n; +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * log_packet - format a packet and log it. + */ + +void +log_packet(p, len, prefix, level) + u_char *p; + int len; + char *prefix; + int level; +{ + init_pr_log(prefix, level); + ppp_format_packet(p, len, pr_log, &level); + end_pr_log(); +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ppp_format_packet - make a readable representation of a packet, + * calling `printer(arg, format, ...)' to output it. + */ +static void ppp_format_packet(const u_char *p, int len, + void (*printer) (void *, const char *, ...), void *arg) { + int i, n; + u_short proto; + const struct protent *protp; + + if (len >= 2) { + GETSHORT(proto, p); + len -= 2; + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (proto == protp->protocol) + break; + if (protp != NULL) { + printer(arg, "[%s", protp->name); + n = (*protp->printpkt)(p, len, printer, arg); + printer(arg, "]"); + p += n; + len -= n; + } else { + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (proto == (protp->protocol & ~0x8000)) + break; + if (protp != 0 && protp->data_name != 0) { + printer(arg, "[%s data]", protp->data_name); + if (len > 8) + printer(arg, "%.8B ...", p); + else + printer(arg, "%.*B", len, p); + len = 0; + } else + printer(arg, "[proto=0x%x]", proto); + } + } + + if (len > 32) + printer(arg, "%.32B ...", p); + else + printer(arg, "%.*B", len, p); +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * init_pr_log, end_pr_log - initialize and finish use of pr_log. + */ + +static char line[256]; /* line to be logged accumulated here */ +static char *linep; /* current pointer within line */ +static int llevel; /* level for logging */ + +void +init_pr_log(prefix, level) + const char *prefix; + int level; +{ + linep = line; + if (prefix != NULL) { + ppp_strlcpy(line, prefix, sizeof(line)); + linep = line + strlen(line); + } + llevel = level; +} + +void +end_pr_log() +{ + if (linep != line) { + *linep = 0; + ppp_log_write(llevel, line); + } +} + +/* + * pr_log - printer routine for outputting to log + */ +void +pr_log (void *arg, const char *fmt, ...) +{ + int l, n; + va_list pvar; + char *p, *eol; + char buf[256]; + + va_start(pvar, fmt); + n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar); + va_end(pvar); + + p = buf; + eol = strchr(buf, '\n'); + if (linep != line) { + l = (eol == NULL)? n: eol - buf; + if (linep + l < line + sizeof(line)) { + if (l > 0) { + memcpy(linep, buf, l); + linep += l; + } + if (eol == NULL) + return; + p = eol + 1; + eol = strchr(p, '\n'); + } + *linep = 0; + ppp_log_write(llevel, line); + linep = line; + } + + while (eol != NULL) { + *eol = 0; + ppp_log_write(llevel, p); + p = eol + 1; + eol = strchr(p, '\n'); + } + + /* assumes sizeof(buf) <= sizeof(line) */ + l = buf + n - p; + if (l > 0) { + memcpy(line, p, n); + linep = line + l; + } +} +#endif /* UNUSED */ + +/* + * ppp_print_string - print a readable representation of a string using + * printer. + */ +void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) { + int c; + + printer(arg, "\""); + for (; len > 0; --len) { + c = *p++; + if (' ' <= c && c <= '~') { + if (c == '\\' || c == '"') + printer(arg, "\\"); + printer(arg, "%c", c); + } else { + switch (c) { + case '\n': + printer(arg, "\\n"); + break; + case '\r': + printer(arg, "\\r"); + break; + case '\t': + printer(arg, "\\t"); + break; + default: + printer(arg, "\\%.3o", (u8_t)c); + /* no break */ + } + } + } + printer(arg, "\""); +} + +/* + * ppp_logit - does the hard work for fatal et al. + */ +static void ppp_logit(int level, const char *fmt, va_list args) { + char buf[1024]; + + ppp_vslprintf(buf, sizeof(buf), fmt, args); + ppp_log_write(level, buf); +} + +static void ppp_log_write(int level, char *buf) { + LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */ + LWIP_UNUSED_ARG(buf); + PPPDEBUG(level, ("%s\n", buf) ); +#if 0 + if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { + int n = strlen(buf); + + if (n > 0 && buf[n-1] == '\n') + --n; + if (write(log_to_fd, buf, n) != n + || write(log_to_fd, "\n", 1) != 1) + log_to_fd = -1; + } +#endif +} + +/* + * ppp_fatal - log an error message and die horribly. + */ +void ppp_fatal(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_ERR, fmt, pvar); + va_end(pvar); + + LWIP_ASSERT("ppp_fatal", 0); /* as promised */ +} + +/* + * ppp_error - log an error message. + */ +void ppp_error(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_ERR, fmt, pvar); + va_end(pvar); +#if 0 /* UNUSED */ + ++error_count; +#endif /* UNUSED */ +} + +/* + * ppp_warn - log a warning message. + */ +void ppp_warn(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_WARNING, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_notice - log a notice-level message. + */ +void ppp_notice(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_NOTICE, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_info - log an informational message. + */ +void ppp_info(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_INFO, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_dbglog - log a debug message. + */ +void ppp_dbglog(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_DEBUG, fmt, pvar); + va_end(pvar); +} + +#if PRINTPKT_SUPPORT +/* + * ppp_dump_packet - print out a packet in readable form if it is interesting. + * Assumes len >= PPP_HDRLEN. + */ +void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) { + int proto; + + /* + * don't print data packets, i.e. IPv4, IPv6, VJ, and compressed packets. + */ + proto = (p[0] << 8) + p[1]; + if (proto < 0xC000 && (proto & ~0x8000) == proto) + return; + + /* + * don't print valid LCP echo request/reply packets if the link is up. + */ + if (proto == PPP_LCP && pcb->phase == PPP_PHASE_RUNNING && len >= 2 + HEADERLEN) { + unsigned char *lcp = p + 2; + int l = (lcp[2] << 8) + lcp[3]; + + if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP) + && l >= HEADERLEN && l <= len - 2) + return; + } + + ppp_dbglog("%s %P", tag, p, len); +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* Unused */ + +/* + * complete_read - read a full `count' bytes from fd, + * unless end-of-file or an error other than EINTR is encountered. + */ +ssize_t +complete_read(int fd, void *buf, size_t count) +{ + size_t done; + ssize_t nb; + char *ptr = buf; + + for (done = 0; done < count; ) { + nb = read(fd, ptr, count - done); + if (nb < 0) { + if (errno == EINTR) + continue; + return -1; + } + if (nb == 0) + break; + done += nb; + ptr += nb; + } + return done; +} + +/* Procedures for locking the serial device using a lock file. */ +#ifndef LOCK_DIR +#ifdef __linux__ +#define LOCK_DIR "/var/lock" +#else +#ifdef SVR4 +#define LOCK_DIR "/var/spool/locks" +#else +#define LOCK_DIR "/var/spool/lock" +#endif +#endif +#endif /* LOCK_DIR */ + +static char lock_file[MAXPATHLEN]; + +/* + * lock - create a lock file for the named device + */ +int +lock(dev) + char *dev; +{ +#ifdef LOCKLIB + int result; + + result = mklock (dev, (void *) 0); + if (result == 0) { + ppp_strlcpy(lock_file, dev, sizeof(lock_file)); + return 0; + } + + if (result > 0) + ppp_notice("Device %s is locked by pid %d", dev, result); + else + ppp_error("Can't create lock file %s", lock_file); + return -1; + +#else /* LOCKLIB */ + + char lock_buffer[12]; + int fd, pid, n; + +#ifdef SVR4 + struct stat sbuf; + + if (stat(dev, &sbuf) < 0) { + ppp_error("Can't get device number for %s: %m", dev); + return -1; + } + if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { + ppp_error("Can't lock %s: not a character device", dev); + return -1; + } + ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", + LOCK_DIR, major(sbuf.st_dev), + major(sbuf.st_rdev), minor(sbuf.st_rdev)); +#else + char *p; + char lockdev[MAXPATHLEN]; + + if ((p = strstr(dev, "dev/")) != NULL) { + dev = p + 4; + strncpy(lockdev, dev, MAXPATHLEN-1); + lockdev[MAXPATHLEN-1] = 0; + while ((p = strrchr(lockdev, '/')) != NULL) { + *p = '_'; + } + dev = lockdev; + } else + if ((p = strrchr(dev, '/')) != NULL) + dev = p + 1; + + ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev); +#endif + + while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { + if (errno != EEXIST) { + ppp_error("Can't create lock file %s: %m", lock_file); + break; + } + + /* Read the lock file to find out who has the device locked. */ + fd = open(lock_file, O_RDONLY, 0); + if (fd < 0) { + if (errno == ENOENT) /* This is just a timing problem. */ + continue; + ppp_error("Can't open existing lock file %s: %m", lock_file); + break; + } +#ifndef LOCK_BINARY + n = read(fd, lock_buffer, 11); +#else + n = read(fd, &pid, sizeof(pid)); +#endif /* LOCK_BINARY */ + close(fd); + fd = -1; + if (n <= 0) { + ppp_error("Can't read pid from lock file %s", lock_file); + break; + } + + /* See if the process still exists. */ +#ifndef LOCK_BINARY + lock_buffer[n] = 0; + pid = atoi(lock_buffer); +#endif /* LOCK_BINARY */ + if (pid == getpid()) + return 1; /* somebody else locked it for us */ + if (pid == 0 + || (kill(pid, 0) == -1 && errno == ESRCH)) { + if (unlink (lock_file) == 0) { + ppp_notice("Removed stale lock on %s (pid %d)", dev, pid); + continue; + } + ppp_warn("Couldn't remove stale lock on %s", dev); + } else + ppp_notice("Device %s is locked by pid %d", dev, pid); + break; + } + + if (fd < 0) { + lock_file[0] = 0; + return -1; + } + + pid = getpid(); +#ifndef LOCK_BINARY + ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); + write (fd, lock_buffer, 11); +#else + write(fd, &pid, sizeof (pid)); +#endif + close(fd); + return 0; + +#endif +} + +/* + * relock - called to update our lockfile when we are about to detach, + * thus changing our pid (we fork, the child carries on, and the parent dies). + * Note that this is called by the parent, with pid equal to the pid + * of the child. This avoids a potential race which would exist if + * we had the child rewrite the lockfile (the parent might die first, + * and another process could think the lock was stale if it checked + * between when the parent died and the child rewrote the lockfile). + */ +int +relock(pid) + int pid; +{ +#ifdef LOCKLIB + /* XXX is there a way to do this? */ + return -1; +#else /* LOCKLIB */ + + int fd; + char lock_buffer[12]; + + if (lock_file[0] == 0) + return -1; + fd = open(lock_file, O_WRONLY, 0); + if (fd < 0) { + ppp_error("Couldn't reopen lock file %s: %m", lock_file); + lock_file[0] = 0; + return -1; + } + +#ifndef LOCK_BINARY + ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); + write (fd, lock_buffer, 11); +#else + write(fd, &pid, sizeof(pid)); +#endif /* LOCK_BINARY */ + close(fd); + return 0; + +#endif /* LOCKLIB */ +} + +/* + * unlock - remove our lockfile + */ +void +unlock() +{ + if (lock_file[0]) { +#ifdef LOCKLIB + (void) rmlock(lock_file, (void *) 0); +#else + unlink(lock_file); +#endif + lock_file[0] = 0; + } +} + +#endif /* Unused */ + +#endif /* PPP_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/vj.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/vj.c new file mode 100644 index 0000000..3fecba6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/ppp/vj.c @@ -0,0 +1,685 @@ +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * Initial distribution. + * + * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, + * so that the entire packet being decompressed doesn't have + * to be in contiguous memory (just the compressed header). + * + * Modified March 1998 by Guy Lancaster, glanca@gesn.com, + * for a 16 bit processor. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppdebug.h" + +#include "netif/ppp/vj.h" + +#include + +#if LINK_STATS +#define INCR(counter) ++comp->stats.counter +#else +#define INCR(counter) +#endif + +void +vj_compress_init(struct vjcompress *comp) +{ + u8_t i; + struct cstate *tstate = comp->tstate; + +#if MAX_SLOTS == 0 + memset((char *)comp, 0, sizeof(*comp)); +#endif + comp->maxSlotIndex = MAX_SLOTS - 1; + comp->compressSlot = 0; /* Disable slot ID compression by default. */ + for (i = MAX_SLOTS - 1; i > 0; --i) { + tstate[i].cs_id = i; + tstate[i].cs_next = &tstate[i - 1]; + } + tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; + tstate[0].cs_id = 0; + comp->last_cs = &tstate[0]; + comp->last_recv = 255; + comp->last_xmit = 255; + comp->flags = VJF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero. ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ + if ((u16_t)(n) >= 256) { \ + *cp++ = 0; \ + cp[1] = (u8_t)(n); \ + cp[0] = (u8_t)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u8_t)(n); \ + } \ +} +#define ENCODEZ(n) { \ + if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \ + *cp++ = 0; \ + cp[1] = (u8_t)(n); \ + cp[0] = (u8_t)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u8_t)(n); \ + } \ +} + +#define DECODEL(f) { \ + if (*cp == 0) {\ + u32_t tmp_ = lwip_ntohl(f) + ((cp[1] << 8) | cp[2]); \ + (f) = lwip_htonl(tmp_); \ + cp += 3; \ + } else { \ + u32_t tmp_ = lwip_ntohl(f) + (u32_t)*cp++; \ + (f) = lwip_htonl(tmp_); \ + } \ +} + +#define DECODES(f) { \ + if (*cp == 0) {\ + u16_t tmp_ = lwip_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \ + (f) = lwip_htons(tmp_); \ + cp += 3; \ + } else { \ + u16_t tmp_ = lwip_ntohs(f) + (u16_t)*cp++; \ + (f) = lwip_htons(tmp_); \ + } \ +} + +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = lwip_htons(((u16_t)cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = lwip_htons((u16_t)*cp++); \ + } \ +} + +/* Helper structures for unaligned *u32_t and *u16_t accesses */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct vj_u32_t { + PACK_STRUCT_FIELD(u32_t v); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct vj_u16_t { + PACK_STRUCT_FIELD(u16_t v); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* + * vj_compress_tcp - Attempt to do Van Jacobson header compression on a + * packet. This assumes that nb and comp are not null and that the first + * buffer of the chain contains a valid IP header. + * Return the VJ type code indicating whether or not the packet was + * compressed. + */ +u8_t +vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) +{ + struct pbuf *np = *pb; + struct ip_hdr *ip = (struct ip_hdr *)np->payload; + struct cstate *cs = comp->last_cs->cs_next; + u16_t ilen = IPH_HL(ip); + u16_t hlen; + struct tcp_hdr *oth; + struct tcp_hdr *th; + u16_t deltaS, deltaA = 0; + u32_t deltaL; + u32_t changes = 0; + u8_t new_seq[16]; + u8_t *cp = new_seq; + + /* + * Check that the packet is IP proto TCP. + */ + if (IPH_PROTO(ip) != IP_PROTO_TCP) { + return (TYPE_IP); + } + + /* + * Bail if this is an IP fragment or if the TCP packet isn't + * `compressible' (i.e., ACK isn't set or some other control bit is + * set). + */ + if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) { + return (TYPE_IP); + } + th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen]; + if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { + return (TYPE_IP); + } + + /* Check that the TCP/IP headers are contained in the first buffer. */ + hlen = ilen + TCPH_HDRLEN(th); + hlen <<= 2; + if (np->len < hlen) { + PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); + return (TYPE_IP); + } + + /* TCP stack requires that we don't change the packet payload, therefore we copy + * the whole packet before compression. */ + np = pbuf_clone(PBUF_RAW, PBUF_RAM, *pb); + if (!np) { + return (TYPE_IP); + } + + *pb = np; + ip = (struct ip_hdr *)np->payload; + + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need + * to locate (or create) the connection state. Special case the + * most recently used connection since it's most likely to be used + * again & we don't have to do any reordering if it's used. + */ + INCR(vjs_packets); + if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src) + || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { + /* + * Wasn't the first -- search for it. + * + * States are kept in a circularly linked list with + * last_cs pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + struct cstate *lcs; + struct cstate *lastcs = comp->last_cs; + + do { + lcs = cs; cs = cs->cs_next; + INCR(vjs_searches); + if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src) + && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { + goto found; + } + } while (cs != lastcs); + + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * last_cs to update the lru linkage. + */ + INCR(vjs_misses); + comp->last_cs = lcs; + goto uncompressed; + + found: + /* + * Found it -- move to the front on the connection list. + */ + if (cs == lastcs) { + comp->last_cs = lcs; + } else { + lcs->cs_next = cs->cs_next; + cs->cs_next = lastcs->cs_next; + lastcs->cs_next = cs; + } + } + + oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen]; + deltaS = ilen; + + /* + * Make sure that only what we expect to change changed. The first + * line of the `if' checks the IP protocol version, header length & + * type of service. The 2nd line checks the "Don't fragment" bit. + * The 3rd line checks the time-to-live and protocol (the protocol + * check is unnecessary but costless). The 4th line checks the TCP + * header length. The 5th line checks IP options, if any. The 6th + * line checks TCP options, if any. If any of these things are + * different between the previous & current datagram, we send the + * current datagram `uncompressed'. + */ + if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v + || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v + || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v + || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth) + || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) + || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) { + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if (TCPH_FLAGS(th) & TCP_URG) { + deltaS = lwip_ntohs(th->urgp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->urgp != oth->urgp) { + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + + if ((deltaS = (u16_t)(lwip_ntohs(th->wnd) - lwip_ntohs(oth->wnd))) != 0) { + ENCODE(deltaS); + changes |= NEW_W; + } + + if ((deltaL = lwip_ntohl(th->ackno) - lwip_ntohl(oth->ackno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaA = (u16_t)deltaL; + ENCODE(deltaA); + changes |= NEW_A; + } + + if ((deltaL = lwip_ntohl(th->seqno) - lwip_ntohl(oth->seqno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaS = (u16_t)deltaL; + ENCODE(deltaS); + changes |= NEW_S; + } + + switch(changes) { + case 0: + /* + * Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && + lwip_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { + break; + } + /* no break */ + /* fall through */ + + case SPECIAL_I: + case SPECIAL_D: + /* + * actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + + case NEW_S|NEW_A: + if (deltaS == deltaA && deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + default: + break; + } + + deltaS = (u16_t)(lwip_ntohs(IPH_ID(ip)) - lwip_ntohs(IPH_ID(&cs->cs_ip))); + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + if (TCPH_FLAGS(th) & TCP_PSH) { + changes |= TCP_PUSH_BIT; + } + /* + * Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = lwip_ntohs(th->chksum); + MEMCPY(&cs->cs_ip, ip, hlen); + + /* + * We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how + * many bytes of the original packet to toss so subtract the two to + * get the new packet size. + */ + deltaS = (u16_t)(cp - new_seq); + if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + if (pbuf_remove_header(np, hlen)){ + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + } + cp = (u8_t*)np->payload; + *cp++ = (u8_t)(changes | NEW_C); + *cp++ = cs->cs_id; + } else { + hlen -= deltaS + 3; + if (pbuf_remove_header(np, hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + } + cp = (u8_t*)np->payload; + *cp++ = (u8_t)changes; + } + *cp++ = (u8_t)(deltaA >> 8); + *cp++ = (u8_t)deltaA; + MEMCPY(cp, new_seq, deltaS); + INCR(vjs_compressed); + return (TYPE_COMPRESSED_TCP); + + /* + * Update connection state cs & send uncompressed packet (that is, + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + MEMCPY(&cs->cs_ip, ip, hlen); + IPH_PROTO_SET(ip, cs->cs_id); + comp->last_xmit = cs->cs_id; + return (TYPE_UNCOMPRESSED_TCP); +} + +/* + * Called when we may have missed a packet. + */ +void +vj_uncompress_err(struct vjcompress *comp) +{ + comp->flags |= VJF_TOSS; + INCR(vjs_errorin); +} + +/* + * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. + * Return 0 on success, -1 on failure. + */ +int +vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) +{ + u32_t hlen; + struct cstate *cs; + struct ip_hdr *ip; + + ip = (struct ip_hdr *)nb->payload; + hlen = IPH_HL(ip) << 2; + if (IPH_PROTO(ip) >= MAX_SLOTS + || hlen + sizeof(struct tcp_hdr) > nb->len + || (hlen += TCPH_HDRLEN_BYTES((struct tcp_hdr *)&((char *)ip)[hlen])) + > nb->len + || hlen > MAX_HDR) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", + IPH_PROTO(ip), hlen, nb->len)); + vj_uncompress_err(comp); + return -1; + } + cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; + comp->flags &=~ VJF_TOSS; + IPH_PROTO_SET(ip, IP_PROTO_TCP); + /* copy from/to bigger buffers checked above instead of cs->cs_ip and ip + just to help static code analysis to see this is correct ;-) */ + MEMCPY(&cs->cs_hdr, nb->payload, hlen); + cs->cs_hlen = (u16_t)hlen; + INCR(vjs_uncompressedin); + return 0; +} + +/* + * Uncompress a packet of type TYPE_COMPRESSED_TCP. + * The packet is composed of a buffer chain and the first buffer + * must contain an accurate chain length. + * The first buffer must include the entire compressed TCP/IP header. + * This procedure replaces the compressed header with the uncompressed + * header and returns the length of the VJ header. + */ +int +vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) +{ + u8_t *cp; + struct tcp_hdr *th; + struct cstate *cs; + struct vj_u16_t *bp; + struct pbuf *n0 = *nb; + u32_t tmp; + u32_t vjlen, hlen, changes; + + INCR(vjs_compressedin); + cp = (u8_t*)n0->payload; + changes = *cp++; + if (changes & NEW_C) { + /* + * Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + if (*cp >= MAX_SLOTS) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); + goto bad; + } + + comp->flags &=~ VJF_TOSS; + comp->last_recv = *cp++; + } else { + /* + * this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. + */ + if (comp->flags & VJF_TOSS) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); + INCR(vjs_tossed); + return (-1); + } + } + cs = &comp->rstate[comp->last_recv]; + hlen = IPH_HL(&cs->cs_ip) << 2; + th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen]; + th->chksum = lwip_htons((*cp << 8) | cp[1]); + cp += 2; + if (changes & TCP_PUSH_BIT) { + TCPH_SET_FLAG(th, TCP_PSH); + } else { + TCPH_UNSET_FLAG(th, TCP_PSH); + } + + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + u32_t i = lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + /* some compilers can't nest inline assembler.. */ + tmp = lwip_ntohl(th->ackno) + i; + th->ackno = lwip_htonl(tmp); + tmp = lwip_ntohl(th->seqno) + i; + th->seqno = lwip_htonl(tmp); + } + break; + + case SPECIAL_D: + /* some compilers can't nest inline assembler.. */ + tmp = lwip_ntohl(th->seqno) + lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + th->seqno = lwip_htonl(tmp); + break; + + default: + if (changes & NEW_U) { + TCPH_SET_FLAG(th, TCP_URG); + DECODEU(th->urgp); + } else { + TCPH_UNSET_FLAG(th, TCP_URG); + } + if (changes & NEW_W) { + DECODES(th->wnd); + } + if (changes & NEW_A) { + DECODEL(th->ackno); + } + if (changes & NEW_S) { + DECODEL(th->seqno); + } + break; + } + if (changes & NEW_I) { + DECODES(cs->cs_ip._id); + } else { + IPH_ID_SET(&cs->cs_ip, lwip_ntohs(IPH_ID(&cs->cs_ip)) + 1); + IPH_ID_SET(&cs->cs_ip, lwip_htons(IPH_ID(&cs->cs_ip))); + } + + /* + * At this point, cp points to the first byte of data in the + * packet. Fill in the IP total length and update the IP + * header checksum. + */ + vjlen = (u16_t)(cp - (u8_t*)n0->payload); + if (n0->len < vjlen) { + /* + * We must have dropped some characters (crc should detect + * this but the old slip framing won't) + */ + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", + n0->len, vjlen)); + goto bad; + } + +#if BYTE_ORDER == LITTLE_ENDIAN + tmp = n0->tot_len - vjlen + cs->cs_hlen; + IPH_LEN_SET(&cs->cs_ip, lwip_htons((u16_t)tmp)); +#else + IPH_LEN_SET(&cs->cs_ip, lwip_htons(n0->tot_len - vjlen + cs->cs_hlen)); +#endif + + /* recompute the ip header checksum */ + bp = (struct vj_u16_t*) &cs->cs_ip; + IPH_CHKSUM_SET(&cs->cs_ip, 0); + for (tmp = 0; hlen > 0; hlen -= 2) { + tmp += (*bp++).v; + } + tmp = (tmp & 0xffff) + (tmp >> 16); + tmp = (tmp & 0xffff) + (tmp >> 16); + IPH_CHKSUM_SET(&cs->cs_ip, (u16_t)(~tmp)); + + /* Remove the compressed header and prepend the uncompressed header. */ + if (pbuf_remove_header(n0, vjlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + goto bad; + } + + if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { + struct pbuf *np; + +#if IP_FORWARD + /* If IP forwarding is enabled we are using a PBUF_LINK packet type so + * the packet is being allocated with enough header space to be + * forwarded (to Ethernet for example). + */ + np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL); +#else /* IP_FORWARD */ + np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); +#endif /* IP_FORWARD */ + if(!np) { + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); + goto bad; + } + + if (pbuf_remove_header(np, cs->cs_hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_remove_header failed\n", 0); + goto bad; + } + + pbuf_take(np, n0->payload, n0->len); + + if(n0->next) { + pbuf_chain(np, n0->next); + pbuf_dechain(n0); + } + pbuf_free(n0); + n0 = np; + } + + if (pbuf_add_header(n0, cs->cs_hlen)) { + struct pbuf *np; + + LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); + np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); + if(!np) { + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); + goto bad; + } + pbuf_cat(np, n0); + n0 = np; + } + LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); + MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); + + *nb = n0; + + return vjlen; + +bad: + vj_uncompress_err(comp); + return (-1); +} + +#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/slipif.xcx b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/slipif.xcx new file mode 100644 index 0000000..9b175dc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/slipif.xcx @@ -0,0 +1,558 @@ +/** + * @file + * SLIP Interface + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is built upon the file: src/arch/rtxc/netif/sioslip.c + * + * Author: Magnus Ivarsson + * Simon Goldschmidt + */ + + +/** + * @defgroup slipif SLIP + * @ingroup netifs + * + * This is an arch independent SLIP netif. The specific serial hooks must be + * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send + * + * Usage: This netif can be used in three ways:\n + * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() + * until data is received.\n + * 2) In your main loop, call slipif_poll() to check for new RX bytes, + * completed packets are fed into netif->input().\n + * 3) Call slipif_received_byte[s]() from your serial RX ISR and + * slipif_process_rxqueue() from your main loop. ISR level decodes + * packets and puts completed packets on a queue which is fed into + * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for + * pbuf_alloc to work on ISR level!). + * + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/sys.h" +#include "lwip/sio.h" + +#define SLIP_END 0xC0 /* 0300: start and end of every packet */ +#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ +#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ +#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ + +/** Maximum packet size that is received by this netif */ +#ifndef SLIP_MAX_SIZE +#define SLIP_MAX_SIZE 1500 +#endif + +/** Define this to the interface speed for SNMP + * (sio_fd is the sio_fd_t returned by sio_open). + * The default value of zero means 'unknown'. + */ +#ifndef SLIP_SIO_SPEED +#define SLIP_SIO_SPEED(sio_fd) 0 +#endif + +enum slipif_recv_state { + SLIP_RECV_NORMAL, + SLIP_RECV_ESCAPE +}; + +struct slipif_priv { + sio_fd_t sd; + /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ + struct pbuf *p, *q; + u8_t state; + u16_t i, recved; +#if SLIP_RX_FROM_ISR + struct pbuf *rxpackets; +#endif +}; + +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output(struct netif *netif, struct pbuf *p) +{ + struct slipif_priv *priv; + struct pbuf *q; + u16_t i; + u8_t c; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + LWIP_ASSERT("p != NULL", (p != NULL)); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output: sending %"U16_F" bytes\n", p->tot_len)); + priv = (struct slipif_priv *)netif->state; + + /* Send pbuf out on the serial I/O device. */ + /* Start with packet delimiter. */ + sio_send(SLIP_END, priv->sd); + + for (q = p; q != NULL; q = q->next) { + for (i = 0; i < q->len; i++) { + c = ((u8_t *)q->payload)[i]; + switch (c) { + case SLIP_END: + /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ + sio_send(SLIP_ESC, priv->sd); + sio_send(SLIP_ESC_END, priv->sd); + break; + case SLIP_ESC: + /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ + sio_send(SLIP_ESC, priv->sd); + sio_send(SLIP_ESC_ESC, priv->sd); + break; + default: + /* normal byte - no need for escaping */ + sio_send(c, priv->sd); + break; + } + } + } + /* End with packet delimiter. */ + sio_send(SLIP_END, priv->sd); + return ERR_OK; +} + +#if LWIP_IPV4 +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} +#endif /* LWIP_IPV6 */ + +/** + * Handle the incoming SLIP stream character by character + * + * @param netif the lwip network interface structure for this slipif + * @param c received character (multiple calls to this function will + * return a complete packet, NULL is returned before - used for polling) + * @return The IP packet when SLIP_END is received + */ +static struct pbuf * +slipif_rxbyte(struct netif *netif, u8_t c) +{ + struct slipif_priv *priv; + struct pbuf *t; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + switch (priv->state) { + case SLIP_RECV_NORMAL: + switch (c) { + case SLIP_END: + if (priv->recved > 0) { + /* Received whole packet. */ + /* Trim the pbuf to the size of the received packet. */ + pbuf_realloc(priv->q, priv->recved); + + LINK_STATS_INC(link.recv); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); + t = priv->q; + priv->p = priv->q = NULL; + priv->i = priv->recved = 0; + return t; + } + return NULL; + case SLIP_ESC: + priv->state = SLIP_RECV_ESCAPE; + return NULL; + default: + break; + } /* end switch (c) */ + break; + case SLIP_RECV_ESCAPE: + /* un-escape END or ESC bytes, leave other bytes + (although that would be a protocol error) */ + switch (c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + default: + break; + } + priv->state = SLIP_RECV_NORMAL; + break; + default: + break; + } /* end switch (priv->state) */ + + /* byte received, packet not yet completely received */ + if (priv->p == NULL) { + /* allocate a new pbuf */ + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); + priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL); + + if (priv->p == NULL) { + LINK_STATS_INC(link.drop); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); + /* don't process any further since we got no pbuf to receive to */ + return NULL; + } + + if (priv->q != NULL) { + /* 'chain' the pbuf to the existing chain */ + pbuf_cat(priv->q, priv->p); + } else { + /* p is the first pbuf in the chain */ + priv->q = priv->p; + } + } + + /* this automatically drops bytes if > SLIP_MAX_SIZE */ + if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { + ((u8_t *)priv->p->payload)[priv->i] = c; + priv->recved++; + priv->i++; + if (priv->i >= priv->p->len) { + /* on to the next pbuf */ + priv->i = 0; + if (priv->p->next != NULL && priv->p->next->len > 0) { + /* p is a chain, on to the next in the chain */ + priv->p = priv->p->next; + } else { + /* p is a single pbuf, set it to NULL so next time a new + * pbuf is allocated */ + priv->p = NULL; + } + } + } + return NULL; +} + +/** Like slipif_rxbyte, but passes completed packets to netif->input + * + * @param netif The lwip network interface structure for this slipif + * @param c received character + */ +static void +slipif_rxbyte_input(struct netif *netif, u8_t c) +{ + struct pbuf *p; + p = slipif_rxbyte(netif, c); + if (p != NULL) { + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } +} + +#if SLIP_USE_RX_THREAD +/** + * The SLIP input thread. + * + * Feed the IP layer with incoming packets + * + * @param nf the lwip network interface structure for this slipif + */ +static void +slipif_loop_thread(void *nf) +{ + u8_t c; + struct netif *netif = (struct netif *)nf; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + + while (1) { + if (sio_read(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); + } + } +} +#endif /* SLIP_USE_RX_THREAD */ + +/** + * @ingroup slipif + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + * + * @param netif the lwip network interface structure for this slipif + * @return ERR_OK if serial line could be opened, + * ERR_MEM if no memory could be allocated, + * ERR_IF is serial line couldn't be opened + * + * @note If netif->state is interpreted as an u8_t serial port number. + * + */ +err_t +slipif_init(struct netif *netif) +{ + struct slipif_priv *priv; + u8_t sio_num; + + LWIP_ASSERT("slipif needs an input callback", netif->input != NULL); + + /* netif->state contains serial port number */ + sio_num = LWIP_PTR_NUMERIC_CAST(u8_t, netif->state); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)sio_num)); + + /* Allocate private data */ + priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); + if (!priv) { + return ERR_MEM; + } + + netif->name[0] = 's'; + netif->name[1] = 'l'; +#if LWIP_IPV4 + netif->output = slipif_output_v4; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = slipif_output_v6; +#endif /* LWIP_IPV6 */ + netif->mtu = SLIP_MAX_SIZE; + + /* Try to open the serial port. */ + priv->sd = sio_open(sio_num); + if (!priv->sd) { + /* Opening the serial port failed. */ + mem_free(priv); + return ERR_IF; + } + + /* Initialize private data */ + priv->p = NULL; + priv->q = NULL; + priv->state = SLIP_RECV_NORMAL; + priv->i = 0; + priv->recved = 0; +#if SLIP_RX_FROM_ISR + priv->rxpackets = NULL; +#endif + + netif->state = priv; + + /* initialize the snmp variables and counters inside the struct netif */ + MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); + +#if SLIP_USE_RX_THREAD + /* Create a thread to poll the serial line. */ + sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, + SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); +#endif /* SLIP_USE_RX_THREAD */ + return ERR_OK; +} + +/** + * @ingroup slipif + * Polls the serial device and feeds the IP layer with incoming packets. + * + * @param netif The lwip network interface structure for this slipif + */ +void +slipif_poll(struct netif *netif) +{ + u8_t c; + struct slipif_priv *priv; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + while (sio_tryread(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); + } +} + +#if SLIP_RX_FROM_ISR +/** + * @ingroup slipif + * Feeds the IP layer with incoming packets that were receive + * + * @param netif The lwip network interface structure for this slipif + */ +void +slipif_process_rxqueue(struct netif *netif) +{ + struct slipif_priv *priv; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + SYS_ARCH_PROTECT(old_level); + while (priv->rxpackets != NULL) { + struct pbuf *p = priv->rxpackets; +#if SLIP_RX_QUEUE + /* dequeue packet */ + struct pbuf *q = p; + while ((q->len != q->tot_len) && (q->next != NULL)) { + q = q->next; + } + priv->rxpackets = q->next; + q->next = NULL; +#else /* SLIP_RX_QUEUE */ + priv->rxpackets = NULL; +#endif /* SLIP_RX_QUEUE */ + SYS_ARCH_UNPROTECT(old_level); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + SYS_ARCH_PROTECT(old_level); + } + SYS_ARCH_UNPROTECT(old_level); +} + +/** Like slipif_rxbyte, but queues completed packets. + * + * @param netif The lwip network interface structure for this slipif + * @param data Received serial byte + */ +static void +slipif_rxbyte_enqueue(struct netif *netif, u8_t data) +{ + struct pbuf *p; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + SYS_ARCH_DECL_PROTECT(old_level); + + p = slipif_rxbyte(netif, data); + if (p != NULL) { + SYS_ARCH_PROTECT(old_level); + if (priv->rxpackets != NULL) { +#if SLIP_RX_QUEUE + /* queue multiple pbufs */ + struct pbuf *q = p; + while (q->next != NULL) { + q = q->next; + } + q->next = p; + } else { +#else /* SLIP_RX_QUEUE */ + pbuf_free(priv->rxpackets); + } + { +#endif /* SLIP_RX_QUEUE */ + priv->rxpackets = p; + } + SYS_ARCH_UNPROTECT(old_level); + } +} + +/** + * @ingroup slipif + * Process a received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + */ +void +slipif_received_byte(struct netif *netif, u8_t data) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + slipif_rxbyte_enqueue(netif, data); +} + +/** + * @ingroup slipif + * Process multiple received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + * @param len Number of received characters + */ +void +slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) +{ + u8_t i; + u8_t *rxdata = data; + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + for (i = 0; i < len; i++, rxdata++) { + slipif_rxbyte_enqueue(netif, *rxdata); + } +} +#endif /* SLIP_RX_FROM_ISR */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/zepif.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/zepif.c new file mode 100644 index 0000000..de43b99 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/netif/zepif.c @@ -0,0 +1,300 @@ +/** + * @file + * + * @defgroup zepif ZEP - ZigBee Encapsulation Protocol + * @ingroup netifs + * A netif implementing the ZigBee Encapsulation Protocol (ZEP). + * This is used to tunnel 6LowPAN over UDP. + * + * Usage (there must be a default netif before!): + * @code{.c} + * netif_add(&zep_netif, NULL, NULL, NULL, NULL, zepif_init, tcpip_6lowpan_input); + * netif_create_ip6_linklocal_address(&zep_netif, 1); + * netif_set_up(&zep_netif); + * netif_set_link_up(&zep_netif); + * @endcode + */ + +/* + * Copyright (c) 2018 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "netif/zepif.h" + +#if LWIP_IPV6 && LWIP_UDP + +#include "netif/lowpan6.h" +#include "lwip/udp.h" +#include "lwip/timeouts.h" +#include + +/** Define this to 1 to loop back TX packets for testing */ +#ifndef ZEPIF_LOOPBACK +#define ZEPIF_LOOPBACK 0 +#endif + +#define ZEP_MAX_DATA_LEN 127 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct zep_hdr { + PACK_STRUCT_FLD_8(u8_t prot_id[2]); + PACK_STRUCT_FLD_8(u8_t prot_version); + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t channel_id); + PACK_STRUCT_FIELD(u16_t device_id); + PACK_STRUCT_FLD_8(u8_t crc_mode); + PACK_STRUCT_FLD_8(u8_t unknown_1); + PACK_STRUCT_FIELD(u32_t timestamp[2]); + PACK_STRUCT_FIELD(u32_t seq_num); + PACK_STRUCT_FLD_8(u8_t unknown_2[10]); + PACK_STRUCT_FLD_8(u8_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +struct zepif_state { + struct zepif_init init; + struct udp_pcb *pcb; + u32_t seqno; +}; + +static u8_t zep_lowpan_timer_running; + +/* Helper function that calls the 6LoWPAN timer and reschedules itself */ +static void +zep_lowpan_timer(void *arg) +{ + lowpan6_tmr(); + if (zep_lowpan_timer_running) { + sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, arg); + } +} + +/* Pass received pbufs into 6LowPAN netif */ +static void +zepif_udp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port) +{ + err_t err; + struct netif *netif_lowpan6 = (struct netif *)arg; + struct zep_hdr *zep; + + LWIP_ASSERT("arg != NULL", arg != NULL); + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_UNUSED_ARG(pcb); /* for LWIP_NOASSERT */ + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + if (p == NULL) { + return; + } + + /* Parse and hide the ZEP header */ + if (p->len < sizeof(struct zep_hdr)) { + /* need the zep_hdr in one piece */ + goto err_return; + } + zep = (struct zep_hdr *)p->payload; + if (zep->prot_id[0] != 'E') { + goto err_return; + } + if (zep->prot_id[1] != 'X') { + goto err_return; + } + if (zep->prot_version != 2) { + /* we only support this version for now */ + goto err_return; + } + if (zep->type != 1) { + goto err_return; + } + if (zep->crc_mode != 1) { + goto err_return; + } + if (zep->len != p->tot_len - sizeof(struct zep_hdr)) { + goto err_return; + } + /* everything seems to be OK, hide the ZEP header */ + if (pbuf_remove_header(p, sizeof(struct zep_hdr))) { + goto err_return; + } + /* TODO Check CRC? */ + /* remove CRC trailer */ + pbuf_realloc(p, p->tot_len - 2); + + /* Call into 6LoWPAN code. */ + err = netif_lowpan6->input(p, netif_lowpan6); + if (err == ERR_OK) { + return; + } +err_return: + pbuf_free(p); +} + +/* Send 6LoWPAN TX packets as UDP broadcast */ +static err_t +zepif_linkoutput(struct netif *netif, struct pbuf *p) +{ + err_t err; + struct pbuf *q; + struct zep_hdr *zep; + struct zepif_state *state; + + LWIP_ASSERT("invalid netif", netif != NULL); + LWIP_ASSERT("invalid pbuf", p != NULL); + + if (p->tot_len > ZEP_MAX_DATA_LEN) { + return ERR_VAL; + } + LWIP_ASSERT("TODO: support chained pbufs", p->next == NULL); + + state = (struct zepif_state *)netif->state; + LWIP_ASSERT("state->pcb != NULL", state->pcb != NULL); + + q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct zep_hdr) + p->tot_len, PBUF_RAM); + if (q == NULL) { + return ERR_MEM; + } + zep = (struct zep_hdr *)q->payload; + memset(zep, 0, sizeof(struct zep_hdr)); + zep->prot_id[0] = 'E'; + zep->prot_id[1] = 'X'; + zep->prot_version = 2; + zep->type = 1; /* Data */ + zep->channel_id = 0; /* whatever */ + zep->device_id = lwip_htons(1); /* whatever */ + zep->crc_mode = 1; + zep->unknown_1 = 0xff; + zep->seq_num = lwip_htonl(state->seqno); + state->seqno++; + zep->len = (u8_t)p->tot_len; + + err = pbuf_copy_partial_pbuf(q, p, p->tot_len, sizeof(struct zep_hdr)); + if (err == ERR_OK) { +#if ZEPIF_LOOPBACK + zepif_udp_recv(netif, state->pcb, pbuf_clone(PBUF_RAW, PBUF_RAM, q), NULL, 0); +#endif + err = udp_sendto(state->pcb, q, state->init.zep_dst_ip_addr, state->init.zep_dst_udp_port); + } + pbuf_free(q); + + return err; +} + +/** + * @ingroup zepif + * Set up a raw 6LowPAN netif and surround it with input- and output + * functions for ZEP + */ +err_t +zepif_init(struct netif *netif) +{ + err_t err; + struct zepif_init *init_state = (struct zepif_init *)netif->state; + struct zepif_state *state = (struct zepif_state *)mem_malloc(sizeof(struct zepif_state)); + + LWIP_ASSERT("zepif needs an input callback", netif->input != NULL); + + if (state == NULL) { + return ERR_MEM; + } + memset(state, 0, sizeof(struct zepif_state)); + if (init_state != NULL) { + memcpy(&state->init, init_state, sizeof(struct zepif_init)); + } + if (state->init.zep_src_udp_port == 0) { + state->init.zep_src_udp_port = ZEPIF_DEFAULT_UDP_PORT; + } + if (state->init.zep_dst_udp_port == 0) { + state->init.zep_dst_udp_port = ZEPIF_DEFAULT_UDP_PORT; + } +#if LWIP_IPV4 + if (state->init.zep_dst_ip_addr == NULL) { + /* With IPv4 enabled, default to broadcasting packets if no address is set */ + state->init.zep_dst_ip_addr = IP_ADDR_BROADCAST; + } +#endif /* LWIP_IPV4 */ + + netif->state = NULL; + + state->pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (state->pcb == NULL) { + err = ERR_MEM; + goto err_ret; + } + err = udp_bind(state->pcb, state->init.zep_src_ip_addr, state->init.zep_src_udp_port); + if (err != ERR_OK) { + goto err_ret; + } + if (state->init.zep_netif != NULL) { + udp_bind_netif(state->pcb, state->init.zep_netif); + } + LWIP_ASSERT("udp_bind(lowpan6_broadcast_pcb) failed", err == ERR_OK); + ip_set_option(state->pcb, SOF_BROADCAST); + udp_recv(state->pcb, zepif_udp_recv, netif); + + err = lowpan6_if_init(netif); + LWIP_ASSERT("lowpan6_if_init set a state", netif->state == NULL); + if (err == ERR_OK) { + netif->state = state; + netif->hwaddr_len = 6; + if (init_state != NULL) { + memcpy(netif->hwaddr, init_state->addr, 6); + } else { + u8_t i; + for (i = 0; i < 6; i++) { + netif->hwaddr[i] = i; + } + netif->hwaddr[0] &= 0xfc; + } + netif->linkoutput = zepif_linkoutput; + + if (!zep_lowpan_timer_running) { + sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, NULL); + zep_lowpan_timer_running = 1; + } + + return ERR_OK; + } + +err_ret: + if (state->pcb != NULL) { + udp_remove(state->pcb); + } + mem_free(state); + return err; +} + +#endif /* LWIP_IPV6 && LWIP_UDP */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/cc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/cc.h new file mode 100644 index 0000000..10407fb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/cc.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ +#if defined __ANDROID__ +#define LWIP_UNIX_ANDROID +#elif defined __linux__ +#define LWIP_UNIX_LINUX +#elif defined __APPLE__ +#define LWIP_UNIX_MACH +#elif defined __OpenBSD__ +#define LWIP_UNIX_OPENBSD +#elif defined __CYGWIN__ +#define LWIP_UNIX_CYGWIN +#elif defined __GNU__ +#define LWIP_UNIX_HURD +#endif +#include "bsp.h" +#define LWIP_TIMEVAL_PRIVATE 0 +#include + +#define LWIP_ERRNO_INCLUDE + +#if defined(LWIP_UNIX_LINUX) || defined(LWIP_UNIX_HURD) +#define LWIP_ERRNO_STDINCLUDE 1 +#endif + +#define LWIP_RAND() ((u32_t)rand()) + +/* different handling for unit test, normally not needed */ +#ifdef LWIP_NOASSERT_ON_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;}} while(0) +#endif + +#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET) +typedef __kernel_fd_set fd_set; +#endif + +#if defined(LWIP_UNIX_MACH) +/* sys/types.h and signal.h bring in Darwin byte order macros. pull the + header here and disable LwIP's version so that apps still can get + the macros via LwIP headers and use system headers */ +#include +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#endif + +#define LWIP_PLATFORM_ASSERT(x) do {bsp_printf(x);}while(0) + +struct sio_status_s; +typedef struct sio_status_s sio_status_t; +#define sio_fd_t sio_status_t* +#define __sio_fd_t_defined + +typedef unsigned int sys_prot_t; + +#endif /* LWIP_ARCH_CC_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.c new file mode 100644 index 0000000..7f50597 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.c @@ -0,0 +1,422 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "lwip/etharp.h" +#include "netif/ppp/pppoe.h" +#include "ethernetif.h" +#include "dmasg.h" +#include "efx_tse_mac.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' +//define out of 512KB heap memory size +#define mem ((uint32_t*)0x80000) +#define memtx ((uint32_t*)0x2000000) + +#define ETH_TX_BUF_SIZE 1519 +#define LINK_SPEED_OF_YOUR_NETIF_IN_BPS 1000 + +//struct cmn_rx_ctrl rxctrl ={0}; + +volatile struct dmasg_descriptor descriptors0[FRAME_PACKET] __attribute__ ((aligned (64))); + +void flush_data_cache(){ + asm(".word(0x500F)"); +} + +void program_descriptor() +{ + + for (int j=0; jstate; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = 0x00; + netif->hwaddr[1] = 0x11; + netif->hwaddr[2] = 0x22; + netif->hwaddr[3] = 0x33; + netif->hwaddr[4] = 0x44; + netif->hwaddr[5] = 0x41; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + /* Do whatever else is needed to initialize interface. */ + program_descriptor(); +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static void SendData(uint32_t *pucEthernetBuffer,size_t xDataLength){ + + int n; + + //write_u32(xDataLength,IO_APB_SLAVE_2_APB+4); //workaround for tkeep tlast handle with module tkeep_ctrl with abp3 + dmasg_input_memory(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, ((u32)pucEthernetBuffer), 64); + dmasg_output_stream(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0, 0, 1); + dmasg_direct_start(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, xDataLength, 0); + + while(dmasg_busy(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH)); +} + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + + //initiate transfer(); + +#if ETH_PAD_SIZE + pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */ +#endif + + uint32_t framelength = 0; + uint32_t bufferoffset = 0; + uint32_t byteslefttocopy = 0; + uint32_t payloadoffset = 0; + for (q = p; q != NULL; q = q->next) { + /* Get bytes in current lwIP buffer */ + byteslefttocopy = q->len; + payloadoffset = 0; + + /* Check if the length of data to copy is bigger than Tx buffer size*/ + while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE ) { + /* Copy data to Tx buffer*/ + memcpy( (uint8_t*)((uint8_t*)memtx + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) ); + byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset); + payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset); + framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset); + bufferoffset = 0; + } + + /* Copy the remaining bytes */ + memcpy( (uint8_t*)((uint8_t*)memtx + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy ); + bufferoffset = bufferoffset + byteslefttocopy; + framelength = framelength + byteslefttocopy; + } + +// signal that packet should be sent(); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } else { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + /* increase ifoutdiscards or ifouterrors on error */ + +#if ETH_PAD_SIZE + pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + SendData(memtx, framelength); + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ + int check_dma_status(int num_descriptor) + { + if(descriptors0[num_descriptor].status & 0x3FFFFFFF) + return 1; + else + return 0; + } + +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p, *q; + u16_t len; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len =descriptors0[cur_des].status & DMASG_DESCRIPTOR_STATUS_BYTES; + +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + //p = pbuf_alloc_reference((mem+(cur_des*BUFFER_SIZE)), len, PBUF_REF); + + //bsp_printf("p addr = 0x%x pointer addr = 0x%x len = %d cur_des = %d\n\r",(u32)p,(u32)(mem+(cur_des*BUFFER_SIZE)),descriptors0[cur_des].status&DMASG_DESCRIPTOR_STATUS_BYTES,cur_des); + + descriptors0[cur_des].status = 0; + + if (p != NULL) { + +#if ETH_PAD_SIZE + pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */ +#endif + + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for (q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + * available data in the pbuf is given by the q->len + * variable. + * This does not necessarily have to be a memcpy, you can also preallocate + * pbufs for a DMA-enabled MAC and after receiving truncate it to the + * actually received size. In this case, ensure the tot_len member of the + * pbuf is the sum of the chained pbuf len members. + */ + //read data into(q->payload, q->len); + p->payload=(mem+(cur_des*BUFFER_SIZE)); + } + //acknowledge that packet has been read(); + + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } else { + /* unicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } +#if ETH_PAD_SIZE + pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } else { + // drop packet(); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + cur_des=(cur_des+1) & ((unsigned int)FRAME_PACKET-1); + + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input(struct netif *netif) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + struct pbuf *p; + + ethernetif = netif->state; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + /* if no packet could be read, silently ignore this */ + if (p != NULL) { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; + } + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]); + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.h new file mode 100644 index 0000000..946553e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/ethernetif.h @@ -0,0 +1,21 @@ +//HIHI ethernetif +#ifndef LWIP_ETHERNETIF_H +#define LWIP_ETHERNETIF_H + + +#include "lwip/err.h" +#include "lwip/netif.h" +#include "dmasg.h" + +#define FRAME_PACKET 256 +#define BUFFER_SIZE 1514 + +err_t ethernetif_init(struct netif *netif); +void ethernetif_input(struct netif *netif); + +int check_dma_status(int num_descriptor); +void flush_data_cache(void); + +int cur_des; + +#endif /* LWIP_ETHERNETIF_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/lwipopts.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/lwipopts.h new file mode 100644 index 0000000..b525327 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/app/lwip/user/arch/lwipopts.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +#ifdef LWIP_OPTTEST_FILE +#include "lwipopts_test.h" +#else /* LWIP_OPTTEST_FILE */ + +#define LWIP_IPV4 1 +#define LWIP_IPV6 0 + +#define NO_SYS 1 +#define LWIP_SOCKET (NO_SYS==0) +#define LWIP_NETCONN (NO_SYS==0) +#define LWIP_NETIF_API (NO_SYS==0) + +#define LWIP_IGMP LWIP_IPV4 +#define LWIP_ICMP LWIP_IPV4 + +#define LWIP_SNMP LWIP_UDP +#define MIB2_STATS 0 +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_SNMP_V3 (LWIP_SNMP) +#endif + +#define LWIP_DNS LWIP_UDP +#define LWIP_MDNS_RESPONDER LWIP_UDP + +#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER) + +#define LWIP_HAVE_LOOPIF 1 +#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_LOOPBACK_MAX_PBUFS 10 + +#define TCP_LISTEN_BACKLOG 1 + +#define LWIP_COMPAT_SOCKETS 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_RCVBUF 1 + +#define LWIP_TCPIP_CORE_LOCKING 1 + +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 + +#ifdef LWIP_DEBUG + +#define LWIP_DBG_MIN_LEVEL 0 +#define PPP_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) + + +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ +/* MSVC port: intel processors don't need 4-byte alignment, + but are faster that way! */ +#define MEM_ALIGNMENT 4U + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#define MEM_SIZE 10240 + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#define MEMP_NUM_PBUF 16 +/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One + per active RAW "connection". */ +#define MEMP_NUM_RAW_PCB 3 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 8 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 5 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 17 + +/* The following four are used only with the sequential API and can be + set to 0 if the application only will use the raw API. */ +/* MEMP_NUM_NETBUF: the number of struct netbufs. */ +#define MEMP_NUM_NETBUF 2 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 12 +/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used + for sequential API communication and incoming packets. Used in + src/api/tcpip.c. */ +#define MEMP_NUM_TCPIP_MSG_API 16 +#define MEMP_NUM_TCPIP_MSG_INPKT 16 + + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 400 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 256 + +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT (NO_SYS==0) + + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +#define LWIP_ALTCP (LWIP_TCP) +#ifdef LWIP_HAVE_MBEDTLS +#define LWIP_ALTCP_TLS (LWIP_TCP) +#define LWIP_ALTCP_TLS_MBEDTLS (LWIP_TCP) +#endif + + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 1 + +/* TCP Maximum segment size. */ +#define TCP_MSS 1460 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF TCP_WND + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) + +/* TCP writable space (bytes). This must be less than or equal + to TCP_SND_BUF. It is the amount of space which must be + available in the tcp snd_buf for select to return writable */ +#define TCP_SNDLOWAT (TCP_SND_BUF/2) + +/* TCP receive window. */ +#define TCP_WND 0xFFFF + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + + +/* ---------- ARP options ---------- */ +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_QUEUEING 1 + + +/* ---------- IP options ---------- */ +/* Define IP_FORWARD to 1 if you wish to have the ability to forward + IP packets across network interfaces. If you are going to run lwIP + on a device with only one network interface, define this to 0. */ +#define IP_FORWARD 1 + +/* IP reassembly and segmentation.These are orthogonal even + * if they both deal with IP fragments */ +#define IP_REASSEMBLY 1 +#define IP_REASS_MAX_PBUFS (10 * ((1500 + PBUF_POOL_BUFSIZE - 1) / PBUF_POOL_BUFSIZE)) +#define MEMP_NUM_REASSDATA IP_REASS_MAX_PBUFS +#define IP_FRAG 1 +#define IPV6_FRAG_COPYHEADER 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. */ +#define LWIP_DHCP LWIP_UDP + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK (LWIP_DHCP) + + +/* ---------- AUTOIP options ------- */ +#define LWIP_AUTOIP (LWIP_DHCP) +#define LWIP_DHCP_AUTOIP_COOP (LWIP_DHCP && LWIP_AUTOIP) + + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define LWIP_UDPLITE LWIP_UDP +#define UDP_TTL 255 + + +/* ---------- RAW options ---------- */ +#define LWIP_RAW 1 + + +/* ---------- Statistics options ---------- */ + +#define LWIP_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#if LWIP_STATS +#define LINK_STATS 1 +#define IP_STATS 1 +#define ICMP_STATS 1 +#define IGMP_STATS 1 +#define IPFRAG_STATS 1 +#define UDP_STATS 1 +#define TCP_STATS 1 +#define MEM_STATS 1 +#define MEMP_STATS 1 +#define PBUF_STATS 1 +#define SYS_STATS 1 +#endif /* LWIP_STATS */ + +/* ---------- NETBIOS options ---------- */ +#define LWIP_NETBIOS_RESPOND_NAME_QUERY 1 + +/* ---------- PPP options ---------- */ + +#define PPP_SUPPORT 1 /* Set > 0 for PPP */ + +#if PPP_SUPPORT + +#define NUM_PPP 1 /* Max PPP sessions. */ + + +/* Select modules to enable. Ideally these would be set in the makefile but + * we're limited by the command line length so you need to modify the settings + * in this file. + */ +#define PPPOE_SUPPORT 1 +#define PPPOS_SUPPORT 1 + +#define PAP_SUPPORT 1 /* Set > 0 for PAP. */ +#define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */ +#define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP */ +#define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */ +#define CCP_SUPPORT 0 /* Set > 0 for CCP */ +#define VJ_SUPPORT 0 /* Set > 0 for VJ header compression. */ +#define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */ + +#endif /* PPP_SUPPORT */ + +#endif /* LWIP_OPTTEST_FILE */ + +/* The following defines must be done even in OPTTEST mode: */ + +#if !defined(NO_SYS) || !NO_SYS /* default is 0 */ +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() +#endif + +//#ifndef LWIP_PLATFORM_ASSERT +///* Define LWIP_PLATFORM_ASSERT to something to catch missing stdio.h includes */ +//void lwip_example_app_platform_assert(const char *msg, int line, const char *file); +//#define LWIP_PLATFORM_ASSERT(x) lwip_example_app_platform_assert(x, __LINE__, __FILE__) +//#endif + +#define TCP_OVERSIZE 1 + +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 0 +#define CHECKSUM_GEN_TCP 0 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_GEN_ICMP6 0 +#define CHECKSUM_CHECK_IP 0 +#define CHECKSUM_CHECK_UDP 0 +#define CHECKSUM_CHECK_TCP 0 +#define CHECKSUM_CHECK_ICMP 0 +#define CHECKSUM_CHECK_ICMP6 0 +#define LWIP_CHECKSUM_ON_COPY 0 + +#endif /* LWIP_LWIPOPTS_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/.soc.h.swp b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/.soc.h.swp new file mode 100644 index 0000000..a01f0db Binary files /dev/null and b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/.soc.h.swp differ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/LICENSE.MD b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/LICENSE.MD new file mode 100644 index 0000000..89b37d3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/LICENSE.MD @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +//////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// +// MIT License +// +// Copyright (c) 2025 SaxonSoc contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/bsp.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/bsp.h new file mode 100644 index 0000000..e738827 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/bsp.h @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "soc.h" +#include "uart.h" +#include "clint.h" +#include "semihosting.h" + +//////////////////////////////////////////////////////////////////////////////// + /* + * Default main peripherals for SoC. + */ +//////////////////////////////////////////////////////////////////////////////// + +#define BSP_PLIC SYSTEM_PLIC_CTRL +#define BSP_PLIC_CPU_0 SYSTEM_PLIC_SYSTEM_CORES_0_EXTERNAL_INTERRUPT +#define BSP_UART_TERMINAL SYSTEM_UART_0_IO_CTRL +#define BSP_UART_BAUDRATE 115200 +#define BSP_UART_DATA_LEN 8 +#define bsp_putChar(c) uart_write(BSP_UART_TERMINAL, c); +#define BSP_CLINT SYSTEM_CLINT_CTRL +#define BSP_CLINT_HZ SYSTEM_CLINT_HZ +#define bsp_uDelay(usec) clint_uDelay(usec, SYSTEM_CLINT_HZ, SYSTEM_CLINT_CTRL); + +#ifdef SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_INTERRUPT +#define BSP_PLIC_CPU_1 SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_INTERRUPT +#endif + +#ifdef SYSTEM_PLIC_SYSTEM_CORES_2_EXTERNAL_INTERRUPT +#define BSP_PLIC_CPU_2 SYSTEM_PLIC_SYSTEM_CORES_2_EXTERNAL_INTERRUPT +#endif + +#ifdef SYSTEM_PLIC_SYSTEM_CORES_3_EXTERNAL_INTERRUPT +#define BSP_PLIC_CPU_3 SYSTEM_PLIC_SYSTEM_CORES_3_EXTERNAL_INTERRUPT +#endif + +//////////////////////////////////////////////////////////////////////////////// + /* + * Support printing for char, string , decimal and hexadecinaml specifier. + * Support print_float and print_dec function. + * Uses moderate memory resource. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_BSP_PRINTF 1 + +//////////////////////////////////////////////////////////////////////////////// + /* + * Full support for printf function, including flag and precisions. + * Uses more memory resource. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_BSP_PRINTF_FULL 0 + +//////////////////////////////////////////////////////////////////////////////// + /* + * Enable the function sharing between 'full' and 'lite' printing. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_BRIDGE_FULL_TO_LITE 1 + +//////////////////////////////////////////////////////////////////////////////// + /* + * Enable more printing specifier like floating point, exponential, + * pointer difference and long long data type. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_FLOATING_POINT_SUPPORT SYSTEM_CORES_0_FPU +#define ENABLE_FP_EXPONENTIAL_SUPPORT 0 +#define ENABLE_PTRDIFF_SUPPORT 0 +#define ENABLE_LONG_LONG_SUPPORT 0 + +//////////////////////////////////////////////////////////////////////////////// + /* + * Warning message when specifier is not supported. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_PRINTF_WARNING 1 + +//////////////////////////////////////////////////////////////////////////////// + /* + * Enable printing with semihosting. + */ +//////////////////////////////////////////////////////////////////////////////// +#define ENABLE_SEMIHOSTING_PRINT 0 + + +#if (ENABLE_BSP_PRINTF) + #include "print.h" +#endif //#if (ENABLE_BSP_PRINTF) + +#if (ENABLE_BSP_PRINTF_FULL) + #if (!ENABLE_FLOATING_POINT_SUPPORT) + #define PRINTF_DISABLE_SUPPORT_FLOAT 1 + #endif //#if (ENABLE_FLOATING_POINT_SUPPORT) + + #if (!ENABLE_FP_EXPONENTIAL_SUPPORT) + #define PRINTF_DISABLE_SUPPORT_EXPONENTIAL 1 + #endif //#if (ENABLE_FP_EXPONENTIAL_SUPPORT) + + #if (!ENABLE_PTRDIFF_SUPPORT) + #define PRINTF_DISABLE_SUPPORT_PTRDIFF_T 1 + #endif //#if (ENABLE_PTRDIFF_SUPPORT) + + #if (!ENABLE_LONG_LONG_SUPPORT) + #define PRINTF_DISABLE_SUPPORT_LONG_LONG 1 + #endif //#if (ENABLE_LONG_LONG_SUPPORT) + + #if(ENABLE_BRIDGE_FULL_TO_LITE) + #if (!ENABLE_BSP_PRINTF) + #define bsp_printf bsp_printf_full + #endif // #if (!ENABLE_BSP_PRINTF) + #endif //#if(ENABLE_BRIDGE_EFX_TO_BSP) + #include "print_full.h" + +#endif //#if (ENABLE_BSP_PRINTF_FULL) + + +//////////////////////////////////////////////////////////////////////////////// + /* + * Peripherals initialization routine when power up the SoC. + * 1. UART baudrate + * 2. + */ +//////////////////////////////////////////////////////////////////////////////// + static void bsp_init() + { + Uart_Config uartConfig; + uartConfig.dataLength = BITS_8; + uartConfig.parity = NONE; + uartConfig.stop = ONE; + uartConfig.clockDivider = BSP_CLINT_HZ/(BSP_UART_BAUDRATE*BSP_UART_DATA_LEN)-1; + uart_applyConfig(BSP_UART_TERMINAL, &uartConfig); + } diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/freertosHalConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/freertosHalConfig.h new file mode 100644 index 0000000..f4ed0df --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/freertosHalConfig.h @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// +/******************************************************************************* +* +* @file freertosHalConfig.h +* +* @brief Header file define external interrupt for FreeRTOS. +* +******************************************************************************/ + + +#pragma once +#include "bsp.h" + +#define PLIC_MACHINE_TIMER_ID SYSTEM_PLIC_SYSTEM_CORES_0_EXTERNAL_INTERRUPT +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint64_t ) ( BSP_CLINT_HZ ) ) \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print.h new file mode 100644 index 0000000..4879457 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print.h @@ -0,0 +1,437 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file print.h +* +* @brief Header file contain all necessary print function that supports char, string, +* decimal, and hexadecimal specifiers. Uses medium RAM resources. +* +******************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include "bsp.h" + +#if (ENABLE_BSP_PRINTF) + static void _putchar(char character){ + #if (ENABLE_SEMIHOSTING_PRINT == 1) + sh_writec(character); + #else + bsp_putChar(character); + #endif // (ENABLE_SEMIHOSTING_PRINT == 1) + } + + static void _putchar_s(char *p) + { + #if (ENABLE_SEMIHOSTING_PRINT == 1) + sh_write0(p); + #else + while (*p) + _putchar(*(p++)); + #endif // (ENABLE_SEMIHOSTING_PRINT == 1) + } + + static void bsp_printHex(uint32_t val) + { + uint32_t digits; + digits =8; + + for (int i = (4*digits)-4; i >= 0; i -= 4) { + _putchar("0123456789ABCDEF"[(val >> i) % 16]); + } + } + + static void bsp_printHex_lower(uint32_t val) + { + uint32_t digits; + digits =8; + + for (int i = (4*digits)-4; i >= 0; i -= 4) { + _putchar("0123456789abcdef"[(val >> i) % 16]); + + } + } + + #if (ENABLE_FLOATING_POINT_SUPPORT) +/******************************************************************************* +* +* @brief This function takes a character array as input and reverses its content. +* +* @param s[] Character array to be reversed. +* +* @notes: +* - Initializes two indices, i and j, for the start and end of the string respectively. +* - Iterates through the string from both ends towards the middle. +* - Swaps the characters at positions i and j in each iteration. +* +******************************************************************************/ + static void reverse(char s[]) + { + int i, j, len; + char c; + + for (i = 0, j = strlen(s)-1; i 0); /* delete it */ + if (sign < 0) + s[i++] = '-'; + s[i] = '\0'; + reverse(s); + } + + +/******************************************************************************* +* +* @brief This function converts a double number to its string representation with a +* specified number of decimal places and stores the integer and fractional parts +* in separate character arrays. +* +* @param n Double number to be converted. +* @param res1 Character array to store the integer part of the number. +* @param res2 Character array to store the fractional part of the number. +* +* @notes: +* - Extracts the integer part of the double number. +* - Calculates the fractional part of the double number. +* - Converts the integer part to its string representation using the 'itos' function. +* - Adds a dot to the 'res2' array. +* - Converts the fractional part to its string representation with a specified +* number of decimal places. +* +******************************************************************************/ + static void ftoa(double n, char* res1, char* res2) + { + float fpart_f; + int afterpoint=4; + + // Extract integer part + int ipart = (int)n; + + // Extract floating part + double fpart = n - (double)ipart; + + // convert integer part to string + itos(n, res1); + + // add dot + *res2 = '.'; + res2++; + + // convert fraction part to string + fpart_f = (float)fpart * pow(10, afterpoint); + if (fpart_f<0) + { + *res2 = '-'; + res2++; + fpart_f = -(fpart_f); + } + // handling of 0 after decimal point e.g. 1.003 + for (int i=afterpoint; i>0; i--) + { + if ((fpart_f<(1 * pow(10, i-1))) && (fpart_f>0)) + { + *res2='0'; + res2++; + } + } + + itos((int)fpart_f, res2); + } + +/******************************************************************************* +* +* @brief This function converts an unsigned 32-bit integer to its string representation +* and prints it using the '_putchar_s' function. +* +* @param val Unsigned 32-bit integer value to be printed. +* +******************************************************************************/ + static void print_dec(uint32_t val) + { + char sval[10]; + itos(val, sval); + _putchar_s(sval); + + } + +/******************************************************************************* +* +* @brief This function prints a floating-point value. +* +* @param val Double precision floating-point value to be printed. +* +* @notes: +* - Converts the double precision floating-point value to its string +* representation using the 'ftoa' function. +* - Adjusts the string representation to handle negative signs and proper +* placement of decimal points. +* - Prints the adjusted string representation using the '_putchar_s' function. +* +******************************************************************************/ + static void print_float(double val) + { + int i, j, neg; + neg=0; + i=2; + j=19; + char sval[21], fval[10]; + ftoa(val, sval, fval); + if (fval[1] == '-') + { + neg = 1; + while (i<10) + { + fval[i-1] = fval[i]; + i++; + } + + } + strcat(sval, fval); + if ((sval[0] != '-') && (neg == 1)) + { + while (j>=0) + { + sval[j+1] = sval[j]; + j--; + } + sval[0] = '-'; + } + _putchar_s(sval); + } + + #endif //#if (ENABLE_FLOATING_POINT_SUPPORT) + +/******************************************************************************* +* +* @brief This function is used to output a single character. +* +* @param c: The character to be output. +* +******************************************************************************/ + static void bsp_printf_c(int c) + { + _putchar(c); + } + +/******************************************************************************* +* @brief This function is used to outputs a null-terminated string. +* +* @param s: A pointer to the null-terminated string to be output. +* +*******************************************************************************/ + static void bsp_printf_s(char *p) + { + _putchar_s(p); + } + + +/******************************************************************************* +* +* @brief This function prints an integer to the output. +* +* @param val Integer value to be printed. +* +* @notes: +* - Converts the integer to a string representation by extracting digits. +* - Handles negative numbers by printing a '-' sign. +* - Uses the 'bsp_printf_c' function to print each character. +* +******************************************************************************/ + static void bsp_printf_d(int val) + { + char buffer[32]; + char *p = buffer; + if (val < 0) { + bsp_printf_c('-'); + val = -val; + } + while (val || p == buffer) { + *(p++) = '0' + val % 10; + val = val / 10; + } + while (p != buffer) + bsp_printf_c(*(--p)); + } + +/******************************************************************************* +* +* @brief This function prints an integer in hexadecimal format to the output. +* +* @param val Integer value to be printed in hexadecimal format. +* +* @notes: +* - Determines the number of hexadecimal digits required for the given value. +* - Calls 'bsp_printHex_lower' to print the hexadecimal representation. +* - Determines the number of leading zeros to be printed based on the value. +* +******************************************************************************/ + static void bsp_printf_x(int val) + { + int i,digi=2; + + for(i=0;i<8;i++) + { + if((val & (0xFFFFFFF0 <<(4*i))) == 0) + { + digi=i+1; + break; + } + } + bsp_printHex_lower(val); + } + +/******************************************************************************* +* +* @brief This function prints an integer in uppercase hexadecimal format to the output. +* +* @param val Integer value to be printed in uppercase hexadecimal format. +* +* @notes: +* - Determines the number of hexadecimal digits required for the given value. +* - Calls 'bsp_printHex' to print the uppercase hexadecimal representation. +* - Determines the number of leading zeros to be printed based on the value. +* +******************************************************************************/ + static void bsp_printf_X(int val) + { + int i,digi=2; + + for(i=0;i<8;i++) + { + if((val & (0xFFFFFFF0 <<(4*i))) == 0) + { + digi=i+1; + break; + } + } + bsp_printHex(val); + } +#if (ENABLE_SEMIHOSTING_PRINT == 0) +/******************************************************************************* +* +* @brief This function is a Printf-like function to print formatted data to the output. +* which acts similar to the standard 'printf' function but supports a +* limited set of format specifiers: 'c', 's', 'd', 'x', 'X', and 'f'. +* +* @param format Format string followed by the arguments to be formatted. +* @param ... Variable arguments corresponding to the format specifiers in 'format'. +* +* @notes: +* - Iterates over each character in the format string. +* - Recognizes '%' as the start of a format specifier. +* - Handles each format specifier by calling the appropriate helper function. +* - If floating-point support is disabled, prints a warning for the 'f' specifier. +* +******************************************************************************/ + static void bsp_printf(const char *format, ...) + { + int i; + va_list ap; + + va_start(ap, format); + + for (i = 0; format[i]; i++) + if (format[i] == '%') { + while (format[++i]) { + if (format[i] == 'c') { + bsp_printf_c(va_arg(ap,int)); + break; + } + else if (format[i] == 's') { + bsp_printf_s(va_arg(ap,char*)); + break; + } + else if (format[i] == 'd') { + bsp_printf_d(va_arg(ap,int)); + break; + } + else if (format[i] == 'X') { + bsp_printf_X(va_arg(ap,int)); + break; + } + else if (format[i] == 'x') { + bsp_printf_x(va_arg(ap,int)); + break; + } +#if (ENABLE_FLOATING_POINT_SUPPORT) + else if (format[i] == 'f') { + print_float(va_arg(ap,double)); + break; + } +#elif (ENABLE_PRINTF_WARNING) + else if (format[i] == 'f') { + bsp_printf_s(""); + break; + } +#endif //#if (ENABLE_FLOATING_POINT_SUPPORT) + } + } else + bsp_printf_c(format[i]); + + va_end(ap); + } + +#else // #if (ENABLE_SEMIHOSTING_PRINT == 1) + #include "print_full.h" +/******************************************************************************* +* +* @brief This function is printf-like function to print formatted data to the output +* when semihosting is enabled. +* +* @param format Format string followed by the arguments to be formatted. +* @param ... Variable arguments corresponding to the format specifiers in 'format'. +* +******************************************************************************/ + static int bsp_printf(const char* format, ...) + { + va_list va; + va_start(va, format); + + char buffer[MAX_STRING_BUFFER_SIZE]; + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + _putchar_s(buffer); + + va_end(va); + return ret; + } + + +#endif // #if (ENABLE_SEMIHOSTING_PRINT == 0) +#endif //#if (ENABLE_BSP_PRINTF) diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print_full.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print_full.h new file mode 100644 index 0000000..0df8c05 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/print_full.h @@ -0,0 +1,1407 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2025, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +// Github: https://github.com/mpaland +/////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file print_full.h +* +* @brief Header file contain all necessary print function that fully support for printf, +* including flags and precisions. Uses the most RAM resources. +* +******************************************************************************/ + + +#pragma once + +#ifndef _PRINT_FULL_H_ +#define _PRINT_FULL_H_ + +#include +#include +#include +#include +#include "bsp.h" +#include "soc.h" + +#if (ENABLE_BSP_PRINTF_FULL || ENABLE_SEMIHOSTING_PRINT == 1) +#ifdef __cplusplus +extern "C" { +#endif + +#if (!ENABLE_BSP_PRINTF) + static void _putchar(char character){ + #if (ENABLE_SEMIHOSTING_PRINT == 1) + sh_writec(character); + #else + bsp_putChar(character); + #endif // (ENABLE_SEMIHOSTING_PRINT == 1) + } + + static void _putchar_s(char *p) + { + #if (ENABLE_SEMIHOSTING_PRINT == 1) + sh_write0(p); + #else + while (*p) + _putchar(*(p++)); + #endif // (ENABLE_SEMIHOSTING_PRINT == 1) + } + + static void bsp_printHex(uint32_t val) + { + uint32_t digits; + digits =8; + + for (int i = (4*digits)-4; i >= 0; i -= 4) { + _putchar("0123456789ABCDEF"[(val >> i) % 16]); + } + } + + static void bsp_printf_c(int c) + { + _putchar(c); + } + + static void bsp_printf_s(char *p) + { + _putchar_s(p); + } + +#endif + +//void _putchar(char character); +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +#define bsp_printf_full printf_ +//int printf_(const char* format, ...); + + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define bsp_sprintf_full sprintf_ +//int sprintf_(char* buffer, const char* format, ...); + + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define bsp_snprintf_full snprintf_ +#define bsp_efx_vsnprintf_full vsnprintf_ +//int snprintf_(char* buffer, size_t count, const char* format, ...); +//int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); + + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define bsp_vprintf_full vprintf_ +//int vprintf_(const char* format, va_list va); + + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +#define bsp_fctprintf_full fctprintf +//int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 4 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 4U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +// Define the max string buffer size can be allocate when using the semihosting printing +#ifndef MAX_STRING_BUFFER_SIZE +#define MAX_STRING_BUFFER_SIZE 100 +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + +/******************************************************************************* +* +* @brief This internal function is an inline helper function used by the vsnprintf +* function to output a single character to a buffer at a specified index. +* +* @param character The character to be written to the buffer. +* @param buffer Pointer to the buffer where the character will be stored. +* @param idx Index indicating the position in the buffer where the +* character will be written. +* @param maxlen Maximum length of the buffer to prevent buffer overflow. +* +******************************************************************************/ + +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + + +/******************************************************************************* +* +* @brief This internal function is an inline helper function used as a null output +* function. It is used to discard any output without performing any +* operation. +* +* @param character The character that would be discarded (unused). +* @param buffer Pointer to the buffer (unused). +* @param idx Index indicating the position in the buffer (unused). +* @param maxlen Maximum length of the buffer (unused). +* +******************************************************************************/ +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +/******************************************************************************* +* +* @brief This function is an inline wrapper for the putchar function. It outputs +* a single character to the standard output if the character is valid. +* +* @param character The character to be output. +* @param buffer Pointer to the buffer (unused). +* @param idx Index indicating the position in the buffer (unused). +* @param maxlen Maximum length of the buffer (unused). +* +******************************************************************************/ + +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + +/******************************************************************************* +* +* @brief Internal output function wrapper. This function serves as a wrapper for +* an output function. It takes a'character' and uses a pointer to a function +* stored in 'buffer' to output it. +* +* @param character Character to be outputted. +* @param buffer Pointer to the output function and its argument. +* @param idx Current index (unused in this function). +* @param maxlen Maximum length (unused in this function). +* +******************************************************************************/ +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + +/******************************************************************************* +* +* @brief This funciton calculate the length of a string, limited by a maximum size. +* +* @param str Pointer to the string to be measured. +* @param maxsize Maximum number of characters to count. +* +* @return The length of the string (excluding the terminating null character), +* limited by 'maxsize'. +* +******************************************************************************/ +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + + +/******************************************************************************* +* +* @brief This function checks if the given character is a digit (0-9). +* +* @param ch Character to be checked. +* +* @return True if the character is a digit, otherwise false. +* +******************************************************************************/ +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +/******************************************************************************* +* +* @brief Internal ASCII string to unsigned int conversion. +* +* This function converts an ASCII string to an unsigned integer. +* +* @param str Pointer to a pointer to the string to be converted. +* +* @return Converted unsigned integer value. +* +******************************************************************************/ +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +/******************************************************************************* +* +* @brief This function outputs the specified string in reverse with zero-padding and alignment. +* +* @param out Custom output function that takes a character, buffer index, +* and other parameters. +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param buf Pointer to the string to be outputted. +* @param len Length of the string to be outputted. +* @param width Minimum width of the output string. Padding is added if necessary. +* @param flags Formatting flags (e.g., 'FLAGS_LEFT' for left alignment, +* 'FLAGS_ZEROPAD' for zero-padding). +* +* @return Updated index in the buffer after outputting the string. +* +******************************************************************************/ +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +/******************************************************************************* +* +* @brief This internal function to format the output string based on formatting flags. +* +* @param out Custom output function that takes a character, buffer index, +* and other parameters. +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param buf Pointer to the formatted number string. +* @param len Length of the formatted number string. +* @param negative Flag indicating if the number is negative. +* @param base Base of the number system (e.g., 10 for decimal, 16 for hexadecimal). +* @param prec Number of decimal places. +* @param width Minimum width of the output string. Padding is added if necessary. +* @param flags Formatting flags (e.g., '#' for alternate form, '+' to show sign). +* +* @return Number of characters written to the buffer. +* +******************************************************************************/ +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + + +/******************************************************************************* +* +* @brief This internal function to format an unsigned long integer to a string +* representation in a given base. +* +* @param out Custom output function that takes a character, buffer index, +* and other parameters. +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param value Unsigned long integer value to be formatted. +* @param negative Flag indicating if the number is negative. +* @param base Base of the number system (e.g., 10 for decimal, 16 for hexadecimal). +* @param prec Number of decimal places. +* @param width Minimum width of the output string. Padding is added if necessary. +* @param flags Formatting flags (e.g., '#' for alternate form, '+' to show sign). +* +* @return Number of characters written to the buffer. +* +* +******************************************************************************/ +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +/******************************************************************************* +* +* @brief This internal function to format an unsigned long long integer to a string +* representation in a given base. +* +* @param out Custom output function that takes a character, buffer index, +* and other parameters. +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param value Unsigned long long integer value to be formatted. +* @param negative Flag indicating if the number is negative. +* @param base Base of the number system (e.g., 10 for decimal, 16 for hexadecimal). +* @param prec Number of decimal places. +* @param width Minimum width of the output string. Padding is added if necessary. +* @param flags Formatting flags (e.g., '#' for alternate form, '+' to show sign). +* +* @return Number of characters written to the buffer. +* +******************************************************************************/ +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + + + +/******************************************************************************* +* +* @brief This internal function to format a floating-point number for fixed decimal +* floating point representation. +* +* @param out Custom output function that takes a character, buffer index, +* and other parameters. +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param value Floating-point value to be formatted. +* @param prec Number of decimal places. +* @param width Minimum width of the output string. Padding is added if necessary. +* @param flags Formatting flags (like '+' to show sign). +* +* @return Number of characters written to the buffer. +* +******************************************************************************/ +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) { + } + else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +/******************************************************************************* +* +* @brief This function is an internal variant of ftoa designed to handle exponential +* floating-point numbers. It follows the algorithm by David Gay for logarithmic +* calculations and the exponential function computation using continued fractions. +* +* @param out Output function. +* @param buffer Pointer to the buffer where the output will be stored. +* @param idx Current index in the buffer. +* @param maxlen Maximum length of the buffer. +* @param value Floating-point value to convert. +* @param prec Precision (number of decimal places). +* @param width Minimum width of the output. +* @param flags Flags indicating formatting options. +* +* @return The index after writing to the buffer. +* +* @note Contributed by: Martijn Jasperse +* +******************************************************************************/ +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + +/******************************************************************************* +* +* @brief This function is an internal variant of vsnprintf designed to format +* and output data based on a given format string and variable arguments. +* It supports various format specifiers for integers, characters, strings, +* and floating-point numbers. +* +* @param out Output function. +* @param buffer Pointer to the buffer where the formatted output will be stored. +* @param maxlen Maximum length of the buffer. +* @param format Format string specifying the format of the output. +* @param va Variable arguments list. +* +* @return The number of characters written to the buffer (excluding the +* terminating null character), or a negative value if an error +* occurred. +* +******************************************************************************/ +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#elif (ENABLE_PRINTF_WARNING) + case 'e': + case 'E': + case 'g': + case 'G': { + const char* p = "', buffer, idx++, maxlen); + format++; + break; + } +#endif // PRINTF_SUPPORT_EXPONENTIAL +#elif (ENABLE_PRINTF_WARNING) + case 'f' : + case 'F' : { + const char* p = "', buffer, idx++, maxlen); + format++; + break; + } +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @brief This function prints formatted data to the standard output device. +* +* @param format Format string followed by the arguments to be formatted. +* @param ... Variable arguments corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `printf` in the standard C library. +* It formats the string according to the format string and prints the result +* to the standard output device. +* +* @return Number of characters printed or formatted (excluding the null byte). +* +******************************************************************************/ +static int printf_(const char* format, ...) +{ + va_list va; + va_start(va, format); +#if (ENABLE_SEMIHOSTING_PRINT == 1) // if semihosting is enabled. This is to speed up the printing process by printing string instead of char + char buffer[MAX_STRING_BUFFER_SIZE]; + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + _putchar_s(buffer); +#else + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + +#endif + + va_end(va); + return ret; +} + + +/******************************************************************************* +* +* @brief This function formats a string and stores the result in a buffer. +* +* @param buffer Pointer to the buffer where the formatted string will be stored. +* @param format Format string followed by the arguments to be formatted. +* @param ... Variable arguments corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `sprintf` in the standard C library. +* It formats the string according to the format string and stores the result +* in the provided buffer. +* +******************************************************************************/ +static int sprintf_(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +/******************************************************************************* +* +* @brief This function prints formatted data to a buffer with a specified size. +* +* @param buffer Pointer to the buffer where the resulting formatted string is stored. +* @param count Maximum number of characters to write to the buffer, including the null terminator. +* @param format Format string followed by the arguments to be formatted. +* @param ... Variable arguments corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `snprintf` in the standard C library. +* It formats the string according to the format string and writes the result +* to the provided buffer with a specified maximum size. +* +* @return Number of characters printed or formatted (excluding the null byte). +* If the return value is equal to or greater than 'count', the output was truncated. +* +******************************************************************************/ + +static int snprintf_(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + + +/******************************************************************************* +* +* @brief This function prints formatted data to the standard output using a variable argument list. +* +* @param format Format string followed by the arguments to be formatted. +* @param va Variable argument list corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `vprintf` in the standard C library. +* It formats the string according to the format string and writes the result +* to the standard output using a variable argument list. +* +* @return Number of characters printed or formatted (excluding the null byte). +* +******************************************************************************/ +static int vprintf_(const char* format, va_list va) +{ + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + +/******************************************************************************* +* +* @brief This function writes formatted data to a string using a variable argument list. +* +* @param buffer Pointer to the buffer where the formatted string will be written. +* @param count Maximum number of characters to write to the buffer, including the null byte. +* @param format Format string followed by the arguments to be formatted. +* @param va Variable argument list corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `vsnprintf` in the standard C library. +* It formats the string according to the format string and writes the result +* to the provided buffer using a variable argument list. +* +* @return Number of characters printed or formatted (excluding the null byte). +* If the return value is greater than or equal to 'count', it indicates +* that the output was truncated. +* +******************************************************************************/ + +static int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + +/******************************************************************************* +* +* @brief Formatted print function that uses a custom output function. +* +* @param out Pointer to the custom output function that takes a character and +* a void pointer as arguments. +* @param arg Argument to be passed to the custom output function. +* @param format Format string followed by the arguments to be formatted. +* @param va Variable argument list corresponding to the format specifiers in 'format'. +* +* @notes: +* This function behaves similarly to `vsnprintf` but allows for custom output +* through a user-defined output function. The formatted data is passed to this +* output function character by character. +* +* @return Number of characters sent to the custom output function. +* +******************************************************************************/ + +static int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +#ifdef __cplusplus +} +#endif + +#endif //#if (ENABLE_BSP_PRINTF_FULL) + +#endif //_PRINT_FULL_H_ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/semihosting.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/semihosting.h new file mode 100644 index 0000000..999b2b7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/semihosting.h @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#ifndef EFX_SEMIHOSTING_H +#define EFX_SEMIHOSTING_H + +/******************************************************************************* +/** +* @file semihosting.h +* +* @brief Header file for ARM semihosting functions that allow input and output operations +* with the debug console of ARM-based systems using semihosting operations. +* +* The available functions are: +* - sh_write0: Writes a zero-terminated string to the debug console. +* - sh_writec: Writes a single character to the debug console. +* - sh_readc: Reads a single character from the debug console. +* +* @note The exact behavior of these functions may depend on the underlying +* semihosting implementation and debugger. +* +******************************************************************************/ + + +#include "bsp.h" +#include "vexriscv.h" + +/******************************************************************************* +* @brief Definitions of ARM semihosting operation numbers. +* +* @note This enumeration defines the ARM semihosting operation numbers along with their +* corresponding hexadecimal values. These operation numbers are used to identify +* different semihosting operations when making semihosting system calls. This +* enumeration contains the ARM semihosting operations in lexicographic order. +* +******************************************************************************/ + +#define RISCV_SEMIHOSTING_CALL_NUMBER 7 +enum semihosting_operation_numbers { + /* + * ARM semihosting operations, in lexicographic order. + */ + SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */ + + SEMIHOSTING_SYS_CLOSE = 0x02, + SEMIHOSTING_SYS_CLOCK = 0x10, + SEMIHOSTING_SYS_ELAPSED = 0x30, + SEMIHOSTING_SYS_ERRNO = 0x13, + SEMIHOSTING_SYS_EXIT = 0x18, + SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20, + SEMIHOSTING_SYS_FLEN = 0x0C, + SEMIHOSTING_SYS_GET_CMDLINE = 0x15, + SEMIHOSTING_SYS_HEAPINFO = 0x16, + SEMIHOSTING_SYS_ISERROR = 0x08, + SEMIHOSTING_SYS_ISTTY = 0x09, + SEMIHOSTING_SYS_OPEN = 0x01, + SEMIHOSTING_SYS_READ = 0x06, + SEMIHOSTING_SYS_READC = 0x07, + SEMIHOSTING_SYS_REMOVE = 0x0E, + SEMIHOSTING_SYS_RENAME = 0x0F, + SEMIHOSTING_SYS_SEEK = 0x0A, + SEMIHOSTING_SYS_SYSTEM = 0x12, + SEMIHOSTING_SYS_TICKFREQ = 0x31, + SEMIHOSTING_SYS_TIME = 0x11, + SEMIHOSTING_SYS_TMPNAM = 0x0D, + SEMIHOSTING_SYS_WRITE = 0x05, + SEMIHOSTING_SYS_WRITEC = 0x03, + SEMIHOSTING_SYS_WRITE0 = 0x04, +}; + +/******************************************************************************* +* @brief This function is used for making a semihosting call to the host. +* +* @param reason: The reason code for the semihosting call. +* @param arg: A pointer to an argument to be passed to the host. +* +* @return The return value from the semihosting call. +* +* @note This function uses inline assembly to issue a sequence of RISC-V instructions +* to perform the semihosting call. It ensures that the call is always inlined +* into the calling code using the "always_inline" attribute. +* +******************************************************************************/ +static inline int __attribute__ ((always_inline)) call_host(int reason, void* arg) { + register int value asm ("a0") = reason; + register void* ptr asm ("a1") = arg; + asm volatile ( + " .option push \n" + // Force non-compressed RISC-V instructions + " .option norvc \n" + // Force 16-byte alignment to make sure that the 3 instructions fall + // within the same virtual page. + // Note: align 4 means, align by 2 to the power of 4! + " .align 4 \n" + " slli x0, x0, 0x1f \n" + " ebreak \n" + " srai x0, x0, %[swi] \n" + " .option pop \n" + " nop \n" + + : "=r" (value) /* Outputs */ + : "0" (value), "r" (ptr), [swi] "i" (RISCV_SEMIHOSTING_CALL_NUMBER) /* Inputs */ + : "memory" /* Clobbers */ + ); + return value; +} + +/******************************************************************************* +* @brief This function write a zero-terminated string to the debug console. +* +* @param buf: Pointer to the zero-terminated string to be written. +* +* @return None. +* +* @note None. +* +******************************************************************************/ + +static void sh_write0(char* buf) +{ + // Print zero-terminated string + call_host(SEMIHOSTING_SYS_WRITE0, (void*) buf); +} + +/******************************************************************************* +* +* @brief This function writes a single character to the debug console using the ARM +* semihosting system call for writing a character. +* +* @param c: The character to be written to the debug console. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void sh_writec(char c) +{ + // Print single character + call_host(SEMIHOSTING_SYS_WRITEC, (void*)&c); +} + +/******************************************************************************* +* +* @brief This function reads a single character from the debug console using the ARM +* semihosting system call for reading a character. Note that this is a blocking +* operation. +* +* @return The character read from the debug console. +* +* @note None. +* +******************************************************************************/ + +static char sh_readc(void) +{ + // Read character - Blocking operation! + return call_host(SEMIHOSTING_SYS_READC, (void*)0); +} + + +#endif // EFX_SEMIHOSTING_H diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.h new file mode 100644 index 0000000..f2b38b5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.h @@ -0,0 +1,147 @@ +#ifndef SOC_H +#define SOC_H +#define SYSTEM_RISCV_ISA_RV32I 1 +#define SYSTEM_RISCV_ISA_EXT_M 1 +#define SYSTEM_RISCV_ISA_EXT_A 1 +#define SYSTEM_RISCV_ISA_EXT_C 1 +#define SYSTEM_RISCV_ISA_EXT_F 1 +#define SYSTEM_RISCV_ISA_EXT_D 1 +#define SYSTEM_RISCV_ISA_EXT_ZICSR 1 +#define SYSTEM_RISCV_ISA_EXT_ZIFENCE 1 +#define SYSTEM_PLIC_SYSTEM_CORES_0_EXTERNAL_INTERRUPT 0 +#define SYSTEM_PLIC_SYSTEM_CORES_0_EXTERNAL_SUPERVISOR_INTERRUPT 1 +#define SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_INTERRUPT 2 +#define SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_SUPERVISOR_INTERRUPT 3 +#define SYSTEM_PLIC_SYSTEM_CORES_2_EXTERNAL_INTERRUPT 4 +#define SYSTEM_PLIC_SYSTEM_CORES_2_EXTERNAL_SUPERVISOR_INTERRUPT 5 +#define SYSTEM_PLIC_SYSTEM_CORES_3_EXTERNAL_INTERRUPT 6 +#define SYSTEM_PLIC_SYSTEM_CORES_3_EXTERNAL_SUPERVISOR_INTERRUPT 7 +#define SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT 1 +#define SYSTEM_PLIC_USER_INTERRUPT_B_INTERRUPT 2 +#define SYSTEM_PLIC_USER_INTERRUPT_C_INTERRUPT 3 +#define SYSTEM_PLIC_USER_INTERRUPT_D_INTERRUPT 4 +#define SYSTEM_PLIC_USER_INTERRUPT_E_INTERRUPT 5 +#define SYSTEM_PLIC_USER_INTERRUPT_F_INTERRUPT 6 +#define SYSTEM_PLIC_USER_INTERRUPT_G_INTERRUPT 7 +#define SYSTEM_PLIC_USER_INTERRUPT_H_INTERRUPT 8 +#define SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT 9 +#define SYSTEM_PLIC_USER_INTERRUPT_J_INTERRUPT 10 +#define SYSTEM_PLIC_USER_INTERRUPT_K_INTERRUPT 11 +#define SYSTEM_PLIC_USER_INTERRUPT_L_INTERRUPT 12 +#define SYSTEM_PLIC_USER_INTERRUPT_M_INTERRUPT 13 +#define SYSTEM_PLIC_USER_INTERRUPT_N_INTERRUPT 14 +#define SYSTEM_PLIC_USER_INTERRUPT_O_INTERRUPT 15 +#define SYSTEM_PLIC_USER_INTERRUPT_P_INTERRUPT 16 +#define SYSTEM_PLIC_USER_INTERRUPT_Q_INTERRUPT 17 +#define SYSTEM_PLIC_USER_INTERRUPT_R_INTERRUPT 18 +#define SYSTEM_PLIC_USER_INTERRUPT_S_INTERRUPT 19 +#define SYSTEM_PLIC_USER_INTERRUPT_T_INTERRUPT 20 +#define SYSTEM_PLIC_USER_INTERRUPT_U_INTERRUPT 21 +#define SYSTEM_PLIC_USER_INTERRUPT_V_INTERRUPT 22 +#define SYSTEM_PLIC_USER_INTERRUPT_W_INTERRUPT 23 +#define SYSTEM_PLIC_USER_INTERRUPT_X_INTERRUPT 24 +#define SYSTEM_PLIC_SYSTEM_AXI_A_INTERRUPT 30 +#define SYSTEM_PLIC_SYSTEM_USER_TIMER_1_INTERRUPTS_0 49 +#define SYSTEM_PLIC_SYSTEM_USER_TIMER_0_INTERRUPTS_0 50 +#define SYSTEM_RAM_A_SIZE 16384 +#define SYSTEM_CORES_0_CFU 1 +#define SYSTEM_CORES_0_FPU 1 +#define SYSTEM_CORES_0_MMU 1 +#define SYSTEM_CORES_0_ICACHE_WAYS 4 +#define SYSTEM_CORES_0_ICACHE_SIZE 16384 +#define SYSTEM_CORES_0_BYTES_PER_LINE 64 +#define SYSTEM_CORES_0_DCACHE_WAYS 4 +#define SYSTEM_CORES_0_DCACHE_SIZE 16384 +#define SYSTEM_CORES_0_BYTES_PER_LINE 64 +#define SYSTEM_CORES_0_SUPERVISOR 1 +#define SYSTEM_CORES_1_CFU 1 +#define SYSTEM_CORES_1_FPU 1 +#define SYSTEM_CORES_1_MMU 1 +#define SYSTEM_CORES_1_ICACHE_WAYS 4 +#define SYSTEM_CORES_1_ICACHE_SIZE 16384 +#define SYSTEM_CORES_1_BYTES_PER_LINE 64 +#define SYSTEM_CORES_1_DCACHE_WAYS 4 +#define SYSTEM_CORES_1_DCACHE_SIZE 16384 +#define SYSTEM_CORES_1_BYTES_PER_LINE 64 +#define SYSTEM_CORES_1_SUPERVISOR 1 +#define SYSTEM_CORES_2_CFU 1 +#define SYSTEM_CORES_2_FPU 1 +#define SYSTEM_CORES_2_MMU 1 +#define SYSTEM_CORES_2_ICACHE_WAYS 4 +#define SYSTEM_CORES_2_ICACHE_SIZE 16384 +#define SYSTEM_CORES_2_BYTES_PER_LINE 64 +#define SYSTEM_CORES_2_DCACHE_WAYS 4 +#define SYSTEM_CORES_2_DCACHE_SIZE 16384 +#define SYSTEM_CORES_2_BYTES_PER_LINE 64 +#define SYSTEM_CORES_2_SUPERVISOR 1 +#define SYSTEM_CORES_3_CFU 1 +#define SYSTEM_CORES_3_FPU 1 +#define SYSTEM_CORES_3_MMU 1 +#define SYSTEM_CORES_3_ICACHE_WAYS 4 +#define SYSTEM_CORES_3_ICACHE_SIZE 16384 +#define SYSTEM_CORES_3_BYTES_PER_LINE 64 +#define SYSTEM_CORES_3_DCACHE_WAYS 4 +#define SYSTEM_CORES_3_DCACHE_SIZE 16384 +#define SYSTEM_CORES_3_BYTES_PER_LINE 64 +#define SYSTEM_CORES_3_SUPERVISOR 1 +#define SYSTEM_BRIDGE_BMB 0x0 +#define SYSTEM_RAM_A_CTRL 0xf9000000 +#define SYSTEM_RAM_A_CTRL_SIZE 0x4000 +#define SYSTEM_BMB_PERIPHERAL_BMB 0xf8000000 +#define SYSTEM_BMB_PERIPHERAL_BMB_SIZE 0x1000000 +#define SYSTEM_PLIC_CTRL 0xf8c00000 +#define SYSTEM_PLIC_CTRL_SIZE 0x400000 +#define SYSTEM_CLINT_CTRL 0xf8b00000 +#define SYSTEM_CLINT_CTRL_SIZE 0x10000 +#define SYSTEM_USER_TIMER_1_CTRL 0xf8016000 +#define SYSTEM_USER_TIMER_1_CTRL_SIZE 0x1000 +#define SYSTEM_USER_TIMER_0_CTRL 0xf8015000 +#define SYSTEM_USER_TIMER_0_CTRL_SIZE 0x1000 +#define SYSTEM_DDR_BMB 0x1000 +#define SYSTEM_DDR_BMB_SIZE 0xe7fff000 +#define SYSTEM_AXI_A_BMB 0xe8000000 +#define SYSTEM_AXI_A_BMB_SIZE 0x10000000 +#define SYSTEM_WATCHDOG_LOGIC_PARAMETER_PRESCALER_WIDTH 24 +#define SYSTEM_WATCHDOG_LOGIC_PARAMETER_TIMEOUT_WIDTH 16 +#define SYSTEM_WATCHDOG_LOGIC_PARAMETER_COUNTERS 2 +#define SYSTEM_WATCHDOG_LOGIC_CTRL 0xe8050000 +#define SYSTEM_WATCHDOG_LOGIC_CTRL_SIZE 0x100 +#define IO_APB_SLAVE_0_INPUT_SIZE 65536 +#define IO_APB_SLAVE_0_INPUT 0xe8100000 +#define SYSTEM_UART_0_IO_CTRL_SIZE 0x40 +#define SYSTEM_UART_0_IO_CTRL 0xe8010000 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_DATA_WIDTH_MAX 8 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_CLOCK_DIVIDER_WIDTH 20 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_PRE_SAMPLING_SIZE 1 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_SAMPLING_SIZE 5 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_POST_SAMPLING_SIZE 2 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_CTS_GEN 0 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_RTS_GEN 0 +#define SYSTEM_UART_0_IO_PARAMETER_UART_CTRL_CONFIG_RX_SAMPLE_PER_BIT 8 +#define SYSTEM_UART_0_IO_PARAMETER_INIT_CONFIG_BAUDRATE 115200 +#define SYSTEM_UART_0_IO_PARAMETER_INIT_CONFIG_DATA_LENGTH 7 +#define SYSTEM_UART_0_IO_PARAMETER_INIT_CONFIG_PARITY NONE +#define SYSTEM_UART_0_IO_PARAMETER_INIT_CONFIG_STOP ONE +#define SYSTEM_UART_0_IO_PARAMETER_BUS_CAN_WRITE_CLOCK_DIVIDER_CONFIG 1 +#define SYSTEM_UART_0_IO_PARAMETER_BUS_CAN_WRITE_FRAME_CONFIG 1 +#define SYSTEM_UART_0_IO_PARAMETER_TX_FIFO_DEPTH 128 +#define SYSTEM_UART_0_IO_PARAMETER_RX_FIFO_DEPTH 128 +#define SYSTEM_I2C_0_IO_CTRL_SIZE 0x100 +#define SYSTEM_I2C_0_IO_CTRL 0xe8020000 +#define SYSTEM_GPIO_0_IO_CTRL_SIZE 0x100 +#define SYSTEM_GPIO_0_IO_CTRL 0xe8040000 +#define SYSTEM_CLINT_HZ 200000000 +#define SYSTEM_SPI_0_IO_CTRL_SIZE 0x1000 +#define SYSTEM_SPI_0_IO_CTRL 0xe8030000 +#define SYSTEM_SPI_0_IO_PARAMETER_CMD_FIFO_DEPTH 256 +#define SYSTEM_SPI_0_IO_PARAMETER_RSP_FIFO_DEPTH 256 +#define SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT +#define SYSTEM_PLIC_SYSTEM_SPI_0_IO_INTERRUPT SYSTEM_PLIC_USER_INTERRUPT_B_INTERRUPT +#define SYSTEM_PLIC_SYSTEM_I2C_0_IO_INTERRUPT SYSTEM_PLIC_USER_INTERRUPT_C_INTERRUPT +#define SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0 SYSTEM_PLIC_USER_INTERRUPT_D_INTERRUPT +#define SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_1 SYSTEM_PLIC_USER_INTERRUPT_E_INTERRUPT +#define SYSTEM_PLIC_SYSTEM_WATCHDOG_SOFT_PANIC_INTERRUPT SYSTEM_PLIC_USER_INTERRUPT_F_INTERRUPT +#define SYSTEM_HARD_RISCV_QC32 1 +#define FAMILY_TYPE TITANIUM + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.mk new file mode 100644 index 0000000..b0592f4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/include/soc.mk @@ -0,0 +1,8 @@ +RV_M=yes +RV_C=yes +RV_A=yes +RV_F=yes +RV_D=yes +#CFLAGS+=-DSMP +DEBUG?=yes +DEBUG_OG?=yes diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/attach.cmm b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/attach.cmm new file mode 100644 index 0000000..f71bdf7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/attach.cmm @@ -0,0 +1,40 @@ +; ------------------------------------------------------------------------------- +; SapphireSoC Debug (Attach mode) +; -------------------------------------------------------------------------------- +; initialize and start the debugger +RESet +SYStem.RESet +SYStem.CPU RV32 +SYStem.Option.ResetMode NDMRST +SYStem.Option.IMASKASM on +SETUP.DIS AbiNames +SYStem.Mode Attach +Break + +; -------------------------------------------------------------------------------- +; load demo program +Data.LOAD.Elf ./build/demo.elf /NoCODE + +; -------------------------------------------------------------------------------- +; start program execution +; Go.direct main +; WAIT !STATE.RUN() + +; -------------------------------------------------------------------------------- +; open some windows +WinCLEAR +Mode.Hll +WinPOS 0. 0. 116. 26. +List.auto +WinPOS 120. 0. 100. 8. +Frame.view +WinPOS 120. 14. +Register.view +WinPOS 0. 32. +AREA + +TERM.GATE +TERM.METHOD RISCVSWI + +ENDDO + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/debug.cmm b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/debug.cmm new file mode 100644 index 0000000..c89f1d8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/debug.cmm @@ -0,0 +1,32 @@ +; ------------------------------------------------------------------------------- +; SapphireSoC Debug +; ------------------------------------------------------------------------------- +; initialize and start the debugger +RESet +SYStem.RESet +SYStem.CPU RV32 +SYStem.Option.ResetMode NDMRST +SYStem.Option.IMASKASM on +SYStem.Up + +; -------------------------------------------------------------------------------- +; load demo program +Data.LOAD.Elf ./build/demo.elf /Verify + +; -------------------------------------------------------------------------------- +; start program execution +Go.direct main +WAIT !STATE.RUN() + +; -------------------------------------------------------------------------------- +; open some windows +;WinCLEAR +Mode.Hll +WinPOS 0. 0. 116. 26. +List.auto +WinPOS 120. 0. 100. 8. +Frame.view +WinPOS 120. 14. + + +ENDDO diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/freertos.cmm b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/freertos.cmm new file mode 100644 index 0000000..b9cebbb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/freertos.cmm @@ -0,0 +1,40 @@ +; ------------------------------------------------------------------------------- +; SapphireSoC FreeRTOS Debug +; -------------------------------------------------------------------------------- +; initialize and start the debugger +RESet +SYStem.RESet +SYStem.CPU RV32 +SYStem.Option.ResetMode NDMRST +SYStem.Option.IMASKASM on +SYStem.Up + +; Disable the CLINT timer when the CPU is in debug mode +per.Set.Field CSR:0x7B0 0x600 0x3 + +; -------------------------------------------------------------------------------- +; load demo program +Data.LOAD.Elf ./build/freertos.elf /Verify + +; https://www2.lauterbach.com/pdf/rtos_freertos.pdf +task.config ~~/demo/riscv/kernel/freertos/freertos.t32 + +; -------------------------------------------------------------------------------- +; start program execution +Go.direct main +WAIT !STATE.RUN() + +; -------------------------------------------------------------------------------- +; open some windows +WinCLEAR +Mode.Hll +WinPOS 0. 0. 116. 26. +List.auto +WinPOS 120. 0. 100. 8. +Frame.view +WinPOS 120. 14. +AREA +TASK.TaskList + +ENDDO + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/readme.txt b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/readme.txt new file mode 100644 index 0000000..db34a69 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/readme.txt @@ -0,0 +1,40 @@ +=================================================================================================== +Lauterbach TRACE32 Debug Scripts for SapphireSoC +=================================================================================================== + +This folder contains sample debug scripts for Lauterbach TRACE32 software, to debug SapphireSoC. + +This folder contains 4 debug scripts, which are: +1. debug.cmm + - Halt and reset the system, load and program software ELF file into the system, + and start debugging from the beginning of software. + +2. attach.cmm + - Halt the system, load ELF file for debugging symbols (not re-programming the system), + then start debugging from the point where the system was before it was halted. + +3. freertos.cmm + - To debug FreeRTOS. + +4. smp.cmm + - To debug multicore system. + + +------------- +HOW TO USE +------------- +1. Look for the command "Data.LOAD.Elf" within the scripts, change the ELF file path, + to the path to your ELF file. + +2. For SMP debugging, you might need to further modify the smp.cmm script according to the + number of cores in your SapphireSoC. + +3. You may further modify the scripts to fit your environment/system/personal preference. + + +For more information on Lauterbach TRACE32 software and its commands: + - Debugger tutorial: https://www2.lauterbach.com/pdf/debugger_tutorial.pdf + - RISC-V Debugger: https://www2.lauterbach.com/pdf/debugger_riscv.pdf + - Lauterbach TRACE32 General Commands Reference Guide (multiple volumes) + - Lauterbach official website: https://www.lauterbach.com/ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/smp.cmm b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/smp.cmm new file mode 100644 index 0000000..8fb15c7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/lauterbach_trace32/smp.cmm @@ -0,0 +1,41 @@ +; -------------------------------------------------------------------------------- +; SapphireSoC 2-core SMP Debug +; -------------------------------------------------------------------------------- +; initialize and start the debugger +RESet +SYStem.RESet +SYStem.CPU RV32 +SYStem.CONFIG CORE 1. 1. +SYStem.CONFIG CoreNumber 2. +SYStem.CONFIG HARTINDEX 0. 1. +CORE.ASSIGN 1. 2. +SYStem.Option.ResetMode NDMRST +SYStem.Option.IMASKASM on +SYStem.Up + +; -------------------------------------------------------------------------------- +; load demo program +Data.LOAD.Elf ./build/smpDemo.elf /Verify + +; -------------------------------------------------------------------------------- +; start program execution +;Go.direct main +;WAIT !STATE.RUN() + +Register.Set PC 0x1000 /CORE 0. +Register.Set PC 0x1000 /CORE 1. + +; -------------------------------------------------------------------------------- +; open some windows +WinCLEAR +Mode.Hll +List.auto /CORE 0. +List.auto /CORE 1. +Register.view /CORE 0. +Register.view /CORE 1. +PERF.ListFunc /CORE 0. +PERF.ListFunc /CORE 1. +AREA + +ENDDO + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/bootloader.ld b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/bootloader.ld new file mode 100644 index 0000000..51f5426 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/bootloader.ld @@ -0,0 +1,154 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram (wxai!r) : ORIGIN = 0xF9000000, LENGTH = 16K +} + +PHDRS +{ + ram PT_LOAD; +} + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 256; + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ram AT>ram :ram + + .text : + { + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } >ram AT>ram :ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram AT>ram :ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram + + .lalign : ALIGN(4) + { + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram + + .dalign : ALIGN(4) + { + PROVIDE( _data = . ); + } >ram AT>ram :ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x7F0 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . += 10; /* fix for linker false error message */ + } >ram AT>ram :ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram AT>ram :ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack (NOLOAD) : ALIGN(16) + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + } >ram AT>ram :ram +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default.ld b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default.ld new file mode 100644 index 0000000..e92148a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default.ld @@ -0,0 +1,169 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram (wxai!r) : ORIGIN = 0x00001000, LENGTH = 2044K +} + +PHDRS +{ + ram PT_LOAD; +} + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 8K; + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ram AT>ram :ram + + .text : + { + *(.text.Proc_1); + *(.text.Proc_2); + *(.text.Proc_3); + *(.text.Proc_4); + *(.text.Proc_5); + *(.text.Proc_6); + *(.text.Proc_7); + *(.text.Proc_8); + *(.text.Func_1); + *(.text.Func_2); + *(.text.Func_3); + *(.text.strcpy); + *libc.a:*(.text .text.*) + *(.text.main); + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } >ram AT>ram :ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram AT>ram :ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram + + .lalign : ALIGN(4) + { + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram + + .dalign : ALIGN(4) + { + PROVIDE( _data = . ); + } >ram AT>ram :ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x7F0 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . += 10; /* fix for linker false error message */ + } >ram AT>ram :ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram AT>ram :ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack : ALIGN(16) + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + __freertos_irq_stack_top = .; + } >ram AT>ram :ram +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default_i.ld b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default_i.ld new file mode 100644 index 0000000..9f4d241 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/default_i.ld @@ -0,0 +1,169 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram (wxai!r) : ORIGIN = 0xF9000000, LENGTH = 16K +} + +PHDRS +{ + ram PT_LOAD; +} + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 2048; + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ram AT>ram :ram + + .text : + { + *(.text.Proc_1); + *(.text.Proc_2); + *(.text.Proc_3); + *(.text.Proc_4); + *(.text.Proc_5); + *(.text.Proc_6); + *(.text.Proc_7); + *(.text.Proc_8); + *(.text.Func_1); + *(.text.Func_2); + *(.text.Func_3); + *(.text.strcpy); + *libc.a:*(.text .text.*) + *(.text.main); + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } >ram AT>ram :ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram AT>ram :ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram + + .lalign : ALIGN(4) + { + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram + + .dalign : ALIGN(4) + { + PROVIDE( _data = . ); + } >ram AT>ram :ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x7F0 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . += 10; /* fix for linker false error message */ + } >ram AT>ram :ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram AT>ram :ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack : ALIGN(16) + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + __freertos_irq_stack_top = .; + } >ram AT>ram :ram +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos.ld b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos.ld new file mode 100644 index 0000000..1de357c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos.ld @@ -0,0 +1,169 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram (wxai!r) : ORIGIN = 0x00001000, LENGTH = 16380K +} + +PHDRS +{ + ram PT_LOAD; +} + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 4K; + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ram AT>ram :ram + + .text : + { + *(.text.Proc_1); + *(.text.Proc_2); + *(.text.Proc_3); + *(.text.Proc_4); + *(.text.Proc_5); + *(.text.Proc_6); + *(.text.Proc_7); + *(.text.Proc_8); + *(.text.Func_1); + *(.text.Func_2); + *(.text.Func_3); + *(.text.strcpy); + *libc.a:*(.text .text.*) + *(.text.main); + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } >ram AT>ram :ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram AT>ram :ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram + + .lalign : ALIGN(4) + { + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram + + .dalign : ALIGN(4) + { + PROVIDE( _data = . ); + } >ram AT>ram :ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x7F0 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . += 10; /* fix for linker false error message */ + } >ram AT>ram :ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram AT>ram :ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack : ALIGN(16) + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + __freertos_irq_stack_top = .; + } >ram AT>ram :ram +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos_i.ld b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos_i.ld new file mode 100644 index 0000000..9f4d241 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/linker/freertos_i.ld @@ -0,0 +1,169 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram (wxai!r) : ORIGIN = 0xF9000000, LENGTH = 16K +} + +PHDRS +{ + ram PT_LOAD; +} + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 2048; + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ram AT>ram :ram + + .text : + { + *(.text.Proc_1); + *(.text.Proc_2); + *(.text.Proc_3); + *(.text.Proc_4); + *(.text.Proc_5); + *(.text.Proc_6); + *(.text.Proc_7); + *(.text.Proc_8); + *(.text.Func_1); + *(.text.Func_2); + *(.text.Func_3); + *(.text.strcpy); + *libc.a:*(.text .text.*) + *(.text.main); + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } >ram AT>ram :ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram AT>ram :ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram + + .lalign : ALIGN(4) + { + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram + + .dalign : ALIGN(4) + { + PROVIDE( _data = . ); + } >ram AT>ram :ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x7F0 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . += 10; /* fix for linker false error message */ + } >ram AT>ram :ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram AT>ram :ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack : ALIGN(16) + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + __freertos_irq_stack_top = .; + } >ram AT>ram :ram +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_profile_hard.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_profile_hard.cfg new file mode 100644 index 0000000..8e2f3c6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_profile_hard.cfg @@ -0,0 +1,7 @@ +CO_DEBUG=0 +INTF_JTAG_TYPE=0 +INTF_JTAG_TAP_SEL=8 +FAMILY=Titanium +DEVICE=Ti375C529 +EFINITY_ROOT=/home/byron/Software/Efinix/Efinity/2025.2 +JTAG_DAEMON=/home/byron/Software/Efinix/Efinity/2025.2/debugger/bin/jtag_daemon_cmd.sh diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_softTap.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_softTap.cfg new file mode 100644 index 0000000..9834396 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_softTap.cfg @@ -0,0 +1,43 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +gdb_target_description disable +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal + +jtag newtap $_CHIPNAME bridge -irlen 5 -ircapture 0x1 -irmask 0x1F +if { $cpu_count > 1 && [info exists RUN_SMP_APP] } { + target create $_CHIPNAME.cpu0 riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid 0 -dbgbase [expr 0*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 -rtos hwthread + for {set i 1} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + } + target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 $_CHIPNAME.cpu2 $_CHIPNAME.cpu3 + +} else { + for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + } +} +riscv resume_order reversed + +#insert target tap(s) info# +#start# + +#end# + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + #soft_reset_halt + halt +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_ti.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_ti.cfg new file mode 100644 index 0000000..83fe7dd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_ti.cfg @@ -0,0 +1,45 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +gdb_target_description disable +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal +jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 5 -ircapture 0x5 -irmask 0xF +if { $cpu_count > 1 && [info exists RUN_SMP_APP] } { + target create $_CHIPNAME.cpu0 riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid 0 -dbgbase [expr 0*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 -rtos hwthread + for {set i 1} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + } + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 + target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 $_CHIPNAME.cpu2 $_CHIPNAME.cpu3 + +} else { + for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 + } +} +riscv resume_order reversed + +#insert target tap(s) info# +#start# + +#end# + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + #soft_reset_halt + halt +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_tz.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_tz.cfg new file mode 100644 index 0000000..83fe7dd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/debug_tz.cfg @@ -0,0 +1,45 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +gdb_target_description disable +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal +jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 5 -ircapture 0x5 -irmask 0xF +if { $cpu_count > 1 && [info exists RUN_SMP_APP] } { + target create $_CHIPNAME.cpu0 riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid 0 -dbgbase [expr 0*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 -rtos hwthread + for {set i 1} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + } + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 + target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 $_CHIPNAME.cpu2 $_CHIPNAME.cpu3 + +} else { + for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 + } +} +riscv resume_order reversed + +#insert target tap(s) info# +#start# + +#end# + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + #soft_reset_halt + halt +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/external.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/external.cfg new file mode 100644 index 0000000..d66c62c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/external.cfg @@ -0,0 +1,13 @@ +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + #default + set _CPUTAPID 0x10002fff +} + +adapter driver ftdi +#ftdi device_desc "Titanium Ti375C529 Development Kit" +ftdi vid_pid 0x0403 0x6011 +ftdi channel 0 + +ftdi layout_init 0x0008 0x000b diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_softTap.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_softTap.cfg new file mode 100644 index 0000000..6c0f802 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_softTap.cfg @@ -0,0 +1,31 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal +jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 4 -ircapture 0x1 -irmask 0xF + +for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 +} +#insert target tap(s) info# +#start# + +#end# + +flash bank xip vexriscv_nor_spi 0x00000000 0x100000 0 0 $_CHIPNAME.cpu0 0xF8014000 + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + soft_reset_halt +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_ti.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_ti.cfg new file mode 100644 index 0000000..bf90fcf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_ti.cfg @@ -0,0 +1,33 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal +jtag newtap $_CHIPNAME bridge -irlen 5 -ircapture 0x5 -irmask 0xF + +for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 +} +#insert chain target tap(s) info# +#start# + +#end# + +flash bank xip vexriscv_nor_spi 0x00000000 0x1000000 0 0 $_CHIPNAME.cpu0 0xF8014000 + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + soft_reset_halt +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_tz.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_tz.cfg new file mode 100644 index 0000000..bf90fcf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/flash_tz.cfg @@ -0,0 +1,33 @@ +set _ENDIAN little +set _TAP_TYPE 1234 + +set cpu_count 4 +set instr_addr 0x00001000 + +set proj_loc ..//..//..// + +adapter speed 6000 +adapter srst delay 260 +jtag_ntrst_delay 250 + +set _CHIPNAME fpga_spinal +jtag newtap $_CHIPNAME bridge -irlen 5 -ircapture 0x5 -irmask 0xF + +for {set i 0} {$i < $cpu_count} {incr i} { + target create $_CHIPNAME.cpu$i riscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] -work-area-phys 0xF9000000 -work-area-size 1024 + riscv use_bscan_tunnel 6 1 + riscv set_bscan_tunnel_ir 8 +} +#insert chain target tap(s) info# +#start# + +#end# + +flash bank xip vexriscv_nor_spi 0x00000000 0x1000000 0 0 $_CHIPNAME.cpu0 0xF8014000 + +for {set i 0} {$i < $cpu_count} {incr i} { + targets $_CHIPNAME.cpu$i + poll_period 50 + init + soft_reset_halt +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_ti.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_ti.cfg new file mode 100644 index 0000000..16d174a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_ti.cfg @@ -0,0 +1,24 @@ +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + #default + set _CPUTAPID 0x006A0A79 +} + +adapter driver ftdi +#ftdi device_desc "Titanium Ti375C529 Development Kit" +ftdi vid_pid 0x0403 0x6011 + +# Channel for using JTAG. 0 => channel A, 1 => channel B +ftdi channel 1 + +# name signal state direction JTAG name +# *DBUS0 TCK/SK (low =0) (out=1) +# *DBUS1 TDI/DO (low =0) (out=1) +# *DBUS2 TDO/DI (low =0) (in =0) +# *DBUS3 TMS/CS (high=1) (out=1) +# *DBUS4 GPIOL0 (low =0) (out=0) (nTRST) +# *DBUS5 GPIOL1 (low =0) (out=0) WAIT | STOPCLK +# *DBUS6 GPIOL2 (low =0) (out=0) (nRST) +# *DBUS7 GPIOL3 (low =0) (out=0) RTCK +ftdi layout_init 0x08 0x0b diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_tz.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_tz.cfg new file mode 100644 index 0000000..8da707e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/ftdi_tz.cfg @@ -0,0 +1,33 @@ +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + #_CPUTAPID for Tz75 + #set _CPUTAPID 0x006C8A79 + + #_CPUTAPID for Tz100 + #set _CPUTAPID 0x006C9A79 + + #_CPUTAPID for Tz200 + #set _CPUTAPID 0x006A8A79 + + #default _CPUTAPID set for Tz325 + set _CPUTAPID 0x006A9A79 +} + +adapter driver ftdi +#ftdi device_desc "Topaz Tz Development Kit" +ftdi vid_pid 0x0403 0x6011 + +# Channel for using JTAG. 0 => channel A, 1 => channel B +ftdi channel 1 + +# name signal state direction JTAG name +# *DBUS0 TCK/SK (low =0) (out=1) +# *DBUS1 TDI/DO (low =0) (out=1) +# *DBUS2 TDO/DI (low =0) (in =0) +# *DBUS3 TMS/CS (high=1) (out=1) +# *DBUS4 GPIOL0 (low =0) (out=0) (nTRST) +# *DBUS5 GPIOL1 (low =0) (out=0) WAIT | STOPCLK +# *DBUS6 GPIOL2 (low =0) (out=0) (nRST) +# *DBUS7 GPIOL3 (low =0) (out=0) RTCK +ftdi layout_init 0x08 0x0b diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/gdb-target.dtd b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/gdb-target.dtd new file mode 100644 index 0000000..df558ee --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/gdb-target.dtd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%xinclude; \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/jtag_daemon.cfg b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/jtag_daemon.cfg new file mode 100644 index 0000000..0be092a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/jtag_daemon.cfg @@ -0,0 +1,11 @@ +REGISTER_ID=RISCV-IDE +AUTO_SELECT=1 +CHAIN_TAP= +VID= +PID= +JTAG_CHANNEL_NO= +SERIAL_NO= +GDB_PORT=3333 +JTAG_KHZ=6000 +DEBUG=1 +CFG_FILE= diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-cpu.xml b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-cpu.xml new file mode 100644 index 0000000..e8f34e6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-cpu.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-csr.xml b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-csr.xml new file mode 100644 index 0000000..08acbed --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-csr.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-fpu.xml b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-fpu.xml new file mode 100644 index 0000000..209afff --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-fpu.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-reg.xml b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-reg.xml new file mode 100644 index 0000000..9fe28fe --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_32bit-reg.xml @@ -0,0 +1,9 @@ + + + + +riscv:rv32 + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_xsvd.json b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_xsvd.json new file mode 100644 index 0000000..af80064 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/sapphire_soc_xsvd.json @@ -0,0 +1,2086 @@ +{ + "schemaVersion": "0.2.4", + "contentVersion": "0.2.0", + "headerVersion": "0.2.0", + "license": "MIT", + "copyright": "Copyright (C) 2013-2024 Efinix Inc. All rights reserved.", + "device": { + "Sapphire High Performance SoC": { + "version": "1.0.0", + "displayName": "Sapphire High Performance SoC", + "description": " Hardened High Performance Quad Core RISC-V SoC", + "supplier": { + "name": "efinix", + "id": "1", + "displayName": "Efinix", + "fullName": "Efinix, Inc.", + "contact": "sales-na@efinixinc.com" + }, + "busWidth": "32", + "resetMask": "all", + "resetValue": "0x00000000", + "access": "rw", + "headerGuardPrefix": "SAPPHIRE_HP_SOC_", + "headerTypePrefix": "sapphire_hp_soc_", + "headerInterruptPrefix": "sapphire_soc_interrupt_global_", + "headerInterruptEnumPrefix": "riscv_interrupts_global_", + "revision": "r0p0", + "numInterrupts": "24", + "priorityBits": "3", + "regWidth": "32", + "cores": { + "VexRiscv": { + "harts": "4", + "isa": "RV32IMCAFD", + "isaVersion": "2.2", + "mpu": "none", + "mmu": "1", + "numLocalInterrupts": "24" + } + }, + "peripherals": { + "clint": { + "description": "Core Local Interrupt (CLINT) Peripheral", + "baseAddress": "0xf8b00000", + "size": "0x10000", + "registers": { + "PIP": { + "description": "MSIP (Machine-mode Software Interrupts) Register per Hart", + "addressOffset": "0x0000", + "fields": { + "softInt": { + "description": "Machine mode software interrupt.", + "bitOffset": "0", + "bitWidth": "1" + } + } + }, + "mtimecmp(lo)": { + "description": "Machine Time Compare Registers per Hart (Lower 32 bit)", + "addressOffset": "0x4000", + "arraySize": "1", + "access": "w", + "regWidth": "32" + }, + "mtimecmp(hi)": { + "description": "Machine Time Compare Registers per Hart (Higher 32 bit)", + "addressOffset": "0x4004", + "arraySize": "1", + "access": "w", + "regWidth": "32" + }, + "mtime(lo)": { + "description": "Machine Time Register (Lower 32 bit)", + "addressOffset": "0xBFF8", + "access": "r", + "regWidth": "32" + }, + "mtime(hi)": { + "description": "Machine Time Register (Higher 32 bit)", + "addressOffset": "0xBFFC", + "access": "r", + "regWidth": "32" + } + } + }, + "plic": { + "description": "Platform-Level Interrupt Controller (PLIC) Peripheral", + "baseAddress": "0xf8c00000", + "size": "0x400000", + "registers": { + "pendings": { + "description": "Interrupt Pending Bits Registers", + "addressOffset": "0x1000", + "access": "r", + "fields": { + "userIntA_ip": { + "description": "User Interrupt A Pending", + "bitOffset": "1", + "bitWidth": "1" + }, + "userIntB_ip": { + "description": "User Interrupt B Pending", + "bitOffset": "2", + "bitWidth": "1" + }, + "userIntC_ip": { + "description": "User Interrupt C Pending", + "bitOffset": "3", + "bitWidth": "1" + }, + "userIntD_ip": { + "description": "User Interrupt D Pending", + "bitOffset": "4", + "bitWidth": "1" + }, + "userIntE_ip": { + "description": "User Interrupt E Pending", + "bitOffset": "5", + "bitWidth": "1" + }, + "userIntF_ip": { + "description": "User Interrupt F Pending", + "bitOffset": "6", + "bitWidth": "1" + }, + "userIntG_ip": { + "description": "User Interrupt G Pending", + "bitOffset": "7", + "bitWidth": "1" + }, + "userIntH_ip": { + "description": "User Interrupt H Pending", + "bitOffset": "8", + "bitWidth": "1" + }, + "userIntI_ip": { + "description": "User Interrupt I Pending", + "bitOffset": "9", + "bitWidth": "1" + }, + "userIntJ_ip": { + "description": "User Interrupt J Pending", + "bitOffset": "10", + "bitWidth": "1" + }, + "userIntK_ip": { + "description": "User Interrupt K Pending", + "bitOffset": "11", + "bitWidth": "1" + }, + "userIntL_ip": { + "description": "User Interrupt L Pending", + "bitOffset": "12", + "bitWidth": "1" + }, + "userIntM_ip": { + "description": "User Interrupt M Pending", + "bitOffset": "13", + "bitWidth": "1" + }, + "userIntN_ip": { + "description": "User Interrupt N Pending", + "bitOffset": "14", + "bitWidth": "1" + }, + "userIntO_ip": { + "description": "User Interrupt O Pending", + "bitOffset": "15", + "bitWidth": "1" + }, + "userIntP_ip": { + "description": "User Interrupt P Pending", + "bitOffset": "16", + "bitWidth": "1" + }, + "userIntQ_ip": { + "description": "User Interrupt Q Pending", + "bitOffset": "17", + "bitWidth": "1" + }, + "userIntR_ip": { + "description": "User Interrupt R Pending", + "bitOffset": "18", + "bitWidth": "1" + }, + "userIntS_ip": { + "description": "User Interrupt S Pending", + "bitOffset": "19", + "bitWidth": "1" + }, + "userIntT_ip": { + "description": "User Interrupt T Pending", + "bitOffset": "20", + "bitWidth": "1" + }, + "userIntU_ip": { + "description": "User Interrupt U Pending", + "bitOffset": "21", + "bitWidth": "1" + }, + "userIntV_ip": { + "description": "User Interrupt V Pending", + "bitOffset": "22", + "bitWidth": "1" + }, + "userIntW_ip": { + "description": "User Interrupt W Pending", + "bitOffset": "23", + "bitWidth": "1" + }, + "userIntX_ip": { + "description": "User Interrupt X Pending", + "bitOffset": "24", + "bitWidth": "1" + }, + "userTim0_ip": { + "description": "User Timer Interrupt 0 Pending", + "bitOffset": "50", + "bitWidth": "1" + }, + "userTim1_ip": { + "description": "User Timer Interrupt 1 Pending", + "bitOffset": "49", + "bitWidth": "1" + }, + "axiA_ip": { + "description": "AXI A Interrupt Pending", + "bitOffset": "30", + "bitWidth": "1" + } + } + } + }, + "clusters": { + "priorities": { + "description": "Interrupt Priorities Registers", + "addressOffset": "0x0000", + "clusters": { + "uart0": { + "addressOffset": "0x0004", + "description": "The priority for UART 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "uart1": { + "addressOffset": "0x0008", + "description": "The priority for UART 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "uart2": { + "addressOffset": "0x000C", + "description": "The priority for UART 2 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userTimer0": { + "addressOffset": "0x004C", + "description": "The priority for User Timer 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userTimer1": { + "addressOffset": "0x0050", + "description": "The priority for User Timer 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userTimer2": { + "addressOffset": "0x0054", + "description": "The priority for User Timer 2 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "spi0": { + "addressOffset": "0x0010", + "description": "The priority for SPI 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "spi1": { + "addressOffset": "0x0014", + "description": "The priority for SPI 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "spi2": { + "addressOffset": "0x0018", + "description": "The priority for SPI 2 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "i2c0": { + "addressOffset": "0x0020", + "description": "The priority for I2C 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "i2c1": { + "addressOffset": "0x0024", + "description": "The priority for I2C 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "i2c2": { + "addressOffset": "0x0028", + "description": "The priority for I2C 2 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "gpio0i0": { + "addressOffset": "0x0030", + "description": "The priority for GPIO 0 Interrupt 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "gpio0i1": { + "addressOffset": "0x0034", + "description": "The priority for GPIO 0 Interrupt 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "gpio1i0": { + "addressOffset": "0x0038", + "description": "The priority for GPIO 1 Interrupt 0 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "gpio1i1": { + "addressOffset": "0x003C", + "description": "The priority for GPIO 1 Interrupt 1 global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntA": { + "addressOffset": "0x0040", + "description": "The priority for User Interrupt A global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntB": { + "addressOffset": "0x0044", + "description": "The priority for User Interrupt B global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntC": { + "addressOffset": "0x0058", + "description": "The priority for User Interrupt C global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntD": { + "addressOffset": "0x005C", + "description": "The priority for User Interrupt D global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntE": { + "addressOffset": "0x0060", + "description": "The priority for User Interrupt E global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntF": { + "addressOffset": "0x0064", + "description": "The priority for User Interrupt F global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntG": { + "addressOffset": "0x0068", + "description": "The priority for User Interrupt G global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "userIntH": { + "addressOffset": "0x006C", + "description": "The priority for User Interrupt H global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + }, + "axiA": { + "addressOffset": "0x0078", + "description": "The priority for AXI A Interface global interrupt", + "registers": { + "priority": { + "description": "The Priority Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + } + } + }, + "enablestarget0": { + "description": "Hart 0 Interrupt Enable Bits", + "addressOffset": "0x00002000", + "clusters": { + "m": { + "addressOffset": "0x0000", + "description": "Hart 0 M-mode Interrupt Enable Bits", + "registers": { + "enables": { + "description": "Interrupt Enable Bits Registers", + "addressOffset": "0x0000", + "fields": { + "userInterruptA": { + "description": "User Interrupt A Enable Bit", + "bitOffset": "1", + "bitWidth": "1" + }, + "userInterruptB": { + "description": "User Interrupt B Enable Bit", + "bitOffset": "2", + "bitWidth": "1" + }, + "userInterruptC": { + "description": "User Interrupt C Enable Bit", + "bitOffset": "3", + "bitWidth": "1" + }, + "userInterruptD": { + "description": "User Interrupt D Enable Bit", + "bitOffset": "4", + "bitWidth": "1" + }, + "userInterruptE": { + "description": "User Interrupt E Enable Bit", + "bitOffset": "5", + "bitWidth": "1" + }, + "userInterruptF": { + "description": "User Interrupt F Enable Bit", + "bitOffset": "6", + "bitWidth": "1" + }, + "userInterruptG": { + "description": "User Interrupt G Enable Bit", + "bitOffset": "7", + "bitWidth": "1" + }, + "userInterruptH": { + "description": "User Interrupt H Enable Bit", + "bitOffset": "8", + "bitWidth": "1" + }, + "userInterruptI": { + "description": "User Interrupt I Enable Bit", + "bitOffset": "9", + "bitWidth": "1" + }, + "userInterruptJ": { + "description": "User Interrupt J Enable Bit", + "bitOffset": "10", + "bitWidth": "1" + }, + "userInterruptK": { + "description": "User Interrupt K Enable Bit", + "bitOffset": "11", + "bitWidth": "1" + }, + "userInterruptL": { + "description": "User Interrupt L Enable Bit", + "bitOffset": "12", + "bitWidth": "1" + }, + "userInterruptM": { + "description": "User Interrupt M Enable Bit", + "bitOffset": "13", + "bitWidth": "1" + }, + "userInterruptN": { + "description": "User Interrupt N Enable Bit", + "bitOffset": "14", + "bitWidth": "1" + }, + "userInterruptO": { + "description": "User Interrupt O Enable Bit", + "bitOffset": "15", + "bitWidth": "1" + }, + "userInterruptP": { + "description": "User Interrupt P Enable Bit", + "bitOffset": "16", + "bitWidth": "1" + }, + "userInterruptQ": { + "description": "User Interrupt Q Enable Bit", + "bitOffset": "17", + "bitWidth": "1" + }, + "userInterruptR": { + "description": "User Interrupt R Enable Bit", + "bitOffset": "18", + "bitWidth": "1" + }, + "userInterruptS": { + "description": "User Interrupt S Enable Bit", + "bitOffset": "19", + "bitWidth": "1" + }, + "userInterruptT": { + "description": "User Interrupt T Enable Bit", + "bitOffset": "20", + "bitWidth": "1" + }, + "userInterruptU": { + "description": "User Interrupt U Enable Bit", + "bitOffset": "21", + "bitWidth": "1" + }, + "userInterruptV": { + "description": "User Interrupt V Enable Bit", + "bitOffset": "22", + "bitWidth": "1" + }, + "userInterruptW": { + "description": "User Interrupt W Enable Bit", + "bitOffset": "23", + "bitWidth": "1" + }, + "userInterruptX": { + "description": "User Interrupt X Enable Bit", + "bitOffset": "24", + "bitWidth": "1" + }, + "axiA": { + "description": "AXI A Interrupt Enable Bit", + "bitOffset": "30", + "bitWidth": "1" + }, + "userTim0": { + "description": "User Timer 0 Interrupt Enable Bit", + "bitOffset": "50", + "bitWidth": "1" + }, + "userTim1": { + "description": "User Timer 1 Interrupt Enable Bit", + "bitOffset": "49", + "bitWidth": "1" + } + } + } + } + } + } + }, + "target0": { + "description": "Hart 0 Interrupt Thresholds", + "addressOffset": "0x00200000", + "clusters": { + "m": { + "addressOffset": "0x0000", + "description": "Hart 0 M-Mode Interrupt Threshold", + "registers": { + "threshold": { + "description": "The Priority Threshold Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "The priority threshold value", + "bitOffset": "0", + "bitWidth": "2", + "resetMask": "all", + "resetValue": "0x0" + } + } + }, + "claimcomplete": { + "description": "The Interrupt Claim/Completion Register", + "addressOffset": "0x0004", + "fields": { + "value": { + "description": "The Interrupt Claim/Completion value", + "bitOffset": "0", + "bitWidth": "5", + "resetMask": "all", + "resetValue": "0x0" + } + } + } + } + } + } + } + }, + "interrupts": { + "userInterruptA": { + "description": "User Interrupt A", + "value": "1" + }, + "userInterruptB": { + "description": "User Interrupt B", + "value": "2" + }, + "userInterruptC": { + "description": "User Interrupt C", + "value": "3" + }, + "userInterruptD": { + "description": "User Interrupt D", + "value": "4" + }, + "userInterruptE": { + "description": "User Interrupt E", + "value": "5" + }, + "userInterruptF": { + "description": "User Interrupt F", + "value": "6" + }, + "userInterruptG": { + "description": "User Interrupt G", + "value": "7" + }, + "userInterruptH": { + "description": "User Interrupt H", + "value": "8" + }, + "userInterruptI": { + "description": "User Interrupt I", + "value": "9" + }, + "userInterruptJ": { + "description": "User Interrupt J", + "value": "10" + }, + "userInterruptK": { + "description": "User Interrupt K", + "value": "11" + }, + "userInterruptL": { + "description": "User Interrupt L", + "value": "12" + }, + "userInterruptM": { + "description": "User Interrupt M", + "value": "13" + }, + "userInterruptN": { + "description": "User Interrupt N", + "value": "14" + }, + "userInterruptO": { + "description": "User Interrupt O", + "value": "15" + }, + "userInterruptP": { + "description": "User Interrupt P", + "value": "16" + }, + "userInterruptQ": { + "description": "User Interrupt Q", + "value": "17" + }, + "userInterruptR": { + "description": "User Interrupt R", + "value": "18" + }, + "userInterruptS": { + "description": "User Interrupt S", + "value": "19" + }, + "userInterruptT": { + "description": "User Interrupt T", + "value": "20" + }, + "userInterruptU": { + "description": "User Interrupt U", + "value": "21" + }, + "userInterruptV": { + "description": "User Interrupt V", + "value": "22" + }, + "userInterruptW": { + "description": "User Interrupt W", + "value": "23" + }, + "userInterruptX": { + "description": "User Interrupt X", + "value": "24" + } + } + }, + "gpio 0": { + "description": "General Purpose Input/Output Controller (GPIO) 0 Peripheral", + "baseAddress": "0xe8040000", + "size": "0x100", + "registers": { + "Input": { + "description": "Input Pin Value Register", + "addressOffset": "0x0000", + "fields": { + "bit": { + "repeatGenerator": "0-3", + "description": "Input Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "", + "access": "r" + } + } + }, + "output": { + "description": "Output Register", + "addressOffset": "0x0004", + "fields": { + "bit": { + "repeatGenerator": "0-3", + "description": "Output Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + }, + "outputen": { + "description": "Output Enable Register", + "addressOffset": "0x0008", + "fields": { + "bit": { + "repeatGenerator": "0-3", + "description": "Pin Output Enable Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + }, + "riseie": { + "description": "Rise Interrupt Enable Register", + "addressOffset": "0x0020", + "fields": { + "bit": { + "repeatGenerator": "0-1", + "description": "Rise Interrupt Enable Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + }, + "fallie": { + "description": "Fall Interrupt Enable Register", + "addressOffset": "0x0024", + "fields": { + "bit": { + "repeatGenerator": "0-1", + "description": "Fall Interrupt Enable Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + }, + "highie": { + "description": "High Interrupt Enable Register", + "addressOffset": "0x0028", + "fields": { + "bit": { + "repeatGenerator": "0-1", + "description": "High Interrupt Enable Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + }, + "lowie": { + "description": "Low Interrupt Enable Register", + "addressOffset": "0x002C", + "fields": { + "bit": { + "repeatGenerator": "0-1", + "description": "Low Interrupt Enable Bit Field", + "bitOffset": "0", + "bitWidth": "1", + "headerName": "" + } + } + } + }, + "interrupts": { + "gpio0int0": { + "description": "GPIO0 Interrupt 0", + "value": "SYSTEM_PLIC_USER_INTERRUPT_D_INTERRUPT" + }, + "gpio0int1": { + "description": "GPIO0 Interrupt 1", + "value": "SYSTEM_PLIC_USER_INTERRUPT_E_INTERRUPT" + } + } + }, + "uart0": { + "description": "Universal Asynchronous Receiver/Transmitter (UART) 0 Peripheral", + "baseAddress": "0xe8010000", + "size": "0x40", + "resetMask": "none", + "groupName": "uart", + "registers": { + "data": { + "description": "Transmit Data Register", + "addressOffset": "0x0000", + "fields": { + "data": { + "description": "Transmit/ Receive data", + "bitOffset": "0", + "bitWidth": "8" + }, + "dataValid": { + "description": "Read data valid", + "bitOffset": "16", + "bitWidth": "1", + "access": "r" + } + } + }, + "status": { + "description": "Status Register", + "addressOffset": "0x0004", + "fields": { + "txInterruptEnable": { + "description": "Enable interrupt when TX FIFO is empty", + "bitOffset": "0", + "bitWidth": "1" + }, + "rxInterruptEnable": { + "description": "Enable interrupt when RX FIFO is not empty", + "bitOffset": "1", + "bitWidth": "1" + }, + "txInterrupt": { + "description": "Interrupt when TX FIFO is empty", + "bitOffset": "8", + "bitWidth": "1", + "access": "r" + }, + "rxInterrupt": { + "description": "Interrupt when RX FIFO is not empty", + "bitOffset": "9", + "bitWidth": "1", + "access": "r" + }, + "writeBusy": { + "description": "Write operation in progress", + "bitOffset": "15", + "bitWidth": "1", + "access": "r" + }, + "writeAvailability": { + "description": "UART FIFO availability", + "bitOffset": "16", + "bitWidth": "8", + "access": "r" + }, + "readOccupancy": { + "description": "UART FIFO occupancy", + "bitOffset": "24", + "bitWidth": "8", + "access": "r" + } + } + }, + "clockDivider": { + "description": "Clock Divider Register", + "addressOffset": "0x0008", + "fields": { + "divFac": { + "description": "Divider factor for UART baud rate", + "bitOffset": "0", + "bitWidth": "20", + "access": "w" + } + } + }, + "config": { + "description": "Config Register", + "addressOffset": "0x000C", + "fields": { + "dataLen": { + "description": "Data length", + "bitOffset": "0", + "bitWidth": "3", + "access": "w" + }, + "parity": { + "description": "Parity bit number; 0: None; 1: Even; 2: Odd", + "bitOffset": "8", + "bitWidth": "2", + "access": "w" + }, + "stop": { + "description": "Stop bit number", + "bitOffset": "16", + "bitWidth": "1", + "access": "w" + } + } + }, + "errorBreak": { + "description": "Error Break Register", + "addressOffset": "0x0010", + "fields": { + "readError": { + "description": "Read error. Write 1 to reset error", + "bitOffset": "0", + "bitWidth": "1" + }, + "readOverflow": { + "description": "Read overflow error. Write 1 to reset error", + "bitOffset": "1", + "bitWidth": "1" + }, + "readBreak": { + "description": "Read break occur", + "bitOffset": "8", + "bitWidth": "1", + "access": "r" + }, + "breakDetect": { + "description": "Break detected during read operation. Write 1 to reset error", + "bitOffset": "9", + "bitWidth": "1" + }, + "enableBreak": { + "description": "Enable break", + "bitOffset": "10", + "bitWidth": "1", + "access": "w" + }, + "disableBreak": { + "description": "Disable break", + "bitOffset": "11", + "bitWidth": "1", + "access": "w" + } + } + } + }, + "interrupts": { + "uart0": { + "description": "UART0 Interrupt", + "value": "SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT" + } + } + }, + "spi0": { + "description": "Serial Peripheral Interface (SPI) 0 Peripheral", + "baseAddress": "0xe8030000", + "size": "0x1000", + "resetMask": "none", + "groupName": "spi", + "registers": { + "cmd": { + "description": "Command Register", + "addressOffset": "0x0000", + "fields": { + "data": { + "description": "FIFO data value transmit/receive", + "bitOffset": "0", + "bitWidth": "8" + }, + "wr": { + "description": "Write trigger", + "bitOffset": "8", + "bitWidth": "1", + "access": "w" + }, + "rd": { + "description": "Read trigger", + "bitOffset": "9", + "bitWidth": "1", + "access": "w" + }, + "ss": { + "description": "SPI chip select. Configure up to 8 chip select ID numbers", + "bitOffset": "11", + "bitWidth": "3" + } + } + }, + "rsp": { + "description": "Response Register", + "addressOffset": "0x0004", + "fields": { + "fifoAvailability": { + "description": "FIFO availability", + "bitOffset": "0", + "bitWidth": "9", + "access": "r" + }, + "fifoOccupancy": { + "description": "FIFO Occupancy", + "bitOffset": "16", + "bitWidth": "9", + "access": "r" + } + } + }, + "config": { + "description": "Config Register", + "addressOffset": "0x0008", + "fields": { + "cpol": { + "description": "Clock polarity setting", + "bitOffset": "0", + "bitWidth": "1", + "access": "w" + }, + "cpha": { + "description": "Clock phase setting", + "bitOffset": "1", + "bitWidth": "1", + "access": "w" + }, + "mode": { + "description": "SPI Mode selection. 0: Full duplex dual line. 1: Half-duplex dual line. 2: Half-duplex quad line", + "bitOffset": "4", + "bitWidth": "2", + "access": "w" + } + } + }, + "interrupt": { + "description": "Interrupt Register", + "addressOffset": "0x000C", + "fields": { + "cmdIntEn": { + "description": "Command FIFO empty interrupt enable", + "bitOffset": "0", + "bitWidth": "1" + }, + "rspIntEn": { + "description": "Read FIFO not empty interrupt enable", + "bitOffset": "1", + "bitWidth": "1" + }, + "cmdInt": { + "description": "Command FIFO empty interrupt pending", + "bitOffset": "8", + "bitWidth": "1" + }, + "rspInt": { + "description": "Read FIFO not empty interrupt pending", + "bitOffset": "9", + "bitWidth": "1" + }, + "cmdValid": { + "description": "Command FIFO is not empty", + "bitOffset": "16", + "bitWidth": "1", + "access": "r" + } + } + }, + "clkDiv": { + "description": "Clock Divider Register", + "addressOffset": "0x0020", + "fields": { + "clkDiv": { + "description": "Clock divider, SPI frequency = FCLK / ((clockDivider+1)*2", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "ssSetup": { + "description": "ssSetup Register", + "addressOffset": "0x0024", + "fields": { + "ssSetup": { + "description": "Time between the chip select enable and the next byte", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "ssHold": { + "description": "ssHold Register", + "addressOffset": "0x0028", + "fields": { + "ssHold": { + "description": "Time between the last byte transmission and the chip select disable", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "ssDisable": { + "description": "ssDisable Register", + "addressOffset": "0x002C", + "fields": { + "ssDisable": { + "description": "Time between the chip select disable and the chip select enable", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "ssActiveHigh": { + "description": "ssActiveHigh Register", + "addressOffset": "0x0030", + "fields": { + "ssActiveHigh": { + "description": "These bits correspond to the hardware SPI chip select. 0: Chip select is active low. 1: Chip select is active high.", + "bitOffset": "0", + "bitWidth": "8", + "access": "w" + } + } + }, + "cmd32_0": { + "description": "cmd32_0 Register. Large data transmit", + "addressOffset": "0x0050", + "fields": { + "data": { + "description": "Trigger to transmit data. The data width is configurable up to 16 bits.", + "bitOffset": "0", + "bitWidth": "16", + "access": "w" + } + } + }, + "cmd32_1": { + "description": "cmd32_1 Register. Large data transmit", + "addressOffset": "0x0054", + "fields": { + "data": { + "description": "Trigger to transmit data. The data width is configurable up to 16 bits.", + "bitOffset": "0", + "bitWidth": "16", + "access": "w" + } + } + }, + "rsp32": { + "description": "rsp32 Register. Large data transmit", + "addressOffset": "0x0058", + "fields": { + "data": { + "description": "Trigger to receive data. The data width is configurable up to 16 bits.", + "bitOffset": "0", + "bitWidth": "16", + "access": "w" + } + } + } + }, + "interrupts": { + "spi0": { + "description": "SPI0 Interrupt", + "value": "SYSTEM_PLIC_USER_INTERRUPT_B_INTERRUPT" + } + } + }, + "i2c0": { + "description": "Inter-Integrated Circuit (I2C) 0 Peripheral", + "baseAddress": "0xe8020000", + "size": "0x100", + "resetMask": "none", + "groupName": "i2c", + "registers": { + "txData": { + "description": "Transmit Data Register", + "addressOffset": "0x0000", + "fields": { + "value": { + "description": "Transmit data value", + "bitOffset": "0", + "bitWidth": "8", + "access": "w" + }, + "valid": { + "description": "Transmit data valid bit", + "bitOffset": "8", + "bitWidth": "1" + }, + "enable": { + "description": "Transmit data enable", + "bitOffset": "9", + "bitWidth": "1" + }, + "repeat": { + "description": "Transmit data repeat bit", + "bitOffset": "10", + "bitWidth": "1", + "access": "w" + }, + "disableDataConflict": { + "description": "Disable transmit data conflict", + "bitOffset": "11", + "bitWidth": "1", + "access": "w" + } + } + }, + "txAck": { + "description": "Transmit Acknowledge Register", + "addressOffset": "0x0004", + "fields": { + "value": { + "description": "Transmit acknowledge bit", + "bitOffset": "0", + "bitWidth": "1", + "access": "w" + }, + "valid": { + "description": "Transmit acknowledge valid bit", + "bitOffset": "8", + "bitWidth": "1" + }, + "enable": { + "description": "Transmit acknowledge enable", + "bitOffset": "9", + "bitWidth": "1" + }, + "repeat": { + "description": "Transmit acknowledge repeat bit", + "bitOffset": "10", + "bitWidth": "1", + "access": "w" + }, + "disableDataConflict": { + "description": "Disable acknowledge data conflict", + "bitOffset": "11", + "bitWidth": "1", + "access": "w" + } + } + }, + "rxData": { + "description": "Receive Data Register", + "addressOffset": "0x0008", + "fields": { + "value": { + "description": "Received data", + "bitOffset": "0", + "bitWidth": "8", + "access": "r" + }, + "valid": { + "description": "Receive data valid", + "bitOffset": "8", + "bitWidth": "1" + }, + "listen": { + "description": "Start listen data", + "bitOffset": "9", + "bitWidth": "1" + } + } + }, + "rxAck": { + "description": "Receive Acknowledge Register", + "addressOffset": "0x000C", + "fields": { + "value": { + "description": "Received acknowledge bit", + "bitOffset": "0", + "bitWidth": "1", + "access": "r" + }, + "valid": { + "description": "Receive acknowledge valid", + "bitOffset": "8", + "bitWidth": "1" + }, + "listen": { + "description": "Start listen acknowledge", + "bitOffset": "9", + "bitWidth": "1" + } + } + }, + "interrupt": { + "description": "Interrupt Register", + "addressOffset": "0x0020", + "fields": { + "rxDataEnable": { + "description": "Receive data interrupt enable", + "bitOffset": "0", + "bitWidth": "1" + }, + "rxAckEnable": { + "description": "Receive acknowledge interrupt enable", + "bitOffset": "1", + "bitWidth": "1" + }, + "txDataEnable": { + "description": "Transmit data interrupt enable", + "bitOffset": "2", + "bitWidth": "1" + }, + "txAckEnable": { + "description": "Transmit acknowledge interrupt enable", + "bitOffset": "3", + "bitWidth": "1" + }, + "startEnable": { + "description": "Start interrupt enable", + "bitOffset": "4", + "bitWidth": "1" + }, + "restartEnable": { + "description": "Restart interrupt enable", + "bitOffset": "5", + "bitWidth": "1" + }, + "endEnable": { + "description": "End interrupt enable", + "bitOffset": "6", + "bitWidth": "1" + }, + "dropEnable": { + "description": "Drop interrupt enable", + "bitOffset": "7", + "bitWidth": "1" + }, + "clockGenExitEnable": { + "description": "Master clock generation exit interrupt enable", + "bitOffset": "15", + "bitWidth": "1" + }, + "clockGenEnterEnable": { + "description": "Master clock generation enter interrupt enable", + "bitOffset": "16", + "bitWidth": "1" + }, + "filterEnable": { + "description": "Slave address filtering hit interrupt enable", + "bitOffset": "17", + "bitWidth": "1" + } + } + }, + "interruptClear": { + "description": "Interrupt Clear Register", + "addressOffset": "0x0024", + "fields": { + "startFlag": { + "description": "Start interrupt flag", + "bitOffset": "4", + "bitWidth": "1" + }, + "restartFlag": { + "description": "Restart interrupt flag", + "bitOffset": "5", + "bitWidth": "1" + }, + "endFlag": { + "description": "End interrupt flag", + "bitOffset": "6", + "bitWidth": "1" + }, + "dropFlag": { + "description": "Drop interrupt flag", + "bitOffset": "7", + "bitWidth": "1" + }, + "clockGenExitFlag": { + "description": "Master clock generation exit interrupt flag", + "bitOffset": "15", + "bitWidth": "1" + }, + "clockGenEnterFlag": { + "description": "Master clock generation enter interrupt flag", + "bitOffset": "16", + "bitWidth": "1" + }, + "filterFlag": { + "description": "Slave address filtering hit interrupt", + "bitOffset": "17", + "bitWidth": "1", + "access": "w" + } + } + }, + "sampClkDiv": { + "description": "Sampling Clock Divider Register", + "addressOffset": "0x0028", + "fields": { + "samplingClockDividerWidth": { + "description": "Clock divider width. Controls the rate at which the I2C controller reads SCL and SDA", + "bitOffset": "0", + "bitWidth": "10", + "access": "w" + } + } + }, + "timeout": { + "description": "Timeout Register", + "addressOffset": "0x002C", + "fields": { + "value": { + "description": "Inactive timeout setting", + "bitOffset": "0", + "bitWidth": "20", + "access": "w" + } + } + }, + "tsuData": { + "description": "Data Setup Time Register", + "addressOffset": "0x0030", + "fields": { + "value": { + "description": "Data setup time", + "bitOffset": "0", + "bitWidth": "6", + "access": "w" + } + } + }, + "masterStatus": { + "description": "Master Status Register", + "addressOffset": "0x0040", + "fields": { + "isBusy": { + "description": "Master busy", + "bitOffset": "0", + "bitWidth": "1", + "access": "r" + }, + "start": { + "description": "Master start", + "bitOffset": "4", + "bitWidth": "1" + }, + "stop": { + "description": "Master stop", + "bitOffset": "5", + "bitWidth": "1" + }, + "drop": { + "description": "Master drop", + "bitOffset": "6", + "bitWidth": "1" + }, + "recover": { + "description": "Order a recover sequence", + "bitOffset": "7", + "bitWidth": "1" + }, + "startDropped": { + "description": "Indicates timeout occurred during start sequence. Clear on set", + "bitOffset": "9", + "bitWidth": "1" + }, + "stopDropped": { + "description": "Indicates timeout occurred during stop sequence. Clear on set", + "bitOffset": "10", + "bitWidth": "1" + }, + "recoverDropped": { + "description": "Indicates timeout occurred during recover sequence. Clear on set", + "bitOffset": "11", + "bitWidth": "1" + } + } + }, + "slaveStatus": { + "description": "Slave Status Register", + "addressOffset": "0x0044", + "fields": { + "inFrame": { + "description": "Indicates the transaction is already started.", + "bitOffset": "0", + "bitWidth": "1", + "access": "r" + }, + "sda": { + "description": "Read the current state of SDA line. 1: High state; 0: Low state", + "bitOffset": "1", + "bitWidth": "1", + "access": "r" + }, + "scl": { + "description": "Read the current state of SCL line. 1: High state; 0: Low state", + "bitOffset": "2", + "bitWidth": "1", + "access": "r" + } + } + }, + "slaveOverride": { + "description": "Slave Override Register", + "addressOffset": "0x0048", + "fields": { + "sda": { + "description": "Force SDA line pull low when cleared", + "bitOffset": "1", + "bitWidth": "1" + }, + "scl": { + "description": "Force SCL line pull low when cleared", + "bitOffset": "2", + "bitWidth": "1" + } + } + }, + "tLow": { + "description": "tLow Register", + "addressOffset": "0x0050", + "fields": { + "value": { + "description": "SCL low period", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "tHigh": { + "description": "tHigh Register", + "addressOffset": "0x0054", + "fields": { + "value": { + "description": "SCL high period", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "tBuf": { + "description": "tBuf Register", + "addressOffset": "0x0054", + "fields": { + "value": { + "description": "Start and stop bus free time", + "bitOffset": "0", + "bitWidth": "12", + "access": "w" + } + } + }, + "filterStatus": { + "description": "Filtering Status Register", + "addressOffset": "0x0080", + "fields": { + "hit_0": { + "description": "Filtering hit bit 0", + "bitOffset": "0", + "bitWidth": "1", + "access": "r" + }, + "hit_1": { + "description": "Filtering hit bit 1", + "bitOffset": "1", + "bitWidth": "1", + "access": "r" + } + } + }, + "hitContext": { + "description": "Hit Context Register", + "addressOffset": "0x0084", + "fields": { + "rw": { + "description": "Hit context read", + "bitOffset": "0", + "bitWidth": "1", + "access": "r" + } + } + }, + "filterConfig0": { + "description": "Filtering Configuration 0 Register", + "addressOffset": "0x0088", + "fields": { + "value": { + "description": "Set the filter 0 value", + "bitOffset": "0", + "bitWidth": "10", + "access": "w" + }, + "10BitAddr": { + "description": "Set the filter address to 10 bits wide", + "bitOffset": "14", + "bitWidth": "1", + "access": "w" + }, + "enable": { + "description": "Enable filter address 0", + "bitOffset": "15", + "bitWidth": "1", + "access": "w" + } + } + }, + "filterConfig1": { + "description": "Filtering Configuration 1 Register", + "addressOffset": "0x008C", + "fields": { + "value": { + "description": "Set the filter 1 value", + "bitOffset": "0", + "bitWidth": "10", + "access": "w" + }, + "10BitAddr": { + "description": "Set the filter address to 10 bits wide", + "bitOffset": "14", + "bitWidth": "1", + "access": "w" + }, + "enable": { + "description": "Enable filter address 1", + "bitOffset": "15", + "bitWidth": "1", + "access": "w" + } + } + } + }, + "interrupts": { + "i2c0": { + "description": "I2C0 Interrupt", + "value": "SYSTEM_PLIC_USER_INTERRUPT_C_INTERRUPT" + } + } + }, + "timer0": { + "description": "User Timer 0 Peripheral", + "baseAddress": "0xF8015000", + "size": "0x1000", + "registers": { + "Prescaler": { + "description": "Prescaler Register", + "addressOffset": "0x0000", + "fields": { + "prescalerValue": { + "description": "The clock divider ratio", + "bitOffset": "0", + "bitWidth": "16" + } + } + }, + "timerConfig": { + "description": "Prescaler Register", + "addressOffset": "0x0040", + "fields": { + "withPrescaler": { + "description": "Run timer with prescaler", + "bitOffset": "0", + "bitWidth": "1" + }, + "withoutPrescaler": { + "description": "Run timer without prescaler", + "bitOffset": "1", + "bitWidth": "1" + }, + "selfRestart": { + "description": "self-restart when reach timer limit", + "bitOffset": "16", + "bitWidth": "1" + } + } + }, + "timerLimit": { + "description": "Timer Limit Register", + "addressOffset": "0x0044", + "fields": { + "limitValue": { + "description": "Value for the timer to an generate output pulse", + "bitOffset": "0", + "bitWidth": "32" + } + } + }, + "timerValue": { + "description": "Timer Value Register", + "addressOffset": "0x0048", + "fields": { + "timerValue": { + "description": "Value of the increment counter when it detects a timer tick", + "bitOffset": "0", + "bitWidth": "32" + } + } + } + }, + "interrupts": { + "userTimer0": { + "description": "User Timer Interrupt 0", + "value": "22" + } + } + }, + "timer1": { + "description": "User Timer 1 Peripheral", + "baseAddress": "0xF8016000", + "size": "0x1000", + "registers": { + "Prescaler": { + "description": "Prescaler Register", + "addressOffset": "0x0000", + "fields": { + "prescalerValue": { + "description": "The clock divider ratio", + "bitOffset": "0", + "bitWidth": "16" + } + } + }, + "timerConfig": { + "description": "Prescaler Register", + "addressOffset": "0x0040", + "fields": { + "withPrescaler": { + "description": "Run timer with prescaler", + "bitOffset": "0", + "bitWidth": "1" + }, + "withoutPrescaler": { + "description": "Run timer without prescaler", + "bitOffset": "1", + "bitWidth": "1" + }, + "selfRestart": { + "description": "self-restart when reach timer limit", + "bitOffset": "16", + "bitWidth": "1" + } + } + }, + "timerLimit": { + "description": "Timer Limit Register", + "addressOffset": "0x0044", + "fields": { + "limitValue": { + "description": "Value for the timer to an generate output pulse", + "bitOffset": "0", + "bitWidth": "32" + } + } + }, + "timerValue": { + "description": "Timer Value Register", + "addressOffset": "0x0048", + "fields": { + "timerValue": { + "description": "Value of the increment counter when it detects a timer tick", + "bitOffset": "0", + "bitWidth": "32" + } + } + } + }, + "interrupts": { + "userTimer1": { + "description": "User Timer Interrupt 1", + "value": "23" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/xinclude.dtd b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/xinclude.dtd new file mode 100644 index 0000000..a4b6978 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/bsp/efinix/EfxSapphireSoc/openocd/xinclude.dtd @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/bsp.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/bsp.mk new file mode 100644 index 0000000..17724d4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/bsp.mk @@ -0,0 +1,9 @@ +BSP_PATH ?= ${STANDALONE}/../../bsp/${BSP} +LWIP_PATH ?= ${BSP_PATH}/app/lwip +FATFS_PATH ?= ${BSP_PATH}/app/fatfs +CFLAGS += -I${BSP_PATH}/include +CFLAGS += -I${BSP_PATH}/app + +include ${BSP_PATH}/include/soc.mk + +LDSCRIPT ?= ${BSP_PATH}/linker/freertos.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/riscv64-unknown-elf.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/riscv64-unknown-elf.mk new file mode 100644 index 0000000..745c81b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/riscv64-unknown-elf.mk @@ -0,0 +1,57 @@ +RISCV_BIN ?= riscv-none-embed- +RISCV_CC=${RISCV_BIN}gcc +RISCV_OBJCOPY=${RISCV_BIN}objcopy +RISCV_OBJDUMP=${RISCV_BIN}objdump + +MARCH := rv32i +MABI := ilp32 +BENCH ?= no + +ifeq ($(RV_M),yes) + MARCH := $(MARCH)m +endif + +ifeq ($(RV_A),yes) + MARCH := $(MARCH)a +else + ifeq ($(RV_C),yes) + MARCH := $(MARCH)a + endif +endif + +ifeq ($(RV_F),yes) + MARCH := $(MARCH)f + + ifeq ($(RV_D),no) + MABI := $(MABI)f + endif +endif + +ifeq ($(RV_D),yes) + MARCH := $(MARCH)d + MABI := $(MABI)d +endif + +ifeq ($(RV_C),yes) + MARCH := $(MARCH)c +endif + +ifeq ($(DEBUG),yes) + ifneq ($(DEBUG_OG),yes) + CFLAGS += -g3 -O0 + else + CFLAGS += -g3 -Og + endif +endif + +ifneq ($(DEBUG),yes) + ifneq ($(BENCH),yes) + CFLAGS += -Os + else + CFLAGS += -O3 + endif +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DUSE_GP +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpFunc.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpFunc.S new file mode 100644 index 0000000..728fedf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpFunc.S @@ -0,0 +1,39 @@ +// This assembly is used to compile the internal bootloader for multicore +.global smp_unlock +.type smp_unlock,%function +smp_unlock: + sw a0, smp_lottery_target, a1 + fence w, w + li a0, 1 + sw a0, smp_lottery_lock, a1 + ret + +.global smp_tyranny +.global smp_slave + +smp_tyranny: + csrr a0, mhartid + beqz a0, init + +smp_slave: + lw a0, smp_lottery_lock + beqz a0, smp_slave + + fence r, r + //li a1, -1 + //amoadd.w x0, a1,(a0) + + .word(0x100F) //i$ flush + lw a5, smp_lottery_target + li a0, 0 + li a1, 0 + li a2, 0 + jr a5 + +.global smp_lottery_target +.global smp_lottery_lock + +.bss +.align 2 + smp_lottery_target: .word 0 + smp_lottery_lock: .word 0 diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpInit.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpInit.S new file mode 100644 index 0000000..c63268a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/smpInit.S @@ -0,0 +1,21 @@ +#include "userDef.h" + +.global smpInit + +smpInit: + //Initialise the stack of the given hart + la sp, hartStack + csrr a0, mhartid + li a1, STACK_PER_HART + addi a0, a0, 1 + mul a0, a0, a1 + add sp, sp, a0 + call mainSmp + +smpDone: + j smpDone + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/standalone.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/standalone.mk new file mode 100644 index 0000000..c25b4ec --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/standalone.mk @@ -0,0 +1,66 @@ +OBJDIR ?= build + +LDFLAGS += -lc + +SPINAL_SIM ?= no +ifeq ($(SPINAL_SIM),yes) + PROJ_NAME := $(PROJ_NAME)_spinal_sim + CFLAGS += -DSPINAL_SIM +endif +CFLAGS += ${CFLAGS_ARGS} +CFLAGS += -I${STANDALONE}/include +CFLAGS += -I${STANDALONE}/driver +CFLAGS += -I${STANDALONE}/../standalone/driver +LDFLAGS += -L${STANDALONE}/common +LDFLAGS += -specs=nosys.specs -lgcc -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage -lm + +DOT:= . +COLON:=: +SEPARATOR:=o: +SEPARATOR_REPLACE:=o + +OBJS := $(SRCS) +OBJS := $(notdir $(OBJS)) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:.s=.o) +OBJS := $(addprefix $(OBJDIR)/obj_files/,$(OBJS)) + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + @echo "LD $(PROJ_NAME)" + @$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + +%.hex: %.elf + @$(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + @$(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + @$(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + @$(RISCV_OBJDUMP) -S -d $^ > $@ + +define LIST_RULE +$(1) + @mkdir -p $(dir $(subst $(SEPARATOR),$(SEPARATOR_REPLACE),$(1))) + @echo "CC $(word 2,$(subst $(SEPARATOR),$(SEPARATOR_REPLACE),$(1)))" + @$(RISCV_CC) -c $(CFLAGS) $(INC) -o $(subst $(SEPARATOR),$(SEPARATOR_REPLACE),$(1)) + +endef + +CAT:= $(addsuffix $(COLON), $(OBJS)) +CAT:= $(join $(CAT), $(SRCS)) +$(foreach i,$(CAT),$(eval $(call LIST_RULE,$(i)))) + +$(OBJDIR): + @mkdir -p $@ + +clean: + @rm -rf $(OBJDIR) + +.SECONDARY: $(OBJS) diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start.S new file mode 100644 index 0000000..49e434b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start.S @@ -0,0 +1,95 @@ + .section .init + .globl _start + .type _start,@function + + +_start: +#ifdef USE_GP +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif + +#ifdef SMP +.global smp_lottery_target +.global smp_lottery_lock +.global smp_slave + + + sw x0, smp_lottery_lock, a1 + +smp_tyranny: + csrr a0, mhartid + beqz a0, init + +smp_slave: + lw a0, smp_lottery_lock + beqz a0, smp_slave + + fence r, r + //li a1, -1 + //amoadd.w x0, a1,(a0) + + .word(0x100F) //i$ flush + lw a5, smp_lottery_target + li a0, 0 + li a1, 0 + li a2, 0 + jr a5 + +.global smp_unlock +.type smp_unlock,%function +smp_unlock: + sw a0, smp_lottery_target, a1 + fence w, w + li a0, 1 + sw a0, smp_lottery_lock, a1 + ret +#endif + +init: + la sp, _sp + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, _end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + +#ifndef NO_LIBC_INIT_ARRAY + call __libc_init_array +#endif + + call main +mainDone: + j mainDone + + + .globl _init +_init: + ret + +#ifdef SMP +.bss +.align 2 + smp_lottery_target: .word 0 + smp_lottery_lock: .word 0 +#endif \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start_int.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start_int.S new file mode 100644 index 0000000..edf397c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/start_int.S @@ -0,0 +1,65 @@ +// This assembly is required if you were to compile internal multicore bootloader + + .section .init + .globl _start + .type _start,@function + + +_start: +#ifdef USE_GP +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif + +#ifdef SMP + + sw x0, smp_lottery_lock, a1 + +call smp_tyranny +call smp_slave +call smp_unlock + +#endif + +.global init + +init: + la sp, _sp + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, _end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + +#ifndef NO_LIBC_INIT_ARRAY + call __libc_init_array +#endif + + call main +mainDone: + j mainDone + + + .globl _init +_init: + ret diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/trap.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/trap.S new file mode 100644 index 0000000..8149173 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/common/trap.S @@ -0,0 +1,39 @@ +.global trap_entry +.align(2) //mtvec require 32 bits allignement +trap_entry: + addi sp,sp, -16*4 + sw x1, 0*4(sp) + sw x5, 1*4(sp) + sw x6, 2*4(sp) + sw x7, 3*4(sp) + sw x10, 4*4(sp) + sw x11, 5*4(sp) + sw x12, 6*4(sp) + sw x13, 7*4(sp) + sw x14, 8*4(sp) + sw x15, 9*4(sp) + sw x16, 10*4(sp) + sw x17, 11*4(sp) + sw x28, 12*4(sp) + sw x29, 13*4(sp) + sw x30, 14*4(sp) + sw x31, 15*4(sp) + call trap + lw x1 , 0*4(sp) + lw x5, 1*4(sp) + lw x6, 2*4(sp) + lw x7, 3*4(sp) + lw x10, 4*4(sp) + lw x11, 5*4(sp) + lw x12, 6*4(sp) + lw x13, 7*4(sp) + lw x14, 8*4(sp) + lw x15, 9*4(sp) + lw x16, 10*4(sp) + lw x17, 11*4(sp) + lw x28, 12*4(sp) + lw x29, 13*4(sp) + lw x30, 14*4(sp) + lw x31, 15*4(sp) + addi sp,sp, 16*4 + mret diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/freertos_risc_v_chip_specific_extensions.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/freertos_risc_v_chip_specific_extensions.h new file mode 100644 index 0000000..6f684c3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/freertos_risc_v_chip_specific_extensions.h @@ -0,0 +1,65 @@ +//*------------------------------------------------------------------------------------------ +// FreeRTOS Kernel V10.2.1 +// Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// http://www.FreeRTOS.org +// http://aws.amazon.com/freertos +// +// 1 tab == 4 spaces! +// +// The FreeRTOS kernel's RISC-V port is split between the the code that is +// common across all currently supported RISC-V chips (implementations of the +// RISC-V ISA), and code that tailors the port to a specific RISC-V chip: +// +// + FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S contains the code that +// is common to all currently supported RISC-V chips. There is only one +// portASM.S file because the same file is built for all RISC-V target chips. +// +// + Header files called freertos_risc_v_chip_specific_extensions.h contain the +// code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V +// chip. There are multiple freertos_risc_v_chip_specific_extensions.h files +// as there are multiple RISC-V chip implementations. +// +// !!!NOTE!!! +// TAKE CARE TO INCLUDE THE CORRECT freertos_risc_v_chip_specific_extensions.h +// HEADER FILE FOR THE CHIP IN USE. This is done using the assembler's (not the +// compiler's!) include path. For example, if the chip in use includes a core +// local interrupter (CLINT) and does not include any chip specific register +// extensions then add the path below to the assembler's include path: +// FreeRTOS\Source\portable\GCC\RISC-V-RV32\chip_specific_extensions\RV32I_CLINT_no_extensions +//*------------------------------------------------------------------------------------------ +#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__ +#define __FREERTOS_RISC_V_EXTENSIONS_H__ + +#define portasmHAS_MTIME 1 +/* Must be even number on 32-bit cores. */ +#define portasmADDITIONAL_CONTEXT_SIZE 0 + + + .macro portasmSAVE_ADDITIONAL_REGISTERS + /* No additional registers to save, so this macro does nothing. */ + .endm + + /* Restore the additional registers found on the Pulpino. */ + .macro portasmRESTORE_ADDITIONAL_REGISTERS + /* No additional registers to restore, so this macro does nothing. */ + .endm + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/hal.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/hal.h new file mode 100644 index 0000000..8d55d02 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/driver/hal.h @@ -0,0 +1,46 @@ +//*------------------------------------------------------------------------------------------ +// MIT License +// +// Copyright (c) 2025 SaxonSoc contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//*----------------------------------------------------------------------------------------- +#ifndef HAL_H_ +#define HAL_H_ + +#include "FreeRTOS.h" +#include "task.h" +#include "portmacro.h" +#include "bsp.h" +#include "plic.h" + + + void external_interrupt_handler(void){ + uint32_t claim; + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + // case YOUR_INTERRUPT_ID: + // ... + // break; + } + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); //unmask the claimed interrupt + } + } + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/makefile new file mode 100644 index 0000000..b03969a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/makefile @@ -0,0 +1,29 @@ +PROJ_NAME=freertosDemo + +STANDALONE = .. + +CFLAGS+=-DSMP + +FREERTOS=${FreeRTOS_KERNEL_SRC}/FreeRTOS/Source +FREERTOS_RISCV=${FREERTOS}/portable/GCC/RISC-V + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${FREERTOS}/*.c) \ + ${FREERTOS}/portable/MemMang/heap_4.c \ + ${FREERTOS_RISCV}/port.c \ + ${FREERTOS_RISCV}/portASM.S \ + ${STANDALONE}/common/start.S + +CFLAGS += -Isrc +CFLAGS += -I../driver +CFLAGS += -I${FREERTOS}/include +CFLAGS += -I${FREERTOS_RISCV} +CFLAGS += -DportasmHANDLE_INTERRUPT=external_interrupt_handler + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/freertos.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/FreeRTOSConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/FreeRTOSConfig.h new file mode 100644 index 0000000..6f8ec0e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/FreeRTOSConfig.h @@ -0,0 +1,226 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bsp.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15U * 1024U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Currently the TCP/IP stack is using dynamic allocation, and the MQTT task is + * using static allocation. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* The function that implements FreeRTOS printf style output, and the macro + * that maps the configPRINTF() macros to that function. */ +void vLoggingPrintf( char const * pcFormat, + ... ); + +#define configPRINTF( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT_STRING( X ) bsp_printf X + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace + * macros are defined to gather some UDP stack statistics that can then be viewed + * through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there + * are multiple command interpreters running at once (for example, one on a UART + * and one on TCP/IP). This is done to prevent an output buffer being defined by + * each implementation - which would waste RAM. In this case, there is only one + * command interpreter running, and it has its own local output buffer, so the + * global buffer is just set to be one byte long as it is not used and should not + * take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE ( 0L ) + +/* The address of an echo server that will be used by the two demo echo client + * tasks: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 31 +#define configECHO_SERVER_ADDR3 6 +#define configTCP_ECHO_CLIENT_PORT 7 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x32 + +/* Default IP address configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DHCP is set to + * 0, or ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 192 +#define configGATEWAY_ADDR1 168 +#define configGATEWAY_ADDR2 31 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. Google DNS addresses are 8.8.8.8 and + * 8.8.4.4. Used in ipconfigUSE_DHCP is set to 0, or ipconfigUSE_DHCP is + * set to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 8 +#define configDNS_SERVER_ADDR1 8 +#define configDNS_SERVER_ADDR2 8 +#define configDNS_SERVER_ADDR3 8 + +/* Default netmask configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configPROFILING ( 0 ) + +/* Pseudo random number generator used by some tasks. */ +extern uint32_t ulRand( void ); +#define configRAND32() ulRand() + +/* The platform that FreeRTOS is running on. */ +#define configPLATFORM_NAME "Efinix_FPGA" + +// Freertos specifics +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint32_t ) ( BSP_CLINT_HZ ) ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main.c new file mode 100644 index 0000000..4e4d5cc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main.c @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS V202212.01 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* FreeRTOS kernel includes. */ +#include +#include + +#include "bsp.h" +#include "riscv.h" +#include "hal.h" +#include "gpio.h" + +/****************************************************************************** + * This project provides two demo applications. A simple blinky style project, + * and a more comprehensive test and demo application. The + * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting (defined in this file) is used to + * select between the two. The simply blinky demo is implemented and described + * in main_blinky.c. The more comprehensive test and demo application is + * implemented and described in main_full.c. + * + * This file implements the code that is not demo specific, including the + * hardware setup and standard FreeRTOS hook functions. + * + * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON + * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO + * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT! + * + */ +extern void main_blinky( void ); +/* Prototypes for the standard FreeRTOS callback/hook functions implemented +within this file. See https://www.freertos.org/a00016.html */ + +void vApplicationMallocFailedHook( void ); +void vApplicationIdleHook( void ); +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/* Prepare hardware to run the demo. */ +static void prvSetupHardware( void ); + +/* Send a message to the UART initialised in prvSetupHardware. */ +void vSendString( const char * const pcString ); + +/*-----------------------------------------------------------*/ +int main( void ) +{ + bsp_init(); + prvSetupHardware(); + main_blinky(); +} +/*-----------------------------------------------------------*/ + +static void prvSetupHardware( void ) +{ + extern void freertos_risc_v_trap_handler(); + csr_write(mtvec, freertos_risc_v_trap_handler); + + gpio_setOutputEnable(SYSTEM_GPIO_0_IO_CTRL, 0x0E); + gpio_setOutput(SYSTEM_GPIO_0_IO_CTRL, 0x00000000); + + vSendString( "Hello world, this is FreeRTOS\r\n" ); +} +/*-----------------------------------------------------------*/ + +void vToggleLED( void ) +{ +static uint32_t ulLEDState = 0; + gpio_setOutput(SYSTEM_GPIO_0_IO_CTRL, gpio_getOutput(SYSTEM_GPIO_0_IO_CTRL) ^ 0x0E); +} +/*-----------------------------------------------------------*/ + +void vSendString( const char * const pcString ) +{ + bsp_printf(pcString); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* vApplicationMallocFailedHook() will only be called if + configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook + function that will get called if a call to pvPortMalloc() fails. + pvPortMalloc() is called internally by the kernel whenever a task, queue, + timer or semaphore is created. It is also called by various parts of the + demo application. If heap_1.c or heap_2.c are used, then the size of the + heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in + FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used + to query the size of free heap space that remains (although it does not + provide information on how the remaining heap might be fragmented). */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ + /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set + to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle + task. It is essential that code added to this hook function never attempts + to block in any way (for example, call xQueueReceive() with a block time + specified, or call vTaskDelay()). If the application makes use of the + vTaskDelete() API function (as this demo application does) then it is also + important that vApplicationIdleHook() is permitted to return to its calling + function, because it is the responsibility of the idle task to clean up + memory allocated by the kernel to any task that has since been deleted. */ +} +/*-----------------------------------------------------------*/ + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} + +/*-----------------------------------------------------------*/ + +void vApplicationTickHook( void ) +{ + extern void vFullDemoTickHook( void ); +} + +/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ +static StaticTask_t xIdleTaskTCBBuffer; +static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; + *ppxIdleTaskStackBuffer = &xIdleStack[0]; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + /* place for user code */ +} +/* USER CODE END GET_IDLE_TASK_MEMORY */ + +/* USER CODE BEGIN GET_TIMER_TASK_MEMORY */ +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} +/* USER CODE END GET_TIMER_TASK_MEMORY */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main_blinky.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main_blinky.c new file mode 100644 index 0000000..05f4242 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosDemo/src/main_blinky.c @@ -0,0 +1,175 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS V202212.01 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* Standard includes. */ +#include +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* Priorities used by the tasks. */ +#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) + +/* The rate at which data is sent to the queue. The 200ms value is converted +to ticks using the pdMS_TO_TICKS() macro. */ +#ifdef SPINAL_SIM +#define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 4 ) +#else +#define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 500 ) +#endif +/* The maximum number items the queue can hold. The priority of the receiving +task is above the priority of the sending task, so the receiving task will +preempt the sending task and remove the queue items each time the sending task +writes to the queue. Therefore the queue will never have more than one item in +it at any time, and even with a queue length of 1, the sending task will never +find the queue full. */ +#define mainQUEUE_LENGTH ( 1 ) + +/*-----------------------------------------------------------*/ + +/* + * Called by main when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1 in + * main.c. + */ +void main_blinky( void ); + +/* + * The tasks as described in the comments at the top of this file. + */ +static void prvQueueReceiveTask( void *pvParameters ); +static void prvQueueSendTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* The queue used by both tasks. */ +static QueueHandle_t xQueue = NULL; + +/*-----------------------------------------------------------*/ + +void main_blinky( void ) +{ + /* Create the queue. */ + xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) ); + + if( xQueue != NULL ) + { + /* Start the two tasks as described in the comments at the top of this + file. */ + xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */ + "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE * 2U, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */ + NULL ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE * 2U, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL ); + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); + } + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the Idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details on the FreeRTOS heap + http://www.freertos.org/a00111.html. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void prvQueueSendTask( void *pvParameters ) +{ +TickType_t xNextWakeTime; +const unsigned long ulValueToSend = 100UL; +BaseType_t xReturned; + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + /* Initialise xNextWakeTime - this only needs to be done once. */ + xNextWakeTime = xTaskGetTickCount(); + + for( ;; ) + { + /* Place this task in the blocked state until it is time to run again. */ + vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS ); + + /* Send to the queue - causing the queue receive task to unblock and + toggle the LED. 0 is used as the block time so the sending operation + will not block - it shouldn't need to block as the queue should always + be empty at this point in the code. */ + xReturned = xQueueSend( xQueue, &ulValueToSend, 0U ); + configASSERT( xReturned == pdPASS ); + } +} +/*-----------------------------------------------------------*/ + +static void prvQueueReceiveTask( void *pvParameters ) +{ +unsigned long ulReceivedValue; +const unsigned long ulExpectedValue = 100UL; +const char * const pcPassMessage = "Blink\r\n"; +const char * const pcFailMessage = "Unexpected value received\r\n"; +extern void vSendString( const char * const pcString ); +extern void vToggleLED( void ); + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Wait until something arrives in the queue - this task will block + indefinitely provided INCLUDE_vTaskSuspend is set to 1 in + FreeRTOSConfig.h. */ + xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY ); + + /* To get here something must have been received from the queue, but + is it the expected value? If it is, toggle the LED. */ + if( ulReceivedValue == ulExpectedValue ) + { + vSendString( pcPassMessage ); + vToggleLED(); + ulReceivedValue = 0U; + } + else + { + vSendString( pcFailMessage ); + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/makefile new file mode 100644 index 0000000..0061be8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/makefile @@ -0,0 +1,34 @@ +PROJ_NAME=freertosEchoServerDemo + +STANDALONE = .. + +CFLAGS+=-DSMP + +FREERTOS=${FreeRTOS_KERNEL_SRC}/FreeRTOS/${FreeRTOS_KERNEL_SRC_DIR} +FREERTOS_RISCV=${FREERTOS}/portable/GCC/RISC-V +FREERTOS_TCP=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/source + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${FREERTOS}/*.c) \ + $(wildcard ${FREERTOS_TCP}/*.c) \ + ${FREERTOS}/portable/MemMang/heap_4.c \ + ${FREERTOS_TCP}/portable/BufferManagement/BufferAllocation_2.c \ + ${FREERTOS_RISCV}/port.c \ + ${FREERTOS_RISCV}/portASM.S \ + ${STANDALONE}/common/start.S + +CFLAGS += -Isrc +CFLAGS += -I../driver +CFLAGS += -I${FREERTOS}/include +CFLAGS += -I${FREERTOS_TCP}/include +CFLAGS += -I${FREERTOS_TCP}/portable/Compiler/GCC +CFLAGS += -I${FREERTOS_RISCV} +CFLAGS += -DportasmHANDLE_INTERRUPT=freertos_risc_v_application_interrupt_handler + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/freertos.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSConfig.h new file mode 100644 index 0000000..6f8ec0e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSConfig.h @@ -0,0 +1,226 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bsp.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15U * 1024U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Currently the TCP/IP stack is using dynamic allocation, and the MQTT task is + * using static allocation. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* The function that implements FreeRTOS printf style output, and the macro + * that maps the configPRINTF() macros to that function. */ +void vLoggingPrintf( char const * pcFormat, + ... ); + +#define configPRINTF( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT_STRING( X ) bsp_printf X + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace + * macros are defined to gather some UDP stack statistics that can then be viewed + * through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there + * are multiple command interpreters running at once (for example, one on a UART + * and one on TCP/IP). This is done to prevent an output buffer being defined by + * each implementation - which would waste RAM. In this case, there is only one + * command interpreter running, and it has its own local output buffer, so the + * global buffer is just set to be one byte long as it is not used and should not + * take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE ( 0L ) + +/* The address of an echo server that will be used by the two demo echo client + * tasks: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 31 +#define configECHO_SERVER_ADDR3 6 +#define configTCP_ECHO_CLIENT_PORT 7 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x32 + +/* Default IP address configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DHCP is set to + * 0, or ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 192 +#define configGATEWAY_ADDR1 168 +#define configGATEWAY_ADDR2 31 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. Google DNS addresses are 8.8.8.8 and + * 8.8.4.4. Used in ipconfigUSE_DHCP is set to 0, or ipconfigUSE_DHCP is + * set to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 8 +#define configDNS_SERVER_ADDR1 8 +#define configDNS_SERVER_ADDR2 8 +#define configDNS_SERVER_ADDR3 8 + +/* Default netmask configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configPROFILING ( 0 ) + +/* Pseudo random number generator used by some tasks. */ +extern uint32_t ulRand( void ); +#define configRAND32() ulRand() + +/* The platform that FreeRTOS is running on. */ +#define configPLATFORM_NAME "Efinix_FPGA" + +// Freertos specifics +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint32_t ) ( BSP_CLINT_HZ ) ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSIPConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSIPConfig.h new file mode 100644 index 0000000..3db5b66 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/FreeRTOSIPConfig.h @@ -0,0 +1,334 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/***************************************************************************** +* +* See the following URL for configuration information. +* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html +* +*****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +#define ipconfigUSE_IPv4 ( 1 ) + +#define ipconfigUSE_IPv6 ( 0 ) + +#define ipconfigUSE_DHCPv6 0 +#define ipconfigIPv4_BACKWARD_COMPATIBLE 1 +#define ipconfigUSE_ARP_REVERSED_LOOKUP 1 +#define ipconfigUSE_ARP_REMOVE_ENTRY 1 +#define ipconfigARP_STORES_REMOTE_ADDRESSES 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 +#define ipconfigFORCE_IP_DONT_FRAGMENT 1 +#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS 1 +#define ipconfigDHCP_FALL_BACK_AUTO_IP 1 +#define ipconfigARP_USE_CLASH_DETECTION 1 +#define ipconfigUSE_LLMNR 1 +#define ipconfigUSE_NBNS 1 +#define ipconfigUSE_MDNS 1 +#define ipconfigSUPPORT_OUTGOING_PINGS 1 +#define ipconfigETHERNET_DRIVER_FILTERS_PACKETS 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1 +#define ipconfigSOCKET_HAS_USER_SEMAPHORE 1 +#define ipconfigSELECT_USES_NOTIFY 1 +#define ipconfigSUPPORT_SIGNALS 1 +#define ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES 1 +#define ipconfigDNS_USE_CALLBACKS 1 +#define ipconfigIGNORE_UNKNOWN_PACKETS 1 +#define ipconfigCHECK_IP_QUEUE_SPACE 1 +#define ipconfigUDP_MAX_RX_PACKETS 1 +#define ipconfigETHERNET_MINIMUM_PACKET_BYTES 1 +#define ipconfigTCP_IP_SANITY 1 +#define ipconfigSUPPORT_NETWORK_DOWN_EVENT 1 + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf( X ) bsp_printf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 1 +#if ( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf( X ) bsp_printf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing + * on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading then set + * ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software + * stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been + * performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be + * set per socket, using setsockopt(). If not set, the times below will be + * used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very + * useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low + * and also DNS may use small timeouts. If a DNS reply comes in after the DNS + * socket has been destroyed, the result will be stored into the cache. The next + * call to FreeRTOS_gethostbyname() will return immediately, without even creating + * a socket. + */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ( 6 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make + * use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY + * sets the priority of the task that executes the IP stack. The priority is a + * standard FreeRTOS task priority so can take any value from 0 (the lowest + * priority) to (configMAX_PRIORITIES - 1) (the highest priority). + * configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in + * FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to + * the priority assigned to the task executing the IP stack relative to the + * priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP + * task. This setting is less important when the FreeRTOS Win32 simulator is used + * as the Win32 simulator only stores a fixed amount of information on the task + * stack. FreeRTOS includes optional stack overflow detection, see: + * http://www.freertos.org/Stacks-and-stack-overflow-checking.html. */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the + * network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK + * is not set to 1 then the network event hook will never be called. See: + * https://freertos.org/Documentation/03-Libraries/02-FreeRTOS-plus/02-FreeRTOS-plus-TCP/09-API-reference/57-vApplicationIPNetworkEventHook. + */ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but + * a network buffer cannot be obtained then the calling task is held in the Blocked + * state (so other tasks can continue to executed) until either a network buffer + * becomes available or the send block time expires. If the send block time expires + * then the send operation is aborted. The maximum allowable send block time is + * capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the + * maximum allowable send block time prevents prevents a deadlock occurring when + * all the network buffers are in use and the tasks that process (and subsequently + * free) the network buffers are themselves blocked waiting for a network buffer. + * ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in + * milliseconds can be converted to a time in ticks by dividing the time in + * milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000U / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP + * address, netmask, DNS server address and gateway address from a DHCP server. If + * ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The + * stack will revert to using the static IP address even when ipconfigUSE_DHCP is + * set to 1 if a valid configuration cannot be obtained from a DHCP server for any + * reason. The static configuration used is that passed into the stack by the + * FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 0 +#define ipconfigDHCP_REGISTER_HOSTNAME 1 +#define ipconfigDHCP_USES_UNICAST 1 + +/* If ipconfigDHCP_USES_USER_HOOK is set to 1 then the application writer must + * provide an implementation of the DHCP callback function, + * xApplicationDHCPUserHook(). */ +#define ipconfigUSE_DHCP_HOOK 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at + * increasing time intervals until either a reply is received from a DHCP server + * and accepted, or the interval between transmissions reaches + * ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the + * static IP address passed as a parameter to FreeRTOS_IPInit() if the + * re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without + * a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD \ + ( 120000U / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP + * stack can only send a UDP message to a remove IP address if it knowns the MAC + * address associated with the IP address, or the MAC address of the router used to + * contact the remote IP address. When a UDP message is received from a remote IP + * address the MAC address and IP address are added to the ARP cache. When a UDP + * message is sent to a remote IP address that does not already appear in the ARP + * cache then the UDP message is replaced by a ARP message that solicits the + * required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum + * number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a + * maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is + * aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP + * table being created or refreshed and the entry being removed because it is stale. + * New ARP requests are sent for ARP cache entries that are nearing their maximum + * age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is + * equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling + * routines, which are relatively large. To save code space the full + * FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster + * alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() + * takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. + * FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets + * (for example, 192, 168, 0, 1) as its parameters. If + * ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and + * FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is + * not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that + * are available to the IP stack. The total number of network buffers is limited + * to ensure the total amount of RAM that can be consumed by the IP stack is capped + * to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP + * stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can + * be queued for processing at any one time. The event queue must be a minimum of + * 5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH \ + ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port + * number. FreeRTOS_bind() is used to manually allocate a port number to a socket + * (to 'bind' the socket to a port), but manual binding is not normally necessary + * for client sockets (those sockets that initiate outgoing connections rather than + * wait for incoming connections on a known port number). If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling + * FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP + * stack automatically binding the socket to a port number from the range + * socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() + * on a socket that has not yet been bound will result in the send operation being + * aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +/* Also defined in FreeRTOSIPConfigDefaults.h. */ +#define ipconfigTCP_TIME_TO_LIVE 128 + +/* USE_TCP: Use TCP and all its features. */ +#define ipconfigUSE_TCP ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can + * contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a + * lower value can save RAM, depending on the buffer management scheme used. If + * ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must + * be divisible by 8. */ +#define ipconfigNETWORK_MTU 1500U + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used + * through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will + * generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the + * FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 1 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() + * (and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames + * that are not in Ethernet II format will be dropped. This option is included for + * potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the + * responsibility of the Ethernet interface to filter out packets that are of no + * interest. If the Ethernet interface does not implement this functionality, then + * set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack + * perform the filtering instead (it is much less efficient for the stack to do it + * because the packet will already have been passed into the stack). If the + * Ethernet driver does all the necessary filtering in hardware then software + * filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to + * block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with + * 32-bit memory instructions, all packets will be stored 32-bit-aligned, + * plus 16-bits. This has to do with the contents of the IP-packets: all + * 32-bit fields are 32-bit-aligned, plus 16-bit. */ +#define ipconfigPACKET_FILLER_SIZE 2U + +/* Define the size of the pool of TCP window descriptors. On the average, each + * TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 + * outstanding packets (for Rx and Tx). When using up to 10 TP sockets + * simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed + * maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 10000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 10000 ) + +/* When using call-back handlers, the driver may check if the handler points to + * real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* Seconds. */ + +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK ( 1 ) +#define ipconfigUSE_CALLBACKS ( 1 ) + + +#define portINLINE __inline + +#define ipconfigISO_STRICTNESS_VIOLATION_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + +#define ipconfigISO_STRICTNESS_VIOLATION_END _Pragma("GCC diagnostic pop") + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/NetworkInterface.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/NetworkInterface.c new file mode 100644 index 0000000..de42399 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/NetworkInterface.c @@ -0,0 +1,337 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "list.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* Efinix includes. */ +#include "userDef.h" +#include "dmasg.h" +#include "rtl8211fd.h" +#include "efx_tse_mac.h" +#include "plic.h" +#include "riscv.h" + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet + * driver will filter incoming packets and only pass the stack those packets it + * considers need processing. */ +#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +#define FRAME_PACKET 256 +#define BUFFER_SIZE 1519 + +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +typedef struct { + uint8_t* pucEthernetBuffer; + size_t xDataLength; +} DMADescriptor_t; +DMADescriptor_t tx_desc; + +static BaseType_t InitialiseNetwork( void ); +static u32 ReceiveSize(void); +static void interrupt_init(); +static void program_descriptor(); +static void userInterrupt(); +static void crash(); +static void prvEMACDeferredInterruptHandlerTask( void *pvParameters ); +static void prvNetworkInterfaceInput( void ); +static struct dmasg_descriptor* pxGetNextTransmitBuffer(void); +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void); +void freertos_risc_v_application_interrupt_handler(); + +u32 rx_cur_desc = 0; +u32 tx_cur_desc = 0; +u32 ulPHYLinkStatus = 0; +volatile struct dmasg_descriptor rx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); +volatile struct dmasg_descriptor tx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); + +static TaskHandle_t xRxTaskHandle = NULL; + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + BaseType_t xReturn; + + if( InitialiseNetwork() == 0 ) { + xReturn = pdFAIL; + } else { + xReturn = pdPASS; + } + + return xReturn; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) +{ + // Currently, hardware only supports TCP/UDP checksums, IP and ICMP checksum still need to be done in software + #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) pxDescriptor->pucEthernetBuffer; + + if( xProtPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xICMPPacket.xIPHeader ); + usGenerateProtocolChecksum( ( uint8_t * ) &( xProtPacket->xICMPPacket ), pxDescriptor->xDataLength, pdTRUE ); + } else if( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + } + } + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + + struct dmasg_descriptor *pxTransmitBuffer = pxGetNextTransmitBuffer(); + + pxTransmitBuffer->from = (u32)pxDescriptor->pucEthernetBuffer; + pxTransmitBuffer->control = (u32)((pxDescriptor->xDataLength)-1) | 1 << 30; + pxTransmitBuffer->status = 0; + + while(dmasg_busy(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH)); + dmasg_input_memory (TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, pxTransmitBuffer->from, 64); + dmasg_output_stream(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0, 0, 1); + dmasg_interrupt_config(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, DMASG_CHANNEL_INTERRUPT_DESCRIPTOR_COMPLETION_MASK); + dmasg_linked_list_start(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, (u32) pxTransmitBuffer); + + iptraceNETWORK_INTERFACE_TRANSMIT(); + + if(xReleaseAfterSend != pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } + + return pdTRUE; +} + +BaseType_t xGetPhyLinkStatus( void ) +{ + if(ulPHYLinkStatus) { + return pdPASS; + } else { + return pdFALSE; + } +} + +static BaseType_t InitialiseNetwork( void ) +{ + int speed,Value,reg; + BaseType_t xReturn = pdFAIL; + + ulPHYLinkStatus=0; + + MacRst(1, 1); + + rtl8211_drv_init(); + speed=rtl8211_drv_linkup(); + + if((speed == TSE_Speed_1000Mhz) || (speed == TSE_Speed_100Mhz) || (speed == TSE_Speed_10Mhz)) { + MacNormalInit(speed); + + ulPHYLinkStatus=1; + + interrupt_init(); + program_descriptor(); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_RX_CH, 0, 0); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0); + + xTaskCreate( prvEMACDeferredInterruptHandlerTask,"ETHER_TASK",configMINIMAL_STACK_SIZE*4,NULL,RX_HANDLER_PRIORITY, &xRxTaskHandle); + + xReturn = pdPASS; + } + + return xReturn; +} + +static void interrupt_init() +{ + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_priority(BSP_PLIC, TSE_RX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_RX_INTR, 1); + plic_set_priority(BSP_PLIC, TSE_TX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_TX_INTR, 1); + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +static void program_descriptor() +{ + size_t uRequestedBytes = BUFFER_SIZE; + for (int j=0; jpucEthernetBuffer; + + pxDescriptor->pucEthernetBuffer = (uint8_t*)(u32)(pxReceiveBuffer->to); + pxDescriptor->xDataLength = ReceiveSize(); + + pxReceiveBuffer->to = (u32)pucTemp; + + *((NetworkBufferDescriptor_t **) (pxDescriptor->pucEthernetBuffer - ipBUFFER_PADDING) ) = pxDescriptor; + + if(eConsiderFrameForProcessing(pxDescriptor->pucEthernetBuffer) == eProcessBuffer) { + IPStackEvent_t xRxEvent; + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = (void*) pxDescriptor; + + if(xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + iptraceETHERNET_RX_EVENT_LOST(); + } else { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } else { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } +} + +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void) { + return (struct dmasg_descriptor*)&rx_dmasg_desc[rx_cur_desc]; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/main.c new file mode 100644 index 0000000..6668220 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/main.c @@ -0,0 +1,527 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/***************************************************************************** +* Note: This file is Not! to be used as is. The purpose of this file is to provide +* a template for writing a network interface. Each network interface will have to provide +* concrete implementations of the functions in this file. +* +* See the following URL for an explanation of this file and its functions: +* https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html +* +*****************************************************************************/ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" +#include "bsp.h" +#include "riscv.h" +#include "gpio.h" + +/* Demo application includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOSIPConfig.h" + +#define mainHOST_NAME "Efinix" +#define mainDEVICE_NICK_NAME "Sapphire" + +/* + * Just seeds the simple pseudo random number generator. + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialisation including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); +static void vCreateTCPServerSocket( void *pvParameters); +static void prvServerConnectionInstance( void *pvParameters ); +#define THREAD_STACKSIZE 1024 +#define BUFFER_SIZE 512 +#define tskECHO_PRIORITY 3 + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +//const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/* Prepare hardware to run the demo. */ +static void prvSetupHardware( void ); +/* Send a message to the UART initialised in prvSetupHardware. */ +void vSendString( const char * const pcString ); +/*-----------------------------------------------------------*/ +void vSendString( const char * const pcString ) +{ + bsp_printf(pcString); +} + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL ); + + bsp_init(); + + /* + * Instructions for using this project are provided on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + prvSetupHardware(); + + /* Miscellaneous initialisation including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialise the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the definition of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + /* Start the RTOS scheduler. */ + + + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + bsp_uDelay( ulLongTime_ms ); + } +} + +/*-----------------------------------------------------------*/ +static void prvSetupHardware( void ) +{ + extern void freertos_risc_v_trap_handler(); + csr_write(mtvec, freertos_risc_v_trap_handler); + + vSendString( "***Hello world, this is FreeRTOS Echo Server***\n\r" ); +} + +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ +const uint32_t ulMSToSleep = 1; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in + FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the + idle task just sleeps to lower the CPU usage. */ + bsp_uDelay( ulMSToSleep ); +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ +const uint32_t ulLongSleep = 1000UL; +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + FreeRTOS_printf( ( "vAssertCalled( %s, %ld\r\n", pcFile, ulLine ) ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + bsp_uDelay( ulLongSleep ); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ + static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* Both eNetworkUp and eNetworkDown events can be processed here. */ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the TCP/IP stack if they have not already + been created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* + * For convenience, tasks that use FreeRTOS+TCP can be created here + * to ensure they are not created before the network is usable. + */ + + xTasksAlreadyCreated = pdTRUE; + + xTaskCreate( vCreateTCPServerSocket, "ServerListener", THREAD_STACKSIZE, NULL, tskECHO_PRIORITY, NULL ); + } + } +} +/*-----------------------------------------------------------*/ + +static void vCreateTCPServerSocket( void *pvParameters ) +{ + struct freertos_sockaddr xClient, xBindAddress; + Socket_t xListeningSocket, xConnectedSocket; + socklen_t xSize = sizeof( xClient ); + static const TickType_t xReceiveTimeOut = portMAX_DELAY; + const BaseType_t xBacklog = 20; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + + /* Check the socket was created. */ + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* If FREERTOS_SO_RCVBUF or FREERTOS_SO_SNDBUF are to be used with + FreeRTOS_setsockopt() to change the buffer sizes from their default then do + it here!. (see the FreeRTOS_setsockopt() documentation. */ + + /* If ipconfigUSE_TCP_WIN is set to 1 and FREERTOS_SO_WIN_PROPERTIES is to + be used with FreeRTOS_setsockopt() to change the sliding window size from + its default then do it here! (see the FreeRTOS_setsockopt() + documentation. */ + + /* Set a time out so accept() will just wait for a connection. */ + FreeRTOS_setsockopt( xListeningSocket, + 0, + FREERTOS_SO_RCVTIMEO, + &xReceiveTimeOut, + sizeof( xReceiveTimeOut ) ); + + /* Set the listening port to 10000. */ + xBindAddress.sin_port = ( uint16_t ) 10000; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + + /* Bind the socket to the port that the client RTOS task will send to. */ + FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + + /* Set the socket into a listening state so it can accept connections. + The maximum number of simultaneous connections is limited to 20. */ + FreeRTOS_listen( xListeningSocket, xBacklog ); + + int8_t cIPAddressString[ 16 ]; + FreeRTOS_inet_ntoa( FreeRTOS_GetIPAddress(), ( char * ) cIPAddressString ); + bsp_printf( "To test this demo, execute following command on your host computer:\r\n" ); + bsp_printf( " echotool.exe %s /p tcp /r 10000 /d efinix /n 1\r\n", cIPAddressString ); + bsp_printf( "You should see the string being received and echoed back\r\n" ); + + for( ;; ) + { + /* Wait for incoming connections. */ + xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); + configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); + + /* Spawn a RTOS task to handle the connection. */ + xTaskCreate( prvServerConnectionInstance, + "EchoServer", + THREAD_STACKSIZE, + ( void * ) xConnectedSocket, + tskECHO_PRIORITY, + NULL ); + } +} + +static void prvServerConnectionInstance( void *pvParameters ) +{ + Socket_t xSocket; + static char cRxedData[ BUFFER_SIZE ]; + BaseType_t lBytesReceived; + + /* It is assumed the socket has already been created and connected before + being passed into this RTOS task using the RTOS task's parameter. */ + xSocket = ( Socket_t ) pvParameters; + + for( ;; ) + { + // Clear array so that old longer string do not contaminate current shorter string + // E.g previous string was "strawberry", current string is "apple" + // Without clearing the array, current string would become "appleberry" + memset(cRxedData, 0, sizeof cRxedData); + + /* Receive another block of data into the cRxedData buffer. */ + lBytesReceived = FreeRTOS_recv( xSocket, &cRxedData, BUFFER_SIZE, 0 ); + + if( lBytesReceived > 0 ) + { + /* Data was received, process it here. */ + bsp_printf("Received bytes: %d, Received data %s\r\n", lBytesReceived, cRxedData); + + /* break if the received message = "quit" */ + if (!strncmp(cRxedData, "quit", 4)) + break; + + /* Send received data back to the client */ + BaseType_t BytesSent; + BytesSent = FreeRTOS_send( /* The socket being sent to. */ + xSocket, + /* The data being sent. */ + &( cRxedData[ 0 ] ), + /* The remaining length of data to send. */ + lBytesReceived, + /* ulFlags. */ + 0 ); + + if( BytesSent < lBytesReceived ) + break; + } + else if( lBytesReceived == 0 ) + { + /* No data was received, but FreeRTOS_recv() did not return an error. + Timeout? */ + } + else + { + /* Error (maybe the connected socket already shut down the socket?). + Attempt graceful shutdown. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + break; + } + } + + /* Shutdown is complete and the socket can be safely closed. */ + FreeRTOS_closesocket( xSocket ); + + /* Must not drop off the end of the RTOS task - delete the RTOS task. */ + vTaskDelete( NULL ); +} + +void vApplicationMallocFailedHook( void ) +{ + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + vAssertCalled( __FILE__, __LINE__ ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + /* Seed the random number generator. */ + prvSRand( ( uint32_t ) 555987 ); + +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( strcasecmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} + +/* + * Supply a random number to FreeRTOS+TCP stack. + * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER + * SO IS NOT INTENDED FOR USE IN PRODUCTION SYSTEMS. + */ +BaseType_t xApplicationGetRandomNumber(uint32_t* pulNumber) +{ + *(pulNumber) = uxRand(); + return pdTRUE; +} +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} + + +void vApplicationTickHook( void ) +{ + extern void vFullDemoTickHook( void ); +} + +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) +{ + +} + +eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ + ( void ) ( pxNetworkBuffer ); + return eProcessBuffer; +} + +/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ +static StaticTask_t xIdleTaskTCBBuffer; +static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; + *ppxIdleTaskStackBuffer = &xIdleStack[0]; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + /* place for user code */ +} +/* USER CODE END GET_IDLE_TASK_MEMORY */ + +/* USER CODE BEGIN GET_TIMER_TASK_MEMORY */ +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} +/* USER CODE END GET_TIMER_TASK_MEMORY */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/userDef.h new file mode 100644 index 0000000..6a974a2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosEchoServerDemo/src/userDef.h @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "bsp.h" + +/************************** Project Header File ***************************/ +#define DEBUG_PRINTF_EN 0 +#define TEST_MODE 0 //0:Normal Mode; 1:Link partner Test Mode; +#define PAT_NUM 0 +#define PAT_DLEN 8 +#define PAT_IPG 4095 +#define PAT_TYPE 0 //0:UDP Pattern; //1:MAC Pattern; +#define DST_MAC_H 0xffff +#define DST_MAC_L 0xffffffff +#define SRC_MAC_H (configMAC_ADDR5<<8)|configMAC_ADDR4 +#define SRC_MAC_L (configMAC_ADDR3<<24)|(configMAC_ADDR2<<16)|(configMAC_ADDR1<<8)|configMAC_ADDR0//0x5e0060c8 +#define SRC_IP (configIP_ADDR3<<24)|(configIP_ADDR2<<16)|(configIP_ADDR1<<8)|configIP_ADDR0 +#define DST_IP 0xc0a80165 +#define SRC_PORT 0x0521 +#define DST_PORT 0x2715 +#define RX_HANDLER_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/************************** System Header File ***************************/ +#define PHY_ADDR 0x0 + +/************************** HW Header File ***************************/ +#define TSEMAC_BASE 0xe9100000 +#define TSEMAC_DMASG_BASE IO_APB_SLAVE_0_INPUT +#define TSE_DMASG_RX_CH 0 +#define TSE_RX_INTR SYSTEM_PLIC_USER_INTERRUPT_G_INTERRUPT +#define TSE_DMASG_TX_CH 1 +#define TSE_TX_INTR SYSTEM_PLIC_USER_INTERRUPT_H_INTERRUPT +#define TSE_Speed_1000Mhz 0x04 +#define TSE_Speed_100Mhz 0x02 +#define TSE_Speed_10Mhz 0x01 + +/************************** Application Header File ***************************/ +#define TX_ENA_MASK 0xFFFFFFFE +#define RX_ENA_MASK 0xFFFFFFFD +#define XON_GEN_MASK 0xFFFFFFFB +#define PROMIS_EN_MASK 0xFFFFFFEF +#define PAD_EN_MASK 0xFFFFFFDF +#define CRC_FWD_MASK 0xFFFFFFBF +#define PAUSE_IGNORE_MASK 0xFFFFFEFF +#define TX_ADDR_INS_MASK 0xFFFFFBFF +#define LOOP_ENA_MASK 0xFFFF7FFF +#define ETH_SPEED_MASK 0xFFF8FFFF +#define XOFF_GEN_MASK 0xFFBFFFFF +#define CNT_RST_MASK 0x7FFFFFFF + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/makefile new file mode 100644 index 0000000..28652d7 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/makefile @@ -0,0 +1,29 @@ +PROJ_NAME=freertosFatDemo + +STANDALONE = .. +FREERTOS=${FreeRTOS_KERNEL_SRC}/FreeRTOS/${FreeRTOS_KERNEL_SRC_DIR} +FREERTOS_RISCV=${FREERTOS}/portable/GCC/RISC-V +FREERTOS_FAT=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${FREERTOS}/*.c) \ + $(wildcard ${FREERTOS_FAT}/*.c) \ + ${FREERTOS}/portable/MemMang/heap_4.c \ + ${FREERTOS_RISCV}/port.c \ + ${FREERTOS_RISCV}/portASM.S \ + ${STANDALONE}/common/start.S + +CFLAGS += -Isrc +CFLAGS += -I../driver +CFLAGS += -I${FREERTOS}/include +CFLAGS += -I${FREERTOS_FAT}/include +CFLAGS += -I${FREERTOS_RISCV} +CFLAGS += -DportasmHANDLE_INTERRUPT=freertos_risc_v_application_interrupt_handler + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/freertos.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSConfig.h new file mode 100644 index 0000000..6f8ec0e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSConfig.h @@ -0,0 +1,226 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bsp.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15U * 1024U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Currently the TCP/IP stack is using dynamic allocation, and the MQTT task is + * using static allocation. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* The function that implements FreeRTOS printf style output, and the macro + * that maps the configPRINTF() macros to that function. */ +void vLoggingPrintf( char const * pcFormat, + ... ); + +#define configPRINTF( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT_STRING( X ) bsp_printf X + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace + * macros are defined to gather some UDP stack statistics that can then be viewed + * through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there + * are multiple command interpreters running at once (for example, one on a UART + * and one on TCP/IP). This is done to prevent an output buffer being defined by + * each implementation - which would waste RAM. In this case, there is only one + * command interpreter running, and it has its own local output buffer, so the + * global buffer is just set to be one byte long as it is not used and should not + * take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE ( 0L ) + +/* The address of an echo server that will be used by the two demo echo client + * tasks: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 31 +#define configECHO_SERVER_ADDR3 6 +#define configTCP_ECHO_CLIENT_PORT 7 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x32 + +/* Default IP address configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DHCP is set to + * 0, or ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 192 +#define configGATEWAY_ADDR1 168 +#define configGATEWAY_ADDR2 31 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. Google DNS addresses are 8.8.8.8 and + * 8.8.4.4. Used in ipconfigUSE_DHCP is set to 0, or ipconfigUSE_DHCP is + * set to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 8 +#define configDNS_SERVER_ADDR1 8 +#define configDNS_SERVER_ADDR2 8 +#define configDNS_SERVER_ADDR3 8 + +/* Default netmask configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configPROFILING ( 0 ) + +/* Pseudo random number generator used by some tasks. */ +extern uint32_t ulRand( void ); +#define configRAND32() ulRand() + +/* The platform that FreeRTOS is running on. */ +#define configPLATFORM_NAME "Efinix_FPGA" + +// Freertos specifics +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint32_t ) ( BSP_CLINT_HZ ) ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSFATConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSFATConfig.h new file mode 100644 index 0000000..63bad34 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/FreeRTOSFATConfig.h @@ -0,0 +1,290 @@ +/* + * FreeRTOS+FAT V2.3.3 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef _FF_CONFIG_H_ +#define _FF_CONFIG_H_ + + + + +/* Must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN, + * depending on the endian of the architecture on which FreeRTOS is running. */ +#define ffconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* Set to 1 to maintain a current working directory (CWD) for each task that + * accesses the file system, allowing relative paths to be used. + * + * Set to 0 not to use a CWD, in which case full paths must be used for each + * file access. */ +#define ffconfigHAS_CWD 1 + +/* Set to an index within FreeRTOS's thread local storage array that is free for + * use by FreeRTOS+FAT. FreeRTOS+FAT will use two consecutive indexes from this + * that set by ffconfigCWD_THREAD_LOCAL_INDEX. The number of thread local storage + * pointers provided by FreeRTOS is set by configNUM_THREAD_LOCAL_STORAGE_POINTERS + * in FreeRTOSConfig.h */ +#define ffconfigCWD_THREAD_LOCAL_INDEX 0 + +/* Set to 1 to include long file name support. Set to 0 to exclude long + * file name support. + * + * If long file name support is excluded then only 8.3 file names can be used. + * Long file names will be recognised but ignored. + * + * Users should familiarise themselves with any patent issues that may + * potentially exist around the use of long file names in FAT file systems + * before enabling long file name support. */ +#define ffconfigLFN_SUPPORT 1 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + * + * Set to 1 to include a file's short name when listing a directory, i.e. when + * calling findfirst()/findnext(). The short name will be stored in the + * 'pcShortName' field of FF_DirEnt_t. + * + * Set to 0 to only include a file's long name. */ +#define ffconfigINCLUDE_SHORT_NAME 0 + +/* Set to 1 to recognise and apply the case bits used by Windows XP+ when + * using short file names - storing file names such as "readme.TXT" or + * "SETUP.exe" in a short-name entry. This is the recommended setting for + * maximum compatibility. + * + * Set to 0 to ignore the case bits. */ +#define ffconfigSHORTNAME_CASE 1 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + * + * Set to 1 to use UTF-16 (wide-characters) for file and directory names. + * + * Set to 0 to use either 8-bit ASCII or UTF-8 for file and directory names + * (see the ffconfigUNICODE_UTF8_SUPPORT). */ +#define ffconfigUNICODE_UTF16_SUPPORT 0 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + * + * Set to 1 to use UTF-8 encoding for file and directory names. + * + * Set to 0 to use either 8-bit ASCII or UTF-16 for file and directory + * names (see the ffconfig_UTF_16_SUPPORT setting). */ +#define ffconfigUNICODE_UTF8_SUPPORT 0 + +/* Set to 1 to include FAT12 support. + * + * Set to 0 to exclude FAT12 support. + * + * FAT16 and FAT32 are always enabled. */ +#define ffconfigFAT12_SUPPORT 0 + +/* When writing and reading data, i/o becomes less efficient if sizes other + * than 512 bytes are being used. When set to 1 each file handle will + * allocate a 512-byte character buffer to facilitate "unaligned access". */ +#define ffconfigOPTIMISE_UNALIGNED_ACCESS 1 + +/* Input and output to a disk uses buffers that are only flushed at the +* following times: +* +* - When a new buffer is needed and no other buffers are available. +* - When opening a buffer in READ mode for a sector that has just been changed. +* - After creating, removing or closing a file or a directory. +* +* Normally this is quick enough and it is efficient. If +* ffconfigCACHE_WRITE_THROUGH is set to 1 then buffers will also be flushed each +* time a buffer is released - which is less efficient but more secure. */ +#define ffconfigCACHE_WRITE_THROUGH 1 + +/* In most cases, the FAT table has two identical copies on the disk, + * allowing the second copy to be used in the case of a read error. If + * + * Set to 1 to use both FATs - this is less efficient but more secure. + * + * Set to 0 to use only one FAT - the second FAT will never be written to. */ +#define ffconfigWRITE_BOTH_FATS 1 + +/* Set to 1 to have the number of free clusters and the first free cluster + * to be written to the FS info sector each time one of those values changes. + * + * Set to 0 not to store these values in the FS info sector, making booting + * slower, but making changes faster. */ +#define ffconfigWRITE_FREE_COUNT 1 + +/* Set to 1 to maintain file and directory time stamps for creation, modify + * and last access. + * + * Set to 0 to exclude time stamps. + * + * If time support is used, the following function must be supplied: + * + * time_t FreeRTOS_time( time_t *pxTime ); + * + * FreeRTOS_time has the same semantics as the standard time() function. */ +#define ffconfigTIME_SUPPORT 1 + +/* Set to 1 if the media is removable (such as a memory card). + * + * Set to 0 if the media is not removable. + * + * When set to 1 all file handles will be "invalidated" if the media is + * extracted. If set to 0 then file handles will not be invalidated. + * In that case the user will have to confirm that the media is still present + * before every access. */ +#define ffconfigREMOVABLE_MEDIA 0 + +/* Set to 1 to determine the disk's free space and the disk's first free + * cluster when a disk is mounted. + * + * Set to 0 to find these two values when they are first needed. Determining + * the values can take some time. */ +#define ffconfigMOUNT_FIND_FREE 1 + +/* Set to 1 to 'trust' the contents of the 'ulLastFreeCluster' and + * ulFreeClusterCount fields. + * + * Set to 0 not to 'trust' these fields.*/ +#define ffconfigFSINFO_TRUSTED 1 + +/* Set to 1 to store recent paths in a cache, enabling much faster access + * when the path is deep within a directory structure at the expense of + * additional RAM usage. + * + * Set to 0 to not use a path cache. */ +#define ffconfigPATH_CACHE 1 + +/* Only used if ffconfigPATH_CACHE is 1. + * + * Sets the maximum number of paths that can exist in the patch cache at any + * one time. */ +#define ffconfigPATH_CACHE_DEPTH 8 + +/* Set to 1 to calculate a HASH value for each existing short file name. + * Use of HASH values can improve performance when working with large + * directories, or with files that have a similar name. + * + * Set to 0 not to calculate a HASH value. */ +#define ffconfigHASH_CACHE 0 + +/* Only used if ffconfigHASH_CACHE is set to 1 + * + * Set to CRC8 or CRC16 to use 8-bit or 16-bit HASH values respectively. */ +#define ffconfigHASH_FUNCTION CRC16 + +/*_RB_ Not in FreeRTOSFFConfigDefaults.h. */ +#define ffconfigHASH_CACHE_DEPTH 64 + +/* Set to 1 to add a parameter to ff_mkdir() that allows an entire directory + * tree to be created in one go, rather than having to create one directory in + * the tree at a time. For example mkdir( "/etc/settings/network", pdTRUE );. + * + * Set to 0 to use the normal mkdir() semantics (without the additional + * parameter). */ +#define ffconfigMKDIR_RECURSIVE 0 + +/* Set to a function that will be used for all dynamic memory allocations. + * Setting to pvPortMalloc() will use the same memory allocator as FreeRTOS. */ +#define ffconfigMALLOC( size ) pvPortMalloc( size ) + +/* Set to a function that matches the above allocator defined with + * ffconfigMALLOC. Setting to vPortFree() will use the same memory free + * function as FreeRTOS. */ +#define ffconfigFREE( ptr ) vPortFree( ptr ) + +/* Set to 1 to calculate the free size and volume size as a 64-bit number. + * + * Set to 0 to calculate these values as a 32-bit number. */ +#define ffconfig64_NUM_SUPPORT 0 + +/* Defines the maximum number of partitions (and also logical partitions) + * that can be recognised. */ +#define ffconfigMAX_PARTITIONS 1 + +/* Defines how many drives can be combined in total. Should be set to at + * least 2. */ +#define ffconfigMAX_FILE_SYS 2 + +/* In case the low-level driver returns an error 'FF_ERR_DRIVER_BUSY', + * the library will pause for a number of ms, defined in + * ffconfigDRIVER_BUSY_SLEEP_MS before re-trying. */ +#define ffconfigDRIVER_BUSY_SLEEP_MS 20 + +/* Set to 1 to include the ff_fprintf() function. + * + * Set to 0 to exclude the ff_fprintf() function. + * + * ff_fprintf() is quite a heavy function because it allocates RAM and + * brings in a lot of string and variable argument handling code. If + * ff_fprintf() is not being used then the code size can be reduced by setting + * ffconfigFPRINTF_SUPPORT to 0. */ +#define ffconfigFPRINTF_SUPPORT 1 + +/* ff_fprintf() will allocate a buffer of this size in which it will create + * its formatted string. The buffer will be freed before the function + * exits. */ +#define ffconfigFPRINTF_BUFFER_LENGTH 128 + +/* Set to 1 to inline some internal memory access functions. + * + * Set to 0 to not inline the memory access functions. */ +#define ffconfigINLINE_MEMORY_ACCESS 1 + +/* Officially the only criteria to determine the FAT type (12, 16, or 32 + * bits) is the total number of clusters: + * if( ulNumberOfClusters < 4085 ) : Volume is FAT12 + * if( ulNumberOfClusters < 65525 ) : Volume is FAT16 + * if( ulNumberOfClusters >= 65525 ) : Volume is FAT32 + * Not every formatted device follows the above rule. + * + * Set to 1 to perform additional checks over and above inspecting the + * number of clusters on a disk to determine the FAT type. + * + * Set to 0 to only look at the number of clusters on a disk to determine the + * FAT type. */ +#define ffconfigFAT_CHECK 1 + +/* Sets the maximum length for file names, including the path. + * Note that the value of this define is directly related to the maximum stack + * use of the +FAT library. In some API's, a character buffer of size + * 'ffconfigMAX_FILENAME' will be declared on stack. */ +#ifndef ffconfigMAX_FILENAME +#define ffconfigMAX_FILENAME 250 +#endif + +#define FF_PRINTF bsp_printf + +/* Visual studio does not have an implementation of strcasecmp(). + * _RB_ Cannot use FF_NOSTRCASECMP setting as the internal implementation of + * strcasecmp() is in ff_dir, whereas it is used in the http server. Also not + * sure of why FF_NOSTRCASECMP is being tested against 0 to define the internal + * implementation, so I have to set it to 1 here, so it is not defined. */ +#define FF_NOSTRCASECMP 1 + +/* Include the recursive function ff_deltree(). The use of recursion does not + * conform with the coding standard, so use this function with care! */ +#define ffconfigUSE_DELTREE 1 + +#define ffconfigDEV_SUPPORT 1 +#define ffconfigDEV_PATH "/dev" + +#endif /* _FF_CONFIG_H_ */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.c new file mode 100644 index 0000000..c261cc8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.c @@ -0,0 +1,746 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+FAT V2.3.3 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + + +/* Efinix includes. */ +#include "bsp.h" +#include "userDef.h" +#include "source.h" +#include "spi.h" +#include "efx_mmc_driver.h" +#include "vexriscv.h" +#include "device/pcf8523.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" +#include "ff_error.h" +#include "ff_ioman.h" + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 + +/*-----------------------------------------------------------*/ + +static int32_t prvSDMMC_Init( void ); +static int32_t prvFFRead( uint8_t * pucBuffer, + uint32_t ulSectorNumber, + uint32_t ulSectorCount, + FF_Disk_t * pxDisk ); +static int32_t prvFFWrite( uint8_t * pucBuffer, + uint32_t ulSectorNumber, + uint32_t ulSectorCount, + FF_Disk_t * pxDisk ); +static uint32_t get_sector_count(struct mmc *mmc, struct mmc_cmd *cmd); +static const char* FF_SDDiskGetVolumeLabel( FF_IOManager_t *pxIOManager ); + +/*-----------------------------------------------------------*/ + +static BaseType_t xSDCardStatus; +static SemaphoreHandle_t xSDCardSemaphore; +static SemaphoreHandle_t xPlusFATMutex; +uint8_t pucCacheMemory[ 0x10000 ]; + +/*-----------------------------------------------------------*/ + +static int32_t prvFFRead( uint8_t * pucBuffer, + uint32_t ulSectorNumber, + uint32_t ulSectorCount, + FF_Disk_t * pxDisk ) +{ + int32_t iReturn; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = ulSectorCount*MAX_BLK_BUF; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_READ_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_READ_MULTIPLE_BLOCK; + + cmd->cmdarg =ulSectorNumber; + cmd->resp_type=MMC_RSP_R1; + data->dest=pucBuffer; + data->flags = MMC_DATA_READ; + + + mmc->cfg->ops->send_cmd(mmc,cmd,data); + + data_cache_invalidate_all(); + + free(cmd); + free(data); + + iReturn = FF_ERR_NONE; + } + else + { + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 ); + + if( pxDisk->xStatus.bIsInitialised != 0 ) + { + FF_PRINTF( "prvFFRead: warning: %d + %d > %d\r\n", ( unsigned ) ulSectorNumber, ( unsigned ) ulSectorCount, ( unsigned ) pxDisk->ulNumberOfSectors ); + } + + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG ); + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t * pucBuffer, + uint32_t ulSectorNumber, + uint32_t ulSectorCount, + FF_Disk_t * pxDisk ) +{ + int32_t iReturn; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + if (cmd == NULL){ + bsp_printf("Error cmd \r\n"); + while(1); + } + data = malloc(sizeof(struct mmc_data)); + if (data == NULL){ + bsp_printf("Error data\r\n"); + while(1); + } + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = ulSectorCount; //*MAX_BLK_BUF; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_WRITE_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_WRITE_MULTIPLE_BLOCK; + + cmd->cmdarg =ulSectorNumber; + cmd->resp_type=MMC_RSP_R1; + + data->src=pucBuffer; + data->flags = MMC_DATA_WRITE; + + ops->send_cmd(mmc,cmd,data); + + data_cache_invalidate_all(); + + free(cmd); + free(data); + + iReturn = 0; + } + else + { + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 ); + + if( pxDisk->xStatus.bIsInitialised ) + { + FF_PRINTF( "prvFFWrite: warning: %d + %d > %d\r\n", ( unsigned ) ulSectorNumber, ( unsigned ) ulSectorCount, ( unsigned ) pxDisk->ulNumberOfSectors ); + } + + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t * pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +FF_Disk_t * FF_SDDiskInitWithSettings( const char * pcName, + const FFInitSettings_t * pxSettings ) +{ + ( void ) pxSettings; /* Unused */ + + return FF_SDDiskInit( pcName ); +} +/*-----------------------------------------------------------*/ + +FF_Disk_t * FF_SDDiskInit( const char * pcName ) +{ + FF_Error_t xFFError; + BaseType_t xPartitionNumber = 0; + FF_CreationParameters_t xParameters; + FF_Disk_t * pxDisk; + + xSDCardStatus = prvSDMMC_Init(); + + if( xSDCardStatus == pdPASS ) + { + pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) ); + + if( pxDisk != NULL ) + { + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + + pxDisk->ulNumberOfSectors = get_sector_count(mmc, xmmc_cmd); + //pxDisk->ulNumberOfSectors = 31116288; + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL ) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.pucCacheMemory = pucCacheMemory; + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + * protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + * the +FAT driver, and also to avoid concurrent calls to + * prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManager( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManager: %s\r\n", ( const char * ) FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\r\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\r\n" ); + } + } /* if( xSDCardStatus == pdPASS ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\r\n" ); + pxDisk = NULL; + } + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t * pxDisk, + BaseType_t xPartitionNumber ) +{ + FF_Error_t xError; + BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %x\r\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE ); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\r\n", ( const char * ) FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\r\n" ); + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %x\r\n", ( unsigned ) xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */ +BaseType_t FF_SDDiskMount( FF_Disk_t * pxDisk ) +{ + FF_Error_t xFFError; + BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %X\r\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %d sectors\r\n", ( unsigned ) pxDisk->pxIOManager->xPartition.ulTotalSectors ); + FF_SDDiskShowPartition( pxDisk ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t * sddisk_ioman( FF_Disk_t * pxDisk ) +{ + FF_IOManager_t * pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t * pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t * pxDisk ) +{ + FF_Error_t xError; + uint64_t ullFreeSectors; + uint32_t ulTotalSizeMB, ulFreeSizeMB; + int iPercentageFree; + FF_IOManager_t * pxIOManager; + const char * pcTypeName = "unknown type"; + BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\r\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t ) pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + char vol_label_arr[256]; + const char *vol_label = vol_label_arr; + vol_label = FF_SDDiskGetVolumeLabel(pxIOManager); + /* It is better not to use the 64-bit format such as %Lu because it + * might not be implemented. */ + FF_PRINTF( "Partition Nr %d\r\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %d (%s)\r\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%s' \r\n", vol_label ); + FF_PRINTF( "TotalSectors %d\r\n", ( unsigned ) pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %d\r\n", ( unsigned ) pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %d MB\r\n", ( unsigned ) ulTotalSizeMB ); + FF_PRINTF( "FreeSize %d MB ( %d percent free )\r\n", ( unsigned ) ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static int32_t prvSDMMC_Init( void ) +{ + int32_t lSDCardStatus = pdPASS; + + if( xSDCardSemaphore == NULL ) + { + xSDCardSemaphore = xSemaphoreCreateBinary(); + configASSERT( xSDCardSemaphore ); + xSemaphoreGive( xSDCardSemaphore ); + } + + return lSDCardStatus; +} +/*-----------------------------------------------------------*/ + +int disk_initialize () +{ + u8 busy = 0; + u32 Value; + u32 rca=0; + u8 wait_busy_count; + + if(DEBUG_PRINTF_EN) + bsp_printf("disk_initialize started\r\n"); + + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + data = malloc(sizeof(struct mmc_data)); + + memset(data,0,sizeof(struct mmc_data)); + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_GO_IDLE_STATE,MMC_RSP_NONE,0); // Send CMD0 to reset the SD Card + bsp_uDelay(1000); + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SEND_EXT_CSD,MMC_RSP_R7,0x01AA); //CMD8 + if (xmmc_cmd -> response[0] != 0x01AA){ + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SPI_READ_OCR,MMC_RSP_R3,0); // CMD58 + mmc->ocr=xmmc_cmd->response[0]; + + bsp_uDelay(50000);//delay 50ms + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); // CMD55 + + while (busy==0) + { + Value = 0; + Value |= 0x1<<30; //HCS + Value |= 0x0<<28; //XPC + Value |= 0x0<<24; //S18R - this is to switch to 1.8V operating voltage. our FPGA dont support switching to 1.8v + Value |= 0x100000; //VDD VOLTAGE - indicate the voltage range to be 3.2 to 3.3 (Refer to the OCR Register) + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); //make the card accept acmd command so that we can send ACMD41 to set the operating condition + bsp_uDelay(1000);//delay 50ms + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_APP_SEND_OP_COND,MMC_RSP_R3,Value); // send ACMD41 to set operating condition + busy = (xmmc_cmd->response[0]>>31)&0x1; // need to shift right 31 as the response format is R3. R1 return will be located at bit 32:39 + bsp_uDelay(50000); //delay 50ms + + wait_busy_count++; + if (wait_busy_count >=100000) + { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + } + + mmc->ocr=xmmc_cmd->response[0]; // get back OCR value and put into mmc structure + + bsp_uDelay(1000000); + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_ALL_SEND_CID,MMC_RSP_R2,0); + mmc->cid[0]=xmmc_cmd->response[0]; + mmc->cid[1]=xmmc_cmd->response[1]; + mmc->cid[2]=xmmc_cmd->response[2]; + mmc->cid[3]=xmmc_cmd->response[3]; + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SET_RELATIVE_ADDR,MMC_RSP_R6,0); + + mmc->rca = (xmmc_cmd->response[0]&0xffff0000)>>16; + SD_READ_CSD(mmc,xmmc_cmd); + // End of standby State + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SELECT_CARD,MMC_RSP_R1b,(mmc->rca<<16)); // CMD7 // going to transfer state + + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,(mmc->rca<<16)); + sd_send_cmd(mmc,xmmc_cmd,SD_CMD_APP_SET_BUS_WIDTH,MMC_RSP_R1,DATA_WIDTH); + sd_send_cmd(mmc,xmmc_cmd,MMC_CMD_SET_BLOCKLEN,MMC_RSP_R1,BLOCK_SIZE); + + if(DEBUG_PRINTF_EN) + bsp_printf("disk_initialize done\r\n"); + + free(data); + + return pdPASS; +} + +time_t FreeRTOS_time( time_t * pxTime ) +{ + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_SECONDS,get_data,19); + float LSB; + time_data rtc_time; + + //READ TIME FROM RTC + getdata(&rtc_time); + uint8_t seconds = rtc_time.seconds; + uint8_t minutes = rtc_time.minutes; + uint8_t hours; + + if (rtc_time.timesystem && rtc_time.PM) { + hours = rtc_time.hours + 12; + } else { + hours = rtc_time.hours; + } + + uint8_t days = rtc_time.days; + uint8_t weekdays = rtc_time.weekdays; + uint8_t months = rtc_time.months; + uint8_t years = rtc_time.years; + + years = years + 2000 - 1900; + uint8_t days_jan = 31; + uint8_t days_feb = ((years % 4 == 0)? 29 : 28); + uint8_t days_mar = 31; + uint8_t days_apr = 30; + uint8_t days_may = 31; + uint8_t days_jun = 30; + uint8_t days_jul =31; + uint8_t days_aug = 31; + uint8_t days_sep = 30; + uint8_t days_oct = 31; + uint8_t days_nov = 30; + uint8_t days_dec = 31; + uint16_t days_since_1jan = 0; + + switch (months) { + case 1: + days_since_1jan = days; + break; + case 2: + days_since_1jan = days + days_jan; + break; + case 3: + days_since_1jan = days + days_jan + days_feb; + break; + case 4: + days_since_1jan = days + days_jan + days_feb + days_mar; + break; + case 5: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr; + break; + case 6: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may; + break; + case 7: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun; + break; + case 8: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun + days_jul; + break; + case 9: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun + days_jul + days_aug; + break; + case 10: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun + days_jul + days_aug + days_sep; + break; + case 11: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun + days_jul + days_aug + days_sep + days_oct; + break; + case 12: + days_since_1jan = days + days_jan + days_feb + days_mar + days_apr + days_may + days_jun + days_jul + days_aug + days_sep + days_oct + days_nov; + break; + } + // Formula to convert date time to elapsed seconds since Jan 1st, 1970, UTC + // https://cboard.cprogramming.com/c-programming/169847-convert-date-time-seconds-since-epoch.html + uint32_t second_since_1970 = seconds + minutes*60 + hours*3600 + (days_since_1jan-1)*86400 + (years-70)*31536000 + ((years-69)/4)*86400 - ((years-1)/100)*86400 + ((years+299)/400)*86400; + + return second_since_1970; +} + +uint32_t get_sector_count(struct mmc *mmc, struct mmc_cmd *cmd) +{ + uint32_t sector_count; + // Formula to calculate card size for SD 2.00 + // Size = (C_SIZE + 1) * 2^19 + // https://www.hjreggel.net/cardspeed/special-sd.html + uint32_t c_size = (mmc->capacity / 1024 / 512) - 1; + uint64_t size = ((uint64_t)c_size + 1) * 524288; // 2^19=524288 + sector_count = size / 512; + if(DEBUG_PRINTF_EN) { + bsp_printf("SD c_size: %d\r\n", c_size); + bsp_printf("SD sector count: %d\r\n", sector_count); + } + + return sector_count; +} + +static const char* FF_SDDiskGetVolumeLabel( FF_IOManager_t *pxIOManager ) +{ + BaseType_t xIndex; + const uint8_t *pucEntryBuffer = 0; + uint8_t ucAttrib; + FF_FetchContext_t xFetchContext; + FF_Error_t pxError; + + pxError = FF_InitEntryFetch( pxIOManager, pxIOManager->xPartition.ulRootDirCluster, &xFetchContext ); + if (!FF_isERR( pxError )) + { + for ( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) + { + /* Call FF_FetchEntryWithContext only once for every 512-byte block */ + if ( !xIndex || pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) + { + pxError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, 0 ); + if ( FF_isERR( pxError ) ) + { + break; + } + pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer; + } + else + { + /* Advance 32 bytes to get the next directory entry. */ + pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY; + } + + if ( FF_isEndOfDir( pucEntryBuffer ) ) + { + break; + } + if (!FF_isDeleted( pucEntryBuffer )) + { + ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB ); + if ( ucAttrib == FF_FAT_ATTR_VOLID ) + { + memcpy( pxIOManager->xPartition.pcVolumeLabel, pucEntryBuffer, sizeof(pxIOManager->xPartition.pcVolumeLabel) - 1 ); + break; + } + } + } /* for ( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */ + } + FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + + return (const char*)pxIOManager->xPartition.pcVolumeLabel; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.h new file mode 100644 index 0000000..c06cd79 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/ff_sddisk.h @@ -0,0 +1,92 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+FAT V2.3.3 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef __SDDISK_H__ + + #define __SDDISK_H__ + + #include "ff_headers.h" + + #ifdef __cplusplus + extern "C" { + #endif + +/* @brief Initialization settings for more granular control on init. */ + typedef struct FFInitSettings_s + { + BaseType_t xMountFailIgnore; /**< Ignore failure when mounting */ + BaseType_t xDiskPartition; /**< Default disk partition number */ + } FFInitSettings_t; + + +/* Return non-zero if the SD-card is present. + * The parameter 'pxDisk' may be null, unless device locking is necessary. */ + BaseType_t FF_SDDiskDetect( FF_Disk_t * pxDisk ); + +/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */ + FF_Disk_t * FF_SDDiskInitWithSettings( const char * pcName, + const FFInitSettings_t * pxSettings ); + + FF_Disk_t * FF_SDDiskInit( const char * pcName ); + + BaseType_t FF_SDDiskReinit( FF_Disk_t * pxDisk ); + +/* Unmount the volume */ + BaseType_t FF_SDDiskUnmount( FF_Disk_t * pDisk ); + +/* Mount the volume */ + BaseType_t FF_SDDiskMount( FF_Disk_t * pDisk ); + +/* Release all resources */ + BaseType_t FF_SDDiskDelete( FF_Disk_t * pDisk ); + +/* Show some partition information */ + BaseType_t FF_SDDiskShowPartition( FF_Disk_t * pDisk ); + +/* Flush changes from the driver's buf to disk */ + void FF_SDDiskFlush( FF_Disk_t * pDisk ); + +/* Format a given partition on an SD-card. */ + BaseType_t FF_SDDiskFormat( FF_Disk_t * pxDisk, + BaseType_t aPart ); + +/* Return non-zero if an SD-card is detected in a given slot. */ + BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr ); + +/* _RB_ Temporary function - ideally the application would not need the IO + * manager structure, just a handle to a disk. */ + FF_IOManager_t * sddisk_ioman( FF_Disk_t * pxDisk ); + + #ifdef __cplusplus +} /* extern "C" */ + #endif + +#endif /* __SDDISK_H__ */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.c new file mode 100644 index 0000000..bff7443 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.c @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include +#include "bsp.h" +#include "intc.h" +#include "efx_mmc_driver.h" + + +IntStruct IntPtr; +struct sd_ctrl_dev *dev; + +/********************************* Function **********************************/ +void UserInterruptAIsr() +{ + u32 int_status; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,0x00); + + int_status = sd_ctrl_read(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0); + + if(int_status&INT_COMMAND_COMPLETE) { + IntPtr.command_complete = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_COMPLETE); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : COMMAND_COMPLETE\n\r"); + } + } + + if(int_status&INT_TRANSFER_COMPLETE) { + IntPtr.transfer_complete = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_TRANSFER_COMPLETE); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : TRANSFER_COMPLETE\n\r"); + } + } + + if(int_status&INT_BLOCK_GAP_EVENT) { + IntPtr.block_gap_event = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BLOCK_GAP_EVENT); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : BLOCK_GAP_EVENT\n\r"); + } + } + + if(int_status&INT_BUFFER_WRITE_READY) { + //IntPtr.buffer_write_ready = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_WRITE_READY); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : BUFFER_WRITE_READY\n\r"); + } + } + + if(int_status&INT_BUFFER_READ_READY) { + //IntPtr.buffer_read_ready = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_READ_READY); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : BUFFER_READ_READY\n\r"); + } + } + + if(int_status&INT_CARD_INSERTION) { + IntPtr.card_insertion = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_INSERTION); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : CARD_INSERTION\n\r"); + } + } + + if(int_status&INT_CARD_REMOVAL) { + IntPtr.card_removal = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_REMOVAL); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : CARD_REMOVAL\n\r"); + } + } + + if(int_status&INT_COMMAND_TIMEOUT_ERROR) { + IntPtr.command_timeout_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_TIMEOUT_ERROR); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : COMMAND_TIMEOUT_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_CRC_ERROR) { + IntPtr.command_crc_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_CRC_ERROR); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : COMMAND_CRC_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_END_BIT_ERROR) { + IntPtr.command_end_bit_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_END_BIT_ERROR); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : COMMAND_END_BIT_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_INDEX_ERROR) { + IntPtr.command_index_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_INDEX_ERROR); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : COMMAND_INDEX_ERROR\n\r"); + } + } + + if(int_status&INT_DATA_CRC_ERROR) { + //IntPtr.data_crc_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_DATA_CRC_ERROR); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("INT : DATA_CRC_ERROR\n\r"); + } + } + + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); +} + + +/********************************* Function **********************************/ +//Used on unexpected trap/interrupt codes +void crash(){ + bsp_printf( "\n*** CRASH ***\n"); + while(1); +} + +void userInterrupt(){ + //struct example_apb3_ctrl_reg cfg={0}; + uint32_t claim; + //While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT: + UserInterruptAIsr(); break; + default: crash(); break; + } + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); //unmask the claimed interrupt + } +} + +//Called by trap_entry on both exceptions and interrupts events +void freertos_risc_v_application_interrupt_handler(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; //Interrupt if true, exception if false + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: userInterrupt(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void freertos_risc_v_application_exception_handler(){ + if(DEBUG_PRINTF_EN) { + bsp_printf("exception\r\n"); + } +} + +void IntcInitialize(struct mmc *mmc) +{ + dev=mmc->priv; + + //configure PLIC + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); //cpu 0 accept all interrupts with priority above 0 + + //enable SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT rising edge interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT, 1); + + //enable riscV interrupts +// csr_set(mie, MIE_MTIE | MIE_MEIE); //Enable machine timer and external interrupts + csr_set(mie, MIE_MEIE); //Enable machine timer and external interrupts + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); + + //enable User interrupts + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,0x00); //Clean All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,INT_ENABLE); //Enable All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); //Open All Interrupts Signal +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.h new file mode 100644 index 0000000..cd480f6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/intc.h @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#ifndef HEADER_INTC_H_ +#define HEADER_INTC_H_ + +#include +#include "bsp.h" +#include "plic.h" +#include "riscv.h" + +void IntcInitialize(); + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main.c new file mode 100644 index 0000000..ae8f5c8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main.c @@ -0,0 +1,173 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+FAT V2.3.3 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* FreeRTOS kernel includes. */ +#include +#include + +#include "bsp.h" +#include "riscv.h" +#include "gpio.h" + +#include "ff_headers.h" + +/****************************************************************************** + * This project provides two demo applications. A simple blinky style project, + * and a more comprehensive test and demo application. The + * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting (defined in this file) is used to + * select between the two. The simply blinky demo is implemented and described + * in main_blinky.c. The more comprehensive test and demo application is + * implemented and described in main_full.c. + * + * This file implements the code that is not demo specific, including the + * hardware setup and standard FreeRTOS hook functions. + * + * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON + * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO + * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT! + * + */ +extern void main_sd( void ); +/* Prototypes for the standard FreeRTOS callback/hook functions implemented +within this file. See https://www.freertos.org/a00016.html */ + +void vApplicationMallocFailedHook( void ); +void vApplicationIdleHook( void ); +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/* Prepare hardware to run the demo. */ +static void prvSetupHardware( void ); + +/* Send a message to the UART initialised in prvSetupHardware. */ +void vSendString( const char * const pcString ); + +/*-----------------------------------------------------------*/ +int main( void ) +{ + bsp_init(); + prvSetupHardware(); + main_sd(); +} +/*-----------------------------------------------------------*/ + +static void prvSetupHardware( void ) +{ + extern void freertos_risc_v_trap_handler(); + csr_write(mtvec, freertos_risc_v_trap_handler); + + vSendString( "***Hello world, this is FreeRTOS FAT demo***\r\n" ); +} +/*-----------------------------------------------------------*/ + +void vSendString( const char * const pcString ) +{ + bsp_printf(pcString); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* vApplicationMallocFailedHook() will only be called if + configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook + function that will get called if a call to pvPortMalloc() fails. + pvPortMalloc() is called internally by the kernel whenever a task, queue, + timer or semaphore is created. It is also called by various parts of the + demo application. If heap_1.c or heap_2.c are used, then the size of the + heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in + FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used + to query the size of free heap space that remains (although it does not + provide information on how the remaining heap might be fragmented). */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ + /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set + to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle + task. It is essential that code added to this hook function never attempts + to block in any way (for example, call xQueueReceive() with a block time + specified, or call vTaskDelay()). If the application makes use of the + vTaskDelete() API function (as this demo application does) then it is also + important that vApplicationIdleHook() is permitted to return to its calling + function, because it is the responsibility of the idle task to clean up + memory allocated by the kernel to any task that has since been deleted. */ +} +/*-----------------------------------------------------------*/ + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} + +/*-----------------------------------------------------------*/ + +void vApplicationTickHook( void ) +{ + extern void vFullDemoTickHook( void ); +} + +/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ +static StaticTask_t xIdleTaskTCBBuffer; +static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; + *ppxIdleTaskStackBuffer = &xIdleStack[0]; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + /* place for user code */ +} +/* USER CODE END GET_IDLE_TASK_MEMORY */ + +/* USER CODE BEGIN GET_TIMER_TASK_MEMORY */ +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} +/* USER CODE END GET_TIMER_TASK_MEMORY */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main_sd.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main_sd.c new file mode 100644 index 0000000..35c850f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/main_sd.c @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+FAT V2.3.3 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +#include "ff_headers.h" +#include "ff_sddisk.h" +#include "ff_stdio.h" + +#include "mmc.h" +#include "efx_mmc_driver.h" +#include "intc.h" +#include "i2c.h" + + +/* The maximum number items the queue can hold. The priority of the receiving +task is above the priority of the sending task, so the receiving task will +preempt the sending task and remove the queue items each time the sending task +writes to the queue. Therefore the queue will never have more than one item in +it at any time, and even with a queue length of 1, the sending task will never +find the queue full. */ +#define mainQUEUE_LENGTH ( 1 ) +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ + +/*-----------------------------------------------------------*/ + +void main_sd( void ); +static void prvFatSetupTask( void *pvParameters ); +extern int disk_initialize (); +static void init(); +/*-----------------------------------------------------------*/ + +/* The queue used by both tasks. */ +static QueueHandle_t xQueue = NULL; +struct mmc *mmc; +struct mmc_cmd *xmmc_cmd; +struct mmc_data *data; +struct mmc_config *cfg; +struct mmc_ops *ops; + +/*-----------------------------------------------------------*/ + +void main_sd( void ) +{ + /* Create the queue. */ + xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) ); + + if( xQueue != NULL ) + { + /* Start the two tasks as described in the comments at the top of this + file. */ + xTaskCreate( prvFatSetupTask, /* The function that implements the task. */ + "FAT", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE * 2U, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + tskIDLE_PRIORITY + 2, /* The priority assigned to the task. */ + NULL ); /* The task handle is not required, so NULL is passed. */ + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); + } + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the Idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details on the FreeRTOS heap + http://www.freertos.org/a00111.html. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void prvFatSetupTask( void *pvParameters ) +{ +TickType_t xNextWakeTime; +const unsigned long ulValueToSend = 100UL; +BaseType_t xReturned; +FF_Disk_t * pxDisk; + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + /* Initialise xNextWakeTime - this only needs to be done once. */ + xNextWakeTime = xTaskGetTickCount(); + + init(); + + mmc=malloc(sizeof(struct mmc)); + cfg=malloc(sizeof(struct mmc_config)); + ops=malloc(sizeof(struct mmc_ops)); + xmmc_cmd=malloc(sizeof(struct mmc_cmd)); + data=malloc(sizeof(struct mmc_data)); + + bsp_printf("\n\r--- FreeRTOS Demo Start ---\n\r"); + bsp_printf("\r\nInitialize..."); + + //Allocation Struct Space + + memset(mmc, 0, sizeof(struct mmc)); + memset(cfg, 0, sizeof(struct mmc_config)); + memset(ops, 0, sizeof(struct mmc_ops)); + memset(xmmc_cmd, 0, sizeof(struct mmc_cmd)); + memset(data, 0, sizeof(struct mmc_data)); + + mmc->cfg = cfg; //pass the pointer after malloc in struct + mmc->cfg->ops = ops;//pass the pointer after malloc in struct + + sd_ctrl_mmc_probe(mmc,SDHC_BASE); //init SD Card driver + + IntcInitialize(mmc); // init interrupt + + disk_initialize(); + + pxDisk = FF_SDDiskInit("/sd0"); + + FF_FILE *pxFile = ff_fopen("/sd0/freertos.txt", "a"); + if (!pxFile) { + FF_PRINTF("ff_fopen failed: %s (%d)\r\n", strerror(stdioGET_ERRNO()), + stdioGET_ERRNO()); + } + if (ff_fprintf(pxFile, "Write from FreeRTOS\n") < 0) { + FF_PRINTF("ff_fprintf failed: %s (%d)\r\n", strerror(stdioGET_ERRNO()), + stdioGET_ERRNO()); + } + if (-1 == ff_fclose(pxFile)) { + FF_PRINTF("ff_fclose failed: %s (%d)\r\n", strerror(stdioGET_ERRNO()), + stdioGET_ERRNO()); + } + FF_FS_Remove("/sd0"); + FF_Unmount(pxDisk); + FF_SDDiskDelete(pxDisk); + bsp_printf("\n\r--- FreeRTOS Demo Finish ---\n\r"); + + vTaskDelete(NULL); +} +/*-----------------------------------------------------------*/ + +static void init(){ + // Initial I2C Protocol + // Data Hold Time - Standard mode/Fast mode: 0.9us + // SCL Clock Frequency: 100 - 400kHz + // Start setup time: 4.7us + + // Data Setup Time - Standard mode: 250ns, Fast mode: 100ns + // Low Period of SCL clock - Standard mode: 4.7us, Fast mode: 1.3us + // High Period of SCL clock - Standard mode: 4.0us, Fast mode: 0.6us + // Bus Free Time Between STOP and START Conditions - Standard mode: 4.7us, Fast mode: 1.3us + +#define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + I2c_Config i2c; + i2c.samplingClockDivider = 3; // Sampling rate = (FCLK/(samplingClockDivider + 1). Controls the rate at which the I2C controller samples SCL and SDA. + i2c.timeout = 0;//I2C_CTRL_HZ/1000; // Set to 0 in order to avoid timeout // Inactive timeout clock cycle. The controller will drop the transfer when the value of the timeout is reached or exceeded. Setting the timeout value to zero will disable the timeout feature. + i2c.tsuDat = I2C_CTRL_HZ/10000000; // Data setup time. The number of clock cycles should SDA hold its state before the rising edge of SCL. Refer to your I2C slave datasheet. + i2c.tLow = I2C_CTRL_HZ/666667; // The number of clock cycles of SCL in LOW state. + i2c.tHigh = I2C_CTRL_HZ/1250000; // The number of clock cycles of SCL in HIGH state. + i2c.tBuf = I2C_CTRL_HZ/666667; // The number of clock cycles delay before master can initiate a START bit after a STOP bit is issued. Refer to your I2C slave datasheet. + + i2c_applyConfig(I2C_CTRL, &i2c); + + bsp_init(); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/source.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/source.c new file mode 100644 index 0000000..29c5be1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosFatDemo/src/source.c @@ -0,0 +1,284 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "userDef.h" +#include "uart.h" +#include "bsp.h" +#include "mmc.h" +#include "efx_mmc_driver.h" +#include "mmc.h" + +static const int fbase[] = { + 10000, + 100000, + 1000000, + 10000000, +}; + +static const int multipliers[] = { + 0, /* reserved */ + 10, + 12, + 13, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 70, + 80, +}; + +void SD_READ_CSD(struct mmc *mmc, struct mmc_cmd *cmd) +{ + sd_send_cmd(mmc,cmd,MMC_CMD_SEND_CSD,MMC_RSP_R2,(mmc->rca<<16)); + mmc->csd[0]= cmd->response[0]; + mmc->csd[1]= cmd->response[1]; + mmc->csd[2]= cmd->response[2]; + mmc->csd[3]= cmd->response[3]; + + mmc->capacity = (((mmc->csd[1]>>8) &0x3FFFFF)+1)*512; + mmc->capacity *=1024; + mmc->tran_speed = multipliers[(mmc->csd[2]>>27) &0x07] * fbase[(mmc->csd[2]>>24) &0x03]; + + if(DEBUG_PRINTF_EN == 1) + { + bsp_printf("CSD 0x%x 0x%x 0x%x 0x%x\r\n",mmc->csd[0],mmc->csd[1],mmc->csd[2],mmc->csd[3]); + bsp_printf("FILE_FORMAT = %d\r\n",(mmc->csd[0]>>2) &0x03); //[11:10] + bsp_printf("TMP_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>4) &0x01);//[12] + bsp_printf("PERM_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>5) &0x01);//[13] + bsp_printf("COPY = %d\r\n",(mmc->csd[0]>>6) &0x01); //[14] + bsp_printf("FILE_FORMAT_GRP = %d\r\n",(mmc->csd[0]>>7) &0x01);//[15] + //[20:16] + bsp_printf("WRITE_BL_PARTIAL = %d\r\n",(mmc->csd[0]>>13) &0x01);//[21] + bsp_printf("WRITE_BL_LEN = %d\r\n",(mmc->csd[0]>>14) &0x0F);//[25:22] + bsp_printf("R2W_FACTOR = %d\r\n",(mmc->csd[0]>>18) &0x07);//[28:26] + //[30:29] + bsp_printf("WP_GRP_ENABLE = %d\r\n",(mmc->csd[0]>>23) &0x01);//[31] + + bsp_printf("WP_GRP_SIZE = %d\r\n",(mmc->csd[0]>>24) &0x7F);//[38:32] + + bsp_printf("SECTOR_SIZE = %d\r\n",((mmc->csd[1] & 0x3F)<<1)|((mmc->csd[0])>>31 &0x1));//[45:39] + bsp_printf("ERASE_BLK_EN = %d\r\n",(mmc->csd[1]>>6) &0x01);//[46] + //[47] + bsp_printf("C_SIZE = %d\r\n",(mmc->csd[1]>>8) &0x3FFFFF);//[69:48] + //[75:70] + bsp_printf("DSR_IMP = %d\r\n",(mmc->csd[2]>>4) &0x01);//[76] + bsp_printf("READ_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>5) &0x01);//[77] + bsp_printf("WRITE_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>6) &0x01);//[78] + bsp_printf("READ_BL_PARTIAL = %d\r\n",(mmc->csd[2]>>7) &0x01);//[79] + bsp_printf("READ_BL_LEN = %d\r\n",(mmc->csd[2]>>8) &0x0F);//[83:80] + bsp_printf("CCC = %d\r\n",(mmc->csd[2]>>12) &0x0FFF);//[95:84] + bsp_printf("TRAN_SPEED = 0x%x\r\n",(mmc->csd[2]>>24) &0x0FF);//[103:96] + bsp_printf("NSAC = 0x%x\r\n",(mmc->csd[3]) &0x0FF);//[111:104] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>8) &0x0FF);//[119:112] + //[125:120] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>22) &0x03);//[127:126] + bsp_printf("mmc->capacity = %d\r\n",(((mmc->csd[1]>>8) &0x3FFFFF)+1)*512); + bsp_printf("mmc->tran_speed = %d\r\n",mmc->tran_speed); + } + + +} + +/************************** Function File ***************************/ +void SD_CardInitial(struct mmc *mmc, struct mmc_cmd *cmd) +{ + u32 Value; + char busy=0; + u32 rca=0; + int wait_busy_count; + + for(int i=0; i<1; i++) { + + sd_send_cmd(mmc,cmd,MMC_CMD_GO_IDLE_STATE,MMC_RSP_NONE,0); + bsp_uDelay(1000); + + sd_send_cmd(mmc,cmd,MMC_CMD_SEND_EXT_CSD,MMC_RSP_R7,0x01AA); + + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); + + wait_busy_count = 0; + while (busy==0) + { + Value = 0; + Value |= 0x1<<30;//HCS + Value |= 0x0<<28;//XPC + Value |= 0x0<<24;//S18R + Value |= 0x100000;//VDD VOLTAGE + bsp_uDelay(50000);//delay 50ms + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); + sd_send_cmd(mmc,cmd,SD_CMD_APP_SEND_OP_COND,MMC_RSP_R3,Value); + bsp_printf("Response: 0x%x\r\n",cmd->response[0]); + busy = (cmd->response[0]>>31)&0x1; + bsp_uDelay(1000000);//delay 50ms + + wait_busy_count++; + if (wait_busy_count >=10) + { + break; + } + } + + + if(busy == 1) { + break; + } else if(i == 1) { + bsp_printf("Err : ACMD41 OCR BUSY!\r\n"); + while(1); + } + bsp_uDelay(1000000); + } + + sd_send_cmd(mmc,cmd,MMC_CMD_ALL_SEND_CID,MMC_RSP_R2,0); + mmc->cid[0]=cmd->response[0]; + mmc->cid[1]=cmd->response[1]; + mmc->cid[2]=cmd->response[2]; + mmc->cid[3]=cmd->response[3]; + + sd_send_cmd(mmc,cmd,MMC_CMD_SET_RELATIVE_ADDR,MMC_RSP_R6,0); + + mmc->rca = (cmd->response[0]&0xffff0000)>>16; + SD_READ_CSD(mmc,cmd); + sd_send_cmd(mmc,cmd,MMC_CMD_SELECT_CARD,MMC_RSP_R1b,(mmc->rca<<16)); + //write_u32(DATA_WIDTH, APB_0+SDHC_ADDR+0x028);//sdhc_reg - Host Control 1 + + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,(mmc->rca<<16)); + sd_send_cmd(mmc,cmd,SD_CMD_APP_SET_BUS_WIDTH,MMC_RSP_R1,DATA_WIDTH); + sd_send_cmd(mmc,cmd,MMC_CMD_SET_BLOCKLEN,MMC_RSP_R1,BLOCK_SIZE); + + if(DEBUG_PRINTF_EN) + bsp_printf("SD_CardInitial done\r\n"); +} + + +void SD_EraseBlk(struct mmc *mmc, struct mmc_cmd *cmd,u32 sd_addr, u32 blk_count) +{ + sd_send_cmd(mmc,cmd,SD_CMD_ERASE_WR_BLK_START,MMC_RSP_R1,sd_addr); + sd_send_cmd(mmc,cmd,SD_CMD_ERASE_WR_BLK_END,MMC_RSP_R1,sd_addr+(blk_count-1)*BLOCK_SIZE); + sd_send_cmd(mmc,cmd,MMC_CMD_ERASE,MMC_RSP_R1b,0); +} + + +void SD_WRITE_BLOCK(struct mmc *mmc, u32 addr, void* src, u32 blocks) +{ + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = blocks; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_WRITE_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_WRITE_MULTIPLE_BLOCK; + + cmd->cmdarg =addr; + cmd->resp_type=MMC_RSP_R1; + + data->src=src; + data->flags = MMC_DATA_WRITE; + + ops->send_cmd(mmc,cmd,data); + + free(cmd); + free(data); + + return; +} + +void SD_READ_BLOCK(struct mmc *mmc, u32 addr, char* dest, u32 blocks) +{ + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = blocks; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_READ_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_READ_MULTIPLE_BLOCK; + + cmd->cmdarg =addr; + cmd->resp_type=MMC_RSP_R1; + data->dest=dest; + data->flags = MMC_DATA_READ; + + + mmc->cfg->ops->send_cmd(mmc,cmd,data); + + free(cmd); + free(data); + + return; +} + +char SD_ReadWriteCompare(char* wrbuf, char* rdbuf ,u64 wr_start ,u64 wr_end ,u64 rd_start ,u64 rd_end,u32 block_count,u32 current_blk,u32 total_blk) +{ + char err=0; + u32 m,cmpblk; + u32 rd_speed,wr_speed; + + if(block_count>MAX_BLK_BUF) cmpblk=MAX_BLK_BUF; + else cmpblk=block_count; + + if(memcmp(wrbuf,rdbuf,sizeof(char)*cmpblk*BLOCK_SIZE)) + { + bsp_printf("Tested Block %d/%d\n\r",current_blk,total_blk); + + for(m=0;m<(cmpblk*BLOCK_SIZE/4);m++) + { + if(wrbuf[m] != rdbuf[m]) + { + bsp_printf("compare fail m=%d wr= 0x%x rd=0x%x\n\r",m,wrbuf[m],rdbuf[m]); + err=1; + break; + } + + } + } + else + { + wr_speed = ((block_count*BLOCK_SIZE)*1024)/((wr_end-wr_start)/(SYSTEM_CLINT_HZ/1000000)); + rd_speed = ((block_count*BLOCK_SIZE)*1024)/((rd_end-rd_start)/(SYSTEM_CLINT_HZ/1000000)); + + if((current_blk % 1024) ==0) + bsp_printf("Tested Block %d/%d Write s=%d KByte/s Read s=%d KByte/s \r",current_blk,total_blk,wr_speed,rd_speed); + + } + + return err; +} + + +void SD_InitRandomBuff(char* buf, u32 size) +{ + int m; + + for(m=0;m +#include +#include "soc.h" +#include "mmc.h" + +/************************** Hardware Header File ***************************/ +#define SDHC_BASE 0xe9000000 +#define I2C_CTRL SYSTEM_I2C_0_IO_CTRL +/************************** Main Header File ***************************/ +#define DEBUG_PRINTF_EN 0 + +/************************** SDHC Header File ***************************/ +#define MAX_CLK_FREQ 50000//KHz +#define SD_CLK_FREQ MAX_CLK_FREQ//KHz +#define SDHC_ADDR 0x100 +#define BLOCK_SIZE 0x200 +#define MAX_BLK_BUF 0x1 +#define DATA_WIDTH 0x2 //0x0:1-bit mode; 0x2:4-bit mode; +#define DMA_MODE 1 +/************************** INTC Header File *****************************/ +#define INT_ENABLE 0xffffffcf + +#define INT_COMMAND_COMPLETE 0x1 +#define INT_TRANSFER_COMPLETE 0x2 +#define INT_BLOCK_GAP_EVENT 0x4 +#define INT_BUFFER_WRITE_READY 0x10 +#define INT_BUFFER_READ_READY 0x20 +#define INT_CARD_INSERTION 0x40 +#define INT_CARD_REMOVAL 0x80 +#define INT_COMMAND_TIMEOUT_ERROR 0x10000 +#define INT_COMMAND_CRC_ERROR 0x20000 +#define INT_COMMAND_END_BIT_ERROR 0x40000 +#define INT_COMMAND_INDEX_ERROR 0x80000 +#define INT_DATA_CRC_ERROR 0x200000 + +extern struct mmc *mmc; +extern struct mmc_cmd *xmmc_cmd; +extern struct mmc_data *data; + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/makefile new file mode 100644 index 0000000..6490a64 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/makefile @@ -0,0 +1,35 @@ +PROJ_NAME=freertosIperfDemo + +STANDALONE = .. + +CFLAGS+=-DSMP + +FREERTOS=${FreeRTOS_KERNEL_SRC}/FreeRTOS/${FreeRTOS_KERNEL_SRC_DIR} +FREERTOS_RISCV=${FREERTOS}/portable/GCC/RISC-V +FREERTOS_TCP=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/source + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${FREERTOS}/*.c) \ + $(wildcard ${FREERTOS_TCP}/*.c) \ + ${FREERTOS}/portable/MemMang/heap_4.c \ + ${FREERTOS_TCP}/portable/BufferManagement/BufferAllocation_2.c \ + ${FREERTOS_RISCV}/port.c \ + ${FREERTOS_RISCV}/portASM.S \ + ${STANDALONE}/common/start.S + +CFLAGS += -Isrc +CFLAGS += -I../driver +CFLAGS += -I${FREERTOS}/include +CFLAGS += -I${FREERTOS_TCP}/include +CFLAGS += -I${FREERTOS_TCP}/portable/Compiler/GCC +CFLAGS += -I${FREERTOS_RISCV} +CFLAGS += -DportasmHANDLE_INTERRUPT=freertos_risc_v_application_interrupt_handler + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/freertos.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSConfig.h new file mode 100644 index 0000000..6f8ec0e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSConfig.h @@ -0,0 +1,226 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bsp.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15U * 1024U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Currently the TCP/IP stack is using dynamic allocation, and the MQTT task is + * using static allocation. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* The function that implements FreeRTOS printf style output, and the macro + * that maps the configPRINTF() macros to that function. */ +void vLoggingPrintf( char const * pcFormat, + ... ); + +#define configPRINTF( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT_STRING( X ) bsp_printf X + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace + * macros are defined to gather some UDP stack statistics that can then be viewed + * through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there + * are multiple command interpreters running at once (for example, one on a UART + * and one on TCP/IP). This is done to prevent an output buffer being defined by + * each implementation - which would waste RAM. In this case, there is only one + * command interpreter running, and it has its own local output buffer, so the + * global buffer is just set to be one byte long as it is not used and should not + * take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE ( 0L ) + +/* The address of an echo server that will be used by the two demo echo client + * tasks: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 31 +#define configECHO_SERVER_ADDR3 6 +#define configTCP_ECHO_CLIENT_PORT 7 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x32 + +/* Default IP address configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DHCP is set to + * 0, or ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 192 +#define configGATEWAY_ADDR1 168 +#define configGATEWAY_ADDR2 31 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. Google DNS addresses are 8.8.8.8 and + * 8.8.4.4. Used in ipconfigUSE_DHCP is set to 0, or ipconfigUSE_DHCP is + * set to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 8 +#define configDNS_SERVER_ADDR1 8 +#define configDNS_SERVER_ADDR2 8 +#define configDNS_SERVER_ADDR3 8 + +/* Default netmask configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configPROFILING ( 0 ) + +/* Pseudo random number generator used by some tasks. */ +extern uint32_t ulRand( void ); +#define configRAND32() ulRand() + +/* The platform that FreeRTOS is running on. */ +#define configPLATFORM_NAME "Efinix_FPGA" + +// Freertos specifics +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint32_t ) ( BSP_CLINT_HZ ) ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSIPConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSIPConfig.h new file mode 100644 index 0000000..3db5b66 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/FreeRTOSIPConfig.h @@ -0,0 +1,334 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/***************************************************************************** +* +* See the following URL for configuration information. +* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html +* +*****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +#define ipconfigUSE_IPv4 ( 1 ) + +#define ipconfigUSE_IPv6 ( 0 ) + +#define ipconfigUSE_DHCPv6 0 +#define ipconfigIPv4_BACKWARD_COMPATIBLE 1 +#define ipconfigUSE_ARP_REVERSED_LOOKUP 1 +#define ipconfigUSE_ARP_REMOVE_ENTRY 1 +#define ipconfigARP_STORES_REMOTE_ADDRESSES 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 +#define ipconfigFORCE_IP_DONT_FRAGMENT 1 +#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS 1 +#define ipconfigDHCP_FALL_BACK_AUTO_IP 1 +#define ipconfigARP_USE_CLASH_DETECTION 1 +#define ipconfigUSE_LLMNR 1 +#define ipconfigUSE_NBNS 1 +#define ipconfigUSE_MDNS 1 +#define ipconfigSUPPORT_OUTGOING_PINGS 1 +#define ipconfigETHERNET_DRIVER_FILTERS_PACKETS 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1 +#define ipconfigSOCKET_HAS_USER_SEMAPHORE 1 +#define ipconfigSELECT_USES_NOTIFY 1 +#define ipconfigSUPPORT_SIGNALS 1 +#define ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES 1 +#define ipconfigDNS_USE_CALLBACKS 1 +#define ipconfigIGNORE_UNKNOWN_PACKETS 1 +#define ipconfigCHECK_IP_QUEUE_SPACE 1 +#define ipconfigUDP_MAX_RX_PACKETS 1 +#define ipconfigETHERNET_MINIMUM_PACKET_BYTES 1 +#define ipconfigTCP_IP_SANITY 1 +#define ipconfigSUPPORT_NETWORK_DOWN_EVENT 1 + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf( X ) bsp_printf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 1 +#if ( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf( X ) bsp_printf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing + * on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading then set + * ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software + * stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been + * performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be + * set per socket, using setsockopt(). If not set, the times below will be + * used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very + * useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low + * and also DNS may use small timeouts. If a DNS reply comes in after the DNS + * socket has been destroyed, the result will be stored into the cache. The next + * call to FreeRTOS_gethostbyname() will return immediately, without even creating + * a socket. + */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ( 6 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make + * use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY + * sets the priority of the task that executes the IP stack. The priority is a + * standard FreeRTOS task priority so can take any value from 0 (the lowest + * priority) to (configMAX_PRIORITIES - 1) (the highest priority). + * configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in + * FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to + * the priority assigned to the task executing the IP stack relative to the + * priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP + * task. This setting is less important when the FreeRTOS Win32 simulator is used + * as the Win32 simulator only stores a fixed amount of information on the task + * stack. FreeRTOS includes optional stack overflow detection, see: + * http://www.freertos.org/Stacks-and-stack-overflow-checking.html. */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the + * network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK + * is not set to 1 then the network event hook will never be called. See: + * https://freertos.org/Documentation/03-Libraries/02-FreeRTOS-plus/02-FreeRTOS-plus-TCP/09-API-reference/57-vApplicationIPNetworkEventHook. + */ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but + * a network buffer cannot be obtained then the calling task is held in the Blocked + * state (so other tasks can continue to executed) until either a network buffer + * becomes available or the send block time expires. If the send block time expires + * then the send operation is aborted. The maximum allowable send block time is + * capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the + * maximum allowable send block time prevents prevents a deadlock occurring when + * all the network buffers are in use and the tasks that process (and subsequently + * free) the network buffers are themselves blocked waiting for a network buffer. + * ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in + * milliseconds can be converted to a time in ticks by dividing the time in + * milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000U / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP + * address, netmask, DNS server address and gateway address from a DHCP server. If + * ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The + * stack will revert to using the static IP address even when ipconfigUSE_DHCP is + * set to 1 if a valid configuration cannot be obtained from a DHCP server for any + * reason. The static configuration used is that passed into the stack by the + * FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 0 +#define ipconfigDHCP_REGISTER_HOSTNAME 1 +#define ipconfigDHCP_USES_UNICAST 1 + +/* If ipconfigDHCP_USES_USER_HOOK is set to 1 then the application writer must + * provide an implementation of the DHCP callback function, + * xApplicationDHCPUserHook(). */ +#define ipconfigUSE_DHCP_HOOK 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at + * increasing time intervals until either a reply is received from a DHCP server + * and accepted, or the interval between transmissions reaches + * ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the + * static IP address passed as a parameter to FreeRTOS_IPInit() if the + * re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without + * a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD \ + ( 120000U / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP + * stack can only send a UDP message to a remove IP address if it knowns the MAC + * address associated with the IP address, or the MAC address of the router used to + * contact the remote IP address. When a UDP message is received from a remote IP + * address the MAC address and IP address are added to the ARP cache. When a UDP + * message is sent to a remote IP address that does not already appear in the ARP + * cache then the UDP message is replaced by a ARP message that solicits the + * required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum + * number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a + * maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is + * aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP + * table being created or refreshed and the entry being removed because it is stale. + * New ARP requests are sent for ARP cache entries that are nearing their maximum + * age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is + * equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling + * routines, which are relatively large. To save code space the full + * FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster + * alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() + * takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. + * FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets + * (for example, 192, 168, 0, 1) as its parameters. If + * ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and + * FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is + * not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that + * are available to the IP stack. The total number of network buffers is limited + * to ensure the total amount of RAM that can be consumed by the IP stack is capped + * to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP + * stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can + * be queued for processing at any one time. The event queue must be a minimum of + * 5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH \ + ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port + * number. FreeRTOS_bind() is used to manually allocate a port number to a socket + * (to 'bind' the socket to a port), but manual binding is not normally necessary + * for client sockets (those sockets that initiate outgoing connections rather than + * wait for incoming connections on a known port number). If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling + * FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP + * stack automatically binding the socket to a port number from the range + * socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() + * on a socket that has not yet been bound will result in the send operation being + * aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +/* Also defined in FreeRTOSIPConfigDefaults.h. */ +#define ipconfigTCP_TIME_TO_LIVE 128 + +/* USE_TCP: Use TCP and all its features. */ +#define ipconfigUSE_TCP ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can + * contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a + * lower value can save RAM, depending on the buffer management scheme used. If + * ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must + * be divisible by 8. */ +#define ipconfigNETWORK_MTU 1500U + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used + * through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will + * generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the + * FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 1 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() + * (and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames + * that are not in Ethernet II format will be dropped. This option is included for + * potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the + * responsibility of the Ethernet interface to filter out packets that are of no + * interest. If the Ethernet interface does not implement this functionality, then + * set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack + * perform the filtering instead (it is much less efficient for the stack to do it + * because the packet will already have been passed into the stack). If the + * Ethernet driver does all the necessary filtering in hardware then software + * filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to + * block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with + * 32-bit memory instructions, all packets will be stored 32-bit-aligned, + * plus 16-bits. This has to do with the contents of the IP-packets: all + * 32-bit fields are 32-bit-aligned, plus 16-bit. */ +#define ipconfigPACKET_FILLER_SIZE 2U + +/* Define the size of the pool of TCP window descriptors. On the average, each + * TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 + * outstanding packets (for Rx and Tx). When using up to 10 TP sockets + * simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed + * maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 10000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 10000 ) + +/* When using call-back handlers, the driver may check if the handler points to + * real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* Seconds. */ + +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK ( 1 ) +#define ipconfigUSE_CALLBACKS ( 1 ) + + +#define portINLINE __inline + +#define ipconfigISO_STRICTNESS_VIOLATION_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + +#define ipconfigISO_STRICTNESS_VIOLATION_END _Pragma("GCC diagnostic pop") + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/NetworkInterface.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/NetworkInterface.c new file mode 100644 index 0000000..de42399 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/NetworkInterface.c @@ -0,0 +1,337 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "list.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* Efinix includes. */ +#include "userDef.h" +#include "dmasg.h" +#include "rtl8211fd.h" +#include "efx_tse_mac.h" +#include "plic.h" +#include "riscv.h" + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet + * driver will filter incoming packets and only pass the stack those packets it + * considers need processing. */ +#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +#define FRAME_PACKET 256 +#define BUFFER_SIZE 1519 + +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +typedef struct { + uint8_t* pucEthernetBuffer; + size_t xDataLength; +} DMADescriptor_t; +DMADescriptor_t tx_desc; + +static BaseType_t InitialiseNetwork( void ); +static u32 ReceiveSize(void); +static void interrupt_init(); +static void program_descriptor(); +static void userInterrupt(); +static void crash(); +static void prvEMACDeferredInterruptHandlerTask( void *pvParameters ); +static void prvNetworkInterfaceInput( void ); +static struct dmasg_descriptor* pxGetNextTransmitBuffer(void); +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void); +void freertos_risc_v_application_interrupt_handler(); + +u32 rx_cur_desc = 0; +u32 tx_cur_desc = 0; +u32 ulPHYLinkStatus = 0; +volatile struct dmasg_descriptor rx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); +volatile struct dmasg_descriptor tx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); + +static TaskHandle_t xRxTaskHandle = NULL; + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + BaseType_t xReturn; + + if( InitialiseNetwork() == 0 ) { + xReturn = pdFAIL; + } else { + xReturn = pdPASS; + } + + return xReturn; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) +{ + // Currently, hardware only supports TCP/UDP checksums, IP and ICMP checksum still need to be done in software + #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) pxDescriptor->pucEthernetBuffer; + + if( xProtPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xICMPPacket.xIPHeader ); + usGenerateProtocolChecksum( ( uint8_t * ) &( xProtPacket->xICMPPacket ), pxDescriptor->xDataLength, pdTRUE ); + } else if( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + } + } + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + + struct dmasg_descriptor *pxTransmitBuffer = pxGetNextTransmitBuffer(); + + pxTransmitBuffer->from = (u32)pxDescriptor->pucEthernetBuffer; + pxTransmitBuffer->control = (u32)((pxDescriptor->xDataLength)-1) | 1 << 30; + pxTransmitBuffer->status = 0; + + while(dmasg_busy(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH)); + dmasg_input_memory (TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, pxTransmitBuffer->from, 64); + dmasg_output_stream(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0, 0, 1); + dmasg_interrupt_config(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, DMASG_CHANNEL_INTERRUPT_DESCRIPTOR_COMPLETION_MASK); + dmasg_linked_list_start(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, (u32) pxTransmitBuffer); + + iptraceNETWORK_INTERFACE_TRANSMIT(); + + if(xReleaseAfterSend != pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } + + return pdTRUE; +} + +BaseType_t xGetPhyLinkStatus( void ) +{ + if(ulPHYLinkStatus) { + return pdPASS; + } else { + return pdFALSE; + } +} + +static BaseType_t InitialiseNetwork( void ) +{ + int speed,Value,reg; + BaseType_t xReturn = pdFAIL; + + ulPHYLinkStatus=0; + + MacRst(1, 1); + + rtl8211_drv_init(); + speed=rtl8211_drv_linkup(); + + if((speed == TSE_Speed_1000Mhz) || (speed == TSE_Speed_100Mhz) || (speed == TSE_Speed_10Mhz)) { + MacNormalInit(speed); + + ulPHYLinkStatus=1; + + interrupt_init(); + program_descriptor(); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_RX_CH, 0, 0); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0); + + xTaskCreate( prvEMACDeferredInterruptHandlerTask,"ETHER_TASK",configMINIMAL_STACK_SIZE*4,NULL,RX_HANDLER_PRIORITY, &xRxTaskHandle); + + xReturn = pdPASS; + } + + return xReturn; +} + +static void interrupt_init() +{ + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_priority(BSP_PLIC, TSE_RX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_RX_INTR, 1); + plic_set_priority(BSP_PLIC, TSE_TX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_TX_INTR, 1); + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +static void program_descriptor() +{ + size_t uRequestedBytes = BUFFER_SIZE; + for (int j=0; jpucEthernetBuffer; + + pxDescriptor->pucEthernetBuffer = (uint8_t*)(u32)(pxReceiveBuffer->to); + pxDescriptor->xDataLength = ReceiveSize(); + + pxReceiveBuffer->to = (u32)pucTemp; + + *((NetworkBufferDescriptor_t **) (pxDescriptor->pucEthernetBuffer - ipBUFFER_PADDING) ) = pxDescriptor; + + if(eConsiderFrameForProcessing(pxDescriptor->pucEthernetBuffer) == eProcessBuffer) { + IPStackEvent_t xRxEvent; + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = (void*) pxDescriptor; + + if(xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + iptraceETHERNET_RX_EVENT_LOST(); + } else { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } else { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } +} + +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void) { + return (struct dmasg_descriptor*)&rx_dmasg_desc[rx_cur_desc]; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.c new file mode 100644 index 0000000..01e6e9f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.c @@ -0,0 +1,1107 @@ +/* + * FreeRTOS+TCP V2.3.2 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iperf_task_v3_0f.c + * @brief Implements an iperf3 server using FreeRTOS_TCP. + */ + +/* + * A FreeRTOS+TCP demo program: + * A simple example of a TCP/UDP iperf server, see https://iperf.fr + * + * It uses a single task which will store some client information in a: + * List_t xTCPClientList; + * + * The task will sleep constantly by calling: + * xResult = FreeRTOS_select( xSocketSet, xBlockingTime ); + * + * Command examples for testing: + * + * iperf3 -c 192.168.2.114 -4 --port 5001 --bytes 100M + * iperf3 -c 192.168.2.114 -4 --port 5001 --bytes 100M -R + * + * iperf3 -c fe80::8d11:cd9b:8b66:4a80 -6 --port 5001 --bytes 1M + * iperf3 -c fe80::8d11:cd9b:8b66:4a81 -6 --port 5001 --bytes 1M + * iperf3 -c fe80::6802:9887:8670:b37c -6 --port 5001 --bytes 1M + * + * ping fe80::8d11:cd9b:8b66:4a80 + * ping fe80::8d11:cd9b:8b66:4a81 + * iperf3 -s --port 5001 + * Using local name resolution for names like "zynq" and "laptop". + * iperf3 -c zynq --port 5001 --bytes 1024 + * iperf3 -c laptop --port 5001 --bytes 1024 + * fe80::8d11:cd9b:8b66:4a80 + * TCP : iperf3 -c 192.168.2.116 --port 5001 --bytes 1024 + * UDP : iperf3 -c 192.168.2.116 --port 5001 --udp --bandwidth 50M --mss 1460 --bytes 1024 + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" +#include "timers.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_TCP_IP.h" + +#include "iperf_task.h" + +#define ipconfigIPERF_BUFSIZE 8 +#define ipconfigIPERF_WINSIZE 8 + +/* Put the TCP server at this port number: */ +#ifndef ipconfigIPERF_TCP_ECHO_PORT + /* 5001 seems to be the standard TCP server port number. */ + #define ipconfigIPERF_TCP_ECHO_PORT 5001 +#endif + +/* Put the TCP server at this port number: */ +#ifndef ipconfigIPERF_UDP_ECHO_PORT + /* 5001 seems to be the standard UDP server port number. */ + #define ipconfigIPERF_UDP_ECHO_PORT 5001 +#endif + +#ifndef ipconfigIPERF_STACK_SIZE_IPERF_TASK + /* Stack size needed for vIPerfTask(), a bit of a guess: */ + #define ipconfigIPERF_STACK_SIZE_IPERF_TASK 1000 +#endif + +#ifndef ipconfigIPERF_PRIORITY_IPERF_TASK + +/* The priority of vIPerfTask(). Should be lower than the IP-task + * and the task running in NetworkInterface.c. */ + #define ipconfigIPERF_PRIORITY_IPERF_TASK ( configMAX_PRIORITIES - 3 ) +#endif + +#ifndef ipconfigIPERF_RECV_BUFFER_SIZE + +/* Only used when ipconfigIPERF_USE_ZERO_COPY = 0. + * Buffer size when reading from the sockets. */ + #define ipconfigIPERF_RECV_BUFFER_SIZE ( ipconfigIPERF_BUFSIZE * 24 * ipconfigTCP_MSS ) +#endif + +#ifndef ipconfigIPERF_LOOP_BLOCKING_TIME_MS + /* Let the mainloop wake-up so now and then. */ + #define ipconfigIPERF_LOOP_BLOCKING_TIME_MS 5000UL +#endif + +#ifndef ipconfigIPERF_HAS_TCP + /* A TCP server socket will be created. */ + #define ipconfigIPERF_HAS_TCP 1 +#endif + +#ifndef ipconfigIPERF_HAS_UDP + /* A UDP server socket will be created. */ + #define ipconfigIPERF_HAS_UDP 1 +#endif + +#ifndef ipconfigIPERF_DOES_ECHO_UDP + /* By default, this server will echo UDP data as required by iperf. */ + #define ipconfigIPERF_DOES_ECHO_UDP 1 +#endif + +#ifndef ipconfigIPERF_USE_ZERO_COPY + #define ipconfigIPERF_USE_ZERO_COPY 1 +#endif + +#ifndef ipconfigIPERF_TX_BUFSIZE + #define ipconfigIPERF_TX_BUFSIZE ( ipconfigIPERF_BUFSIZE * 24 * ipconfigTCP_MSS ) /* Units of bytes. */ + #define ipconfigIPERF_TX_WINSIZE ( ipconfigIPERF_WINSIZE * 8 ) /* Size in units of MSS */ + #define ipconfigIPERF_RX_BUFSIZE ( ipconfigIPERF_BUFSIZE * 24 * ipconfigTCP_MSS ) /* Units of bytes. */ + #define ipconfigIPERF_RX_WINSIZE ( ipconfigIPERF_WINSIZE * 8 ) /* Size in units of MSS */ +#endif + +#ifndef ARRAY_SIZE + #define ARRAY_SIZE( x ) ( BaseType_t ) ( sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +#define ipconfigIPERF_VERSION 3 + +void vIPerfTask( void * pvParameter ); + +/* It is not certain that sscanf() can handle a 64-bit number. */ +extern int sscanf64( char * pcString, + uint64_t * pullAmount ); + +#if ( ipconfigIPERF_HAS_TCP != 0 ) + static Socket_t xCreateTCPServerSocket( void ); +#endif + +#if ( ipconfigIPERF_HAS_UDP != 0 ) + static Socket_t xCreateUDPServerSocket( void ); +#endif + +#if ( ipconfigUSE_IPv6 == 1 ) + static NetworkEndPoint_t * pxFindLocalEndpoint( void ); +#endif + +static void vListInsertGeneric( List_t * const pxList, + ListItem_t * const pxNewListItem, + MiniListItem_t * pxWhere ) +{ + /* Insert a new list item into pxList, it does not sort the list, + * but it puts the item just before xListEnd, so it will be the last item + * returned by listGET_HEAD_ENTRY() */ + + /* MISRA Ref 11.3.1 [Misaligned access] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ + /* coverity[misra_c_2012_rule_11_3_violation] */ + pxNewListItem->pxNext = ( ( ListItem_t * ) pxWhere ); + + pxNewListItem->pxPrevious = pxWhere->pxPrevious; + pxWhere->pxPrevious->pxNext = pxNewListItem; + pxWhere->pxPrevious = pxNewListItem; + + /* Remember which list the item is in. */ + listLIST_ITEM_CONTAINER( pxNewListItem ) = ( struct xLIST * configLIST_VOLATILE ) pxList; + + ( pxList->uxNumberOfItems )++; +} + +static portINLINE void vListInsertFifo( List_t * const pxList, + ListItem_t * const pxNewListItem ) +{ + vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd ); +} + +#if ( ipconfigIPERF_VERSION == 3 ) + typedef enum + { + eTCP_0_WaitName, /* Expect a text like "osboxes.1460335312.612572.527642c36f" */ + eTCP_1_WaitCount, + eTCP_2_WaitHeader, + eTCP_3_WaitOneTwo, + eTCP_4_WaitCount2, + eTCP_5_WaitHeader2, + eTCP_6_WaitDone, + eTCP_7_WaitTransfer + } eTCP_Server_Status_t; +#endif /* if ( ipconfigIPERF_VERSION == 3 ) */ +typedef struct +{ + Socket_t xServerSocket; + #if ( ipconfigIPERF_VERSION == 3 ) + struct + { + uint32_t + bIsControl : 1, + bReverse : 1, + bTimed : 1, /* Reverse role, limited time. */ + bTimedOut : 1, /* Time is up. */ + bHasShutdown : 1, /* Has called FreeRTOS_shutdown() for this socket. */ + bIsIPv6 : 1; /* IPv6 connection. */ + } bits; + eTCP_Server_Status_t eTCP_Status; + uint32_t ulSkipCount; + uint64_t ullAmount; + TickType_t xRemainingTime; + TimeOut_t xTimeOut; + #endif /* ipconfigIPERF_VERSION == 3 */ + struct freertos_sockaddr xRemoteAddr; + uint32_t ulRecvCount; + struct xLIST_ITEM xListItem; /* With this item the client will be bound to a List_t. */ +} TcpClient_t; + + +#if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) + struct xRawBuffer + { + char pcBuffer[ ipconfigIPERF_RECV_BUFFER_SIZE ]; + } + * pxRawBuffer; + #define pcSendBuffer ( pxRawBuffer->pcBuffer ) + static char * pcRecvBuffer; +#else + struct xRawBuffer + { + char pcBuffer[ ipconfigIPERF_RECV_BUFFER_SIZE ]; + } + * pxRawBuffer; + #define pcRecvBuffer ( pxRawBuffer->pcBuffer ) + #define pcSendBuffer ( pxRawBuffer->pcBuffer ) +#endif /* if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) */ + +#if ( ipconfigIPERF_VERSION == 3 ) + char pcExpectedClient[ 80 ]; + TcpClient_t * pxControlClient, * pxDataClient; + /*{"cpu_util_total":0,"cpu_util_user":0,"cpu_util_system":0,"sender_has_retransmits":-1,"streams":[{"id":1,"bytes":8760,"retransmits":-1,"jitter":0,"errors":0,"packets":0}]} */ +#endif + +static List_t xTCPClientList; +#if ( ipconfigIPERF_HAS_UDP != 0 ) + static uint32_t ulUDPRecvCount = 0, ulUDPRecvCountShown = 0, ulUDPRecvCountSeen = 0; +#endif + +static SocketSet_t xSocketSet; +static TaskHandle_t pxIperfTask; + +void vIPerfInstall( void ) +{ + if( pxRawBuffer == NULL ) + { + pxRawBuffer = ( struct xRawBuffer * ) pvPortMalloc( sizeof *pxRawBuffer ); + FreeRTOS_printf( ( "vIPerfInstall: malloc %d bytes %s\r\n", + ( unsigned ) sizeof *pxRawBuffer, + ( pxRawBuffer != NULL ) ? "OK." : "failed!" ) ); + + if( pxRawBuffer == NULL ) + { + return; + } + } + + if( pxIperfTask == NULL ) + { + /* Call this function once to start the test with FreeRTOS_accept(). */ + xTaskCreate( vIPerfTask, "IPerf", ipconfigIPERF_STACK_SIZE_IPERF_TASK, NULL, ipconfigIPERF_PRIORITY_IPERF_TASK, &pxIperfTask ); + } +} + +static void vIPerfServerWork( Socket_t xSocket ) +{ + struct freertos_sockaddr xAddress; + socklen_t xSocketLength = sizeof( xAddress ); + Socket_t xNexSocket; + + xNexSocket = FreeRTOS_accept( xSocket, &xAddress, &xSocketLength ); + + if( ( xNexSocket != NULL ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) + { + char pcBuffer[ 41 ]; +// BaseType_t xAddressFamily = FREERTOS_AF_INET4; + TcpClient_t * pxClient; + + pxClient = ( TcpClient_t * ) pvPortMalloc( sizeof *pxClient ); + memset( pxClient, '\0', sizeof *pxClient ); + pxClient->xServerSocket = xNexSocket; + + /* Add this client to the list of clients. */ + listSET_LIST_ITEM_OWNER( &( pxClient->xListItem ), ( void * ) pxClient ); + + FreeRTOS_GetRemoteAddress( xNexSocket, ( struct freertos_sockaddr * ) &( pxClient->xRemoteAddr ) ); + #if ( ipconfigUSE_IPv6 == 1 ) + { + static const uint32_t ulEmpty[ 3 ] = { 0U, 0U, 0U }; + + if( memcmp( ulEmpty, pxClient->xRemoteAddr.sin_address.xIP_IPv6.ucBytes + 4, sizeof ulEmpty ) != 0 ) + { + pxClient->bits.bIsIPv6 = pdTRUE; + xAddressFamily = FREERTOS_AF_INET6; + } + } + #endif + +// FreeRTOS_inet_ntop( xAddressFamily, +// pxClient->xRemoteAddr.sin_address.xIP_IPv6.ucBytes, +// pcBuffer, sizeof pcBuffer ); + +// FreeRTOS_printf( ( "vIPerfTask: Received a connection from %s:%d\r\n", +// pcBuffer, +// FreeRTOS_ntohs( pxClient->xRemoteAddr.sin_port ) ) ); + + FreeRTOS_FD_SET( xNexSocket, xSocketSet, eSELECT_READ ); + + vListInsertFifo( &xTCPClientList, &( pxClient->xListItem ) ); + } +} + +static void vIPerfTCPClose( TcpClient_t * pxClient ) +{ + if( pxControlClient == pxClient ) + { + pxControlClient = NULL; + } + + if( pxDataClient == pxClient ) + { + pxDataClient = NULL; + } + + /* Remove server socket from the socket set. */ + if( pxClient->xServerSocket != NULL ) + { + char pcBuffer[ 16 ]; +// BaseType_t xAddressFamily = FREERTOS_AF_INET4; + + #if ( ipconfigUSE_IPv6 == 1 ) + if( pxClient->bits.bIsIPv6 == pdTRUE_UNSIGNED ) + { + xAddressFamily = FREERTOS_AF_INET6; + } + #endif +// FreeRTOS_inet_ntop( xAddressFamily, +// pxClient->xRemoteAddr.sin_address.xIP_IPv6.ucBytes, +// pcBuffer, sizeof pcBuffer ); + +// FreeRTOS_printf( ( "vIPerfTCPClose: Closing server socket %s:%d after %d bytes\r\n", +// pcBuffer, +// ( unsigned ) FreeRTOS_ntohs( pxClient->xRemoteAddr.sin_port ), +// ( unsigned ) pxClient->ulRecvCount ) ); + + FreeRTOS_FD_CLR( pxClient->xServerSocket, xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xServerSocket ); + pxClient->xServerSocket = NULL; + } + + /* Remove client socket from the socket set. */ + + { + if( pxClient->xServerSocket == NULL ) + { + /* Remove this socket from the list. */ + uxListRemove( &( pxClient->xListItem ) ); + vPortFree( ( void * ) pxClient ); + } + } +} + +static int vIPerfTCPSend( TcpClient_t * pxClient ) +{ + BaseType_t xResult = 0; + + do + { + size_t uxMaxSpace = ( size_t ) FreeRTOS_tx_space( pxClient->xServerSocket ); + size_t uxSize = ( size_t ) FreeRTOS_min_uint32( uxMaxSpace, ( int32_t ) sizeof( pcSendBuffer ) ); + + if( pxClient->bits.bTimed != pdFALSE_UNSIGNED ) + { + if( xTaskCheckForTimeOut( &( pxClient->xTimeOut ), &( pxClient->xRemainingTime ) ) != pdFALSE ) + { + /* Time is up. */ + if( pxClient->bits.bTimedOut == pdFALSE_UNSIGNED ) + { + FreeRTOS_shutdown( pxClient->xServerSocket, FREERTOS_SHUT_RDWR ); + pxClient->bits.bTimedOut = pdTRUE_UNSIGNED; + } + + break; + } + } + + if( pxClient->ullAmount < ( uint64_t ) uxSize ) + { + uxSize = pxClient->ullAmount; + } + + if( uxSize <= 0 ) + { + break; + } + + xResult = FreeRTOS_send( pxClient->xServerSocket, ( const void * ) pcSendBuffer, uxSize, 0 ); + + if( xResult < 0 ) + { + break; + } + + if( pxClient->bits.bTimed == pdFALSE_UNSIGNED ) + { + pxClient->ullAmount -= ( uint64_t ) uxSize; + + if( pxClient->ullAmount == 0U ) + { + /* All data have been sent. No longer interested in eSELECT_WRITE events. */ + FreeRTOS_FD_CLR( pxClient->xServerSocket, xSocketSet, eSELECT_WRITE ); + } + } + + if( uxSize > 0 ) + { + xResult += uxSize; + } + } + while( 0 ); + + return xResult; +} + +#if ( ipconfigIPERF_VERSION == 3 ) + static void handleRecvPacket( TcpClient_t * pxClient, + char * pcReadBuffer, + BaseType_t xRecvResult ) + { + BaseType_t xRemaining = xRecvResult; + + if( pxClient->eTCP_Status < eTCP_7_WaitTransfer ) + { + FreeRTOS_printf( ( "TCP[ port %d ] recv[ %d ] %d\r\n", FreeRTOS_ntohs( pxClient->xRemoteAddr.sin_port ), ( int ) pxClient->eTCP_Status, ( int ) xRecvResult ) ); + } + +/* + * 2016-04-11 09:26:55.533 192.168.2.106 16.926.349 [] TCP recv[ 1 ] 4 + * 2016-04-11 09:26:55.539 192.168.2.106 16.926.365 [] TCP skipcount 83 xRecvResult 4 + * 2016-04-11 09:26:55.546 192.168.2.106 16.926.402 [] TCP recv[ 2 ] 4 + * 2016-04-11 09:26:55.552 192.168.2.106 16.927.015 [] ipTCP_FLAG_PSH received + * 2016-04-11 09:26:55.560 192.168.2.106 16.927.085 [] TCP recv[ 2 ] 83 + */ + switch( pxClient->eTCP_Status ) + { + case eTCP_0_WaitName: + { + int rc; + + if( pcExpectedClient[ 0 ] != '\0' ) + { + /* Get a string like 'LAPTOP.1463928623.162445.0fbe105c6eb', + * where 'LAPTOP' is the hostname. */ + rc = strncmp( pcExpectedClient, pcReadBuffer, sizeof( pcExpectedClient ) ); + } + else + { + rc = -1; + } + + { + unsigned char tab[ 1 ] = { '\t' }; + FreeRTOS_send( pxClient->xServerSocket, ( const void * ) tab, 1, 0 ); + } + + if( rc != 0 ) + { + FreeRTOS_printf( ( "Got Control Socket: rc %d: exp: '%s' got: '%s'\r\n", rc, pcExpectedClient, pcReadBuffer ) ); + strncpy( pcExpectedClient, pcReadBuffer, sizeof( pcExpectedClient ) ); + pxControlClient = pxClient; + pxClient->bits.bIsControl = pdTRUE_UNSIGNED; + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + else + { + FreeRTOS_printf( ( "Got expected client: rc %d: '%s'\r\n", rc, pcExpectedClient ) ); + pcExpectedClient[ 0 ] = '\0'; + pxDataClient = pxClient; + + if( pxControlClient != NULL ) + { + /* Transfer all properties to the data client. */ + memcpy( &( pxDataClient->bits ), &( pxControlClient->bits ), sizeof( pxDataClient->bits ) ); + pxDataClient->ullAmount = pxControlClient->ullAmount; + pxDataClient->xRemainingTime = pxControlClient->xRemainingTime; + vTaskSetTimeOutState( &( pxDataClient->xTimeOut ) ); + + if( pxDataClient->bits.bReverse != pdFALSE_UNSIGNED ) + { + /* As this socket will only write data, set the WRITE select flag. */ + FreeRTOS_FD_SET( pxClient->xServerSocket, xSocketSet, eSELECT_WRITE ); + } + + pxControlClient->bits.bIsControl = pdTRUE_UNSIGNED; + pxDataClient->bits.bIsControl = pdFALSE_UNSIGNED; + } + + pxDataClient->eTCP_Status = eTCP_7_WaitTransfer; + } + } + break; + + case eTCP_1_WaitCount: + + if( xRemaining < 4 ) + { + break; + } + + { + pxClient->ulSkipCount = + ( ( ( uint32_t ) pcReadBuffer[ 0 ] ) << 24 ) | + ( ( ( uint32_t ) pcReadBuffer[ 1 ] ) << 16 ) | + ( ( ( uint32_t ) pcReadBuffer[ 2 ] ) << 8 ) | + ( ( ( uint32_t ) pcReadBuffer[ 3 ] ) << 0 ); + /* Receive a number: an amount of bytes to be skipped. */ + FreeRTOS_printf( ( "TCP skipcount %d xRecvResult %d\r\n", ( unsigned ) pxClient->ulSkipCount, ( int ) xRemaining ) ); + pcReadBuffer += 4; + xRemaining -= 4; + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + + if( xRemaining == 0 ) + { + break; + } + + /* fall through */ + case eTCP_2_WaitHeader: + + if( xRemaining > 0 ) + { + char * pcPtr; + pcReadBuffer[ xRemaining ] = '\0'; + FreeRTOS_printf( ( "Control string: %s\r\n", pcReadBuffer ) ); + + for( pcPtr = pcReadBuffer; *pcPtr; pcPtr++ ) + { + if( strncmp( pcPtr, "\"reverse\"", 9 ) == 0 ) + { + pxClient->bits.bReverse = pcPtr[ 10 ] == 't'; + } + else if( strncmp( pcPtr, "\"num\"", 5 ) == 0 ) + { + uint64_t ullAmount; + + /* It is not certain that sscanf() can handle a 64-bit number. */ + if( sscanf64( pcPtr + 6, &( ullAmount ) ) > 0 ) + { + pxClient->ullAmount = ullAmount; + } + } + else if( strncmp( pcPtr, "\"time\"", 6 ) == 0 ) + { + unsigned uSeconds; + + if( sscanf( pcPtr + 7, "%d", &( uSeconds ) ) > 0 ) + { + pxClient->xRemainingTime = uSeconds * 1000U; + pxClient->bits.bTimed = pdTRUE_UNSIGNED; + } + } + } + + if( pxClient->bits.bReverse != pdFALSE_UNSIGNED ) + { + FreeRTOS_printf( ( "Reverse %d send %d bytes timed %d: %d\r\n", + pxClient->bits.bReverse, + ( unsigned ) pxClient->ullAmount, + pxClient->bits.bTimed, + ( unsigned ) pxClient->xRemainingTime ) ); + } + } + + if( pxClient->ulSkipCount > ( uint32_t ) xRemaining ) + { + pxClient->ulSkipCount -= ( uint32_t ) xRemaining; + } + else + { + unsigned char newline[ 1 ] = { '\n' }; + unsigned char onetwo[ 2 ] = { '\1', '\2' }; + FreeRTOS_send( pxClient->xServerSocket, ( const void * ) newline, sizeof( newline ), 0 ); + FreeRTOS_send( pxClient->xServerSocket, ( const void * ) onetwo, sizeof( onetwo ), 0 ); + + pxClient->ulSkipCount = 0; + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + + break; + + case eTCP_3_WaitOneTwo: + { + unsigned char ch = pcReadBuffer[ 0 ]; + unsigned char cr[ 1 ] = { '\r' }; + + FreeRTOS_printf( ( "TCP[ port %d ] recv %d bytes: 0x%02X\r\n", + FreeRTOS_ntohs( pxClient->xRemoteAddr.sin_port ), ( int ) xRecvResult, ch ) ); + + FreeRTOS_send( pxClient->xServerSocket, ( const void * ) cr, sizeof( cr ), 0 ); + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + break; + + case eTCP_4_WaitCount2: + + if( xRemaining < 4 ) + { + break; + } + + { + pxClient->ulSkipCount = + ( ( ( uint32_t ) pcReadBuffer[ 0 ] ) << 24 ) | + ( ( ( uint32_t ) pcReadBuffer[ 1 ] ) << 16 ) | + ( ( ( uint32_t ) pcReadBuffer[ 2 ] ) << 8 ) | + ( ( ( uint32_t ) pcReadBuffer[ 3 ] ) << 0 ); + FreeRTOS_printf( ( "TCP skipcount %d xRecvResult %d\r\n", + ( unsigned ) pxClient->ulSkipCount, + ( unsigned ) xRemaining ) ); + + pcReadBuffer += 4; + xRemaining -= 4; + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + + if( xRemaining == 0 ) + { + break; + } + + /* fall through */ + case eTCP_5_WaitHeader2: + + if( pxClient->ulSkipCount > ( uint32_t ) xRemaining ) + { + pxClient->ulSkipCount -= xRemaining; + } + else + { + char pcResponse[ 200 ]; + uint32_t ulLength, ulStore, ulCount = 0; + + if( pxDataClient != NULL ) + { + ulCount = pxDataClient->ulRecvCount; + } + + ulLength = snprintf( pcResponse + 4, sizeof( pcResponse ) - 4, + "{" + "\"cpu_util_total\":0," + "\"cpu_util_user\":0," + "\"cpu_util_system\":0," + "\"sender_has_retransmits\":0," + "\"streams\":[" + "{" + "\"id\":1," + "\"bytes\":%d," + "\"retransmits\":-1," + "\"jitter\":0," + "\"errors\":0," + "\"packets\":0" + "}" + "]" + "}\xe", + ( unsigned ) ulCount ); + ulStore = FreeRTOS_htonl( ulLength - 1 ); + memcpy( pcResponse, &( ulStore ), sizeof( ulStore ) ); + FreeRTOS_send( pxClient->xServerSocket, ( const void * ) pcResponse, ulLength + 4, 0 ); + + pxClient->ulSkipCount = 0; + pxClient->eTCP_Status = ( eTCP_Server_Status_t ) ( ( ( int ) pxClient->eTCP_Status ) + 1 ); + } + + break; + + case eTCP_6_WaitDone: + break; + + case eTCP_7_WaitTransfer: + break; + } + } +#endif /* ipconfigIPERF_VERSION == 3 */ + +static void vIPerfTCPWork( TcpClient_t * pxClient ) +{ + BaseType_t xRecvResult; + + if( pxClient->xServerSocket == NULL ) + { + vIPerfTCPClose( pxClient ); + return; + } + + #if ( ipconfigIPERF_VERSION == 3 ) + /* Is this a data client with the -R reverse option ? */ + if( ( pxClient->bits.bIsControl == pdFALSE_UNSIGNED ) && ( pxClient->bits.bReverse != pdFALSE_UNSIGNED ) ) + { + if( ( pxClient->bits.bTimed == pdFALSE_UNSIGNED ) && ( pxClient->bits.bHasShutdown == pdFALSE_UNSIGNED ) && ( pxClient->ullAmount == ( uint64_t ) 0U ) ) + { + FreeRTOS_printf( ( "Shutdown connection\r\n" ) ); + FreeRTOS_shutdown( pxClient->xServerSocket, FREERTOS_SHUT_RDWR ); + pxClient->bits.bHasShutdown = pdTRUE_UNSIGNED; + } + } + #endif /* if ( ipconfigIPERF_VERSION == 3 ) */ + + for( ; ; ) + { + #if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) + { + const BaseType_t xRecvSize = 0x10000; + xRecvResult = FreeRTOS_recv( pxClient->xServerSocket, /* The socket being received from. */ + &pcRecvBuffer, /* The buffer into which the received data will be written. */ + xRecvSize, /* Any size is OK here. */ + FREERTOS_ZERO_COPY ); + } + #else + { + const BaseType_t xRecvSize = sizeof pcRecvBuffer; + xRecvResult = FreeRTOS_recv( pxClient->xServerSocket, /* The socket being received from. */ + pcRecvBuffer, /* The buffer into which the received data will be written. */ + sizeof pcRecvBuffer, /* The size of the buffer provided to receive the data. */ + 0 ); + } + #endif /* if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) */ + + if( xRecvResult <= 0 ) + { + break; + } + + pxClient->ulRecvCount += xRecvResult; + + #if ( ipconfigIPERF_VERSION == 3 ) + if( pxClient->eTCP_Status < eTCP_6_WaitDone ) + { + handleRecvPacket( pxClient, pcRecvBuffer, xRecvResult ); + } + #endif /* ipconfigIPERF_VERSION == 3 */ + + #if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) + { + FreeRTOS_recv( pxClient->xServerSocket, /* The socket being received from. */ + NULL, /* The buffer into which the received data will be written. */ + xRecvResult, /* This is important now. */ + 0 ); + } + #endif + } /* for( ;; ) */ + + if( ( xRecvResult == 0 ) && ( pxClient->bits.bIsControl == pdFALSE_UNSIGNED ) && ( pxClient->bits.bReverse != pdFALSE_UNSIGNED ) ) + { + xRecvResult = vIPerfTCPSend( pxClient ); + } + + if( ( xRecvResult < 0 ) && ( xRecvResult != -pdFREERTOS_ERRNO_EAGAIN ) ) + { + vIPerfTCPClose( pxClient ); + } +} + +#if ( ipconfigUSE_CALLBACKS == 0 ) && ( ipconfigIPERF_HAS_UDP != 0 ) + static void vIPerfUDPWork( Socket_t xSocket ) + { + BaseType_t xRecvResult; + struct freertos_sockaddr xAddress; + uint32_t xAddressLength; + + #if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) + { + xRecvResult = FreeRTOS_recvfrom( xSocket, ( void * ) &pcRecvBuffer, sizeof( pcRecvBuffer ), + FREERTOS_ZERO_COPY, &xAddress, &xAddressLength ); + } + #else + { + xRecvResult = FreeRTOS_recvfrom( xSocket, ( void * ) pcRecvBuffer, sizeof( pcRecvBuffer ), + 0, &xAddress, &xAddressLength ); + } + #endif /* ipconfigIPERF_USE_ZERO_COPY */ + + if( xRecvResult > 0 ) + { + ulUDPRecvCount += xRecvResult; + #if ( ipconfigIPERF_DOES_ECHO_UDP != 0 ) + { + FreeRTOS_sendto( xSocket, ( const void * ) pcRecvBuffer, xRecvResult, 0, &xAddress, sizeof( xAddress ) ); + } + #endif /* ipconfigIPERF_DOES_ECHO_UDP */ + #if ( ipconfigIPERF_USE_ZERO_COPY != 0 ) + { + FreeRTOS_ReleaseUDPPayloadBuffer( pcRecvBuffer ); + } + #endif /* ipconfigIPERF_USE_ZERO_COPY */ + } + } +#endif /* ipconfigUSE_CALLBACKS == 0 */ + +#if ( ipconfigUSE_CALLBACKS != 0 ) && ( ipconfigIPERF_HAS_UDP != 0 ) + static BaseType_t xOnUdpReceive( Socket_t xSocket, + void * pvData, + size_t xLength, + const struct freertos_sockaddr * pxFrom, + const struct freertos_sockaddr * pxDest ) + { + ( void ) pvData; + ( void ) pxFrom; + ( void ) pxDest; + + ulUDPRecvCount += xLength; + #if ( ipconfigIPERF_DOES_ECHO_UDP != 0 ) + { + FreeRTOS_sendto( xSocket, ( const void * ) pvData, xLength, 0, pxFrom, sizeof( *pxFrom ) ); + } + #else /* ipconfigIPERF_DOES_ECHO_UDP */ + { + ( void ) xSocket; + } + #endif + /* Tell the driver not to store the RX data */ + return 1; + } +#endif /* ipconfigUSE_CALLBACKS != 0 */ + +#if ( ipconfigIPERF_HAS_TCP != 0 ) + static Socket_t xCreateTCPServerSocket() + { + BaseType_t xBindResult, xListenResult; + struct freertos_sockaddr xEchoServerAddress; + Socket_t xTCPServerSocket; + TickType_t xNoTimeOut = 0; + + xTCPServerSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocketValid( xTCPServerSocket ) ); + + memset( &xEchoServerAddress, '\0', sizeof xEchoServerAddress ); + xEchoServerAddress.sin_port = FreeRTOS_htons( ipconfigIPERF_TCP_ECHO_PORT ); + + /* Set the receive time out to portMAX_DELAY. + * Note that any TCP child connections will inherit this reception time-out. */ + FreeRTOS_setsockopt( xTCPServerSocket, 0, FREERTOS_SO_RCVTIMEO, &xNoTimeOut, sizeof( xNoTimeOut ) ); + + #if ( ipconfigUSE_TCP_WIN == 1 ) + { + WinProperties_t xWinProperties; + + memset( &xWinProperties, '\0', sizeof xWinProperties ); + + xWinProperties.lTxBufSize = ipconfigIPERF_TX_BUFSIZE; /* Units of bytes. */ + xWinProperties.lTxWinSize = ipconfigIPERF_TX_WINSIZE; /* Size in units of MSS */ + xWinProperties.lRxBufSize = ipconfigIPERF_RX_BUFSIZE; /* Units of bytes. */ + xWinProperties.lRxWinSize = ipconfigIPERF_RX_WINSIZE; /* Size in units of MSS */ + + FreeRTOS_setsockopt( xTCPServerSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProperties, sizeof( xWinProperties ) ); + FreeRTOS_printf( ( "vIPerfTask: buffers %d, %d WIN %d x %d, %d x %d\r\n", + xWinProperties.lTxBufSize, + xWinProperties.lRxBufSize, + xWinProperties.lTxWinSize, ipconfigTCP_MSS, + xWinProperties.lRxWinSize, ipconfigTCP_MSS ) ); + } + #endif /* ( ipconfigUSE_TCP_WIN == 1 ) */ + + xBindResult = FreeRTOS_bind( xTCPServerSocket, &xEchoServerAddress, sizeof xEchoServerAddress ); + xListenResult = FreeRTOS_listen( xTCPServerSocket, 4 ); + + FreeRTOS_FD_SET( xTCPServerSocket, xSocketSet, eSELECT_READ ); + + FreeRTOS_printf( ( "vIPerfTask: created TCP server socket %p bind port %d: %d listen %d\r\n", + xTCPServerSocket, ipconfigIPERF_TCP_ECHO_PORT, xBindResult, xListenResult ) ); + + return xTCPServerSocket; + } +#endif /* ipconfigIPERF_HAS_TCP */ + +#if ( ipconfigIPERF_HAS_UDP != 0 ) + static Socket_t xCreateUDPServerSocket() + { + BaseType_t xBindResult; + struct freertos_sockaddr xEchoServerAddress; + TickType_t xNoTimeOut = 0; + Socket_t xUDPServerSocket; + + xUDPServerSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( ( xUDPServerSocket != FREERTOS_INVALID_SOCKET ) && ( xUDPServerSocket != NULL ) ); + + xEchoServerAddress.sin_port = FreeRTOS_htons( ipconfigIPERF_UDP_ECHO_PORT ); + + FreeRTOS_setsockopt( xUDPServerSocket, 0, FREERTOS_SO_RCVTIMEO, &xNoTimeOut, sizeof( xNoTimeOut ) ); + xBindResult = FreeRTOS_bind( xUDPServerSocket, &xEchoServerAddress, sizeof xEchoServerAddress ); + + FreeRTOS_printf( ( "vIPerfTask: created UDP server socket %p bind port %d: %d\r\n", + xUDPServerSocket, ipconfigIPERF_UDP_ECHO_PORT, xBindResult ) ); + #if ( ipconfigUSE_CALLBACKS == 0 ) + { + FreeRTOS_FD_SET( xUDPServerSocket, xSocketSet, eSELECT_READ ); + } + #else + { + F_TCP_UDP_Handler_t xHandler; + + memset( &xHandler, '\0', sizeof( xHandler ) ); + xHandler.pOnUdpReceive = xOnUdpReceive; + FreeRTOS_setsockopt( xUDPServerSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) ); + } + #endif /* ipconfigUSE_CALLBACKS */ + return xUDPServerSocket; + } +#endif /* ipconfigIPERF_HAS_UDP */ + +#if ( ipconfigUSE_IPv6 == 1 ) + static NetworkEndPoint_t * pxFindLocalEndpoint( void ) + { + NetworkEndPoint_t * pxEndPoint; + + for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); + pxEndPoint != NULL; + pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) + { + if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) + { + IPv6_Type_t eType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ); + + if( eType == eIPv6_LinkLocal ) + { + break; + } + } + } + + return pxEndPoint; + } +#endif /* if ( ipconfigUSE_IPv6 == 1 ) */ + +void vIPerfTask( void * pvParameter ) +{ + #if ( ipconfigIPERF_HAS_TCP != 0 ) + Socket_t xTCPServerSocket; + #endif /* ipconfigIPERF_HAS_TCP */ + + #if ( ipconfigIPERF_HAS_UDP != 0 ) + Socket_t xUDPServerSocket; + #endif /* ipconfigIPERF_HAS_UDP */ + + char pcBuffer[ 41 ]; + uint32_t ulAddress; + + ( void ) pvParameter; + + xSocketSet = FreeRTOS_CreateSocketSet(); + + vListInitialise( &xTCPClientList ); + + + #if ( ipconfigIPERF_HAS_TCP != 0 ) + { + xTCPServerSocket = xCreateTCPServerSocket(); + } + #endif /* ipconfigIPERF_HAS_TCP */ + + #if ( ipconfigIPERF_HAS_UDP != 0 ) + { + xUDPServerSocket = xCreateUDPServerSocket(); + ( void ) xUDPServerSocket; + } + #endif /* ipconfigIPERF_HAS_UDP */ + + int8_t cIPAddressString[ 16 ]; + FreeRTOS_inet_ntoa( FreeRTOS_GetIPAddress(), ( char * ) cIPAddressString ); + + FreeRTOS_printf( ( "IMPORTANT: Please test with iPerf3 v3.1.3\r\n" ) ); + FreeRTOS_printf( ( "Use for example:\r\n" ) ); + FreeRTOS_printf( ( "TCP receive: iperf3 -c %s -p %d -n 100M \r\n", + cIPAddressString, ipconfigIPERF_UDP_ECHO_PORT ) ); + FreeRTOS_printf( ( "TCP send: iperf3 -c %s -p %d -n 100M -R\r\n", + cIPAddressString, ipconfigIPERF_UDP_ECHO_PORT ) ); + FreeRTOS_printf( ( "UDP: iperf3 -c %s -p %d -n 1000M -u -b 1000M\r\n", + cIPAddressString, ipconfigIPERF_UDP_ECHO_PORT ) ); + #if ( ipconfigUSE_IPv6 == 1 ) + NetworkEndPoint_t * pxEndpoint = pxFindLocalEndpoint(); + + if( pxEndpoint != NULL ) + { + char pcBuffer[ 41 ]; + FreeRTOS_inet_ntop6( ( void * ) pxEndpoint->ipv6_settings.xIPAddress.ucBytes, + pcBuffer, sizeof pcBuffer ); + FreeRTOS_printf( ( "iperf3 -c %s -6 --port %d --bytes 100M [ -R ]\r\n", + pcBuffer, + ipconfigIPERF_TCP_ECHO_PORT ) ); + } + #endif /* if ( ipconfigUSE_IPv6 == 1 ) */ + +#define HUNDREDTH_MB ( ( 1024 * 1024 ) / 100 ) + + for( ; ; ) + { + BaseType_t xResult; + const TickType_t xBlockingTime = pdMS_TO_TICKS( ipconfigIPERF_LOOP_BLOCKING_TIME_MS ); + + /* Wait at most 5 seconds. */ + xResult = FreeRTOS_select( xSocketSet, xBlockingTime ); + #if ( ipconfigIPERF_HAS_TCP != 0 ) + if( xResult != 0 ) + { + const MiniListItem_t * pxEnd; + const ListItem_t * pxIterator; + + pxEnd = ( const MiniListItem_t * ) listGET_END_MARKER( &xTCPClientList ); + + vIPerfServerWork( xTCPServerSocket ); + + /* Check all TCP clients: */ + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + ) + { + TcpClient_t * pxClient; + + pxClient = ( TcpClient_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + /* Let the iterator point to the next element before the current element + * removes itself from the list. */ + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + + vIPerfTCPWork( pxClient ); + } + } + #endif /* ipconfigIPERF_HAS_TCP */ + + #if ( ipconfigIPERF_HAS_UDP != 0 ) + #if ( ipconfigUSE_CALLBACKS == 0 ) + if( xResult != 0 ) + { + vIPerfUDPWork( xUDPServerSocket ); + } + else + #endif /* ipconfigUSE_CALLBACKS */ + { + if( ulUDPRecvCountSeen != ulUDPRecvCount ) + { + /* The amount is still changing, do not show it yet. */ + ulUDPRecvCountSeen = ulUDPRecvCount; + } + else if( ulUDPRecvCountShown != ulUDPRecvCount ) + { + uint32_t ulNewBytes = ulUDPRecvCount - ulUDPRecvCountShown; + uint32_t ulMB = ( ulNewBytes + HUNDREDTH_MB / 2 ) / HUNDREDTH_MB; + + FreeRTOS_printf( ( "UDP received %d + %d (%d.%02lu MB) = %d\r\n", + ulUDPRecvCountShown, + ulNewBytes, + ulMB / 100, + ulMB % 100, + ulUDPRecvCount ) ); + ulUDPRecvCountShown = ulUDPRecvCount; + } + } + #endif /* ipconfigIPERF_HAS_UDP */ + } +} + +int sscanf64( char * pcString, + uint64_t * pullAmount ) +{ + int retValue = 0; + char * pcSource = pcString; + uint64_t ullAmount = 0U; + + if( isdigit( ( int ) *pcSource ) ) + { + retValue = 1; + + do + { + ullAmount = 10U * ullAmount; + ullAmount += ( uint64_t ) ( *pcSource - '0' ); + pcSource++; + } while( isdigit( ( int ) *pcSource ) ); + } + + *pullAmount = ullAmount; + return retValue; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.h new file mode 100644 index 0000000..76ce8a9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/iperf_task.h @@ -0,0 +1,43 @@ +/* + * FreeRTOS+TCP V2.3.2 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef IPERF_TASK_H_ + +#define IPERF_TASK_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/* This function will start a task that will handle all IPERF requests from outside. +Call it after the IP-stack is up and running. */ + +void vIPerfInstall( void ); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/main.c new file mode 100644 index 0000000..db6b81d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/main.c @@ -0,0 +1,378 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/***************************************************************************** +* Note: This file is Not! to be used as is. The purpose of this file is to provide +* a template for writing a network interface. Each network interface will have to provide +* concrete implementations of the functions in this file. +* +* See the following URL for an explanation of this file and its functions: +* https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html +* +*****************************************************************************/ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" +#include "bsp.h" +#include "riscv.h" +#include "gpio.h" + +/* Demo application includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOSIPConfig.h" +#include "iperf_task.h" + +#define mainHOST_NAME "Efinix" +#define mainDEVICE_NICK_NAME "Sapphire" + +/* + * Just seeds the simple pseudo random number generator. + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialisation including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +//const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/* Prepare hardware to run the demo. */ +static void prvSetupHardware( void ); +/* Send a message to the UART initialised in prvSetupHardware. */ +void vSendString( const char * const pcString ); +/*-----------------------------------------------------------*/ +void vSendString( const char * const pcString ) +{ + bsp_printf(pcString); +} + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL ); + + bsp_init(); + + /* + * Instructions for using this project are provided on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + prvSetupHardware(); + + /* Miscellaneous initialisation including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialise the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the definition of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + /* Start the RTOS scheduler. */ + + + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + bsp_uDelay( ulLongTime_ms ); + } +} + +/*-----------------------------------------------------------*/ +static void prvSetupHardware( void ) +{ + extern void freertos_risc_v_trap_handler(); + csr_write(mtvec, freertos_risc_v_trap_handler); + + vSendString( "***Hello world, this is FreeRTOS iPerf demo***\n\r" ); +} + +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ +const uint32_t ulMSToSleep = 1; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in + FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the + idle task just sleeps to lower the CPU usage. */ + bsp_uDelay( ulMSToSleep ); +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ +const uint32_t ulLongSleep = 1000UL; +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + FreeRTOS_printf( ( "vAssertCalled( %s, %ld\n", pcFile, ulLine ) ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + bsp_uDelay( ulLongSleep ); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ + vIPerfInstall(); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + vAssertCalled( __FILE__, __LINE__ ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + /* Seed the random number generator. */ + prvSRand( ( uint32_t ) 555987 ); + +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( strcasecmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} + +/* + * Supply a random number to FreeRTOS+TCP stack. + * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER + * SO IS NOT INTENDED FOR USE IN PRODUCTION SYSTEMS. + */ +BaseType_t xApplicationGetRandomNumber(uint32_t* pulNumber) +{ + *(pulNumber) = uxRand(); + return pdTRUE; +} +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} + + +void vApplicationTickHook( void ) +{ + extern void vFullDemoTickHook( void ); +} + +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) +{ + +} + +eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ + ( void ) ( pxNetworkBuffer ); + return eProcessBuffer; +} + +/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ +static StaticTask_t xIdleTaskTCBBuffer; +static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; + *ppxIdleTaskStackBuffer = &xIdleStack[0]; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + /* place for user code */ +} +/* USER CODE END GET_IDLE_TASK_MEMORY */ + +/* USER CODE BEGIN GET_TIMER_TASK_MEMORY */ +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} +/* USER CODE END GET_TIMER_TASK_MEMORY */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/userDef.h new file mode 100644 index 0000000..6a974a2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosIperfDemo/src/userDef.h @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "bsp.h" + +/************************** Project Header File ***************************/ +#define DEBUG_PRINTF_EN 0 +#define TEST_MODE 0 //0:Normal Mode; 1:Link partner Test Mode; +#define PAT_NUM 0 +#define PAT_DLEN 8 +#define PAT_IPG 4095 +#define PAT_TYPE 0 //0:UDP Pattern; //1:MAC Pattern; +#define DST_MAC_H 0xffff +#define DST_MAC_L 0xffffffff +#define SRC_MAC_H (configMAC_ADDR5<<8)|configMAC_ADDR4 +#define SRC_MAC_L (configMAC_ADDR3<<24)|(configMAC_ADDR2<<16)|(configMAC_ADDR1<<8)|configMAC_ADDR0//0x5e0060c8 +#define SRC_IP (configIP_ADDR3<<24)|(configIP_ADDR2<<16)|(configIP_ADDR1<<8)|configIP_ADDR0 +#define DST_IP 0xc0a80165 +#define SRC_PORT 0x0521 +#define DST_PORT 0x2715 +#define RX_HANDLER_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/************************** System Header File ***************************/ +#define PHY_ADDR 0x0 + +/************************** HW Header File ***************************/ +#define TSEMAC_BASE 0xe9100000 +#define TSEMAC_DMASG_BASE IO_APB_SLAVE_0_INPUT +#define TSE_DMASG_RX_CH 0 +#define TSE_RX_INTR SYSTEM_PLIC_USER_INTERRUPT_G_INTERRUPT +#define TSE_DMASG_TX_CH 1 +#define TSE_TX_INTR SYSTEM_PLIC_USER_INTERRUPT_H_INTERRUPT +#define TSE_Speed_1000Mhz 0x04 +#define TSE_Speed_100Mhz 0x02 +#define TSE_Speed_10Mhz 0x01 + +/************************** Application Header File ***************************/ +#define TX_ENA_MASK 0xFFFFFFFE +#define RX_ENA_MASK 0xFFFFFFFD +#define XON_GEN_MASK 0xFFFFFFFB +#define PROMIS_EN_MASK 0xFFFFFFEF +#define PAD_EN_MASK 0xFFFFFFDF +#define CRC_FWD_MASK 0xFFFFFFBF +#define PAUSE_IGNORE_MASK 0xFFFFFEFF +#define TX_ADDR_INS_MASK 0xFFFFFBFF +#define LOOP_ENA_MASK 0xFFFF7FFF +#define ETH_SPEED_MASK 0xFFF8FFFF +#define XOFF_GEN_MASK 0xFFBFFFFF +#define CNT_RST_MASK 0x7FFFFFFF + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/makefile new file mode 100644 index 0000000..c8a0c33 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/makefile @@ -0,0 +1,47 @@ +PROJ_NAME=freertosMqttPlainTextDemo + +STANDALONE = .. + +FREERTOS=${FreeRTOS_KERNEL_SRC}/FreeRTOS/${FreeRTOS_KERNEL_SRC_DIR} +FREERTOS_RISCV=${FREERTOS}/portable/GCC/RISC-V +FREERTOS_TCP=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/source +FREERTOS_UTILITIES=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/Utilities +FREERTOS_PROTOCOLS=${FreeRTOS_KERNEL_SRC}/FreeRTOS-Plus/Source/Application-Protocols +FREERTOS_MQTT=${FREERTOS_PROTOCOLS}/coreMQTT/source +FREERTOS_BACKOFF=${FREERTOS_UTILITIES}/backoff_algorithm/source +FREERTOS_TRANSPORT=${FREERTOS_PROTOCOLS}/network_transport + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${FREERTOS}/*.c) \ + $(wildcard ${FREERTOS_TCP}/*.c) \ + $(wildcard ${FREERTOS_MQTT}/*.c) \ + ${FREERTOS}/portable/MemMang/heap_4.c \ + ${FREERTOS_TCP}/portable/BufferManagement/BufferAllocation_2.c \ + ${FREERTOS_UTILITIES}/backoff_algorithm/source/backoff_algorithm.c \ + ${FREERTOS_TRANSPORT}/transport_plaintext.c \ + ${FREERTOS_TRANSPORT}/tcp_sockets_wrapper/ports/freertos_plus_tcp/tcp_sockets_wrapper.c \ + ${FREERTOS_RISCV}/port.c \ + ${FREERTOS_RISCV}/portASM.S \ + ${STANDALONE}/common/start.S + +CFLAGS += -Isrc +CFLAGS += -I../driver +CFLAGS += -I${FREERTOS}/include +CFLAGS += -I${FREERTOS_TCP}/include +CFLAGS += -I${FREERTOS_TCP}/portable/Compiler/GCC +CFLAGS += -I${FREERTOS_RISCV} +CFLAGS += -I${FREERTOS_UTILITIES}/logging +CFLAGS += -I${FREERTOS_MQTT}/include +CFLAGS += -I${FREERTOS_MQTT}/interface +CFLAGS += -I${FREERTOS_BACKOFF}/include +CFLAGS += -I${FREERTOS_TRANSPORT} +CFLAGS += -I${FREERTOS_TRANSPORT}/tcp_sockets_wrapper/include +CFLAGS += -DportasmHANDLE_INTERRUPT=freertos_risc_v_application_interrupt_handler + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/freertos.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSConfig.h new file mode 100644 index 0000000..6f8ec0e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSConfig.h @@ -0,0 +1,226 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bsp.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15U * 1024U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Currently the TCP/IP stack is using dynamic allocation, and the MQTT task is + * using static allocation. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* The function that implements FreeRTOS printf style output, and the macro + * that maps the configPRINTF() macros to that function. */ +void vLoggingPrintf( char const * pcFormat, + ... ); + +#define configPRINTF( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT( X ) bsp_printf X + +/* Non-format version thread-safe print. */ +#define configPRINT_STRING( X ) bsp_printf X + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace + * macros are defined to gather some UDP stack statistics that can then be viewed + * through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there + * are multiple command interpreters running at once (for example, one on a UART + * and one on TCP/IP). This is done to prevent an output buffer being defined by + * each implementation - which would waste RAM. In this case, there is only one + * command interpreter running, and it has its own local output buffer, so the + * global buffer is just set to be one byte long as it is not used and should not + * take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE ( 0L ) + +/* The address of an echo server that will be used by the two demo echo client + * tasks: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 31 +#define configECHO_SERVER_ADDR3 6 +#define configTCP_ECHO_CLIENT_PORT 7 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x32 + +/* Default IP address configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DHCP is set to + * 0, or ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 192 +#define configGATEWAY_ADDR1 168 +#define configGATEWAY_ADDR2 31 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. Google DNS addresses are 8.8.8.8 and + * 8.8.4.4. Used in ipconfigUSE_DHCP is set to 0, or ipconfigUSE_DHCP is + * set to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 8 +#define configDNS_SERVER_ADDR1 8 +#define configDNS_SERVER_ADDR2 8 +#define configDNS_SERVER_ADDR3 8 + +/* Default netmask configuration. Used in ipconfigUSE_DHCP is set to 0, or + * ipconfigUSE_DHCP is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configPROFILING ( 0 ) + +/* Pseudo random number generator used by some tasks. */ +extern uint32_t ulRand( void ); +#define configRAND32() ulRand() + +/* The platform that FreeRTOS is running on. */ +#define configPLATFORM_NAME "Efinix_FPGA" + +// Freertos specifics +#define configMTIME_BASE_ADDRESS (BSP_CLINT + 0xBFF8) +#define configMTIMECMP_BASE_ADDRESS (BSP_CLINT + 0x4000) +#define configCPU_CLOCK_HZ ( ( uint32_t ) ( BSP_CLINT_HZ ) ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSIPConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSIPConfig.h new file mode 100644 index 0000000..3db5b66 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/FreeRTOSIPConfig.h @@ -0,0 +1,334 @@ +/* + * FreeRTOS+TCP V4.3.1 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/***************************************************************************** +* +* See the following URL for configuration information. +* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html +* +*****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +#define ipconfigUSE_IPv4 ( 1 ) + +#define ipconfigUSE_IPv6 ( 0 ) + +#define ipconfigUSE_DHCPv6 0 +#define ipconfigIPv4_BACKWARD_COMPATIBLE 1 +#define ipconfigUSE_ARP_REVERSED_LOOKUP 1 +#define ipconfigUSE_ARP_REMOVE_ENTRY 1 +#define ipconfigARP_STORES_REMOTE_ADDRESSES 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 +#define ipconfigFORCE_IP_DONT_FRAGMENT 1 +#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS 1 +#define ipconfigDHCP_FALL_BACK_AUTO_IP 1 +#define ipconfigARP_USE_CLASH_DETECTION 1 +#define ipconfigUSE_LLMNR 1 +#define ipconfigUSE_NBNS 1 +#define ipconfigUSE_MDNS 1 +#define ipconfigSUPPORT_OUTGOING_PINGS 1 +#define ipconfigETHERNET_DRIVER_FILTERS_PACKETS 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1 +#define ipconfigSOCKET_HAS_USER_SEMAPHORE 1 +#define ipconfigSELECT_USES_NOTIFY 1 +#define ipconfigSUPPORT_SIGNALS 1 +#define ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES 1 +#define ipconfigDNS_USE_CALLBACKS 1 +#define ipconfigIGNORE_UNKNOWN_PACKETS 1 +#define ipconfigCHECK_IP_QUEUE_SPACE 1 +#define ipconfigUDP_MAX_RX_PACKETS 1 +#define ipconfigETHERNET_MINIMUM_PACKET_BYTES 1 +#define ipconfigTCP_IP_SANITY 1 +#define ipconfigSUPPORT_NETWORK_DOWN_EVENT 1 + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf( X ) bsp_printf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 1 +#if ( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf( X ) bsp_printf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing + * on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading then set + * ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software + * stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been + * performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be + * set per socket, using setsockopt(). If not set, the times below will be + * used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very + * useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low + * and also DNS may use small timeouts. If a DNS reply comes in after the DNS + * socket has been destroyed, the result will be stored into the cache. The next + * call to FreeRTOS_gethostbyname() will return immediately, without even creating + * a socket. + */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ( 6 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make + * use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY + * sets the priority of the task that executes the IP stack. The priority is a + * standard FreeRTOS task priority so can take any value from 0 (the lowest + * priority) to (configMAX_PRIORITIES - 1) (the highest priority). + * configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in + * FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to + * the priority assigned to the task executing the IP stack relative to the + * priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP + * task. This setting is less important when the FreeRTOS Win32 simulator is used + * as the Win32 simulator only stores a fixed amount of information on the task + * stack. FreeRTOS includes optional stack overflow detection, see: + * http://www.freertos.org/Stacks-and-stack-overflow-checking.html. */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the + * network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK + * is not set to 1 then the network event hook will never be called. See: + * https://freertos.org/Documentation/03-Libraries/02-FreeRTOS-plus/02-FreeRTOS-plus-TCP/09-API-reference/57-vApplicationIPNetworkEventHook. + */ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but + * a network buffer cannot be obtained then the calling task is held in the Blocked + * state (so other tasks can continue to executed) until either a network buffer + * becomes available or the send block time expires. If the send block time expires + * then the send operation is aborted. The maximum allowable send block time is + * capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the + * maximum allowable send block time prevents prevents a deadlock occurring when + * all the network buffers are in use and the tasks that process (and subsequently + * free) the network buffers are themselves blocked waiting for a network buffer. + * ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in + * milliseconds can be converted to a time in ticks by dividing the time in + * milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000U / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP + * address, netmask, DNS server address and gateway address from a DHCP server. If + * ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The + * stack will revert to using the static IP address even when ipconfigUSE_DHCP is + * set to 1 if a valid configuration cannot be obtained from a DHCP server for any + * reason. The static configuration used is that passed into the stack by the + * FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 0 +#define ipconfigDHCP_REGISTER_HOSTNAME 1 +#define ipconfigDHCP_USES_UNICAST 1 + +/* If ipconfigDHCP_USES_USER_HOOK is set to 1 then the application writer must + * provide an implementation of the DHCP callback function, + * xApplicationDHCPUserHook(). */ +#define ipconfigUSE_DHCP_HOOK 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at + * increasing time intervals until either a reply is received from a DHCP server + * and accepted, or the interval between transmissions reaches + * ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the + * static IP address passed as a parameter to FreeRTOS_IPInit() if the + * re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without + * a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD \ + ( 120000U / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP + * stack can only send a UDP message to a remove IP address if it knowns the MAC + * address associated with the IP address, or the MAC address of the router used to + * contact the remote IP address. When a UDP message is received from a remote IP + * address the MAC address and IP address are added to the ARP cache. When a UDP + * message is sent to a remote IP address that does not already appear in the ARP + * cache then the UDP message is replaced by a ARP message that solicits the + * required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum + * number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a + * maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is + * aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP + * table being created or refreshed and the entry being removed because it is stale. + * New ARP requests are sent for ARP cache entries that are nearing their maximum + * age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is + * equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling + * routines, which are relatively large. To save code space the full + * FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster + * alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() + * takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. + * FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets + * (for example, 192, 168, 0, 1) as its parameters. If + * ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and + * FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is + * not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that + * are available to the IP stack. The total number of network buffers is limited + * to ensure the total amount of RAM that can be consumed by the IP stack is capped + * to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP + * stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can + * be queued for processing at any one time. The event queue must be a minimum of + * 5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH \ + ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port + * number. FreeRTOS_bind() is used to manually allocate a port number to a socket + * (to 'bind' the socket to a port), but manual binding is not normally necessary + * for client sockets (those sockets that initiate outgoing connections rather than + * wait for incoming connections on a known port number). If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling + * FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP + * stack automatically binding the socket to a port number from the range + * socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() + * on a socket that has not yet been bound will result in the send operation being + * aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +/* Also defined in FreeRTOSIPConfigDefaults.h. */ +#define ipconfigTCP_TIME_TO_LIVE 128 + +/* USE_TCP: Use TCP and all its features. */ +#define ipconfigUSE_TCP ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can + * contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a + * lower value can save RAM, depending on the buffer management scheme used. If + * ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must + * be divisible by 8. */ +#define ipconfigNETWORK_MTU 1500U + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used + * through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will + * generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the + * FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 1 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() + * (and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames + * that are not in Ethernet II format will be dropped. This option is included for + * potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the + * responsibility of the Ethernet interface to filter out packets that are of no + * interest. If the Ethernet interface does not implement this functionality, then + * set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack + * perform the filtering instead (it is much less efficient for the stack to do it + * because the packet will already have been passed into the stack). If the + * Ethernet driver does all the necessary filtering in hardware then software + * filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to + * block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with + * 32-bit memory instructions, all packets will be stored 32-bit-aligned, + * plus 16-bits. This has to do with the contents of the IP-packets: all + * 32-bit fields are 32-bit-aligned, plus 16-bit. */ +#define ipconfigPACKET_FILLER_SIZE 2U + +/* Define the size of the pool of TCP window descriptors. On the average, each + * TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 + * outstanding packets (for Rx and Tx). When using up to 10 TP sockets + * simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed + * maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 10000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 10000 ) + +/* When using call-back handlers, the driver may check if the handler points to + * real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* Seconds. */ + +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK ( 1 ) +#define ipconfigUSE_CALLBACKS ( 1 ) + + +#define portINLINE __inline + +#define ipconfigISO_STRICTNESS_VIOLATION_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + +#define ipconfigISO_STRICTNESS_VIOLATION_END _Pragma("GCC diagnostic pop") + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/NetworkInterface.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/NetworkInterface.c new file mode 100644 index 0000000..de42399 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/NetworkInterface.c @@ -0,0 +1,337 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "list.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* Efinix includes. */ +#include "userDef.h" +#include "dmasg.h" +#include "rtl8211fd.h" +#include "efx_tse_mac.h" +#include "plic.h" +#include "riscv.h" + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet + * driver will filter incoming packets and only pass the stack those packets it + * considers need processing. */ +#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +#define FRAME_PACKET 256 +#define BUFFER_SIZE 1519 + +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +typedef struct { + uint8_t* pucEthernetBuffer; + size_t xDataLength; +} DMADescriptor_t; +DMADescriptor_t tx_desc; + +static BaseType_t InitialiseNetwork( void ); +static u32 ReceiveSize(void); +static void interrupt_init(); +static void program_descriptor(); +static void userInterrupt(); +static void crash(); +static void prvEMACDeferredInterruptHandlerTask( void *pvParameters ); +static void prvNetworkInterfaceInput( void ); +static struct dmasg_descriptor* pxGetNextTransmitBuffer(void); +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void); +void freertos_risc_v_application_interrupt_handler(); + +u32 rx_cur_desc = 0; +u32 tx_cur_desc = 0; +u32 ulPHYLinkStatus = 0; +volatile struct dmasg_descriptor rx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); +volatile struct dmasg_descriptor tx_dmasg_desc[FRAME_PACKET] __attribute__ ((aligned (64))); + +static TaskHandle_t xRxTaskHandle = NULL; + +BaseType_t xNetworkInterfaceInitialise( void ) +{ + BaseType_t xReturn; + + if( InitialiseNetwork() == 0 ) { + xReturn = pdFAIL; + } else { + xReturn = pdPASS; + } + + return xReturn; +} + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) +{ + // Currently, hardware only supports TCP/UDP checksums, IP and ICMP checksum still need to be done in software + #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) pxDescriptor->pucEthernetBuffer; + + if( xProtPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xICMPPacket.xIPHeader ); + usGenerateProtocolChecksum( ( uint8_t * ) &( xProtPacket->xICMPPacket ), pxDescriptor->xDataLength, pdTRUE ); + } else if( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) { + IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + } + } + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + + struct dmasg_descriptor *pxTransmitBuffer = pxGetNextTransmitBuffer(); + + pxTransmitBuffer->from = (u32)pxDescriptor->pucEthernetBuffer; + pxTransmitBuffer->control = (u32)((pxDescriptor->xDataLength)-1) | 1 << 30; + pxTransmitBuffer->status = 0; + + while(dmasg_busy(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH)); + dmasg_input_memory (TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, pxTransmitBuffer->from, 64); + dmasg_output_stream(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0, 0, 1); + dmasg_interrupt_config(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, DMASG_CHANNEL_INTERRUPT_DESCRIPTOR_COMPLETION_MASK); + dmasg_linked_list_start(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, (u32) pxTransmitBuffer); + + iptraceNETWORK_INTERFACE_TRANSMIT(); + + if(xReleaseAfterSend != pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } + + return pdTRUE; +} + +BaseType_t xGetPhyLinkStatus( void ) +{ + if(ulPHYLinkStatus) { + return pdPASS; + } else { + return pdFALSE; + } +} + +static BaseType_t InitialiseNetwork( void ) +{ + int speed,Value,reg; + BaseType_t xReturn = pdFAIL; + + ulPHYLinkStatus=0; + + MacRst(1, 1); + + rtl8211_drv_init(); + speed=rtl8211_drv_linkup(); + + if((speed == TSE_Speed_1000Mhz) || (speed == TSE_Speed_100Mhz) || (speed == TSE_Speed_10Mhz)) { + MacNormalInit(speed); + + ulPHYLinkStatus=1; + + interrupt_init(); + program_descriptor(); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_RX_CH, 0, 0); + dmasg_priority(TSEMAC_DMASG_BASE, TSE_DMASG_TX_CH, 0, 0); + + xTaskCreate( prvEMACDeferredInterruptHandlerTask,"ETHER_TASK",configMINIMAL_STACK_SIZE*4,NULL,RX_HANDLER_PRIORITY, &xRxTaskHandle); + + xReturn = pdPASS; + } + + return xReturn; +} + +static void interrupt_init() +{ + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_priority(BSP_PLIC, TSE_RX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_RX_INTR, 1); + plic_set_priority(BSP_PLIC, TSE_TX_INTR, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_TX_INTR, 1); + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +static void program_descriptor() +{ + size_t uRequestedBytes = BUFFER_SIZE; + for (int j=0; jpucEthernetBuffer; + + pxDescriptor->pucEthernetBuffer = (uint8_t*)(u32)(pxReceiveBuffer->to); + pxDescriptor->xDataLength = ReceiveSize(); + + pxReceiveBuffer->to = (u32)pucTemp; + + *((NetworkBufferDescriptor_t **) (pxDescriptor->pucEthernetBuffer - ipBUFFER_PADDING) ) = pxDescriptor; + + if(eConsiderFrameForProcessing(pxDescriptor->pucEthernetBuffer) == eProcessBuffer) { + IPStackEvent_t xRxEvent; + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = (void*) pxDescriptor; + + if(xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + iptraceETHERNET_RX_EVENT_LOST(); + } else { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } else { + vReleaseNetworkBufferAndDescriptor(pxDescriptor); + } +} + +static struct dmasg_descriptor* pxGetNextReceiveBuffer(void) { + return (struct dmasg_descriptor*)&rx_dmasg_desc[rx_cur_desc]; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/PlaintextMQTTExample.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/PlaintextMQTTExample.c new file mode 100644 index 0000000..f98d467 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/PlaintextMQTTExample.c @@ -0,0 +1,1103 @@ +/* + * FreeRTOS V202212.01 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* + * Demo for showing use of the managed MQTT API. + * + * The example shown below uses this API to create MQTT messages and + * send them over the connection established using FreeRTOS sockets. + * The example is single threaded and uses statically allocated memory; + * + * !!! NOTE !!! + * This MQTT demo does not authenticate the server nor the client. + * Hence, this demo should not be used as production ready code. + * + * Also see https://www.freertos.org/mqtt/mqtt-agent-demo.html? for an + * alternative run time model whereby coreMQTT runs in an autonomous + * background agent task. Executing the MQTT protocol in an agent task + * removes the need for the application writer to explicitly manage any MQTT + * state or call the MQTT_ProcessLoop() API function. Using an agent task + * also enables multiple application tasks to more easily share a single + * MQTT connection. + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Demo Specific configs. */ +#include "demo_config.h" + +/* MQTT library includes. */ +#include "core_mqtt.h" + +/* Exponential backoff retry include. */ +#include "backoff_algorithm.h" + +/* Transport interface implementation include header for plaintext connection. */ +#include "transport_plaintext.h" + +/*-----------------------------------------------------------*/ + +/* Compile time error for undefined configs. */ +#ifndef democonfigMQTT_BROKER_ENDPOINT + #error "Define the config democonfigMQTT_BROKER_ENDPOINT by following the instructions in file demo_config.h." +#endif +/*-----------------------------------------------------------*/ + +/* Default values for configs. */ +#ifndef democonfigCLIENT_IDENTIFIER + +/** + * @brief The MQTT client identifier used in this example. Each client identifier + * must be unique so edit as required to ensure no two clients connecting to the + * same broker use the same client identifier. + * + * @note Appending __TIME__ to the client id string will help to create a unique + * client id every time an application binary is built. Only a single instance of + * this application's compiled binary may be used at a time, since the client ID + * will always be the same. + */ + #define democonfigCLIENT_IDENTIFIER "testClient"__TIME__ +#endif + +#ifndef democonfigMQTT_BROKER_PORT + +/** + * @brief The port to use for the demo. + */ + #define democonfigMQTT_BROKER_PORT ( 8883 ) +#endif + +/*-----------------------------------------------------------*/ +BaseType_t xPlatformIsNetworkUp( void ); +extern UBaseType_t uxRand( void ); +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + +/** + * @brief Timeout for receiving CONNACK packet in milliseconds. + */ +#define mqttexampleCONNACK_RECV_TIMEOUT_MS ( 1000U ) + +/** + * @brief The prefix to the topic(s) subscribe(d) to and publish(ed) to in the example. + * + * The topic name starts with the client identifier to ensure that each demo + * interacts with a unique topic name. + */ +#define mqttexampleTOPIC_PREFIX democonfigCLIENT_IDENTIFIER "/example/topic" + +/** + * @brief The number of topic filters to subscribe. + */ +#define mqttexampleTOPIC_COUNT ( 3 ) + +/** + * @brief The size of the buffer for each topic string. + */ +#define mqttexampleTOPIC_BUFFER_SIZE ( 100U ) + +/** + * @brief The MQTT message published in this example. + */ +#define mqttexampleMESSAGE "Hello World!" + +/** + * @brief Time in ticks to wait between each cycle of the demo implemented + * by prvMQTTDemoTask(). + */ +#define mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) ) + +/** + * @brief Timeout for MQTT_ProcessLoop in milliseconds. + */ +#define mqttexamplePROCESS_LOOP_TIMEOUT_MS ( 500U ) + +/** + * @brief The keep-alive timeout period reported to the broker while establishing + * an MQTT connection. + * + * It is the responsibility of the client to ensure that the interval between + * control packets being sent does not exceed this keep-alive value. In the + * absence of sending any other control packets, the client MUST send a + * PINGREQ packet. + */ +#define mqttexampleKEEP_ALIVE_TIMEOUT_SECONDS ( 60U ) + +/** + * @brief Delay (in ticks) between consecutive cycles of MQTT publish operations in a + * demo iteration. + * + * Note that the process loop also has a timeout, so the total time between + * publishes is the sum of the two delays. + */ +#define mqttexampleDELAY_BETWEEN_PUBLISHES_TICKS ( pdMS_TO_TICKS( 2000U ) ) + +/** + * @brief Transport timeout in milliseconds for transport send and receive. + */ +#define mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS ( 200U ) + +/** + * @brief The length of the outgoing publish records array used by the coreMQTT + * library to track QoS > 0 packet ACKS for outgoing publishes. + */ +#define mqttexampleOUTGOING_PUBLISH_RECORD_LEN ( 10U ) + +/** + * @brief The length of the incoming publish records array used by the coreMQTT + * library to track QoS > 0 packet ACKS for incoming publishes. + */ +#define mqttexampleINCOMING_PUBLISH_RECORD_LEN ( 10U ) + +/** + * @brief Milliseconds per second. + */ +#define MILLISECONDS_PER_SECOND ( 1000U ) + +/** + * @brief Milliseconds per FreeRTOS tick. + */ +#define MILLISECONDS_PER_TICK ( MILLISECONDS_PER_SECOND / configTICK_RATE_HZ ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Each compilation unit that consumes the NetworkContext must define it. + * It should contain a single pointer to the type of your desired transport. + * When using multiple transports in the same compilation unit, define this pointer as void *. + * + * @note Transport stacks are defined in FreeRTOS-Plus/Source/Application-Protocols/network_transport. + */ +struct NetworkContext +{ + PlaintextTransportParams_t * pParams; +}; + +/*-----------------------------------------------------------*/ + +/** + * @brief The task used to demonstrate the MQTT API. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvMQTTDemoTask( void * pvParameters ); + +/** + * @brief Connect to MQTT broker with reconnection retries. + * + * If connection fails, retry is attempted after a timeout. + * Timeout value will exponentially increase until the maximum + * timeout value is reached or the number of attempts are exhausted. + * + * @param[out] pxNetworkContext The output parameter to return the created network context. + * + * @return The status of the final connection attempt. + */ +static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext_t * pxNetworkContext ); + +/** + * @brief Sends an MQTT Connect packet over the already connected TLS over TCP connection. + * + * @param[in, out] pxMQTTContext MQTT context pointer. + * @param[in] xNetworkContext network context. + */ +static void prvCreateMQTTConnectionWithBroker( MQTTContext_t * pxMQTTContext, + NetworkContext_t * pxNetworkContext ); + +/** + * @brief Function to update variable #Context with status + * information from Subscribe ACK. Called by the event callback after processing + * an incoming SUBACK packet. + * + * @param[in] Server response to the subscription request. + */ +static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ); + +/** + * @brief Subscribes to the topic as specified in mqttexampleTOPIC at the top of + * this file. In the case of a Subscribe ACK failure, then subscription is + * retried using an exponential backoff strategy with jitter. + * + * @param[in] pxMQTTContext MQTT context pointer. + */ +static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ); + +/** + * @brief Publishes a message mqttexampleMESSAGE on mqttexampleTOPIC topic. + * + * @param[in] pxMQTTContext MQTT context pointer. + */ +static void prvMQTTPublishToTopics( MQTTContext_t * pxMQTTContext ); + +/** + * @brief Unsubscribes from the previously subscribed topic as specified + * in mqttexampleTOPIC. + * + * @param[in] pxMQTTContext MQTT context pointer. + */ +static void prvMQTTUnsubscribeFromTopics( MQTTContext_t * pxMQTTContext ); + +/** + * @brief The timer query function provided to the MQTT context. + * + * @return Time in milliseconds. + */ +static uint32_t prvGetTimeMs( void ); + +/** + * @brief Process a response or ack to an MQTT request (PING, PUBLISH, + * SUBSCRIBE or UNSUBSCRIBE). This function processes PINGRESP, PUBACK, + * PUBREC, PUBREL, PUBCOMP, SUBACK, and UNSUBACK. + * + * @param[in] pxIncomingPacket is a pointer to structure containing deserialized + * MQTT response. + * @param[in] usPacketId is the packet identifier from the ack received. + */ +static void prvMQTTProcessResponse( MQTTPacketInfo_t * pxIncomingPacket, + uint16_t usPacketId ); + +/** + * @brief Process incoming Publish message. + * + * @param[in] pxPublishInfo is a pointer to structure containing deserialized + * Publish message. + */ +static void prvMQTTProcessIncomingPublish( MQTTPublishInfo_t * pxPublishInfo ); + +/** + * @brief The application callback function for getting the incoming publishes, + * incoming acks, and ping responses reported from the MQTT library. + * + * @param[in] pxMQTTContext MQTT context pointer. + * @param[in] pxPacketInfo Packet Info pointer for the incoming packet. + * @param[in] pxDeserializedInfo Deserialized information from the incoming packet. + */ +static void prvEventCallback( MQTTContext_t * pxMQTTContext, + MQTTPacketInfo_t * pxPacketInfo, + MQTTDeserializedInfo_t * pxDeserializedInfo ); + +/** + * @brief Call #MQTT_ProcessLoop in a loop for the duration of a timeout or + * #MQTT_ProcessLoop returns a failure. + * + * @param[in] pMqttContext MQTT context pointer. + * @param[in] ulTimeoutMs Duration to call #MQTT_ProcessLoop for. + * + * @return Returns the return value of the last call to #MQTT_ProcessLoop. + */ +static MQTTStatus_t prvProcessLoopWithTimeout( MQTTContext_t * pMqttContext, + uint32_t ulTimeoutMs ); + +/** + * @brief Initialize the topic filter string and SUBACK buffers. + */ +static void prvInitializeTopicBuffers( void ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Static buffer used to hold MQTT messages being sent and received. + */ +static uint8_t ucSharedBuffer[ democonfigNETWORK_BUFFER_SIZE ]; + +/** + * @brief Global entry time into the application to use as a reference timestamp + * in the #prvGetTimeMs function. #prvGetTimeMs will always return the difference + * between the current time and the global entry time. This will reduce the chances + * of overflow for the 32 bit unsigned integer used for holding the timestamp. + */ +static uint32_t ulGlobalEntryTimeMs; + +/** + * @brief Packet Identifier generated when Publish request was sent to the broker; + * it is used to match received Publish ACK to the transmitted Publish packet. + */ +static uint16_t usPublishPacketIdentifier; + +/** + * @brief Packet Identifier generated when Subscribe request was sent to the broker; + * it is used to match received Subscribe ACK to the transmitted Subscribe packet. + */ +static uint16_t usSubscribePacketIdentifier; + +/** + * @brief Packet Identifier generated when Unsubscribe request was sent to the broker; + * it is used to match received Unsubscribe response to the transmitted Unsubscribe + * request. + */ +static uint16_t usUnsubscribePacketIdentifier; + +/** + * @brief A pair containing a topic filter and its SUBACK status. + */ +typedef struct topicFilterContext +{ + uint8_t pcTopicFilter[ mqttexampleTOPIC_BUFFER_SIZE ]; + MQTTSubAckStatus_t xSubAckStatus; +} topicFilterContext_t; + +/** + * @brief An array containing the context of a SUBACK; the SUBACK status + * of a filter is updated when the event callback processes a SUBACK. + */ +static topicFilterContext_t xTopicFilterContext[ mqttexampleTOPIC_COUNT ]; + + +/** @brief Static buffer used to hold MQTT messages being sent and received. */ +static MQTTFixedBuffer_t xBuffer = +{ + ucSharedBuffer, + democonfigNETWORK_BUFFER_SIZE +}; + +/** + * @brief Array to track the outgoing publish records for outgoing publishes + * with QoS > 0. + * + * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. + * + */ +static MQTTPubAckInfo_t pOutgoingPublishRecords[ mqttexampleOUTGOING_PUBLISH_RECORD_LEN ]; + +/** + * @brief Array to track the incoming publish records for incoming publishes + * with QoS > 0. + * + * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. + * + */ +static MQTTPubAckInfo_t pIncomingPublishRecords[ mqttexampleINCOMING_PUBLISH_RECORD_LEN ]; + +/*-----------------------------------------------------------*/ + +/* + * @brief Create the task that demonstrates the MQTT API Demo over a + * server-authenticated network connection with MQTT broker. + */ +void vStartSimpleMQTTDemo( void ) +{ + /* This example uses a single application task, which in turn is used to + * connect, subscribe, publish, unsubscribe, and disconnect from the MQTT + * broker. + * + * Also see https://www.freertos.org/mqtt/mqtt-agent-demo.html? for an + * alternative run time model whereby coreMQTT runs in an autonomous + * background agent task. Executing the MQTT protocol in an agent task + * removes the need for the application writer to explicitly manage any MQTT + * state or call the MQTT_ProcessLoop() API function. Using an agent task + * also enables multiple application tasks to more easily share a single + * MQTT connection. */ + xTaskCreate( prvMQTTDemoTask, /* Function that implements the task. */ + "DemoTask", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + 3, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +/* + * @brief The Example shown below uses MQTT APIs to create MQTT messages and + * send them over the server-authenticated network connection established with the + * MQTT broker. This example is single-threaded and uses statically allocated + * memory. It uses QoS2 for sending and receiving messages from the broker. + * + * This MQTT client subscribes to the topic as specified in mqttexampleTOPIC at the + * top of this file by sending a subscribe packet and waiting for a subscribe + * acknowledgment (SUBACK) from the broker. The client will then publish to the + * same topic it subscribed to, therefore expecting that all outgoing messages will be + * sent back from the broker. + */ +static void prvMQTTDemoTask( void * pvParameters ) +{ + uint32_t ulPublishCount = 0U, ulTopicCount = 0U; + const uint32_t ulMaxPublishCount = 5UL; + NetworkContext_t xNetworkContext = { 0 }; + PlaintextTransportParams_t xPlaintextTransportParams = { 0 }; + MQTTContext_t xMQTTContext = { 0 }; + MQTTStatus_t xMQTTStatus; + PlaintextTransportStatus_t xNetworkStatus; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* Set the pParams member of the network context with desired transport. */ + xNetworkContext.pParams = &xPlaintextTransportParams; + + /* Set the entry time of the demo application. This entry time will be used + * to calculate relative time elapsed in the execution of the demo application, + * by the timer utility function that is provided to the MQTT library. + */ + ulGlobalEntryTimeMs = prvGetTimeMs(); + + for( ; ; ) + { + LogInfo( ( "---------STARTING DEMO---------\r\n" ) ); + + /**************************** Initialize. *****************************/ + + prvInitializeTopicBuffers(); + + /****************************** Connect. ******************************/ + + /* Wait for Networking */ + if( xPlatformIsNetworkUp() == pdFALSE ) + { + LogInfo( ( "Waiting for the network link up event..." ) ); + + while( xPlatformIsNetworkUp() == pdFALSE ) + { + vTaskDelay( pdMS_TO_TICKS( 1000U ) ); + } + } + + /* Attempt to establish a TLS connection with the MQTT broker. This example + * connects to the MQTT broker specified in democonfigMQTT_BROKER_ENDPOINT, using + * the port number specified in democonfigMQTT_BROKER_PORT (these macros are defined + * in file demo_config.h). If the connection fails, attempt to re-connect after a timeout. + * The timeout value will be exponentially increased until either the maximum timeout value + * is reached, or the maximum number of attempts are exhausted. The function returns a failure status + * if the TCP connection cannot be established with the broker after a configured number + * of attempts. */ + xNetworkStatus = prvConnectToServerWithBackoffRetries( &xNetworkContext ); + configASSERT( xNetworkStatus == PLAINTEXT_TRANSPORT_SUCCESS ); + + /* Send an MQTT CONNECT packet over the established TLS connection, + * and wait for the connection acknowledgment (CONNACK) packet. */ + LogInfo( ( "Creating an MQTT connection to %s.\r\n", democonfigMQTT_BROKER_ENDPOINT ) ); + prvCreateMQTTConnectionWithBroker( &xMQTTContext, &xNetworkContext ); + + /**************************** Subscribe. ******************************/ + + /* If the server rejected the subscription request, attempt to resubscribe to the + * topic. Attempts are made according to the exponential backoff retry strategy + * implemented in BackoffAlgorithm. */ + prvMQTTSubscribeWithBackoffRetries( &xMQTTContext ); + + /**************************** Publish and Keep-Alive Loop. ******************************/ + + /* Publish messages with QoS2, and send and process keep-alive messages. */ + for( ulPublishCount = 0; ulPublishCount < ulMaxPublishCount; ulPublishCount++ ) + { + prvMQTTPublishToTopics( &xMQTTContext ); + + /* Process incoming publish echo. Since the application subscribed and published + * to the same topic, the broker will send the incoming publish message back + * to the application. */ + LogInfo( ( "Attempt to receive publishes from broker.\r\n" ) ); + xMQTTStatus = prvProcessLoopWithTimeout( &xMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS ); + configASSERT( xMQTTStatus == MQTTSuccess ); + + /* Leave connection idle for some time. */ + LogInfo( ( "Keeping Connection Idle...\r\n\r\n" ) ); + vTaskDelay( mqttexampleDELAY_BETWEEN_PUBLISHES_TICKS ); + } + + /************************ Unsubscribe from the topic. **************************/ + + prvMQTTUnsubscribeFromTopics( &xMQTTContext ); + + /* Process incoming UNSUBACK packet from the broker. */ + xMQTTStatus = prvProcessLoopWithTimeout( &xMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS ); + configASSERT( xMQTTStatus == MQTTSuccess ); + + /**************************** Disconnect. ******************************/ + + /* Send an MQTT DISCONNECT packet over the already-connected TLS over TCP connection. + * There is no corresponding response expected from the broker. After sending the + * disconnect request, the client must close the network connection. */ + LogInfo( ( "Disconnecting the MQTT connection with %s.\r\n", democonfigMQTT_BROKER_ENDPOINT ) ); + xMQTTStatus = MQTT_Disconnect( &xMQTTContext ); + configASSERT( xMQTTStatus == MQTTSuccess ); + + /* Close the network connection. */ + Plaintext_FreeRTOS_Disconnect( &xNetworkContext ); + + /* Reset SUBACK status for each topic filter after completion of the subscription request cycle. */ + for( ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++ ) + { + xTopicFilterContext[ ulTopicCount ].xSubAckStatus = MQTTSubAckFailure; + } + + /* Wait for some time between two iterations to ensure that we do not + * bombard the broker. */ + LogInfo( ( "prvMQTTDemoTask() completed an iteration successfully. Total free heap is %u.\r\n", xPortGetFreeHeapSize() ) ); + LogInfo( ( "Demo completed successfully.\r\n" ) ); + LogInfo( ( "-------DEMO FINISHED-------\r\n" ) ); + LogInfo( ( "Short delay before starting the next iteration.... \r\n\r\n" ) ); + vTaskDelay( mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS_TICKS ); + } +} +/*-----------------------------------------------------------*/ + +static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext_t * pxNetworkContext ) +{ + PlaintextTransportStatus_t xNetworkStatus; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; + + /* Initialize reconnect attempts and interval.*/ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS ); + + /* Attempt to connect to MQTT broker. If connection fails, retry after + * a timeout. Timeout value will exponentially increase till maximum + * attempts are reached. + */ + do + { + /* Establish a TCP connection with the MQTT broker. This example connects to + * the MQTT broker as specified in democonfigMQTT_BROKER_ENDPOINT and + * democonfigMQTT_BROKER_PORT at the top of this file. */ + LogInfo( ( "Create a TCP connection to %s:%d.", + democonfigMQTT_BROKER_ENDPOINT, + democonfigMQTT_BROKER_PORT ) ); + xNetworkStatus = Plaintext_FreeRTOS_Connect( pxNetworkContext, + democonfigMQTT_BROKER_ENDPOINT, + democonfigMQTT_BROKER_PORT, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS ); + + if( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) + { + /* Generate a random number and calculate backoff value (in milliseconds) for + * the next connection retry. + * Note: It is recommended to seed the random number generator with a device-specific + * entropy source so that possibility of multiple devices retrying failed network operations + * at similar intervals can be avoided. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, uxRand(), &usNextRetryBackOff ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + } + } while( ( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); + + return xNetworkStatus; +} +/*-----------------------------------------------------------*/ + +static void prvCreateMQTTConnectionWithBroker( MQTTContext_t * pxMQTTContext, + NetworkContext_t * pxNetworkContext ) +{ + MQTTStatus_t xResult; + MQTTConnectInfo_t xConnectInfo; + bool xSessionPresent; + TransportInterface_t xTransport; + + /*** + * For readability, error handling in this function is restricted to the use of + * asserts(). + ***/ + + /* Fill in Transport Interface send and receive function pointers. */ + xTransport.pNetworkContext = pxNetworkContext; + xTransport.send = Plaintext_FreeRTOS_send; + xTransport.recv = Plaintext_FreeRTOS_recv; + xTransport.writev = NULL; + + /* Initialize MQTT library. */ + xResult = MQTT_Init( pxMQTTContext, &xTransport, prvGetTimeMs, prvEventCallback, &xBuffer ); + configASSERT( xResult == MQTTSuccess ); + xResult = MQTT_InitStatefulQoS( pxMQTTContext, + pOutgoingPublishRecords, + mqttexampleOUTGOING_PUBLISH_RECORD_LEN, + pIncomingPublishRecords, + mqttexampleINCOMING_PUBLISH_RECORD_LEN ); + configASSERT( xResult == MQTTSuccess ); + + /* Some fields are not used in this demo so start with everything at 0. */ + ( void ) memset( ( void * ) &xConnectInfo, 0x00, sizeof( xConnectInfo ) ); + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + xConnectInfo.cleanSession = true; + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + xConnectInfo.pClientIdentifier = democonfigCLIENT_IDENTIFIER; + xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( democonfigCLIENT_IDENTIFIER ); + + /* Set MQTT keep-alive period. If the application does not send packets at an interval less than + * the keep-alive period, the MQTT library will send PINGREQ packets. */ + xConnectInfo.keepAliveSeconds = mqttexampleKEEP_ALIVE_TIMEOUT_SECONDS; + + /* Send MQTT CONNECT packet to broker. LWT is not used in this demo, so it + * is passed as NULL. */ + xResult = MQTT_Connect( pxMQTTContext, + &xConnectInfo, + NULL, + mqttexampleCONNACK_RECV_TIMEOUT_MS, + &xSessionPresent ); + configASSERT( xResult == MQTTSuccess ); + + /* Successfully established and MQTT connection with the broker. */ + LogInfo( ( "An MQTT connection is established with %s.", democonfigMQTT_BROKER_ENDPOINT ) ); +} +/*-----------------------------------------------------------*/ + +static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ) +{ + MQTTStatus_t xResult = MQTTSuccess; + uint8_t * pucPayload = NULL; + size_t ulSize = 0; + uint32_t ulTopicCount = 0U; + + xResult = MQTT_GetSubAckStatusCodes( pxPacketInfo, &pucPayload, &ulSize ); + + /* MQTT_GetSubAckStatusCodes always returns success if called with packet info + * from the event callback and non-NULL parameters. */ + configASSERT( xResult == MQTTSuccess ); + + for( ulTopicCount = 0; ulTopicCount < ulSize; ulTopicCount++ ) + { + xTopicFilterContext[ ulTopicCount ].xSubAckStatus = pucPayload[ ulTopicCount ]; + } +} +/*-----------------------------------------------------------*/ + +static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) +{ + MQTTStatus_t xResult = MQTTSuccess; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; + uint16_t usNextRetryBackOff = 0U; + MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; + bool xFailedSubscribeToTopic = false; + uint32_t ulTopicCount = 0U; + + /* Some fields not used by this demo so start with everything at 0. */ + ( void ) memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) ); + + /* Get a unique packet id. */ + usSubscribePacketIdentifier = MQTT_GetPacketId( pxMQTTContext ); + + /* Populate subscription list. */ + for(ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++) + { + xMQTTSubscription[ ulTopicCount ].qos = MQTTQoS2; + xMQTTSubscription[ ulTopicCount ].pTopicFilter = xTopicFilterContext[ ulTopicCount ].pcTopicFilter; + xMQTTSubscription[ ulTopicCount ].topicFilterLength = ( uint16_t ) strlen( xTopicFilterContext[ ulTopicCount ].pcTopicFilter ); + } + + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS ); + + do + { + /* The client is now connected to the broker. Subscribe to the topic + * as specified in mqttexampleTOPIC at the top of this file by sending a + * subscribe packet then waiting for a subscribe acknowledgment (SUBACK). + * This client will then publish to the same topic it subscribed to, so it + * will expect all the messages it sends to the broker to be sent back to it + * from the broker. This demo uses QOS2 in Subscribe, therefore, the Publish + * messages received from the broker will have QOS2. */ + xResult = MQTT_Subscribe( pxMQTTContext, + xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( MQTTSubscribeInfo_t ), + usSubscribePacketIdentifier ); + configASSERT( xResult == MQTTSuccess ); + + for(ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++) + { + LogInfo( ( "SUBSCRIBE sent for topic %s to broker.\n\n", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + + /* Process incoming packet from the broker. After sending the subscribe, the + * client may receive a publish before it receives a subscribe ack. Therefore, + * call generic incoming packet processing function. Since this demo is + * subscribing to the topic to which no one is publishing, probability of + * receiving Publish message before subscribe ack is zero; but application + * must be ready to receive any packet. This demo uses the generic packet + * processing function everywhere to highlight this fact. */ + xResult = prvProcessLoopWithTimeout( pxMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS ); + configASSERT( xResult == MQTTSuccess ); + + /* Reset flag before checking suback responses. */ + xFailedSubscribeToTopic = false; + + /* Check if recent subscription request has been rejected. #xTopicFilterContext is updated + * in the event callback to reflect the status of the SUBACK sent by the broker. It represents + * either the QoS level granted by the server upon subscription, or acknowledgement of + * server rejection of the subscription request. */ + for( ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++ ) + { + if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus == MQTTSubAckFailure ) + { + xFailedSubscribeToTopic = true; + + /* Generate a random number and calculate backoff value (in milliseconds) for + * the next connection retry. + * Note: It is recommended to seed the random number generator with a device-specific + * entropy source so that possibility of multiple devices retrying failed network operations + * at similar intervals can be avoided. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, uxRand(), &usNextRetryBackOff ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + + break; + } + } + + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTPublishToTopics( MQTTContext_t * pxMQTTContext ) +{ + MQTTStatus_t xResult; + MQTTPublishInfo_t xMQTTPublishInfo; + uint32_t ulTopicCount; + + /*** + * For readability, error handling in this function is restricted to the use of + * asserts(). + ***/ + + for( ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++ ) + { + /* Some fields are not used by this demo so start with everything at 0. */ + ( void ) memset( ( void * ) &xMQTTPublishInfo, 0x00, sizeof( xMQTTPublishInfo ) ); + + /* This demo uses QoS2 */ + xMQTTPublishInfo.qos = MQTTQoS2; + xMQTTPublishInfo.retain = false; + xMQTTPublishInfo.pTopicName = xTopicFilterContext[ ulTopicCount ].pcTopicFilter; + xMQTTPublishInfo.topicNameLength = ( uint16_t ) strlen( xTopicFilterContext[ ulTopicCount ].pcTopicFilter ); + xMQTTPublishInfo.pPayload = mqttexampleMESSAGE; + xMQTTPublishInfo.payloadLength = strlen( mqttexampleMESSAGE ); + + /* Get a unique packet id. */ + usPublishPacketIdentifier = MQTT_GetPacketId( pxMQTTContext ); + + LogInfo( ( "Publishing to the MQTT topic %s.\r\n", xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Send PUBLISH packet. */ + xResult = MQTT_Publish( pxMQTTContext, &xMQTTPublishInfo, usPublishPacketIdentifier ); + configASSERT( xResult == MQTTSuccess ); + } +} +/*-----------------------------------------------------------*/ + +static void prvMQTTUnsubscribeFromTopics( MQTTContext_t * pxMQTTContext ) +{ + MQTTStatus_t xResult; + MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; + uint32_t ulTopicCount; + + /* Some fields are not used by this demo so start with everything at 0. */ + memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) ); + + /* Populate subscription list. */ + for(ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++) + { + xMQTTSubscription[ ulTopicCount ].qos = MQTTQoS2; + xMQTTSubscription[ ulTopicCount ].pTopicFilter = xTopicFilterContext[ ulTopicCount ].pcTopicFilter; + xMQTTSubscription[ ulTopicCount ].topicFilterLength = ( uint16_t ) strlen( xTopicFilterContext[ ulTopicCount ].pcTopicFilter ); + + LogInfo( ( "Unsubscribing from topic %s.\r\n", xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + + /* Get next unique packet identifier. */ + usUnsubscribePacketIdentifier = MQTT_GetPacketId( pxMQTTContext ); + /* Make sure the packet id obtained is valid. */ + configASSERT( usUnsubscribePacketIdentifier != 0 ); + + /* Send UNSUBSCRIBE packet. */ + xResult = MQTT_Unsubscribe( pxMQTTContext, + xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( MQTTSubscribeInfo_t ), + usUnsubscribePacketIdentifier ); + + configASSERT( xResult == MQTTSuccess ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTProcessResponse( MQTTPacketInfo_t * pxIncomingPacket, + uint16_t usPacketId ) +{ + uint32_t ulTopicCount = 0U; + + switch( pxIncomingPacket->type ) + { + case MQTT_PACKET_TYPE_PUBACK: + LogInfo( ( "PUBACK received for packet ID %u.\r\n", usPacketId ) ); + break; + + case MQTT_PACKET_TYPE_SUBACK: + + LogInfo( ( "SUBACK received for packet ID %u.", usPacketId ) ); + + /* A SUBACK from the broker, containing the server response to our subscription request, has been received. + * It contains the status code indicating server approval/rejection for the subscription to the single topic + * requested. The SUBACK will be parsed to obtain the status code, and this status code will be stored in global + * variable #xTopicFilterContext. */ + prvUpdateSubAckStatus( pxIncomingPacket ); + + for( ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++ ) + { + if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus != MQTTSubAckFailure ) + { + LogInfo( ( "Subscribed to the topic %s with maximum QoS %u.\r\n", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter, + xTopicFilterContext[ ulTopicCount ].xSubAckStatus ) ); + } + } + + /* Make sure ACK packet identifier matches with Request packet identifier. */ + configASSERT( usSubscribePacketIdentifier == usPacketId ); + break; + + case MQTT_PACKET_TYPE_UNSUBACK: + LogInfo( ( "UNSUBACK received for packet ID %u.", usPacketId ) ); + /* Make sure ACK packet identifier matches with Request packet identifier. */ + configASSERT( usUnsubscribePacketIdentifier == usPacketId ); + break; + + case MQTT_PACKET_TYPE_PINGRESP: + + /* Nothing to be done from application as library handles + * PINGRESP with the use of MQTT_ProcessLoop API function. */ + LogWarn( ( "PINGRESP should not be handled by the application " + "callback when using MQTT_ProcessLoop.\n" ) ); + break; + + case MQTT_PACKET_TYPE_PUBREC: + LogInfo( ( "PUBREC received for packet id %u.\n\n", + usPacketId ) ); + break; + + case MQTT_PACKET_TYPE_PUBREL: + + /* Nothing to be done from application as library handles + * PUBREL. */ + LogInfo( ( "PUBREL received for packet id %u.\n\n", + usPacketId ) ); + break; + + case MQTT_PACKET_TYPE_PUBCOMP: + + /* Nothing to be done from application as library handles + * PUBCOMP. */ + LogInfo( ( "PUBCOMP received for packet id %u.\n\n", + usPacketId ) ); + break; + + /* Any other packet type is invalid. */ + default: + LogWarn( ( "prvMQTTProcessResponse() called with unknown packet type:(%02X).\r\n", + pxIncomingPacket->type ) ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvMQTTProcessIncomingPublish( MQTTPublishInfo_t * pxPublishInfo ) +{ + uint32_t ulTopicCount; + BaseType_t xTopicFound = pdFALSE; + + configASSERT( pxPublishInfo != NULL ); + + /* Process incoming Publish. */ + LogInfo( ( "Incoming QoS : %d\n", pxPublishInfo->qos ) ); + + /* Verify the received publish is for one of the topics that's been subscribed to. */ + for( ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++) + { + if( ( pxPublishInfo->topicNameLength == strlen( xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ) && + ( strncmp( xTopicFilterContext[ ulTopicCount ].pcTopicFilter, pxPublishInfo->pTopicName, pxPublishInfo->topicNameLength ) == 0 ) ) + { + xTopicFound = pdTRUE; + break; + } + } + + if( xTopicFound == pdTRUE ) + { + LogInfo( ( "\r\nIncoming Publish Topic Name: %s matches a subscribed topic.\r\n", + //pxPublishInfo->topicNameLength, + pxPublishInfo->pTopicName ) ); + } + else + { + LogError( ( "Incoming Publish Topic Name: %s does not match a subscribed topic.\r\n", + //pxPublishInfo->topicNameLength, + pxPublishInfo->pTopicName ) ); + } + + /* Verify the message received matches the message sent. */ + if( strncmp( mqttexampleMESSAGE, ( const char * ) ( pxPublishInfo->pPayload ), pxPublishInfo->payloadLength ) != 0 ) + { + LogError( ( "Incoming Publish Message: %s does not match Expected Message: %s.\r\n", + //pxPublishInfo->topicNameLength, + pxPublishInfo->pTopicName, mqttexampleMESSAGE ) ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvEventCallback( MQTTContext_t * pxMQTTContext, + MQTTPacketInfo_t * pxPacketInfo, + MQTTDeserializedInfo_t * pxDeserializedInfo ) +{ + /* The MQTT context is not used in this function. */ + ( void ) pxMQTTContext; + + if( ( pxPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH ) + { + LogInfo( ( "PUBLISH received for packet id %u.\n\n", + pxDeserializedInfo->packetIdentifier ) ); + prvMQTTProcessIncomingPublish( pxDeserializedInfo->pPublishInfo ); + } + else + { + prvMQTTProcessResponse( pxPacketInfo, pxDeserializedInfo->packetIdentifier ); + } +} + +/*-----------------------------------------------------------*/ + +static uint32_t prvGetTimeMs( void ) +{ + TickType_t xTickCount = 0; + uint32_t ulTimeMs = 0UL; + + /* Get the current tick count. */ + xTickCount = xTaskGetTickCount(); + + /* Convert the ticks to milliseconds. */ + ulTimeMs = ( uint32_t ) xTickCount * MILLISECONDS_PER_TICK; + + /* Reduce ulGlobalEntryTimeMs from obtained time so as to always return the + * elapsed time in the application. */ + ulTimeMs = ( uint32_t ) ( ulTimeMs - ulGlobalEntryTimeMs ); + + return ulTimeMs; +} + +/*-----------------------------------------------------------*/ + +static MQTTStatus_t prvProcessLoopWithTimeout( MQTTContext_t * pMqttContext, + uint32_t ulTimeoutMs ) +{ + uint32_t ulMqttProcessLoopTimeoutTime; + uint32_t ulCurrentTime; + + MQTTStatus_t eMqttStatus = MQTTSuccess; + + ulCurrentTime = pMqttContext->getTime(); + ulMqttProcessLoopTimeoutTime = ulCurrentTime + ulTimeoutMs; + + /* Call MQTT_ProcessLoop multiple times a timeout happens, or + * MQTT_ProcessLoop fails. */ + while( ( ulCurrentTime < ulMqttProcessLoopTimeoutTime ) && + ( eMqttStatus == MQTTSuccess || eMqttStatus == MQTTNeedMoreBytes ) ) + { + eMqttStatus = MQTT_ProcessLoop( pMqttContext ); + ulCurrentTime = pMqttContext->getTime(); + } + + if( eMqttStatus == MQTTNeedMoreBytes ) + { + eMqttStatus = MQTTSuccess; + } + + return eMqttStatus; +} + +/*-----------------------------------------------------------*/ + +static void prvInitializeTopicBuffers( void ) +{ + uint32_t ulTopicCount; + int xCharactersWritten; + + + for(ulTopicCount = 0; ulTopicCount < mqttexampleTOPIC_COUNT; ulTopicCount++) + { + /* Write topic strings into buffers. */ + xCharactersWritten = snprintf( xTopicFilterContext[ ulTopicCount ].pcTopicFilter, + mqttexampleTOPIC_BUFFER_SIZE, + "%s%d", mqttexampleTOPIC_PREFIX, ( int ) ulTopicCount ); + + configASSERT( xCharactersWritten >= 0 && xCharactersWritten < mqttexampleTOPIC_BUFFER_SIZE ); + + /* Assign topic string to its corresponding SUBACK code initialized as a failure. */ + xTopicFilterContext[ ulTopicCount ].xSubAckStatus = MQTTSubAckFailure; + } +} + +/*-----------------------------------------------------------*/ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/core_mqtt_config.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/core_mqtt_config.h new file mode 100644 index 0000000..1d65f7a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/core_mqtt_config.h @@ -0,0 +1,125 @@ +/* + * FreeRTOS V202212.01 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ +#ifndef CORE_MQTT_CONFIG_H +#define CORE_MQTT_CONFIG_H + +/**************************************************/ +/******* DO NOT CHANGE the following order ********/ +/**************************************************/ + +/* Include logging header files and define logging macros in the following order: + * 1. Include the header file "logging_levels.h". + * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on + * the logging configuration for MQTT. + * 3. Include the header file "logging_stack.h", if logging is enabled for MQTT. + */ + +#include "logging_levels.h" + +/* Logging configuration for the MQTT library. */ +#ifndef LIBRARY_LOG_NAME + #define LIBRARY_LOG_NAME "MQTT" +#endif + +#ifndef LIBRARY_LOG_LEVEL + #define LIBRARY_LOG_LEVEL LOG_ERROR +#endif + +/* Prototype for the function used to print to console on Windows simulator + * of FreeRTOS. + * The function prints to the console before the network is connected; + * then a UDP port after the network has connected. */ +extern void vLoggingPrintf( const char * pcFormatString, + ... ); + +/* Map the SdkLog macro to the logging function to enable logging + * on Windows simulator. */ +#ifndef SdkLog + #define SdkLog( message ) bsp_printf message +#endif + +#include "logging_stack.h" +/************ End of logging configuration ****************/ + +/** + * @brief The maximum number of MQTT PUBLISH messages that may be pending + * acknowledgement at any time. + * + * QoS 1 and 2 MQTT PUBLISHes require acknowledgment from the server before + * they can be completed. While they are awaiting the acknowledgment, the + * client must maintain information about their state. The value of this + * macro sets the limit on how many simultaneous PUBLISH states an MQTT + * context maintains. + */ +#define MQTT_STATE_ARRAY_MAX_COUNT 20U + +/** + * @brief The maximum duration between non-empty network reads while + * receiving an MQTT packet via the #MQTT_ProcessLoop or #MQTT_ReceiveLoop + * API functions. + * + * When an incoming MQTT packet is detected, the transport receive function + * may be called multiple times until all of the expected number of bytes of the + * packet are received. This timeout represents the maximum polling duration that + * is allowed without any data reception from the network for the incoming packet. + * + * @note For this demo, the timeout value is configured to zero as the demo uses a + * dummy timer function (of #MQTTGetCurrentTimeFunc_t) that always returns zero. + * It is REQUIRED to set the the timeout to zero when using a dummy timer function + * that always returns zero. + */ +#define MQTT_RECV_POLLING_TIMEOUT_MS 0U + +/*********************** coreMQTT Agent Configurations **********************/ +/** + * @brief The maximum number of pending acknowledgments to track for a single + * connection. + * + * @note The MQTT agent tracks MQTT commands (such as PUBLISH and SUBSCRIBE) th + * at are still waiting to be acknowledged. MQTT_AGENT_MAX_OUTSTANDING_ACKS set + * the maximum number of acknowledgments that can be outstanding at any one time. + * The higher this number is the greater the agent's RAM consumption will be. + */ +#define MQTT_AGENT_MAX_OUTSTANDING_ACKS ( 20U ) + +/** + * @brief Time in MS that the MQTT agent task will wait in the Blocked state (so + * not using any CPU time) for a command to arrive in its command queue before + * exiting the blocked state so it can call MQTT_ProcessLoop(). + * + * @note It is important MQTT_ProcessLoop() is called often if there is known + * MQTT traffic, but calling it too often can take processing time away from + * lower priority tasks and waste CPU time and power. + */ +#define MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME ( 1000 ) + +/** + * @brief The number of command structures to allocate in the pool + * for the agent. + */ +#define MQTT_COMMAND_CONTEXTS_POOL_SIZE 10 + +#endif /* ifndef CORE_MQTT_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/demo_config.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/demo_config.h new file mode 100644 index 0000000..3d5e64f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/demo_config.h @@ -0,0 +1,113 @@ +/* + * FreeRTOS V202212.01 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/**************************************************/ +/******* DO NOT CHANGE the following order ********/ +/**************************************************/ + +/* Include logging header files and define logging macros in the following order: + * 1. Include the header file "logging_levels.h". + * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on + * the logging configuration for DEMO. + * 3. Include the header file "logging_stack.h", if logging is enabled for DEMO. + */ + +#include "logging_levels.h" + +/* Logging configuration for the Demo. */ +#ifndef LIBRARY_LOG_NAME + #define LIBRARY_LOG_NAME "MQTTDemo" +#endif + +#ifndef LIBRARY_LOG_LEVEL + #define LIBRARY_LOG_LEVEL LOG_INFO +#endif + +/* Prototype for the function used to print to console on Windows simulator + * of FreeRTOS. + * The function prints to the console before the network is connected; + * then a UDP port after the network has connected. */ +extern void vLoggingPrintf( const char * pcFormatString, + ... ); + +/* Map the SdkLog macro to the logging function to enable logging + * on Windows simulator. */ +#ifndef SdkLog + #define SdkLog( message ) bsp_printf message +#endif + +#include "logging_stack.h" + +/************ End of logging configuration ****************/ + +/** + * @brief The MQTT client identifier used in this example. Each client identifier + * must be unique so edit as required to ensure no two clients connecting to the + * same broker use the same client identifier. + * + *!!! Please note a #defined constant is used for convenience of demonstration + *!!! only. Production devices can use something unique to the device that can + *!!! be read by software, such as a production serial number, instead of a + *!!! hard coded constant. + * + * #define democonfigCLIENT_IDENTIFIER "insert here." + */ + + +/** + * @brief MQTT broker end point to connect to. + * + * @note If you would like to setup an MQTT broker for running this demo, + * please see `mqtt_broker_setup.txt`. + * + * #define democonfigMQTT_BROKER_ENDPOINT "insert here." + */ +#define democonfigMQTT_BROKER_ENDPOINT "192.168.31.222" + +/** + * @brief The port to use for the demo. + * + * #define democonfigMQTT_BROKER_PORT ( insert here. ) + */ +#define democonfigMQTT_BROKER_PORT ( 1883 ) + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +/** + * @brief Size of the network buffer for MQTT packets. + */ +#define democonfigNETWORK_BUFFER_SIZE ( 1024U ) + +#endif /* DEMO_CONFIG_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/logging_output.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/logging_output.c new file mode 100644 index 0000000..663aca8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/logging_output.c @@ -0,0 +1,385 @@ +/* + * Lab-Project-coreMQTT-Agent 201215 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed + * to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 1024 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to + * the server + */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void * pvParameter1, + uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that + * needs Win32 system calls. */ +static void * pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the + * vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 + * thread that is responsible for making Win32 calls (when stdout or a disk log is + * used). */ +static StreamBuffer_t * xLogStreamBuffer = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set + * to pdFALSE - at which time prints that require Win32 system calls are done by + * the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + // configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if ( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If UDP logging is used then store the address to which the log data + * will be sent - but don't create the socket yet because the network is + * not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + * have to be made. Such system calls cannot be made from FreeRTOS tasks + * so create a stream buffer to pass the messages to a Win32 thread, then + * create the thread itself, along with a Win32 event that can be used to + * unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) pvPortMalloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + } + } + #else /* if ( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) */ + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + * Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void * pvParameter1, + uint32_t ulParameter2 ) +{ + static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); + Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + * are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char * pcFormat, + ... ) +{ + char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; + char * pcSource, * pcTarget, * pcBegin; + size_t xLength, xLength2, rc; + static BaseType_t xMessageNumber = 0; + static BaseType_t xAfterLineBreak = pdTRUE; + va_list args; + uint32_t ulIPAddress; + const char * pcTaskName; + const char * pcNoTask = "None"; + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( ( xAfterLineBreak == pdTRUE ) && ( strcmp( pcFormat, "\r\n" ) != 0 ) ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + xAfterLineBreak = pdFALSE; + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + xAfterLineBreak = pdTRUE; + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + * IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( ( ulIPAddress >> 16UL ) & 0xffUL ), + ( unsigned long ) ( ( ulIPAddress >> 8UL ) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + * because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + * xTimerPendFunctionCall() function is used even though this is + * not an interrupt because this function is called from the IP task + * and the IP task cannot itself wait for a socket to bind. The + * parameters to prvCreatePrintSocket() are not required so set to + * NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + //FreeRTOS_sendto( xPrintSocket, "\r\n", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + * be output here - so instead write the message to the stream buffer and wake + * the Win32 thread which will read it from the stream buffer and perform the + * actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + * the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + * itself. Raising the thread priority is used as a critical section + * as there are potentially multiple writers. The stream buffer is + * only thread safe when there is a single writer (likewise for + * reading from the buffer). */ +vTaskSuspendAll(); +// xCurrentTask = GetCurrentThread(); +// iOriginalPriority = GetThreadPriority( xCurrentTask ); +// SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); +// SetThreadPriority( GetCurrentThread(), iOriginalPriority ); +xTaskResumeAll(); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + * logging output function is called directly. When the system is running + * the output function cannot be called directly because it would get + * called from both FreeRTOS tasks and Win32 threads - so instead wake the + * Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + * is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ + size_t xLength; + char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + * used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + configASSERT( xLength < dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + * vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + //_write( _fileno( stdout ), cPrintString, strlen( cPrintString ) ); + printf(cPrintString); + } + } +} +/*-----------------------------------------------------------*/ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/main.c new file mode 100644 index 0000000..8abe9fa --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/main.c @@ -0,0 +1,385 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/* + * FreeRTOS+TCP V3.1.0 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/***************************************************************************** +* Note: This file is Not! to be used as is. The purpose of this file is to provide +* a template for writing a network interface. Each network interface will have to provide +* concrete implementations of the functions in this file. +* +* See the following URL for an explanation of this file and its functions: +* https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html +* +*****************************************************************************/ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" +#include "bsp.h" +#include "riscv.h" +#include "gpio.h" + +/* Demo application includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOSIPConfig.h" + +#define mainHOST_NAME "Efinix" +#define mainDEVICE_NICK_NAME "Sapphire" + +/* + * Just seeds the simple pseudo random number generator. + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialisation including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +//const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/* Prepare hardware to run the demo. */ +static void prvSetupHardware( void ); +/* Send a message to the UART initialised in prvSetupHardware. */ +void vSendString( const char * const pcString ); +/*-----------------------------------------------------------*/ +void vSendString( const char * const pcString ) +{ + bsp_printf(pcString); +} + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL ); + + bsp_init(); + + /* + * Instructions for using this project are provided on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + prvSetupHardware(); + + /* Miscellaneous initialisation including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialise the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the definition of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + /* Start the RTOS scheduler. */ + + + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + bsp_uDelay( ulLongTime_ms ); + } +} + +/*-----------------------------------------------------------*/ +static void prvSetupHardware( void ) +{ + extern void freertos_risc_v_trap_handler(); + csr_write(mtvec, freertos_risc_v_trap_handler); + + vSendString( "***Hello world, this is FreeRTOS MQTT Plain Text demo***\n\r" ); +} + +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ +const uint32_t ulMSToSleep = 1; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in + FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the + idle task just sleeps to lower the CPU usage. */ + bsp_uDelay( ulMSToSleep ); +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ +const uint32_t ulLongSleep = 1000UL; +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + FreeRTOS_printf( ( "vAssertCalled( %s, %ld\n", pcFile, ulLine ) ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + bsp_uDelay( ulLongSleep ); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ +#include "demo_config.h" +extern void vStartSimpleMQTTDemo( void ); +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ + //vIPerfInstall(); + vStartSimpleMQTTDemo(); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + vAssertCalled( __FILE__, __LINE__ ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + /* Seed the random number generator. */ + prvSRand( ( uint32_t ) 555987 ); + +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( strcasecmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} + +/* + * Supply a random number to FreeRTOS+TCP stack. + * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER + * SO IS NOT INTENDED FOR USE IN PRODUCTION SYSTEMS. + */ +BaseType_t xApplicationGetRandomNumber(uint32_t* pulNumber) +{ + *(pulNumber) = uxRand(); + return pdTRUE; +} +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + __asm volatile( "ebreak" ); + for( ;; ); +} + + +void vApplicationTickHook( void ) +{ + extern void vFullDemoTickHook( void ); +} + +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) +{ + +} + +BaseType_t xPlatformIsNetworkUp( void ) +{ + return FreeRTOS_IsNetworkUp(); +} + +eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ + ( void ) ( pxNetworkBuffer ); + return eProcessBuffer; +} + +/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ +static StaticTask_t xIdleTaskTCBBuffer; +static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; + *ppxIdleTaskStackBuffer = &xIdleStack[0]; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + /* place for user code */ +} +/* USER CODE END GET_IDLE_TASK_MEMORY */ + +/* USER CODE BEGIN GET_TIMER_TASK_MEMORY */ +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} +/* USER CODE END GET_TIMER_TASK_MEMORY */ + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/userDef.h new file mode 100644 index 0000000..1d8fdeb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/freeRTOS/freertosMqttPlainTextDemo/src/userDef.h @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "bsp.h" + +/************************** Project Header File ***************************/ +#define DEBUG_PRINTF_EN 0 +#define TEST_MODE 0 //0:Normal Mode; 1:Link partner Test Mode; +#define PAT_NUM 0 +#define PAT_DLEN 8 +#define PAT_IPG 4095 +#define PAT_TYPE 0 //0:UDP Pattern; //1:MAC Pattern; +#define DST_MAC_H 0xffff +#define DST_MAC_L 0xffffffff +#define SRC_MAC_H (configMAC_ADDR5<<8)|configMAC_ADDR4 +#define SRC_MAC_L (configMAC_ADDR3<<24)|(configMAC_ADDR2<<16)|(configMAC_ADDR1<<8)|configMAC_ADDR0//0x5e0060c8 +#define SRC_IP (configIP_ADDR3<<24)|(configIP_ADDR2<<16)|(configIP_ADDR1<<8)|configIP_ADDR0 +#define DST_IP 0xc0a80165 +#define SRC_PORT 0x0521 +#define DST_PORT 0x2715 +#define RX_HANDLER_PRIORITY ( configMAX_PRIORITIES - 5 ) + +/************************** System Header File ***************************/ +#define PHY_ADDR 0x0 + +/************************** HW Header File ***************************/ +#define TSEMAC_BASE 0xe9100000 +#define TSEMAC_DMASG_BASE IO_APB_SLAVE_0_INPUT +#define TSE_DMASG_RX_CH 0 +#define TSE_RX_INTR SYSTEM_PLIC_USER_INTERRUPT_G_INTERRUPT +#define TSE_DMASG_TX_CH 1 +#define TSE_TX_INTR SYSTEM_PLIC_USER_INTERRUPT_H_INTERRUPT +#define TSE_Speed_1000Mhz 0x04 +#define TSE_Speed_100Mhz 0x02 +#define TSE_Speed_10Mhz 0x01 + +/************************** Application Header File ***************************/ +#define TX_ENA_MASK 0xFFFFFFFE +#define RX_ENA_MASK 0xFFFFFFFD +#define XON_GEN_MASK 0xFFFFFFFB +#define PROMIS_EN_MASK 0xFFFFFFEF +#define PAD_EN_MASK 0xFFFFFFDF +#define CRC_FWD_MASK 0xFFFFFFBF +#define PAUSE_IGNORE_MASK 0xFFFFFEFF +#define TX_ADDR_INS_MASK 0xFFFFFBFF +#define LOOP_ENA_MASK 0xFFFF7FFF +#define ETH_SPEED_MASK 0xFFF8FFFF +#define XOFF_GEN_MASK 0xFFBFFFFF +#define CNT_RST_MASK 0x7FFFFFFF + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/makefile new file mode 100644 index 0000000..4b5e90e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/makefile @@ -0,0 +1,22 @@ +PROJ_NAME=coremark + +STANDALONE=../.. + +CFLAGS+=-DSMP + +DEBUG=no +BENCH=yes + +CFLAGS += -DITERATIONS=40000 + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/LICENSE.md b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/LICENSE.md new file mode 100644 index 0000000..14e53e9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/LICENSE.md @@ -0,0 +1,100 @@ +# COREMARK® ACCEPTABLE USE AGREEMENT + +This ACCEPTABLE USE AGREEMENT (this “Agreement”) is offered by Embedded Microprocessor Benchmark Consortium, a California nonprofit corporation (“Licensor”), to users of its CoreMark® software (“Licensee”) exclusively on the following terms. + +Licensor offers benchmarking software (“Software”) pursuant to an open source license, but carefully controls use of its benchmarks and their associated goodwill. Licensor has registered its trademark in one of the benchmarks available through the Software, COREMARK, Ser. No. 85/487,290; Reg. No. 4,179,307 (the “Trademark”), and promotes the use of a standard metric as a benchmark for assessing the performance of embedded systems. Solely on the terms described herein, Licensee may use and display the Trademark in connection with the generation of data regarding measurement and analysis of computer and embedded system benchmarking via the Software (the “Licensed Use”). + +## Article 1 – License Grant. +1.1. License. Subject to the terms and conditions of this Agreement, Licensor hereby grants to Licensee, and Licensee hereby accepts from Licensor, a personal, non-exclusive, royalty-free, revocable right and license to use and display the Trademark during the term of this Agreement (the “Term”), solely and exclusively in connection with the Licensed Use. During the Term, Licensee (i) shall not modify or otherwise create derivative works of the Trademark, and (ii) may use the Trademark only to the extent permitted under this License. Neither Licensee nor any affiliate or agent thereof shall otherwise use the Trademark without the prior express written consent of Licensor, which may be withheld in its sole and absolute discretion. All rights not expressly granted to Licensee hereunder shall remain the exclusive property of Licensor. + +1.2. Modifications to the Software. Licensee shall not use the Trademark in connection with any use of a modified, derivative, or otherwise altered copy of the Software. + +1.3. Licensor’s Use. Nothing in this Agreement shall preclude Licensor or any of its successors or assigns from using or permitting other entities to use the Trademark, whether or not such entity directly or indirectly competes or conflicts with Licensee’s Licensed Use in any manner. + +1.4. Term and Termination. This Agreement is perpetual unless terminated by either of the parties. Licensee may terminate this Agreement for convenience, without cause or liability, for any reason or for no reason whatsoever, upon ten (10) business days written notice. Licensor may terminate this Agreement effective immediately upon notice of breach. Upon termination, Licensee shall immediately remove all implementations of the Trademark from the Licensed Use, and delete all digitals files and records of all materials related to the Trademark. + +## Article 2 – Ownership. +2.1. Ownership. Licensee acknowledges and agrees that Licensor is the owner of all right, title, and interest in and to the Trademark, and all such right, title, and interest shall remain with Licensor. Licensee shall not contest, dispute, challenge, oppose, or seek to cancel Licensor’s right, title, and interest in and to the Trademark. Licensee shall not prosecute any application for registration of the Trademark. Licensee shall display appropriate notices regarding ownership of the Trademark in connection with the Licensed Use. + +2.2. Goodwill. Licensee acknowledges that Licensee shall not acquire any right, title, or interest in the Trademark by virtue of this Agreement other than the license granted hereunder, and disclaims any such right, title, interest, or ownership. All goodwill and reputation generated by Licensee’s use of the Trademark shall inure to the exclusive benefit of Licensor. Licensee shall not by any act or omission use the Trademark in any manner that disparages or reflects adversely on Licensor or its Licensed Use or reputation. Licensee shall not take any action that would interfere with or prejudice Licensor’s ownership or registration of the Trademark, the validity of the Trademark or the validity of the license granted by this Agreement. If Licensor determines and notifies Licensee that any act taken in connection with the Licensed Use (i) is inaccurate, unlawful or offensive to good taste; (ii) fails to provide for proper trademark notices, or (iii) otherwise violates Licensee’s obligations under this Agreement, the license granted under this Agreement shall terminate. + +## Article 3 – Indemnification. +3.1. Indemnification Generally. Licensee agrees to indemnify, defend, and hold harmless (collectively “indemnify” or “indemnification”) Licensor, including Licensor’s members, managers, officers, and employees (collectively “Related Persons”), from and against, and pay or reimburse Licensor and such Related Persons for, any and all third-party actions, claims, demands, proceedings, investigations, inquiries (collectively, “Claims”), and any and all liabilities, obligations, fines, deficiencies, costs, expenses, royalties, losses, and damages (including reasonable outside counsel fees and expenses) associated with such Claims, to the extent that such Claim arises out of (i) Licensee’s material breach of this Agreement, or (ii) any allegation(s) that Licensee’s actions infringe or violate any third-party intellectual property right, including without limitation, any U.S. copyright, patent, or trademark, or are otherwise found to be tortious or criminal (whether or not such indemnified person is a named party in a legal proceeding). + +3.2. Notice and Defense of Claims. Licensor shall promptly notify Licensee of any Claim for which indemnification is sought, following actual knowledge of such Claim, provided however that the failure to give such notice shall not relieve Licensee of its obligations hereunder except to the extent that Licensee is materially prejudiced by such failure. In the event that any third-party Claim is brought, Licensee shall have the right and option to undertake and control the defense of such action with counsel of its choice, provided however that (i) Licensor at its own expense may participate and appear on an equal footing with Licensee in the defense of any such Claim, (ii) Licensor may undertake and control such defense in the event of the material failure of Licensee to undertake and control the same; and (iii) the defense of any Claim relating to the intellectual property rights of Licensor or its licensors and any related counterclaims shall be solely controlled by Licensor with counsel of its choice. Licensee shall not consent to judgment or concede or settle or compromise any Claim without the prior written approval of Licensor (whose approval shall not be unreasonably withheld), unless such concession or settlement or compromise includes a full and unconditional release of Licensor and any applicable Related Persons from all liabilities in respect of such Claim. + +## Article 4 – Miscellaneous. +4.1. Relationship of the Parties. This Agreement does not create a partnership, franchise, joint venture, agency, fiduciary, or employment relationship between the parties. + +4.2. No Third-Party Beneficiaries. Except for the rights of Related Persons under Article 3 (Indemnification), there are no third-party beneficiaries to this Agreement. + +4.3. Assignment. Licensee’s rights hereunder are non-assignable, and may not be sublicensed. + +4.4. Equitable Relief. Licensee acknowledges that the remedies available at law for any breach of this Agreement will, by their nature, be inadequate. Accordingly, Licensor may obtain injunctive relief or other equitable relief to restrain a breach or threatened breach of this Agreement or to specifically enforce this Agreement, without proving that any monetary damages have been sustained, and without the requirement of posting of a bond prior to obtaining such equitable relief. + +4.5. Governing Law. This Agreement will be interpreted, construed, and enforced in all respects in accordance with the laws of the State of California, without reference to its conflict of law principles. + +4.6. Attorneys’ Fees. If any legal action, arbitration or other proceeding is brought for the enforcement of this Agreement, or because of an alleged dispute, breach, default, or misrepresentation in connection with any of the provisions of this Agreement, the successful or prevailing party shall be entitled to recover its reasonable attorneys’ fees and other reasonable costs incurred in that action or proceeding, in addition to any other relief to which it may be entitled. + +4.7. Amendment; Waiver. This Agreement may not be amended, nor may any rights under it be waived, except in writing by Licensor. + +4.8. Severability. If any provision of this Agreement is held by a court of competent jurisdiction to be contrary to law, the provision shall be modified by the court and interpreted so as best to accomplish the objectives of the original provision to the fullest extent +permitted by law, and the remaining provisions of this Agreement shall remain in effect. + +4.9. Entire Agreement. This Agreement constitutes the entire agreement between the parties and supersedes all prior and contemporaneous agreements, proposals or representations, written or oral, concerning its subject matter. + + +# Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_list_join.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_list_join.c new file mode 100644 index 0000000..b8c6e41 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_list_join.c @@ -0,0 +1,595 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this +library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accommodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b +are divided as follows: o Upper 8b are backup of original data. o Bit 7 +indicates if the lower 7 bits are to be used as is or calculated. o Bits 0-2 +indicate type of operation to perform to get a 7b value. o Bits 3-6 provide +input for the operation. + +*/ + +/* local functions */ + +list_head *core_list_find(list_head *list, list_data *info); +list_head *core_list_reverse(list_head *list); +list_head *core_list_remove(list_head *item); +list_head *core_list_undo_remove(list_head *item_removed, + list_head *item_modified); +list_head *core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end); +typedef ee_s32 (*list_cmp)(list_data *a, list_data *b, core_results *res); +list_head *core_list_mergesort(list_head * list, + list_cmp cmp, + core_results *res); + +ee_s16 +calc_func(ee_s16 *pdata, core_results *res) +{ + ee_s16 data = *pdata; + ee_s16 retval; + ee_u8 optype + = (data >> 7) + & 1; /* bit 7 indicates if the function result has been cached */ + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else + { /* otherwise calculate and cache the result */ + ee_s16 flag = data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype + = ((data >> 3) + & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + switch (flag) + { + case 0: + if (dtype < 0x22) /* set min period for bit corruption */ + dtype = 0x22; + retval = core_bench_state(res->size, + res->memblock[3], + res->seed1, + res->seed2, + dtype, + res->crc); + if (res->crcstate == 0) + res->crcstate = retval; + break; + case 1: + retval = core_bench_matrix(&(res->mat), dtype, res->crc); + if (res->crcmatrix == 0) + res->crcmatrix = retval; + break; + default: + retval = data; + break; + } + res->crc = crcu16(retval, res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 +cmp_complex(list_data *a, list_data *b, core_results *res) +{ + ee_s16 val1 = calc_func(&(a->data16), res); + ee_s16 val2 = calc_func(&(b->data16), res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 +cmp_idx(list_data *a, list_data *b, core_results *res) +{ + if (res == NULL) + { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16 >> 8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16 >> 8)); + } + return a->idx - b->idx; +} + +void +copy_info(list_data *to, list_data *from) +{ + to->data16 = from->data16; + to->idx = from->idx; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + * At the end of this function, the list is back to original state +*/ +ee_u16 +core_bench_list(core_results *res, ee_s16 finder_idx) +{ + ee_u16 retval = 0; + ee_u16 found = 0, missed = 0; + list_head *list = res->list; + ee_s16 find_num = res->seed3; + list_head *this_find; + list_head *finder, *remover; + list_data info; + ee_s16 i; + + info.idx = finder_idx; + /* find values in the list, and change the list each time + * (reverse and cache if value found) */ + for (i = 0; i < find_num; i++) + { + info.data16 = (i & 0xff); + this_find = core_list_find(list, &info); + list = core_list_reverse(list); + if (this_find == NULL) + { + missed++; + retval += (list->next->info->data16 >> 8) & 1; + } + else + { + found++; + if (this_find->info->data16 & 0x1) /* use found value */ + retval += (this_find->info->data16 >> 9) & 1; + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next = list->next; + list->next = finder; + } + } + if (info.idx >= 0) + info.idx++; +#if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\r\n", i, retval, missed, found); +#endif + } + retval += found * 4 - missed; + /* sort the list by data content and remove one item*/ + if (finder_idx > 0) + list = core_list_mergesort(list, cmp_complex, res); + remover = core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo + * remove */ + finder = core_list_find(list, &info); + if (!finder) + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 1: %04x\r\n", retval); +#endif + remover = core_list_undo_remove(remover, list->next); + /* sort the list by index, in effect returning the list to original state */ + list = core_list_mergesort(list, cmp_idx, NULL); + /* CRC data content of list */ + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 2: %04x\r\n", retval); +#endif + return retval; +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be + determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head * +core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) +{ + /* calculated pointers for the list */ + ee_u32 per_item = 16 + sizeof(struct list_data_s); + ee_u32 size = (blksize / per_item) + - 2; /* to accommodate systems with 64b pointers, and make sure + same code is executed, set max list elements */ + list_head *memblock_end = memblock + size; + list_data *datablock = (list_data *)(memblock_end); + list_data *datablock_end = datablock + size; + /* some useful variables */ + ee_u32 i; + list_head *finder, *list = memblock; + list_data info; + + /* create a fake items for the list head and tail */ + list->next = NULL; + list->info = datablock; + list->info->idx = 0x0000; + list->info->data16 = (ee_s16)0x8080; + memblock++; + datablock++; + info.idx = 0x7fff; + info.data16 = (ee_s16)0xffff; + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + + /* then insert size items */ + for (i = 0; i < size; i++) + { + ee_u16 datpat = ((ee_u16)(seed ^ i) & 0xf); + ee_u16 dat + = (datpat << 3) | (i & 0x7); /* alternate between algorithms */ + info.data16 = (dat << 8) | dat; /* fill the data with actual data and + upper bits with rebuild value */ + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + } + /* and now index the list so we know initial seed order of the list */ + finder = list->next; + i = 1; + while (finder->next != NULL) + { + if (i < size / 5) /* first 20% of the list in order */ + finder->info->idx = i++; + else + { + ee_u16 pat = (ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx = 0x3fff + & (((i & 0x07) << 8) + | pat); /* make sure the mixed items end up + after the ones in sequence */ + } + finder = finder->next; + } + list = core_list_mergesort(list, cmp_idx, NULL); +#if CORE_DEBUG + ee_printf("Initialized list:\r\n"); + finder = list; + while (finder) + { + ee_printf( + "[%04x,%04x]", finder->info->idx, (ee_u16)finder->info->data16); + finder = finder->next; + } + ee_printf("\r\n"); +#endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head * +core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end) +{ + list_head *newitem; + + if ((*memblock + 1) >= memblock_end) + return NULL; + if ((*datablock + 1) >= datablock_end) + return NULL; + + newitem = *memblock; + (*memblock)++; + newitem->next = insert_point->next; + insert_point->next = newitem; + + newitem->info = *datablock; + (*datablock)++; + copy_info(newitem->info, info); + + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to + check for NULL. + + Returns: + Removed item. +*/ +list_head * +core_list_remove(list_head *item) +{ + list_data *tmp; + list_head *ret = item->next; + /* swap data pointers */ + tmp = item->info; + item->info = ret->info; + ret->info = tmp; + /* and eliminate item */ + item->next = item->next->next; + ret->next = NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the + item_modified - List item that was modified during + + Returns: + The item that was linked back to the list. + +*/ +list_head * +core_list_undo_remove(list_head *item_removed, list_head *item_modified) +{ + list_data *tmp; + /* swap data pointers */ + tmp = item_removed->info; + item_removed->info = item_modified->info; + item_modified->info = tmp; + /* and insert item */ + item_removed->next = item_modified->next; + item_modified->next = item_removed; + return item_removed; +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head * +core_list_reverse(list_head *list) +{ + list_head *next = NULL, *tmp; + while (list) + { + tmp = list->next; + list->next = next; + next = list; + list = tmp; + } + return next; +} +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative + rather then recursive algorithm. The sort can either return the list to + original order (by idx) , or use the data item to invoke other other + algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + + */ +list_head * +core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) +{ + list_head *p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + if (!q) + break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info, q->info, res) <= 0) + { + /* First element of p is lower (or same); e must come from + * p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } +#if COMPILER_REQUIRES_SORT_RETURN + return list; +#endif +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_main.c new file mode 100644 index 0000000..c5c69e5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_main.c @@ -0,0 +1,444 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed + initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" + +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = { (ee_u16)0xd4b0, + (ee_u16)0x3340, + (ee_u16)0x6a79, + (ee_u16)0xe714, + (ee_u16)0xe3c1 }; +static ee_u16 matrix_known_crc[] = { (ee_u16)0xbe52, + (ee_u16)0x1199, + (ee_u16)0x5608, + (ee_u16)0x1fd7, + (ee_u16)0x0747 }; +static ee_u16 state_known_crc[] = { (ee_u16)0x5e47, + (ee_u16)0x39bf, + (ee_u16)0xe5a4, + (ee_u16)0x8e3a, + (ee_u16)0x8d84 }; +void * +iterate(void *pres) +{ + ee_u32 i; + ee_u16 crc; + core_results *res = (core_results *)pres; + ee_u32 iterations = res->iterations; + res->crc = 0; + res->crclist = 0; + res->crcmatrix = 0; + res->crcstate = 0; + + for (i = 0; i < iterations; i++) + { + crc = core_bench_list(res, 1); + res->crc = crcu16(crc, res->crc); + crc = core_bench_list(res, -1); + res->crc = crcu16(crc, res->crc); + if (i == 0) + res->crclist = res->crc; + } + return NULL; +} + +#if (SEED_METHOD == SEED_ARG) +ee_s32 get_seed_args(int i, int argc, char *argv[]); +#define get_seed(x) (ee_s16) get_seed_args(x, argc, argv) +#define get_seed_32(x) get_seed_args(x, argc, argv) +#else /* via function or volatile */ +ee_s32 get_seed_32(int i); +#define get_seed(x) (ee_s16) get_seed_32(x) +#endif + +#if (MEM_METHOD == MEM_STATIC) +ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char *mem_name[3] = { "Static", "Heap", "Stack" }; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at + compile time. 2 - Initialize memory block for use. 3 - Run and time the + benchmark. 4 - Report results, testing the validity of the output if the + seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be + identical 3 - third seed : Any value, should be at least an order of + magnitude less then the input size, but bigger then 32. 4 - Iterations : + Special, if set to 0, iterations will be automatically determined such that + the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE +main(void) +{ + int argc = 0; + char *argv[1]; + ee_printf("coremark app is running, please wait..."); +#else +MAIN_RETURN_TYPE +main(int argc, char *argv[]) +{ +#endif + ee_u16 i, j = 0, num_algorithms = 0; + ee_s16 known_id = -1, total_errors = 0; + ee_u16 seedcrc = 0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; +#if (MEM_METHOD == MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE * MULTITHREAD]; +#endif + ee_printf("coremark app is running, please wait...\r\n"); + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s) > 128) + { + ee_printf("list_head structure too big for comparable data!\r\n"); + return MAIN_RETURN_VAL; + } + results[0].seed1 = get_seed(1); + results[0].seed2 = get_seed(2); + results[0].seed3 = get_seed(3); + results[0].iterations = get_seed_32(4); +#if CORE_DEBUG + results[0].iterations = 1; +#endif + results[0].execs = get_seed_32(5); + if (results[0].execs == 0) + { /* if not supplied, execute all algorithms */ + results[0].execs = ALL_ALGORITHMS_MASK; + } + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1 == 0) && (results[0].seed2 == 0) + && (results[0].seed3 == 0)) + { /* performance run */ + results[0].seed1 = 0; + results[0].seed2 = 0; + results[0].seed3 = 0x66; + } + if ((results[0].seed1 == 1) && (results[0].seed2 == 0) + && (results[0].seed3 == 0)) + { /* validation run */ + results[0].seed1 = 0x3415; + results[0].seed2 = 0x3415; + results[0].seed3 = 0x66; + } +#if (MEM_METHOD == MEM_STATIC) + results[0].memblock[0] = (void *)static_memblk; + results[0].size = TOTAL_DATA_SIZE; + results[0].err = 0; +#if (MULTITHREAD > 1) +#error "Cannot use a static data area with multiple contexts!" +#endif +#elif (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) + { + ee_s32 malloc_override = get_seed(7); + if (malloc_override != 0) + results[i].size = malloc_override; + else + results[i].size = TOTAL_DATA_SIZE; + results[i].memblock[0] = portable_malloc(results[i].size); + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; + } +#elif (MEM_METHOD == MEM_STACK) +for (i = 0; i < MULTITHREAD; i++) +{ + results[i].memblock[0] = stack_memblock + i * TOTAL_DATA_SIZE; + results[i].size = TOTAL_DATA_SIZE; + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; +} +#else +#error "Please define a way to initialize a memory block." +#endif + /* Data init */ + /* Find out how space much we have based on number of algorithms */ + for (i = 0; i < NUM_ALGORITHMS; i++) + { + if ((1 << (ee_u32)i) & results[0].execs) + num_algorithms++; + } + for (i = 0; i < MULTITHREAD; i++) + results[i].size = results[i].size / num_algorithms; + /* Assign pointers */ + for (i = 0; i < NUM_ALGORITHMS; i++) + { + ee_u32 ctx; + if ((1 << (ee_u32)i) & results[0].execs) + { + for (ctx = 0; ctx < MULTITHREAD; ctx++) + results[ctx].memblock[i + 1] + = (char *)(results[ctx].memblock[0]) + results[0].size * j; + j++; + } + } + /* call inits */ + for (i = 0; i < MULTITHREAD; i++) + { + if (results[i].execs & ID_LIST) + { + results[i].list = core_list_init( + results[0].size, results[i].memblock[1], results[i].seed1); + } + if (results[i].execs & ID_MATRIX) + { + core_init_matrix(results[0].size, + results[i].memblock[2], + (ee_s32)results[i].seed1 + | (((ee_s32)results[i].seed2) << 16), + &(results[i].mat)); + } + if (results[i].execs & ID_STATE) + { + core_init_state( + results[0].size, results[i].seed1, results[i].memblock[3]); + } + } + + /* automatically determine number of iterations if not set */ + if (results[0].iterations == 0) + { + secs_ret secs_passed = 0; + ee_u32 divisor; + results[0].iterations = 1; + while (secs_passed < (secs_ret)1) + { + results[0].iterations *= 10; + start_time(); + iterate(&results[0]); + stop_time(); + secs_passed = time_in_secs(get_time()); + } + /* now we know it executes for at least 1 sec, set actual run time at + * about 10 secs */ + divisor = (ee_u32)secs_passed; + if (divisor == 0) /* some machines cast float to int as 0 since this + conversion is not defined by ANSI, but we know at + least one second passed */ + divisor = 1; + results[0].iterations *= 1 + 10 / divisor; + } + /* perform actual benchmark */ + start_time(); +#if (MULTITHREAD > 1) + if (default_num_contexts > MULTITHREAD) + { + default_num_contexts = MULTITHREAD; + } + for (i = 0; i < default_num_contexts; i++) + { + results[i].iterations = results[0].iterations; + results[i].execs = results[0].execs; + core_start_parallel(&results[i]); + } + for (i = 0; i < default_num_contexts; i++) + { + core_stop_parallel(&results[i]); + } +#else + iterate(&results[0]); +#endif + stop_time(); + total_time = get_time(); + /* get a function of the input to report */ + seedcrc = crc16(results[0].seed1, seedcrc); + seedcrc = crc16(results[0].seed2, seedcrc); + seedcrc = crc16(results[0].seed3, seedcrc); + seedcrc = crc16(results[0].size, seedcrc); + + switch (seedcrc) + { /* test known output for common seeds */ + case 0x8a02: /* seed1=0, seed2=0, seed3=0x66, size 2000 per algorithm */ + known_id = 0; + ee_printf("6k performance run parameters for coremark.\r\n"); + break; + case 0x7b05: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 2000 per + algorithm */ + known_id = 1; + ee_printf("6k validation run parameters for coremark.\r\n"); + break; + case 0x4eaf: /* seed1=0x8, seed2=0x8, seed3=0x8, size 400 per algorithm + */ + known_id = 2; + ee_printf("Profile generation run parameters for coremark.\r\n"); + break; + case 0xe9f5: /* seed1=0, seed2=0, seed3=0x66, size 666 per algorithm */ + known_id = 3; + ee_printf("2K performance run parameters for coremark.\r\n"); + break; + case 0x18f2: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 666 per + algorithm */ + known_id = 4; + ee_printf("2K validation run parameters for coremark.\r\n"); + break; + default: + total_errors = -1; + break; + } + if (known_id >= 0) + { + for (i = 0; i < default_num_contexts; i++) + { + results[i].err = 0; + if ((results[i].execs & ID_LIST) + && (results[i].crclist != list_known_crc[known_id])) + { + ee_printf("[%u]ERROR! list crc 0x%04x - should be 0x%04x\r\n", + i, + results[i].crclist, + list_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_MATRIX) + && (results[i].crcmatrix != matrix_known_crc[known_id])) + { + ee_printf("[%u]ERROR! matrix crc 0x%04x - should be 0x%04x\r\n", + i, + results[i].crcmatrix, + matrix_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_STATE) + && (results[i].crcstate != state_known_crc[known_id])) + { + ee_printf("[%u]ERROR! state crc 0x%04x - should be 0x%04x\r\n", + i, + results[i].crcstate, + state_known_crc[known_id]); + results[i].err++; + } + total_errors += results[i].err; + } + } + total_errors += check_data_types(); + /* and report results */ + ee_printf("CoreMark Size : %lu\r\n", (long unsigned)results[0].size); + ee_printf("Total ticks : %lu\r\n", (long unsigned)total_time); +#if HAS_FLOAT + ee_printf("Total time (secs): %f\r\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %f\r\n", + default_num_contexts * results[0].iterations + / time_in_secs(total_time)); +#else + ee_printf("Total time (secs): %d\r\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\r\n", + default_num_contexts * results[0].iterations + / time_in_secs(total_time)); +#endif + if (time_in_secs(total_time) < 10) + { + ee_printf( + "ERROR! Must execute for at least 10 secs for a valid result!\r\n"); + total_errors++; + } + + ee_printf("Iterations : %lu\r\n", + (long unsigned)default_num_contexts * results[0].iterations); + ee_printf("Compiler version : %s\r\n", COMPILER_VERSION); + ee_printf("Compiler flags : %s\r\n", COMPILER_FLAGS); +#if (MULTITHREAD > 1) + ee_printf("Parallel %s : %d\r\n", PARALLEL_METHOD, default_num_contexts); +#endif + ee_printf("Memory location : %s\r\n", MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\r\n", seedcrc); + if (results[0].execs & ID_LIST) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crclist : 0x%04x\r\n", i, results[i].crclist); + if (results[0].execs & ID_MATRIX) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcmatrix : 0x%04x\r\n", i, results[i].crcmatrix); + if (results[0].execs & ID_STATE) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcstate : 0x%04x\r\n", i, results[i].crcstate); + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcfinal : 0x%04x\r\n", i, results[i].crc); + if (total_errors == 0) + { + ee_printf( + "Correct operation validated. See README.md for run and reporting " + "rules.\r\n"); +#if HAS_FLOAT + if (known_id == 3) + { + ee_printf("CoreMark 1.0 : %f / %s / %s", + default_num_contexts * results[0].iterations + / time_in_secs(total_time), + COMPILER_VERSION, + COMPILER_FLAGS); +#if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) + ee_printf(" / %s", MEM_LOCATION); +#else + ee_printf(" / %s", mem_name[MEM_METHOD]); +#endif + +#if (MULTITHREAD > 1) + ee_printf(" / %d:%s", default_num_contexts, PARALLEL_METHOD); +#endif + ee_printf("\r\n"); + } +#endif + } + if (total_errors > 0) + ee_printf("Errors detected\r\n"); + if (total_errors < 0) + ee_printf( + "Cannot validate operation for these seed values, please compare " + "with results on a known platform.\r\n"); + +#if (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) + portable_free(results[i].memblock[0]); +#endif + /* And last call any target specific code for finalizing */ + portable_fini(&(results[0].port)); + + return MAIN_RETURN_VAL; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_matrix.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_matrix.c new file mode 100644 index 0000000..83c5922 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_matrix.c @@ -0,0 +1,359 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Matrix manipulation benchmark + + This very simple algorithm forms the basis of many more complex +algorithms. + + The tight inner loop is the focus of many optimizations (compiler as +well as hardware based) and is thus relevant for embedded processing. + + The total available data space will be divided to 3 parts: + NxN Matrix A - initialized with small values (upper 3/4 of the bits all +zero). NxN Matrix B - initialized with medium values (upper half of the bits all +zero). NxN Matrix C - used for the result. + + The actual values for A and B must be derived based on input that is not +available at compile time. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val); +ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval); +void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val); +void matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val); + +#define matrix_test_next(x) (x + 1) +#define matrix_clip(x, y) ((y) ? (x)&0x0ff : (x)&0x0ffff) +#define matrix_big(x) (0xf000 | (x)) +#define bit_extract(x, from, to) (((x) >> (from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void +printmat(MATDAT *A, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\r\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", A[i * N + j]); + } + ee_printf("\r\n"); + } +} +void +printmatC(MATRES *C, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\r\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", C[i * N + j]); + } + ee_printf("\r\n"); + } +} +#endif +/* Function: core_bench_matrix + Benchmark function + + Iterate N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 +core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) +{ + ee_u32 N = p->N; + MATRES *C = p->C; + MATDAT *A = p->A; + MATDAT *B = p->B; + MATDAT val = (MATDAT)seed; + + crc = crc16(matrix_test(N, C, A, B, val), crc); + + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by . + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 +matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) +{ + ee_u16 crc = 0; + MATDAT clipval = matrix_big(val); + + matrix_add_const(N, A, val); /* make sure data changes */ +#if CORE_DEBUG + printmat(A, N, "matrix_add_const"); +#endif + matrix_mul_const(N, C, A, val); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_const"); +#endif + matrix_mul_vect(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_vect"); +#endif + matrix_mul_matrix(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix"); +#endif + matrix_mul_matrix_bitextract(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix_bitextract"); +#endif + + matrix_add_const(N, A, -val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +ee_u32 +core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) +{ + ee_u32 N = 0; + MATDAT *A; + MATDAT *B; + ee_s32 order = 1; + MATDAT val; + ee_u32 i = 0, j = 0; + if (seed == 0) + seed = 1; + while (j < blksize) + { + i++; + j = i * i * 2 * 4; + } + N = i - 1; + A = (MATDAT *)align_mem(memblk); + B = A + N * N; + + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + seed = ((order * seed) % 65536); + val = (seed + order); + val = matrix_clip(val, 0); + B[i * N + j] = val; + val = (val + order); + val = matrix_clip(val, 1); + A[i * N + j] = val; + order++; + } + } + + p->A = A; + p->B = B; + p->C = (MATRES *)align_mem(B + N * N); + p->N = N; +#if CORE_DEBUG + printmat(A, N, "A"); + printmat(B, N, "B"); +#endif + return N; +} + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the + matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ +ee_s16 +matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) +{ + MATRES tmp = 0, prev = 0, cur = 0; + ee_s16 ret = 0; + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + cur = C[i * N + j]; + tmp += cur; + if (tmp > clipval) + { + ret += 10; + tmp = 0; + } + else + { + ret += (cur > prev) ? 1 : 0; + } + prev = cur; + } + } + return ret; +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void +matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = (MATRES)A[i * N + j] * (MATRES)val; + } + } +} + +/* Function: matrix_add_const + Add a constant value to all elements of a matrix. +*/ +void +matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + A[i * N + j] += val; + } + } +} + +/* Function: matrix_mul_vect + Multiply a matrix by a vector. + This is common in many simple filters (e.g. fir where a vector of + coefficients is applied to the matrix.) +*/ +void +matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + C[i] = 0; + for (j = 0; j < N; j++) + { + C[i] += (MATRES)A[i * N + j] * (MATRES)B[j]; + } + } +} + +/* Function: matrix_mul_matrix + Multiply a matrix by a matrix. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + C[i * N + j] += (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + } + } + } +} + +/* Function: matrix_mul_matrix_bitextract + Multiply a matrix by a matrix, and extract some bits from the result. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + MATRES tmp = (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + C[i * N + j] += bit_extract(tmp, 2, 4) * bit_extract(tmp, 5, 7); + } + } + } +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.c new file mode 100644 index 0000000..b4f37e4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.c @@ -0,0 +1,155 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" +#include "bsp.h" +#include "clint.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() +{ + return (clint_getTime(BSP_CLINT)); +//#error \ +// "You must implement a method to measure time in barebones_clock()! This function should return current time.\n" +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC BSP_CLINT_HZ + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void +start_time(void) +{ + GETMYTIME(&start_time_val); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void +stop_time(void) +{ + GETMYTIME(&stop_time_val); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by . This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by +*/ +CORE_TICKS +get_time(void) +{ + CORE_TICKS elapsed + = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + bsp_init(); + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) + { + ee_printf( + "ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\r\n"); + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\r\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void +portable_fini(core_portable *p) +{ + p->portable_id = 0; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.h new file mode 100644 index 0000000..5723208 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_portme.h @@ -0,0 +1,212 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#include "type.h" + +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 1 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 1 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 1 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "xpack risc-v gcc v8.3.0-2.3" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS "-o3" +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef unsigned long long ee_u64; +typedef ee_u32 ee_ptr_int; +typedef unsigned int ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u64 +typedef ee_u64 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use or + to enable them. + + It is valid to have a different implementation of + and in , to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ + && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_state.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_state.c new file mode 100644 index 0000000..c256076 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_state.c @@ -0,0 +1,330 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* local functions */ +enum CORE_STATE core_state_transition(ee_u8 **instr, ee_u32 *transition_count); + +/* +Topic: Description + Simple state machines like this one are used in many embedded products. + + For more complex state machines, sometimes a state transition table +implementation is used instead, trading speed of direct coding for ease of +maintenance. + + Since the main goal of using a state machine in CoreMark is to excercise +the switch/if behaviour, we are using a small moore machine. + + In particular, this machine tests type of string input, + trying to determine whether the input is a number or something else. + (see core_state.png). +*/ + +/* Function: core_bench_state + Benchmark function + + Go over the input twice, once direct, and once after introducing some + corruption. +*/ +ee_u16 +core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc) +{ + ee_u32 final_counts[NUM_CORE_STATES]; + ee_u32 track_counts[NUM_CORE_STATES]; + ee_u8 *p = memblock; + ee_u32 i; + +#if CORE_DEBUG + ee_printf("State Bench: %d,%d,%d,%04x\r\n", seed1, seed2, step, crc); +#endif + for (i = 0; i < NUM_CORE_STATES; i++) + { + final_counts[i] = track_counts[i] = 0; + } + /* run the state machine over the input */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\r\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* insert some corruption */ + if (*p != ',') + *p ^= (ee_u8)seed1; + p += step; + } + p = memblock; + /* run the state machine over the input again */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\r\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* undo corruption is seed1 and seed2 are equal */ + if (*p != ',') + *p ^= (ee_u8)seed2; + p += step; + } + /* end timing */ + for (i = 0; i < NUM_CORE_STATES; i++) + { + crc = crcu32(final_counts[i], crc); + crc = crcu32(track_counts[i], crc); + } + return crc; +} + +/* Default initialization patterns */ +static ee_u8 *intpat[4] + = { (ee_u8 *)"5012", (ee_u8 *)"1234", (ee_u8 *)"-874", (ee_u8 *)"+122" }; +static ee_u8 *floatpat[4] = { (ee_u8 *)"35.54400", + (ee_u8 *)".1234500", + (ee_u8 *)"-110.700", + (ee_u8 *)"+0.64400" }; +static ee_u8 *scipat[4] = { (ee_u8 *)"5.500e+3", + (ee_u8 *)"-.123e-2", + (ee_u8 *)"-87e+832", + (ee_u8 *)"+0.6e-12" }; +static ee_u8 *errpat[4] = { (ee_u8 *)"T0.3e-1F", + (ee_u8 *)"-T.T++Tq", + (ee_u8 *)"1T3.4e4z", + (ee_u8 *)"34.0e-T^" }; + +/* Function: core_init_state + Initialize the input data for the state machine. + + Populate the input with several predetermined strings, interspersed. + Actual patterns chosen depend on the seed parameter. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +void +core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p) +{ + ee_u32 total = 0, next = 0, i; + ee_u8 *buf = 0; +#if CORE_DEBUG + ee_u8 *start = p; + ee_printf("State: %d,%d\r\n", size, seed); +#endif + size--; + next = 0; + while ((total + next + 1) < size) + { + if (next > 0) + { + for (i = 0; i < next; i++) + *(p + total + i) = buf[i]; + *(p + total + i) = ','; + total += next + 1; + } + seed++; + switch (seed & 0x7) + { + case 0: /* int */ + case 1: /* int */ + case 2: /* int */ + buf = intpat[(seed >> 3) & 0x3]; + next = 4; + break; + case 3: /* float */ + case 4: /* float */ + buf = floatpat[(seed >> 3) & 0x3]; + next = 8; + break; + case 5: /* scientific */ + case 6: /* scientific */ + buf = scipat[(seed >> 3) & 0x3]; + next = 8; + break; + case 7: /* invalid */ + buf = errpat[(seed >> 3) & 0x3]; + next = 8; + break; + default: /* Never happen, just to make some compilers happy */ + break; + } + } + size++; + while (total < size) + { /* fill the rest with 0 */ + *(p + total) = 0; + total++; + } +#if CORE_DEBUG + ee_printf("State Input: %s\r\n", start); +#endif +} + +static ee_u8 +ee_isdigit(ee_u8 c) +{ + ee_u8 retval; + retval = ((c >= '0') & (c <= '9')) ? 1 : 0; + return retval; +} + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detected. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the + end state is returned (either specific format determined or invalid). +*/ + +enum CORE_STATE +core_state_transition(ee_u8 **instr, ee_u32 *transition_count) +{ + ee_u8 * str = *instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state = CORE_START; + for (; *str && state != CORE_INVALID; str++) + { + NEXT_SYMBOL = *str; + if (NEXT_SYMBOL == ',') /* end of this input */ + { + str++; + break; + } + switch (state) + { + case CORE_START: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_S1; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + transition_count[CORE_START]++; + break; + case CORE_S1: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + break; + case CORE_INT: + if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + break; + case CORE_FLOAT: + if (NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e') + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + break; + case CORE_S2: + if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + break; + case CORE_EXPONENT: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + break; + case CORE_SCIENTIFIC: + if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + break; + default: + break; + } + } + *instr = str; + return state; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_util.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_util.c new file mode 100644 index 0000000..c13d273 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/core_util.c @@ -0,0 +1,249 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different + methods are provided: 1 - Using a volatile variable. This method is only + valid if the compiler is forced to generate code that reads the value of a + volatile variable from memory at run time. Please note, if using this method, + you would need to modify core_portme.c to generate training profile. 2 - + Command line arguments. This is the preferred method if command line + arguments are supported. 3 - System function. If none of the first 2 methods + is available on the platform, a system function which is not a stub can be + used. + + e.g. read the value on GPIO pins connected to switches, or invoke + special simulator functions. +*/ +#if (SEED_METHOD == SEED_VOLATILE) +extern volatile ee_s32 seed1_volatile; +extern volatile ee_s32 seed2_volatile; +extern volatile ee_s32 seed3_volatile; +extern volatile ee_s32 seed4_volatile; +extern volatile ee_s32 seed5_volatile; +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = seed1_volatile; + break; + case 2: + retval = seed2_volatile; + break; + case 3: + retval = seed3_volatile; + break; + case 4: + retval = seed4_volatile; + break; + case 5: + retval = seed5_volatile; + break; + default: + retval = 0; + break; + } + return retval; +} +#elif (SEED_METHOD == SEED_ARG) +ee_s32 +parseval(char *valstring) +{ + ee_s32 retval = 0; + ee_s32 neg = 1; + int hexmode = 0; + if (*valstring == '-') + { + neg = -1; + valstring++; + } + if ((valstring[0] == '0') && (valstring[1] == 'x')) + { + hexmode = 1; + valstring += 2; + } + /* first look for digits */ + if (hexmode) + { + while (((*valstring >= '0') && (*valstring <= '9')) + || ((*valstring >= 'a') && (*valstring <= 'f'))) + { + ee_s32 digit = *valstring - '0'; + if (digit > 9) + digit = 10 + *valstring - 'a'; + retval *= 16; + retval += digit; + valstring++; + } + } + else + { + while ((*valstring >= '0') && (*valstring <= '9')) + { + ee_s32 digit = *valstring - '0'; + retval *= 10; + retval += digit; + valstring++; + } + } + /* now add qualifiers */ + if (*valstring == 'K') + retval *= 1024; + if (*valstring == 'M') + retval *= 1024 * 1024; + + retval *= neg; + return retval; +} + +ee_s32 +get_seed_args(int i, int argc, char *argv[]) +{ + if (argc > i) + return parseval(argv[i]); + return 0; +} + +#elif (SEED_METHOD == SEED_FUNC) +/* If using OS based function, you must define and implement the functions below + * in core_portme.h and core_portme.c ! */ +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = portme_sys1(); + break; + case 2: + retval = portme_sys2(); + break; + case 3: + retval = portme_sys3(); + break; + case 4: + retval = portme_sys4(); + break; + case 5: + retval = portme_sys5(); + break; + default: + retval = 0; + break; + } + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ +ee_u16 +crcu8(ee_u8 data, ee_u16 crc) +{ + ee_u8 i = 0, x16 = 0, carry = 0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + crc >>= 1; + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + return crc; +} +ee_u16 +crcu16(ee_u16 newval, ee_u16 crc) +{ + crc = crcu8((ee_u8)(newval), crc); + crc = crcu8((ee_u8)((newval) >> 8), crc); + return crc; +} +ee_u16 +crcu32(ee_u32 newval, ee_u16 crc) +{ + crc = crc16((ee_s16)newval, crc); + crc = crc16((ee_s16)(newval >> 16), crc); + return crc; +} +ee_u16 +crc16(ee_s16 newval, ee_u16 crc) +{ + return crcu16((ee_u16)newval, crc); +} + +ee_u8 +check_data_types() +{ + ee_u8 retval = 0; + if (sizeof(ee_u8) != 1) + { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\r\n"); + retval++; + } + if (sizeof(ee_u16) != 2) + { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\r\n"); + retval++; + } + if (sizeof(ee_s16) != 2) + { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\r\n"); + retval++; + } + if (sizeof(ee_s32) != 4) + { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\r\n"); + retval++; + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\r\n"); + retval++; + } + if (sizeof(ee_ptr_int) != sizeof(int *)) + { + ee_printf( + "ERROR: ee_ptr_int is not a datatype that holds an int pointer!\r\n"); + retval++; + } + if (retval > 0) + { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\r\n"); + } + return retval; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/coremark.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/coremark.h new file mode 100644 index 0000000..9c5e406 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/coremark.h @@ -0,0 +1,183 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE +#define TOTAL_DATA_SIZE 2 * 1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" + +#if HAS_STDIO +#include +#endif +#if HAS_PRINTF +#define ee_printf printf +#endif + +/* Actual benchmark execution in iterate */ +void *iterate(void *pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as + a double. Otherwise an unsigned int. +*/ +#if HAS_FLOAT +typedef double secs_ret; +#else +typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN +#define MAIN_RETURN_VAL +#define MAIN_RETURN_TYPE void +#else +#define MAIN_RETURN_VAL 0 +#define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void * portable_malloc(ee_size_t size); +void portable_free(void *p); +ee_s32 parseval(char *valstring); + +/* Algorithm IDS */ +#define ID_LIST (1 << 0) +#define ID_MATRIX (1 << 1) +#define ID_STATE (1 << 2) +#define ALL_ALGORITHMS_MASK (ID_LIST | ID_MATRIX | ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT +typedef ee_s16 MATDAT; +typedef ee_s32 MATRES; +#else +typedef ee_f16 MATDAT; +typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S +{ + int N; + MATDAT *A; + MATDAT *B; + MATRES *C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE +{ + CORE_START = 0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e; + +/* Helper structure to hold results */ +typedef struct RESULTS_S +{ + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void * memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s *list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD > 1) +ee_u8 core_start_parallel(core_results *res); +ee_u8 core_stop_parallel(core_results *res); +#endif + +/* list benchmark functions */ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); +ee_u16 core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, + void * memblk, + ee_s32 seed, + mat_params *p); +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/cvt.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/cvt.c new file mode 100644 index 0000000..333e8ea --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/ee_printf.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/ee_printf.c new file mode 100644 index 0000000..f5baabb --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/coremark/src/ee_printf.c @@ -0,0 +1,703 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "coremark.h" +#include +#include "bsp.h" + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char * digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char * upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen_cr(const char *s, ee_size_t count); + +static ee_size_t +strnlen_cr(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int +skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char * +number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char * +eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char * +iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void +ee_bufcpy(char *pd, char *ps, int count) +{ + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void +parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void +decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) + { + int n = strnlen_cr(buffer, 256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void +cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char * +flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen_cr(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int +ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + char * s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strnlen_cr(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), + 16, + field_width, + precision, + flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + else + str = iaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, + va_arg(args, double), + field_width, + precision, + *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void +uart_send_char(char c) +{ + uart_write(BSP_UART_TERMINAL, c); + /* Output of a char to a UART usually follows the following model: + Wait until UART is ready + Write char to UART + Wait until UART is done + + Or in code: + while (*UART_CONTROL_ADDRESS != UART_READY); + *UART_DATA_ADDRESS = c; + while (*UART_CONTROL_ADDRESS != UART_READY); + + Check the UART sample code on your platform or the board + documentation. + */ +} + +int +ee_printf(const char *fmt, ...) +{ + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) + { + uart_send_char(*p); + n++; + p++; + } + uart_send_char('\n'); + uart_send_char('\r'); + + return n; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/makefile new file mode 100644 index 0000000..a50a3b1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/makefile @@ -0,0 +1,22 @@ +PROJ_NAME=dhrystone + +STANDALONE=../.. + +CFLAGS+=-DSMP + +DEBUG=no +BENCH=yes + +CFLAGS += -fno-inline -fno-common +CFLAGS += -Wno-implicit-int -Wno-implicit-function-declaration -ffunction-sections + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.c new file mode 100644 index 0000000..cf68b63 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.c @@ -0,0 +1,181 @@ +// See LICENSE for license details. + +#pragma GCC optimize ("no-inline") + +#include "dhrystone.h" + +#ifndef REG +#define REG + /* REG becomes defined as empty */ + /* i.e. no register variables */ +#else +#undef REG +#define REG register +#endif + +extern int Int_Glob; +extern char Ch_1_Glob; + + +Proc_6 (Enum_Val_Par, Enum_Ref_Par) +/*********************************/ + /* executed once */ + /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ + +Enumeration Enum_Val_Par; +Enumeration *Enum_Ref_Par; +{ + *Enum_Ref_Par = Enum_Val_Par; + if (! Func_3 (Enum_Val_Par)) + /* then, not executed */ + *Enum_Ref_Par = Ident_4; + switch (Enum_Val_Par) + { + case Ident_1: + *Enum_Ref_Par = Ident_1; + break; + case Ident_2: + if (Int_Glob > 100) + /* then */ + *Enum_Ref_Par = Ident_1; + else *Enum_Ref_Par = Ident_4; + break; + case Ident_3: /* executed */ + *Enum_Ref_Par = Ident_2; + break; + case Ident_4: break; + case Ident_5: + *Enum_Ref_Par = Ident_3; + break; + } /* switch */ +} /* Proc_6 */ + + +Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref) +/**********************************************/ + /* executed three times */ + /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ + /* Int_Par_Ref becomes 7 */ + /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ + /* Int_Par_Ref becomes 17 */ + /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ + /* Int_Par_Ref becomes 18 */ +One_Fifty Int_1_Par_Val; +One_Fifty Int_2_Par_Val; +One_Fifty *Int_Par_Ref; +{ + One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 2; + *Int_Par_Ref = Int_2_Par_Val + Int_Loc; +} /* Proc_7 */ + + +Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val) +/*********************************************************************/ + /* executed once */ + /* Int_Par_Val_1 == 3 */ + /* Int_Par_Val_2 == 7 */ +Arr_1_Dim Arr_1_Par_Ref; +Arr_2_Dim Arr_2_Par_Ref; +int Int_1_Par_Val; +int Int_2_Par_Val; +{ + REG One_Fifty Int_Index; + REG One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 5; + Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; + Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; + Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; + for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) + Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; + Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; + Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; + Int_Glob = 5; +} /* Proc_8 */ + + +Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val) +/*************************************************/ + /* executed three times */ + /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ + /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ + /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ + +Capital_Letter Ch_1_Par_Val; +Capital_Letter Ch_2_Par_Val; +{ + Capital_Letter Ch_1_Loc; + Capital_Letter Ch_2_Loc; + + Ch_1_Loc = Ch_1_Par_Val; + Ch_2_Loc = Ch_1_Loc; + if (Ch_2_Loc != Ch_2_Par_Val) + /* then, executed */ + return (Ident_1); + else /* not executed */ + { + Ch_1_Glob = Ch_1_Loc; + return (Ident_2); + } +} /* Func_1 */ + + +Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref) +/*************************************************/ + /* executed once */ + /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ + /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ + +Str_30 Str_1_Par_Ref; +Str_30 Str_2_Par_Ref; +{ + REG One_Thirty Int_Loc; + Capital_Letter Ch_Loc; + + Int_Loc = 2; + while (Int_Loc <= 2) /* loop body executed once */ + if (Func_1 (Str_1_Par_Ref[Int_Loc], + Str_2_Par_Ref[Int_Loc+1]) == Ident_1) + /* then, executed */ + { + Ch_Loc = 'A'; + Int_Loc += 1; + } /* if, while */ + if (Ch_Loc >= 'W' && Ch_Loc < 'Z') + /* then, not executed */ + Int_Loc = 7; + if (Ch_Loc == 'R') + /* then, not executed */ + return (true); + else /* executed */ + { + if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) + /* then, not executed */ + { + Int_Loc += 7; + Int_Glob = Int_Loc; + return (true); + } + else /* executed */ + return (false); + } /* if Ch_Loc */ +} /* Func_2 */ + + +Boolean Func_3 (Enum_Par_Val) +/***************************/ + /* executed once */ + /* Enum_Par_Val == Ident_3 */ +Enumeration Enum_Par_Val; +{ + Enumeration Enum_Loc; + + Enum_Loc = Enum_Par_Val; + if (Enum_Loc == Ident_3) + /* then, executed */ + return (true); + else /* not executed */ + return (false); +} /* Func_3 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.h new file mode 100644 index 0000000..da00a2f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone.h @@ -0,0 +1,478 @@ +// See LICENSE for license details. + +#ifndef _DHRYSTONE_H +#define _DHRYSTONE_H + +/****************** "DHRYSTONE" Benchmark Program ***************************/ +#define Version "C, Version 2.2" +/* File: dhry_1.c (part 2 of 3) + * Author: Reinhold P. Weicker + * Siemens Nixdorf, Paderborn/Germany + * weicker@specbench.org + * Date: May 25, 1988 + * Modified: Steven Pemberton, CWI, Amsterdam; Steven.Pemberton@cwi.nl + * Date: October, 1993; March 1995 + * Included both files into one source, that gets compiled + * in two passes. Made program auto-compiling, and auto-running, + * and generally made it much easier to use. + * + * Original Version (in Ada) published in + * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), + * pp. 1013 - 1030, together with the statistics + * on which the distribution of statements etc. is based. + * + * In this C version, the following C library functions are used: + * - strcpy, strcmp (inside the measurement loop) + * - printf, scanf (outside the measurement loop) + * In addition, Berkeley UNIX system calls "times ()" or "time ()" + * are used for execution time measurement. For measurements + * on other systems, these calls have to be changed. + * + * Collection of Results: + * Reinhold Weicker (address see above) and + * + * Rick Richardson + * PC Research. Inc. + * 94 Apple Orchard Drive + * Tinton Falls, NJ 07724 + * Phone: (201) 389-8963 (9-17 EST) + * Usenet: ...!uunet!pcrat!rick + * + * Please send results to Rick Richardson and/or Reinhold Weicker. + * Complete information should be given on hardware and software used. + * Hardware information includes: Machine type, CPU, type and size + * of caches; for microprocessors: clock frequency, memory speed + * (number of wait states). + * Software information includes: Compiler (and runtime library) + * manufacturer and version, compilation switches, OS version. + * The Operating System version may give an indication about the compiler; + * Dhrystone itself performs no OS calls in the measurement loop. + * + * The complete output generated by the program should be mailed + * such that at least some checks for correctness can be made. + * + *************************************************************************** + * + * Defines: The following "Defines" are possible: + * -DREG (default: Not defined) + * As an approximation to what an average C programmer + * might do, causes the "register" storage class to be applied + * - for local variables, if they are used (dynamically) + * five or more times + * - for parameters if they are used (dynamically) + * six or more times + * Note that an optimal "register" strategy is + * compiler-dependent, and that "register" declarations + * do not necessarily lead to faster execution. + * -DNOSTRUCTASSIGN (default: Not defined) + * Define if the C compiler does not support + * assignment of structures. + * -DNOENUMS (default: Not defined) + * Define if the C compiler does not support + * enumeration types. + * -DTIMES (default) + * -DTIME + * The "times" function of UNIX (returning process times) + * or the "time" function (returning wallclock time) + * is used for measurement. + * For single user machines, "time ()" is adequate. For + * multi-user machines where you cannot get single-user + * access, use the "times ()" function. If you have + * neither, use a stopwatch in the dead of night. + * "printf"s are provided marking the points "Start Timer" + * and "Stop Timer". DO NOT use the UNIX "time(1)" + * command, as this will measure the total time to + * run this program, which will (erroneously) include + * the time to allocate storage (malloc) and to perform + * the initialization. + * -DHZ=nnn + * In Berkeley UNIX, the function "times" returns process + * time in 1/HZ seconds, with HZ = 60 for most systems. + * CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY + * A VALUE. + * + *************************************************************************** + * + * History: Version C/2.1 was made for two reasons: + * + * 1) There was an obvious need for a common C version of + * Dhrystone, since C is at present the most popular system + * programming language for the class of processors + * (microcomputers, minicomputers) where Dhrystone is used most. + * There should be, as far as possible, only one C version of + * Dhrystone such that results can be compared without + * restrictions. In the past, the C versions distributed + * by Rick Richardson (Version 1.1) and by Reinhold Weicker + * had small (though not significant) differences. + * + * 2) As far as it is possible without changes to the Dhrystone + * statistics, optimizing compilers should be prevented from + * removing significant statements. + * + * This C version has been developed in cooperation with + * Rick Richardson (Tinton Falls, NJ), it incorporates many + * ideas from the "Version 1.1" distributed previously by + * him over the UNIX network Usenet. + * I also thank Chaim Benedelac (National Semiconductor), + * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), + * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) + * for their help with comments on earlier versions of the + * benchmark. + * + * Changes: In the initialization part, this version follows mostly + * Rick Richardson's version distributed via Usenet, not the + * version distributed earlier via floppy disk by Reinhold Weicker. + * As a concession to older compilers, names have been made + * unique within the first 8 characters. + * Inside the measurement loop, this version follows the + * version previously distributed by Reinhold Weicker. + * + * At several places in the benchmark, code has been added, + * but within the measurement loop only in branches that + * are not executed. The intention is that optimizing compilers + * should be prevented from moving code out of the measurement + * loop, or from removing code altogether. Since the statements + * that are executed within the measurement loop have NOT been + * changed, the numbers defining the "Dhrystone distribution" + * (distribution of statements, operand types and locality) + * still hold. Except for sophisticated optimizing compilers, + * execution times for this version should be the same as + * for previous versions. + * + * Since it has proven difficult to subtract the time for the + * measurement loop overhead in a correct way, the loop check + * has been made a part of the benchmark. This does have + * an impact - though a very minor one - on the distribution + * statistics which have been updated for this version. + * + * All changes within the measurement loop are described + * and discussed in the companion paper "Rationale for + * Dhrystone version 2". + * + * Because of the self-imposed limitation that the order and + * distribution of the executed statements should not be + * changed, there are still cases where optimizing compilers + * may not generate code for some statements. To a certain + * degree, this is unavoidable for small synthetic benchmarks. + * Users of the benchmark are advised to check code listings + * whether code is generated for all statements of Dhrystone. + * + * Version 2.1 is identical to version 2.0 distributed via + * the UNIX network Usenet in March 1988 except that it corrects + * some minor deficiencies that were found by users of version 2.0. + * The only change within the measurement loop is that a + * non-executed "else" part was added to the "if" statement in + * Func_3, and a non-executed "else" part removed from Proc_3. + * + * Version C/2.2, Steven Pemberton, October 1993 + * Functionally, identical to version 2.2; the changes are in + * how you compile and use it: + * - Everything is in one file now, but compiled in 2 passes + * - Compile (and run) by running the file through the shell: 'sh dhry.c" + * - Uses the system definition of HZ if one can be found + * - HZ must be defined, otherwise it won't compile (no defaults here) + * - The (uninteresting) output is printed to stderr (dhry2 > /dev/null) + * - The number of loops is passed as a parameter, rather than read + * (dhry2 500000) + * - If the number of loops is insufficient to get a good result, + * it repeats it with loops*10 until it is enough (rather than just + * stopping) + * - Output says which sort of clock it is using, and the HZ value + * - You can use -DREG instead of the -DREG=register of previous versions + * - Some stylistic cleanups. + * + *************************************************************************** + * + * Compilation model and measurement (IMPORTANT): + * + * The following "ground rules" apply for measurements: + * - Separate compilation + * - No procedure merging + * - Otherwise, compiler optimizations are allowed but should be indicated + * - Default results are those without register declarations + * See the companion paper "Rationale for Dhrystone Version 2" for a more + * detailed discussion of these ground rules. + * + * For 16-Bit processors (e.g. 80186, 80286), times for all compilation + * models ("small", "medium", "large" etc.) should be given if possible, + * together with a definition of these models for the compiler system used. + * + ************************************************************************** + * + * Dhrystone (C version) statistics: + * + * [Comment from the first distribution, updated for version 2. + * Note that because of language differences, the numbers are slightly + * different from the Ada version.] + * + * The following program contains statements of a high level programming + * language (here: C) in a distribution considered representative: + * + * assignments 52 (51.0 %) + * control statements 33 (32.4 %) + * procedure, function calls 17 (16.7 %) + * + * 103 statements are dynamically executed. The program is balanced with + * respect to the three aspects: + * + * - statement type + * - operand type + * - operand locality + * operand global, local, parameter, or constant. + * + * The combination of these three aspects is balanced only approximately. + * + * 1. Statement Type: + * ----------------- number + * + * V1 = V2 9 + * (incl. V1 = F(..) + * V = Constant 12 + * Assignment, 7 + * with array element + * Assignment, 6 + * with record component + * -- + * 34 34 + * + * X = Y +|-|"&&"|"|" Z 5 + * X = Y +|-|"==" Constant 6 + * X = X +|- 1 3 + * X = Y *|/ Z 2 + * X = Expression, 1 + * two operators + * X = Expression, 1 + * three operators + * -- + * 18 18 + * + * if .... 14 + * with "else" 7 + * without "else" 7 + * executed 3 + * not executed 4 + * for ... 7 | counted every time + * while ... 4 | the loop condition + * do ... while 1 | is evaluated + * switch ... 1 + * break 1 + * declaration with 1 + * initialization + * -- + * 34 34 + * + * P (...) procedure call 11 + * user procedure 10 + * library procedure 1 + * X = F (...) + * function call 6 + * user function 5 + * library function 1 + * -- + * 17 17 + * --- + * 103 + * + * The average number of parameters in procedure or function calls + * is 1.82 (not counting the function values aX * + * + * 2. Operators + * ------------ + * number approximate + * percentage + * + * Arithmetic 32 50.8 + * + * + 21 33.3 + * - 7 11.1 + * * 3 4.8 + * / (int div) 1 1.6 + * + * Comparison 27 42.8 + * + * == 9 14.3 + * /= 4 6.3 + * > 1 1.6 + * < 3 4.8 + * >= 1 1.6 + * <= 9 14.3 + * + * Logic 4 6.3 + * + * && (AND-THEN) 1 1.6 + * | (OR) 1 1.6 + * ! (NOT) 2 3.2 + * + * -- ----- + * 63 100.1 + * + * + * 3. Operand Type (counted once per operand reference): + * --------------- + * number approximate + * percentage + * + * Integer 175 72.3 % + * Character 45 18.6 % + * Pointer 12 5.0 % + * String30 6 2.5 % + * Array 2 0.8 % + * Record 2 0.8 % + * --- ------- + * 242 100.0 % + * + * When there is an access path leading to the final operand (e.g. a record + * component), only the final data type on the access path is counted. + * + * + * 4. Operand Locality: + * ------------------- + * number approximate + * percentage + * + * local variable 114 47.1 % + * global variable 22 9.1 % + * parameter 45 18.6 % + * value 23 9.5 % + * reference 22 9.1 % + * function result 6 2.5 % + * constant 55 22.7 % + * --- ------- + * 242 100.0 % + * + * The program does not compute anything meaningful, but it is syntactically + * and semantically correct. All variables have a value assigned to them + * before they are used as a source operand. + * + * There has been no explicit effort to account for the effects of a + * cache, or to balance the use of long or short displacements for code or + * data. + * + *************************************************************************** + */ + +/* Compiler and system dependent definitions: */ +#include "riscv.h" +#include "bsp.h" +/* variables for time measurement: */ + +#ifdef TIME + +#define CLOCK_TYPE "time()" +#undef HZ +#define HZ CORE_HZ /* time() returns time in clock cycles*/ +extern long time(); /* see library function "time" */ +#define Too_Small_Time 100000 /* Measurements should last at least 2 seconds */ +#define Start_Timer() Begin_Time = time ( (long *) 0) +#define Stop_Timer() End_Time = time ( (long *) 0) + +#else + +#ifdef MSC_CLOCK /* Use Microsoft C hi-res clock */ + +#undef HZ +#undef TIMES +#include +#define HZ CLK_TCK +#define CLOCK_TYPE "MSC clock()" +extern clock_t clock(); +#define Too_Small_Time (2*HZ) +#define Start_Timer() Begin_Time = clock() +#define Stop_Timer() End_Time = clock() + +#elif defined(__riscv) + +#define HZ SYSTEM_CLINT_HZ +#define Too_Small_Time 1 +#define CLOCK_TYPE "rdcycle()" +#define Start_Timer() Begin_Time = csr_read(mcycle) +#define Stop_Timer() End_Time = csr_read(mcycle) + +#else + /* Use times(2) time function unless */ + /* explicitly defined otherwise */ +#define CLOCK_TYPE "times()" +#include +#include +#ifndef HZ /* Added by SP 900619 */ +#include /* If your system doesn't have this, use -DHZ=xxx */ +#else + *** You must define HZ!!! *** +#endif /* HZ */ +#ifndef PASS2 +struct tms time_info; +#endif +/*extern int times ();*/ + /* see library function "times" */ +#define Too_Small_Time (2*HZ) + /* Measurements should last at least about 2 seconds */ +#define Start_Timer() times(&time_info); Begin_Time=(long)time_info.tms_utime +#define Stop_Timer() times(&time_info); End_Time = (long)time_info.tms_utime + +#endif /* MSC_CLOCK */ +#endif /* TIME */ + + +#define Mic_secs_Per_Second 1000000 +#define NUMBER_OF_RUNS 500 /* Default number of runs */ + +#ifdef NOSTRUCTASSIGN +#define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) +#else +#define structassign(d, s) d = s +#endif + +#ifdef NOENUM +#define Ident_1 0 +#define Ident_2 1 +#define Ident_3 2 +#define Ident_4 3 +#define Ident_5 4 + typedef int Enumeration; +#else + typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} + Enumeration; +#endif + /* for boolean and enumeration types in Ada, Pascal */ + +/* General definitions: */ + +#include +#include + /* for strcpy, strcmp */ + +#define Null 0 + /* Value of a Null pointer */ +#define true 1 +#define false 0 + +typedef int One_Thirty; +typedef int One_Fifty; +typedef char Capital_Letter; +typedef int Boolean; +typedef char Str_30 [31]; +typedef int Arr_1_Dim [50]; +typedef int Arr_2_Dim [50] [50]; + +typedef struct record + { + struct record *Ptr_Comp; + Enumeration Discr; + union { + struct { + Enumeration Enum_Comp; + int Int_Comp; + char Str_Comp [31]; + } var_1; + struct { + Enumeration E_Comp_2; + char Str_2_Comp [31]; + } var_2; + struct { + char Ch_1_Comp; + char Ch_2_Comp; + } var_3; + } variant; + } Rec_Type, *Rec_Pointer; + +#endif \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone_main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone_main.c new file mode 100644 index 0000000..0c94078 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/dhrystone_main.c @@ -0,0 +1,343 @@ +// See LICENSE for license details. + +/****************************************************************************** +* +* @file dhrystone_main.c: Dhrystone +* +* @brief The Dhrystone example (dhrystone directory) is a classic benchmark for +* testing CPU performance. +* +******************************************************************************/ +#pragma GCC optimize ("no-inline") + +#include "dhrystone.h" + +#define debug_printf printf +//#define debug_printf(str, ...) {} + +#include + +/* Global Variables: */ + +Rec_Pointer Ptr_Glob, + Next_Ptr_Glob; +int Int_Glob; +Boolean Bool_Glob; +char Ch_1_Glob, + Ch_2_Glob; +int Arr_1_Glob [50]; +int Arr_2_Glob [50] [50]; + +Enumeration Func_1 (); + /* forward declaration necessary since Enumeration may not simply be int */ + +#ifndef REG + Boolean Reg = false; +#define REG + /* REG becomes defined as empty */ + /* i.e. no register variables */ +#else + Boolean Reg = true; +#undef REG +#define REG register +#endif + +Boolean Done; + +long Begin_Time, + End_Time, + User_Time; +long Microseconds, + Dhrystones_Per_Second; + +/* end of variables for time measurement */ + + +int main (int argc, char** argv) +/*****/ + /* main program, corresponds to procedures */ + /* Main and Proc_0 in the Ada version */ +{ + One_Fifty Int_1_Loc; + REG One_Fifty Int_2_Loc; + One_Fifty Int_3_Loc; + REG char Ch_Index; + Enumeration Enum_Loc; + Str_30 Str_1_Loc; + Str_30 Str_2_Loc; + REG int Run_Index; + REG int Number_Of_Runs; + + /* Arguments */ + Number_Of_Runs = NUMBER_OF_RUNS; + + /* Initializations */ + bsp_init(); + + Next_Ptr_Glob = (Rec_Pointer) alloca (sizeof (Rec_Type)); + Ptr_Glob = (Rec_Pointer) alloca (sizeof (Rec_Type)); + + Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; + Ptr_Glob->Discr = Ident_1; + Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; + Ptr_Glob->variant.var_1.Int_Comp = 40; + strcpy (Ptr_Glob->variant.var_1.Str_Comp, + "DHRYSTONE PROGRAM, SOME STRING"); + strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); + + Arr_2_Glob [8][7] = 10; + /* Was missing in published program. Without this statement, */ + /* Arr_2_Glob [8][7] would have an undefined value. */ + /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ + /* overflow may occur for this array element. */ + + debug_printf("\r\n"); + debug_printf("Dhrystone Benchmark, Version %s\r\n", Version); + if (Reg) + { + debug_printf("Program compiled with 'register' attribute\r\n"); + } + else + { + debug_printf("Program compiled without 'register' attribute\r\n"); + } + debug_printf("Using %s, HZ=%d\r\n", CLOCK_TYPE, HZ); + debug_printf("\r\n"); + + Done = false; + while (!Done) { + debug_printf("Trying %d runs through Dhrystone:\r\n", Number_Of_Runs); + + /***************/ + /* Start timer */ + /***************/ + + setStats(1); + Start_Timer(); + + for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) + { + Proc_5(); + Proc_4(); + /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ + Int_1_Loc = 2; + Int_2_Loc = 3; + strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); + Enum_Loc = Ident_2; + Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); + /* Bool_Glob == 1 */ + while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ + { + Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; + /* Int_3_Loc == 7 */ + Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); + /* Int_3_Loc == 7 */ + Int_1_Loc += 1; + } /* while */ + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); + /* Int_Glob == 5 */ + Proc_1 (Ptr_Glob); + for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) + /* loop body executed twice */ + { + if (Enum_Loc == Func_1 (Ch_Index, 'C')) + /* then, not executed */ + { + Proc_6 (Ident_1, &Enum_Loc); + strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); + Int_2_Loc = Run_Index; + Int_Glob = Run_Index; + } + } + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Int_2_Loc = Int_2_Loc * Int_1_Loc; + Int_1_Loc = Int_2_Loc / Int_3_Loc; + Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; + /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ + Proc_2 (&Int_1_Loc); + /* Int_1_Loc == 5 */ + + } /* loop "for Run_Index" */ + + /**************/ + /* Stop timer */ + /**************/ + + Stop_Timer(); + setStats(0); + + User_Time = End_Time - Begin_Time; + + if (User_Time < Too_Small_Time) + { + printf("Measured time too small to obtain meaningful results\r\n"); + Number_Of_Runs = Number_Of_Runs * 10; + printf("\r\n"); + } else Done = true; + } + + debug_printf("Final values of the variables used in the benchmark:\r\n"); + debug_printf("\r\n"); + debug_printf("Int_Glob: %d\r\n", Int_Glob); + debug_printf(" should be: %d\r\n", 5); + debug_printf("Bool_Glob: %d\r\n", Bool_Glob); + debug_printf(" should be: %d\r\n", 1); + debug_printf("Ch_1_Glob: %c\r\n", Ch_1_Glob); + debug_printf(" should be: %c\r\n", 'A'); + debug_printf("Ch_2_Glob: %c\r\n", Ch_2_Glob); + debug_printf(" should be: %c\r\n", 'B'); + debug_printf("Arr_1_Glob[8]: %d\r\n", Arr_1_Glob[8]); + debug_printf(" should be: %d\r\n", 7); + debug_printf("Arr_2_Glob[8][7]: %d\r\n", Arr_2_Glob[8][7]); + debug_printf(" should be: Number_Of_Runs + 10\r\n"); + debug_printf("Ptr_Glob->\r\n"); + debug_printf(" Ptr_Comp: %d\r\n", (long) Ptr_Glob->Ptr_Comp); + debug_printf(" should be: (implementation-dependent)\r\n"); + debug_printf(" Discr: %d\r\n", Ptr_Glob->Discr); + debug_printf(" should be: %d\r\n", 0); + debug_printf(" Enum_Comp: %d\r\n", Ptr_Glob->variant.var_1.Enum_Comp); + debug_printf(" should be: %d\r\n", 2); + debug_printf(" Int_Comp: %d\r\n", Ptr_Glob->variant.var_1.Int_Comp); + debug_printf(" should be: %d\r\n", 17); + debug_printf(" Str_Comp: %s\r\n", Ptr_Glob->variant.var_1.Str_Comp); + debug_printf(" should be: DHRYSTONE PROGRAM, SOME STRING\r\n"); + debug_printf("Next_Ptr_Glob->\r\n"); + debug_printf(" Ptr_Comp: %d\r\n", (long) Next_Ptr_Glob->Ptr_Comp); + debug_printf(" should be: (implementation-dependent), same as above\r\n"); + debug_printf(" Discr: %d\r\n", Next_Ptr_Glob->Discr); + debug_printf(" should be: %d\r\n", 0); + debug_printf(" Enum_Comp: %d\r\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); + debug_printf(" should be: %d\r\n", 1); + debug_printf(" Int_Comp: %d\r\n", Next_Ptr_Glob->variant.var_1.Int_Comp); + debug_printf(" should be: %d\r\n", 18); + debug_printf(" Str_Comp: %s\r\n", + Next_Ptr_Glob->variant.var_1.Str_Comp); + debug_printf(" should be: DHRYSTONE PROGRAM, SOME STRING\r\n"); + debug_printf("Int_1_Loc: %d\r\n", Int_1_Loc); + debug_printf(" should be: %d\r\n", 5); + debug_printf("Int_2_Loc: %d\r\n", Int_2_Loc); + debug_printf(" should be: %d\r\n", 13); + debug_printf("Int_3_Loc: %d\r\n", Int_3_Loc); + debug_printf(" should be: %d\r\n", 7); + debug_printf("Enum_Loc: %d\r\n", Enum_Loc); + debug_printf(" should be: %d\r\n", 1); + debug_printf("Str_1_Loc: %s\r\n", Str_1_Loc); + debug_printf(" should be: DHRYSTONE PROGRAM, 1'ST STRING\r\n"); + debug_printf("Str_2_Loc: %s\r\n", Str_2_Loc); + debug_printf(" should be: DHRYSTONE PROGRAM, 2'ND STRING\r\n"); + debug_printf("\r\n"); + + + Microseconds = ((User_Time / Number_Of_Runs) * Mic_secs_Per_Second) / HZ; + Dhrystones_Per_Second = (HZ * Number_Of_Runs) /User_Time; + printf("Microseconds for one run through Dhrystone: %ld\r\n", Microseconds); + printf("Dhrystones per Second: %ld\r\n", Dhrystones_Per_Second); + + + printf ("User_Time : %d\r\n", User_Time); + printf ("Number_Of_Runs : %d\r\n", Number_Of_Runs); + printf ("HZ : %d\r\n", (int)HZ); + + printf ("DMIPS per Mhz: "); + int dmips = 100ll*(1000000/1757) * Number_Of_Runs / User_Time; + int dmipsNatural = dmips/100; + int dmipsReal = (dmips - dmipsNatural*100); + printf ("%d.", dmipsNatural); + if(dmipsReal < 10) printf("0"); + printf ("%d\r\n", dmipsReal); + return 0; +} + + +Proc_1 (Ptr_Val_Par) +/******************/ + +REG Rec_Pointer Ptr_Val_Par; + /* executed once */ +{ + REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; + /* == Ptr_Glob_Next */ + /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ + /* corresponds to "rename" in Ada, "with" in Pascal */ + + structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); + Ptr_Val_Par->variant.var_1.Int_Comp = 5; + Next_Record->variant.var_1.Int_Comp + = Ptr_Val_Par->variant.var_1.Int_Comp; + Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; + Proc_3 (&Next_Record->Ptr_Comp); + /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp + == Ptr_Glob->Ptr_Comp */ + if (Next_Record->Discr == Ident_1) + /* then, executed */ + { + Next_Record->variant.var_1.Int_Comp = 6; + Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, + &Next_Record->variant.var_1.Enum_Comp); + Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; + Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, + &Next_Record->variant.var_1.Int_Comp); + } + else /* not executed */ + structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); +} /* Proc_1 */ + + +Proc_2 (Int_Par_Ref) +/******************/ + /* executed once */ + /* *Int_Par_Ref == 1, becomes 4 */ + +One_Fifty *Int_Par_Ref; +{ + One_Fifty Int_Loc; + Enumeration Enum_Loc; + + Int_Loc = *Int_Par_Ref + 10; + do /* executed once */ + if (Ch_1_Glob == 'A') + /* then, executed */ + { + Int_Loc -= 1; + *Int_Par_Ref = Int_Loc - Int_Glob; + Enum_Loc = Ident_1; + } /* if */ + while (Enum_Loc != Ident_1); /* true */ +} /* Proc_2 */ + + +Proc_3 (Ptr_Ref_Par) +/******************/ + /* executed once */ + /* Ptr_Ref_Par becomes Ptr_Glob */ + +Rec_Pointer *Ptr_Ref_Par; + +{ + if (Ptr_Glob != Null) + /* then, executed */ + *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; + Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); +} /* Proc_3 */ + + +Proc_4 () /* without parameters */ +/*******/ + /* executed once */ +{ + Boolean Bool_Loc; + + Bool_Loc = Ch_1_Glob == 'A'; + Bool_Glob = Bool_Loc | Bool_Glob; + Ch_2_Glob = 'B'; +} /* Proc_4 */ + + +Proc_5 () /* without parameters */ +/*******/ + /* executed once */ +{ + Ch_1_Glob = 'A'; + Bool_Glob = false; +} /* Proc_5 */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/stdlib.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/stdlib.c new file mode 100644 index 0000000..d07abc4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/dhrystone/src/stdlib.c @@ -0,0 +1,128 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. + +#include +#include + +void setStats(int enable) +{ + +} + +#include "bsp.h" + +#ifdef BSP_MACHINE_TIMER +long time(){ + return machineTimer_getTime(SYSTEM_MACHINE_TIMER_APB); +} +#else +#ifdef BSP_CLINT +long time(){ + return clint_getTime(BSP_CLINT); +} +#else +#include "dhrystoneHal.h" +#endif +#endif + +static void printf_c(int c) +{ + putchar(c); +} + +static void printf_s(char *p) +{ + while (*p) + putchar(*(p++)); +} + +static void printf_d(int val) +{ + char buffer[32]; + char *p = buffer; + if (val < 0) { + printf_c('-'); + val = -val; + } + while (val || p == buffer) { + *(p++) = '0' + val % 10; + val = val / 10; + } + while (p != buffer) + printf_c(*(--p)); +} + +int printf(const char *format, ...) +{ + int i; + va_list ap; + + va_start(ap, format); + + for (i = 0; format[i]; i++) + if (format[i] == '%') { + while (format[++i]) { + if (format[i] == 'c') { + printf_c(va_arg(ap,int)); + break; + } + if (format[i] == 's') { + printf_s(va_arg(ap,char*)); + break; + } + if (format[i] == 'd') { + printf_d(va_arg(ap,int)); + break; + } + } + } else + printf_c(format[i]); + + va_end(ap); +} + + +int puts(char *s){ + while (*s) { + putchar(*s); + s++; + } + putchar('\n'); + return 0; +} + +int putchar(int c){ + bsp_putChar(c); + return c; +} + + +//See https://github.com/zephyrproject-rtos/meta-zephyr-sdk/issues/110 +//It does not interfere with the benchmark code. +unsigned long long __divdi3 (unsigned long long numerator,unsigned long long divisor) +{ + unsigned long long result = 0; + unsigned long long count = 0; + unsigned long long remainder = numerator; + + while((divisor & 0x8000000000000000ll) == 0) { + divisor = divisor << 1; + count++; + } + while(remainder != 0) { + if(remainder >= divisor) { + remainder = remainder - divisor; + result = result | (1 << count); + } + if(count == 0) { + break; + } + divisor = divisor >> 1; + count--; + } + return result; +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/makefile new file mode 100644 index 0000000..0128209 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=memTest + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/src/main.c new file mode 100644 index 0000000..decb173 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/memTest/src/main.c @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: memTest +* +* @brief This demo performs memory test on the external memory module and reports +* the results on a UART terminal. +* +******************************************************************************/ + +#include +#include "bsp.h" +#include "userDef.h" + +/****************************************************************************** +* +* @brief This main function performs a memory test by writing ascending values +* to a memory array and then reading and checking each value. +* If a mismatch is found between the expected and read values, +* it prints an error message and enters an infinite loop. +* +******************************************************************************/ +void main() { + + bsp_printf("***Starting Memory Test*** \r\n"); + for(int i=0; i +#include +#include +#include +#include + + +void trap(); +void crash(); +void trap_entry(); +void gpioIsr(); +void isrRoutine(); +void isrInit(); + +// Encryption count for single core processing +#define ENCRYPT_COUNT HART_COUNT +// Stack space used by smpInit.S to provide stack to secondary harts +u8 hartStack[STACK_PER_HART*HART_COUNT] __attribute__((aligned(16))); + +// Used as a syncronization barrier between all threads +volatile u32 hartCounter = 0; +// Flag used by hart 0 to notify the other harts that the "value" variable is loaded +volatile u32 h0_ready = 0; + +#define WITH_RV32M +#define debug(...) + +//Store the count of interrupt happened +u8 dir=0; + +// torus radii and distance from camera +// these are pretty baked-in to other constants now, so it probably won't work +// if you change them too much. +const int dz = 5, r1 = 1, r2 = 2; + +// "Magic circle algorithm"? DDA? I've seen this formulation in a few places; +// first in Hal Chamberlain's Musical Applications of Microprocessors, but not +// sure what to call it, or how to justify it theoretically. It seems to +// correctly rotate around a point "near" the origin, without losing magnitude +// over long periods of time, as long as there are enough bits of precision in x +// and y. I use 14 bits here. +#define R(s,x,y) x-=(y>>s); y+=(x>>s) + +// CORDIC algorithm to find magnitude of |x,y| by rotating the x,y vector onto +// the x axis. This also brings vector (x2,y2) along for the ride, and writes +// back to x2 -- this is used to rotate the lighting vector from the normal of +// the torus surface towards the camera, and thus determine the lighting amount. +// We only need to keep one of the two lighting normal coordinates. +int length_cordic(int16_t x, int16_t y, int16_t *x2_, int16_t y2) { + int x2 = *x2_; + if (x < 0) { // start in right half-plane + x = -x; + x2 = -x2; + } + for (int i = 0; i < 8; i++) { + int t = x; + int t2 = x2; + if (y < 0) { + x -= y >> i; + y += t >> i; + x2 -= y2 >> i; + y2 += t2 >> i; + } else { + x += y >> i; + y -= t >> i; + x2 += y2 >> i; + y2 -= t2 >> i; + } + } + // divide by 0.625 as a cheap approximation to the 0.607 scaling factor factor + // introduced by this algorithm (see https://en.wikipedia.org/wiki/CORDIC) + *x2_ = (x2 >> 1) + (x2 >> 3); + return (x >> 1) + (x >> 3); +} + +void donut() { + // high-precision rotation directions, sines and cosines and their products + int16_t sB = 0, cB = 16384; + int16_t sA = 11583, cA = 11583; + int16_t sAsB = 0, cAsB = 0; + int16_t sAcB = 11583, cAcB = 11583; + + for (;;) { + int x1_16 = cAcB << 2; + + // yes this is a multiply but dz is 5 so it's (sb + (sb<<2)) >> 6 effectively + int p0x = dz * sB >> 6; + int p0y = dz * sAcB >> 6; + int p0z = -dz * cAcB >> 6; + + const int r1i = r1*256; + const int r2i = r2*256; + + int niters = 0; + int nnormals = 0; + int16_t yincC = (cA >> 6) + (cA >> 5); // 12*cA >> 8; + int16_t yincS = (sA >> 6) + (sA >> 5); // 12*sA >> 8; + int16_t xincX = (cB >> 7) + (cB >> 6); // 6*cB >> 8; + int16_t xincY = (sAsB >> 7) + (sAsB >> 6); // 6*sAsB >> 8; + int16_t xincZ = (cAsB >> 7) + (cAsB >> 6); // 6*cAsB >> 8; + int16_t ycA = -((cA >> 1) + (cA >> 4)); // -12 * yinc1 = -9*cA >> 4; + int16_t ysA = -((sA >> 1) + (sA >> 4)); // -12 * yinc2 = -9*sA >> 4; + //int dmin = INT_MAX, dmax = -INT_MAX; + for (int j = 0; j < 23; j++, ycA += yincC, ysA += yincS) { + int xsAsB = (sAsB >> 4) - sAsB; // -40*xincY + int xcAsB = (cAsB >> 4) - cAsB; // -40*xincZ; + + int16_t vxi14 = (cB >> 4) - cB - sB; // -40*xincX - sB; + int16_t vyi14 = ycA - xsAsB - sAcB; + int16_t vzi14 = ysA + xcAsB + cAcB; + + for (int i = 0; i < 79; i++, vxi14 += xincX, vyi14 -= xincY, vzi14 += xincZ) { + int t = 512; // (256 * dz) - r2i - r1i; + + int16_t px = p0x + (vxi14 >> 5); // assuming t = 512, t*vxi>>8 == vxi<<1 + int16_t py = p0y + (vyi14 >> 5); + int16_t pz = p0z + (vzi14 >> 5); + debug("pxyz (%+4d,%+4d,%+4d)\n", px, py, pz); + int16_t lx0 = sB >> 2; + int16_t ly0 = sAcB - cA >> 2; + int16_t lz0 = -cAcB - sA >> 2; + for (;;) { + int t0, t1, t2, d; + int16_t lx = lx0, ly = ly0, lz = lz0; + debug("[%2d,%2d] (px, py) = (%d, %d), (lx, ly) = (%d, %d) -> ", j, i, px, py, lx, ly); + t0 = length_cordic(px, py, &lx, ly); + debug("t0=%d (lx', ly') = (%d, %d)\n", t0, lx, ly); + t1 = t0 - r2i; + t2 = length_cordic(pz, t1, &lz, lx); + d = t2 - r1i; + t += d; + + if (t > 8*256) { + bsp_printf_c(' '); + break; + } else if (d < 2) { + int N = lz >> 9; + bsp_printf_c(".,-~:;!*=#$@"[N > 0 ? N < 12 ? N : 11 : 0]); + nnormals++; + break; + } + // todo: shift and add version of this + + + /* + if (d < dmin) dmin = d; + if (d > dmax) dmax = d; + */ + +#ifdef WITH_RV32M + px += d*vxi14 >> 14; + py += d*vyi14 >> 14; + pz += d*vzi14 >> 14; +#else + { + // 11x1.14 fixed point 3x parallel multiply + // only 16 bit registers needed; starts from highest bit to lowest + // d is about 2..1100, so 11 bits are sufficient + int16_t dx = 0, dy = 0, dz = 0; + int16_t a = vxi14, b = vyi14, c = vzi14; + while (d) { + if (d&1024) { + dx += a; + dy += b; + dz += c; + } + d = (d&1023) << 1; + a >>= 1; + b >>= 1; + c >>= 1; + } + // we already shifted down 10 bits, so get the last four + px += dx >> 4; + py += dy >> 4; + pz += dz >> 4; + } +#endif + niters++; + } + } + bsp_printf_s(""); + } + bsp_printf("%d iterations %d lit pixels\x1b[K", niters, nnormals); +// fflush(stdout); + + // rotate sines, cosines, and products thereof + // this animates the torus rotation about two axes + R(5, cA, sA); + R(5, cAsB, sAsB); + R(5, cAcB, sAcB); + R(6, cB, sB); + R(6, cAcB, cAsB); + R(6, sAcB, sAsB); + +// usleep(15000); + bsp_printf("\r\x1b[23A"); + } +} + +// Used on unexpected trap/interrupt codes +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + +// Called by trap_entry on both exceptions and interrupts events +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; //Interrupt if true, exception if false + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void gpioIsr(){ + //bsp_printf("Entering gpio interrupt routine .. \r\n"); + //count++; + //bsp_printf("Count:%d .. Done \r\n",count); + bsp_uDelay(500); + dir = 1 - dir; +} + +void isrRoutine(){ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0: gpioIsr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +void isrInit(){ + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0, 1); + // Enable rising edge interrupts + gpio_setInterruptRiseEnable(GPIO0, 1); + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + //Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +extern void smpInit(); +void mainSmp(); + +__inline__ __attribute__((always_inline)) s32 atomicAdd(s32 *a, u32 increment) { + s32 old; + __asm__ volatile( + "amoadd.w %[old], %[increment], (%[atomic])" + : [old] "=r"(old) + : [increment] "r"(increment), [atomic] "r"(a) + : "memory" + ); + return old; +} + +void mainSmp(){ + u32 hartId = csr_read(mhartid); + atomicAdd((s32*)&hartCounter, 1); + + while(hartCounter != HART_COUNT); + // Hart 0 will provide a value to the other harts, other harts wait on it by pulling the "ready" variable + if(hartId == 0) { + bsp_printf("synced! \r\n"); + + asm("fence w,w"); + h0_ready = 1; + isrInit(); + gpio_setOutputEnable(GPIO0, 0xe); + gpio_setOutput(GPIO0, 0x0); + while(1) { + + if(dir == 0 ){ + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x2); + bsp_uDelay(LOOP_UDELAY); + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x4); + bsp_uDelay(LOOP_UDELAY); + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x8); + bsp_uDelay(LOOP_UDELAY); + } + else { + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x8); + bsp_uDelay(LOOP_UDELAY); + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x4); + bsp_uDelay(LOOP_UDELAY); + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0x2); + bsp_uDelay(LOOP_UDELAY); + } + } + + } + else if(hartId == 1){ + while(!dir); + asm("fence r,r"); + + donut(); + + } + else if(hartId == 2){ + while(1){} + } + else if(hartId == 3){ + while(1){} + } +} + +void main() { + bsp_init(); + bsp_printf("***Starting SMP Demo*** \r\n"); + smp_unlock(smpInit); + mainSmp(); + bsp_printf("***Succesfully Ran Demo*** \r\n"); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/oob/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/oob/src/userDef.h new file mode 100644 index 0000000..9bac8a9 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/application/oob/src/userDef.h @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// donut.c by Andy Sloane (@a1k0n) +// https://gist.github.com/a1k0n/8ea6516b4946ab36348fb61703dc3194 +//////////////////////////////////////////////////////////////////////////////// + +#include "soc.h" + +#define STACK_PER_HART 4096 +#define HART_COUNT 4 + +#ifdef SYSTEM_GPIO_0_IO_CTRL + #define GPIO0 SYSTEM_GPIO_0_IO_CTRL +#else + #error "GPIO required in soft logic block .." +#endif +#ifdef SIM + #define LOOP_UDELAY 100 +#else + #define LOOP_UDELAY 500000 +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/makefile new file mode 100644 index 0000000..36fa8b1 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/makefile @@ -0,0 +1,17 @@ +PROJ_NAME=bootloader + +STANDALONE = .. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/bootloader.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/bootloaderConfig.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/bootloaderConfig.h new file mode 100644 index 0000000..445d606 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/bootloaderConfig.h @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "bsp.h" +#include "io.h" +#include "spiFlash.h" +#include "start.h" + +#define SPI SYSTEM_SPI_0_IO_CTRL +#define SPI_CS 0 + +#define USER_SOFTWARE_MEMORY 0x00001000 +#define USER_SOFTWARE_FLASH 0x400000 +#define USER_SOFTWARE_SIZE 0x01F000 + +#define SINGLE_SPI 1 //define DUAL_SPI for dual data SPI or QUAD_SPI for quad data SPI + +void bspMain() { +#ifndef SIM + spiFlash_init(SPI, SPI_CS); + spiFlash_wake(SPI, SPI_CS); + spiFlash_exit4ByteAddr(SPI, SPI_CS); +#ifdef SINGLE_SPI + spiFlash_f2m(SPI, SPI_CS, USER_SOFTWARE_FLASH, USER_SOFTWARE_MEMORY, USER_SOFTWARE_SIZE); +#elif DUAL_SPI + spiFlash_f2m_dual(SPI, SPI_CS, USER_SOFTWARE_FLASH, USER_SOFTWARE_MEMORY, USER_SOFTWARE_SIZE); // dual data line half duplex +#elif QUAD_SPI + spiFlash_f2m_quad(SPI, SPI_CS, USER_SOFTWARE_FLASH, USER_SOFTWARE_MEMORY, USER_SOFTWARE_SIZE); // quad data line full duplex +#else + #error "You must either define SINGLE_SPI to use single data line SPI, DUAL_SPI to use dual data line SPI or QUAD_SPI to use quad data line SPI." +#endif +#endif + + void (*userMain)() = (void (*)())USER_SOFTWARE_MEMORY; + #ifdef SMP + smp_unlock(userMain); + #endif + userMain(); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/main.c new file mode 100644 index 0000000..702bb9a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/bootloader/src/main.c @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: bootloader +* +* @brief This demo initialize the spiFlash and copy the data from spiFlash to the memory. +* +* @note Please configure bootloader through "bootloaderConfig.h" +* +******************************************************************************/ +#include "type.h" +#include "bsp.h" +#include "bootloaderConfig.h" + +void main() { + bsp_init(); + bspMain(); +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/bsp.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/bsp.mk new file mode 100644 index 0000000..3b5e631 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/bsp.mk @@ -0,0 +1,10 @@ +BSP_PATH ?= ${STANDALONE}/../../bsp/${BSP} +LWIP_PATH ?= ${BSP_PATH}/app/lwip +FATFS_PATH ?= ${BSP_PATH}/app/fatfs +CFLAGS += -I${BSP_PATH}/include +CFLAGS += -I${BSP_PATH}/app + + +include ${BSP_PATH}/include/soc.mk + +LDSCRIPT ?= ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/riscv64-unknown-elf.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/riscv64-unknown-elf.mk new file mode 100644 index 0000000..745c81b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/riscv64-unknown-elf.mk @@ -0,0 +1,57 @@ +RISCV_BIN ?= riscv-none-embed- +RISCV_CC=${RISCV_BIN}gcc +RISCV_OBJCOPY=${RISCV_BIN}objcopy +RISCV_OBJDUMP=${RISCV_BIN}objdump + +MARCH := rv32i +MABI := ilp32 +BENCH ?= no + +ifeq ($(RV_M),yes) + MARCH := $(MARCH)m +endif + +ifeq ($(RV_A),yes) + MARCH := $(MARCH)a +else + ifeq ($(RV_C),yes) + MARCH := $(MARCH)a + endif +endif + +ifeq ($(RV_F),yes) + MARCH := $(MARCH)f + + ifeq ($(RV_D),no) + MABI := $(MABI)f + endif +endif + +ifeq ($(RV_D),yes) + MARCH := $(MARCH)d + MABI := $(MABI)d +endif + +ifeq ($(RV_C),yes) + MARCH := $(MARCH)c +endif + +ifeq ($(DEBUG),yes) + ifneq ($(DEBUG_OG),yes) + CFLAGS += -g3 -O0 + else + CFLAGS += -g3 -Og + endif +endif + +ifneq ($(DEBUG),yes) + ifneq ($(BENCH),yes) + CFLAGS += -Os + else + CFLAGS += -O3 + endif +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DUSE_GP +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpFunc.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpFunc.S new file mode 100644 index 0000000..728fedf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpFunc.S @@ -0,0 +1,39 @@ +// This assembly is used to compile the internal bootloader for multicore +.global smp_unlock +.type smp_unlock,%function +smp_unlock: + sw a0, smp_lottery_target, a1 + fence w, w + li a0, 1 + sw a0, smp_lottery_lock, a1 + ret + +.global smp_tyranny +.global smp_slave + +smp_tyranny: + csrr a0, mhartid + beqz a0, init + +smp_slave: + lw a0, smp_lottery_lock + beqz a0, smp_slave + + fence r, r + //li a1, -1 + //amoadd.w x0, a1,(a0) + + .word(0x100F) //i$ flush + lw a5, smp_lottery_target + li a0, 0 + li a1, 0 + li a2, 0 + jr a5 + +.global smp_lottery_target +.global smp_lottery_lock + +.bss +.align 2 + smp_lottery_target: .word 0 + smp_lottery_lock: .word 0 diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpInit.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpInit.S new file mode 100644 index 0000000..c63268a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/smpInit.S @@ -0,0 +1,21 @@ +#include "userDef.h" + +.global smpInit + +smpInit: + //Initialise the stack of the given hart + la sp, hartStack + csrr a0, mhartid + li a1, STACK_PER_HART + addi a0, a0, 1 + mul a0, a0, a1 + add sp, sp, a0 + call mainSmp + +smpDone: + j smpDone + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/standalone.mk b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/standalone.mk new file mode 100644 index 0000000..896a103 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/standalone.mk @@ -0,0 +1,62 @@ +OBJDIR ?= build + +LDFLAGS += -lc + +SPINAL_SIM ?= no +ifeq ($(SPINAL_SIM),yes) + PROJ_NAME := $(PROJ_NAME)_spinal_sim + CFLAGS += -DSPINAL_SIM +endif +CFLAGS += ${CFLAGS_ARGS} +CFLAGS += -I${STANDALONE}/include +CFLAGS += -I${STANDALONE}/driver +LDFLAGS += -L${STANDALONE}/common +LDFLAGS += -specs=nosys.specs -lgcc -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage -lm + +DOT:= . +COLON:=: + +OBJS := $(SRCS) +OBJS := $(notdir $(OBJS)) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:.s=.o) +OBJS := $(addprefix $(OBJDIR)/obj_files/,$(OBJS)) + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + @echo "LD $(PROJ_NAME)" + @$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + +%.hex: %.elf + @$(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + @$(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + @$(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + @$(RISCV_OBJDUMP) -S -d $^ > $@ + +define LIST_RULE +$(1) + @mkdir -p $(dir $(word 1, $(subst $(COLON), ,$(1)))) + @echo "CC $(word 2,$(subst $(COLON), ,$(1)))" + @$(RISCV_CC) -c $(CFLAGS) $(INC) -o $(subst $(COLON), ,$(1)) +endef + +CAT:= $(addsuffix $(COLON), $(OBJS)) +CAT:= $(join $(CAT), $(SRCS)) +$(foreach i,$(CAT),$(eval $(call LIST_RULE,$(i)))) + +$(OBJDIR): + @mkdir -p $@ + +clean: + @rm -rf $(OBJDIR) + +.SECONDARY: $(OBJS) diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start.S new file mode 100644 index 0000000..49e434b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start.S @@ -0,0 +1,95 @@ + .section .init + .globl _start + .type _start,@function + + +_start: +#ifdef USE_GP +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif + +#ifdef SMP +.global smp_lottery_target +.global smp_lottery_lock +.global smp_slave + + + sw x0, smp_lottery_lock, a1 + +smp_tyranny: + csrr a0, mhartid + beqz a0, init + +smp_slave: + lw a0, smp_lottery_lock + beqz a0, smp_slave + + fence r, r + //li a1, -1 + //amoadd.w x0, a1,(a0) + + .word(0x100F) //i$ flush + lw a5, smp_lottery_target + li a0, 0 + li a1, 0 + li a2, 0 + jr a5 + +.global smp_unlock +.type smp_unlock,%function +smp_unlock: + sw a0, smp_lottery_target, a1 + fence w, w + li a0, 1 + sw a0, smp_lottery_lock, a1 + ret +#endif + +init: + la sp, _sp + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, _end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + +#ifndef NO_LIBC_INIT_ARRAY + call __libc_init_array +#endif + + call main +mainDone: + j mainDone + + + .globl _init +_init: + ret + +#ifdef SMP +.bss +.align 2 + smp_lottery_target: .word 0 + smp_lottery_lock: .word 0 +#endif \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start_int.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start_int.S new file mode 100644 index 0000000..edf397c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/start_int.S @@ -0,0 +1,65 @@ +// This assembly is required if you were to compile internal multicore bootloader + + .section .init + .globl _start + .type _start,@function + + +_start: +#ifdef USE_GP +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif + +#ifdef SMP + + sw x0, smp_lottery_lock, a1 + +call smp_tyranny +call smp_slave +call smp_unlock + +#endif + +.global init + +init: + la sp, _sp + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, _end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + +#ifndef NO_LIBC_INIT_ARRAY + call __libc_init_array +#endif + + call main +mainDone: + j mainDone + + + .globl _init +_init: + ret diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/trap.S b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/trap.S new file mode 100644 index 0000000..8149173 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/common/trap.S @@ -0,0 +1,39 @@ +.global trap_entry +.align(2) //mtvec require 32 bits allignement +trap_entry: + addi sp,sp, -16*4 + sw x1, 0*4(sp) + sw x5, 1*4(sp) + sw x6, 2*4(sp) + sw x7, 3*4(sp) + sw x10, 4*4(sp) + sw x11, 5*4(sp) + sw x12, 6*4(sp) + sw x13, 7*4(sp) + sw x14, 8*4(sp) + sw x15, 9*4(sp) + sw x16, 10*4(sp) + sw x17, 11*4(sp) + sw x28, 12*4(sp) + sw x29, 13*4(sp) + sw x30, 14*4(sp) + sw x31, 15*4(sp) + call trap + lw x1 , 0*4(sp) + lw x5, 1*4(sp) + lw x6, 2*4(sp) + lw x7, 3*4(sp) + lw x10, 4*4(sp) + lw x11, 5*4(sp) + lw x12, 6*4(sp) + lw x13, 7*4(sp) + lw x14, 8*4(sp) + lw x15, 9*4(sp) + lw x16, 10*4(sp) + lw x17, 11*4(sp) + lw x28, 12*4(sp) + lw x29, 13*4(sp) + lw x30, 14*4(sp) + lw x31, 15*4(sp) + addi sp,sp, 16*4 + mret diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/makefile new file mode 100755 index 0000000..771bebe --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/makefile @@ -0,0 +1,19 @@ +PROJ_NAME=customInstructionDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +DEBUG?=yes +BENCH?=yes + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/main.c new file mode 100755 index 0000000..31ade6a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/main.c @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: customInstructionDemo +* +* @brief This demo shows how to use a custom instruction to accelerate the processing +* time of an algorithm. It demonstrates how performing an algorithm +* in hardware can provide significant acceleration vs, using software only. +* This demo uses the Tiny encryption algorithm to encrypt two 32-bit unsigned +* integers with a 128-bit key. The encryption is 1,024 cycles. +* +* @note Please ensure that the custom instruction is enabled in Sapphire Soc. +* +******************************************************************************/ +#include +#include +#include "bsp.h" +#include "userDef.h" +#include "riscv.h" + + +/******************************************************************************* + * + * @brief This function perform a TEA (Tiny Encryption Algorithm) operation on two 32-bit words. + * + * @param v0 The first 32-bit word + * @param v1 The second 32-bit word + * @param rv0 Pointer to store the result of v0 after encryption + * @param rv1 Pointer to store the result of v1 after encryption + * + ******************************************************************************/ + +void software_tinyEncrypt (uint32_t v0, uint32_t v1, uint32_t *rv0, uint32_t *rv1) { + uint32_t sum=0, i; + + uint32_t delta=0x9e3779b9; + + uint32_t k0=0x01234567, + k1=0x89abcdef, + k2=0x13579248, + k3=0x248a0135; + + for (i=0; i < 1024; i++) { + sum += delta; + v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); + v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); + + } + *rv0=v0; + *rv1=v1; +} + +/******************************************************************************* +* +* @brief This function prints error message on terminal and enters an infinite loop +* to halt the program's execution. +* +******************************************************************************/ +void error_state() { + bsp_printf("Custom instruction and software output results are not matched .. \r\n"); + while (1) {} +} + +/******************************************************************************* +* +* @brief This function print processing time between two timestamps +* +* @param ts1 First timestamp. +* @param ts2 Second timestamp. +* @param s Character +* +******************************************************************************/ +void printPTime(uint64_t ts1, uint64_t ts2, char *s) { + uint64_t rts; + rts=ts2-ts1; + bsp_printf("%s %d \n\n\r", s, rts); + +} + +/******************************************************************************* +* +* @brief This main function initializes variables, performs custom instruction +* TEA encryption, software TEA encryption, and compares the results in +* terms of the processing time. +* + ******************************************************************************/ +void main() { + uint32_t num1, num2; + uint64_t timerCmp0, timerCmp1; + uint32_t result_ci0,result_ci1,result_s0,result_s1; + + num1=0x84425820; + num2=0xdeadbe11; + + bsp_init(); +#if (SYSTEM_CORES_0_CFU == 1) + bsp_printf("***Starting Custom Instruction Demo*** \r\n"); + timerCmp0 = clint_getTime(BSP_CLINT); + result_ci0=tinyEncryption_lowerword(num1,num2); + result_ci1=tinyEncryption_upperword(0x0, 0x0); + timerCmp1 = clint_getTime(BSP_CLINT); + bsp_printf("Custom instruction method"); + printPTime(timerCmp0,timerCmp1," processing clock cycles:"); + + timerCmp0 = clint_getTime(BSP_CLINT); + software_tinyEncrypt(num1, num2, &result_s0, &result_s1); + timerCmp1 = clint_getTime(BSP_CLINT); + bsp_printf("Software method"); + printPTime(timerCmp0,timerCmp1," processing clock cycles:"); + + if(result_ci0 != result_s0 || result_ci1 != result_s1) { + error_state(); + } else { + bsp_printf("Custom instruction and software output results are matched .. \r\n"); + } + + bsp_printf("***Succesfully Ran Demo*** \r\n"); +#else + bsp_printf("Custom instruction plugin is disabled, please enable it to run this app \r\n"); +#endif + +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/userDef.h new file mode 100644 index 0000000..5273f5d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/customInstruction/customInstructionDemo/src/userDef.h @@ -0,0 +1,2 @@ +#define tinyEncryption_lowerword(rs1, rs2) opcode_R(CUSTOM0, 0x00, 0x00, rs1, rs2) +#define tinyEncryption_upperword(rs1, rs2) opcode_R(CUSTOM0, 0x01, 0x00, rs1, rs2) diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/DDRCali_i2c.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/DDRCali_i2c.h new file mode 100644 index 0000000..c8d9171 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/DDRCali_i2c.h @@ -0,0 +1,974 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// +* +* @file DDRCali_i2c.h +* +* @brief Header file for calibrating DDR. +* +******************************************************************************/ +#ifndef SRC_DDRCALI_I2C_H_ +#define SRC_DDRCALI_I2C_H_ + + +#include "bsp.h" +#include "i2c.h" +#include "soc.h" + +#ifdef SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL_PLIC_INTERRUPT SYSTEM_PLIC_SYSTEM_I2C_0_IO_INTERRUPT +#endif + +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ + +#define DDR_I2C_CH SYSTEM_I2C_0_IO_CTRL //I2C Channel for DDR Calibration +#define MAX_WORDS (128 *1024*1024) //4Gb= 128K WORD *8 *4 //8Gb= 256K WORD *8 *4 + +//**************************Main Control****************************** +#define LPDDR3_DEVICE //default for T120F324 DevBoard Configure + +#ifdef LPDDR3_DEVICE +#else +#define DDR3_DEVICE +#endif + +#define MAX_SLICE 2 //1=8bits 2=16bits 4=32bits +#define GATE_OFFSET 64 //64=1/4 cycle 128=1/2 cycle + +#define READ_ACCESS_CALI +//#define WRITE_ACCESS_CALI + +//#define DEUBG_MASSAGE +//******************************************************************** + +#define mem ((volatile uint32_t*)0x00001000) +#define BRUST 16 + +int MemoryTest_Train(int size); + +void DDR_AccessTimingCali(void); +void ddr_cmd_issue(int num); +void ctrl_update_req(void); + +#ifdef READ_ACCESS_CALI +void GateLeveling_soft(void); +void ReadLeveling_PatternCali(void); +#endif + +#ifdef WRITE_ACCESS_CALI +void WriteLeveling(void); +#endif + +#ifdef LPDDR3_DEVICE + +void LPDDR_Write_CMD(int CA30, int MA,int OP); + +#ifdef WRITE_ACCESS_CALI +void CA_Training(void); +#endif + +#define GATE_TRAINING_COARSE_START 2 +#define GATE_TRAINING_COARSE_END 5 + +#else + +void DDR3_READ_CMD(void); +void ddr_Write_MRS_Op(int MRS, int op); + +#define GATE_TRAINING_COARSE_START 0 +#define GATE_TRAINING_COARSE_END 2 + +#endif + +/******************************************************************************* +* +* @brief This function implements a 32-bit Linear Feedback Shift Register (LFSR) +* with specific taps and a feedback polynomial. It generates a pseudo-random +* sequence based on the given seed and count. +* +* @param seed The initial value for the LFSR. +* @param count The number of times to iterate the LFSR to generate the sequence. +* +* @return The final value of the LFSR after the specified number of iterations. +* +* @note The LFSR uses taps at bits 32, 30, 26, and 25 with a feedback +* polynomial of x^32 + x^30 + x^26 + x^25 + 1. +* +******************************************************************************/ +int32_t lfsr1_32bits(int32_t seed, int32_t count) +{ + //uint32_t start_state = 0x12345678u; /* Any nonzero start state will work. */ + uint32_t lfsr = seed; + uint32_t bit,n; /* Must be 16-bit to allow bit<<15 later in the code */ + + for(n=0;n> 0) ^ (lfsr >> 2) ^ (lfsr >> 6) ^ (lfsr >> 7)) /* & 1u */; + lfsr = (lfsr >> 1) | (bit << 31); + } + return lfsr; +} + +/******************************************************************************* +* +* @brief This function prints the hexadecimal representation of a 32-bit value. +* +* @param val The 32-bit value to be printed. +* @param digits The number of hexadecimal digits to print. +* +* @note The function uses the UART to output the hexadecimal digits. +* +******************************************************************************/ +void print_hex(uint32_t val, uint32_t digits) +{ + for (int i = (4*digits)-4; i >= 0; i -= 4) + uart_write(BSP_UART_TERMINAL, "0123456789ABCDEF"[(val >> i) % 16]); +} + +/******************************************************************************* +* +* @brief This function sends a null-terminated string via UART. +* +* @param data Pointer to the null-terminated string to be sent. +* +* @note The function uses the UART to output the string. +* +******************************************************************************/ + +void print(uint8_t * data) { + uart_writeStr(BSP_UART_TERMINAL, data); +} + +/******************************************************************************* +* +* @brief This function checks for an acknowledgment (ACK) from an I2C device. +* +* @return Returns 1 if an ACK is received, otherwise returns 0. +* +* @note The function uses the I2C interface to check for the ACK. +* If an ACK is received, it stops the I2C transmission. +* +******************************************************************************/ +uint8_t checkAck(void){ + + if(i2c_rxAck(DDR_I2C_CH)==0){ + i2c_masterStopBlocking(DDR_I2C_CH); + // uart_writeStr(UART_A, "\rGet Ack Fail\n"); + return 0; + } + else + { + // uart_writeStr(UART_A, "\rGet Ack Pass\n"); + return 1; + } +} + +/******************************************************************************* +* +* @brief This function writes an array of data to an I2C device. +* +* @param data Pointer to the data array to be sent. +* @param size Size of the data array. +* +* @note The function uses the I2C interface to write the data to the device. +* It starts by sending a start condition, then iterates over the data +* array sending each byte one by one. After sending each byte, it checks +* for an ACK from the I2C device. If an ACK is not received, the function +* stops the I2C transmission and returns. +* +******************************************************************************/ +void WriteDDRArray(uint8_t *data, uint32_t size) +{ + unsigned char buf; + int out; + + i2c_masterStartBlocking(DDR_I2C_CH); + + for(int i = 0;i < size;i++){ + i2c_txByte(DDR_I2C_CH, data[i]); + i2c_txNackBlocking(DDR_I2C_CH); + if(!checkAck()) return; + } + + i2c_masterStopBlocking(DDR_I2C_CH); +} + +/******************************************************************************* +* +* @brief This function writes a 32-bit address to an I2C device. +* +* @param addr 32-bit address to be written to the device. +* +******************************************************************************/ +void WriteDDRAddr(uint32_t addr) +{ + char buf[6]; + + buf[0] = 0x41<<1; + buf[1] = 0x01; + buf[2] = addr & 0xFF; + buf[3] = (addr >> 8) & 0xFF; + buf[4] = (addr >> 16) & 0xFF; + buf[5] = (addr >> 24) & 0xFF; + + WriteDDRArray(buf, 6); + +} + +/******************************************************************************* +* +* @brief This function writes a 32-bit data value to an I2C device. +* +* @param data 32-bit data value to be written to the device. +* +******************************************************************************/ +void WriteDDRData(uint32_t data) +{ + char buf[6]; + + buf[0] = 0x41<<1; + buf[1] = 0x00; + buf[2] = data & 0xFF; + buf[3] = (data >> 8) & 0xFF; + buf[4] = (data >> 16) & 0xFF; + buf[5] = (data >> 24) & 0xFF; + + WriteDDRArray(buf, 6); + +} + +/******************************************************************************* +* +* @brief This function writes a 32-bit data value to a specified address on an +* I2C device. +* +* @param Addr 32-bit address where the data will be written. +* @param Data 32-bit data value to be written to the address. +* +******************************************************************************/ + +void WriteDDR_Addr_Data(uint32_t Addr, uint32_t Data) +{ + WriteDDRAddr(Addr); + WriteDDRData(Data); +} + +/******************************************************************************* +* +* @brief This function reads a 32-bit data value from a specified address on an +* I2C device. +* +* @return 32-bit data value read from the specified address. +* Returns 0 if reading fails. +* +******************************************************************************/ +uint32_t ReadDDRData(void) +{ + uint32_t outdata=0; + + i2c_masterStartBlocking(DDR_I2C_CH); + + i2c_txByte(DDR_I2C_CH, (0x41<<1)+1); + i2c_txAckBlocking(DDR_I2C_CH); + if(!checkAck()) return 0; + + for(int i = 0; i < 4; i++){ + i2c_txByte(DDR_I2C_CH, 0xFF); + if(i != 3) i2c_txAckBlocking(DDR_I2C_CH); else i2c_txNackBlocking(DDR_I2C_CH); + outdata |= i2c_rxData(DDR_I2C_CH) << (i*8); + } + + i2c_masterStopBlocking(DDR_I2C_CH); + + return outdata; +} + +/******************************************************************************* +* +* @brief This function reads a 32-bit data value from a specified address on an +* I2C device by first writing the address and then reading the data. +* +* @param Addr The address from which to read the data. +* +* @return 32-bit data value read from the specified address. +* Returns 0 if writing the address or reading the data fails. +* +******************************************************************************/ +uint32_t ReadAddrData(uint32_t Addr) +{ + WriteDDRAddr(Addr); + return ReadDDRData(); +} + +/******************************************************************************* +* +* @brief This function sends a control update request to an I2C device by writing +* a specific data value to a control address and then waits for an update +* completion by polling the status. +* +******************************************************************************/ +void ctrl_update_req(void) +{ + int poll; + + WriteDDR_Addr_Data(0x483, 1); + + for (poll = 0; poll < 16; poll++) + { + if ((ReadAddrData(0x483) & 0x01) == 0x00) + break; + } +} + +/******************************************************************************* +* +* @brief This function issues a DDR command by writing a command value to a +* specific address and then waits for the command execution to complete +* by polling the status. +* +* @param num The command number to be issued (0 to 15). +* +******************************************************************************/ + +void ddr_cmd_issue(int num) +{ + int timeout; + uint32_t data= 0x10; + int rdData; + + num -= 1; + + if (num <= 0) num = 0; + else if (num >= 16) num = 15; + else num = 0; + + data |= (num & 0xF); + + WriteDDRAddr(0x0412); + + WriteDDRData(data); + + for (timeout = 0; timeout < 32; timeout++) + { + rdData = ReadDDRData(); + + if ((rdData & 0x10) == 0) + { + //uart_writeStr(UART_A,"\rIssue Done\n"); + return; + } + } + + // uart_writeStr(UART_A,"\rIssue Fail\n"); +} + +/******************************************************************************* +* +* @brief This function performs a memory test by writing pseudo-random values +* to a memory array and then reading them back to verify correctness. +* It uses an LFSR (Linear Feedback Shift Register) for generating pseudo-random +* values. +* +* @param size Size of the memory test in 32-bit words. +* +* @return Returns 1 if the memory test passes, and 0 if it fails. +* +******************************************************************************/ + +int MemoryTest_Train(int size) +{ + int n; + uint32_t buff[BRUST]; + static uint32_t seed; + + if(seed==0) seed=0x123ABC99; + + if(size <=BRUST) size=BRUST; + + for(int i=0;i<(size/BRUST);i++) + { + for(n=0;n>3)<<8) |(wait <<12); + + WriteDDRAddr(0x00000430); + WriteDDRData(data); + + ddr_cmd_issue(1); +} + +#else +/******************************************************************************* +* +* @brief This function issues a read command to DDR3 memory. +* +* @note The function sets up the necessary address and data fields and then +* issues the read command to the DDR3 memory. +* +******************************************************************************/ +void DDR3_READ_CMD(void) +{ + WriteDDR_Addr_Data(0x0420, 0x00FFFA01); + WriteDDR_Addr_Data(0x0430, 0x00000000); + ddr_cmd_issue(1); +} + + +/******************************************************************************* +* +* @brief This function writes Mode Register Set (MRS) and operation (op) values +* to DDR3 memory. +* +* @param MRS Mode Register Set value. +* @param op Operation value. +* +******************************************************************************/ + +void ddr_Write_MRS_Op(int MRS, int op) +{ + uint32_t data = 0x00FFF001; + + op &= 0x1FFF; + + data |= (op & 0xFF) << 24; + WriteDDR_Addr_Data(0x0420,data); + + MRS &= 0x0007; + + WriteDDR_Addr_Data(0x0430,(0x00000000 | (MRS<<8) | ((op>>8)&0xFF)) ); + + ddr_cmd_issue(1); +} + +#endif + + +#ifdef WRITE_ACCESS_CALI +/******************************************************************************* +* +* @brief This function performs software-based write leveling for DDR3 or LPDDR3 memory. +* Write leveling helps to equalize the write delay across different DQ lines. +* +******************************************************************************/ +void WriteLeveling_soft(void) +{ + uint32_t rData; + int val = 0; + int Byte; + int Result[4] = {0,0,0,0}; + int rising_edge[4] = { 0xFF,0xFF,0xFF,0xFF}; + int LastState[4] = {0,0,0,0}; + int Done[4]={0,0,0,0}; + + if(MAX_SLICE == 2) + { + Done[2]=1; + Done[3]=1; + } + + #ifdef LPDDR3_DEVICE + LPDDR_Write_CMD(0, 0x02, 0x84); //[3:0]=4 :RL6/WL3 (<=400Mhz) [7]=Enable Write leveling + #else + //DDR3********************* + ddr_Write_MRS_Op(1, 0x00A4); + //************************* + #endif + + WriteDDR_Addr_Data(0x59, 2); //Enable soft_wrlvl_en + + for (val = 0; val < 0xBF; val+=2) //0xFF - 0x40 + { + for (Byte = 0; Byte < MAX_SLICE; Byte++) + WriteDDR_Addr_Data(0x05 + (0x10 * Byte), (ReadAddrData(0x05 + (0x10 * Byte)) & 0xFF00FFFF) | (val << 16)); + + ctrl_update_req(); + + for (Byte = 0; Byte < MAX_SLICE; Byte++) + { + WriteDDR_Addr_Data(0x01 + (0x10 * Byte), ((ReadAddrData(0x01 + (0x10 * Byte)) & 0xFFFFFFFE) | 0x01)); + + Result[Byte] = (ReadAddrData(0x0F + (0x10 * Byte)) >> 4) & 0x01; + + if ((LastState[Byte] == 0) && (Result[Byte] == 1)) + { + rising_edge[Byte] = val; + Done[Byte]=1; + } + + LastState[Byte] = Result[Byte]; + } + + + if(Done[0] && Done[1] && Done[2] && Done[3]) + { + break; + } + } + + for (Byte = 0; Byte < MAX_SLICE; Byte++) + { + WriteDDR_Addr_Data(0x05 + (0x10 * Byte), (ReadAddrData(0x05 + (0x10 * Byte)) & 0xFF0000FF) | (rising_edge[Byte] << 16) | ((rising_edge[Byte] +0x40)<<8)); + // WriteDDR_Addr_Data(0x01 + (0x10 * Byte), ((ReadAddrData(0x01 + (0x10 * Byte)) & 0xFFFFFFFE))); + } + + print("Write leveling Done!!\n\r"); + + #ifdef DEUBG_MASSAGE + print("slice[0]=0x"); + print_hex(rising_edge[0],4); + print(" slice[1]=0x"); + print_hex(rising_edge[1],4); + print(" slice[2]=0x"); + print_hex(rising_edge[2],4); + print(" slice[3]=0x"); + print_hex(rising_edge[3],4); + print("\n\r"); + #endif + + ctrl_update_req(); + + WriteDDR_Addr_Data(0x59, 0); //Disable soft_wrlvl_en + + #ifdef LPDDR3_DEVICE + LPDDR_Write_CMD(0, 0x02, 0x04); //[3:0]=4 :RL6/WL3 (<=400Mhz) [7]=Disable Write leveling + #else + //DDR3********************* + ddr_Write_MRS_Op(1, 0x0024); + //************************* + #endif +} + + +#ifdef LPDDR3_DEVICE +/******************************************************************************* +* +* @brief This function performs Command/Address (CA) training for DDR3 or LPDDR3 memory. +* It determines the optimal values for certain training patterns. +* +******************************************************************************/ +void CA_Training(void) +{ + int n,tmp,out,Pattern; + int StartPass_MR41=0; + int StartPass_MR48 = 0; + int EndPass_MR41 = 0; + int EndPass_MR48 = 0; + int min, max, result; + int result_MR41, result_MR48; + int val; + + LPDDR_Write_CMD(0x00, 41, 0xA4); + + WriteDDR_Addr_Data(0x480, 0x0210a0a0); + WriteDDR_Addr_Data(0x59, 0x01); + + for (val = 0; val < 0xBF; val++) + { + + WriteDDR_Addr_Data(0x45, (ReadAddrData(0x45) & 0xFF0000FF)|((val &0xFF)<<16)| (((val +0x40) & 0xFF) << 8)); + ctrl_update_req(); + WriteDDR_Addr_Data(0x420, 0xABFFEA00); + WriteDDR_Addr_Data(0x430, 0x0000A550); + ddr_cmd_issue(1); + + //WriteDDR_Addr_Data(0x480, 0x0310a0a0); + + tmp = ReadAddrData(0x53); + out = ReadAddrData(0x5B); + + + if (out == 0x9959) + { + if (StartPass_MR41 == 0) + StartPass_MR41 = val; + + EndPass_MR41 = val; + } + + } + + result_MR41 = (StartPass_MR41 + EndPass_MR41) >>1; + + WriteDDR_Addr_Data(0x45, 0x20004040); + ctrl_update_req(); + + LPDDR_Write_CMD(0x00, 48, 0xC0); + WriteDDR_Addr_Data(0x480, 0x0210a0a0); + + for (val = 0; val < 0xBF; val++) + { + WriteDDR_Addr_Data(0x45, (ReadAddrData(0x45) & 0xFF0000FF) | ((val & 0xFF) << 16) | (((val + 0x40) & 0xFF) << 8)); + ctrl_update_req(); + + WriteDDR_Addr_Data(0x420, 0xABFFEA00); //Data MR41 = 0x9959 + WriteDDR_Addr_Data(0x430, 0x0000A550); //Data MR48 = 0x0101 + ddr_cmd_issue(1); + + // WriteDDR_Addr_Data(0x480, 0x0310a0a0); + + tmp = ReadAddrData(0x53); + + out = ReadAddrData(0x5B); + if (out == 0x101) + { + if (StartPass_MR48 == 0) + StartPass_MR48 = val; + + EndPass_MR48 = val; + } + + } + + result_MR48 = (StartPass_MR48 + EndPass_MR48) >> 1; + + // printf("Fail\n"); + + if (StartPass_MR41 >= StartPass_MR48) + { + min = StartPass_MR41; + } + else + { + min = StartPass_MR48; + } + + if (EndPass_MR41 <= EndPass_MR48) + { + max = EndPass_MR41; + } + else + { + max = EndPass_MR48; + } + + result = (min + max) / 2; + + WriteDDR_Addr_Data(0x45, (ReadAddrData(0x45) & 0xFF0000FF) | (result <<16) | ((result+0x40)<<8)); + ctrl_update_req(); + + WriteDDR_Addr_Data(0x0480, 0x20a0a0); + WriteDDR_Addr_Data(0x59, 0x00); + LPDDR_Write_CMD(0x00, 42, 0xA8); +} +#endif +#endif + +#ifdef READ_ACCESS_CALI +/******************************************************************************* +* +* @brief This function performs Read Leveling Calibration for DDR3 or LPDDR3 memory. +* It determines the optimal read leveling pattern and applies the result. +* +******************************************************************************/ +void ReadLeveling_PatternCali(void) +{ + int rng = 0,rData=0,n; + int bank,poll,check,Byte; + uint32_t buff[8]; + int FirstPass=-1,LastPass=-1,result; + + for(bank=0;bank> 1) | ((valc & 0x1) << 29)); + + + for (valf = 0; valf < 0x7F; valf += 4) + { + for (Byte = 0; Byte < MAX_SLICE; Byte++) + WriteDDR_Addr_Data(0x05 + (0x10 * Byte), (ReadAddrData(0x05 + (0x10 * Byte)) & 0x00FFFFFF) | valf << 24); + + ctrl_update_req(); + + + #ifdef LPDDR3_DEVICE + + LPDDR_Write_CMD(0x08, 32, 0x00); //MR32 DQ calibration pattern A 0xAA + + #else + //DDR3********************* + DDR3_READ_CMD(); + //************************* + #endif + + for (Byte = 0; Byte < MAX_SLICE; Byte++) + { + Result[Byte] = (ReadAddrData(0x0C + (0x10 * Byte)) >> 16) & 0xFF; + + if ((LastState[Byte] == 0) && (Result[Byte] == 1)) + { + rising_edge_f[Byte] = valf; + rising_edge_c[Byte] = valc; + Done[Byte]=1; + } + + LastState[Byte] = Result[Byte]; + } + + } + + if(Done[0] && Done[1] && Done[2] && Done[3]) + { + break; + } + } + + + for (Byte = 0; Byte < MAX_SLICE; Byte++) + { + if ((rising_edge_c[Byte] == 0xFF) && (rising_edge_f[Byte] == 0xFF)) + { + //Fail + } + else + { + if (rising_edge_f[Byte] < GATE_OFFSET) //64 = 1/4 cycle offset + { + rising_edge_f[Byte] += GATE_OFFSET; + rising_edge_c[Byte] -=1; + } + else + { + rising_edge_f[Byte] -= GATE_OFFSET; + } + + WriteDDR_Addr_Data(0x02 + (0x10 * Byte), (ReadAddrData(0x02 + (0x10 * Byte)) & 0xDFFFFFF8) | ((rising_edge_c[Byte] & 0xE) >> 1) | ((rising_edge_c[Byte] & 0x1) << 29)); + WriteDDR_Addr_Data(0x05 + (0x10 * Byte), (ReadAddrData(0x05 + (0x10 * Byte)) & 0x00FFFFFF) | rising_edge_f[Byte] << 24); + } + } + + print("Gate Level Done !!\n\r"); + + #ifdef DEUBG_MASSAGE + print("rising_edge_c[0] = "); + print_hex(rising_edge_c[0],4); + print(" rising_edge_f[0] = "); + print_hex(rising_edge_f[0],4); + print("\n\r"); + + print("rising_edge_c[1] = "); + print_hex(rising_edge_c[1],4); + print(" rising_edge_f[1] = "); + print_hex(rising_edge_f[1],4); + print("\n\r"); + + print("rising_edge_c[2] = "); + print_hex(rising_edge_c[2],4); + print(" rising_edge_f[2] = "); + print_hex(rising_edge_f[2],4); + print("\n\r"); + + print("rising_edge_c[3] = "); + print_hex(rising_edge_c[3],4); + print(" rising_edge_f[3] = "); + print_hex(rising_edge_f[3],4); + print("\n\r"); + #endif + + ctrl_update_req(); + + for (Byte = 0; Byte < MAX_SLICE; Byte++) + WriteDDR_Addr_Data(0x0B+(0x10*Byte), (ReadAddrData(0x0B+(0x10*Byte))) &0xFFFFEFFF); + + + #ifdef LPDDR3_DEVICE + + #else + //DDR3********************* + ddr_Write_MRS_Op(3, 0x0000); + //************************* + #endif + + WriteDDR_Addr_Data(0x59, 0x00); + WriteDDR_Addr_Data(0x0480, 0x20a0a0); +} +#endif + +/******************************************************************************* +* +* @brief This function performs Access Timing Calibration for DDR3 or LPDDR3 memory. +* It configures I2C parameters and calls specific calibration functions +* based on preprocessor directives. +* +******************************************************************************/ +void DDR_AccessTimingCali(void) +{ + + //I2C init + I2c_Config i2c; + i2c.samplingClockDivider = 3; + i2c.timeout = I2C_CTRL_HZ/1000; //1 ms; + i2c.tsuDat = I2C_CTRL_HZ/2000000; //500 ns + + i2c.tLow = I2C_CTRL_HZ/800000; //1.25 us + i2c.tHigh = I2C_CTRL_HZ/800000; //1.25 us + i2c.tBuf = I2C_CTRL_HZ/400000; //2.5 us + + i2c_applyConfig(DDR_I2C_CH, &i2c); + + + #ifdef WRITE_ACCESS_CALI + #ifdef LPDDR3_DEVICE + CA_Training(); + #endif + WriteLeveling_soft(); + #endif + + #ifdef READ_ACCESS_CALI + GateLeveling_soft(); + ReadLeveling_PatternCali(); + #endif +} + +#endif /* SRC_DDRCALI_I2C_H_ */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/apb3_cl.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/apb3_cl.h new file mode 100644 index 0000000..5912011 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/apb3_cl.h @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* @file apb3_cl.h +* +* @brief Header file for apb3 function such as read/write to/from APB3 slave and +* configure APB3 slave by controling configuration register for APB3demo. +* Functions: +* - apb3_read: Reads a 32-bit value from an APB3 slave register. +* - apb3_ctrl_write: Write a control register configuration to an APB3 slave. +* - cfg_write: Write configuration data to an APB3 slave. +* - cfg_data: Write data to an APB3 slave. +* - cfg_addr: Write an address to an APB3 slave. +* +******************************************************************************/ + + +#pragma once + +#include "bsp.h" +#include "io.h" + +#define EXAMPLE_APB3_SLV_REG0_OFFSET 0 +#define EXAMPLE_APB3_SLV_REG1_OFFSET 4 +#define EXAMPLE_APB3_SLV_REG2_OFFSET 8 +#define EXAMPLE_APB3_SLV_REG3_OFFSET 12 +#define EXAMPLE_APB3_SLV_REG4_OFFSET 16 +#define EXAMPLE_APB3_SLV_REG5_OFFSET 20 + +/******************************************************************************* +* +* @brief Structure representing the control register configuration for APB3 slave +* +******************************************************************************/ + struct ctrl_reg { + unsigned int lfsr_stop :1; // 1 bit for stopping LFSR operation + unsigned int reserved :31; // Reserved 31 bits + + }apb3_ctrl_reg; + +/******************************************************************************* +* +* @brief Structure representing the control register configuration for APB3 slave +* +******************************************************************************/ + struct ctrl_reg2{ + unsigned int mem_start : 1; // 1 bit for starting memory operation + unsigned int rsv0 : 7; // 7 bits reserved + unsigned int ilen : 8; // 8 bits for length + unsigned int rsv1 : 16; // 16 bits reserved + }owrite_crtl; + +/******************************************************************************* +* +* @brief This function read a 32-bit value from an APB3 slave register. +* +* @return The value read from the APB3 slave register. +* +******************************************************************************/ + u32 apb3_read(u32 slave) + { + return read_u32(slave+EXAMPLE_APB3_SLV_REG0_OFFSET); + } + +/******************************************************************************* +* +* @brief This funciton write a control register configuration to an APB3 slave. +* +* @param slave The base address of slave. +* @param ctrl_reg* Control register. +* +******************************************************************************/ + void apb3_ctrl_write(u32 slave, struct ctrl_reg *cfg) + { + write_u32(*(int *)cfg, slave+EXAMPLE_APB3_SLV_REG1_OFFSET); + } + +/******************************************************************************* +* +* @brief This funciton write configuration data to an APB3 slave. +* +* @param slave The base address of slave. +* @param ctrl_reg* Control register. +* +******************************************************************************/ + void cfg_write(u32 slave, struct ctrl_reg2 *cfg) + { + write_u32(*(int *)cfg, slave+EXAMPLE_APB3_SLV_REG3_OFFSET); + } + +/******************************************************************************* +* +* @brief This funciton write data to an APB3 slave. +* +* @param slave The base address of slave. +* @param data The data to be written to slave. +* +******************************************************************************/ + void cfg_data(u32 slave, u32 data) + { + write_u32(data, slave+EXAMPLE_APB3_SLV_REG4_OFFSET); + } + +/******************************************************************************* +* +* @brief This funciton write an address to an APB3 slave. +* +* @param slave The base address of slave. +* @param addr Address to be written to slave. +* +******************************************************************************/ + void cfg_addr(u32 slave, u32 addr) + { + write_u32(addr, slave+EXAMPLE_APB3_SLV_REG5_OFFSET); + } + +void apb3_ctrl_write(u32 slave, struct ctrl_reg *cfg); +void cfg_write(u32 slave, struct ctrl_reg2 *cfg); +void cfg_data(u32 slave, u32 data); +void cfg_addr(u32 slave, u32 addr); +u32 apb3_read(u32 slave); + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/clint.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/clint.h new file mode 100755 index 0000000..c60011a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/clint.h @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file clint.h +* +* @brief Header file containing definitions and functions for CLINT operations. +* +* +* Functions: +* - clint_getTimeLow: Retrieves the low 32 bits of the current timer value. +* - clint_getTimeHigh: Retrieves the high 32 bits of the current timer value. +* - clint_setCmp: Sets the compare value for the timer interrupt. +* - clint_getTime: Retrieves the current timer value as a 64-bit unsigned integer. +* - clint_uDelay: Delays execution for a specified number of microseconds. +* +******************************************************************************/ + +#pragma once + +#include "type.h" +#include "io.h" + +#define CLINT_IPI_ADDR 0x0000 /*Base address for the inter-processor interrupt registers.*/ +#define CLINT_CMP_ADDR 0x4000 /* Timer interrupts related */ +#define CLINT_TIME_ADDR 0xBFF8 /* Base address for the timer registers. */ + +/******************************************************************************* +* +* This usage of the readReg_u32 macro defines two functions for reading 32-bit +* unsigned integer values from the CLINT peripheral registers representing the low +* and high parts of the current time. +* +* - clint_getTimeLow: +* - Function name for reading the low part of the current time. +* - This function reads a 32-bit unsigned integer value from the CLINT +* TIME register. +* +* - clint_getTimeHigh: +* - Function name for reading the high part of the current time. +* - This function reads a 32-bit unsigned integer value from the CLINT +* TIME register offset by 4 bytes (representing the high part). +* +* @param CLINT_TIME_ADDR: Base address of the CLINT TIME register. +* +* @return The 32-bit unsigned integer value read from the specified register. +* +* @note The readReg_u32 macro is used to define these functions, which internally +* call the read_u32 function to perform the read operation. +* +******************************************************************************/ + readReg_u32 (clint_getTimeLow , CLINT_TIME_ADDR) + readReg_u32 (clint_getTimeHigh, CLINT_TIME_ADDR+4) + +/******************************************************************************* +* +* @brief This function sets the compare value for the CLINT CMP register for a specific hardware thread. +* +* @param p is a pointer to the base address of the CLINT CMP register set +* for the specified hardware thread. +* @param cmp is the 64-bit compare value to be set in the CMP register. +* @param hart_id is the ID of the hardware thread for which the compare value +* is being set. +* +* @return None. +* +* @note The function calculates the address offset for the CMP register +* associated with the specified hardware thread and writes the lower +* 32 bits of the compare value to the lower 32 bits of the CMP register, +* the upper 32 bits of the compare value to the upper 32 bits of the CMP +* register, and sets the lower 32 bits to all 1s (0xFFFFFFFF) to ensure the compare +* value is treated as an absolute value. +* +******************************************************************************/ + + static void clint_setCmp(u32 p, u64 cmp, u32 hart_id) { + p += CLINT_CMP_ADDR + hart_id*8; + write_u32(0xFFFFFFFF, p + 4); + write_u32(cmp, p + 0); + write_u32(cmp >> 32, p + 4); + } + +/******************************************************************************* +* +* @brief This function retrieves the current time from the CLINT TIME register. +* +* @param p is the base address of the CLINT TIME register. +* +* @return The 64-bit current time value read from the CLINT TIME register. +* +* @note The function reads the high and low parts of the time value separately +* to guard against rollover. It checks if the high part remains unchanged +* during the read operation to ensure consistency. The high and low parts +* are then combined to form the 64-bit current time value. +* +******************************************************************************/ + static u64 clint_getTime(u32 p){ + u32 lo, hi; + + /* Likewise, must guard against rollover when reading */ + do { + hi = clint_getTimeHigh(p); + lo = clint_getTimeLow(p); + } while (clint_getTimeHigh(p) != hi); + + return (((u64)hi) << 32) | lo; + } + +/******************************************************************************* +* +* @brief This function introduces a microsecond delay using the CLINT TIME register. +* +* @param usec is the delay time in microseconds. +* @param hz is the frequency of the timer in Hz. +* @param reg is the base address of the CLINT TIME register. +* +* @return None. +* +* @note The function calculates the number of machine cycles per microsecond +* based on the given timer frequency 'hz'. It then calculates the time +* limit by adding the delay 'usec' in microseconds to the current time +* obtained from the CLINT TIME register. The function enters a loop, +* continuously checking if the difference between the current time +* and the time limit is non-negative, indicating that the delay has +* not yet elapsed. +* +******************************************************************************/ + static void clint_uDelay(u32 usec, u32 hz, u32 reg){ + u32 mTimePerUsec = hz/1000000; + u32 limit = clint_getTimeLow(reg) + usec*mTimePerUsec; + while((int32_t)(limit-(clint_getTimeLow(reg))) >= 0); + } \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/emc1413.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/emc1413.h new file mode 100644 index 0000000..6aa9123 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/emc1413.h @@ -0,0 +1,772 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file Temperature_Driver_EMC1413.h +* +* @brief Header file contain definition and function for EMC1413 Temperature module. +* +******************************************************************************/ + +#ifndef TEMPERATURE_DRIVER_EMC1413_H_ +#define TEMPERATURE_DRIVER_EMC1413_H_ + +#pragma once +#include +#include +#include "i2c.h" +#include "bsp.h" +#include + +/******************************************* REGISTER-MAP FOR TEMPERATURE EMC1413 MODULE ********************************************/ + +//ADDRESS FOR I2C Temperature Slave Address +#define MUX_ADDR 0x71<<1 +#define TEMP_ADDR 0x4C<<1 + +//ADDRESS FOR ID Register +#define PRODUCT_ID 0xFD //Should return h'21 +#define MICROCHIP_ID 0xFE //Should return h'5D + +//ADDRESS FOR Temperature Data Register +#define INT_DIODE_HB 0x00 +#define INT_DIODE_LB 0x29 +#define EXT_DIODE1_HB 0x01 +#define EXT_DIODE1_LB 0x10 +#define EXT_DIODE2_HB 0x23 +#define EXT_DIODE2_LB 0x24 + +//ADDRESS FOR CSR REGISTER +#define STATUS_REG 0x02 +#define CONFIG_REG 0x03 //Can accessed this at address of 0x09 as well +#define CONVERT_RATE_REG 0x04 //Can accessed this at address of 0x0A as well + +//ADDRESS FOR LIMIT REGISTER +#define HIGH_LIMIT_REG_INT_DIODE 0x05 //Can accessed this at address of 0x0B as well +#define LOW_LIMIT_REG_INT_DIODE 0x06 //Can accessed this at address of 0x0C as well + +#define HIGH_LIMIT_REG_EXT_DIODE1_HB 0x07 //Can accessed this at address of 0x0D as well +#define LOW_LIMIT_REG_EXT_DIODE1_HB 0x08 //Can accessed this at address of 0x0E as well + +#define HIGH_LIMIT_REG_EXT_DIODE1_LB 0x13 +#define LOW_LIMIT_REG_EXT_DIODE1_LB 0x14 + +#define HIGH_LIMIT_REG_EXT_DIODE2_HB 0x15 +#define LOW_LIMIT_REG_EXT_DIODE2_HB 0x16 +#define HIGH_LIMIT_REG_EXT_DIODE2_LB 0x17 +#define LOW_LIMIT_REG_EXT_DIODE2_LB 0x18 + +//Only for EMC1414 - EXT DIODE 3 +#define HIGH_LIMIT_REG_EXT_DIODE3_HB 0x2C +#define HIGH_LIMIT_REG_EXT_DIODE3_LB 0x2E +#define LOW_LIMIT_REG_EXT_DIODE3_HB 0x2D +#define LOW_LIMIT_REG_EXT_DIODE3_LB 0x2F + +//ADDRESS FOR THERM LIMIT REGISTER +#define THERM_LIMIT 0X37 +#define THERM_LIMIT_EXT_DIODE1 0X19 +#define THERM_LIMIT_EXT_DIODE2 0X1A +#define THERM_LIMIT_EXT_DIODE3 0X30 +#define THERM_LIMIT_INT_DIODE 0X20 +#define THERM_LIMIT_HYSTERESIS 0X21 + +//ADDRESS FOR LIMIT STATUS REGISTER +#define HIGH_LIMIT_STATUS_REG 0x35 +#define LOW_LIMIT_STATUS_REG 0x36 +#define THERM_LIMIT_STATUS_REG 0x37 + +//ADDRESS FOR CALIBRATION +#define BETA_CONFIG_EX1_REG 0x25 //Default: h'08 +#define BETA_CONFIG_EX2_REG 0x26 //Default: h'08 + +//ADDRESS FOR OTHER REGISTER +#define FILTER_CTRL_REG 0x40 +#define EXT_DIODE_FAULT 0x1B +#define CONSECUTIVE_ALRT_REG 0x70 +#define CHANNEL_MASK_REG 0x1F + +//DEFAULT VALUE FOR LIMIT TEMP DATA +#define DEFAULT_HIGH_LIMIT_VALUE 0x55 +#define DEFAULT_LOW_LIMIT_VALUE 0x00 + + +/******************************************* Function Prototype ********************************************/ + +//Function prototype - Accessing Temperature data (R/W) +static void get_templimit(); +static void get_tempdata (); +static uint8_t check_temp_alert(); +static uint8_t check_lowtemp_alert(); +static uint8_t check_hightemp_alert(); +static uint8_t check_temprange_reg(); +static void config_temprange_reg(const uint8_t val); +static void config_REC(const uint8_t sensor, const uint8_t enable); +static void config_softreset(const uint8_t enable); +static void config_ALERTpin(const uint8_t sensor, const uint8_t enable); +static void set_templimit(double high_limit, double low_limit, uint8_t sensor); + +//Function prototype - Accessing Temperature Module (EMC1413) +static uint8_t check_temprange_reg(); +static void setI2cMux(const uint8_t cr); +static uint8_t readtemp_reg(const uint8_t reg); +static void writetemp_reg(const uint8_t reg, const uint8_t data); +static uint8_t check_inputval_templimit(double *high_limit, double *low_limit, uint8_t sensor); + +//Internal Function prototype +static void convert_templimit(); +static void read_templimit(const uint8_t sensor,double *temp_data); +static void read_raw_templimit(const uint8_t sensor,int8_t *raw_data); +static void get_sensor_addr_templimit(const uint8_t sensor, uint8_t *address); +static void write_raw_templimit(const uint8_t sensor,int8_t *raw_data); +static void fractional_extractor(const double val, int8_t *process_data); + + +/******************************************* Structure of temperature data ********************************************/ + +/****************************************************************************** +* +* @brief Temperature data Structure. +* +* This structure represents various temperatue data for different purpose. +* +******************************************************************************/ +typedef struct { + double int_HB; //internal diode high byte + double int_LB; //internal diode low byte + double int_HL_temp; //internal diode temperature high limit + double int_LL_temp; //internal diode temperature low limit + uint8_t therm_int; //internal diode thermal limit + + double ext1_HL_HB; //external diode 1 high limit (HB) temperature + double ext1_HL_LB; //external diode 1 high limit (LB) temperature + double ext1_LL_HB; //external diode 1 low limit (HB) temperature + double ext1_LL_LB; //internal diode 1 low limit (LB) temperature + double ext1_HL_temp; //external diode 1 high limit temperature + double ext1_LL_temp; //external diode 1 low limit temperature + uint8_t therm_ext1; //external diode 1 thermal limit + + double ext2_HL_HB; //external diode 2 high limit (HB) temperature + double ext2_HL_LB; //external diode 2 high limit (LB) temperature + double ext2_LL_HB; //external diode 2 low limit (HB) temperature + double ext2_LL_LB; //internal diode 2 low limit (LB) temperature + double ext2_HL_temp; //external diode 2 high limit temperature + double ext2_LL_temp; //external diode 2 low limit temperature + uint8_t therm_ext2; //external diode 2 thermal limit + +} temperature_data; + +/********************************************** Accessing Temperature data (R/W) Function **************************************************/ + +/****************************************************************************** +* +* @brief This function retrieve temperature data and store it into struct. +* @param temperature_data Structure that contain various temperature data. +* @return none. +* +******************************************************************************/ +static void get_tempdata(temperature_data *config) { + + uint8_t ext_temp = check_temprange_reg(); + + //Reading internal diode data + config->int_HB = readtemp_reg(INT_DIODE_HB); + config->int_LB = (readtemp_reg(INT_DIODE_LB) >> 5); + config->int_HL_temp = + (ext_temp) ? + (config->int_HB - 64 + (config->int_LB / 8)) : + ((config->int_HB) + (config->int_LB / 8)); + //Reading external diode 1 data + config->ext1_HL_HB = readtemp_reg(EXT_DIODE1_HB); + config->ext1_HL_LB = (readtemp_reg(EXT_DIODE1_LB) >> 5); + config->ext1_HL_temp = + (ext_temp) ? + (config->ext1_HL_HB - 64 + (config->ext1_HL_LB / 8)) : + ((config->ext1_HL_HB) + (config->ext1_HL_LB / 8)); + //Reading external diode 2 data + config->ext2_HL_HB = readtemp_reg(EXT_DIODE2_HB); + config->ext2_HL_LB = (readtemp_reg(EXT_DIODE2_LB) >> 5); + config->ext2_HL_temp = + (ext_temp) ? + (config->ext2_HL_HB - 64 + (config->ext2_HL_LB / 8)) : + ((config->ext2_HL_HB) + (config->ext2_HL_LB / 8)); + return; +} + +/****************************************************************************** +* +* @brief This function retrieve high/low temperature limit and store it into struct. +* @param temperature_data Structure that contain various temperature data. +* @return none. +* +******************************************************************************/ +static void get_templimit(temperature_data *config) { + + double temp_data[3]; + uint8_t ext_temp = check_temprange_reg(); + + read_templimit(0,temp_data); + config->int_HL_temp = (ext_temp)?temp_data[0]-64:temp_data[0]; + config->int_LL_temp = (ext_temp)?temp_data[1]-64:temp_data[1]; + config->therm_int = (ext_temp)?temp_data[2]-64:temp_data[2]; + + read_templimit(1,temp_data); + config->ext1_HL_temp = (ext_temp)?temp_data[0]-64:temp_data[0]; + config->ext1_LL_temp = (ext_temp)?temp_data[1]-64:temp_data[1]; + config->therm_ext1 = (ext_temp)?temp_data[2]-64:temp_data[2]; + + read_templimit(2,temp_data); + config->ext2_HL_temp = (ext_temp)?temp_data[0]-64:temp_data[0]; + config->ext2_LL_temp = (ext_temp)?temp_data[1]-64:temp_data[1]; + config->therm_ext2 = (ext_temp)?temp_data[2]-64:temp_data[2]; + return; +} + +/****************************************************************************** +* +* @brief This function set the high/low temperature limit. +* +* @param high_limit High limit temperature data in double type format. +* @param low_limit Low limit temperature data in double type format. +* @param sensor 0: Internal temperature sensor in EMC1413 itself. +* 1: Temperature sensor 1 on Ti375C529. +* 2: Temperature sensor 2 on Ti375C529. +* @return none. +* +******************************************************************************/ +static void set_templimit(double high_limit, double low_limit, uint8_t sensor){ + + uint8_t ext_temp = check_temprange_reg(); + int8_t temp_limit_data[5] = {}; + int8_t raw_data[5]; + int8_t processed_HL_data[2]; //High Limit temperature data (Processed) + int8_t processed_LL_data[2]; //Low Limit temperature data (Processed) + + //Check high/low limit input ,prints msg if invalid input + uint8_t error = check_inputval_templimit(&high_limit,&low_limit,sensor); + if (error) bsp_printf ("Invalid input,set to default value\r\n"); + + //Read temperature limit data from reg + read_raw_templimit(sensor,raw_data); + + //Separate the value into two variable, fractional and integer. + fractional_extractor(high_limit,processed_HL_data); + fractional_extractor(low_limit,processed_LL_data); + + temp_limit_data[0] = (ext_temp)?(processed_HL_data[1] + 64): processed_HL_data[1]; + temp_limit_data[1] = processed_HL_data[0]<<5; + temp_limit_data[2] = (ext_temp)?(processed_LL_data[1] + 64): processed_LL_data[1]; + temp_limit_data[3] = processed_LL_data[0]<<5; + temp_limit_data[4] = (ext_temp)?(processed_HL_data[1] + 64): processed_HL_data[1]; + + //Write temperature limit data to reg + write_raw_templimit(sensor,temp_limit_data); + return; +} + +/****************************************************************************** +* +* @brief This function check whether the temperature exceed the high limit +* temperature register. +* +* @return 0 The temperature of the device still within the acceptable range. +* @return 1 The temperature of the device exceed above the high temp limit register. +* +******************************************************************************/ +static uint8_t check_hightemp_alert() { + uint8_t status; + status = (readtemp_reg(HIGH_LIMIT_STATUS_REG)& 0x0E) ; + return 1?(status>0):0; //Return 1 means high temp. +} + +/****************************************************************************** +* +* @brief This function check whether the temperature drop below the low limit +* temperature register. +* +* @return 0 The temperature of the device still within the acceptable range. +* @return 1 The temperature of the device drop below the low temp limit register. +* +******************************************************************************/ +static uint8_t check_lowtemp_alert() { + uint8_t status; + status= (readtemp_reg(LOW_LIMIT_STATUS_REG) & 0x0E) ; + return 1?(status>0):0; //Return 1 means low temp. +} + +/****************************************************************************** +* +* @brief This function check whether the temperature exceed/drop above/below +* the high/low limit temperature register. +* +* @return 0 The temperature of the device still within the acceptable range. +* @return 1 The temperature of the device drop below the low temp limit register. +* @return 2 The temperature of the device exceed above the high temp limit register. +* +* @note Not recomended to use it as it will autoclear the alert bit once read the reg. +* +******************************************************************************/ +static uint8_t check_temp_alert() { + uint8_t status[1] = { }; + status[0] = (readtemp_reg(STATUS_REG) & 0x18) >> 3; + return status[0]; //Return 2 means high temp. +} +/****************************************************************************** +* +* @brief This function configure the range of the temperature +* +* @param temperature_data Structure that contain various temperature data. +* @param val If set to 0, means range of temp from 0°C to +127°C +* If set to 1, means range of temp from -64°C to +191°C +* @return none. +* +******************************************************************************/ +static void config_temprange_reg(const uint8_t val) { + uint8_t status[1] = { }; + status[0] = readtemp_reg(CONFIG_REG); + uint8_t current_status = ((status[0] &= 0x04) >> 2) ; + if (current_status == val) return; //if input val is same as current value, then return + else { + //Clear bit and add new val + status[0] &= 0xFB; + status[0] |= (val << 2); + writetemp_reg(CONFIG_REG, status[0]); + } return; +} + +/****************************************************************************** +* +* @brief This function check whether the extended range of temperature is in used. +* +* @return 0 Default Range of the temperature measurement (0°C to +127°C) is used. +* @return 1 Extended Range of the temperature measurement (-65°C to +191°C) is used +* +******************************************************************************/ +static uint8_t check_temprange_reg() { + uint8_t status[1] = { }; + status[0] = readtemp_reg(CONFIG_REG); + status[0] = (status[0] & 0x04) >> 2; + return status[0]; //return 1 means extended range of temp is used. +} + + +/****************************************************************************** +* +* @brief This function configure individual channel masking to disable !ALERT pin. +* +* @param enable 0: (DEFAULT) Temperature sensor will cause !ALERT pin to be +* asserted if it is out of limit or reports a diode fault. +* 1: Temperature sensor will NOT cause !ALERT pin to be asserted +* if it is out of limit or reports a diode fault. +* +* @param sensor 0: Internal temperature sensor in EMC1413 itself. +* 1: Temperature sensor 1 on Ti375C529. +* 2: Temperature sensor 2 on Ti375C529. +* +* @note When a channel is masked, the !ALERT pin will not be asserted when the masked +* channel reads a diode fault or out of limit error. The channel mask does not +* mask the !THERM pin. +******************************************************************************/ +static void config_ALERTpin(const uint8_t sensor, const uint8_t enable){ + uint8_t status[3]; + status[0] = readtemp_reg(CHANNEL_MASK_REG); + status[0] &= ~(1 << sensor); //Clear the specific bit based on the sensor + status[0] |= (enable <> 5); + double data_1 = (readtemp_reg(address_data[3]) >> 5); + //First two data are for high/low limit data + temp_data[0]= (sensor==0)?readtemp_reg(address_data[0]):readtemp_reg(address_data[0]) + (data_0/8); + temp_data[1]= (sensor==0)?readtemp_reg(address_data[2]):readtemp_reg(address_data[2]) + (data_1/8); + //Thermal Limit data + temp_data[2]= readtemp_reg(address_data[4]); + return; +} + +/****************************************************************************** +* +* @brief This internal function read raw data from temperature limit register. +* +* @param sensor 0: Internal temperature sensor in EMC1413 itself. +* 1: Temperature sensor 1 on Ti375C529. +* 2: Temperature sensor 2 on Ti375C529. +* @param temp_data Address of the High/Low limit temp reg. +* * raw_data[0] = High Limit Temperature High Byte Value +* * raw_data[1] = High Limit Temperature Low Byte Value +* * raw_data[2] = Low Limit Temperature High Byte Value +* * raw_data[3] = Low Limit Temperature Low Byte Value +* * raw_data[4] = Thermal Limit data +* @return none. +* +******************************************************************************/ +static void read_raw_templimit(const uint8_t sensor,int8_t *raw_data){ + + uint8_t address_data[5] ={}; + + get_sensor_addr_templimit(sensor,address_data); + raw_data[0]= readtemp_reg(address_data[0]); + raw_data[1]= readtemp_reg(address_data[1]); + raw_data[2]= readtemp_reg(address_data[2]); + raw_data[3]= readtemp_reg(address_data[3]); + raw_data[4]= readtemp_reg(address_data[4]); + +} + + +/****************************************************************************** +* +* @brief This internal function write raw data to temperature limit register. +* +* @param sensor 0: Internal temperature sensor in EMC1413 itself. +* 1: Temperature sensor 1 on Ti375C529. +* 2: Temperature sensor 2 on Ti375C529. +* @param temp_data Address of the High/Low limit temp reg. +* * raw_data[0] = High Limit Temperature High Byte Value +* * raw_data[1] = High Limit Temperature Low Byte Value +* * raw_data[2] = Low Limit Temperature High Byte Value +* * raw_data[3] = Low Limit Temperature Low Byte Value +* * raw_data[4] = Thermal Limit data +* @return none. +* +* @note For sensor 0, raw_data[1] & raw_data[3] are ignored. +* +******************************************************************************/ +static void write_raw_templimit(const uint8_t sensor,int8_t *raw_data){ + + uint8_t address_data[5] ={}; + + get_sensor_addr_templimit(sensor,address_data); + writetemp_reg(address_data[0],raw_data[0]); + writetemp_reg(address_data[2],raw_data[2]); + writetemp_reg(address_data[4],raw_data[4]); + if(sensor>0){ //Ignore internal diode 1 data as it doesnt have low byte register + writetemp_reg(address_data[1],raw_data[1]); + writetemp_reg(address_data[3],raw_data[3]); + } return; + +} + + +/****************************************************************************** +* +* @brief This internal function separate a double type variable into integer and +* fractional value. +* +* @param val Temperature data in double type format. +* @param process_data process_data[0]: Value contain only fractional part. +* process_data[1]: Value contain only integral part. +* +* @return none. +* +******************************************************************************/ +static void fractional_extractor(const double val, int8_t *process_data) { + double fractional, integral; + + // Check if the value is negative + if (val < 0) { + // Convert negative value to positive + double positive_val = -val; + + // Extract the fractional and integral parts + fractional = modf(positive_val, &integral); + + // Convert back to negative after extracting fractional and integral parts + integral = -integral; + fractional = 0; + } else { + // Extract the fractional and integral parts + fractional = modf(val, &integral); + } + + // Shift the fractional part right by 3 bits + process_data[0] = (int8_t)(fractional * 8); // Only fractional + process_data[1] = (int8_t)integral; // Only integer + return; +} + +/****************************************************************************** +* +* @brief This internal function check user input for high & low limit value and default +* value is used if invalid input. +* +* @param high_limit High limit temperature data in double type format. +* @param low_limit Low limit temperature data in double type format. +* @param process_data process_data[0]: Value contain only fractional part. +* process_data[1]: Value contain only integral part. +* @param sensor 0: Internal temperature sensor in EMC1413 itself. +* 1: Temperature sensor 1 on Ti375C529. +* 2: Temperature sensor 2 on Ti375C529. +* @return none. +* +******************************************************************************/ +static uint8_t check_inputval_templimit(double *high_limit, double *low_limit, uint8_t sensor) { + uint8_t ext_temp = check_temprange_reg(); + uint8_t error =0; + + switch (ext_temp) { + case 0: + if (*high_limit < 0 || *high_limit > 127) { + *high_limit = DEFAULT_HIGH_LIMIT_VALUE; + error++; + } + if (*low_limit < 0 || *low_limit > 127) { + *low_limit = DEFAULT_LOW_LIMIT_VALUE; + error++; + } + break; + + case 1: + if (*high_limit < -64 || *high_limit > 191.875) { + *high_limit = DEFAULT_HIGH_LIMIT_VALUE; + error++; + } + if (*low_limit < -64 || *low_limit > 191.875) { + *low_limit = DEFAULT_LOW_LIMIT_VALUE; + error++; + } + break; + } + + return error?error:0 ; // If 0 means free from errors. +} + +/****************************************************************************** +* +* @brief This internal function convert the temperature data format (High/Low) +* of the high/low limit temperature data in all sensors. +* +* @return none. +* +* @note Not recomended to use this function for converting the data format. +* Instead, use config_temprange_reg() function and reset the value by +* using set_templimit(); +* +******************************************************************************/ +static void convert_templimit(){ + + uint8_t ext_temp = check_temprange_reg(); + uint8_t temp_limit_data[5] = {}; + uint8_t sensor =0; + uint8_t raw_data[5]; + + for(;sensor<3;sensor++){ //Will convert all temp data format + //Read temperature limit data from reg + read_raw_templimit(sensor,raw_data); + + //Change only in high Byte data in reg + temp_limit_data[0] = (ext_temp)?(raw_data[0] + 64): (raw_data[0] - 64); + temp_limit_data[1] = raw_data[1]; + temp_limit_data[2] = (ext_temp)?(raw_data[2] + 64): (raw_data[2] - 64); + temp_limit_data[3] = raw_data[3]; + temp_limit_data[4] = (ext_temp)?(raw_data[4] + 64): (raw_data[4] - 64); + + //Write temperature limit data to reg + write_raw_templimit(sensor,temp_limit_data); + + }return; +} + +/****************************************************************************** +* +* @brief This function is prints all limit register for debugging purposes. +* @return none. +* +******************************************************************************/ +static void debug_print(){ + bsp_printf("High Limit int register (HB):%x \r\n",readtemp_reg(HIGH_LIMIT_REG_INT_DIODE)); + bsp_printf("Low Limit int register (LB):%x \r\n",readtemp_reg(LOW_LIMIT_REG_INT_DIODE)); + bsp_printf("High Limit ext1 register (HB):%x \r\n",readtemp_reg(HIGH_LIMIT_REG_EXT_DIODE1_HB)); + bsp_printf("High Limit ext1 register (LB):%x \r\n",readtemp_reg(HIGH_LIMIT_REG_EXT_DIODE1_LB)); + bsp_printf("Low Limit ext1 register (HB):%x \r\n",readtemp_reg(LOW_LIMIT_REG_EXT_DIODE1_HB)); + bsp_printf("Low Limit ext1 register (LB):%x \r\n",readtemp_reg(LOW_LIMIT_REG_EXT_DIODE1_LB)); + bsp_printf("High Limit ext2 register (HB):%x \r\n",readtemp_reg(HIGH_LIMIT_REG_EXT_DIODE2_HB)); + bsp_printf("High Limit ext2 register (LB):%x \r\n",readtemp_reg(HIGH_LIMIT_REG_EXT_DIODE2_LB)); + bsp_printf("Low Limit ext2 register (HB):%x \r\n",readtemp_reg(LOW_LIMIT_REG_EXT_DIODE2_HB)); + bsp_printf("Low Limit ext2 register (LB):%x \r\n",readtemp_reg(LOW_LIMIT_REG_EXT_DIODE2_LB)); + bsp_printf("High Limit Status register:%x \r\n",readtemp_reg(HIGH_LIMIT_STATUS_REG)); + bsp_printf("Low Limit Status register:%x \r\n",readtemp_reg(LOW_LIMIT_STATUS_REG)); + bsp_printf("External Fault register:%x \r\n",readtemp_reg(EXT_DIODE_FAULT)); + bsp_printf("Thermal limit on external diode 1:%x \r\n",readtemp_reg(THERM_LIMIT_EXT_DIODE1)); + bsp_printf("Thermal limit on external diode 2:%x \r\n",readtemp_reg(THERM_LIMIT_EXT_DIODE2)); + bsp_printf("Thermal limit on internal diode :%x \r\n",readtemp_reg(THERM_LIMIT_INT_DIODE )); + bsp_printf("Thermal limit (Hysteresis):%x \r\n",readtemp_reg(THERM_LIMIT_HYSTERESIS )); + bsp_printf("Thermal limit status register :%x \r\n",readtemp_reg(THERM_LIMIT)); +} +#endif /* TEMPERATURE_DRIVER_EMC1413_H_ */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/pcf8523.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/pcf8523.h new file mode 100644 index 0000000..38015ab --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/device/pcf8523.h @@ -0,0 +1,920 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file RTC_Driver_PCF8523.h +* +* @brief Header file contain definition and function for PCF8523 RTC module. +* +******************************************************************************/ +#ifndef SRC_RTC_PCF8523_H_ +#define SRC_RTC_PCF8523_H_ + +#pragma once +#include +#include +#include "i2c.h" +#include "bsp.h" + +/******************************************* REGISTER-MAP FOR RTC PCF8523 MODULE ********************************************/ +//ADDRESS FOR I2C RTC Slave Address +#define MUX_ADDR 0x71<<1 +#define RTC_ADDR 0x68<<1 + +//ADDRESS FOR CONTROL STATUS REGISTER +#define RTC_CONTROL_1 0X00 +#define RTC_CONTROL_2 0X01 +#define RTC_CONTROL_3 0X02 + +//ADDRESS FOR TIMEKEEPING REGISTER +#define RTC_SECONDS 0X03 +#define RTC_MINUTES 0X04 +#define RTC_HOURS 0X05 +#define RTC_DAYS 0X06 +#define RTC_WEEKDAYS 0X07 +#define RTC_MONTH 0X08 +#define RTC_YEAR 0X09 + +//ADDRESS FOR ALARM REGISTER +#define ALARM_MINUTES 0X0A +#define ALARM_HOURS 0X0B +#define ALARM_DAYS 0X0C +#define ALARM_WEEKDAYS 0X0D + +#define OFFSET 0x0E //This is used for Aging adjustment, temperature compensation, accuracy tunning. + +//ADDRESS FOR TIMER REGISTER +#define TIMER_A_FREQ_CTRL 0x10 +#define TIMER_A_REG 0x11 +#define TIMER_B_FREQ_CTRL 0x12 +#define TIMER_B_REG 0x13 + +//DATA FOR TIMEKEEPING/ALARM IN EACH REG +#define SECONDS_DATA 0X7F //The BIT_7 is used to indicate the oscillator has stopped when set to 1. +#define MINUTES_DATA 0X7F //The BIT_7 is unused. +#define HOURS_DATA 0X3F +#define DAYS_DATA 0X3F +#define WEEKDAYS_DATA 0X07 +#define MONTH_DATA 0X1F +#define YEAR_DATA 0XFF + + +//************************************************* Power Management Function Control Bits *********************************************// +#define PM_0 0x00 //battery switch-over function is enabled in standard mode; battery low detection function is enabled +#define PM_1 0x20 //battery switch-over function is enabled in direct switching mode; battery low detection function is enabled +#define PM_2 0x40 //battery switch-over function is disabled - only one power supply (VDD); battery low detection function is enabled +#define PM_3 0x60 //battery switch-over function is disabled - only one power supply (VDD); battery low detection function is enabled +#define PM_4 0x80 //battery switch-over function is enabled in standard mode; battery low detection function is disabled +#define PM_5 0xA0 //battery switch-over function is enabled in direct switching mode; battery low detection function is disabled +#define PM_6 0xC0 //not allowed +#define PM_7 0xE0 //battery switch-over function is disabled - only one power supply (VDD); battery low detection function is disabled + +//********************************************************** Function Prototype ***********************************************// + +//Global variable - Time Keeping +static uint8_t get_data [17] = {}; + +//Function prototype for accessing RTC +static void setI2cMux(const uint8_t cr); +static void RTC_softreset(); +static void readCR_RTC(); + +//Function Prototype for battery related function +static uint8_t check_battery_status_RTC(uint8_t *data); +static void print_battery_status_RTC(); +static void battery_mode_RTC(const uint8_t mode); + +//Function Prototype for time related function +static uint8_t get_seconds(); +static uint8_t get_minutes(); +static uint8_t get_hours(); +static uint8_t get_days(); +static uint8_t get_weekdays(); +static uint8_t get_months(); +static uint8_t get_years(); +static void set_timesystem (const uint8_t _12hour); +static void set_datetime(const uint8_t set_seconds, const uint8_t set_minutes, const uint8_t set_hours, const uint8_t set_dayOfWeek, \ +const uint8_t set_days, const uint8_t set_month, const uint8_t set_years); + +//Function Prototype for alarm related function +static bool alarmDisable(); +static bool alarmClearFlag(); +static uint8_t checkalarmStatus(); +static uint8_t alarmMinutes(); +static uint8_t alarmHours(); +static uint8_t alarmDays(); +static uint8_t alarmWeekdays(); +static bool alarmSet(const uint8_t minute, const uint8_t hour, const uint8_t day, const uint8_t weekday); + +//Function Prototype for internal function +static uint8_t decimal_to_bcd(const uint8_t decimal); +static uint8_t isLeapYear(const uint8_t temp_year); +static uint8_t check_month_error(const uint8_t temp_month,const uint8_t temp_day,const uint8_t temp_year); + + +//********************************************************** Structure of timekeeping ***********************************************// + +/****************************************************************************** +* +* @brief Time-keeping Structure. +* +* This structure represents real-time data and alarm data from register. +* +******************************************************************************/ +typedef struct { + uint8_t seconds; + uint8_t minutes; + uint8_t hours; + uint8_t PM; + uint8_t timesystem; + uint8_t weekdays; + uint8_t days; + uint8_t months; + uint8_t years; + uint8_t AL_minutes; + uint8_t AL_hours; + uint8_t AL_days; + uint8_t AL_weekdays; + uint8_t AL_status; + +}time_data; + +/****************************************************************************** +* +* @brief This array contain the ordinal numbers for DAY register. +* +******************************************************************************/ +static const char* Day_ordinal [] = { + "st", + "nd", + "rd", + "th" +}; + +/****************************************************************************** +* +* @brief This array contain the day strings. +* +******************************************************************************/ +static const char* const DayStrings[] = { + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" +}; + +/****************************************************************************** +* +* @brief This array contain the month strings. +* +******************************************************************************/ +static const char* const MonthStrings[] = { + "January", + "February", + "March", + "April", + "May", + "June", + "July" , + "August" , + "September" , + "October", + "November" , + "December" +}; + +/****************************************************************************** +* +* @brief This array contain the Ante meridiem and Post meridiem strings. +* +******************************************************************************/ +static const char* const meridiem[] = { + "am", + "pm" +}; + +/****************************************************************************** +* +* @brief This array contain oridinal date (st,nd,th) in string format. +* +******************************************************************************/ +static const char* get_days_ordinalno(time_data *config){ + switch(config->days){ + case 1: + case 21: + case 31: + return Day_ordinal[0]; + break; + case 2: + case 22: + return Day_ordinal[1]; + break; + case 3: + case 23: + return Day_ordinal[2]; + break; + default: + return Day_ordinal[3]; + break; + } + +} + +/********************************************** TimeKeeping Function **************************************************/ + + +/****************************************************************************** +* +* @brief This function extract real-time data from RTC Module and save it into +* timedata struct. +* +* @return none. +* +******************************************************************************/ +static void getdata(time_data *config) { + + //uint8_t timesystem[1] ={} ; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL, RTC_ADDR, RTC_CONTROL_1, get_data, 14); + + //Read Time from RTC + config->timesystem = (get_data[RTC_CONTROL_1] & 0x08)>> 3; + config->seconds = (get_data[RTC_SECONDS] & 0x0F) + ((get_data[RTC_SECONDS] >> 4) & 0x7) * 10; + config->minutes = (get_data[RTC_MINUTES] & 0x0F) + ((get_data[RTC_MINUTES] >> 4) & 0x7) * 10; + config->days = (get_data[RTC_DAYS] & 0x0F) + ((get_data[RTC_DAYS] >> 4) & 0x3) * 10; + config->weekdays = (get_data[RTC_WEEKDAYS] & WEEKDAYS_DATA); + config->months = (get_data[RTC_MONTH] & 0x0F) + ((get_data[RTC_MONTH] >> 4) & 0x01) * 10; + config->years = (get_data[RTC_YEAR] & 0x0F) + ((get_data[RTC_YEAR] >> 4) & 0x0F) * 10; + config->PM = ((get_data[RTC_HOURS] & 0x20)>> 5); //Check for Time AM/PM + config->AL_status = ((get_data[ALARM_HOURS] & 0x20)>> 5); //Check for Alarm AM/PM + + //Checking timesystem from register + if ((config->timesystem)==1){ // 12 hour time system is selected + config->hours = (get_data[RTC_HOURS] & 0x0F) + ((get_data[RTC_HOURS] >> 4) & 0x1) * 10; + config->AL_hours = (get_data[ALARM_HOURS] & 0x0F) + ((get_data[ALARM_HOURS] >> 4) & 0x1) * 10; + }else{ // 24 hour time system is selected + config->hours = (get_data[RTC_HOURS] & 0x0F) + ((get_data[RTC_HOURS] >> 4) & 0x3) * 10; + config->AL_hours = (get_data[ALARM_HOURS] & 0x0F) + ((get_data[ALARM_HOURS] >> 4) & 0x3) * 10; + } + +#if(DEBUG_MODE) + bsp_printf("Timesystem:%d\r\n",config->timesystem); + bsp_printf("Raw data from Hour reg:%x\r\n",get_data[5]); + bsp_printf("Data Hour (Bcdtodec):%d\r\n",config->hours); + bsp_printf("Data PM (Bcdtodec):%d\r\n",config->PM); + bsp_printf("Raw data from AL_Hour reg:%x\r\n",get_data[11]); + bsp_printf("Data AL_Hour (Bcdtodec):%d\r\n",config->AL_hours); + bsp_printf("Data AL_PM (Bcdtodec):%d\r\n",config->AL_status); +#endif + //Read set Alarm time + config->AL_minutes = (get_data[ALARM_MINUTES] & 0x0F) + ((get_data[ALARM_MINUTES] >> 4) & 0x7) * 10; + config->AL_days = (get_data[ALARM_DAYS] & 0x0F) + ((get_data[ALARM_DAYS] >> 4) & 0x3) * 10; + config->AL_weekdays = (get_data[ALARM_WEEKDAYS] & WEEKDAYS_DATA); +} + + + +/****************************************************************************** +* +* @brief This function change the current timesystem (12/24hr) +* +* @param set_seconds Set for current seconds. +* @param set_minutes Set for current minutes. +* @param set_hours Set for current hours. +* @param set_dayOfWeek Set for current dayOfWeek. +* @param set_days Set for current days. +* @param set_month Set for current month. +* @param set_years Set for current years. +* +* @return none. +* +* @note The value is set in 24hr timesystem only. +* +******************************************************************************/ +static void set_datetime(const uint8_t set_seconds, const uint8_t set_minutes, const uint8_t set_hours, const uint8_t set_dayOfWeek, const uint8_t set_days, const uint8_t set_month, const uint8_t set_years){ + + uint8_t data[7] ={ + decimal_to_bcd(set_seconds), + decimal_to_bcd(set_minutes), + decimal_to_bcd(set_hours), + decimal_to_bcd(set_days), + decimal_to_bcd(set_dayOfWeek), + decimal_to_bcd(set_month), + decimal_to_bcd(set_years) + }; + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_SECONDS,data,7); +} + + +/****************************************************************************** +* +* @brief This function change the current timesystem (12/24hr) for real-time data and alarm. +* +* @param _12hour If value = 0, means it is set to 24hr timesystem, vice versa. +* +* @return none. +* +******************************************************************************/ +static void set_timesystem (const uint8_t _12hour){ + time_data tempConfig; + uint8_t status[1]={}; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + if (((status[0] & 0x08)>>3) == _12hour) + return; + else { //Only Trigger when different TimeSystem is detected + + //Clear the bit and reassign the new value given by user for timesystem + status[0] = status[0] & 0xF7; + status[0] = (status[0] | (_12hour << 3) ); + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + + + uint8_t i[2] = {ALARM_HOURS,RTC_HOURS}; + uint8_t j; + + //If alarm is disabled then it only loops once to change the timesystem for time. + if(checkalarmStatus()!=2) j=0; + else j=1; + for(;j<2;j++){ //Loop twice to change timesystem for alarm hour and time hour. + + //Read hour reg to alter the value based on the timesystem + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,i[j],status,1); + + //Check for current timesystem,if 12hr, then check for AM/PM + tempConfig.PM = (status[0] & 0x20)>> 5; + + + switch (_12hour){ + case 0: //24hours time system + tempConfig.timesystem = 0; + tempConfig.hours = (status[0] & 0x0F) + ((status[0] >> 4) & 0x1) * 10; + uint8_t original_12hr = tempConfig.hours; + if ((tempConfig.hours ==12) && (tempConfig.PM)); // Value remain the same for both TimeSystem + else if (tempConfig.PM) tempConfig.hours = tempConfig.hours + 12;//If 24hr system, then it will change 2pm to 14:00 + status[0] = decimal_to_bcd(tempConfig.hours) ; //Change timesystem bit in 02h_address + //bsp_printf("Timesystem has change to 24hr Timesystem\r\n"); +#if(DEBUG_MODE) + bsp_printf("Timesystem:%d,Convert %d (12hr) to %d (24hr)\r\n",tempConfig.timesystem,original_12hr,tempConfig.hours); + bsp_printf("Hours value:%d,%d\r\n",tempConfig.hours,decimal_to_bcd(tempConfig.hours)); +#endif + break; + + case 1://12hours time system + tempConfig.timesystem = 1; + tempConfig.hours = (status[0] & 0x0F) + ((status[0] >> 4) & 0x3) * 10; + uint8_t original_24hr =tempConfig.hours; + if (tempConfig.hours == 12) tempConfig.PM =1; + else if (tempConfig.hours>12 ) //Evening + { + tempConfig.PM = 1; + tempConfig.hours = tempConfig.hours -12; + } + else if (((tempConfig.hours>=0) | (tempConfig.hours<=3)) && tempConfig.PM) tempConfig.hours = tempConfig.hours +8; + else tempConfig.PM = 0;//Morning + //bsp_printf("Timesystem has change to 12hr Timesystem\r\n"); +#if(DEBUG_MODE) + bsp_printf("Timesystem:%d,Convert %x (24hr) to %x (12hr)\r\n",tempConfig.timesystem,original_24hr,tempConfig.hours); + bsp_printf("Hours value:%d,%d\r\n",tempConfig.hours,decimal_to_bcd(tempConfig.hours)); +#endif + status[0] = ((tempConfig.PM <<5)|decimal_to_bcd(tempConfig.hours)); //Change timesystem bit in 02h_address + break; + default: + break; + + } + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,i[j],status,1); + } + (_12hour)?bsp_printf("Timesystem has change to 12hr Timesystem\r\n"): + bsp_printf("Timesystem has change to 24hr Timesystem\r\n"); +} +} + + + +/****************************************************************************** +* +* @brief This function return seconds from struct of timedata. +* @return seconds. +* +******************************************************************************/ +static uint8_t get_seconds(time_data *config){ + return config->seconds; +} + + +/****************************************************************************** +* +* @brief This function return minutes from struct of timedata. +* @return minutes. +* +******************************************************************************/ +static uint8_t get_minutes(time_data *config){ + return config->minutes; +} + +/****************************************************************************** +* +* @brief This function return hours from struct of timedata. +* @return hours. +* +******************************************************************************/ +static uint8_t get_hours(time_data *config){ + return config->hours; +} + +/****************************************************************************** +* +* @brief This function return days from struct of timedata. +* @return days. +* +******************************************************************************/ +static uint8_t get_days(time_data *config){ + return config->days; +} + +/****************************************************************************** +* +* @brief This function return months from struct of timedata. +* @return months. +* +******************************************************************************/ +static uint8_t get_months(time_data *config){ + return config->months; +} + +/****************************************************************************** +* +* @brief This function return years from struct of timedata. +* @return years. +* +******************************************************************************/ +static uint8_t get_years(time_data *config){ + return config->years; +} + +/****************************************************************************** +* +* @brief This function return weekdays from struct of timedata. +* @return weekdays. +* +******************************************************************************/ +static uint8_t get_weekdays(time_data *config){ + return config->weekdays; +} + +/****************************************************************************** +* +* @brief This function convert decimal value to BCD. +* +* @param decimal Decimal Value +* @return BCD value. +* +******************************************************************************/ +static uint8_t decimal_to_bcd(const uint8_t decimal) { + uint8_t bcd1, bcd2; + + bcd1 = decimal % 10; + bcd2 = (decimal / 10) << 4 ; + + return (bcd2 | bcd1); +} + + + + +/************************************** Alarm Function *****************************************************/ + + +/****************************************************************************** +* +* @brief This function enable Alarm and set the value in 24hr timesystem. +* +* @param minutes Set for alarm minutes. +* @param hours Set for alarm hours. +* @param day Set for alarm day. +* @param weekday Set for alarm weekday. +* +* @note Alarm only triggered when all alarm register match with all +* time register which generate alarm flag (AF) in CSR1. +* +* @return true +* +******************************************************************************/ +static bool alarmSet(const uint8_t minute, const uint8_t hour, const uint8_t day, const uint8_t weekday){ + + time_data config; + uint8_t status[1] = {}; + uint8_t type_alarm = 0; + + //Enable AIE + setI2cMux(0x1); //Read + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + status[0] |= 0x02; + setI2cMux(0xF); //Write + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + + config.AL_minutes = minute; + config.AL_hours = hour; + config.AL_days = day; + config.AL_weekdays = weekday; + + + uint8_t alarm1_set[4] = {(0x00|decimal_to_bcd(minute)),(0x00|decimal_to_bcd(hour)),(0x00|decimal_to_bcd(day)),(0x00|decimal_to_bcd(weekday))}; + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,ALARM_MINUTES,alarm1_set,4); + return true; + +} + +/****************************************************************************** +* +* @brief This function disable Alarm by setting '1' to alarm_en bit in all alarm +* register. +* @return true. +* +******************************************************************************/ +static bool alarmDisable() { + uint8_t status[4]= {}; + + //Disable alarm interrupt enabled bit in CR1 + setI2cMux(0x1); //Read + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + status[0] &= 0xFD; + setI2cMux(0xF); //Write + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); + + //Disable all alarm enabled bit in minute register, ... + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,ALARM_MINUTES,status,4); + for (int i = 0;i<4;i++){ + //bsp_printf("Before masking: %x \r\n",status[i]); + status[i]= (status[i] | 0x80); //Set alarm_en to 1 to disable + //bsp_printf("After masking: %x \r\n",status[i]); + } + setI2cMux(0x1); //Write + i2c_writeData_b(I2C_CTRL,RTC_ADDR,ALARM_MINUTES,status,4); +#if (DEBUG_MODE) + i2c_readData_b(I2C_CTRL,RTC_ADDR,ALARM_MINUTES,status,4); + for (int i = 0;i<4;i++){ + bsp_printf("ReadBack from reg%x: %x \r\n",0x0A+i,status[i]); + } +#endif + return true; + +} + +/****************************************************************************** +* +* @brief This function clear alarmFlag (AF) in CSR1. +* @return true. +* +******************************************************************************/ +static bool alarmClearFlag(){ + uint8_t status[1]; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_2,status,1); + status[0] = status[0] & 0xF7; + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_2,status,1); + return true; + +} + +/****************************************************************************** +* +* @brief This function check alarm status if true means alarm has triggered. +* @return 0 Alarm is not triggered. +* @return 1 Alarm is triggered. +* @return 2 Alarm is disabled. +* +******************************************************************************/ +static uint8_t checkalarmStatus() { + uint8_t status[5]={0,0,0,0,0}; + + //Check Alarm enabled bit in reg + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,ALARM_MINUTES,status,4); +#if (DEBUG_MODE) + bsp_printf("\r\nDebug Mode ENABLED!"); + bsp_printf("\r\n*********************\r\n"); + for (int i = 0;i<4;i++){ + bsp_printf("Before Raw Value from reg%d : %x\r\n", i,status[i]); + bsp_printf("Before Accumulated Raw val : %x\r\n", status[4]); + status[i]=(status[i] & 0x80)>> 7; //Set alarm_en to 1 + status[4]+=status[i]; //Add all alarm_en bit (Bit7) + bsp_printf("Value from masking reg%d : %x\r\n", i,status[i]); + bsp_printf("Accumulated val : %x\r\n", status[4]); + } + uint8_t status_debug[1]={}; + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status_debug,1); //Check Alarm INT in CR1 + bsp_printf("CR2: %x\r\n",status_debug[0]); + bsp_printf("Done printing\r\n"); + +#else + for (int i = 0;i<4;i++){ + status[i]=(status[i] & 0x80)>> 7; //Set alarm_en to 1 + status[4]+=status[i]; //Add all alarm_en bit (Bit7) + } +#endif + if (status[4]>0x00) //If status[4] > 0 means alarm is disabled. + return 2; //Alarm is disabled + + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_2,status,1); //Check Alarm Flag in control reg + + if((status[0] & 0x08) == 0x08) //Alarm 1 is triggered + return 1; //bsp_printf("Alarm 1 is triggered! \r\n"); + else + return 0; //bsp_printf("No Alarm is triggered! \r\n"); + +} + +/****************************************************************************** +* +* @brief This function return alarm minutes from struct of timedata. +* @return alarm minutes. +* +******************************************************************************/ +static uint8_t alarmMinutes(time_data *config){ + return config->AL_minutes; +} + +/****************************************************************************** +* +* @brief This function return alarm Hours from struct of timedata. +* @return alarm hours. +* +******************************************************************************/ +static uint8_t alarmHours(time_data *config){ + return config->AL_hours; +} + +/****************************************************************************** +* +* @brief This function return alarm days from struct of timedata. +* @return alarm days. +* +******************************************************************************/ +static uint8_t alarmDays(time_data *config){ + return config->AL_days; +} + +/****************************************************************************** +* +* @brief This function return alarm weekdays from struct of timedata. +* @return alarm weekdays. +* +******************************************************************************/ +static uint8_t alarmWeekdays(time_data *config){ + return config->AL_weekdays; +} + +/********************************************** Control Register Function**************************************************/ + +/****************************************************************************** +* +* @brief This function intialize soft reset on RTC module. +* @return none. +* @note Upon soft-reset, reconfiguration on CSR is needed as soft-reset will wipe +* the previous configuration, but time-keeping is not affected. +* +******************************************************************************/ +static void RTC_softreset() +{ + uint8_t status[1] = {0x58}; + setI2cMux(0xF); + //writeRtc(RTC_CONTROL_1, 0x08); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_1,status,1); +} + + +/****************************************************************************** +* +* @brief This function checks all control register and prints the info on terminal. +* @return none. +* +******************************************************************************/ +static void readCR_RTC() { + uint8_t status[3] = { }; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL, RTC_ADDR, RTC_CONTROL_1, status, 3); + for (int i = 1; i < 4; i++) { + bsp_printf("RTC CR%d readback: %x\r\n", RTC_CONTROL_1 + i, + status[i - 1]); + } +} + + +/****************************************************************************** +* +* @brief This function is used to set TCA9546A mux to access RTC module in Ti375C529. +* @return none. +* @note Please ensure that this function is used before read/write to RTC module. +* +******************************************************************************/ +static void setI2cMux(const uint8_t cr) +{ + u8 outdata; + + i2c_masterStartBlocking(I2C_CTRL); + + i2c_txByte(I2C_CTRL, MUX_ADDR); + i2c_txNackBlocking(I2C_CTRL); + // assert(i2c_rxAck(I2C_CTRL)); // Optional check + + i2c_txByte(I2C_CTRL, cr); + i2c_txNackBlocking(I2C_CTRL); + // assert(i2c_rxAck(I2C_CTRL)); // Optional check + + i2c_masterStopBlocking(I2C_CTRL); +} + + +/********************************************** Battery Management Function **************************************************/ + +#define BATTERY_STRING "\r\nBattery Management Function" \ + "\r\nSelect 0 to disable battery switch-over and battery low detection function" \ + "\r\nSelect 1 to enable battery low detection function ONLY " \ + "\r\nSelect 2 to enable battery switch-over function ONLY (Direct-switching mode) " \ + "\r\nSelect 3 to enable battery switch-over and battery low detection function" \ + "\r\nPlease select the correct mode: \r\n" + +/****************************************************************************** +* +* @brief This function check battery status (low/ok), battery switch over function, +* battery low detection function and illegal control bit. +* +* @param data The data that store all the information regarding the battery +* status. +* @return data[0]. Return data is illegal control bits. +* +******************************************************************************/ +static uint8_t check_battery_status_RTC(uint8_t *data) +{ + uint8_t status[1]={}; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_3,status,1); + // Update the battery status and switch over flag in data array + //bsp_printf("status: %d \r\n",status[0]); + data[0] = status[0] & 0xE0; // Check for illegal control bits (0xC0) + data[1] = status[0] & 0x04; // Check battery status (low/ok),0 means ok + data[2] = status[0] & 0x40; // Check battery switch over function if 0 then enabled + data[3] = status[0] & 0x80; // Check battery low detection function if 0 + //bsp_printf("Status: %d ,%d\r\n",data[0],data[1]); + return data[0]; // Return 0xC0 if the illegal control bit is detected. + +} + +/****************************************************************************** +* +* @brief This function prints battery information. +* @return none. +* +******************************************************************************/ +static void print_battery_status_RTC(){ + uint8_t battery_status_data[3]={}; + + if (check_battery_status_RTC(battery_status_data) == PM_6) + bsp_printf( + "Invalid value in Power management functions, please reconfigure it " + "using battery_mode_RTC!!!\r\n "); + else + bsp_printf( + "Battery status (LOW/OK): %s\r\nBattery switch-over: %s\r\n" + "Battery low detection: %s\r\n", + battery_status_data[1] ? "LOW" : "OK", + battery_status_data[2] ? "DISABLED" : "ENABLED", + battery_status_data[3] ? "DISABLED" : "ENABLED"); + bsp_printf("Checking completed ! \r\n\n"); +} + +/****************************************************************************** +* +* @brief This function switch battery mode that either enable/disable battery +* switch over function, battery low detection function or both enable/ +* disable the function. +* +* @param mode Battery mode +* @return none. +* +******************************************************************************/ +static void battery_mode_RTC(const uint8_t mode) +{ + uint8_t PM; + uint8_t status[1]={}; + setI2cMux(0x1); + i2c_readData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_3,status,1); + status[0] &= 0x1F; //Clear power management bits + + switch (mode) + { + case 0: //All Disable + PM = PM_7; + break; + case 1: //Battery low detection is enabled only + PM = PM_3; + break; + case 2: //Battery switch over is enabled only (Direct-switching mode) + PM = PM_5; + break; + case 3: //Both battery low detection and switch over are enabled (Standard mode) + PM = PM_0; + break; + default: + PM = PM_7; + break; + } + status[0] = PM | status[0]; + setI2cMux(0xF); + i2c_writeData_b(I2C_CTRL,RTC_ADDR,RTC_CONTROL_3,status,1); +} +/********************************************** Internal Function: Checking Function **************************************************/ + +/****************************************************************************** +* +* @brief This function checks for leap year. +* +* @param temp_year Years +* @return 0 Means it is not a leap year. +* @return 1 Means it is a leap year. +* +******************************************************************************/ +static uint8_t isLeapYear(const uint8_t temp_year) { + // If the year is in the '00' to '99' range, assume it's in the 21st century + int year = temp_year; + if (year >= 0 && year <= 99) { + year = year + 2000; // Convert two-digit year to four-digit year + bsp_printf("year:%d\r\n",year); + } + + // Leap year is divisible by 4 + if (year % 4 == 0) { + // If divisible by 100, it should also be divisible by 400 to be a leap year + if (year % 100 == 0 && year % 400 != 0) { + return 0; // Not a leap year + } else { + return 1; // Leap year + } + } else { + return 0; // Not a leap year + } +} + +/****************************************************************************** +* +* @brief This function checks input value for the number of days in the specific month. +* +* @param temp_day Days +* @param temp_month Month +* @param temp_year Years +* @return 0 No error. +* @return 1 Error. +* +******************************************************************************/ +static uint8_t check_month_error(const uint8_t temp_month,const uint8_t temp_day,const uint8_t temp_year){ + uint8_t leap_year = 8; + switch(temp_month) + { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return (temp_day>31)?1:0; + break; + case 2: + leap_year = isLeapYear(temp_year); + bsp_printf("Is Leap Year: %s \r\n",leap_year?("Yes"):("No")); + + + if((temp_day <30) && (leap_year)) + { + return 0; + } + + return (temp_day>28)?1:0; + + break; + + default: + return (temp_day>30)?1:0; + break; + } + + return 0; +} +/************************************************************************************************************************/ + +#endif /* SRC_RTC_PCF8523_H_ */ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/dmasg.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/dmasg.h new file mode 100644 index 0000000..b72d17b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/dmasg.h @@ -0,0 +1,351 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file dmasg.h +* +* @brief Header file contain DMA function. +* +* Functions: +* - dmasg_input_memory: Configure the input memory for a DMA channel. +* - dmasg_output_memory: Configure the output memory for a DMA channel. +* - dmasg_input_stream: Configures the input stream for a DMA channel. +* - dmasg_output_stream: Configures the output stream for a DMA channel. +* - dmasg_direct_start: Starts a DMA channel for direct control mode. +* - dmasg_linked_list_start: Starts a DMA channel using a linked list. +* - dmasg_stop: Stops a DMA channel. +* - dmasg_interrupt_config: Configures DMA channel interrupts. +* - dmasg_interrupt_pending_clear: Clears pending interrupts for a DMA channel. +* - dmasg_busy: Checks the status of a DMA channel. +* - dmasg_buffer: Specifies the buffer mapping of a DMA channel. +* - dmasg_priority: Sets the priority and weight of a DMA channel. +* - dmasg_progress_bytes: Retrieves the number of bytes transferred for the current descriptor. +* - dmasg_linked_list_sg_start: Start a channel using a linked list streamed not from memory, +* but from the dedicated hardware channel. +* +******************************************************************************/ +#pragma once + +#include "type.h" +#include "io.h" + +#define dmasg_ca(base, channel) (base + channel*0x80) +#define DMASG_CHANNEL_INPUT_ADDRESS 0x00 +#define DMASG_CHANNEL_INPUT_STREAM 0x08 +#define DMASG_CHANNEL_INPUT_CONFIG 0x0C +#define DMASG_CHANNEL_INPUT_CONFIG_MEMORY BIT_12 +#define DMASG_CHANNEL_INPUT_CONFIG_STREAM 0 +#define DMASG_CHANNEL_INPUT_CONFIG_COMPLETION_ON_PACKET BIT_13 +#define DMASG_CHANNEL_INPUT_CONFIG_WAIT_ON_PACKET BIT_14 +#define DMASG_CHANNEL_OUTPUT_ADDRESS 0x10 +#define DMASG_CHANNEL_OUTPUT_STREAM 0x18 +#define DMASG_CHANNEL_OUTPUT_CONFIG 0x1C +#define DMASG_CHANNEL_OUTPUT_CONFIG_MEMORY BIT_12 +#define DMASG_CHANNEL_OUTPUT_CONFIG_STREAM 0 +#define DMASG_CHANNEL_OUTPUT_CONFIG_LAST BIT_13 +#define DMASG_CHANNEL_DIRECT_BYTES 0x20 +#define DMASG_CHANNEL_STATUS 0x2C +#define DMASG_CHANNEL_STATUS_DIRECT_START BIT_0 +#define DMASG_CHANNEL_STATUS_BUSY BIT_0 +#define DMASG_CHANNEL_STATUS_SELF_RESTART BIT_1 +#define DMASG_CHANNEL_STATUS_STOP BIT_2 +#define DMASG_CHANNEL_STATUS_LINKED_LIST_START BIT_4 +#define DMASG_CHANNEL_FIFO 0x40 +#define DMASG_CHANNEL_PRIORITY 0x44 +#define DMASG_CHANNEL_INTERRUPT_ENABLE 0x50 +#define DMASG_CHANNEL_INTERRUPT_PENDING 0x54 +#define DMASG_CHANNEL_PROGRESS_BYTES 0x60 +#define DMASG_CHANNEL_LINKED_LIST_HEAD 0x70 +#define DMASG_CHANNEL_LINKED_LIST_FROM_SG_BUS 0x78 +// Interrupt at the end of each descriptor +#define DMASG_CHANNEL_INTERRUPT_DESCRIPTOR_COMPLETION_MASK BIT_0 +// Interrupt at the middle of each descriptor, require the half_completion_interrupt option to be enabled for the channel +#define DMASG_CHANNEL_INTERRUPT_DESCRIPTOR_COMPLETION_HALF_MASK BIT_1 +// Interrupt when the channel is going off (not busy anymore) +#define DMASG_CHANNEL_INTERRUPT_CHANNEL_COMPLETION_MASK BIT_2 +// Interrupt each time that a linked list's descriptor status field is updated +#define DMASG_CHANNEL_INTERRUPT_LINKED_LIST_UPDATE_MASK BIT_3 +// Interrupt each time a S -> M channel has done transferring a packet into the memory +#define DMASG_CHANNEL_INTERRUPT_INPUT_PACKET_MASK BIT_4 +// Number of bytes (minus one) reserved at the descriptor FROM/TO addresses. +// If you want to transfer 10 bytes, this field should take the value 9 +#define DMASG_DESCRIPTOR_CONTROL_BYTES 0x7FFFFFF +//Only for M -> S transfers, specify if a end of packet should be send at the end of the transfer +#define DMASG_DESCRIPTOR_CONTROL_END_OF_PACKET BIT_30 +#define DMASG_DESCRIPTOR_CONTROL_NO_COMPLETION BIT_31 +// Number of bytes transferred by the DMA for this descriptor. +#define DMASG_DESCRIPTOR_STATUS_BYTES 0x7FFFFFF +// Only for S -> M transfers, specify if the descriptor mark the end of a received packet +// Can be used when the dmasg_input_stream function is called with completion_on_packet set. +#define DMASG_DESCRIPTOR_STATUS_END_OF_PACKET BIT_30 +// Specify if the descriptor was executed by the DMA. +// If the DMA read a completed descriptor, the channel is stopped and will produce a CHANNEL_COMPLETION interrupt. +#define DMASG_DESCRIPTOR_STATUS_COMPLETED BIT_31 + + // Should be aligned to 64 bytes ! + struct dmasg_descriptor { + // See all DMASG_DESCRIPTOR_STATUS_* defines + // Updated by the DMA at the end of each descriptor and when a S -> M packet is completely transferred into memory + u32 status; + // See all DMASG_DESCRIPTOR_CONTROL_* defines + u32 control; + // For M -> ? transfers, memory address of the input data + u64 from; + // For ? -> M transfers, memory address of the output data + u64 to; + // Memory address of the next descriptor + u64 next; + }; + +/******************************************************************************* +* +* @brief This function configure the input memory for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel number +* @param address: Starting address of the input memory buffer +* @param byte_per_burst: Number of bytes to be transferred per burst (should be a power of two) +* +* @note byte_per_burst need to be a power of two, can be set to zero if the channel has +* hardcoded burst length. +* +******************************************************************************/ + static void dmasg_input_memory(u32 base, u32 channel, u32 address, u32 byte_per_burst){ + u32 ca = dmasg_ca(base, channel); + write_u32(address, ca + DMASG_CHANNEL_INPUT_ADDRESS); + write_u32(DMASG_CHANNEL_INPUT_CONFIG_MEMORY | (byte_per_burst-1 & 0xFFF), ca + DMASG_CHANNEL_INPUT_CONFIG); + } + +/******************************************************************************* +* +* @brief This function configure the output memory for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel number +* @param address: Starting address of the input memory buffer +* @param byte_per_burst: Number of bytes to be transferred per burst (should be a power of two) +* +* @note byte_per_burst need to be a power of two, can be set to zero if the channel has +* hardcoded burst length. +* +******************************************************************************/ + static void dmasg_output_memory(u32 base, u32 channel, u32 address, u32 byte_per_burst){ + u32 ca = dmasg_ca(base, channel); + write_u32(address, ca + DMASG_CHANNEL_OUTPUT_ADDRESS); + write_u32(DMASG_CHANNEL_OUTPUT_CONFIG_MEMORY | (byte_per_burst-1 & 0xFFF), ca + DMASG_CHANNEL_OUTPUT_CONFIG); + } + + +/******************************************************************************* +* +* @brief This function configures the input stream for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel number +* @param port: Identifies which physical input port should be used +* ex : If a port can be accessed by 4 channels, and you are the +* second of those channel, then port=1 . +* @param wait_on_packet: Ensure the channel wait the beggining of a packet before capturing +* the data (avoid desync). +* @param completion_on_packet: Indicates whether the descriptor should be limited to only +* contain one packet and force its completion when fully transferred +* into memory. +* +*******************************************************************************/ + static void dmasg_input_stream(u32 base, u32 channel, u32 port, u32 wait_on_packet, u32 completion_on_packet){ + u32 ca = dmasg_ca(base, channel); + write_u32(port << 0, ca + DMASG_CHANNEL_INPUT_STREAM); + write_u32(DMASG_CHANNEL_INPUT_CONFIG_STREAM | (completion_on_packet ? DMASG_CHANNEL_INPUT_CONFIG_COMPLETION_ON_PACKET : 0) | (wait_on_packet ? DMASG_CHANNEL_INPUT_CONFIG_WAIT_ON_PACKET : 0), ca + DMASG_CHANNEL_INPUT_CONFIG); + } + +/******************************************************************************* +* +* @brief This function configures the output stream for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel number +* @param port: Identifies which physical output port should be used. +* ex : If a port can be accessed by 4 channels, and you +* are the second of those channel, then port=1. +* @param source: AXI-Stream TID used in the packet +* @param sink: AXI-Stream TDEST used in the packet +* @param last: Specifies if an end of packet should be sent at the end of the transfer +* (only for direct DMA control, not linked list) +* +*******************************************************************************/ + static void dmasg_output_stream(u32 base, u32 channel, u32 port, u32 source, u32 sink, u32 last){ + u32 ca = dmasg_ca(base, channel); + write_u32(port << 0 | source << 8 | sink << 16, ca + DMASG_CHANNEL_OUTPUT_STREAM); + write_u32(DMASG_CHANNEL_OUTPUT_CONFIG_STREAM | (last ? DMASG_CHANNEL_OUTPUT_CONFIG_LAST : 0), ca + DMASG_CHANNEL_OUTPUT_CONFIG); + } + + +/******************************************************************************* +* +* @brief This function starts a DMA channel without using linked list (direct control). +* Be sure the channel was enabled to support this mode. +* +* @param base: Base address of the DMA controller. +* @param channel: DMA channel ID to use. +* @param bytes: Size of the transfer. +* @param self_restart: Allows the channel to operate in circular mode. +* The DESCRIPTOR_COMPLETION_HALF interrupt can be usefull +* in that mode. +* +*******************************************************************************/ + static void dmasg_direct_start(u32 base, u32 channel, u32 bytes, u32 self_restart){ + u32 ca = dmasg_ca(base, channel); + write_u32(bytes-1, ca + DMASG_CHANNEL_DIRECT_BYTES); + write_u32(DMASG_CHANNEL_STATUS_DIRECT_START | (self_restart ? DMASG_CHANNEL_STATUS_SELF_RESTART : 0), ca + DMASG_CHANNEL_STATUS); + } + +/******************************************************************************* +* +* @brief This function starts a DMA channel using a linked list. +* Be sure the channel was enabled to support this mode. +* +* @param base: Base address of the DMA controller. +* @param channel: DMA channel ID to use. +* @param head: Address of the linked list's first element (see dmasg_descriptor struct) +* +*******************************************************************************/ + static void dmasg_linked_list_start(u32 base, u32 channel, u32 head){ + u32 ca = dmasg_ca(base, channel); + write_u32((u32) head, ca + DMASG_CHANNEL_LINKED_LIST_HEAD); + write_u32(0, ca + DMASG_CHANNEL_LINKED_LIST_FROM_SG_BUS); + write_u32(DMASG_CHANNEL_STATUS_LINKED_LIST_START, ca + DMASG_CHANNEL_STATUS); + } + + +/******************************************************************************* +* +* @brief This function allow to start a channel using a linked list streamed not from memory, +* but from the dedicated hardware channel. Be sure the channel was enabled to support +* linked list mode. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* +*******************************************************************************/ + static void dmasg_linked_list_sg_start(u32 base, u32 channel){ + u32 ca = dmasg_ca(base, channel); + write_u32(1, ca + DMASG_CHANNEL_LINKED_LIST_FROM_SG_BUS); + write_u32(DMASG_CHANNEL_STATUS_LINKED_LIST_START, ca + DMASG_CHANNEL_STATUS); + } + +/******************************************************************************* +* +* @brief This function asks a DMA channel to stop itself. None blocking, so you need +* to pull on dmasg_busy if you want to wait it to be effective. +* The status progress (bytes transfered) of the interrupted descriptor will be unknown. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* +*******************************************************************************/ + static void dmasg_stop(u32 base, u32 channel){ + u32 ca = dmasg_ca(base, channel); + write_u32(DMASG_CHANNEL_STATUS_STOP, ca + DMASG_CHANNEL_STATUS); + } + +/******************************************************************************* +* +* @brief This function configures interrupts for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* @param mask: Bitmask specifying which interrupts to enable +* +* @note See all DMASG_CHANNEL_INTERRUPT_*_MASK defines for possible interrupts +* Multiple interrupts can be used at once. +* This function clear all pending interrupts for the given channel +* before enabling the mask's interrupts. +* +*******************************************************************************/ + static void dmasg_interrupt_config(u32 base, u32 channel, u32 mask){ + u32 ca = dmasg_ca(base, channel); + write_u32(0xFFFFFFFF, ca+DMASG_CHANNEL_INTERRUPT_PENDING); + write_u32(mask, ca+DMASG_CHANNEL_INTERRUPT_ENABLE); + } + +/******************************************************************************* +* +* @brief This function clears pending interrupts for a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* @param mask: Bitmask specifying which interrupts to clear +* +* @note Mask it with 0xFFFFFFFF to clear them all. +*******************************************************************************/ + static void dmasg_interrupt_pending_clear(u32 base, u32 channel, u32 mask){ + u32 ca = dmasg_ca(base, channel); + write_u32(mask, ca+DMASG_CHANNEL_INTERRUPT_PENDING); + } + +/******************************************************************************* +* +* @brief This function checks the status of a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* +* @return 1 if the channel is busy, 0 otherwise +* +*******************************************************************************/ + static u32 dmasg_busy(u32 base, u32 channel){ + u32 ca = dmasg_ca(base, channel); + return read_u32(ca + DMASG_CHANNEL_STATUS) & DMASG_CHANNEL_STATUS_BUSY; + } + +/******************************************************************************* +* +* @brief This function specifies the buffer mapping of a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* @param fifo_base: Base address of the FIFO buffer +* @param fifo_bytes: Size of the FIFO buffer in bytes +* +* @note You don't need to use this function is the buffer address +* and buffer size are hardcoded in the hardware. +* +*******************************************************************************/ + static void dmasg_buffer(u32 base, u32 channel, u32 fifo_base, u32 fifo_bytes){ + u32 ca = dmasg_ca(base, channel); + write_u32(fifo_base << 0 | fifo_bytes-1 << 16, ca+DMASG_CHANNEL_FIFO); + } + +/******************************************************************************* +* +* @brief This function sets the priority and weight of a DMA channel. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* @param priority: Priority of the channel +* @param weight: Weight of the channel +* +*******************************************************************************/ + static void dmasg_priority(u32 base, u32 channel, u32 priority, u32 weight){ + u32 ca = dmasg_ca(base, channel); + write_u32(priority| weight << 8, ca+DMASG_CHANNEL_PRIORITY); + } + +/******************************************************************************* +* +* @brief This function snoops how many bytes were transferred for the current descriptor. +* +* @param base: Base address of the DMA controller +* @param channel: DMA channel ID +* +* @return Number of bytes transferred for the current descriptor +* +*******************************************************************************/ + static u32 dmasg_progress_bytes(u32 base, u32 channel){ + u32 ca = dmasg_ca(base, channel); + return read_u32(ca + DMASG_CHANNEL_PROGRESS_BYTES); + } \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_mmc_driver.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_mmc_driver.h new file mode 100644 index 0000000..fa7afc2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_mmc_driver.h @@ -0,0 +1,748 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +* +* @file efx_mmc_driver.h +* +* @brief Header file containing declarations for SD controller functions and structures. +* +* Functions: +* - sd_ctrl_write: Writes a 32-bit data value to the specified offset within the SD controller device registers. +* - sd_ctrl_read: Reads a 32-bit data value from the specified offset within the SD controller device registers. +* - sd_ctrl_cmd: Sends a command to the SD controller device and handles the response accordingly. +* - sd_ctrl_creat_Descriptor: Creates a descriptor for data transfer by allocating memory and setting up the descriptor entries. +* - sd_ctrl_data: Handles data transfer between the SD controller and the SD card. +* - sd_ctrl_check_read_write: Checks if the MMC command requires data read or write operations. +* - sd_ctrl_send_cmd: Sends the MMC command with or without data transfer based on the command type. +* - sd_ctrl_get_cd: Gets the card detect status. +* - sd_ctrl_get_wp: Gets the write protect status. +* - sd_ctrl_set_clk: Sets the clock frequency for SD operations. +* - sd_ctrl_set_bus: Sets the bus width for SD operations. +* - sd_ctrl_set_ios: Sets the I/O settings for the SD controller. +* - sd_ctrl_init: Initializes the SD controller and MMC/SD card. +* - sd_ctrl_mmc_probe: Probes and initializes the MMC/SD controller. +* +******************************************************************************/ + +#pragma once + +#include "bsp.h" +#include "mmc.h" +#include "userDef.h" + +#define REG_VERSION 0x0000 +#define REG_ARGUMENT2 0x0000 +#define REG_BLOCKSIZE_COUNT 0x0004 +#define REG_ARGUMENT1 0x0008 +#define REG_TRANFER_MODE 0x000C +#define REG_COMMAND_RESP31_0 0x0010 +#define REG_COMMAND_RESP63_32 0x0014 +#define REG_COMMAND_RESP95_64 0x0018 +#define REG_COMMAND_RESP127_96 0x001C +#define REG_BUFFER_DATA 0x0020 +#define REG_PRESENT_STATE 0x0024 +#define REG_HOST_CONTORL 0x0028 +#define REG_CLOCK_CONTORL 0x002C +#define REG_NORMAL_INTERRUPT_STATUS0 0x0030 +#define REG_NORMAL_INTERRUPT_STATUS1 0x0034 +#define REG_AUTO_CMD_ERROR 0x003C +#define REG_CAPABILITIES0 0x0040 +#define REG_CAPABILITIES1 0x0044 +#define REG_MAX_CURRENT 0x0048 +#define REG_CAPABILITIES2 0x004C +#define REG_FORECE_EVENT 0x0050 +#define REG_ADMA_ERROR_STATUS 0x0054 +#define REG_ADMA_SYSTEM_ADDR0 0x0058 +#define REG_ADMA_SYSTEM_ADDR1 0x005C +#define REG_PRESENT_VALUE0 0x0060 +#define REG_PRESENT_VALUE1 0x0064 +#define REG_PRESENT_VALUE2 0x0068 +#define REG_PRESENT_VALUE3 0x006C +#define REG_SHARE_BUS_CONTORL 0x00E0 +#define REG_SLOT_INTERRUPT_STATUS 0x00FC +#define MAX_DESCRIPTOR 65536 + +/******************************************************************************* +* +* @brief Structure to hold various interrupt status flags. +* +******************************************************************************/ +typedef struct _IntStruct { + volatile u32 command_complete; /* Command complete flag */ + volatile u32 transfer_complete; /* Transfer complete flag */ + volatile u32 block_gap_event; /* Block gap event flag */ + volatile u32 buffer_write_ready; /* Buffer write ready flag */ + volatile u32 buffer_read_ready; /* Buffer read ready flag */ + volatile u32 card_insertion; /* Card insertion flag */ + volatile u32 card_removal; /* Card removal flag */ + volatile u32 command_timeout_error; /* Command timeout error flag */ + volatile u32 command_crc_error; /* Command CRC error flag */ + volatile u32 command_end_bit_error; /* Command end bit error flag */ + volatile u32 command_index_error; /* Command index error flag */ + volatile u32 data_crc_error; /* Data CRC error flag */ +} IntStruct; + +/******************************************************************************* +* +* @brief Structure to hold transaction mode settings. +* +******************************************************************************/ +typedef struct { + u32 dma_enable; /* DMA enable flag */ + u32 block_count_enable; /* Block count enable flag */ + u32 auto_cmd_enable; /* Auto command enable flag */ + u32 data_transfer_direction_select; /* Data transfer direction select flag */ + u32 multi_or_single_block_select; /* Multi or single block select flag */ +} TransModeStruct; + +/******************************************************************************* +* +* @brief Structure representing the SD controller device. +* +******************************************************************************/ +struct sd_ctrl_dev { + int base_addr; /* Base address of the SD controller */ + int clk_freq; /* Clock frequency */ + int f_min; /* Minimum clock frequency */ + int f_max; /* Maximum clock frequency */ + int app_cmd; /* Application command flag */ + TransModeStruct *TransModePtr; /* Pointer to transaction mode settings */ +}; + +IntStruct IntPtr; /* Global interrupt status structure */ +u32 Descriptor[64]; /* Array to hold Descriptor */ +u32 DataDescriptor[64]; /* Array to hold Data Descriptor */ +u32 AttributeDescriptor[64]; /* Array to hold Attribute Descriptor */ + + + + +/******************************************************************************* +* +* @brief This function writes a 32-bit data value to the specified offset within the SD controller device registers. +* +* @param dev Pointer to the SD controller device structure. +* @param offset Offset address within the device registers where the data will be written. +* @param data 32-bit data value to be written. +* +******************************************************************************/ +static void sd_ctrl_write(struct sd_ctrl_dev *dev, uint32_t offset, uint32_t data) +{ + write_u32(data,dev->base_addr+offset); +} + +/******************************************************************************* +* +* @brief This function reads a 32-bit data value from the specified offset within the SD controller device registers. +* +* @param dev Pointer to the SD controller device structure. +* @param offset Offset address within the device registers from where the data will be read. +* @return The 32-bit data value read from the specified offset. +* +******************************************************************************/ +static uint32_t sd_ctrl_read(struct sd_ctrl_dev *dev, uint32_t offset) +{ + return read_u32(dev->base_addr+offset); +} + +/******************************************************************************* +* +* @brief This function sends a command to the SD controller device and handles the response accordingly. +* +* @param mmc Pointer to the MMC structure. +* @param cmd Pointer to the MMC command structure containing command details. +* @return 0 on success, -1 on failure. +* +******************************************************************************/ +static int sd_ctrl_cmd(struct mmc *mmc, struct mmc_cmd *cmd) +{ + int time_out; + u32 Value; + struct sd_ctrl_dev *dev = mmc->priv; + +#if(DEBUG_PRINTF_EN == 1) + { + if(dev->app_cmd) + bsp_printf("----[ACMD %d ARG 0x%x Rsp %d ]----\r\n",cmd->cmdidx, cmd->cmdarg,cmd->resp_type); + else + bsp_printf("----[CMD %d ARG 0x%x Rsp %d ]----\r\n",cmd->cmdidx, cmd->cmdarg,cmd->resp_type); + } +#endif //(DEBUG_PRINTF_EN == 1) + + sd_ctrl_write(dev,SDHC_ADDR+REG_ARGUMENT1,cmd->cmdarg); + + //Transfer Mode + Value = 0; + Value |= (dev->TransModePtr->dma_enable&0x1)<<0; + Value |= (dev->TransModePtr->block_count_enable&0x1)<<1; + Value |= (dev->TransModePtr->auto_cmd_enable&0x3)<<2; + Value |= (dev->TransModePtr->data_transfer_direction_select&0x1)<<4; + Value |= (dev->TransModePtr->multi_or_single_block_select&0x1)<<5; + //Command + //-resp_type [000b:No Response; 001b:R2; 010 b:R3,R4; 110b:R1,R5,R6,R7; 011b:R1b,R5b;] + if(cmd->resp_type & MMC_RSP_PRESENT) + { + if(cmd->resp_type & MMC_RSP_BUSY) Value |= 0x03<<16; + else if(cmd->resp_type & MMC_RSP_136) Value |= 0x01<<16; + else Value |= 0x02<<16; + + if(cmd->resp_type & MMC_RSP_CRC) Value |= 0x01<<19; + if(cmd->resp_type & MMC_RSP_OPCODE) Value |= 0x01<<20; + } + + //-data_present_select + if(dev->app_cmd) + { + if(cmd->cmdidx ==SD_CMD_APP_SEND_SCR || cmd->cmdidx == MMC_CMD_SEND_STATUS) //ACMD51 or ACMD13 + Value |= 0x1<<21; + else + Value |= 0x0<<21; + } + else{ + switch(cmd->cmdidx){ + case MMC_CMD_SWITCH: Value |= 0x1<<21; break; //CMD6 + case MMC_CMD_READ_SINGLE_BLOCK: Value |= 0x1<<21; break; //CMD17 + case MMC_CMD_READ_MULTIPLE_BLOCK: Value |= 0x1<<21; break; //CMD18 + case MMC_CMD_SEND_TUNING_BLOCK: Value |= 0x1<<21; break; //CMD19 + case MMC_CMD_WRITE_SINGLE_BLOCK: Value |= 0x1<<21; break; //CMD24 + case MMC_CMD_WRITE_MULTIPLE_BLOCK: Value |= 0x1<<21; break; //CMD25 + default: Value |= 0x0<<21; break; //else + } + } + + //-command_type + Value |= 0x0<<22; + //-command_index + Value |= (cmd->cmdidx&0x3f)<<24; + //Wait CMD Status idle. + + while(read_u32(SDHC_BASE+0x008)&0x1) { + bsp_uDelay(1); + } + sd_ctrl_write(dev,SDHC_ADDR+REG_TRANFER_MODE,Value); + + time_out = 0; + while(1) { + if(IntPtr.command_complete == 0x1) { + IntPtr.command_complete = 0x0; + if((IntPtr.command_timeout_error == 0x0) && (IntPtr.command_crc_error == 0x0) && + (IntPtr.command_end_bit_error == 0x0) && (IntPtr.command_index_error == 0x0)) { +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("Info : CMD Succeed!\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + if((cmd->resp_type&0xf) == 0x0) {//No Response + + } else if(cmd->resp_type & MMC_RSP_136) {//Response Length 136 + cmd->response[0] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP31_0);//cmd_resp[31:0] + cmd->response[1] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP63_32);//cmd_resp[63:32] + cmd->response[2] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP95_64);//cmd_resp[95:64] + cmd->response[3] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP127_96);//cmd_resp[127:96] + } else {//Response Length 48 + cmd->response[0] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP31_0);//cmd_resp[31:0] + cmd->response[1] = sd_ctrl_read(dev,SDHC_ADDR+REG_COMMAND_RESP63_32);//cmd_resp[63:32] + } + + } else { + IntPtr.command_timeout_error = 0x0; + IntPtr.command_crc_error = 0x0; + IntPtr.command_end_bit_error = 0x0; + IntPtr.command_index_error = 0x0; + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("Err : CMD Failed!\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + break; + } + } + + if(cmd->cmdidx == MMC_CMD_APP_CMD) + dev->app_cmd =1; + else + dev->app_cmd =0; + + mmc->priv = dev; + + return 0; +} + +/******************************************************************************* +* +* @brief This function creates a descriptor for data transfer by allocating memory +* for the descriptor table and setting up the descriptor entries. It calculates the +* number of lines required for the descriptor table based on the block size and +* number of blocks to transfer. +* +* @param mmc Pointer to the MMC structure. +* @param blocks Number of blocks to transfer. +* @param block_size Size of each block. +* @param src Source buffer for data transfer. +* @return 0 on success, -1 on failure. +* + ******************************************************************************/ +static int sd_ctrl_creat_Descriptor(struct mmc *mmc,u32 blocks,u32 block_size ,char* src) +{ + u32 Value=0; + u32 addr_location; + u32 lenght,sub,line,n; + + struct sd_ctrl_dev *dev = mmc->priv; + + //Max 64 line Descriptor + //Descriptor=malloc(sizeof(u32)*64); + memset(Descriptor,0,sizeof(Descriptor)); + memset(DataDescriptor,0,sizeof(DataDescriptor)); + memset(AttributeDescriptor,0,sizeof(AttributeDescriptor)); + + lenght = block_size*blocks; + + line=(lenght/MAX_DESCRIPTOR); + + if(lenght%MAX_DESCRIPTOR) line++; + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("lenght = %d line = %d in Addr = 0x%x\r\n",lenght,line,(u32)src); +#endif //(DEBUG_PRINTF_EN == 1) + + //Greate Descriptor Table + //Descriptor Table - Attribute + + for(n=0;n MAX_DESCRIPTOR) + Value |= (MAX_DESCRIPTOR&0xffff) <<16; + else + Value |= (lenght&0xffff)<<16; + // + //[5:4]:Nop(00b)/rsv(01b)/Tran(10b)/Link(11b); [2]:Int; [1]:End; [0]:Valid; + if(n==(line-1)) + { + Value |= 0x23; + } + else + { + Value |= 0x21; + } + + //Descriptor Table - Length + //The maximum data length of each descriptor line is less than 64KB. 0x0=65536 0x1=1 0x2=2......0xFFFFFFFF=65535 + DataDescriptor[n]=((u32)Descriptor)+(sizeof(u32)*2*n); + write_u32(Value, DataDescriptor[n]); + + AttributeDescriptor[n]=((u32)Descriptor)+sizeof(u32)+(sizeof(u32)*2*n); + + //Descriptor Table - Address Field + addr_location=((u32)src+(n*MAX_DESCRIPTOR)) & 0xFFFFFFFF; + write_u32(addr_location, AttributeDescriptor[n]); + + if (lenght > MAX_DESCRIPTOR) + lenght = lenght - MAX_DESCRIPTOR; + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("%d AttributeDescriptor[0x%x] = 0x%x Data[0x%x] = 0x%x\r\n",n,AttributeDescriptor[n],addr_location,DataDescriptor[n],Value); +#endif //(DEBUG_PRINTF_EN == 1) + } + + sd_ctrl_write(dev,SDHC_ADDR+REG_ADMA_SYSTEM_ADDR0,DataDescriptor[0]);//sdhc_reg - adma_system_address[31:0] + + return 0; +} + +/******************************************************************************* +* +* @brief This function handles data transfer between the SD controller and the SD card. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @param cmd Pointer to the MMC command structure. +* @param data Pointer to the MMC data structure containing data transfer information. +* @return Returns 0 upon successful data transfer. +* +******************************************************************************/ +static int sd_ctrl_data(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + u32 buf=0,tmp=0; + struct sd_ctrl_dev *dev =mmc->priv; + + //Transfer Mode Set +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("Write OPS Addr = 0x%x\r\n",dev->base_addr); + bsp_printf("IntPtr.transfer_complete %d \r\n",IntPtr.transfer_complete); +#endif //(DEBUG_PRINTF_EN == 1) + +#ifdef DMA_MODE + + dev->TransModePtr->dma_enable = 0x1; + if(data->flags==MMC_DATA_WRITE) + sd_ctrl_creat_Descriptor(mmc,data->blocks,data->blocksize,(char*)data->src); + else + sd_ctrl_creat_Descriptor(mmc,data->blocks,data->blocksize,data->dest); + +#else + dev->TransModePtr->dma_enable = 0x0; +#endif + + if(data->blocks == 0x1) { + dev->TransModePtr->auto_cmd_enable = 0x0; + } else { + dev->TransModePtr->auto_cmd_enable = 0x1; + } + + if(data->flags==MMC_DATA_WRITE) + dev->TransModePtr->data_transfer_direction_select = 0x0; + else + dev->TransModePtr->data_transfer_direction_select = 0x1; + + mmc->priv = dev; + + //Set Block Size & Block Count + sd_ctrl_write(dev,SDHC_ADDR+REG_BLOCKSIZE_COUNT,((data->blocks&0xffff)<<16) | data->blocksize);//sdhc_reg - Block Size & Block Count Register + + sd_ctrl_cmd(mmc,cmd); + + +#if(DEBUG_PRINTF_EN == 1) + if((cmd->response[0]>>3)&0x1) bsp_printf("CS-AKE_SEQ_ERROR\r\n"); + if((cmd->response[0]>>5)&0x1) bsp_printf("CS-APP_CMD\r\n"); + if((cmd->response[0]>>8)&0x1) bsp_printf("CS-READY_FOR_DATA\r\n"); + bsp_printf("CS-CURRENT_STATE %d\r\n", (cmd->response[0]>>9)&0xf); + if((cmd->response[0]>>13)&0x1) bsp_printf("CS-ERASE_RESET\r\n"); + if((cmd->response[0]>>14)&0x1) bsp_printf("CS-CARD_ECC_DISABLED\r\n"); + if((cmd->response[0]>>15)&0x1) bsp_printf("CS-WP_ERASE_SKIP\r\n"); + if((cmd->response[0]>>16)&0x1) bsp_printf("CS-CSD_OVERWRITE\r\n"); + if((cmd->response[0]>>19)&0x1) bsp_printf("CS-ERROR\r\n"); + if((cmd->response[0]>>20)&0x1) bsp_printf("CS-CC_ERROR\r\n"); + if((cmd->response[0]>>21)&0x1) bsp_printf("CS-CARD_ECC_FAILED\r\n"); + if((cmd->response[0]>>22)&0x1) bsp_printf("CS-ILLEGALCOMMAND\r\n"); + if((cmd->response[0]>>23)&0x1) bsp_printf("CS-COM_CRC_ERROR\r\n"); + if((cmd->response[0]>>24)&0x1) bsp_printf("CS-LOCK_UNLOCK_FAILED\r\n"); + if((cmd->response[0]>>25)&0x1) bsp_printf("CS-CARD_IS_LOCKED\r\n"); + if((cmd->response[0]>>26)&0x1) bsp_printf("CS-WP_VIOLATION\r\n"); + if((cmd->response[0]>>27)&0x1) bsp_printf("CS-ERASE_PARAM\r\n"); + if((cmd->response[0]>>28)&0x1) bsp_printf("CS-ERASE_SEQ_ERROR\r\n"); + if((cmd->response[0]>>29)&0x1) bsp_printf("CS-BLOCK_LEN_ERROR\r\n"); + if((cmd->response[0]>>30)&0x1) bsp_printf("CS-ADDRESS_ERROR\r\n"); + if((cmd->response[0]>>31)&0x1) bsp_printf("CS-OUT_OF_RANGE\r\n"); +#endif //(DEBUG_PRINTF_EN == 1) + +#ifndef DMA_MODE + + if(data->flags==MMC_DATA_WRITE) + { + for(int i=0; i<(data->blocks); i++) { + + //Wait one block data can be written to the buffer. + while(1) { + if(sd_ctrl_read(dev,SDHC_ADDR+REG_PRESENT_STATE)&0x400) { + break; + } + //bsp_uDelay(1); + } + //Write One Block + for(int j=0; j<((data->blocksize)/4); j++) { + + buf = data->src[tmp++]; + buf |= data->src[tmp++]<<8; + buf |= data->src[tmp++]<<16; + buf |= data->src[tmp++]<<24; + //bsp_printf("WRITE %x \r\n",buf); + + sd_ctrl_write(dev,SDHC_ADDR+REG_BUFFER_DATA,buf);//sdhc_reg - buffer_data_port Register +// bsp_uDelay(1); + } + } + } + else + { + for(int i=0; iblocks; i++) { + //Wait readable block data exists in the buffer. + while(1) { + if(sd_ctrl_read(dev,SDHC_ADDR+REG_PRESENT_STATE)&0x800) { + break; + } + //bsp_uDelay(1); + } + //Read One Block + for(int j=0; j<(BLOCK_SIZE/4); j++) { + buf = sd_ctrl_read(dev,SDHC_ADDR+REG_BUFFER_DATA); + + data->dest[tmp++]=buf & 0xFF; + data->dest[tmp++]=(buf>>8) & 0xFF; + data->dest[tmp++]=(buf>>16) & 0xFF; + data->dest[tmp++]=(buf>>24) & 0xFF; + + //bsp_uDelay(1);//Must ensure that the read rate is lower than the SD clock rate. + } + //clear read buffer ready in the end of transfer if the signal asserted in the middle of transfer + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,0x20); + //bsp_uDelay(1); + } + } + +#endif + //Wait Transfer Complete Interrupt + while(1) { + if(IntPtr.transfer_complete == 0x1) { + IntPtr.transfer_complete = 0x0; + //bsp_uDelay(100); + break; + } + } + return 0; +} + + +/******************************************************************************* +* +* @brief This function checks if the MMC command requires data read or write operations. +* +* @param cmd Pointer to the MMC command structure. +* @return Returns 1 if the command requires data read or write operations, otherwise returns 0. +* +*******************************************************************************/ + +static int sd_ctrl_check_read_write(struct mmc_cmd *cmd) +{ + if(cmd->cmdidx== MMC_CMD_READ_SINGLE_BLOCK) return 1; + else if(cmd->cmdidx== MMC_CMD_READ_MULTIPLE_BLOCK) return 1; + else if(cmd->cmdidx== MMC_CMD_WRITE_SINGLE_BLOCK) return 1; + else if(cmd->cmdidx== MMC_CMD_WRITE_MULTIPLE_BLOCK) return 1; + else if(cmd->cmdidx== MMC_CMD_SEND_STATUS) return 1; + else if(cmd->cmdidx== SD_CMD_APP_SEND_SCR) return 1; + else return 0; +} + +/******************************************************************************* +* +* @brief This function sends the MMC command with or without data transfer +* based on the command type. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @param cmd Pointer to the MMC command structure. +* @param data Pointer to the MMC data structure containing data transfer information. +* @return Returns 0 upon successful command execution. +* +*******************************************************************************/ +static int sd_ctrl_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + if(sd_ctrl_check_read_write(cmd)) + { + if(data) + { + sd_ctrl_data(mmc,cmd,data); + } + } + else + { + sd_ctrl_cmd(mmc,cmd); + } + + return 0; +} + +/******************************************************************************* +* +* @brief This function gets the card detect status. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 1 if the card is detected, otherwise returns 0. +* +*******************************************************************************/ +static int sd_ctrl_get_cd(struct mmc *mmc) +{ + return 1; +} + +/******************************************************************************* +* +* @brief This function gets the write protect status. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 0 indicating no write protection. +* +*******************************************************************************/ +static int sd_ctrl_get_wp(struct mmc *mmc) +{ + return 0; +} + +/******************************************************************************* +* +* @brief This function sets the clock frequency for SD operations. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 0 upon successful clock setting. +* +*******************************************************************************/ +static int sd_ctrl_set_clk(struct mmc *mmc) +{ + struct sd_ctrl_dev *dev = mmc->priv; + int clk; + u32 Value; + + if(dev->clk_freq >= mmc->f_max) + clk=mmc->f_max; + else if(dev->clk_freq <= mmc->f_min) + clk=mmc->f_min; + else + clk = dev->clk_freq; + + mmc->clock = clk; + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("clk=%d\r\n",clk); +#endif //(DEBUG_PRINTF_EN == 1) + + Value = 100000/clk; + + //sys_reg - clk_out_en & clk_out_div + sd_ctrl_write(dev,0x004,(0x1<<16) | Value); + +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("SDS Clock Division oefficient %d\r\n", Value); +#endif //(DEBUG_PRINTF_EN == 1) + + bsp_uDelay(10); + + return 0; +} + +/******************************************************************************* +* +* @brief This function sets the bus width for SD operations. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 0 upon successful bus width setting. +* +*******************************************************************************/ +static int sd_ctrl_set_bus(struct mmc *mmc) +{ + int set_width; + struct sd_ctrl_dev *dev = mmc->priv; + + if(mmc->bus_width >=4) set_width=2; //4 bit + else set_width=1; //1 bit + + sd_ctrl_write(dev,SDHC_ADDR+REG_HOST_CONTORL,set_width); + + return 0; +} + +/******************************************************************************* +* +* @brief This function sets the I/O settings for the SD controller. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 0 upon successful I/O setting. +* +*******************************************************************************/ +static int sd_ctrl_set_ios(struct mmc *mmc) +{ + sd_ctrl_set_clk(mmc); // Set clock frequency + sd_ctrl_set_bus(mmc); // Set bus width + return 0; +} + +/******************************************************************************* +* +* @brief This function initializes the SD controller and MMC/SD card. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @return Returns 0 upon successful initialization. +* +*******************************************************************************/ +static int sd_ctrl_init(struct mmc *mmc) +{ + mmc->cfg->ops->getcd(mmc); // Get card detect status + mmc->cfg->ops->getwp(mmc); // Get write protect status + mmc->cfg->ops->set_ios(mmc); // Set I/O settings + return 0; +} + +/******************************************************************************* +* +* @brief This function probes and initializes the MMC/SD controller. +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @param base_addr Base address of the SD controller. +* @return Returns 0 upon successful probe and initialization. +* +*******************************************************************************/ + +static int sd_ctrl_mmc_probe(struct mmc *mmc, int base_addr) +{ + struct sd_ctrl_dev *dev; + TransModeStruct *ptr; + + // Allocate memory for SD controller device and transfer mode structure + dev = malloc(sizeof(struct sd_ctrl_dev)); + ptr = malloc(sizeof(TransModeStruct)); + + // Initialize allocated memory with zeros + memset(dev, 0, sizeof(struct sd_ctrl_dev)); + memset(ptr, 0, sizeof(TransModeStruct)); + + // Set SD controller device properties + dev->base_addr = base_addr; + dev->clk_freq = SD_CLK_FREQ; + dev->TransModePtr = ptr; + + // Set MMC private data to SD controller device + mmc->priv = dev; + + // Set MMC configuration properties + mmc->cfg->name = "efx_sd_controller"; + mmc->cfg->ops->send_cmd = sd_ctrl_send_cmd; + mmc->cfg->ops->set_ios = sd_ctrl_set_ios; + mmc->cfg->ops->getcd = sd_ctrl_get_cd; + mmc->cfg->ops->getwp = sd_ctrl_get_wp; + + // Set MMC clock frequency and capabilities + mmc->f_max = MAX_CLK_FREQ; + mmc->f_min = MAX_CLK_FREQ / 4; + mmc->host_caps = MMC_MODE_4BIT; + mmc->cfg->b_max = 1024; + mmc->bus_width = 4; + mmc->high_capacity = 1; + mmc->read_bl_len = BLOCK_SIZE; + + // Set MMC voltage support + mmc->cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + + // Initialize SD controller and MMC/SD card + sd_ctrl_init(mmc); + + return 0; +} + +/******************************************************************************* +* +* @brief This function triggers send command function +* +* @param mmc Pointer to the MMC structure representing the MMC/SD card. +* @param cmd Pointer to the MMC CMD structure representing the MMC/SD card. +* @param index The Command Index to send to MMC/SD card. +* @param resp_type The Response type expected to return from MMC/SD card. +* @param cmdarg Argument to send. +* @return Returns 0 upon successful probe and initialization. +* +*******************************************************************************/ +static void sd_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, u32 index, u32 resp_type, u32 cmdarg) +{ + struct mmc_ops *ops = mmc->cfg->ops; + struct mmc_data *data = NULL; + + cmd->cmdidx = index; + cmd->resp_type = resp_type; + cmd->cmdarg =cmdarg; + + ops->send_cmd(mmc,cmd,data); +} + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_mac.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_mac.h new file mode 100644 index 0000000..136095a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_mac.h @@ -0,0 +1,308 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file efx_tse_mac.h +* +* @brief Header file contain Mac function for the TSE (Triple-Speed Ethernet) +* +* Functions: +* - MacTxEn: Sets the transmit enable (TxEn) bit in the TSEMAC control/status register. +* - MacRxEn: Sets the receive enable (RxEn) bit in the TSEMAC control/status register. +* - MacSpeedSet: Sets the speed mode in the TSEMAC control/status register. +* - MacLoopbackSet: Sets the loopback mode in the TSEMAC control/status register. +* - MacIpgSet: Sets the Inter-Packet Gap (IPG) value in the TSEMAC IPG register. +* - MacAddrSet: Sets the destination and source MAC addresses in the TSEMAC registers. +* - Pause_XOn: Sets the transmit pause frame (XON) generation in the TSEMAC control/status register. +* - MacCntClean: Resets the statistics counters in the TSEMAC control/status register. +* - CntMonitor: Monitors and prints various statistics counters from the TSEMAC registers. +* - MacNormalInit: Initializes the TSEMAC with normal settings. +* +******************************************************************************/ +#pragma once + +#include "bsp.h" +#include "userDef.h" + +// MAC Configuration Registers +#define VERSION 0x0000 +#define COMMAND_CONFIG 0x0008 +#define MAC_ADDR_LO 0x000C +#define MAC_ADDR_HI 0x0010 +#define FRM_LENGHT 0x0014 +#define PAUSE_QUANT 0x0018 +#define TX_IPG_LEN 0x005C +#define ETHERNET_CTRL_MAC_RST 0x0200 +#define ETHERNET_CTRL_PHY_RST 0x0204 +// MDIO Configuration Registers +#define DIVIDER_PRE 0x0100 +#define RD_WR_EN 0x0104 +#define REG_PHY_ADDR 0x0108 +#define WR_DATA 0x010C +#define RD_DATA 0x0110 +#define STATUS 0x0114 + +// Receive Supplementary Registers +#define BOARD_FILTER_EN 0x0140 +#define MAC_ADDR_MAKE_LO 0x0144 +#define MAC_ADDR_MAKE_HI 0x0148 +#define TX_DST_ADDR_INS 0x0180 +#define DST_MAC_ADDR_LO 0x0184 +#define DST_MAC_ADDR_HI 0x0188 + +// Statistic Counter Registers +#define A_FRAME_TRANSMITTED_OK 0x0068 +#define A_FRAME_RECEIVED_OK 0x006C +#define A_FRAME_CHECK_SEQ_ERR 0x0070 +#define A_TX_PAUSE_MAC_CTRL_FRAME 0x0080 +#define A_RX_PAUSE_MAC_CTRL_FRAME 0x0084 +#define IF_INDICATES_ERROR 0x0088 +#define IF_OUT_ERROR 0x008C +#define A_RX_FILTER_FRAMES_ERROR 0x009C +#define ETHER_STATS_PKTS 0x00B4 +#define ETHER_STATS_UNDER_SIZE_PKTS 0x00B8 +#define ETHER_STATS_OVERSIZE_PKTS 0x00BC +#define ETHER_PACKET_LENS 0x00C0 + +// IP Example Design Configuration Registers +#define MAC_SW_RST 0x0200 //[0] mac_sw_rst +#define MUX_SELECT 0x0204 //[1] pat_mux_select [0] axi4_st_mux_select +#define UDP_MAC_PAT_GEN_EN 0x0208 //[1] mac_pat_gen_en [0] udp_pat_gen_en +#define PAT_GEN_NUM_IPG 0x020C //[15:0] pat_gen_num [31:16] pat_gen_ipg +#define PAT_DST_MAC_LO 0x0210 //[31:0] pat_dst_mac +#define PAT_DST_MAC_HI 0x0214 //[47:32] pat_dst_mac +#define PAT_SRC_MAC_LO 0x0218 //[31:0] pat_src_mac +#define PAT_SRC_MAC_HI 0x021C //[47:32] pat_src_mac +#define PAT_MAC_DLEN 0x0220 //[15:0] pat_mac_dlen +#define PAT_SRC_IP 0x0224 //[31:0] pat_src_ip +#define PAT_DST_IP 0x0228 //[31:0] pat_dst_ip +#define PAT_SRC_DST_PORT 0x022C //[31:16] pat_dst_port [15:0] pat_src_port +#define PAT_UDP_DLEN 0x0230 //[15:0] pat_udp_dlen + + +/******************************************************************************* +* +* @brief This function sets the transmit enable (TxEn) bit in the TSEMAC control/status register. +* +* @param tx_en The value to set for the transmit enable bit. +* - 0: Disable transmit. +* - 1: Enable transmit. +* +******************************************************************************/ +static void MacTxEn(u32 tx_en) +{ + u32 Value; + //Set Mac TxEn + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & TX_ENA_MASK; + Value |= (tx_en&0x1)<<0; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac TxEn.\r\n"); + } +} + +/******************************************************************************* +* +* @brief This function sets the transmit enable (RxEn) bit in the TSEMAC control/status register. +* +* @param tx_en The value to set for the receive enable bit. +* - 0: Disable receive. +* - 1: Enable receive. +* +******************************************************************************/ +static void MacRxEn(u32 rx_en) +{ + u32 Value; + //Set Mac RxEn + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & RX_ENA_MASK; + Value |= (rx_en&0x1)<<1; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac RxEn.\r\n"); + } +} + +/******************************************************************************* +* +* @brief This function sets the Ethernet Speed +* +* @param speed The value to set for the Ethernet Speed. +* - 0x01: 10Mbps +* - 0x02: 100Mbps +* - 0x04: 1000Mbps +* +******************************************************************************/ +static void MacSpeedSet(u32 speed) +{ + u32 Value; + //Set Mac Speed + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & ETH_SPEED_MASK; + Value |= (speed&0x7)<<16; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac Speed %d.\r\n",speed); + } +} + +/******************************************************************************* +* +* @brief This function sets the loopback mode in the TSEMAC control/status register. +* +* @param loopback_en The value to set for the loopback mode. +* - 0: Disable loopback. +* - 1: Enable loopback. +* +******************************************************************************/ +static void MacLoopbackSet(u32 loopback_en) +{ + u32 Value; + //Set Mac Loopback + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & LOOP_ENA_MASK; + Value |= (loopback_en&0x1)<<15; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac Loopback."); + } +} + +/******************************************************************************* +* +* @brief This function sets the inter-packet gap (IPG) value in the TSEMAC IPG register. +* +* @param ipg The value of the inter-packet gap to be set. +* +******************************************************************************/ +static void MacIpgSet(u32 ipg) +{ + //Set Mac IPG + write_u32(ipg&0x3f, (TSEMAC_BASE+TX_IPG_LEN)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac IPG."); + } +} + +/******************************************************************************* +* +* @brief This function sets the destination and source MAC addresses in the TSEMAC control/status register. +* +* @param dst_addr_ins The value to be written to the destination MAC address insert register. +* @param src_addr_ins The value to be written to the source MAC address insert register. +* +******************************************************************************/ +static void MacAddrSet(u32 dst_addr_ins, u32 src_addr_ins) +{ + u32 Value; + //dst mac addr set + //mac_reg mac_addr[47:32] + write_u32(DST_MAC_H, (TSEMAC_BASE+DST_MAC_ADDR_HI)); + //mac_reg mac_addr[31:0] + write_u32(DST_MAC_L, (TSEMAC_BASE+DST_MAC_ADDR_LO)); + //dst mac addr ins set + //mac_reg tx_dst_addr_ins + write_u32(dst_addr_ins, (TSEMAC_BASE+TX_DST_ADDR_INS)); + //src mac addr set + //mac_addr[47:32] + write_u32(SRC_MAC_H, (TSEMAC_BASE+MAC_ADDR_HI)); + //mac_addr[31:0] + write_u32(SRC_MAC_L, (TSEMAC_BASE+MAC_ADDR_LO)); + //src mac addr ins set + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & TX_ADDR_INS_MASK; + Value |= (src_addr_ins&0x1)<<9; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Mac Address."); + } +} + +/********************************* Function ********************************** +* +* @brief This function sets the XON/XOFF pause frame control in the TSEMAC control/status register. +* +******************************************************************************/ +static void Pause_XOn() +{ + u32 Value; + //Set xon_gen 1 + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & XON_GEN_MASK; + Value |= 0x1<<2; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + //Set xon_gen 0 + Value &= XON_GEN_MASK; + Value |= 0x0<<2; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); +} + +/******************************************************************************* +* +* @brief This function sets and clears the statistics counters in the TSEMAC control/status register. +* +******************************************************************************/ +static void MacCntClean() +{ + u32 Value; + //Set cnt_reset 1 + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG) & CNT_RST_MASK; + Value |= 0x80000000; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + bsp_uDelay(1); + //Set cnt_reset 0 + Value &= CNT_RST_MASK; + Value |= 0x0; + write_u32(Value, (TSEMAC_BASE+COMMAND_CONFIG)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Mac Reset Statistics Counters."); + } +} + +/******************************************************************************* +* +* @brief This function prints the values of various statistics counters in the TSEMAC control/status register. +* +* @note This function is usefult to track trasmit/receive frame error such as CRC errors, etc +* +******************************************************************************/ +static void CntMonitor() +{ + bsp_printf("--------------------\r\n"); + bsp_printf("aFramesTransmittedOK :%x\r\n" , read_u32(TSEMAC_BASE+A_FRAME_TRANSMITTED_OK)); + bsp_printf("aFramesReceivedOK :%x\r\n" , read_u32(TSEMAC_BASE+A_FRAME_RECEIVED_OK)); + bsp_printf("ifInErrors :%x\r\n" , read_u32(TSEMAC_BASE+IF_INDICATES_ERROR)); + bsp_printf("ifOutErrors :%x\r\n" , read_u32(TSEMAC_BASE+IF_OUT_ERROR)); + bsp_printf("etherStatsPkts :%x" , read_u32(TSEMAC_BASE+ETHER_STATS_PKTS)); + bsp_printf("etherStatsUndersizePkts :%x\r\n" , read_u32(TSEMAC_BASE+ETHER_STATS_UNDER_SIZE_PKTS)); + bsp_printf("etherStatsOversizePkts :%x\r\n" , read_u32(TSEMAC_BASE+ETHER_STATS_OVERSIZE_PKTS)); + bsp_printf("aRxFilterFramesErrors :%x\r\n" , read_u32(TSEMAC_BASE+A_RX_FILTER_FRAMES_ERROR)); + bsp_printf("aFrameCheckSequenceErrors :%x\r\n", read_u32(TSEMAC_BASE+A_FRAME_CHECK_SEQ_ERR)); + bsp_printf("aTxPAUSEMACCtrlFrames :%x\r\n" , read_u32(TSEMAC_BASE+A_TX_PAUSE_MAC_CTRL_FRAME)); + bsp_printf("aRxPAUSEMACCtrlFrames :%x\r\n" , read_u32(TSEMAC_BASE+A_RX_PAUSE_MAC_CTRL_FRAME)); + bsp_printf("--------------------\r\n"); +} + + +/******************************************************************************* +* +* @brief This function initializes the MAC by setting IPG and Speed. +* +* @param speed The speed setting to be applied to the TSEMAC. +* +******************************************************************************/ +static void MacNormalInit(u32 speed) +{ + MacSpeedSet(speed); + MacIpgSet(0x0C); +} + +/************************** Function File ***************************/ +static void MacRst(u8 macRst, u8 phyRst) +{ + write_u32((phyRst & 0x01), TSEMAC_BASE+ETHERNET_CTRL_PHY_RST); + write_u32((macRst & 0x01), TSEMAC_BASE+ETHERNET_CTRL_MAC_RST); + bsp_uDelay(100*1000); // 100ms delay + write_u32(0, TSEMAC_BASE+ETHERNET_CTRL_MAC_RST); + bsp_uDelay(100*1000); // 100ms delay + write_u32(0, TSEMAC_BASE+ETHERNET_CTRL_PHY_RST); + bsp_uDelay(100*1000); // 100ms delay +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_phy.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_phy.h new file mode 100644 index 0000000..6a5240d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/efx_tse_phy.h @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file efx_tse_phy.h +* +* @brief Header file containing PHY functions for the TSE (Triple-Speed Ethernet) +* +* Functions: +* - Phy_Wr: Writes data to a PHY register. +* - Phy_Rd: Reads data from a PHY register. +* - PhyDlySetRXTX: Sets the RX and TX delays for the PHY. +* - PhyNormalInit: Initializes the PHY in normal mode. +* - PhyLoopInit: Initializes the PHY in loopback mode. +* +******************************************************************************/ +#pragma once + +#include "bsp.h" +#include "userDef.h" + + +/******************************************************************************* +* +* @brief This function writes data to a specified PHY register. +* +* @param RegAddr The address of the PHY register to write to. +* +* @return The data to be written to PHY register. +* +******************************************************************************/ +static void Phy_Wr(u32 RegAddr, u32 Data) +{ + write_u32(((PHY_ADDR&0x1f)<<8)|(RegAddr&0x1f), (TSEMAC_BASE+REG_PHY_ADDR)); + write_u32(Data, (TSEMAC_BASE+WR_DATA)); + write_u32(0x2, (TSEMAC_BASE+RD_WR_EN)); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Wr Phy Addr :%x \r\n", RegAddr); + bsp_printf("Wr Phy Data :%x \r\n ", Data); + } +} + +/******************************************************************************* +* +* @brief This function reads data from a specified PHY register. +* +* @param RegAddr The address of the PHY register to read from. +* +* @return The data read from the PHY register. +* +******************************************************************************/ +static u32 Phy_Rd(u32 RegAddr) +{ + u32 Value; + write_u32(((PHY_ADDR&0x1f)<<8)|(RegAddr&0x1f), (TSEMAC_BASE+REG_PHY_ADDR)); + write_u32(0x1, (TSEMAC_BASE+RD_WR_EN)); + bsp_uDelay(1000); + Value = read_u32(TSEMAC_BASE+RD_DATA); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Rd Phy Addr :%x \r\n ", RegAddr); + bsp_printf("Return Value :%x \r\n ", Value); + } + return Value; +} + +/******************************************************************************* +* +* @brief This function sets the RX and TX delays for the PHY. +* +* @param RX_delay The delay value for the RX path. +* +* @param TX_delay The delay value for the TX path. +* +******************************************************************************/ +static void PhyDlySetRXTX(int RX_delay, int TX_delay) +{ + u32 Value; + bsp_print("Start Info : Set Phy Delay."); + Phy_Wr(0x1F,0x0168); + Phy_Wr(0x1E,0x8040); + Phy_Wr(0x1E,0x401E); + Value = Phy_Rd(0x1F) & 0xFFFF; + + Value &= 0xFF00; + RX_delay &= 0xF; + TX_delay &= 0xF; + bsp_printf("Setup New Value =%x \r\n ", RX_delay); + + Value = ((Value) | (RX_delay<<4) | (TX_delay)); + Phy_Wr(0x1F,Value); + Phy_Wr(0x1E,0x801E); + Phy_Wr(0x1E,0x401E); + Value = Phy_Rd(0x1F) & 0xFFFF; + bsp_printf("Read New Value =%x \r\n ", Value); +} + + +/******************************************************************************* +* +* @brief This function initializes the PHY in normal mode and waits for the Ethernet link to be up. +* +* @return The speed of the Ethernet link (0x01: 10Mbps, 0x02: 100Mbps, 0x04: 1000Mbps). +* +******************************************************************************/ +static u32 PhyNormalInit() +{ + PhyDlySetRXTX(15, 8); + + u32 Value; + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Wait Ethernet Link up..."); + } + // to read Basic control + Phy_Rd(0x0); + // to read phy ID + Phy_Rd(0x2); + // to read phy ID + Phy_Rd(0x3); + + //Unlock Extended registers + Phy_Wr(0x1f, 0x0168); + Phy_Wr(0x1e, 0x8040); + + while(1) { + Value = Phy_Rd(0x11); + //Link up and DUPLEX mode + if((Value&0x2400) == 0x2400) { + if((Value&0xc000) == 0x8000) { //1000Mbps + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Phy Link up on 1000Mbps.\r\n"); + } + return 0x4; + } else if((Value&0xc000) == 0x4000) { //100Mbps + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Phy Link up on 100Mbps.\r\n"); + } + return 0x2; + } else if((Value&0xc000) == 0x0) { //10Mbps + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Phy Link up on 10Mbps.\r\n"); + } + return 0x1; + } + } + bsp_uDelay(100000); + } +} + +/******************************************************************************* +* +* @brief This function initializes the PHY in loopback mode based on the specified speed. +* +* @param speed The speed at which to initialize the PHY (0x01: 10Mbps, 0x02: 100Mbps, 0x04: 1000Mbps). +* +******************************************************************************/ +static void PhyLoopInit(u32 speed) +{ + PhyDlySetRXTX(15, 15); + u32 Value; + if(speed == 0x4) { + Phy_Wr(0x0, 0x4140); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Phy 1000Mbps Loopback Mode.\r\n"); + } + } else if(speed == 0x2) { + Phy_Wr(0x0, 0x6100); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Phy 100Mbps Loopback Mode.\r\n"); + } + } else if(speed == 0x1) { + Phy_Wr(0x0, 0x4100); + if(DEBUG_PRINTF_EN == 1) { + bsp_printf("Info : Set Phy 10Mbps Loopback Mode.\r\n"); + } + } +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/gpio.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/gpio.h new file mode 100644 index 0000000..3d70dbe --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/gpio.h @@ -0,0 +1,162 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file gpio.h +* +* @brief Header file for GPIO (General Purpose Input/Output) register access and control. +* +* Functions: +* - gpio_getInput: reads a 32-bit value from the GPIO input register at address of +* reg + offset (GPIO_INPUT). +* - gpio_getOutput: reads a 32-bit value from the GPIO output register at address of +* reg + offset (GPIO_OUTPUT). +* - gpio_setOutput: Writes a 32-bit value to GPIO output register at address of +* reg + offset (GPIO_OUTPUT). +* - gpio_getOutputEnable: Reads a 32-bit value from the GPIO output enable register +* at address of reg + offset (GPIO_OUTPUT_ENABLE). +* - gpio_setOutputEnable: Writes a 32-bit value to the GPIO output enable register +* at address of reg + offset (GPIO_OUTPUT_ENABLE). +* - gpio_setInterruptRiseEnable: Writes a 32-bit value to GPIO interrupt register +* at address of reg + offset (GPIO_INTERRUPT_RISE_ENABLE). +* - gpio_setInterruptFallEnable: Writes a 32-bit value to GPIO interrupt register +* at address of reg + offset (GPIO_INTERRUPT_FALL_ENABLE). +* - gpio_setInterruptHighEnable: Writes a 32-bit value to GPIO interrupt register +* at address of reg + offset (GPIO_INTERRUPT_HIGH_ENABLE). +* - gpio_setInterruptLOWEnable: Writes a 32-bit value to GPIO interrupt register +* at address of reg + offset (GPIO_INTERRUPT_LOW_ENABLE). +* +******************************************************************************/ +#pragma once + +#include "type.h" +#include "io.h" + +//Offset +#define GPIO_INPUT 0x00 +#define GPIO_OUTPUT 0x04 +#define GPIO_OUTPUT_ENABLE 0x08 +#define GPIO_INTERRUPT_RISE_ENABLE 0x20 +#define GPIO_INTERRUPT_FALL_ENABLE 0x24 +#define GPIO_INTERRUPT_HIGH_ENABLE 0x28 +#define GPIO_INTERRUPT_LOW_ENABLE 0x2c + +/******************************************************************************* +* +* @brief Reads a 32-bit value from the GPIO input register at address of +* reg + offset (GPIO_INPUT). +* +* @return The value read from the GPIO input register. +* +* @note refer to readReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + readReg_u32 (gpio_getInput , GPIO_INPUT) + +/******************************************************************************* +* +* @brief Reads a 32-bit value from the GPIO output register at address of +* reg + offset (GPIO_OUTPUT). +* +* @return The value read from the GPIO output register. +* +* @note refer to readReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + readReg_u32 (gpio_getOutput , GPIO_OUTPUT) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO output register at address of +* reg + offset (GPIO_OUTPUT). +* +* @param data The data to be written to the GPIO output register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + writeReg_u32(gpio_setOutput , GPIO_OUTPUT) + +/******************************************************************************* +* +* @brief Reads a 32-bit value from the GPIO output enable register at address of +* reg + offset (GPIO_OUTPUT_ENABLE). +* +* @return The value read from the GPIO output enable register. +* +* @note refer to readReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + readReg_u32 (gpio_getOutputEnable , GPIO_OUTPUT_ENABLE) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO output enable register at address of +* reg + offset (GPIO_OUTPUT_ENABLE). +* +* @param data The data to be written to the GPIO output enable register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + writeReg_u32(gpio_setOutputEnable , GPIO_OUTPUT_ENABLE) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO interrupt register at address of +* reg + offset (GPIO_INTERRUPT_RISE_ENABLE). +* +* @param data The data to be written to the GPIO interrupt register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + writeReg_u32(gpio_setInterruptRiseEnable , GPIO_INTERRUPT_RISE_ENABLE) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO interrupt register at address of +* reg + offset (GPIO_INTERRUPT_FALL_ENABLE). +* +* @param data The data to be written to the GPIO interrupt register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + writeReg_u32(gpio_setInterruptFallEnable , GPIO_INTERRUPT_FALL_ENABLE) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO interrupt register at address of +* reg + offset (GPIO_INTERRUPT_HIGH_ENABLE). +* +* @param data The data to be written to the GPIO interrupt register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + + writeReg_u32(gpio_setInterruptHighEnable , GPIO_INTERRUPT_HIGH_ENABLE) + +/******************************************************************************* +* +* @brief Writes a 32-bit value to GPIO interrupt register at address of +* reg + offset (GPIO_INTERRUPT_LOW_ENABLE). +* +* @param data The data to be written to the GPIO interrupt register. +* +* @note refer to writeReg_u32 in io.h for detail explanation. +* +******************************************************************************/ + writeReg_u32(gpio_setInterruptLowEnable , GPIO_INTERRUPT_LOW_ENABLE) diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/i2c.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/i2c.h new file mode 100644 index 0000000..32841b3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/i2c.h @@ -0,0 +1,932 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +/** +* @file i2c.h +* +* @brief Header file for I2C module containing various I2C functions for communication. +* +* The available functions are: +* - i2c_writeData_b: Writes data to a specified register address (8bit) on an I2C slave device. +* - i2c_writeData_w: Writes data to a specified register address (16bit) on an I2C slave device. +* - i2c_readData_b: Reads data from a specified register address (8bit) on an I2C slave device. +* - i2c_readData_w: Reads data from a specified register address (16bit) on an I2C slave device. +* - i2c_applyConfig: Applies the configuration settings to the I2C module. +* - i2c_filterEnable: Enables filtering for a specific filter ID. +* - i2c_masterStart: Initiates the start condition for I2C communication. +* - i2c_masterRestart: Initiates a repeated start condition for I2C communication. +* - i2c_masterRecover: Initiates the recovery process for I2C communication. +* - i2c_masterBusy: Checks if the I2C master is busy. +* - i2c_masterStatus: Returns the status of the I2C master. +* - i2c_masterStartBlocking: Initiates the start condition for I2C communication and waits until it completes. +* - i2c_masterRestartBlocking: Initiates the restart condition for I2C communication +* - i2c_masterStop: Initiates the stop condition for I2C communication. +* - i2c_masterRecoverBlocking: Initiates the recovery process for I2C communication and waits until it completes. +* - i2c_masterStopWait: Waits until the I2C master stops. +* - i2c_masterDrop: Initiates the drop condition for I2C communication. +* - i2c_masterStopBlocking: Initiates the stop condition for I2C communication and waits until it completes. +* - i2c_listenAck: Listens for acknowledgment during I2C communication. +* - i2c_txByte: Transmits a byte over the I2C bus. +* - i2c_txAck: Transmits an acknowledgment signal over the I2C bus. +* - i2c_txNack: Transmits a non-acknowledgment signal over the I2C bus. +* - i2c_txAckWait: Waits until the acknowledgment signal transmission completes. +* - i2c_txAckBlocking: Transmits an acknowledgment signal over the I2C bus and waits until it completes. +* - i2c_txNackBlocking: Transmits a non-acknowledgment signal over the I2C bus and waits until it completes. +* - i2c_rxData: Reads received data from the I2C bus. +* - i2c_rxNack: Checks if a NACK signal is received. +* - i2c_rxAck: Checks if an ACK signal is received. +* - i2c_txByteRepeat: Transmits a byte over the I2C bus with repeat mode enabled. +* - i2c_txNackRepeat: Transmits a non-acknowledgment signal over the I2C bus with repeat mode enabled. +* - i2c_setFilterConfig: Sets the filter configuration for a specific filter ID. +* - i2c_enableInterrupt: Enables specific interrupts for the I2C module. +* - i2c_disableInterrupt: Disables specific interrupts for the I2C module. +* - i2c_clearInterruptFlag: Clears specific interrupt flags for the I2C module. +* - i2c_rxAckWait: Waits for ACK signal from Slave. +* - TX_AND_CHECK: Transmits a single byte over the I2C bus and waits for an ACK response. +* - i2c_writeData_b_ack: Write data with an 8-bit register address using I2C and checks rx ack for each transaction. +* - i2c_writeData_w_ack: Write data with an 16-bit register address using I2C and checks rx ack for each transaction. +* - i2c_readData_b_ack: This function is to read data with an 8-bit register address over I2C and checks rx ack. +* - i2c_readData_w_ack: This function is to read data with an 16-bit register address over I2C and checks rx ack. +******************************************************************************/ + +#pragma once +#include "type.h" +#include "io.h" +#define I2C_TX_DATA 0x00 +#define I2C_TX_ACK 0x04 +#define I2C_RX_DATA 0x08 +#define I2C_RX_ACK 0x0C +#define I2C_INTERRUPT_ENABLE 0x20 +#define I2C_INTERRUPT_FLAG 0x24 +#define I2C_SAMPLING_CLOCK_DIVIDER 0x28 +#define I2C_TIMEOUT 0x2C +#define I2C_TSUDAT 0x30 +#define I2C_MASTER_STATUS 0x40 +#define I2C_SLAVE_STATUS 0x44 +#define I2C_SLAVE_OVERRIDE 0x48 +#define I2C_TLOW 0x50 +#define I2C_THIGH 0x54 +#define I2C_TBUF 0x58 +#define I2C_FILTERING_HIT 0x80 +#define I2C_FILTERING_STATUS 0x84 +#define I2C_FILTERING_CONFIG 0x88 +#define I2C_MODE_CPOL (1 << 0) +#define I2C_MODE_CPHA (1 << 1) +#define I2C_TX_VALUE (0xFF) +#define I2C_TX_VALID (1 << 8) +#define I2C_TX_ENABLE (1 << 9) +#define I2C_TX_REPEAT (1 << 10) +#define I2C_TX_DISABLE_ON_DATA_CONFLICT (1 << 11) +#define I2C_RX_VALUE (0xFF) +#define I2C_RX_VALID (1 << 8) +#define I2C_RX_LISTEN (1 << 9) +#define I2C_MASTER_BUSY (1 << 0) +#define I2C_MASTER_START (1 << 4) +#define I2C_MASTER_STOP (1 << 5) +#define I2C_MASTER_DROP (1 << 6) +#define I2C_MASTER_RECOVER (1 << 7) +#define I2C_MASTER_START_DROPPED (1 << 9) +#define I2C_MASTER_STOP_DROPPED (1 << 10) +#define I2C_MASTER_RECOVER_DROPPED (1 << 11) +#define I2C_SLAVE_STATUS_IN_FRAME (1 << 0) +#define I2C_SLAVE_STATUS_SDA (1 << 1) +#define I2C_SLAVE_STATUS_SCL (1 << 2) +#define I2C_SLAVE_OVERRIDE_SDA (1 << 1) +#define I2C_SLAVE_OVERRIDE_SCL (1 << 2) +#define I2C_FILTER_7_BITS (0) +#define I2C_FILTER_10_BITS (1 << 14) +#define I2C_FILTER_ENABLE (1 << 15) +#define I2C_INTERRUPT_TX_DATA (1 << 2) +#define I2C_INTERRUPT_TX_ACK (1 << 3) +#define I2C_INTERRUPT_DROP (1 << 7) +#define I2C_INTERRUPT_CLOCK_GEN_EXIT (1 << 15) +#define I2C_INTERRUPT_CLOCK_GEN_ENTER (1 << 16) +#define I2C_INTERRUPT_CLOCK_GEN_BUSY (1 << 16) //Renamed into I2C_INTERRUPT_CLOCK_GEN_ENTER +#define I2C_INTERRUPT_FILTER (1 << 17) +#define I2C_READ 0x01 +#define I2C_WRITE 0x00 + + +/****************************************************************************** +* +* Backward compatibility +* +* Please use i2c_get* functions for new designs +* +******************************************************************************/ + +#define gpio_getInterruptFlag(reg) i2c_getInterruptFlag(reg) +#define gpio_getMasterStatus(reg) i2c_getMasterStatus(reg) +#define gpio_getFilteringHit(reg) i2c_getFilteringHit(reg) +#define gpio_getFilteringStatus(reg) i2c_getFilteringStatus(reg) +//end + readReg_u32 (i2c_getInterruptFlag , I2C_INTERRUPT_FLAG) + readReg_u32 (i2c_getMasterStatus , I2C_MASTER_STATUS) + readReg_u32 (i2c_getFilteringHit , I2C_FILTERING_HIT) + readReg_u32 (i2c_getFilteringStatus , I2C_FILTERING_STATUS) + readReg_u32 (i2c_getSlaveStatus , I2C_SLAVE_STATUS) + writeReg_u32 (i2c_getSlaveOverride , I2C_SLAVE_OVERRIDE) + + +/****************************************************************************** +* +* This is my try struct. +* +* This structure represents the configuration settings for an I2C interface. +* It contains various parameters related to the timing and operation of the I2C bus. +* +******************************************************************************/ + typedef struct { + //Master/Slave mode + //Number of cycle - 1 between each SDA/SCL sample + u32 samplingClockDivider; + //Number of cycle - 1 after which an inactive frame is considered dropped. + u32 timeout; + //Number of cycle - 1 SCL should be keept low (clock stretching) after having feed the data to + //the SDA to ensure a correct propagation to other devices + u32 tsuDat; + //Master mode + //SCL low (cycle count -1) + u32 tLow; + //SCL high (cycle count -1) + u32 tHigh; + //Minimum time between the Stop/Drop -> Start transition + u32 tBuf; + } I2c_Config; + +/****************************************************************************** +* +* This function is used to apply the provided configuration settings to the specified I2C interface. +* +* @param reg The base address of the I2C registers. +* @param config Pointer to the I2C configuration structure containing the settings to be applied. +* +* @return None. +* +******************************************************************************/ + static void i2c_applyConfig(u32 reg, I2c_Config *config){ + write_u32(config->samplingClockDivider, reg + I2C_SAMPLING_CLOCK_DIVIDER); + write_u32(config->timeout, reg + I2C_TIMEOUT); + write_u32(config->tsuDat, reg + I2C_TSUDAT); + write_u32(config->tLow, reg + I2C_TLOW); + write_u32(config->tHigh, reg + I2C_THIGH); + write_u32(config->tBuf, reg + I2C_TBUF); + } + +/****************************************************************************** +* +* This function enables the specified filter for the I2C interface with the provided configuration. +* +* @param reg The base address of the I2C registers. +* @param filterId The identifier of the filter to be enabled. +* @param config The configuration to be applied to the filter. +* +* @return None. +* +******************************************************************************/ + + static inline void i2c_filterEnable(u32 reg, u32 filterId, u32 config){ + write_u32(config, reg + I2C_FILTERING_CONFIG + 4*filterId); + } + +/****************************************************************************** +* +* This function initiates the start condition for I2C master mode and sets the dropped status if necessary. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_masterStart(u32 reg){ + write_u32(I2C_MASTER_START | I2C_MASTER_START_DROPPED, reg + I2C_MASTER_STATUS); + } + +/****************************************************************************** +* +* This function initiates the restart condition for I2C master mode. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_masterRestart(u32 reg){ + i2c_masterStart(reg); + } + +/****************************************************************************** +* +* This function initiates the recovery sequence for I2C master mode. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_masterRecover(u32 reg){ + write_u32(I2C_MASTER_RECOVER | I2C_MASTER_RECOVER_DROPPED, reg + I2C_MASTER_STATUS); + } + +/****************************************************************************** +* +* This function checks whether the I2C master is busy. +* +* @param reg The base address of the I2C registers. +* +* @return Returns 1 if the I2C master is busy, and 0 otherwise. +* +******************************************************************************/ + static int i2c_masterBusy(u32 reg){ + return (read_u32(reg + I2C_MASTER_STATUS) & I2C_MASTER_BUSY) != 0; + } + +/****************************************************************************** +* +* This function retrieves the status of the I2C master. +* +* @param reg The base address of the I2C registers. +* +* @return Returns the status of the I2C master. +* +******************************************************************************/ + static int i2c_masterStatus(u32 reg){ + return (read_u32(reg + I2C_MASTER_STATUS)); + } + +/****************************************************************************** +* +* This function initiates a start condition on the I2C bus and blocks until the start condition is completed. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_masterStartBlocking(u32 reg){ + i2c_masterStart(reg); + while(i2c_getMasterStatus(reg) & I2C_MASTER_START); + } + +/****************************************************************************** +* +* This function initiates a restart condition on the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_masterRestartBlocking(u32 reg){ + i2c_masterStartBlocking(reg); + } + +/****************************************************************************** +* +* This function initiates a stop condition on the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_masterStop(u32 reg){ + write_u32(I2C_MASTER_STOP | I2C_MASTER_STOP_DROPPED, reg + I2C_MASTER_STATUS); + } + +/****************************************************************************** +* +* This function initiates a recovery sequence on the I2C bus and blocks until the recovery is completed. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_masterRecoverBlocking(u32 reg){ + for(int i = 0;i < 3;i++){ + i2c_masterRecover(reg); + while(i2c_getMasterStatus(reg) & I2C_MASTER_RECOVER); + if((i2c_getMasterStatus(reg) & I2C_MASTER_RECOVER_DROPPED) == 0){ + break; + } + } + } + +/****************************************************************************** +* +* This function waits until the I2C master bus is no longer busy, indicating that the stop condition has been completed. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_masterStopWait(u32 reg){ + while(i2c_masterBusy(reg)); + } + +/****************************************************************************** +* +* This function initiates a drop operation on the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_masterDrop(u32 reg){ + write_u32(I2C_MASTER_DROP, reg + I2C_MASTER_STATUS); + } + +/****************************************************************************** +* +* This function initiates a stop sequence on the I2C bus and waits until the bus is no longer busy. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_masterStopBlocking(u32 reg){ + i2c_masterStop(reg); + i2c_masterStopWait(reg); + } + +/****************************************************************************** +* +* This function configures the I2C controller to listen for ACK signals on the receiver (RX) line. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_listenAck(u32 reg){ + write_u32(I2C_RX_LISTEN ,reg + I2C_RX_ACK); + } + +/****************************************************************************** +* +* This function transmits a byte of data over the I2C bus. +* +* @param reg The base address of the I2C registers. +* @param byte The byte of data to transmit. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_txByte(u32 reg,u8 byte){ + write_u32(byte | I2C_TX_VALID | I2C_TX_ENABLE | I2C_TX_DISABLE_ON_DATA_CONFLICT, reg + I2C_TX_DATA); + } + +/****************************************************************************** +* +* This function transmits an ACK signal over the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_txAck(u32 reg){ + write_u32(I2C_TX_VALID | I2C_TX_ENABLE, reg + I2C_TX_ACK); + } + +/****************************************************************************** +* +* This function transmits an NACK signal over the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_txNack(u32 reg){ + write_u32(1 | I2C_TX_VALID | I2C_TX_ENABLE, reg + I2C_TX_ACK); + } + +/****************************************************************************** +* +* This function waits until the transmission of an ACK signal is complete over the I2C bus. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_txAckWait(u32 reg){ + while(read_u32(reg + I2C_TX_ACK) & I2C_TX_VALID); + } + +/****************************************************************************** +* +* This function waits for ACK signal from Slave. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_rxAckWait(u32 reg){ + while ((read_u32(reg + I2C_RX_ACK) & I2C_RX_VALUE) != 0); + } +/****************************************************************************** +* +* This function sends an ACK signal over the I2C bus and waits until the transmission is complete. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_txAckBlocking(u32 reg){ + i2c_txAck(reg); + i2c_txAckWait(reg); + + + } + +/****************************************************************************** +* +* This function sends an NACK signal over the I2C bus and waits until the transmission is complete. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_txNackBlocking(u32 reg){ + i2c_txNack(reg); + i2c_txAckWait(reg); + } + +/****************************************************************************** +* +* This function reads data from the I2C receive data register. +* +* @param reg The base address of the I2C registers. +* +* @return The received data from the I2C bus. +* +******************************************************************************/ + + static u32 i2c_rxData(u32 reg){ + return read_u32(reg + I2C_RX_DATA) & I2C_RX_VALUE; + } + +/****************************************************************************** +* +* This function checks if the received NACK signal is detected. +* +* @param reg The base address of the I2C registers. +* +* @return 1 if NACK signal is detected, otherwise 0. +* +******************************************************************************/ + static int i2c_rxNack(u32 reg){ + return (read_u32(reg + I2C_RX_ACK) & I2C_RX_VALUE) != 0; + } + +/****************************************************************************** +* +* This function checks if the received ACK signal is detected. +* +* @param reg The base address of the I2C registers. +* +* @return 1 if ACK signal is detected, otherwise 0. +* +******************************************************************************/ + static int i2c_rxAck(u32 reg){ + return (read_u32(reg + I2C_RX_ACK) & I2C_RX_VALUE) == 0; + } + +/****************************************************************************** +* +* This function sends a byte over the I2C bus with repeat mode enabled. +* +* @param reg The base address of the I2C registers. +* @param byte The byte to be sent. +* +* @return None. +* +******************************************************************************/ + static void i2c_txByteRepeat(u32 reg,u8 byte){ + write_u32(byte | I2C_TX_VALID | I2C_TX_ENABLE | I2C_TX_DISABLE_ON_DATA_CONFLICT | I2C_TX_REPEAT, reg + I2C_TX_DATA); + } + +/****************************************************************************** +* +* This function sends a NACK signal over the I2C bus with repeat mode enabled. +* +* @param reg The base address of the I2C registers. +* +* @return None. +* +******************************************************************************/ + static void i2c_txNackRepeat(u32 reg){ + write_u32(1 | I2C_TX_VALID | I2C_TX_ENABLE | I2C_TX_REPEAT, reg + I2C_TX_ACK); + } + +/****************************************************************************** +* +* This function sets the filter configuration for a specific filter ID. +* +* @param reg The base address of the I2C registers. +* @param filterId The ID of the filter. +* @param value The value to be set for the filter configuration. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_setFilterConfig(u32 reg, u32 filterId, u32 value){ + write_u32(value, reg + I2C_FILTERING_CONFIG + 4*filterId); + } + +/****************************************************************************** +* +* This function enables specific interrupts for the I2C module. +* +* @param reg The base address of the I2C registers. +* @param value The value representing the interrupts to be enabled. +* +* @return None. +* +******************************************************************************/ + static void i2c_enableInterrupt(u32 reg, u32 value){ + write_u32(value | read_u32(reg + I2C_INTERRUPT_ENABLE), reg + I2C_INTERRUPT_ENABLE); + } + +/****************************************************************************** +* +* This function disables specific interrupts for the I2C module. +* +* @param reg The base address of the I2C registers. +* @param value The value representing the interrupts to be enabled. +* +* @return None. +* +******************************************************************************/ + static void i2c_disableInterrupt(u32 reg, u32 value){ + write_u32(~value & read_u32(reg + I2C_INTERRUPT_ENABLE), reg + I2C_INTERRUPT_ENABLE); + } + +/****************************************************************************** +* +* This function clears specific interrupt flags for the I2C module. +* +* @param reg The base address of the I2C registers. +* @param value The value representing the interrupt flags to be cleared. +* +* @return None. +* +******************************************************************************/ + static inline void i2c_clearInterruptFlag(u32 reg, u32 value){ + write_u32(value, reg + I2C_INTERRUPT_FLAG); + } + + +/******************************************************************************* +* +* This macro transmits a single byte over the I2C bus and waits for an ACK response. +* +* @param reg: I2C peripheral register base address. +* @param byte: The 8-bit data byte to be transmitted. +* +* This macro performs a single byte transmission as part of an I2C write transaction. +* First, it sends the specified byte using the `i2c_txByte()` function, followed by +* `i2c_txNackBlocking()` to complete the 9-bit transfer cycle (8 data bits + 1 ACK/NACK). +* It then calls `i2c_rxAckWait()` to wait until the ACK status is returned by the slave. +* This ensures that the slave has successfully received and acknowledged the byte. +* The macro is wrapped in a `do { ... } while(0)` construct to allow safe usage +* within conditional blocks or inline statements. +* +*******************************************************************************/ + #define TX_AND_CHECK(reg, byte) \ + do { \ + i2c_txByte(reg, (byte)); \ + i2c_txNackBlocking(reg); \ + i2c_rxAckWait(reg); \ + } while(0) + +/******************************************************************************* +* +* This function is to write data with an 8-bit register address using I2C and checks rx ack for each transaction. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 8-bit register address. +* @param data: Pointer to the data buffer containing bytes to write. +* @param length: Number of bytes to write from the buffer. +* +* This function performs a write operation over the I2C bus using an 8-bit +* register address. It begins by sending the start condition, followed by +* the slave address with the write bit. Next, it transmits the target register +* address within the slave. Then, it iterates through the provided data buffer, +* transmitting each byte individually. After sending each byte, the function +* waits for an acknowledgment (ACK) from the slave device to confirm reception, +* using the `TX_AND_CHECK()` macro. +* +* If at any point the slave does not acknowledge (ACK), the macro ensures that +* the function will block until an ACK is received. Finally, a stop condition +* is sent to complete the transaction. +* +*******************************************************************************/ + static void i2c_writeData_b_ack(u32 reg, u8 slaveAddr, u8 regAddr, u8 *data, u32 length){ + i2c_masterStartBlocking(reg); // Start condition + TX_AND_CHECK(reg, (slaveAddr | I2C_WRITE)); // Send slave address (write mode) + TX_AND_CHECK(reg, regAddr); + for(u32 i = 0; i < length; i++){ + TX_AND_CHECK(reg, data[i]); // Send each byte + } + i2c_masterStopBlocking(reg); // Stop condition + } +/******************************************************************************* +* +* This function is to write data with an 16-bit register address using I2C and checks rx ack for each transaction. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 16-bit register address. +* @param data: Pointer to the data buffer containing bytes to write. +* @param length: Number of bytes to write from the buffer. +* +* This function performs a write operation over the I2C bus using an 8-bit +* register address. It begins by sending the start condition, followed by +* the slave address with the write bit. Next, it transmits the target register +* address within the slave. Then, it iterates through the provided data buffer, +* transmitting each byte individually. After sending each byte, the function +* waits for an acknowledgment (ACK) from the slave device to confirm reception, +* using the `TX_AND_CHECK()` macro. +* +* If at any point the slave does not acknowledge (ACK), the macro ensures that +* the function will block until an ACK is received. Finally, a stop condition +* is sent to complete the transaction. +* +*******************************************************************************/ + static void i2c_writeData_w_ack(u32 reg, u8 slaveAddr, u16 regAddr, u8 *data, u32 length){ + i2c_masterStartBlocking(reg); // Start condition + TX_AND_CHECK(reg, (slaveAddr | I2C_WRITE)); // Send slave address (write mode) + TX_AND_CHECK(reg, (regAddr >> 8) & 0xFF); // MSB of register address + TX_AND_CHECK(reg, regAddr & 0xFF); // LSB of register address + for(u32 i = 0; i < length; i++) { + TX_AND_CHECK(reg, data[i]); // Send each byte + } + i2c_masterStopBlocking(reg); // Stop condition + } + +/******************************************************************************* +* +* This function is to read data with an 8-bit register address over I2C and checks rx ack. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 8-bit register address to read from. +* @param data: Pointer to the data buffer to store the read data. +* @param length: Number of bytes to read from the slave. +* +* This function performs a read operation over the I2C bus using an 8-bit +* register address. It starts by sending the start condition, followed by +* the slave address with the write bit and the register address to access. +* It then issues a repeated start condition to switch to read mode, followed +* by the slave address with the read bit. +* +* If more than one byte is requested, it repeatedly sends 0xFF to generate +* clock pulses and reads each byte, sending an ACK to the slave to continue +* transmission. For the final byte, it sends a NACK to indicate the end of +* the read, and then issues a stop condition. +* +*******************************************************************************/ + static void i2c_readData_b_ack(u32 reg, u8 slaveAddr, u8 regAddr, u8 *data , u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + TX_AND_CHECK(reg, slaveAddr | I2C_WRITE); // write device address byte with write bit + TX_AND_CHECK(reg, (regAddr & 0xFF)); // write second byte address + i2c_masterRestartBlocking(reg); // send restart sequence and wait for it to complete + TX_AND_CHECK(reg, slaveAddr|I2C_READ); // write device address byt ewith read bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txAckBlocking(reg); // send ack bit to ask slave to continue send the next byte + data[i] = i2c_rxData(reg); // read the data from rx data register and place it into data array + } + } + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txNackBlocking(reg); // send nack bit + data[length-1] = i2c_rxData(reg); // read the data from rx data register and place it into last data array + i2c_masterStopBlocking(reg); // send stop sequence + } + +/******************************************************************************* +* +* This function is to read data with an 16-bit register address over I2C and checks rx ack. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 8-bit register address to read from. +* @param data: Pointer to the data buffer to store the read data. +* @param length: Number of bytes to read from the slave. +* +* This function performs a read operation over the I2C bus using an 8-bit +* register address. It starts by sending the start condition, followed by +* the slave address with the write bit and the register address to access. +* It then issues a repeated start condition to switch to read mode, followed +* by the slave address with the read bit. +* +* If more than one byte is requested, it repeatedly sends 0xFF to generate +* clock pulses and reads each byte, sending an ACK to the slave to continue +* transmission. For the final byte, it sends a NACK to indicate the end of +* the read, and then issues a stop condition. +* +*******************************************************************************/ + static void i2c_readData_w_ack(u32 reg, u8 slaveAddr, u16 regAddr, u8 *data , u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + TX_AND_CHECK(reg, slaveAddr|I2C_WRITE); // write device address byte with write bit + TX_AND_CHECK(reg, ((regAddr >>8) & 0xFF)); // write first byte address + TX_AND_CHECK(reg, (regAddr & 0xFF)); // write second byte address + i2c_masterRestartBlocking(reg); // send restart sequence and wait for it to complete + TX_AND_CHECK(reg, slaveAddr|I2C_READ); // write device address byt ewith read bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txAckBlocking(reg); // send ack bit to ask slave to continue send the next byte + data[i] = i2c_rxData(reg); // read the data from rx data register and place it into data array + } + } + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txNackBlocking(reg); // send nack bit + data[length-1] = i2c_rxData(reg); // read the data from rx data register and place it into last data array + i2c_masterStopBlocking(reg); // send stop sequence + } + + + + +/******************************************************************************* +* +* The following functions perform I2C write/read operations without checking for Rx acknowledgment. +* +*******************************************************************************/ + +/******************************************************************************* +* +* The function is to write data with 8-bit register address. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 8-bit register address. +* @param data: Pointer to the data buffer to be written. +* @param length: Length of the data buffer. +* +* This function performs a write operation over I2C bus with an 8-bit register address. +* It starts by sending the start sequence followed by the device address with the write bit. +* Then, it sends the register address byte to access. If the length of the data buffer +* is greater than one, it iterates through the buffer, sending each byte of data to the slave. +* Finally, it sends the stop sequence to complete the transaction. +* +*******************************************************************************/ + static void i2c_writeData_b(u32 reg, u8 slaveAddr, u8 regAddr, u8 *data, u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + i2c_txByte(reg, slaveAddr | I2C_WRITE); // write device address byte with write bit + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, (regAddr & 0xFF)); // write a byte of register address to access + i2c_txNackBlocking(reg); // send nack bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, data[i]); // send 8-bit data to slave + i2c_txNackBlocking(reg); // send nack bit + } + } + i2c_txByte(reg, data[length-1]); // send last 8-bit data to slave + i2c_txNackBlocking(reg); // send nack bit + i2c_masterStopBlocking(reg); // send stop sequence + } + + +/******************************************************************************* +* +* The function is to write data with 16-bit register address. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 16-bit register address. +* @param data: Pointer to the data buffer to be written. +* @param length: Length of the data buffer. +* +* This function performs a write operation over I2C bus with an 16-bit register address. +* It starts by sending the start sequence followed by the device address with the write bit. +* Then, it sends the register address byte to access. If the length of the data buffer +* is greater than one, it iterates through the buffer, sending each byte of data to the slave. +* Finally, it sends the stop sequence to complete the transaction. +* +*******************************************************************************/ + static void i2c_writeData_w(u32 reg, u8 slaveAddr, u16 regAddr, u8 *data, u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + i2c_txByte(reg, slaveAddr | I2C_WRITE); // write device address byte with write bit + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, ((regAddr >>8) & 0xFF)); // send MSB of register address to access + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, (regAddr & 0xFF)); // send LSB of register address to access + i2c_txNackBlocking(reg); // send nack bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, data[i]); // send 8-bit data to slave + i2c_txNackBlocking(reg); // send nack bit + } + } + i2c_txByte(reg, data[length-1]); // send last 8-bit data to slave + i2c_txNackBlocking(reg); // send nack bit + i2c_masterStopBlocking(reg); // send stop sequence + } + +/******************************************************************************* +* +* This function is to read data with 8-bit register address. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 8-bit register address. +* @param data: Pointer to the data buffer to store read data. +* @param length: Length of the data buffer. +* +* This function performs a read operation over I2C bus with an 8-bit register address. +* It starts by sending the start sequence followed by the device address with the write bit. +* Then, it sends the register address byte to access. After that, it sends the restart sequence +* to switch from write mode to read mode. Next, it sends the device address byte with the read bit. +* If the length of the data buffer is greater than one, it iterates through the buffer, sending +* 0xFF to generate clock pulses while receiving data bytes from the slave. Finally, it sends the +* stop sequence to complete the transaction. +* +*******************************************************************************/ + static void i2c_readData_b(u32 reg, u8 slaveAddr, u8 regAddr, u8 *data , u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + i2c_txByte(reg, slaveAddr|I2C_WRITE); // write device address byte with write bit + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, (regAddr & 0xFF)); // write second byte address + i2c_txNackBlocking(reg); // send nack bit + i2c_masterRestartBlocking(reg); // send restart sequence and wait for it to complete + i2c_txByte(reg, slaveAddr|I2C_READ); // write device address byt ewith read bit + i2c_txNackBlocking(reg); // send nack bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txAckBlocking(reg); // send ack bit to ask slave to continue send the next byte + data[i] = i2c_rxData(reg); // read the data from rx data register and place it into data array + } + } + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txNackBlocking(reg); // send nack bit + data[length-1] = i2c_rxData(reg); // read the data from rx data register and place it into last data array + i2c_masterStopBlocking(reg); // send stop sequence + } + +/******************************************************************************* +* +* This function is to read data with 16-bit register address. +* +* @param reg: I2C peripheral register base address. +* @param slaveAddr: Address of the slave device. +* @param regAddr: 16-bit register address. +* @param data: Pointer to the data buffer to store read data. +* @param length: Length of the data buffer. +* +* This function performs a read operation over I2C bus with an 16-bit register address. +* It starts by sending the start sequence followed by the device address with the write bit. +* Then, it sends the register address byte to access. After that, it sends the restart sequence +* to switch from write mode to read mode. Next, it sends the device address byte with the read bit. +* If the length of the data buffer is greater than one, it iterates through the buffer, sending +* 0xFF to generate clock pulses while receiving data bytes from the slave. Finally, it sends the +* stop sequence to complete the transaction. +* +*******************************************************************************/ + static void i2c_readData_w(u32 reg, u8 slaveAddr, u16 regAddr, u8 *data , u32 length){ + i2c_masterStartBlocking(reg); // Send start sequence + i2c_txByte(reg, slaveAddr|I2C_WRITE); // write device address byte with write bit + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, ((regAddr >>8) & 0xFF)); // write first byte address + i2c_txNackBlocking(reg); // send nack bit + i2c_txByte(reg, (regAddr & 0xFF)); // write second byte address + i2c_txNackBlocking(reg); // send nack bit + i2c_masterRestartBlocking(reg); // send restart sequence and wait for it to complete + i2c_txByte(reg, slaveAddr|I2C_READ); // write device address byt ewith read bit + i2c_txNackBlocking(reg); // send nack bit + if(length > 1){ + for(int i = 0; i < length - 1; i++){ + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txAckBlocking(reg); // send ack bit to ask slave to continue send the next byte + data[i] = i2c_rxData(reg); // read the data from rx data register and place it into data array + } + } + i2c_txByte(reg, 0xFF); // send 0xFF (Release SDA line) to the slave while generate 8-bit SCL pulses + i2c_txNackBlocking(reg); // send nack bit + data[length-1] = i2c_rxData(reg); // read the data from rx data register and place it into last data array + i2c_masterStopBlocking(reg); // send stop sequence + } + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/io.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/io.h new file mode 100644 index 0000000..d52d1c3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/io.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/***************************************************************************** +* +* @file io.h +* +* @brief Header file contains basic read and write function with different data types. +* +* Functions: +* - read_u32: Reads a 32-bit unsigned integer value from a memory address. +* - read_u16: Reads a 16-bit unsigned integer value from a memory address. +* - read_u8 : Reads a 8-bit unsigned integer value from a memory address. +* - write_u32: Writes a 32-bit unsigned integer value to a memory address. +* - write_u16: Writes a 16-bit unsigned integer value to a memory address. +* - write_u8 : Writes a 8-bit unsigned integer value to a memory address. +* - writeReg_u32: Defines a function for writing a 32-bit unsigned integer value +* to a register at a specific offset from a base address. +* - readReg_u32: Defines a function for reading a 32-bit unsigned integer value +* from a register at a specific offset from a base address. +* +******************************************************************************/ + +#pragma once + +#include "type.h" +#include "soc.h" + + + static inline u32 read_u32(u32 address){ + return *((volatile u32*) address); + } + + static inline void write_u32(u32 data, u32 address){ + *((volatile u32*) address) = data; + } + + static inline u16 read_u16(u32 address){ + return *((volatile u16*) address); + } + + static inline void write_u16(u16 data, u32 address){ + *((volatile u16*) address) = data; + } + + static inline u8 read_u8(u32 address){ + return *((volatile u8*) address); + } + + static inline void write_u8(u8 data, u32 address){ + *((volatile u8*) address) = data; + } + + static inline void write_u32_ad(u32 address, u32 data){ + *((volatile u32*) address) = data; + } + + #define writeReg_u32(name, offset) \ + static inline void name(u32 reg, u32 value){ \ + write_u32(value, reg + offset); \ + } \ + + #define readReg_u32(name, offset) \ + static inline u32 name(u32 reg){ \ + return read_u32(reg + offset); \ + } \ + + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/mmc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/mmc.h new file mode 100644 index 0000000..88fb5ec --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/mmc.h @@ -0,0 +1,255 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* @file mmc.h +* +* @brief Header file containing MMC (MultiMediaCard) related declarations and structures. +* +******************************************************************************/ +#pragma once +#include + +#define BIT(X) 1<> 16; + } + +/******************************************************************************* + * + * @brief This function writes data to the SPI data register after checking the + * availability of command buffer space. + * + * @param reg The base address of the SPI register + * + * @param data The data to be written + * + ******************************************************************************/ + static void spi_write(u32 reg, u8 data){ + while(spi_cmdAvailability(reg) == 0); + write_u32(data | SPI_CMD_WRITE, reg + SPI_DATA); + } + +/******************************************************************************* + * + * @brief This function reads data from the SPI data register after checking the + * availability of command buffer space and the occupancy of response buffer space. + * + * @param reg The base address of the SPI register + * + * @return The data read from the SPI data register + * + ******************************************************************************/ + static u8 spi_read(u32 reg){ + while(spi_cmdAvailability(reg) == 0); + write_u32(SPI_CMD_READ, reg + SPI_DATA); + while(spi_rspOccupancy(reg) == 0); + return read_u32(reg + SPI_DATA); + } + +/******************************************************************************* + * + * @brief This function writes data to and reads data from the SPI data register. + * + * @param reg The base address of the SPI register + * @param data The data to be written + * + * @return The data read from the SPI data register + * + ******************************************************************************/ + static u8 spi_writeRead(u32 reg, u8 data){ + while(spi_cmdAvailability(reg) == 0); + write_u32(data | SPI_CMD_READ | SPI_CMD_WRITE, reg + SPI_DATA); + while(spi_rspOccupancy(reg) == 0); + return read_u32(reg + SPI_DATA); + } + +/******************************************************************************* + * + * @brief This function writes a 32-bit data value to the SPI write register + * after checking the availability of command buffer space. + * + * @param reg The base address of the SPI register + * @param data The 32-bit data value to be written + * + ******************************************************************************/ + static void spi_write32(u32 reg, u32 data){ + while(spi_cmdAvailability(reg) == 0); + write_u32(data, reg + SPI_WRITE_LARGE); + } + +/******************************************************************************* + * + * @brief This function writes a 32-bit data value to the SPI write register + * and reads a 32-bit value from the SPI read register. + * + * @param reg The base address of the SPI register + * @param data The 32-bit data value to be written + * + * @return The 32-bit value read from the SPI read register + * + ******************************************************************************/ + static u32 spi_writeRead32(u32 reg, u32 data){ + while(spi_cmdAvailability(reg) == 0); + write_u32(data, reg + SPI_READ_WRITE_LARGE); + while(spi_rspOccupancy(reg) == 0); + return read_u32(reg + SPI_READ_LARGE); + } + +/******************************************************************************* + * + * @brief This function reads a 32-bit data value from the SPI read register. + * + * @param reg The base address of the SPI register + * + * @return The 32-bit data value read from the SPI read register + * + ******************************************************************************/ + static u32 spi_read32(u32 reg){ + while(spi_cmdAvailability(reg) == 0); + write_u32(SPI_CMD_READ, reg + SPI_DATA); + while(spi_rspOccupancy(reg) == 0); + return read_u32(reg + SPI_READ_LARGE); + } + +/******************************************************************************* + * + * @brief This function selects a slave device on the SPI bus . + * + * @param reg The base address of the SPI register + * @param slaveId The ID of the slave device to select + * + ******************************************************************************/ + static void spi_select(u32 reg, u32 slaveId){ + while(spi_cmdAvailability(reg) == 0); + write_u32(slaveId | 0x80 | SPI_CMD_SS, reg + SPI_DATA); + } + +/******************************************************************************* + * + * @brief This function deselects a slave device on the SPI bus. + * + * @param reg The base address of the SPI register + * @param slaveId The ID of the slave device to deselect + * + ******************************************************************************/ + static void spi_diselect(u32 reg, u32 slaveId){ + while(spi_cmdAvailability(reg) == 0); + write_u32(slaveId | 0x00 | SPI_CMD_SS, reg + SPI_DATA); + } + +/******************************************************************************* + * + * @brief This function applies SPI configuration settings to the SPI configuration register, + * clock divider register, slave setup register, hold register, and disable register. + * + * @param reg The base address of the SPI register + * @param config Pointer to a Spi_Config structure containing the configuration settings + * + ******************************************************************************/ + static void spi_applyConfig(u32 reg, Spi_Config *config){ + write_u32((config->cpol << 0) | (config->cpha << 1) | (config->mode << 4), reg + SPI_CONFIG); + write_u32(config->clkDivider, reg + SPI_CLK_DIVIDER); + write_u32(config->ssSetup, reg + SPI_SS_SETUP); + write_u32(config->ssHold, reg + SPI_SS_HOLD); + write_u32(config->ssDisable, reg + SPI_SS_DISABLE); + } + +/******************************************************************************* +* +* @brief This function wait for SPI Transfer to complete. + * + * @param reg SPI base address +* +******************************************************************************/ + static void spi_waitXferBusy(u32 reg){ + u16 cmdFifo_depth; + +#ifdef SYSTEM_SPI_0_IO_CTRL + if(reg == SYSTEM_SPI_0_IO_CTRL) cmdFifo_depth = SYSTEM_SPI_0_IO_PARAMETER_CMD_FIFO_DEPTH; +#endif + +#ifdef SYSTEM_SPI_1_IO_CTRL + if(reg == SYSTEM_SPI_1_IO_CTRL) cmdFifo_depth = SYSTEM_SPI_1_IO_PARAMETER_CMD_FIFO_DEPTH; +#endif + +#ifdef SYSTEM_SPI_2_IO_CTRL + if(reg == SYSTEM_SPI_2_IO_CTRL) cmdFifo_depth = SYSTEM_SPI_2_IO_PARAMETER_CMD_FIFO_DEPTH; +#endif + + bsp_uDelay(1); + while(spi_cmdAvailability(reg) != cmdFifo_depth); + } + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/spiFlash.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/spiFlash.h new file mode 100644 index 0000000..7c1deed --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/spiFlash.h @@ -0,0 +1,912 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* + * + * @file spiFlash.h + * + * @brief Header file containing SPI Flash function declarations and configuration structures + * + * Functions: + * - spiFlash_select_withGpioCs: Set SPI Flash device Chip Select with GPIO port. + * - spiFlash_diselect_withGpioCs: Clear SPI Flash device Chip Select with GPIO port. + * - spiFlash_select: Set SPI Flash device Chip Select. + * - spiFlash_diselect: Clear SPI Flash device Chip Select. + * - spiFlash_init_: Initialize SPI port with default settings. + * - spiFlash_init_mode_: Initialize SPI port with default settings with mode selection. + * - spiFlash_init_withGpioCs: Initialize SPI port with GPIO Chip Select. + * - spiFlash_wake_: Wake up the Spi Flash. + * - spiWriteStatusRegister: Write Status Register. + * - spiWriteEnable: Set Write Enable Latch. + * - spiReadStatusRegister: Read Status Register. + * - spiFlash_software_reset: Send software reset to the SPI Flash. + * - spiFlash_manufacturer_id_: Retrieve SPI Flash Manufacturer ID + * - spiFlash_exit4ByteAddr_: Exit 4-byte addressing based on Manufacturer ID + * - spiFlash_exit4ByteAddr: Exit 4-byte addressing by reading Manufacturer ID beforehand + * - spiFlash_exit4ByteAddr_withGpioCs: Exit 4-byte addressing by reading Manufacturer ID beforehand with gpio chip select + * + ******************************************************************************/ +#pragma once + +/* Includes ------------------------------------------------------------------*/ +#include "type.h" +#include "spi.h" +#include "gpio.h" +#include "io.h" + +/* Exported Common instruction for NOR Flash in efx dev kit---------------*/ +#define READ_DATA 0x03 // Read Data from NOR Flash Instruction +#define READ_DEVICE_ID 0xAB // Read Device ID Instruction +#define READ_MANUFACTURER 0x9F // Read Manufacturer ID Instruction +#define READ_STATUS_REG 0x05 // Read status register Instuction +#define WRITE_STATUS_REG 0x01 // Write status register Instuction +#define PAGE_PROGRAM_OP 0x02 // Page Program Operation +#define WRITE_ENABLE 0x06 // WEL Instruction +#define SECTOR_ERASE 0x20 // Sector Erase Instruction +#define GLOBAL_LOCK 0x7E // Global Lock Instruction +#define GLOBAL_UNLOCK 0x98 // Global Unlock Instruction + + +/* Public Vendor-Specific Manufacture ID----------------------------------*/ +#define MACRONIX_ID 0xC2 // Ti180J484 +#define WINDBOND_ID 0xEF // Ti60F225, T120F576 +#define GIGADEVICE_ID 0xC8 // Ti375N1156 +#define ISSI_ID 0x9D // Ti375C529 + +/* Macronix Vendor-Specific Register----------------------------------*/ +#define MX25_QUAD_ENABLE_BIT 0x40 +#define MX25_WRITE_ENABLE_LATCH_BIT 0x02 + +/* -------------------------------------------------------------------------- */ +/* Internal Inline Functions (Low-level register access, no CS handling) */ +/* -------------------------------------------------------------------------- */ +static u8 spiFlash_read_id_ (u32 spi); +static void spiFlash_init_ (u32 spi); +static void spiFlash_wake_ (u32 spi); +static inline u8 spiFlash_manufacturer_id_ (u32 spi, u32 cs); +static void spiFlash_exit4ByteAddr_ (u32 spi, u32 cs, u8 mid); +static void spiFlash_f2m_ (u32 spi, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_dual_f2m_ (u32 spi, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_quad_f2m_ (u32 spi, u32 flashAddress, u32 memoryAddress, u32 size); + +/* -------------------------------------------------------------------------- */ +/* Blocking / Wait Variants of Internal Functions */ +/* -------------------------------------------------------------------------- */ +static u8 spiWaitBusy (u32 reg, u32 cs); +static void spiWriteEnable (u32 reg, u32 cs); +static void spiWriteStatusRegister (u32 reg, u32 cs, u8 data); + +/* -------------------------------------------------------------------------- */ +/* Basic SPI Flash Commands (with CS handling) */ +/* -------------------------------------------------------------------------- */ +static void spiGlobalLock (u32 reg, u32 cs); +static void spiGlobalUnlock (u32 reg, u32 cs); +static u8 spiReadStatusRegister (u32 reg, u32 cs); +static void spiSectorErase (u32 reg, u32 cs, u32 Addr); + +/* -------------------------------------------------------------------------- */ +/* Initialization & Chip-Select Control */ +/* -------------------------------------------------------------------------- */ +static void spiFlash_init_mode (u32 spi, u32 mode); +static void spiFlash_init_withGpioCs (u32 spi, u32 gpio, u32 cs); +static void spiFlash_init (u32 spi, u32 cs); +static void spiFlash_select (u32 spi, u32 cs); +static void spiFlash_diselect (u32 spi, u32 cs); +static void spiFlash_select_withGpioCs (u32 gpio, u32 cs); +static void spiFlash_diselect_withGpioCs (u32 gpio, u32 cs); +static u8 spiFlash_manufacturer_id (u32 spi, u32 cs); + +/* -------------------------------------------------------------------------- */ +/* Power, Mode, and Address Handling */ +/* -------------------------------------------------------------------------- */ + +static void spiFlash_wake (u32 spi, u32 cs); +static void spiFlash_exit4ByteAddr (u32 spi, u32 cs); +static void spiFlash_wake_withGpioCs (u32 spi, u32 gpio, u32 cs); +static void spiFlash_exit4ByteAddr_withGpioCs(u32 spi, u32 gpio, u32 cs); +static void spiFlash_software_reset (u32 spi, u32 cs); +static void spiFlash_enable_quad_access (u32 spi, u32 cs); + +/* -------------------------------------------------------------------------- */ +/* Data Transfer Functions */ +/* -------------------------------------------------------------------------- */ +static u8 spiReadData_fromFlash (u32 reg, u32 cs, u32 addr); +static void spiFlash_f2m (u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_f2m_dual (u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_f2m_quad (u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_f2m_withGpioCs (u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_f2m_dual_withGpioCs (u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); +static void spiFlash_f2m_quad_withGpioCs (u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size); + +/* -------------------------------------------------------------------------- */ +/* Public Vendor-Specific Functions */ +/* -------------------------------------------------------------------------- */ +static void macronix_disable_write_protect (u32 reg, u32 cs); +static void macronix_enable_write_protect (u32 reg, u32 cs); + + +/****************************************************************************** +* +* @brief This function disable write protect for Macronix NOR Flash + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void macronix_disable_write_protect (u32 reg, u32 cs){ // Disable SRWD (status register write protect) + u8 status; + status=spiReadStatusRegister(reg,0); + status= status & 0x43; + spiWriteStatusRegister(reg,cs,status); + + } + + +/****************************************************************************** +* +* @brief This function enable write protect for Macronix NOR Flash + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void macronix_enable_write_protect (u32 reg, u32 cs){ // Enable SRWD (status register write protect) + u8 status; + status=spiReadStatusRegister(reg,0); + status= (status | 0xBC) & 0xFD; + spiWriteStatusRegister(reg,0,status); + } + +/****************************************************************************** +* +* @brief This function read data from NOR Flash + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting + * @param addr 32-bit address for reading +* +******************************************************************************/ + static u8 spiReadData_fromFlash(u32 reg, u32 cs, u32 addr){ + u8 out; + spi_select(reg, cs); + spi_write(reg, READ_DATA); + spi_write(reg, (addr>>16) & 0xFF); + spi_write(reg, (addr>>8) & 0xFF); + spi_write(reg, addr & 0xFF); + out = spi_read(reg); + spi_diselect(reg, cs); + return out; + + } + +/****************************************************************************** +* +* @brief This function waits until the SPI flash is not busy. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static u8 spiWaitBusy(u32 reg, u32 cs) + { + u8 out; + u16 timeout=0; + + while(1) + { + bsp_uDelay(1*1000); + out = spiReadStatusRegister(reg, cs); + if((out & 0x01) ==0x00) + return 0; + timeout++; + //sector erase max=400ms + if(timeout >=400) + { + return 1; //Time out + } + } + } + +/****************************************************************************** +* +* @brief This function globally locks the SPI flash. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiGlobalLock(u32 reg, u32 cs) + { + spiWriteEnable(reg,cs); + spi_select(reg, cs); + //Global lock + spi_write(reg, GLOBAL_LOCK); + spi_diselect(reg, cs); + + + if (spiFlash_manufacturer_id(reg,cs) == MACRONIX_ID) + macronix_enable_write_protect(reg,cs); + + + } + +/****************************************************************************** +* +* @brief This function globally unlocks the SPI flash. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiGlobalUnlock(u32 reg, u32 cs) + { + spiWriteEnable(reg,cs); + spi_select(reg, cs); + //Global unlock + spi_write(reg, GLOBAL_UNLOCK); + spi_diselect(reg, cs); + + if (spiFlash_manufacturer_id(reg,cs) == MACRONIX_ID) + macronix_disable_write_protect(reg,cs); + } + +/****************************************************************************** +* +* @brief This function erases a sector of the SPI flash given an address. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting + * @param Addr 32-bit address +* +******************************************************************************/ + static void spiSectorErase(u32 reg, u32 cs, u32 Addr) + { + spiWriteEnable(reg,cs); + spi_select(reg, cs); + //Erase Sector + spi_write(reg, SECTOR_ERASE); + spi_write(reg, (Addr>>16)&0xFF); + spi_write(reg, (Addr>>8)&0xFF); + spi_write(reg, Addr&0xFF); + spi_diselect(reg, cs); + spiWaitBusy(reg,cs); + } + +/******************************************************************************* +* +* @brief This function read Status Register. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static u8 spiReadStatusRegister(u32 reg, u32 cs){ + spi_select(reg, cs); + spi_write(reg, READ_STATUS_REG); //Read Status Register + u8 value = spi_read(reg); + spi_diselect(reg, cs); + return value; + } + +/******************************************************************************* +* +* @brief This function write Status Register. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting + * @param data 8-bit data +* +******************************************************************************/ + static void spiWriteStatusRegister(u32 reg, u32 cs, u8 data){ + + spi_select(reg, cs); + spi_write(reg, WRITE_STATUS_REG); //Write Status Register + spi_write(reg, data); //Write Status Register + spi_diselect(reg, cs); + } + +/******************************************************************************* +* +* @brief This function set Write Enable Latch. + * + * @param reg SPI base address + * @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiWriteEnable(u32 reg, u32 cs){ + spi_select(reg, cs); + spi_write(reg, WRITE_ENABLE); // Write Enable Sequence + spi_diselect(reg, cs); + } + +/******************************************************************************* +* +* @brief This function set SPI Flash device Chip Select with GPIO port + * + * @param gpio GPIO port base address + * @param cs 32-bit bitwise setting. Set 1 to enable particular bit. +* +******************************************************************************/ + + static void spiFlash_select_withGpioCs(u32 gpio, u32 cs){ + gpio_setOutput(gpio, gpio_getOutput(gpio) & ~(1 << cs)); + bsp_uDelay(1); + } + +/******************************************************************************* +* +* @brief This function clear SPI Flash device Chip Select with GPIO port + * + * @param gpio GPIO port base address + * @param cs 32-bit bitwise setting. Set 1 to disable particular bit. +* +******************************************************************************/ + + static void spiFlash_diselect_withGpioCs(u32 gpio, u32 cs){ + gpio_setOutput(gpio, gpio_getOutput(gpio) | (1 << cs)); + bsp_uDelay(1); + } + +/******************************************************************************* +* +* @brief This function set SPI Flash device Chip Select + * + * @param spi SPI port base address + * @param cs 32-bit bitwise setting. Set 1 to enable particular bit. +* +******************************************************************************/ + + static void spiFlash_select(u32 spi, u32 cs){ + spi_select(spi, cs); + } + +/******************************************************************************* +* +* @brief This function clear SPI Flash device Chip Select + * + * @param spi SPI port base address + * @param cs 32-bit bitwise setting. Set 1 to disable particular bit. +* +******************************************************************************/ + static void spiFlash_diselect(u32 spi, u32 cs){ + spi_diselect(spi, cs); + } + +/******************************************************************************* +* +* @brief This function initialize SPI port with default settings + * + * @param spi SPI port base address +* +******************************************************************************/ + static void spiFlash_init_(u32 spi){ + Spi_Config spiCfg; + spiCfg.cpol = 0; + spiCfg.cpha = 0; + spiCfg.mode = 0; + spiCfg.clkDivider = 2; + spiCfg.ssSetup = 5; + spiCfg.ssHold = 2; + spiCfg.ssDisable = 7; + spi_applyConfig(spi, &spiCfg); + spi_waitXferBusy(spi); + } + +/******************************************************************************* +* +* @brief This function initialize SPI port with default settings with mode selection + * + * @param spi SPI port base address + * @param mode SPI mode selection +* +******************************************************************************/ + static void spiFlash_init_mode_(u32 spi, u32 mode ){ + Spi_Config spiCfg; + spiCfg.cpol = 0; + spiCfg.cpha = 0; + spiCfg.mode = mode; + spiCfg.clkDivider = 2; + spiCfg.ssSetup = 5; + spiCfg.ssHold = 2; + spiCfg.ssDisable = 7; + spi_applyConfig(spi, &spiCfg); + spi_waitXferBusy(spi); + } + +/******************************************************************************* +* +* @brief This function initialize SPI port with GPIO Chip Select + * + * @param spi SPI port base address + * @param gpio GPIO port base address + * @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + + static void spiFlash_init_withGpioCs(u32 spi, u32 gpio, u32 cs){ + spiFlash_init_(spi); + gpio_setOutputEnable(gpio, gpio_getOutputEnable(gpio) | (1 << cs)); + spiFlash_diselect_withGpioCs(gpio,cs); + } + +/******************************************************************************* +* +* @brief This function initialize SPI port with GPIO Chip Select + * + * @param spi SPI port base address + * @param gpio GPIO port base address + * @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static void spiFlash_init(u32 spi, u32 cs){ + spiFlash_init_(spi); + spiFlash_diselect(spi, cs); + } +/******************************************************************************* +* +* @brief This function to retrieve SPI Flash Manufacturer ID + * + * @param spi SPI port base address + * @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static u8 spiFlash_manufacturer_id(u32 spi, u32 cs){ + u8 id; + spi_select(spi,cs); + id =spiFlash_manufacturer_id_(spi,cs); + spi_diselect(spi,cs); + return id; + } + + +/******************************************************************************* +* +* @brief This function to retrieve SPI Flash Manufacturer ID + * + * @param spi SPI port base address + * @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static inline u8 spiFlash_manufacturer_id_(u32 spi, u32 cs){ +#if defined(GD25_FLASH) + spi_write(spi, 0x9E); +#else + spi_write(spi, READ_MANUFACTURER); + // spi_write(spi, 0x00); + // spi_write(spi, 0x00); + // spi_write(spi, 0x00); +#endif + u8 mid = spi_read(spi); + bsp_uDelay(300); + return mid; + } + +/******************************************************************************* +* +* @brief This function wake up the Spi Flash. +* Crucial to ensure the device is in operation state before +* start communicating with the device. + * + * @param spi SPI port base address +* +******************************************************************************/ + static void spiFlash_wake_(u32 spi){ + spi_write(spi, 0xAB); + } + +/******************************************************************************* +* +* @brief This function to exit 4-byte addressing. +* Crucial to ensure the addressing mode is set to 3-byte before access. + * + * @param spi SPI port base address + * @param cs 32-bit bitwise chip select setting + * @param mid 8-bit SPI Flash Manufacturer ID. +* +******************************************************************************/ + static void spiFlash_exit4ByteAddr_(u32 spi, u32 cs, u8 mid){ + switch(mid){ + case 0x9D: + spi_write(spi, 0x29); + break; + default: + spi_write(spi, 0xE9); + break; + } + } + +/******************************************************************************* +* +* @brief This function to exit 4-byte addressing. +* Crucial to ensure the addressing mode is set to 3-byte before access. +* Readback the manufacturer ID before exit 4 byte addressing. +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiFlash_exit4ByteAddr(u32 spi, u32 cs){ + spiFlash_select(spi,cs); + u8 mid = spiFlash_manufacturer_id_(spi, cs); + spiFlash_diselect(spi,cs); + spi_waitXferBusy(spi); + spiFlash_select(spi,cs); + spiFlash_exit4ByteAddr_(spi, cs, mid); + spiFlash_diselect(spi,cs); + spi_waitXferBusy(spi); + } + + +/******************************************************************************* +* +* @brief This function to exit 4-byte addressing with gpio chip select. +* Crucial to ensure the addressing mode is set to 3-byte before access. +* Readback the manufacturer ID before exit 4 byte addressing. +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiFlash_exit4ByteAddr_withGpioCs(u32 spi, u32 gpio, u32 cs){ + spiFlash_select_withGpioCs(gpio,cs); + u8 mid = spiFlash_manufacturer_id_(spi, cs); + spiFlash_diselect_withGpioCs(gpio,cs); + spi_waitXferBusy(spi); + spiFlash_select_withGpioCs(gpio,cs); + spiFlash_exit4ByteAddr_(spi, cs, mid); + spiFlash_diselect_withGpioCs(gpio,cs); + spi_waitXferBusy(spi); + } + +/******************************************************************************* +* +* @brief This function wake up the Spi Flash with gpio chip select +* +* @param spi SPI port base address +* @param gpio GPIO port base address +* @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static void spiFlash_wake_withGpioCs(u32 spi, u32 gpio, u32 cs){ + spiFlash_select_withGpioCs(gpio,cs); + spiFlash_wake_(spi); + spiFlash_diselect_withGpioCs(gpio,cs); + bsp_uDelay(200); + } + +/******************************************************************************* +* +* @brief This function wake up the Spi Flash with chip select +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static void spiFlash_wake(u32 spi, u32 cs){ + spiFlash_select(spi,cs); + spiFlash_wake_(spi); + spiFlash_diselect(spi,cs); + spi_waitXferBusy(spi); + bsp_uDelay(100); // make sure the Flash fully awake + } + + /******************************************************************************* +* +* @brief This function send software reset to the SPI Flash +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static void spiFlash_software_reset(u32 spi, u32 cs){ + spiFlash_select(spi,cs); + spi_write(spi, 0x66); + spiFlash_diselect(spi,cs); + spiFlash_select(spi,cs); + spi_write(spi, 0x99); + spiFlash_diselect(spi,cs); + bsp_uDelay(200); + } + +/******************************************************************************* +* +* @brief This function read current SPI Flash ID +* +* @param spi SPI port base address +* +******************************************************************************/ + static u8 spiFlash_read_id_(u32 spi){ + spi_write(spi, READ_DEVICE_ID); + spi_write(spi, 0x00); + spi_write(spi, 0x00); + spi_write(spi, 0x00); + return spi_read(spi); + } + +/******************************************************************************* +* +* @brief This function read current SPI Flash ID with chip select +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting. +* +******************************************************************************/ + static u8 spiFlash_read_id(u32 spi, u32 cs){ + u8 id; + spiFlash_select(spi,cs); + id = spiFlash_read_id_(spi); + spiFlash_diselect(spi,cs); + return id; + } + +#if defined(DEFAULT_ADDRESS_BYTE) || defined(MX25_FLASH) +/******************************************************************************* +* +* @brief This funciton set Write Enable Latch and set Quad Enable bit to enable Quad SPI +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* +******************************************************************************/ + static void spiFlash_enable_quad_access(u32 spi, u32 cs){ + u8 status = 0; + // Poll until Write Enable Latch bit is set + do { + spiWriteEnable(spi, cs); + status = spiReadStatusRegister(spi, cs); + bsp_uDelay(1); + } while ((status & MX25_WRITE_ENABLE_LATCH_BIT) != MX25_WRITE_ENABLE_LATCH_BIT); + + // Enable Quad Enable (QE) + spiWriteStatusRegister(spi, cs, status | MX25_QUAD_ENABLE_BIT); + + // Poll until Quad Enable is set + do { + status = spiReadStatusRegister(spi, cs); + bsp_uDelay(1); + } while ((status & MX25_QUAD_ENABLE_BIT) != MX25_QUAD_ENABLE_BIT); + + } +#endif + +#if defined(GD25_FLASH) + /** + * Set Write Enable Latch and set Quad Enable bit to enable Quad SPI + * + * @param spi SPI port base address + * @param cs 32-bit bitwise chip select setting + * + */ + static void spiFlash_enable_quad_access(u32 spi, u32 cs){ + u8 status = 0; + // Poll until Write Enable Latch bit is set + do { + spiWriteEnable(spi, cs); + status = spiReadStatusRegister(spi, cs); + bsp_uDelay(1); + } while ((status & MX25_WRITE_ENABLE_LATCH_BIT) != MX25_WRITE_ENABLE_LATCH_BIT); + + // Enable Quad Enable (QE) + spiFlash_select(spi,cs); + spi_write(spi, 0x38); + spiFlash_diselect(spi,cs); + } +#endif + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with single data line. + * + * @param spi SPI port base address + * @param flashAddress The flash address to read the data + * @param memoryAddress The RAM address to write the data + * @param size The size of data to copy +* +******************************************************************************/ + static void spiFlash_f2m_(u32 spi, u32 flashAddress, u32 memoryAddress, u32 size){ + spi_write(spi, 0x0B); + spi_write(spi, flashAddress >> 16); + spi_write(spi, flashAddress >> 8); + spi_write(spi, flashAddress >> 0); + spi_write(spi, 0); + uint8_t *ram = (uint8_t *) memoryAddress; + for(u32 idx = 0;idx < size;idx++){ + u8 value = spi_read(spi); + *ram++ = value; + } + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with dual data line - half duplex. +* +* @param spi SPI port base address +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +* @note Make sure hardware need to connect both Data0 and Data1 port. Else, it would not work. +* +******************************************************************************/ + static void spiFlash_dual_f2m_(u32 spi, u32 flashAddress, u32 memoryAddress, u32 size){ + spi_write(spi, 0x3B); + spi_write(spi, flashAddress >> 16); + spi_write(spi, flashAddress >> 8); + spi_write(spi, flashAddress >> 0); + spi_write(spi, 0); + spi_waitXferBusy(spi); // Make sure all spi data transferred before switching mode + spiFlash_init_mode_(spi, 0x01); // change mode to dual data mode + uint8_t *ram = (uint8_t *) memoryAddress; + for(u32 idx = 0;idx < size;idx++){ + u8 value = spi_read(spi); + *ram++ = value; + } + spiFlash_init_mode_(spi, 0x00); // change mode back to single data mode + } + + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with quad data line - half duplex. +* +* @param spi SPI port base address +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +* @note Make sure hardware need to connect all data ports. +* Else, it would not work. +* +******************************************************************************/ + static void spiFlash_quad_f2m_(u32 spi, u32 flashAddress, u32 memoryAddress, u32 size){ +#if defined(GD25_FLASH) + spiFlash_init_mode_(spi, 0x02); // change mode to quad data mode +#endif + spi_write(spi, 0x6B); + spi_write(spi, flashAddress >> 16); + spi_write(spi, flashAddress >> 8); + spi_write(spi, flashAddress >> 0); + spi_write(spi, 0); +#if defined(GD25_FLASH) + spi_write(spi, 0); + spi_write(spi, 0); +#endif + spi_waitXferBusy(spi); // Make sure all spi data transferred before switching mode +#if !defined(GD25_FLASH) + spiFlash_init_mode_(spi, 0x02); // change mode to quad data mode +#endif + uint8_t *ram = (uint8_t *) memoryAddress; + for(u32 idx = 0;idx < size;idx++){ + u8 value = spi_read(spi); + *ram++ = value; + } + spi_write(spi, 0xFF); + spiFlash_init_mode_(spi, 0x00); // change mode back to single data mode + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with GPIO Chip Select. +* +* @param spi SPI port base address +* @param gpio GPIO port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +******************************************************************************/ + static void spiFlash_f2m_withGpioCs(u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ + spiFlash_select_withGpioCs(gpio,cs); + spiFlash_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect_withGpioCs(gpio,cs); + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with GPIO Chip Select with Dual data lines - half duplex. +* +* @param spi SPI port base address +* @param gpio GPIO port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +******************************************************************************/ + static void spiFlash_f2m_dual_withGpioCs(u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ + spiFlash_select_withGpioCs(gpio,cs); + spiFlash_dual_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect_withGpioCs(gpio,cs); + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with GPIO Chip Select With Quad data lines - half duplex +* +* @param spi SPI port base address +* @param gpio GPIO port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +******************************************************************************/ + static void spiFlash_f2m_quad_withGpioCs(u32 spi, u32 gpio, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ + spiFlash_select_withGpioCs(gpio,cs); + spiFlash_quad_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect_withGpioCs(gpio,cs); + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with Chip Select. +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +******************************************************************************/ + static void spiFlash_f2m(u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ + spiFlash_select(spi,cs); + spiFlash_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect(spi,cs); + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with Chip Select with Dual data lines - half duplex +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +* @note Make sure hardware need to connect both Data0 and Data1 port. +* Else, it would not work. +* +******************************************************************************/ + static void spiFlash_f2m_dual(u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ + spiFlash_select(spi,cs); + spiFlash_dual_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect(spi,cs); + } + +/******************************************************************************* +* +* @brief This function read data from FlashAddress and copy to memoryAddress of +* specific size with Chip Select with Quad data lines - half duplex. +* +* @param spi SPI port base address +* @param cs 32-bit bitwise chip select setting +* @param flashAddress The flash address to read the data +* @param memoryAddress The RAM address to write the data +* @param size The size of data to copy +* +* @note Make sure hardware need to connect all data ports. +* Else, it would not work. +* +******************************************************************************/ + static void spiFlash_f2m_quad(u32 spi, u32 cs, u32 flashAddress, u32 memoryAddress, u32 size){ +#if defined(DEFAULT_ADDRESS_BYTE) || defined(MX25_FLASH) || defined(GD25_FLASH) + spiFlash_enable_quad_access(spi,cs); +#endif + spiFlash_select(spi,cs); + spiFlash_quad_f2m_(spi, flashAddress, memoryAddress, size); + spiFlash_diselect(spi,cs); + } + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/start.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/start.h new file mode 100644 index 0000000..8da6bb6 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/start.h @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// +/******************************************************************************* +* +* @file start.h +* +* @brief Header file containing an external function declaration for SMP (Symmetric Multiprocessing) unlocking +* +* Functions: +* - smp_unlock: External function declaration for unlocking SMP with a user-defined main function +* +******************************************************************************/ + +#pragma once + +extern void smp_unlock(void (*userMain)(u32, u32, u32) ); \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/timer.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/timer.h new file mode 100755 index 0000000..0cd96b3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/timer.h @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* @file timer.h +* +* @brief Header file for timer functionality, including register access and control. +* reading and writing timer registers, configuring timer settings, +* and accessing timer values and limits. +* +******************************************************************************/ +#pragma once + +#include "type.h" +#include "io.h" + +#define TIMER_CONFIG 0x00 +#define TIMER_LIMIT 0x04 +#define TIMER_VALUE 0x08 + +/******************************************************************************* +* +* @brief This function reads a 32-bit value from the timer configuration register. +* +* @return The value read from the timer configuration register. +* +******************************************************************************/ + readReg_u32 (timer_getConfig , TIMER_CONFIG) +/******************************************************************************* +* +* @brief This function writes a 32-bit value to the timer configuration register. +* +* @param data The data to be written to the timer configuration register. +* +******************************************************************************/ + writeReg_u32(timer_setConfig , TIMER_CONFIG) +/******************************************************************************* +* +* @brief This function reads a 32-bit value from the timer limit register. +* +* @return The value read from the timer limit register. +* +******************************************************************************/ + readReg_u32 (timer_getLimit , TIMER_LIMIT) +/******************************************************************************* +* +* @brief This funciton writes a 32-bit value to the timer limit register. +* +* @param data The data to be written to the timer limit register. +* +******************************************************************************/ + writeReg_u32(timer_setLimit , TIMER_LIMIT) + +/******************************************************************************* +* +* @brief This function reads a 32-bit value from the timer value register. +* +* @return The value read from the timer value register. +* +******************************************************************************/ + readReg_u32 (timer_getValue , TIMER_VALUE) +/******************************************************************************* +* +* @brief This function clears the value of the timer register. +* +* @param reg The base address of the timer register. +* +******************************************************************************/ + void timer_clearValue(u32 reg){ + write_u32(0, reg + TIMER_VALUE); + } diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/type.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/type.h new file mode 100644 index 0000000..a78ee82 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/type.h @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file type.h +* +* @brief Header file defines common types and bit macros. +* +******************************************************************************/ + +#pragma once + +#include + +/******************************************************************************* +* +* Types defined: +* - u64: Unsigned 64-bit integer. +* - s64: Signed 64-bit integer. +* - u32: Unsigned 32-bit integer. +* - s32: Signed 32-bit integer. +* - u16: Unsigned 16-bit integer. +* - s16: Signed 16-bit integer. +* - u8: Unsigned 8-bit integer. +* - s8: Signed 8-bit integer. +* +* Bit Macros defined: +* - BIT_0 through BIT_31: Macros representing individual bits, where BIT_0 +* represents bit position 0, BIT_1 represents bit position 1, and so on. +* +******************************************************************************/ + + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint8_t u8; +typedef int8_t s8; + +#define BIT_0 (1 << 0) +#define BIT_1 (1 << 1) +#define BIT_2 (1 << 2) +#define BIT_3 (1 << 3) +#define BIT_4 (1 << 4) +#define BIT_5 (1 << 5) +#define BIT_6 (1 << 6) +#define BIT_7 (1 << 7) +#define BIT_8 (1 << 8) +#define BIT_9 (1 << 9) +#define BIT_10 (1 << 10) +#define BIT_11 (1 << 11) +#define BIT_12 (1 << 12) +#define BIT_13 (1 << 13) +#define BIT_14 (1 << 14) +#define BIT_15 (1 << 15) +#define BIT_16 (1 << 16) +#define BIT_17 (1 << 17) +#define BIT_18 (1 << 18) +#define BIT_19 (1 << 19) +#define BIT_20 (1 << 20) +#define BIT_21 (1 << 21) +#define BIT_22 (1 << 22) +#define BIT_23 (1 << 23) +#define BIT_24 (1 << 24) +#define BIT_25 (1 << 25) +#define BIT_26 (1 << 26) +#define BIT_27 (1 << 27) +#define BIT_28 (1 << 28) +#define BIT_29 (1 << 29) +#define BIT_30 (1 << 30) +#define BIT_31 (1 << 31) + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/uart.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/uart.h new file mode 100644 index 0000000..600ff26 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/uart.h @@ -0,0 +1,264 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file UART.h +* +* @brief Header file containing definitions and functions for UART operations. +* +* Functions: +* - uart_write: Writes a single character of data to the UART buffer. +* - uart_writeStr: Writes a null-terminated string to the UART buffer. +* - uart_read: Reads a single character of data from the UART buffer. +* - uart_applyConfig: Applies configuration settings to the UART module. +* - uart_writeHex: Writes the hexadecimal representation of an integer value to the UART buffer. +* - uart_status_read: Reads the status register of the UART module. +* - uart_status_write: Writes data to the status register of the UART module. +* - uart_TX_emptyInterruptEna: Enables or disables the TX empty interrupt for the UART module. +* - uart_RX_NotemptyInterruptEna: Enables or disables the RX not empty interrupt for the UART module. +* +* +******************************************************************************/ + +#pragma once + +#include "type.h" +#include "io.h" + +#define UART_DATA 0x00 /* Offset for the UART data register */ +#define UART_STATUS 0x04 /* Offset for the UART status register. */ +#define UART_CLOCK_DIVIDER 0x08 +#define UART_FRAME_CONFIG 0x0C + + +enum UartDataLength {BITS_8 = 8}; /* Enumerates different data length configurations for UART. */ +enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; +enum UartStop {ONE = 0,TWO = 1}; +/******************************************************************************* +* +* Structure: +* - Uart_Config: Structure representing UART configuration parameters. +* - dataLength: Enumerated value indicating the data length configuration. +* - parity: Enumerated value indicating the parity configuration. +* - stop: Enumerated value indicating the stop bit configuration. +* - clockDivider: Clock divider value for UART communication. +* +\******************************************************************************/ + typedef struct { + enum UartDataLength dataLength; + enum UartParity parity; + enum UartStop stop; + u32 clockDivider; + } Uart_Config; + +/******************************************************************************* +* +* @brief This function checks the availability of space for writing data to the UART buffer. +* +* @param reg: The base address of the UART registers. +* +* @return The number of available spaces for writing data to the UART buffer +* as a 32-bit unsigned integer. +* +* @note The function reads the UART status register and extracts the number +* of available spaces for writing data from bits 23 to 16. It then +* returns this value after masking with 0xFF. +* +******************************************************************************/ + static u32 uart_writeAvailability(u32 reg){ + return (read_u32(reg + UART_STATUS) >> 16) & 0xFF; + } + +/******************************************************************************* +* +* @brief This function checks the occupancy of the UART buffer for reading data. +* +* @param reg: The base address of the UART registers. +* +* @return The number of occupied spaces in the UART buffer for reading data +* as a 32-bit unsigned integer. +* +* @note The function reads the UART status register and extracts the number +* of occupied spaces for reading data from bits 31 to 24. +* +******************************************************************************/ + static u32 uart_readOccupancy(u32 reg){ + return read_u32(reg + UART_STATUS) >> 24; + } + +/******************************************************************************* +* +* @brief This function writes a single character of data to the UART buffer. +* +* @param reg: The base address of the UART registers. +* @param data: The character data to be written to the UART buffer. +* +* @return None. +* +* @note The function waits until there is available space in the UART buffer +* for writing data. Once space is available, it writes the character +* data to the UART data register. +* +******************************************************************************/ + static void uart_write(u32 reg, char data){ + while(uart_writeAvailability(reg) == 0); + write_u32(data, reg + UART_DATA); + } + +/******************************************************************************* +* +* @brief This function writes a null-terminated string to the UART buffer. +* +* @param reg: The base address of the UART registers. +* @param str: Pointer to the null-terminated string to be written to the UART buffer. +* +* @return None. +* +* @note The function iterates through each character of the string and writes +* them one by one to the UART buffer using the uart_write function. +* +******************************************************************************/ + static void uart_writeStr(u32 reg, const char* str){ + while(*str) uart_write(reg, *str++); + } + +/******************************************************************************* +* +* @brief This function reads a single character of data from the UART buffer. +* +* @param reg: The base address of the UART registers. +* +* @return The character read from the UART buffer as a 32-bit unsigned integer +* (converted to char). +* +* @note The function waits until there is data available in the UART buffer +* for reading. Once data is available, it reads the character data from +* the UART data register and returns it. +* +******************************************************************************/ + static char uart_read(u32 reg){ + while(uart_readOccupancy(reg) == 0); + return read_u32(reg + UART_DATA); + } + +/******************************************************************************* +* +* @brief This function applies the configuration settings to the UART module. +* +* @param reg: The base address of the UART registers. +* @param config: Pointer to the Uart_Config structure containing the configuration +* settings. +* +* @return None. +* +* @note The function writes the clock divider value from the configuration structure +* to the UART clock divider register. It then constructs the frame configuration +* value using data length, parity, and stop bit settings from the configuration +* structure, and writes this value to the UART frame configuration register. +* +******************************************************************************/ + static void uart_applyConfig(u32 reg, Uart_Config *config){ + write_u32(config->clockDivider, reg + UART_CLOCK_DIVIDER); + write_u32(((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16), reg + UART_FRAME_CONFIG); + } + +/******************************************************************************* +* +* @brief This function writes the hexadecimal representation of an integer value to the UART buffer. +* +* @param reg: The base address of the UART registers. +* @param value: The integer value to be converted to hexadecimal and written +* to the UART buffer. +* +* @return None. +* +* @note The function iterates through each nibble (4 bits) of the integer value +* starting from the most significant nibble. It extracts each nibble, +* converts it to its corresponding hexadecimal character, and writes +* the character to the UART buffer using the uart_write function. +* +******************************************************************************/ + static void uart_writeHex(u32 reg, int value){ + for(int i = 7; i >= 0; i--){ + int hex = (value >> i*4) & 0xF; + uart_write(reg, hex > 9 ? 'A' + hex - 10 : '0' + hex); + } + } + +/******************************************************************************* +* +* @brief This function reads the status register of the UART module. +* +* @param reg: The base address of the UART registers. +* +* @return The value read from the UART status register as a 32-bit unsigned integer. +* +* @note The function reads the value from the UART status register and returns it. +* +******************************************************************************/ + static u32 uart_status_read(u32 reg) + { + return read_u32(reg+UART_STATUS); + } + +/******************************************************************************* +* +* @brief This function writes data to the status register of the UART module. +* +* @param reg: The base address of the UART registers. +* @param data: The data to be written to the UART status register. +* +* @return None. +* +* @note The function writes the specified data to the UART status register. +* +******************************************************************************/ + static void uart_status_write(u32 reg, char data) + { + write_u32(data ,reg+UART_STATUS); + } + +/******************************************************************************* +* +* @brief This function enables or disables the transmit (TX) empty interrupt for the UART module. +* +* @param reg: The base address of the UART registers. +* @param Ena: Flag indicating whether to enable (1) or disable (0) the TX empty interrupt. +* +* @return None. +* +* @note The function reads the current value from the UART status register, +* clears the least significant bit to disable the TX empty interrupt, +* or sets it to enable the TX empty interrupt based on the provided flag, +* and then writes the modified value back to the UART status register. +* +******************************************************************************/ + static void uart_TX_emptyInterruptEna(u32 reg, char Ena){ + uart_status_write(reg,(uart_status_read(reg) & 0xFFFFFFFE) | (Ena & 0x01)); + } + +/******************************************************************************* +* +* @brief This function enables or disables the receive (RX) not empty interrupt for the UART module. +* +* @param reg: The base address of the UART registers. +* @param Ena: Flag indicating whether to enable (1) or disable (0) the RX not empty interrupt. +* +* @return None. +* +* @note The function reads the current value from the UART status register, +* clears the second least significant bit to disable the RX not empty interrupt, +* or sets it to enable the RX not empty interrupt based on the provided flag, +* and then writes the modified value back to the UART status register. +* +******************************************************************************/ + static void uart_RX_NotemptyInterruptEna(u32 reg, char Ena){ + uart_status_write(reg,(uart_status_read(reg) & 0xFFFFFFFD) | (Ena << 1)); + } + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/vexriscv.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/vexriscv.h new file mode 100644 index 0000000..d8a3730 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/vexriscv.h @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file vexriscv.h +* +* @brief Header file containing cache manipulation macros for RISC-V architecture. +* +* Functions: +* - data_cache_invalidate_all: Invalidate the entire data cache. +* - data_cache_invalidate_address: Invalidate cache lines corresponding +* to the given memory address. +* - instruction_cache_invalidate: Invalidate the entire instruction cache. +* +******************************************************************************/ + +#pragma once + +#include "riscv.h" + +//Invalidate the whole data cache +#define data_cache_invalidate_all() asm(".word(0x500F)"); + +//Invalidate all the data cache ways lines which could store the given address +#define data_cache_invalidate_address(address) \ +({ \ + asm volatile( \ + ".word ((0x500F) | (regnum_%0 << 15));" \ + : \ + : "r" (address) \ + ); \ +}) + +//Invalidate the whole instruction cache +#define instruction_cache_invalidate() asm("fence.i"); + +//Write buffer flush +#define soc_write_buffer_flush() \ +({ \ + csr_write(0x810, 1); \ + asm volatile ( \ + "1: csrr t0, 0x810 \n\t" \ + " andi t0, t0, 1 \n\t" \ + " bnez t0, 1b \n\t" \ + : \ + : \ + :"t0" \ + ); \ +}) + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/watchdog.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/watchdog.h new file mode 100644 index 0000000..8da8cbf --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/driver/watchdog.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "type.h" +#include "io.h" + +#define WATCHDOG_HEARTBEAT 0x0 +#define WATCHDOG_ENABLE 0x4 +#define WATCHDOG_DISABLE 0x8 +#define WATCHDOG_PRESCALER 0x40 +#define WATCHDOG_COUNTER_LIMIT 0x80 +#define WATCHDOG_COUNTER_VALUE 0xC0 + +#define WATCHDOG_HEARTBEAT_CHALLENGE 0xAD68E70D +#define WATCHDOG_UNLOCK_CHALLENGE 0x3C21B925 +#define WATCHDOG_LOCK_CHALLENGE 0x3C21B924 + + +writeReg_u32(watchdog_setPrescaler , WATCHDOG_PRESCALER) + +void watchdog_setCounterLimit(u32 reg, u32 counterId, u32 value){ + write_u32(value, reg + WATCHDOG_COUNTER_LIMIT + counterId * 4); +} + +u32 watchdog_getCounterValue(u32 reg, u32 counterId, u32 value){ + return read_u32(reg + WATCHDOG_COUNTER_VALUE + counterId * 4); +} + +void watchdog_heartbeat(u32 reg){ + write_u32(WATCHDOG_HEARTBEAT_CHALLENGE, reg + WATCHDOG_HEARTBEAT); +} + +void watchdog_unlock(u32 reg){ + write_u32(WATCHDOG_UNLOCK_CHALLENGE, reg + WATCHDOG_HEARTBEAT); +} + +void watchdog_lock(u32 reg){ + write_u32(WATCHDOG_LOCK_CHALLENGE, reg + WATCHDOG_HEARTBEAT); +} + +void watchdog_enable(u32 reg, u32 mask){ + write_u32(mask, reg + WATCHDOG_ENABLE); +} + +void watchdog_disable(u32 reg, u32 mask){ + write_u32(mask, reg + WATCHDOG_DISABLE); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/makefile new file mode 100644 index 0000000..bdb434c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/makefile @@ -0,0 +1,17 @@ +PROJ_NAME=fpuDemo + +STANDALONE=../.. +DEBUG?=yes +DEBUG_OG?=no +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/src/main.c new file mode 100644 index 0000000..458bbbd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/fpu/fpuDemo/src/main.c @@ -0,0 +1,102 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: Floating-Point Unit Arithmetic Demo +* +* @brief This demo performs various floating-point arithmetic operations and +* measures the processing time for each operation. It also checks if +* the Floating Point Unit (FPU) is enabled and provides information +* accordingly. +* +******************************************************************************/ + +#include +#include +#include "bsp.h" +#include "riscv.h" +#include "clint.h" +#include + + +/******************************************************************************* +* +* @brief This function print processing time between two timestamps +* +* @param ts1 First timestamp. +* @param ts2 Second timestamp. +* @param s Character +* +******************************************************************************/ +void printPTime(uint64_t ts1, uint64_t ts2, char *s) { + uint64_t rts; + rts=ts2-ts1; + bsp_printf("%s %d \n\n\r",s, rts ); +} + + +/****************************************************************************** +* +* @brief This main function demonstrates various floating-point calculations using +* the FPU (Floating Point Unit). Additionally, it measures the clock cycles +* taken for each calculation and prints the results along with the +* processing times. +* +******************************************************************************/ +void main() { + double inp1, + inp2, + rSin, + rCos, + rTan, + rSqrt, + rDiv; + uint64_t timerCmp0, timerCmp1; + bsp_init(); + bsp_printf("***Starting FPU Demo*** \r\n"); +#if (SYSTEM_CORES_0_FPU == 0) // If FPU extension is disabled in SOC + bsp_printf("FPU is disabled, more processing time required for following calculation \r\n"); + bsp_printf("FPU is disabled, please expect bigger size compiled binary \r\n"); +#endif + + /* Calculation */ + inp1=-0.8414709848078965; + timerCmp0 = clint_getTime(BSP_CLINT); + rSin=sin(inp1); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"Sine processing clock cycles:"); + timerCmp0 = clint_getTime(BSP_CLINT); + rCos=cos(inp1); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"Cosine processing clock cycles:"); + timerCmp0 = clint_getTime(BSP_CLINT); + rTan=tan(inp1); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"Tangent processing clock cycles:"); + + + inp2=0.4161468365471424; + timerCmp0 = clint_getTime(BSP_CLINT); + rSqrt=sqrt(inp2); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"Square root processing clock cycles:"); + timerCmp0 = clint_getTime(BSP_CLINT); + rDiv=inp2/3.6789; + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"Division processing clock cycles:"); + + + bsp_printf("\r\n"); + bsp_printf("Input 1 (in rad): %f \r\n", inp1); + bsp_printf("Sine result: %f \r\n", rSin); + bsp_printf("Cosine result: %f \r\n", rCos); + bsp_printf("Tangent result: %f \r\n", rTan); + bsp_printf("Input 2: %f \r\n", inp2); + bsp_printf("Square root result: %f \r\n", rSqrt); + bsp_printf("Divsion result: %f \r\n", rDiv); + + bsp_printf("***Succesfully Ran Demo*** \r\n"); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/makefile new file mode 100644 index 0000000..c4776be --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/makefile @@ -0,0 +1,19 @@ +PROJ_NAME=gpioDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/main.c new file mode 100644 index 0000000..b5398ff --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/main.c @@ -0,0 +1,149 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: GpioDemo (onBoard LED Blinking Demo) +* +* @brief This demo performs onboard LED blinking through GPIO controller +* and allow external interrupt by user. +* +******************************************************************************/ +#include +#include "bsp.h" +#include "userDef.h" +#include "riscv.h" +#include "gpio.h" +#include "clint.h" +#include "plic.h" + +void trap(); +void crash(); +void trap_entry(); +void gpioIsr(); +void isrRoutine(); +void isrInit(); +void main(); + +//Store the count of interrupt happened +u32 count; + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash message +* and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; //Interrupt if true, exception if false + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void gpioIsr(){ + bsp_printf("Entering gpio interrupt routine .. \r\n"); + bsp_uDelay(100); + count++; + bsp_printf("Count:%d .. Done \r\n",count); +} + +/****************************************************************************** +* +* @brief This function handles external interrupts. It checks for pending +* interrupts and processes them accordingly. If an interrupt from +* GPIO 0 is detected, it prints a message indicating the interrupt +* source. If an interrupt from an unknown source is detected, it +* calls a crash function to handle the error. +* +******************************************************************************/ + +void isrRoutine(){ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0: gpioIsr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function initializes GPIO interrupts and enables external interrupts +* by setting up the machine trap vector. +* +******************************************************************************/ +void isrInit(){ + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_SYSTEM_GPIO_0_IO_INTERRUPTS_0, 1); + // Enable rising edge interrupts + gpio_setInterruptRiseEnable(GPIO0, 1); + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + //Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This main function initializes the board, configures GPIO 0 to control onboard +* LEDs, and then sets up a loop to blink the LEDs. After that, it +* demonstrates GPIO 0 interrupt handling by instructing the user to press +* and release various onboard buttons (sw4, sw6, sw7) corresponding to +* different timer intervals. +* +******************************************************************************/ + +void main() { + bsp_init(); + bsp_printf("***Starting GPIO Demo*** \r\n"); + bsp_printf("Configure GPIOs to blink .. \r\n"); + // Set GPIO to output + gpio_setOutputEnable(GPIO0, 0xe); + gpio_setOutput(GPIO0, 0x0); + for (int i=0; i<50; i=i+1) { + gpio_setOutput(GPIO0, gpio_getOutput(GPIO0) ^ 0xe); + bsp_uDelay(LOOP_UDELAY); + } + bsp_printf("***Starting GPIO Interrupt Demo*** \r\n"); + bsp_printf("Press and release onboard button sw4 .. \r\n"); + isrInit(); + while(1); +} + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/userDef.h new file mode 100644 index 0000000..380f653 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/gpioDemo/src/userDef.h @@ -0,0 +1,13 @@ +#include "soc.h" + +#ifdef SYSTEM_GPIO_0_IO_CTRL + #define GPIO0 SYSTEM_GPIO_0_IO_CTRL +#else + #error "GPIO is disabled, please enable it in IP Manager!!!" +#endif +#ifdef SIM + #define LOOP_UDELAY 100 +#else + #define LOOP_UDELAY 100000 +#endif + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/makefile new file mode 100644 index 0000000..26ded62 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=inlineAsmDemo + +STANDALONE = ../.. + + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/src/main.c new file mode 100644 index 0000000..555a9ec --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/gpio/inlineAsmDemo/src/main.c @@ -0,0 +1,163 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: inlineAsmDemo +* +* @brief This demo illustrates utilizing the inline assembly feature. The inline +* assembly feature allows user to embed assembly language code into high-level +* code such as C and C++ whenever user need to implement low-level operations +* or improve the performance. +* +* @note The following are demonstrations of inlineAsmDemo applications +* • Integer arithmetic operations +* • Looping implementation +* • if-else implementation +* • Memory access +* • Proper use of general-purpose register (x0 – x31) +* • Exchange of values between the inline assembly and C +* +******************************************************************************/ + +#include "bsp.h" +#include "gpio.h" + +#ifdef SYSTEM_GPIO_0_IO_CTRL +//#define C_IMPLEMENTATION 1 // uncomment this to use C high level implementation +#define GPIO0 SYSTEM_GPIO_0_IO_CTRL + +/****************************************************************************** +* +* @brief This function reads data from the UART register. It continuously checks +* the occupancy of the UART register and reads data until the register is +* empty. It then returns the last data read. +* +* @param reg: UART register address to read from +* +* @return: Data read from the UART register +* +******************************************************************************/ +uint8_t read_uart(u32 reg) // function implementation in C +{ + uint8_t dat = 0; + while(uart_readOccupancy(reg)) + { + dat=uart_read(reg); + } + return dat; +} + +#ifdef C_IMPLEMENTATION // C implemented main function +/****************************************************************************** +* +* @brief Main Function - C Implementation +* +* @note This function demonstrates a simple C implementation with C implementation. +* It initializes the system and GPIOs, then enters a loop where it increments +* a counter and sets GPIO outputs based on the counter value. +* The LEDs can be reset by pressing 'r' on the UART terminal. +* +******************************************************************************/ + +void main() +{ + int i = 0; + u8 p = 0; + bsp_printf("Inline Assembly Demo\r\n"); + bsp_printf("Demonstrating C implementation\r\n"); + bsp_printf("Reset the LEDs by pressing 'r' \r\n"); + gpio_setOutputEnable(GPIO0,0xe); + gpio_setOutput(GPIO0,0x0); + while(1){ + i=i+1; + if((i>>24) & 0x01){ + p = read_uart(BSP_UART_TERMINAL); + while (p!='r'){ + p = read_uart(BSP_UART_TERMINAL); + } + i = 0; + } else { + p=(i >> 20); + } + gpio_setOutput(GPIO0, p); + } +} +#else //Assembly Implementation + +/****************************************************************************** +* +* @brief Main Function - Assembly Implementation +* +* @note This function demonstrates a main implementation using inline assembly. +* The main function initializes the system and GPIOs, then enters a loop +* with inline assembly for the main operations including counter +* incrementation, checking the UART input, and setting GPIO outputs. +* The LEDs can be reset by pressing 'r' on the UART terminal. +* +******************************************************************************/ +void main() //implementation in inline assembly except function call +{ + uint8_t p=0; + bsp_printf("Inline Assembly Demo\r\n"); + bsp_printf("Reset the LEDs by pressing 'r' \r\n"); + __asm__ __volatile__ + ( + "li %[p], 0\n" // Load immediate: load constant zero into variable p + "li t1, 0\n" // Load immediate: load constant zero into t1 register + //Assign address for GPIO port + "lui t2, %[gpio]\n" // load upper immediate: load t2 with 0xf8015 with last 12 bit set to 0 which indicates 0xf8015000 + "lui t3, %[gpio]\n" // load upper immediate: load t3 with 0xf8015 / last 12 bit set to 0 which indicates 0xf8015000 + //Assign output enable for GPIO port, refer to line "gpio_setOutputEnable(GPIO,0xe)" + "li t4, 14\n" // load immediate: load 0x0e into t4 + "sw t4, 8(t2)\n" // store word: store t4 data into t2 (offset 8) = output enable register + //Store value "0" to the memory address of the GPIO port as initial value of GPIO port. + "sw zero, 4(t2)\n" // store word: store zero into t2 (offset 4)=output register + // While loop starts here + "1:" "addi t1, t1, 1\n" // Add immediate: add 1 to t1 and store it in t1 (C Code = i=i+1). Label `1:`. + "srli t2, t1, 24\n" // Shift right logical immediate: shift right t1 by 24 and store it in t2 (C Code = i>>24) + "li t5, 1\n" // load immediate: load t5 register with value 1 + "and t2, t2, t5\n" // And operation: AND t2 with t5 and store it in t2 + "beqz t2, 4f\n" // branch if equal to zero: if t2 equal zero, jump to 4f + "loop:" "li t6, 'r'\n" // load immediate: load character 'r' to register t6. Label `loop`. + //Output operand + :[p] "+r" (p) // Variable p is used as input and output + :[gpio] "i" ((GPIO0 >> 12) & 0xFFFFF) // input operand using GPIO0 define + ); + + //Function call in C + p=read_uart(BSP_UART_TERMINAL); // get the uart character and put it into variable p + + __asm__ __volatile__ + ( + //The third "if" statement + "bne %[p], t6, loop\n" // branch if not equal zero: Go to label loop if p is not zero ti read from uart again + "li t1,0\n" // reset i = 0 + //Assign Value P to GPIO port + "2:" "andi %[p], %[p], 255\n" // AND with immediate value. Perform and operation on P with 0xFF and store into variable p. Label `2:`. + "3:" "sw %[p], 4(t3)\n" // store word. store variable p value into register t3(offset 4): output register (C code = gpio_set Output()). Label `3:`. + "j 1b\n" // Jump to 1b = '1:'. Go back to start of while loop + //The "else" statement + "4:" "srai %[p], t1, 0x14\n" // shift right arithmetic immediate. Shift right by 20 bits on value t1 and put it into variable p. Label `4`. + "j 2b\n" // Jump to 2b = '2:' + //Output operand + :[p] "+r" (p) // Variable p is used as input and output + ); +} +#endif +#else +/****************************************************************************** +* +* @brief This main function is executed when GPIO functionality is disabled. +* It initializes the BSP and prints a message indicating that +* GPIO 0 is disabled, and the user should enable it to run the app. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("gpio 0 is disabled, please enable it to run this app.\r\n"); +} +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/makefile new file mode 100644 index 0000000..c731e92 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/makefile @@ -0,0 +1,14 @@ +PROJ_NAME=i2cMasterDemo + +STANDALONE = ../.. + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/main.c new file mode 100644 index 0000000..ad53b2c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/main.c @@ -0,0 +1,143 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: i2cMasterDemo +* +* @brief This demo demonstrate how to communicate as a I2C master through I2C Protocol +* by reading single and multiple bytes of data to I2C slave that can be emulated +* with I2CSlaveDemo. It assume it is the single master on the bus, and send frame +* in a blocking manner. +* +******************************************************************************/ +#include +#include "bsp.h" +#include "i2c.h" +#include "userDef.h" + +#define I2C_MASTER_ADDR 0x67 // Slave device address +#define WORD_REG_ADDR 0 // Set 0 if master only expect to send 1-byte of register address, else set 1. +#define I2C_FREQUENCY 100000 // Set your I2C Frequency here +#ifdef SYSTEM_I2C_0_IO_CTRL + +/****************************************************************************** +* +* @brief This function initiates the configuration of I2C by setting it to 100kHz. +* +* @param i2c.samplingClockDivider => Sampling rate = (FCLK/(samplingClockDivider + 1). +* => Controls the rate at which the I2C controller samples SCL and SDA. +* +* @param i2c.timeout => Inactive timeout clock cycle. The controller will drop the transfer when the value of the timeout is reached or exceeded. +* => Setting the timeout value to zero will disable the timeout feature. +* +* @param i2c.tsuDat => Data setup time. The number of clock cycles should SDA hold its state before the rising edge of SCL. +* @param i2c.tLow => The number of clock cycles of SCL in LOW state. +* @param i2c.tHigh => The number of clock cycles of SCL in HIGH state. +* @param i2c.tBuf => The number of clock cycles delay before master can initiate a START bit after a STOP bit is issued. +* @return None. +* +******************************************************************************/ +void init(){ + //I2C init + I2c_Config i2c; + i2c.samplingClockDivider = 3; + i2c.timeout = I2C_CTRL_HZ/10; // timeout = 0.1s + i2c.tsuDat = I2C_CTRL_HZ/I2C_FREQUENCY/3; // tsuDat = 3.33us + i2c.tLow = I2C_CTRL_HZ/I2C_FREQUENCY/2; // tLow = 5us + i2c.tHigh = I2C_CTRL_HZ/I2C_FREQUENCY/2; // tHigh = 5us + i2c.tBuf = I2C_CTRL_HZ/I2C_FREQUENCY; // tBuf = 10us + + i2c_applyConfig(I2C_CTRL, &i2c); // Apply the configs from i2c structure into the I2C controller. +} + +/****************************************************************************** +* +* @brief This main function demonstrates the functionality of I2C Master. It performs +* single byte and multi-byte write-read operations with error checks. +* The I2C Master communicates with an I2C Slave (or another compatible I2C +* device) to perform the tests. +* +******************************************************************************/ +void main() { + bsp_init(); + init(); // Initiatize + bsp_printf("I2C Master Demo! \r\n Please ensure you've either connect to a compatible I2C Slave or running the i2cSlaveDemo with I2C ports connected.\r\n"); + bsp_printf("TEST STARTED ! \r\n"); + u8 dacValue[20]; + u8 readData[20]; + // Set default value for dacValue variable. + for (int i = 0; i < 20; i++){ + dacValue[i] = i; + } + u8 slaveAddr = (I2C_MASTER_ADDR << 1) & 0xFF; // The slave address is shifted left by 1 bit to allocate the bit for rw bit + while(1){ // Forever loop + uint32_t ready; + +#if ( WORD_REG_ADDR == 1) // 2-Byte Register Address + //single byte write and read + i2c_writeData_w(I2C_CTRL, slaveAddr, 0x00, dacValue, 0x01); // Write a byte of dacValue array to address 0x00 with 2-byte of register address + i2c_readData_w(I2C_CTRL, slaveAddr, 0x00, readData , 0x01); // Read a byte of data from address 0x00 with 2-byte of register address + // Make sure the data write and read are tally. + if (dacValue[0] != readData[0]){ + bsp_printf("I2C single data write and read test failed. \r\n"); + while(1){}; + } + + //Multiple bytes write and read + i2c_writeData_w(I2C_CTRL, slaveAddr, 0x00, dacValue, 20); // Write 20 bytes of dacValue array to address 0x00 with 2-byte of register address + i2c_readData_w(I2C_CTRL, slaveAddr, 0x00, readData , 20); // Read 20 bytes of data from address 0x00 with 2-byte of register address + // Make sure the data write and read are tally. + for (int i = 0; i < 20; i++){ + if (dacValue[i] != readData[i]){ + bsp_printf("I2C multi data write and read test failed at data #%i \r\n", i); + while(1){}; + } + } +#else // 1-Byte Register Address + //single byte write and read + i2c_writeData_b(I2C_CTRL, slaveAddr, 0x00, dacValue, 0x01); // Write a byte of dacValue array to address 0x00 with 1-byte of register address + i2c_readData_b(I2C_CTRL, slaveAddr, 0x00, readData , 0x01); // Read a byte of data from address 0x00 with 1-byte of register address + // Make sure the data write and read are tally. + if (dacValue[0] != readData[0]){ + bsp_printf("I2C single data write and read test failed. \r\n"); + while(1){}; + } + + //Multiple bytes write and read + i2c_writeData_b(I2C_CTRL, slaveAddr, 0x00, dacValue, 20); // Write 20 bytes of dacValue array to address 0x00 with 1-byte of register address + i2c_readData_b(I2C_CTRL, slaveAddr, 0x00, readData , 20); // Read 20 bytes of data from address 0x00 with 1-byte of register address + // Make sure the data write and read are tally. + for (int i = 0; i < 20; i++){ + if (dacValue[i] != readData[i]){ + bsp_printf("I2C multi data write and read test failed at data #%i \r\n", i); + while(1){}; + } + } +#endif + bsp_printf("I2C Master Demo completed. \r\n"); + bsp_printf("TEST PASSED! \r\n"); + while(1){}; + } +} +#else +/****************************************************************************** +* +* @brief This main function is executed when I2C functionality is disabled. +* It initializes the BSP and prints a message indicating that +* I2C 0 is disabled, and the user should enable it to run the app. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("i2c 0 is disabled, please enable it to run this app. \r\n"); +} +#endif + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/userDef.h new file mode 100644 index 0000000..aa6ff55 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterDemo/src/userDef.h @@ -0,0 +1,16 @@ +/******************************************************************************* +* +* @file i2cDemo.h +* +* @brief Header file defines I2C controller and interrupt depending on the +* availability of the current system. +* +*******************************************************************************/ + +#pragma once + +#ifdef SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL_PLIC_INTERRUPT SYSTEM_PLIC_SYSTEM_I2C_0_IO_INTERRUPT +#endif +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/makefile new file mode 100644 index 0000000..43d411d --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=i2cMasterInterruptDemo + +STANDALONE = ../.. +DEBUG=yes + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/trap.S \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/main.c new file mode 100644 index 0000000..50e425a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/main.c @@ -0,0 +1,243 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: i2cMasterInterruptDemo +* +* @brief This demo is functionally similar to i2cMasterDemo but includes interrupt support +* to prevent the program from getting stuck if the slave device fails to respond. +* It demonstrates the use of a timeout interrupt to handle stalled I2C communication. +* The program operates as an I2C master, performing both single- and multi-byte reads +* from a slave device, which can be emulated using I2CSlaveDemo. +* It assumes it is the sole master on the bus and performs data transfers in a blocking manner. +* +******************************************************************************/ +#include +#include "bsp.h" +#include "i2c.h" +#include "riscv.h" +#include "clint.h" +#include "plic.h" +#include "userDef.h" + +#define I2C_MASTER_ADDR 0x67 // Slave device address +#define WORD_REG_ADDR 0 // Set 0 if master only expect to send 1-byte of register address, else set 1. +#define I2C_FREQUENCY 100000 // Set your I2C Frequency here +#ifdef SYSTEM_I2C_0_IO_CTRL + +void crash(); +void trap_entry(); +void externalInterrupt(); + +/****************************************************************************** +* +* @brief This function initiates the configuration of I2C by setting it to 100kHz. +* +* @param i2c.samplingClockDivider => Sampling rate = (FCLK/(samplingClockDivider + 1). +* => Controls the rate at which the I2C controller samples SCL and SDA. +* +* @param i2c.timeout => Inactive timeout clock cycle. The controller will drop the transfer when the value of the timeout is reached or exceeded. +* => Setting the timeout value to zero will disable the timeout feature. +* +* @param i2c.tsuDat => Data setup time. The number of clock cycles should SDA hold its state before the rising edge of SCL. +* @param i2c.tLow => The number of clock cycles of SCL in LOW state. +* @param i2c.tHigh => The number of clock cycles of SCL in HIGH state. +* @param i2c.tBuf => The number of clock cycles delay before master can initiate a START bit after a STOP bit is issued. +* @return None. +* +******************************************************************************/ +void init(){ + //I2C init + I2c_Config i2c; + i2c.samplingClockDivider = 3; + i2c.timeout = I2C_CTRL_HZ/10; // timeout = 0.1s + i2c.tsuDat = I2C_CTRL_HZ/I2C_FREQUENCY/3; // tsuDat = 3.33us + i2c.tLow = I2C_CTRL_HZ/I2C_FREQUENCY/2; // tLow = 5us + i2c.tHigh = I2C_CTRL_HZ/I2C_FREQUENCY/2; // tHigh = 5us + i2c.tBuf = I2C_CTRL_HZ/I2C_FREQUENCY; // tBuf = 10us + + i2c_applyConfig(I2C_CTRL, &i2c); // Apply the configs from i2c structure into the I2C controller. + i2c_enableInterrupt(I2C_CTRL, I2C_INTERRUPT_DROP); + + //configure PLIC + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + + //enable PLIC I2C interrupts + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, I2C_CTRL_PLIC_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, I2C_CTRL_PLIC_INTERRUPT, 1); + + //configure RISC-V interrupt CSR + //Set the machine trap vector (trap.S) + csr_write(mtvec, trap_entry); + //Enable machine external interrupts + csr_write(mie, MIE_MEIE); + //Enable interrupts + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: externalInterrupt(); break; + default: crash(); break; + } + } + else + { + crash(); + } +} + +/****************************************************************************** +* +* @brief This function handles I2C interrupts and clear interrupt flag. +* +******************************************************************************/ +void i2c_intc(){ + if (i2c_getInterruptFlag(I2C_CTRL) & I2C_INTERRUPT_DROP) + bsp_printf("I2C Transfer is dropped due to timeout!\r\n"); + else + bsp_printf("I2C Interrupt is triggered!\r\n"); + + i2c_clearInterruptFlag(I2C_CTRL, I2C_INTERRUPT_DROP); + while(1); + +} +/****************************************************************************** +* +* @brief This function handles I2C interrupts by claiming pending interrupts +* and processing them through i2c_intc(). +* +******************************************************************************/ +void externalInterrupt(){ + uint32_t claim; + //While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case I2C_CTRL_PLIC_INTERRUPT: i2c_intc(); break; + default:crash(); break; + } + //unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash message +* and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + + + +/****************************************************************************** +* +* @brief This main function demonstrates the functionality of I2C Master. It performs +* single byte and multi-byte write-read operations with error checks. +* The I2C Master communicates with an I2C Slave (or another compatible I2C +* device) to perform the tests. +* +******************************************************************************/ +void main() { + bsp_init(); + init(); // Initiatize + bsp_printf("I2C Master Interrupt Demo! \r\n Please ensure you've either connect to a compatible I2C Slave or running the i2cSlaveDemo with I2C ports connected.\r\n"); + bsp_printf("TEST STARTED ! \r\n"); + u8 dacValue[20]; + u8 readData[20]; + // Set default value for dacValue variable. + for (int i = 0; i < 20; i++){ + dacValue[i] = i; + } + u8 slaveAddr = (I2C_MASTER_ADDR << 1) & 0xFF; // The slave address is shifted left by 1 bit to allocate the bit for rw bit + while(1){ // Forever loop + uint32_t ready; + +#if ( WORD_REG_ADDR == 1) // 2-Byte Register Address + //single byte write and read + i2c_writeData_w_ack(I2C_CTRL, slaveAddr, 0x00, dacValue, 0x01); // Write a byte of dacValue array to address 0x00 with 2-byte of register address + i2c_readData_w_ack(I2C_CTRL, slaveAddr, 0x00, readData , 0x01); // Read a byte of data from address 0x00 with 2-byte of register address + // Make sure the data write and read are tally. + if (dacValue[0] != readData[0]){ + bsp_printf("I2C single data write and read test failed. \r\n"); + while(1){}; + } + + //Multiple bytes write and read + i2c_writeData_w_ack(I2C_CTRL, slaveAddr, 0x00, dacValue, 20); // Write 20 bytes of dacValue array to address 0x00 with 2-byte of register address + i2c_readData_w_ack(I2C_CTRL, slaveAddr, 0x00, readData , 20); // Read 20 bytes of data from address 0x00 with 2-byte of register address + // Make sure the data write and read are tally. + for (int i = 0; i < 20; i++){ + if (dacValue[i] != readData[i]){ + bsp_printf("I2C multi data write and read test failed at data #%i \r\n", i); + while(1){}; + } + } +#else // 1-Byte Register Address + //single byte write and read + i2c_writeData_b_ack(I2C_CTRL, slaveAddr, 0x00, dacValue, 0x01); // Write a byte of dacValue array to address 0x00 with 1-byte of register address + i2c_readData_b_ack(I2C_CTRL, slaveAddr, 0x00, readData , 0x01); // Read a byte of data from address 0x00 with 1-byte of register address + // Make sure the data write and read are tally. + if (dacValue[0] != readData[0]){ + bsp_printf("I2C single data write and read test failed. \r\n"); + while(1){}; + } + + //Multiple bytes write and read + i2c_writeData_b_ack(I2C_CTRL, slaveAddr, 0x00, dacValue, 20); // Write 20 bytes of dacValue array to address 0x00 with 1-byte of register address + i2c_readData_b_ack(I2C_CTRL, slaveAddr, 0x00, readData , 20); // Read 20 bytes of data from address 0x00 with 1-byte of register address + // Make sure the data write and read are tally. + for (int i = 0; i < 20; i++){ + if (dacValue[i] != readData[i]){ + bsp_printf("I2C multi data write and read test failed at data #%i \r\n", i); + while(1){}; + } + } +#endif + bsp_printf("I2C Master Interrupt Demo completed. \r\n"); + bsp_printf("TEST PASSED! \r\n"); + while(1){}; + } +} +#else +/****************************************************************************** +* +* @brief This main function is executed when I2C functionality is disabled. +* It initializes the BSP and prints a message indicating that +* I2C 0 is disabled, and the user should enable it to run the app. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("i2c 0 is disabled, please enable it to run this app. \r\n"); +} +#endif + + + + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/userDef.h new file mode 100644 index 0000000..6b200de --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cMasterInterruptDemo/src/userDef.h @@ -0,0 +1,13 @@ +/******************************************************************************* +* +* @file userDef.h +* +* @brief Header file defines I2C controller and interrupt depending on the +* availability of the current system. +* +*******************************************************************************/ + +#pragma once + #define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL_PLIC_INTERRUPT SYSTEM_PLIC_SYSTEM_I2C_0_IO_INTERRUPT + #define I2C_CTRL_HZ SYSTEM_CLINT_HZ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/makefile new file mode 100644 index 0000000..4de91ff --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/makefile @@ -0,0 +1,15 @@ +PROJ_NAME=i2cSlaveDemo + +STANDALONE = ../.. + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/main.c new file mode 100644 index 0000000..0725cea --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/main.c @@ -0,0 +1,372 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: i2cSlaveDemo +* +* @brief This demo demonstrate how to configure Sapphire SoC as an I2C Slave device, emulating +* the behavior of an I2C EEPROM device. You may use the I2CMasterDemo to act as the +* master to control this slave device. +* +* @note Please ensure you've configured the correct address and and number of byte of register +* address. +* Please also ensure your hardware and RTL connected the SDA and SCL with pull-up resistors. +* You may run this demo on a Sapphire SoC while the I2CMasterDemo on another Sapphire SoC, +* on the same or different board/ device. +* It assume it is the single master on the bus, and send frame in a blocking manner. +* Please enable printf_full for a cleaner UART printout. +* +******************************************************************************/ + +#include +#include "bsp.h" +#include "riscv.h" +#include "clint.h" +#include "plic.h" +#include "i2c.h" +#include "userDef.h" + +#define MEM_SIZE 256 // Size of the memory +#define I2C_SLAVE_ADDR 0x67 // Slave device address +#define WORD_REG_ADDR 0 // Set 0 if master only expect to send 1-byte of register address, else set 1.#define I2C_SLAVE_ADDR 0x67 // Slave device address +#define I2C_FREQUENCY 100000 // Set your I2C Frequency here +unsigned char addr0 = 0x00; // MSB +unsigned char addr1 = 0x00; // LSB +u16 addr = 0x00; +unsigned char data0[MEM_SIZE]; + +#ifdef SYSTEM_I2C_0_IO_CTRL + +void main(); +void init(); +void trap(); +void crash(); +void trap_entry(); +void externalInterrupt(); +void externalInterrupt_i2c(); + +//I2C interrupt state +enum { + IDLE, + Write_Addr_0, + Write_Addr_1, + Read_DATA_0, + Write_DATA_0 +} state = IDLE; + +I2c_Config i2c; + +/****************************************************************************** +* +* @brief This function initiates the configuration of I2C by setting it to 100kHz and enable I2c interrupt. +* +* @param i2c.samplingClockDivider => Sampling rate = (FCLK/(samplingClockDivider + 1). +* => Controls the rate at which the I2C controller samples SCL and SDA. +* +* @param i2c.timeout => Inactive timeout clock cycle. The controller will drop the transfer when the value of the timeout is reached or exceeded. +* => Setting the timeout value to zero will disable the timeout feature. +* +* @param i2c.tsuDat => Data setup time. The number of clock cycles should SDA hold its state before the rising edge of SCL. +* @param i2c.tLow => The number of clock cycles of SCL in LOW state. +* @param i2c.tHigh => The number of clock cycles of SCL in HIGH state. +* @param i2c.tBuf => The number of clock cycles delay before master can initiate a START bit after a STOP bit is issued. +* @return None. +* +******************************************************************************/ +void init(){ + //I2C init + i2c.samplingClockDivider = 3; // Sampling rate = (FCLK/(samplingClockDivider + 1). Controls the rate at which the I2C controller samples SCL and SDA. + i2c.timeout = I2C_CTRL_HZ/10; // 100 ms; // Inactive timeout clock cycle. The controller will drop the transfer when the value of the timeout is reached or exceeded. Setting the timeout value to zero will disable the timeout feature. + i2c.tsuDat = I2C_CTRL_HZ/I2C_FREQUENCY/3; // Data setup time. The number of clock cycles should SDA hold its state before the rising edge of SCL. Refer to your I2C slave datasheet. + i2c.tLow = I2C_CTRL_HZ/I2C_FREQUENCY/2; // The number of clock cycles of SCL in LOW state. + i2c.tHigh = I2C_CTRL_HZ/I2C_FREQUENCY/2; // The number of clock cycles of SCL in HIGH state. + i2c.tBuf = I2C_CTRL_HZ/I2C_FREQUENCY; // The number of clock cycles delay before master can initiate a START bit after a STOP bit is issued. Refer to your I2C slave datasheet. + i2c_applyConfig(I2C_CTRL, &i2c); + + i2c_setFilterConfig(I2C_CTRL, 0, I2C_SLAVE_ADDR | I2C_FILTER_7_BITS | I2C_FILTER_ENABLE); + i2c_enableInterrupt(I2C_CTRL, I2C_INTERRUPT_FILTER); + + //configure PLIC + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + + //enable PLIC I2C interrupts + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, I2C_CTRL_PLIC_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, I2C_CTRL_PLIC_INTERRUPT, 1); + + //configure RISC-V interrupt CSR + //Set the machine trap vector (trap.S) + csr_write(mtvec, trap_entry); + //Enable machine external interrupts + csr_write(mie, MIE_MEIE); + //Enable interrupts + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); + +} + +/****************************************************************************** +* +* @brief This function checks the provided condition. If the condition is false, +* it prints an "Assert failure" message and enters an infinite loop, +* effectively halting the program. +* +* @param cond Condition to check +* +******************************************************************************/ +void assert(int cond){ + if(!cond) { + bsp_printf("Assert failure \r\n"); + while(1); + } +} + + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: externalInterrupt(); break; + default: crash(); break; + } + } + else + { + crash(); + } +} +/****************************************************************************** +* +* @brief This function handles I2C interrupts by claiming pending interrupts +* and processing them through externalInterrupt_i2c(). +* +******************************************************************************/ +void externalInterrupt(){ + uint32_t claim; + //While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case I2C_CTRL_PLIC_INTERRUPT: externalInterrupt_i2c(); break; + default:crash(); break; + } + //unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash message +* and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + +/****************************************************************************** +* +* @brief This function handles external interrupts for I2C communication. +* It manages I2C read and write operations based on the received data. +* +******************************************************************************/ + +void externalInterrupt_i2c(){ + + u32 irq_status = i2c_getInterruptFlag(I2C_CTRL); + if (irq_status & I2C_INTERRUPT_FILTER) { + i2c_disableInterrupt(I2C_CTRL, I2C_INTERRUPT_TX_DATA); + state = IDLE; + } + + switch(state){ + case IDLE: + //I2C filter 0 hit => frame for us + if(i2c_getFilteringHit(I2C_CTRL) == 1){ + //read + if(i2c_getFilteringStatus(I2C_CTRL) == 1){ // Read Operation requested from master + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, data0[addr0]); // Send First Read Value to Master + state = Read_DATA_0; + } else { // Write Operation requested from master + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + state = Write_Addr_0; + } + + i2c_enableInterrupt(I2C_CTRL, I2C_INTERRUPT_TX_DATA); // Enable the TX Data interrupt + } + else + { + bsp_printf("unknown condition\n\r"); // Interrupt occurred but the interrupt is not due to correct address received. + state = IDLE; + } + i2c_clearInterruptFlag(I2C_CTRL, I2C_INTERRUPT_FILTER); + + break; + +#if ( WORD_REG_ADDR == 1) // 2-Byte Register Address Selected + //Write frame 0 to us + case Write_Addr_0: + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + //Get First register address byte from Master + addr0 = i2c_rxData(I2C_CTRL); + state = Write_Addr_1; + break; + + //Write frame to us + case Write_Addr_1: + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + //Get second register address byte from Master + addr1 = i2c_rxData(I2C_CTRL); + addr = (addr0 << 8) | addr1; // concatenate 2 bytes of register address into a 16-bit address. + state = Write_DATA_0; + break; + + case Write_DATA_0: + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + //Get Value from Master + data0[addr] = i2c_rxData(I2C_CTRL); + state = Write_DATA_0; // Continue remain at here if there is more write data received. + addr++; // Increment the address to store the value. + break; + + //Read frame to us + case Read_DATA_0: + addr++; + i2c_txNack(I2C_CTRL); + // Send second Read Value to Master + i2c_txByte(I2C_CTRL, data0[addr]); // Write selected register data back to master + state = Read_DATA_0; + break; + +#else // 1-Byte Register Address Selected + //Write frame to us + case Write_Addr_0: + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + //Get register address from Master + addr0 = i2c_rxData(I2C_CTRL); + state = Write_DATA_0; + break; + + case Write_DATA_0: + i2c_txAck(I2C_CTRL); + i2c_txByte(I2C_CTRL, 0xFF); + //Get Value from Master + data0[addr0] = i2c_rxData(I2C_CTRL); + state = Write_DATA_0; // Continue here if more data receiving from master + addr0++; // Increment the address to store the value. + break; + + //Read frame to us + case Read_DATA_0: + addr0++; + i2c_txNack(I2C_CTRL); + // Send second Read Value to Master + i2c_txByte(I2C_CTRL, data0[addr0]); + state = Read_DATA_0; + break; +#endif + + + } +} + +/****************************************************************************** +* +* @brief This function displays the content of the memory. It prints the memory content +* in a formatted manner, displaying 16 bytes per line with corresponding memory +* addresses. +* +******************************************************************************/ + +void display_memory_content() +{ + int i, j; + int count = 0; + + bsp_printf("\n\r 0 1 2 3 4 5 6 7 8 9 a b c d e f\n\r"); + for (i = 0; i < MEM_SIZE; i+=16) { + bsp_printf("%2x: ", i); + for (j = 0; j < 16; j++) { + bsp_printf("%2x ", data0[count++]); + } + bsp_printf("\n\r"); + } + + bsp_printf("\n\r"); +} + + +/****************************************************************************** +* +* @brief This main function initializes the system, sets up the I2C slave configuration, +* displays memory content, and waits for user input to display memory content. +* +******************************************************************************/ +void main() { + int n; + u32 irq_status; + char key; + + bsp_init(); + for(n=0;n> "); + key = uart_read(BSP_UART_TERMINAL); + if (key == 'i') { + display_memory_content(); + } + } +} +#else +/****************************************************************************** +* +* @brief This main function is executed when I2C functionality is disabled. +* It initializes the BSP and prints a message indicating that +* I2C 0 is disabled, and the user should enable it to run the app. +* +******************************************************************************/ + +void main() { + int n; + bsp_init(); + bsp_printf("i2c 0 is disabled, please enable it to run this app \r\n"); +} +#endif + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/userDef.h new file mode 100644 index 0000000..aa6ff55 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/i2cSlaveDemo/src/userDef.h @@ -0,0 +1,16 @@ +/******************************************************************************* +* +* @file i2cDemo.h +* +* @brief Header file defines I2C controller and interrupt depending on the +* availability of the current system. +* +*******************************************************************************/ + +#pragma once + +#ifdef SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + #define I2C_CTRL_PLIC_INTERRUPT SYSTEM_PLIC_SYSTEM_I2C_0_IO_INTERRUPT +#endif +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/makefile new file mode 100644 index 0000000..5a63815 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=rtcDemo + +STANDALONE=../.. + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/main.c new file mode 100644 index 0000000..d28d0df --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/main.c @@ -0,0 +1,387 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file main.c: rtcDemo +* +* @brief This demo uses the I2C peripheral to communicate with on-board PCF8523 RTC module +* on Ti375C529. It allows user to change various configuration such as real-time data +* with convertible 12/24hr time system, alarm, battery setting of the PCF8523 module +* if ENABLE_MAIN_MENU is set to 1 in peri.h else it will print the real-time data every +* few seconds. +* +* @note To run this example design, please make sure the following requirements are fulfilled: +* 1. Ti375C529 Dev Board +* 2. Enable UART0 and I2C0 +* +* User are allowed to configure certain parameters in peri.h (User defined Section) +* 1. I2C_FREQ => Frequency of I2C, default set to 100kHz +* 2. DEBUG_MODE => Print detail info for debug purpose if enabled. +* 3. ENABLE_MAIN_MENU => Allow user to select various configuration if enabled. +* +******************************************************************************/ + +#include +#include "bsp.h" +#include "io.h" +#include +#include "stdbool.h" +#include "i2c.h" + +//RTC Driver +#include "peri.h" +#include "device/pcf8523.h" + + +#ifdef SYSTEM_I2C_0_IO_CTRL +//Global variable +char new_line_detected = 0; +uint32_t counter = 0; +uint8_t buffer [200]; + + +void main() { + //Initialization + peri_init(); + i2c_init(); + Rtc_init(); + time_data myConfig; //Initialize timedata struct + uint8_t TIME_CONFIG = 0; + uint8_t stopper = 0; + states state = IDLE; + while (1) { + +#if(!ENABLE_MAIN_MENU) //Disable main menu to print real-time data every few seconds. + getdata(&myConfig); + bsp_printf("%d/%d/20%s%d \r\n", get_days(&myConfig), + get_months(&myConfig), (get_years(&myConfig)<10)? "0" : "",get_years(&myConfig)); + bsp_printf("%s,%d%s %s 20%s%d\r\n", + DayStrings[get_weekdays(&myConfig) - 1], get_days(&myConfig), + get_days_ordinalno(&myConfig), + MonthStrings[get_months(&myConfig) - 1], (get_years(&myConfig)<10)? "0" : "",get_years(&myConfig)); + if (myConfig.timesystem == 1){ + //12 hour time system is selected. + bsp_printf("Current Time: %d:%s%d:%s%d%s \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig), + (myConfig.PM) ? (meridiem[1]) : (meridiem[0])); + } + else{ + // 24 hour time system is selected + bsp_printf("Current Time: %d:%s%d:%s%d \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig)); + } + for (uint32_t i = 0; i < SYSTEM_CLINT_HZ; i++) + asm("nop"); //Show data every few seconds + } +} + +#else //Enable main menu for configuring time, etc + switch (state) { + case IDLE: //idle case wait for input to be 1 or 2 +#if(!DEBUG_MODE) + if ((checkalarmStatus() & !stopper)) { //Checking Alarm status when IDLE + bsp_printf("Alarm 1 is triggered! \r\n"); + stopper = 1; + } +#endif + if (new_line_detected) { + if (buffer[0] == '1' && counter == 1) { //Check Time + getdata(&myConfig); + bsp_printf("Showing current time now...\r\n"); + bsp_printf("%d/%d/20%s%d \r\n", get_days(&myConfig), + get_months(&myConfig), + (get_years(&myConfig) < 10) ? "0" : "", + get_years(&myConfig)); + bsp_printf("%s,%d%s %s 20%s%d\r\n", + DayStrings[get_weekdays(&myConfig) - 1], + get_days(&myConfig), get_days_ordinalno(&myConfig), + MonthStrings[get_months(&myConfig) - 1], + (get_years(&myConfig) < 10) ? "0" : "", + get_years(&myConfig)); + if (myConfig.timesystem) { + //12 hour time system is selected. + bsp_printf("Current Time: %d:%s%d:%s%d%s \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig), + (myConfig.PM) ? (meridiem[1]) : (meridiem[0])); + + } else { // 24 hour time system is selected + bsp_printf("Current Time: %d:%s%d:%s%d \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig)); + } + bsp_printf(SELECT_STRING); + state = IDLE; + } else if (buffer[0] == '2' && counter == 1) { //Check Alarm Status + getdata(&myConfig); + bsp_printf("Showing alarm status now...\r\n"); + uint8_t alarm_status = checkalarmStatus(); + if (alarm_status == 2) + bsp_printf("Alarm STATUS: Alarm is disabled! \r\n"); + else { + if (alarm_status == 0) + bsp_printf( + "Alarm STATUS: No Alarm is triggered! \r\n"); + if (alarm_status) + bsp_printf( + "Alarm STATUS: Alarm is triggered! \r\n"); + bsp_printf( + "Alarm TRIGGERED CONDITION: Triggered when the time is %d:%s%d%s,%s,%d/%d/20%s%d\r\n", + myConfig.AL_hours, + (myConfig.AL_minutes < 10) ? "0" : "", + myConfig.AL_minutes, + myConfig.timesystem ? + ((myConfig.AL_status) ? + (meridiem[1]) : (meridiem[0])) : + "", + DayStrings[myConfig.AL_weekdays - 1], + myConfig.AL_days, myConfig.months,(myConfig.years<10)? "0" : "", + myConfig.years); + } + bsp_printf("Back to main menu...\r\n\n"); + bsp_printf(SELECT_STRING); + state = IDLE; + + } else if (buffer[0] == '3' && counter == 1) { //Configure Time + bsp_printf( + "Default setting: 24hr TimeSystem\r\nConfiguring Time...\r\n"); + bsp_printf("Press enter to start configure\n\r"); + state = CONFIGURATION; + TIME_CONFIG = 1; + + } else if (buffer[0] == '4' && counter == 1) { //Configure Alarm + bsp_printf("Configuring Alarm...\r\n"); + bsp_printf("Press enter to start configure\n\r"); + state = CONFIGURATION; + TIME_CONFIG = 2; + + } else if (buffer[0] == '5' && counter == 1) { //Enable/reset + bsp_printf("Disable/reset Alarm...\r\n"); + bsp_printf("Press enter to start configure\n\r"); + state = CONFIGURATION; + TIME_CONFIG = 3; + } + + else if (buffer[0] == '6' && counter == 1) { //Change Time System + bsp_printf("Changing TimeSystem...\r\n"); + bsp_printf("Press enter to start configure\n\r"); + state = CONFIGURATION; + TIME_CONFIG = 4; + } + + else if (buffer[0] == '7' && counter == 1) { //Change Battery Mode + bsp_printf("Changing battery mode..\r\n"); + bsp_printf("Press enter to start configure\n\r"); + state = CONFIGURATION; + TIME_CONFIG = 5; + } else if (buffer[0] == '8' && counter == 1) { //Checking battery information + bsp_printf("\r\nChecking battery information now ! \r\n"); + print_battery_status_RTC(); + bsp_printf(SELECT_STRING); + state = IDLE; + } else if (buffer[0] == '9' && counter == 1) { //Checking battery information + bsp_printf("\r\nReseting now! \r\n"); + bsp_printf( + "\r\nPlease reconfigure the time if needed! \r\n"); + RTC_softreset(); + bsp_printf("Done! \r\n"); + bsp_printf(SELECT_STRING); + state = IDLE; + } else { + bsp_printf("Invalid input. Please try again...\r\r\n"); + bsp_printf(SELECT_STRING); + state = IDLE; + } + new_line_detected = 0; + counter = 0; + } + break; + case CONFIGURATION: //check if the input location is correct + if (new_line_detected) { + + if (TIME_CONFIG == 1) { + bsp_printf( + "Day of week\r\n1.Sunday\r\n2.Monday\r\n3.Tuesday\r\n4.Wednesday\r\n5.Thursday\r\n6.Friday\r\n7.Saturday\r\n"); + bsp_printf("Please set the value in 24hr time system.\r\n"); + bsp_printf( + "\r\nEnter value for time(h m s) and Day of week,days,month,year such as 14 20 00 1 16 10 23\ + that represent to 14:20 Sunday,16/10/2023 \r\n"); + state = GET_WRITE_DATA; + } + + else if (TIME_CONFIG == 2) { + bsp_printf("Please set the value in 24hr time system.\r\n"); + bsp_printf( + "\r\nEnter value for time(h m day weekday) such as 14 20 08 6 that represent to 14:20 Day 8,Friday \r\n"); + state = GET_WRITE_DATA; + } + + else if (TIME_CONFIG == 3) { + bsp_printf("Press 0 and enter to back to main menu\r\n"); + bsp_printf("Press 1 and enter to disable Alarm\r\n"); + bsp_printf("Press 2 and enter to reset Alarm\r\n"); + state = GET_WRITE_DATA; + } + + else if (TIME_CONFIG == 4) { + bsp_printf("Press 0 for 24hr TimeSystem \r\n"); + bsp_printf("Press 1 for 12hr TimeSystem \r\n"); + state = GET_WRITE_DATA; + } + + else if (TIME_CONFIG == 5) { + bsp_printf(BATTERY_STRING); + state = GET_WRITE_DATA; + } + } + new_line_detected = 0; + counter = 0; + break; + case GET_WRITE_DATA: + if (new_line_detected) { //Setting up temporary variable for user input value + uint8_t error = 0; + time_data temp; + temp.hours = (buffer[0] - UART_DECIMAL_OFFSET) * 10 + + (buffer[1] - UART_DECIMAL_OFFSET); + temp.minutes = (buffer[3] - UART_DECIMAL_OFFSET) * 10 + + (buffer[4] - UART_DECIMAL_OFFSET); + temp.seconds = (buffer[6] - UART_DECIMAL_OFFSET) * 10 + + (buffer[7] - UART_DECIMAL_OFFSET); + temp.weekdays = (buffer[9] - UART_DECIMAL_OFFSET); + temp.days = (buffer[11] - UART_DECIMAL_OFFSET) * 10 + + (buffer[12] - UART_DECIMAL_OFFSET); + temp.months = (buffer[14] - UART_DECIMAL_OFFSET) * 10 + + (buffer[15] - UART_DECIMAL_OFFSET); + temp.years = (buffer[17] - UART_DECIMAL_OFFSET) * 10 + + (buffer[18] - UART_DECIMAL_OFFSET); + temp.AL_status = (buffer[0] - UART_DECIMAL_OFFSET); + + switch (TIME_CONFIG) { + + case 0: + state = IDLE; + break; + + case 1: //Checking input for any error on Time Configuration + error = check_month_error(temp.months, temp.days, + temp.years); + if ((temp.hours > 23) | (temp.minutes > 59) + | (temp.seconds > 59) | (temp.weekdays < 1) + | (temp.weekdays > 7) | (temp.months > 12) + | (temp.days < 1) | (temp.months < 1) | (error)) { + bsp_printf("Invalid input, please try again\r\n"); + state = GET_WRITE_DATA; + break; + } else { + + bsp_printf("\n(24hour System) Time set to %d:%d:%d\r\n", + temp.hours, temp.minutes, temp.seconds); + bsp_printf("%s,%d %s 20%s%d\r\n", + DayStrings[temp.weekdays - 1], temp.days, + MonthStrings[temp.months - 1], (temp.years<10)? "0" : "",temp.years); + bsp_printf("Back to main menu\r\n"); + bsp_printf(SELECT_STRING); + set_timesystem(0); + set_datetime(temp.seconds, temp.minutes, temp.hours, + temp.weekdays, temp.days, temp.months, + temp.years); + TIME_CONFIG = 0; + bsp_printf(SELECT_STRING); + state = IDLE; + break; + } + case 2: //Checking input for any error on Alarm Configuration + if ((temp.hours > 23) | (temp.minutes > 59) + | (temp.days < 1) | (temp.weekdays > 7)) { + bsp_printf("Invalid input, please try again\r\n"); + state = GET_WRITE_DATA; + break; + } else { //Reset first before enable Alarm again + alarmClearFlag(); + stopper = 0; + if (myConfig.timesystem == 1) { + set_timesystem(0); + alarmSet(temp.minutes, temp.hours, temp.seconds, + temp.weekdays); + set_timesystem(1); + } else + alarmSet(temp.minutes, temp.hours, temp.seconds, + temp.weekdays); + TIME_CONFIG = 0; + state = IDLE; + bsp_printf("Done configure !\r\n"); + bsp_printf("Back to main menu\r\n"); + bsp_printf(SELECT_STRING); + break; + } + case 3: // Alarm + if (temp.AL_status == 1) { // Disable alarm + bsp_printf("Alarm is disabled\r\n"); + alarmDisable(); + } else if (temp.AL_status == 2) { //Reset alarm + bsp_printf("Alarm is reset\r\n"); + alarmClearFlag(); + } else + bsp_printf("Invalid input\r\n"); + state = IDLE; + bsp_printf("Back to main menu\r\n"); + bsp_printf(SELECT_STRING); + break; + + case 4: //Change Time System + if (temp.AL_status > 1) + bsp_printf("Invalid input\r\n"); + else + set_timesystem(temp.AL_status); + state = IDLE; + bsp_printf("Back to main menu\r\n"); + bsp_printf(SELECT_STRING); + break; + + case 5: // Change battery Mode + if (temp.AL_status > 3) + bsp_printf("Invalid input\r\n"); + else { + battery_mode_RTC(temp.AL_status); + bsp_printf( + "Battery Mode %d is selected , Back to main menu\r\n", + temp.AL_status); + } + state = IDLE; + bsp_printf(SELECT_STRING); + break; + } + new_line_detected = 0; + counter = 0; + + } + break; + } + } + +} +#endif +#else +void main() { + bsp_init(); + bsp_printf("i2c 0 is disabled, please enable it to run this app. \r\n"); +} +#endif + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.c new file mode 100644 index 0000000..1df80cd --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.c @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file peri.c + +* @brief This file is used for system intialization and interrupt handler. +* +* The available functions are: +* - peri_init : Initiates the configuration of UART. +* - i2c_init : Initiates the configuration of I2C. +* - RTC_init : Initiates battery switch-over and battery low detection +* function and it also check battery information. +* - uartIsr() : Handles UART interrupt sub-events such as TX FIFO +* empty interrupt and RX FIFO not empty interrupt. +* - isrRoutine() : Handles UART interrupts by claiming pending interrupts +* and processing them through UartInterrupt_Sub(). +* - crash : Handles the system crash scenario by printing a crash +* message and entering an infinite loop. +* - trap : Handles exceptions and interrupts in the system. +* +******************************************************************************/ + +#include "bsp.h" +#include "io.h" +#include "i2c.h" +#include "peri.h" +#include "plic.h" + +/******************************** System Initialization ***********************************************/ + +/****************************************************************************** +* +* @brief This function initiates the configuration of UART. + +* @param uartA.dataLength => Enumerated value indicating the data length configuration. +* @param uartA.parity => Enumerated value indicating the parity configuration. +* @param uartA.stop => Enumerated value indicating the stop bit configuration. +* @param uartA.clockDivider => Clock divider value for UART communication. +* @return None. +* +******************************************************************************/ +void peri_init() { + //int notInterrupt_count = 0; + Uart_Config uartA; + uartA.dataLength = BITS_8; + uartA.parity = NONE; + uartA.stop = ONE; + uartA.clockDivider = BSP_CLINT_HZ / (115200 * UART_0_SAMPLE_PER_BAUD) - 1; + uart_applyConfig(BSP_UART_TERMINAL, &uartA); + + // RX FIFO not empty interrupt enable + uart_RX_NotemptyInterruptEna(BSP_UART_TERMINAL,1); + + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + + // Enable SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT rising edge interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT, 1); + + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + // Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This function initiates the configuration of I2C by setting it to 100kHz. +* +* @param i2c.samplingClockDivider => Sampling rate = (FCLK/(samplingClockDivider + 1). +* => Controls the rate at which the I2C controller samples SCL/SDA. +* @param i2c.timeout => Inactive timeout clock cycle. +* => Setting the timeout value to zero will disable the timeout feature. +* @param i2c.tsuDat => Data setup time. +* @param i2c.tLow => The number of clock cycles of SCL in LOW state. +* @param i2c.tHigh => The number of clock cycles of SCL in HIGH state. +* @param i2c.tBuf => The number of clock cycles delay before master can initiate a +* START bit after a STOP bit is issued. +* @return None. +* +******************************************************************************/ +void i2c_init() { + + I2c_Config i2c_mipi; + int freq = I2C_FREQ; + i2c_mipi.samplingClockDivider = 3; + i2c_mipi.timeout = I2C_CTRL_HZ/1000; + i2c_mipi.tsuDat = I2C_CTRL_HZ/(I2C_FREQ*5); + + /* T_low & T_high = i2c period / 2 */ + i2c_mipi.tLow = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c_mipi.tHigh = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c_mipi.tBuf = I2C_CTRL_HZ/(I2C_FREQ); + + i2c_applyConfig(I2C_CTRL, &i2c_mipi); +} + +/****************************************************************************** +* +* @brief This function initiates battery switch-over and battery low detection +* function and it also check battery information. +* +* @return None. +* +******************************************************************************/ +void Rtc_init() { + bsp_printf("Welcome to RTC Demo for Ti375C529\r\n\n"); + bsp_printf("************START OF SYSTEM INITIALIZATION************\r\n"); + + //Checking control register + bsp_printf("\r\nChecking CR information now ! \r\n"); + readCR_RTC(); + + //Enable battery switch-over and battery low detection function + bsp_printf("\r\nEnable battery switch-over!\r\nEnable battery low detection function! \r\n"); + battery_mode_RTC(3); + + //Checking battery information + bsp_printf("\r\nChecking battery information now ! \r\n"); + print_battery_status_RTC(); + bsp_printf("*************END OF SYSTEM INITIALIZATION*************\r\n\n\n"); + +#if (ENABLE_MAIN_MENU) + bsp_printf(SELECT_STRING); +#else + bsp_printf("Showing time data now!\r\n"); +#endif + + +} + +/******************************** Interrupt Handler ***********************************************/ + +/****************************************************************************** +* +* @brief This function handles UART interrupt sub-events such as TX FIFO +* empty interrupt and RX FIFO not empty interrupt. +* +******************************************************************************/ +void uartIsr() +{ + if (uart_status_read(BSP_UART_TERMINAL) & 0x00000100){ + + // Disable TX FIFO empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) & 0xFFFFFFFE); + // Enable TX FIFO empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) | 0x01); + + } + else if (uart_status_read(BSP_UART_TERMINAL) & 0x00000200){ + + // Disable RX FIFO not empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) & 0xFFFFFFFD); + // Read to clear RX FIFO + char uart_read_data = uart_read(BSP_UART_TERMINAL); + uart_write(BSP_UART_TERMINAL, uart_read_data); + + if(uart_read_data == '\r'){ //if newline detected + new_line_detected = 1; + uart_write(BSP_UART_TERMINAL, '\r'); + } + else{ + buffer[counter] = uart_read_data; + counter++; + } + // Enable RX FIFO not empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) | 0x02); + + } +} + +/****************************************************************************** +* +* @brief This function handles UART interrupts by claiming pending interrupts +* and processing them through uartIsr(). +* +******************************************************************************/ +void isrRoutine() +{ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT: uartIsr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash +* message and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + // Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.h new file mode 100644 index 0000000..2b04741 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/rtcDemo/src/peri.h @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file peri.h +* +* @brief Header file contain function prototype for interrupt handler and some +* parameter that used for RTCDriver_C529Demo. +* +* +******************************************************************************/ +#include "riscv.h" +#include "plic.h" +#include "clint.h" + +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ +#define I2C_CTRL SYSTEM_I2C_0_IO_CTRL +#define UART_0_SAMPLE_PER_BAUD 8 +#define UART_DECIMAL_OFFSET 48 + +#include "device/pcf8523.h" + +//Global Variables +extern char new_line_detected ; +extern uint32_t counter ; +extern uint8_t buffer [200] ; + +//User Defined +#define I2C_FREQ 100000 //100kHz +#define DEBUG_MODE 0 //Enable Debug Mode for detail printing +#define ENABLE_MAIN_MENU 1 //Disable main menu at default + +//Main Menu Strings +#define SELECT_STRING "************Rtc Demo Main Menu*************** \r\n" \ + "Please key in the selection and press enter: \r\n" \ + "1: Check Time 2: Check Alarm 3: Configure Time\r\n" \ + "4: Set Alarm 5: Disable/Reset Alarm \r\n" \ + "6: Change TimeSystem (12/24hrs)\r\n" \ + "7: Change Battery mode \r\n" \ + "8: Check Battery information \r\n" \ + "9: Soft Reset on RTC module \r\n" \ + "***************************************** \r\n\n" + +//Structure for RTCdemo +typedef enum { + IDLE, + CONFIGURATION, + GET_WRITE_DATA +} states; + + +extern states state ; + +//Function prototype +void crash(); +void trap(); +void trap_entry(); +void uartIsr(); +void isrRoutine(); +void i2c_init(); +void peri_init(); +void Rtc_init(); + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/makefile new file mode 100644 index 0000000..9a60bf5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/makefile @@ -0,0 +1,15 @@ +PROJ_NAME=temperatureSensorDemo + +STANDALONE= ../.. + + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/main.c new file mode 100644 index 0000000..89e9f89 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/main.c @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file main.c: temperatureSensorDemo +* +* @brief This demo uses the I2C peripheral to communicate with on-board EMC1413 Temperature +* module on Ti375C529. It print out the temperature of the device on terminal every +* few seconds and alerts user if the temperature of the device exceed above the high +* temperature limit. +* +* @note To run this example design, please make sure the following requirements are fulfilled: +* 1. Ti375C529 Dev Board +* 2. Enable UART0 and I2C0 +* +* User are allowed to configure certain parameters in peri.h (User defined Section) +* 1. I2C_FREQ => Frequency of I2C, default set to 100kHz +* 2. DEBUG_MODE => Print detail info if enabled. +* 3. EXTENDED_RANGE_ENABLED =>If set to 0, means range of temp measurement from 0°C to +127°C (Default) +* =>If set to 1, means range of temp measurement from -64°C to +191°C (Extended Range enabled) +* +* 4. HIGH_TEMPERATURE_LIMIT_VALUE_INT => High limit temp for internal temperature sensor in EMC1413 itself. +* 5. LOW_TEMPERATURE_LIMIT_VALUE_INT => Low limit temp for temperature sensor 1 on Ti375C529. +* 6. HIGH_TEMPERATURE_LIMIT_VALUE_EXT1 => High limit temp for internal temperature sensor in EMC1413 itself. +* 7. LOW_TEMPERATURE_LIMIT_VALUE_EXT1 => Low limit temp for temperature sensor 1 on Ti375C529. +* 8. HIGH_TEMPERATURE_LIMIT_VALUE_EXT2 => High limit temp for internal temperature sensor in EMC1413 itself. +* 9. LOW_TEMPERATURE_LIMIT_VALUE_EXT2 => Low limit temp for temperature sensor 1 on Ti375C529. +* +* +******************************************************************************/ + +#include +#include "bsp.h" +#include "io.h" +#include +#include "stdbool.h" +#include "i2c.h" + +//Temperature Driver +#include "peri.h" + + +void main() +{ + //System Initialization + peri_init(); + i2c_init(); + temp_init(); + temperature_data temp; + + while(1){ + + get_tempdata(&temp); + bsp_printf("\r\n"); + bsp_printf("Internal temperature in EMC1413 module : %f°C\r\n", temp.int_HL_temp); + bsp_printf("Temperature sensor 1 on Ti375C529 dev kit: %f°C\r\n", temp.ext1_HL_temp); + bsp_printf("Temperature sensor 2 on Ti375C529 dev kit: %f°C\r\n", temp.ext2_HL_temp); + if (check_lowtemp_alert()) bsp_printf("[WARNING]:Temperature of the device dropped below low limit temperature !!!\r\n"); + if (check_hightemp_alert()) bsp_printf("[WARNING]:Temperature of the device exceed the high limit temperature !!!\r\n"); + for (uint32_t i = 0; i < SYSTEM_CLINT_HZ; i++) + asm("nop"); //Show data every few seconds + }; + +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.c new file mode 100644 index 0000000..2566924 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.c @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file peri.c + +* @brief This file is used for system initialization and interrupt handler. +* +* The available functions are: +* - peri_init : Initiates the configuration of UART. +* - i2c_init : Initiates the configuration of I2C. +* - temp_init : Initiates temperature module. +* +******************************************************************************/ + +#include "bsp.h" +#include "io.h" +#include "i2c.h" +#include "peri.h" + +/******************************** System Initialization ***********************************************/ + +/****************************************************************************** +* +* @brief This function initiates the configuration of UART. + +* @param uartA.dataLength => Enumerated value indicating the data length configuration. +* @param uartA.parity => Enumerated value indicating the parity configuration. +* @param uartA.stop => Enumerated value indicating the stop bit configuration. +* @param uartA.clockDivider => Clock divider value for UART communication. +* @return None. +* +******************************************************************************/ +void peri_init() { + //int notInterrupt_count = 0; + Uart_Config uartA; + uartA.dataLength = BITS_8; + uartA.parity = NONE; + uartA.stop = ONE; + uartA.clockDivider = BSP_CLINT_HZ / (115200 * UART_0_SAMPLE_PER_BAUD) - 1; + uart_applyConfig(BSP_UART_TERMINAL, &uartA); + +} + +/****************************************************************************** +* +* @brief This function initiates the configuration of I2C by setting it to 100kHz. +* +* @param i2c.samplingClockDivider => Sampling rate = (FCLK/(samplingClockDivider + 1). +* => Controls the rate at which the I2C controller samples SCL/SDA. +* @param i2c.timeout => Inactive timeout clock cycle. +* => Setting the timeout value to zero will disable the timeout feature. +* @param i2c.tsuDat => Data setup time. +* @param i2c.tLow => The number of clock cycles of SCL in LOW state. +* @param i2c.tHigh => The number of clock cycles of SCL in HIGH state. +* @param i2c.tBuf => The number of clock cycles delay before master can initiate a +* START bit after a STOP bit is issued. +* @return None. +* +******************************************************************************/ +void i2c_init() { + + I2c_Config i2c_mipi; + int freq = I2C_FREQ; + i2c_mipi.samplingClockDivider = 3; + i2c_mipi.timeout = I2C_CTRL_HZ/1000; + i2c_mipi.tsuDat = I2C_CTRL_HZ/(I2C_FREQ*5); + + /* T_low & T_high = i2c period / 2 */ + i2c_mipi.tLow = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c_mipi.tHigh = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c_mipi.tBuf = I2C_CTRL_HZ/(I2C_FREQ); + + i2c_applyConfig(I2C_CTRL, &i2c_mipi); +} + +/****************************************************************************** +* +* @brief This function initiates temperature module. +* +* @return None. +* +******************************************************************************/ +void temp_init() { + temperature_data temp_limit; + + bsp_printf("Welcome to Temperature Demo for Ti375C529\r\n\n"); + bsp_printf("********************START OF CONFIGURATION***********************\r\n\n"); + + //Checking control register + bsp_printf("Checking info of the EMC1413 module! \r\n"); + //bsp_printf("*****************************************\r\n"); + bsp_printf("Product ID of temperature sensor:%x \r\n",readtemp_reg(PRODUCT_ID)); + bsp_printf("Status register:%x \r\n",readtemp_reg(STATUS_REG)); + bsp_printf("Config register:%x \r\n\n",readtemp_reg(CONFIG_REG)); + + //Configure range of the temperature measurement + config_temprange_reg(EXTENDED_RANGE_ENABLED); + + //Set the high/low temperature limit for the sensors. + bsp_printf("Setting up high/low temperature limit! \r\n"); + //bsp_printf("*****************************************\r\n"); + set_templimit(HIGH_TEMPERATURE_LIMIT_VALUE_INT,LOW_TEMPERATURE_LIMIT_VALUE_INT,0); + set_templimit(HIGH_TEMPERATURE_LIMIT_VALUE_EXT1,LOW_TEMPERATURE_LIMIT_VALUE_EXT1,1); + set_templimit(HIGH_TEMPERATURE_LIMIT_VALUE_EXT2,LOW_TEMPERATURE_LIMIT_VALUE_EXT2,2); + + //Checking temperature limit + get_templimit(&temp_limit); + bsp_printf("Set High Temperature limit in internal EMC1413 sensor: %f°C \r\n",temp_limit.int_HL_temp); + bsp_printf("Set High Temperature limit on temperature sensor 1 : %f°C \r\n",temp_limit.ext1_HL_temp); + bsp_printf("Set High Temperature limit on temperature sensor 2 : %f°C \r\n",temp_limit.ext2_HL_temp); + + bsp_printf("Set Low Temperature limit in internal EMC1413 sensor : %f°C \r\n",temp_limit.int_LL_temp); + bsp_printf("Set Low Temperature limit on temperature sensor 1 : %f°C \r\n",temp_limit.ext1_LL_temp); + bsp_printf("Set Low Temperature limit on temperature sensor 2 : %f°C \r\n",temp_limit.ext2_LL_temp); + + if (check_temprange_reg()) bsp_printf("\r\nRange of the temperature measurement: Extended Range (-64°C to +191°C)\r\n"); + else bsp_printf("\r\nRange of the temperature measurement: Default Range (0°C to +127°C)\r\n"); + bsp_printf("\n********************END OF CONFIGURATION***********************\r\n"); + +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.h new file mode 100644 index 0000000..3f5d95e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/i2c/temperatureSensorDemo/src/peri.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file peri.h +* +* @brief Header file contain function prototype for interrupt handler and some +* parameter that used for TemperatureDriver_C529Demo. +* +* +******************************************************************************/ + +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ +#define I2C_CTRL SYSTEM_I2C_0_IO_CTRL + +#include "device/emc1413.h" + +#define UART_0_SAMPLE_PER_BAUD 8 +#define UART_DECIMAL_OFFSET 48 + + + +/********************************************RULES FOR CONFIGURING PARAMETERS*************************************************** +* +* @brief When configuring high/low temperature limit value, here are some of the rules to follow: +* +* -> It will ignored negative defined input with decimal when extended range mode is enabled. eg, defined input of -60.25°C will be recognize as -60°C. +* -> High/Low temp.limit defined input for internal sensor are in integer format, meaning it will simply extract int part from defined input with decimal into reg. +* -> Default value will be set if defined input is invalid. +* -> Default value for low limit temp is 0°C. +* -> Default value for high limit temp is 85°C. +* -> The resolution of limit temp is 0.125°C. +******************************************************************************************************************************/ +//User Defined +#define I2C_FREQ 100000 //100kHz +#define EXTENDED_RANGE_ENABLED 0 //If set to 0, means range of temp measurement from 0°C to +127°C (Default) + //If set to 1, means range of temp measurement from -64°C to +191°C (Extended Range enabled) +#define HIGH_TEMPERATURE_LIMIT_VALUE_INT 85 //High limit temp for internal temperature sensor in EMC1413 itself. +#define LOW_TEMPERATURE_LIMIT_VALUE_INT 0 //Low limit temp for temperature sensor 1 on Ti375C529. + +#define HIGH_TEMPERATURE_LIMIT_VALUE_EXT1 85 //High limit temp for internal temperature sensor in EMC1413 itself. +#define LOW_TEMPERATURE_LIMIT_VALUE_EXT1 0 //Low limit temp for temperature sensor 1 on Ti375C529. + +#define HIGH_TEMPERATURE_LIMIT_VALUE_EXT2 85 //High limit temp for internal temperature sensor in EMC1413 itself. +#define LOW_TEMPERATURE_LIMIT_VALUE_EXT2 0 //Low limit temp for temperature sensor 1 on Ti375C529. + +//Function prototype +void i2c_init(); +void peri_init(); +void temp_init(); + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/makefile new file mode 100644 index 0000000..fba21c8 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/makefile @@ -0,0 +1,21 @@ +PROJ_NAME=fatFSDemo + +STANDALONE=../.. +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + $(wildcard ${BSP_PATH}/app/fatfs/*.c) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + +CFLAGS += -Isrc +CFLAGS += -I${BSP_PATH}/app/fatfs + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.c new file mode 100644 index 0000000..44a422a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.c @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "intc.h" + +IntStruct IntPtr; +struct sd_ctrl_dev *dev; +char new_line_detected = 0; +uint32_t counter = 0; +uint8_t buffer [20]; +/************************** Function Definitions *****************************/ +void trap_entry(); + +/********************************* Function **********************************/ +void externalInterrupt() +{ + u32 int_status; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,0x00); + + int_status = sd_ctrl_read(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0); + + if(int_status&INT_COMMAND_COMPLETE) { + IntPtr.command_complete = 0x1; + + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_COMPLETE); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : COMMAND_COMPLETE\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_TRANSFER_COMPLETE) { + IntPtr.transfer_complete = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_TRANSFER_COMPLETE); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : TRANSFER_COMPLETE\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_BLOCK_GAP_EVENT) { + IntPtr.block_gap_event = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BLOCK_GAP_EVENT); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : BLOCK_GAP_EVENT\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_BUFFER_WRITE_READY) { + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_WRITE_READY); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : BUFFER_WRITE_READY\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_BUFFER_READ_READY) { + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_READ_READY); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : BUFFER_READ_READY\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + if(int_status&INT_CARD_INSERTION) { + IntPtr.card_insertion = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_INSERTION); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : CARD_INSERTION\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_CARD_REMOVAL) { + IntPtr.card_removal = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_REMOVAL); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : CARD_REMOVAL\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + if(int_status&INT_COMMAND_TIMEOUT_ERROR) { + IntPtr.command_timeout_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_TIMEOUT_ERROR); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : COMMAND_TIMEOUT_ERROR\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + if(int_status&INT_COMMAND_CRC_ERROR) { + IntPtr.command_crc_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_CRC_ERROR); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : COMMAND_CRC_ERROR\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + if(int_status&INT_COMMAND_END_BIT_ERROR) { + IntPtr.command_end_bit_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_END_BIT_ERROR); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : COMMAND_END_BIT_ERROR\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + if(int_status&INT_COMMAND_INDEX_ERROR) { + IntPtr.command_index_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_INDEX_ERROR); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : COMMAND_INDEX_ERROR\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + } + + if(int_status&INT_DATA_CRC_ERROR) { + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_DATA_CRC_ERROR); +#if(DEBUG_PRINTF_EN == 1) + bsp_printf("INT : DATA_CRC_ERROR\n\r"); +#endif //(DEBUG_PRINTF_EN == 1) + + } + + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); +} + + +/********************************* Function **********************************/ +//Used on unexpected trap/interrupt codes +void crash(){ + bsp_printf("\n*** CRASH ***\n"); + while(1); +} + +void userInterrupt(){ + uint32_t claim; + //While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SDHC_INTERRUPT:externalInterrupt(); break; + default: crash(); break; + } + //unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +//Called by trap_entry on both exceptions and interrupts events +void trap(){ + int32_t mcause = csr_read(mcause); + //Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: userInterrupt(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void IntcInitialize(struct mmc *mmc) +{ + dev=mmc->priv; + + //configure PLIC + //cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SDHC_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, SDHC_INTERRUPT, 1); + + //enable riscV interrupts + //Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + //Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); + + //enable User interrupts + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,0x00); //Clean All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,INT_ENABLE); //Enable All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); //Open All Interrupts Signal +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.h new file mode 100644 index 0000000..8ab51de --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/intc.h @@ -0,0 +1,18 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#ifndef HEADER_INTC_H_ +#define HEADER_INTC_H_ + +#include +#include "bsp.h" +#include "plic.h" +#include "riscv.h" +#include "efx_mmc_driver.h" +#include "userDef.h" + +void IntcInitialize(); + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/main.c new file mode 100644 index 0000000..e226ae4 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/main.c @@ -0,0 +1,847 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************* +* +* @file main.c: fatFSDemo +* +* @brief This demo implements the FatFS File System along with a Command Line Interface (CLI) +* for user interaction. It utilizes the SD Host Controller for disk layer I/O to communicate +* with the SD Card.Upon execution, the example automatically initializes the SD Host Controller +* and the FATFS. Additionally, it integrates with the RTC module on-board, providing the current +* time for file and folder creation. +* You may enter "?" into the UART Terminal to list the supported commands. +* The printOrSetRTCTime function allows you to print the current time and date by entering "t". +* If you enter "t" followed by the desired time and date parameters (, , , +* , , , ), you can set the RTC accordingly. +* The should be entered as follows: +* 1: Sunday +* 2: Monday +* 3: Tuesday +* 4: Wednesday +* 5: Thursday +* 6: Friday +* 7: Saturday +* If the arguments are incorrect, the system will prompt you to enter the parameters line by line. +* +* @note To run this example design, please make sure the following requirements are fulfilled: +* 1. Ti375C529 Dev Board +* 2. FAT32 Formatted SD Card inserted to SD1 slot +* +* User are allowed to configure certain parameters in userDef.h (User defined Section) +* 1. DEBUG_PRINTF_EN => To enable debug messages +* 2. DMA_MODE => To use DMA mode if uncomment, comment out to use PIO mode (DMA mode is recommended due to its higher speed) +* +* To configure FatFS related configuration, please modify in /efinix/EfxSapphireSoc/app/fatfs/ffconf.h +* +******************************************************************************/ + +#include +#include +#include +#include "bsp.h" +#include "userDef.h" +#include "intc.h" +#include "mmc.h" +#include "uart.h" +#include "i2c.h" +#include "efx_mmc_driver.h" +#include "fatfs/ff.h" +#include "fatfs/diskio.h" +#include "fatfs/xprintf.h" +#include "vexriscv.h" + + +struct mmc *mmc; +struct mmc_cmd *xmmc_cmd; +struct mmc_data *data; +struct mmc_config *cfg; +struct mmc_ops *ops; + +void put_rc (FRESULT rc); +void putChar(char c); + +char Buff[BLOCK_SIZE*MAX_BLK_BUF] __attribute__ ((aligned (4))) ; + +char Line[256]; +FATFS FatFs; /* File system object for each logical drive */ +FIL File[2]; /* File objects */ +DIR Dir; /* Directory object */ +FILINFO Finfo; +volatile UINT Timer; + +void init(){ + + bsp_init(); + + I2c_Config i2c; + i2c.samplingClockDivider = 3; + i2c.timeout = I2C_CTRL_HZ/1000; + i2c.tsuDat = I2C_CTRL_HZ/(I2C_FREQ*5); + /* T_low & T_high = i2c period / 2 */ + i2c.tLow = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c.tHigh = I2C_CTRL_HZ/(I2C_FREQ*2); + i2c.tBuf = I2C_CTRL_HZ/(I2C_FREQ); + i2c_applyConfig(I2C_CTRL, &i2c); + +} + +void putChar(char c) { + bsp_printf("%c", c); +} + +void put_rc (FRESULT rc) { + const char *str = + "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0" + "INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0" + "INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0" + "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0" "INVALID_PARAMETER\0"; + FRESULT i; + + for (i = 0; i != rc && *str; i++) { + while (*str++) ; + } + bsp_printf("rc=%u\n", (UINT)rc); + bsp_printf("FR_%s\n\r", str); +} + +/*--------------------------------------------------------------------------*/ +/* Monitor */ +/*--------------------------------------------------------------------------*/ + +static FRESULT scan_files ( + char* path, /* Pointer to the path name working buffer */ + UINT* n_dir, + UINT* n_file, + QWORD* sz_file +) +{ + DIR dirs; + FRESULT res; + BYTE i; + + + if ((res = f_opendir(&dirs, path)) == FR_OK) { + i = strlen(path); + while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) { + if (Finfo.fattrib & AM_DIR) { + (*n_dir)++; + *(path+i) = '/'; strcpy(path+i+1, Finfo.fname); + res = scan_files(path, n_dir, n_file, sz_file); + *(path+i) = '\0'; + if (res != FR_OK) break; + } else { + (*n_file)++; + *sz_file += Finfo.fsize; + } + } + } + + return res; +} + + +/****************************************************************************** + * + * @brief Manages Real Time Clock features + * + * This function handles Real Time Clock features. If 't' is input without any + * argument, it prints the current date and time. If 't' is followed by correct + * arguments, it attempts to configure the RTC. To configure the RTC argument + * by argument, input 't' followed by any number, e.g., "t 1". + * + * @param ptr Pointer to characters input by user + * @return true if no error; false if an error occurred + * + ******************************************************************************/ +bool printOrSetRTCTime(char* ptr){ + long p[7] = {0}; // Initialize all elements to 0 + int i; + + // Passing each argument into p array + for (i = 0; i < 7; i++) { + xatoi(&ptr, &p[i]); + } + + // If there is no argument provided by the user, print the current time from RTC + if (!p[0] && !p[1] && !p[2] && !p[3] && !p[4] && !p[5] && !p[6]) { + getdata(&myConfig); + bsp_printf("%d/%d/20%s%d \r\n", get_days(&myConfig), + get_months(&myConfig), (get_years(&myConfig)<10)? "0" : "",get_years(&myConfig)); + bsp_printf("%s,%d%s %s 20%s%d\r\n", + DayStrings[get_weekdays(&myConfig) - 1], get_days(&myConfig), + get_days_ordinalno(&myConfig), + MonthStrings[get_months(&myConfig) - 1], (get_years(&myConfig)<10)? "0" : "",get_years(&myConfig)); + if (myConfig.timesystem == 1){ + //12 hour time system is selected. + bsp_printf("Current Time: %d:%s%d:%s%d%s \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig), + (myConfig.PM) ? (meridiem[1]) : (meridiem[0])); + } + else{ + // 24 hour time system is selected + bsp_printf("Current Time: %d:%s%d:%s%d \r\n\n", + get_hours(&myConfig), + (get_minutes(&myConfig) < 10) ? "0" : "", + get_minutes(&myConfig), + (get_seconds(&myConfig) < 10) ? "0" : "", + get_seconds(&myConfig)); + } + return true; + } + // Configure the time and date based on the input + else { //if (!p[0] && !p[1] && !p[2] && !p[3] && !p[4] && !p[5] && !p[6]) + u8 config = 0x01; + u8 setting = STATE_HOUR; + u8 single_line_setting_pass = 0x00; + time_data temp; + // If all argument are there, use the argument parsed in + if (p[3] && p[4] && p[5] && p[6]){ + uint8_t error = 0; + time_data temp; + temp.hours = p[0]; + temp.minutes = p[1]; + temp.seconds = p[2]; + temp.weekdays = p[3]; + temp.days = p[4]; + temp.months = p[5]; + temp.years = p[6]; + temp.AL_status = p[0]; + + error = check_month_error(temp.months, temp.days, temp.years); + if ((temp.hours > 23) | (temp.minutes > 59) | (temp.seconds > 59) | (temp.weekdays < 1) | (temp.weekdays > 7) | (temp.months > 12) | (temp.days < 1) | (temp.months < 1) | (error)) { + bsp_printf("Invalid input, please try again... \r\n"); + single_line_setting_pass = 0x00; + } else { + bsp_printf("\n(24hour System) Time set to %d:%d:%d\r\n", temp.hours, temp.minutes, temp.seconds); + bsp_printf("%s,%d %s 20%s%d\r\n", DayStrings[temp.weekdays - 1], temp.days, MonthStrings[temp.months - 1],(temp.years < 10) ? "0" : "", temp.years); + set_timesystem(0); + set_datetime(temp.seconds, temp.minutes, temp.hours, \ + temp.weekdays, temp.days, temp.months, \ + temp.years); + single_line_setting_pass = 0x01; + } + } + + // If failed during configuration or user did not provide correct argument, configure each argument 1 by 1 + // User may press q or Q to exit the configuration. + if (!single_line_setting_pass){ + bsp_printf("Invalid input. Retrying configuration...\r\n"); + bsp_printf("Press 'q' or 'Q' to exit configuration\r\n"); + while (config){ + switch (setting){ + + case STATE_HOUR: // configure hours + bsp_printf("Enter Current Hour in 24-Hour Time System, i.e. 13 indicates current time 1P.M.\r\n"); + Line[0] = 0x00; // Reset the first char + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + } else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } + else { + temp.hours = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + if (temp.hours > 24){ + bsp_printf("Invalid input, please try again\r\n"); + }else { + bsp_printf("Configured to %d hour\r\n", temp.hours); + setting = STATE_MINUTES; + } + + } + break; + + case STATE_MINUTES: // configure minutes + bsp_printf("Enter Current Minutes, i.e. 00\r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + } else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + temp.minutes = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + if (temp.minutes > 59){ + bsp_printf("Invalid input, please try again\r\n"); + }else { + bsp_printf("Configured to %d minutes\r\n", temp.minutes); + setting = STATE_SECONDS; + } + + } + break; + + case STATE_SECONDS: // configure minutes + bsp_printf("Enter Current Seconds, i.e. 00\r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + } else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + temp.seconds = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + if (temp.seconds > 59){ + bsp_printf("Invalid input, please try again\r\n"); + }else { + bsp_printf("Configured to %d seconds\r\n", temp.seconds); + setting = STATE_WEEK_DAY; + } + } + + break; + + case STATE_WEEK_DAY: //configure weekdays + bsp_printf("Enter Current day of the week\r\n"); + bsp_printf("Day of week\r\n1.Sunday\r\n2.Monday\r\n3.Tuesday\r\n4.Wednesday\r\n5.Thursday\r\n6.Friday\r\n7.Saturday\r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + }else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + temp.weekdays = ptr[0] - UART_DECIMAL_OFFSET; + if (temp.weekdays == 0 || temp.weekdays > 7 ){ + bsp_printf("Invalid input, please try again\r\n"); + }else { + bsp_printf("Configured to %s\r\n",DayStrings[temp.weekdays - 1]); + setting = STATE_DAYS; + } + } + + break; + + case STATE_DAYS: //configure days + bsp_printf("Enter Current day of the month, i.e. 01 for first day of the month \r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + temp.days = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + if (temp.days < 1 || temp.days > 31){ + bsp_printf("Invalid input, please try again\r\n"); + }else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + bsp_printf("Configured to date %d\r\n",temp.days); + setting = STATE_MONTH; + } + break; + + case STATE_MONTH: //configure month + bsp_printf("Enter Current month, i.e. January = 1; February = 2 ... \r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + } else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + if (ptr[1] == 0){ + temp.months = ptr[0] - UART_DECIMAL_OFFSET; + }else { + temp.months = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + } + + if (temp.months > 12){ + bsp_printf("Invalid input, please try again\r\n"); + }else { + setting = STATE_YEAR; + bsp_printf("Configured to month %s\r\n",MonthStrings[temp.months - 1]); + } + } + + break; + + case STATE_YEAR: // configure year + bsp_printf("Enter Current year, i.e. 24 indicates year 2025\r\n"); + Line[0] = 0x00; + xgets(Line, sizeof Line); + ptr = Line; + if (ptr[0]== ASCII_LOWER_CASE_Q || ptr[0]== ASCII_UPPER_CASE_Q) { //exit with q or Q + setting = STATE_EXIT; + } else if (Line[0] == 0x00){ // If user directly enter + bsp_printf("Invalid input, please try again\r\n"); + } else { + temp.years = (ptr[0] - UART_DECIMAL_OFFSET) * 10 + (ptr[1] - UART_DECIMAL_OFFSET); + bsp_printf("Configured to year 20%s%d\r\n", (temp.years<10)? "0" : "",temp.years); + setting = STATE_CONFIG; + } + + break; + + case STATE_CONFIG: + set_timesystem(0); + set_datetime(temp.seconds, temp.minutes, temp.hours, temp.weekdays, temp.days, temp.months, temp.years); + bsp_printf("RTC configuration successful...\r\n"); + setting = STATE_HOUR; + config = 0x00; + continue; + break; + + case STATE_EXIT: + bsp_printf("Failed to configure RTC. Exit RTC configuration... \r\n"); + setting = STATE_HOUR; + config = 0x00; + return false; + break; + + default: + break; + } + + } + } + return true; + } +} + +void main() { + + init(); // init Efinix related drivers + time_data myConfig; //Initialize timedata struct + static const char *ft[] = {"", "FAT12", "FAT16", "FAT32", "exFAT"}; + char *ptr, *ptr2; + long p1, p2, p3; + BYTE res, b, drv = 0; + UINT s1, s2, cnt, blen = sizeof Buff, acc_files, acc_dirs; + DWORD ofs = 0, sect = 0, blk[2], dw; + QWORD acc_size; + FATFS *fs; + + xdev_out(putChar); + + mmc=malloc(sizeof(struct mmc)); + cfg=malloc(sizeof(struct mmc_config)); + ops=malloc(sizeof(struct mmc_ops)); + xmmc_cmd=malloc(sizeof(struct mmc_cmd)); + data=malloc(sizeof(struct mmc_data)); + + bsp_printf("\n\r***FatFs File System Demo***\n\r"); + bsp_printf("Initialize...\r\n"); + + //Allocation Struct Space + memset(mmc, 0, sizeof(struct mmc)); + memset(cfg, 0, sizeof(struct mmc_config)); + memset(ops, 0, sizeof(struct mmc_ops)); + memset(xmmc_cmd, 0, sizeof(struct mmc_cmd)); + memset(data, 0, sizeof(struct mmc_data)); + + mmc->cfg = cfg; //pass the pointer after malloc in struct + mmc->cfg->ops = ops;//pass the pointer after malloc in struct + + sd_ctrl_mmc_probe(mmc,SDHC_BASE); //init SD Card driver + + IntcInitialize(mmc); // init interrupt + + if(f_mount(&FatFs, "", 1) == FR_OK) // Mount SD Card + { + bsp_printf("Filesystem found in SD card .. \r\n"); + } else + { + bsp_printf("Filesystem not found, please create it using command below .. \r\n"); } + + xputs(HelpMsg); + +for (;;) { + xputc('>'); + xgets(Line, sizeof Line); + ptr = Line; + switch (*ptr++) { + case '?' : /* Show Command List */ + xputs(HelpMsg); + break; + case 'm' : /* Memory dump/fill/edit */ + switch (*ptr++) { + case 'd' : /* md[b|h|w]
[] - Dump memory */ + switch (*ptr++) { + case 'w': p3 = 4; break; + case 'h': p3 = 2; break; + default: p3 = 1; + } + if (!xatoi(&ptr, &p1)) break; + if (!xatoi(&ptr, &p2)) p2 = 128 / p3; + for (ptr = (char*)p1; p2 >= 16 / p3; ptr += 16, p2 -= 16 / p3) + put_dump(ptr, (DWORD)ptr, 16 + / p3, p3); + if (p2) put_dump((BYTE*)ptr, (UINT)ptr, p2, p3); + break; + case 'f' : /* mf
- Fill memory */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break; + while (p3--) { + *(BYTE*)p1 = (BYTE)p2; + p1++; + } + break; + case 'e' : /* me[b|h|w]
[ ...] - Edit memory */ + switch (*ptr++) { /* Get data width */ + case 'w': p3 = 4; break; + case 'h': p3 = 2; break; + default: p3 = 1; + } + if (!xatoi(&ptr, &p1)) break; /* Get start address */ + if (xatoi(&ptr, &p2)) { /* 2nd parameter is given (direct mode) */ + do { + switch (p3) { + case 4: *(DWORD*)p1 = (DWORD)p2; break; + case 2: *(WORD*)p1 = (WORD)p2; break; + default: *(BYTE*)p1 = (BYTE)p2; + } + p1 += p3; + } while (xatoi(&ptr, &p2)); /* Get next value */ + break; + } + for (;;) { /* 2nd parameter is not given (interactive mode) */ + switch (p3) { + case 4: xprintf("%08X 0x%08X-", p1, *(DWORD*)p1); break; + case 2: xprintf("%08X 0x%04X-", p1, *(WORD*)p1); break; + default: xprintf("%08X 0x%02X-", p1, *(BYTE*)p1); + } + ptr = Line; xgets(ptr, sizeof Line); + if (*ptr == '.') break; + if ((BYTE)*ptr >= ' ') { + if (!xatoi(&ptr, &p2)) continue; + switch (p3) { + case 4: *(DWORD*)p1 = (DWORD)p2; break; + case 2: *(WORD*)p1 = (WORD)p2; break; + default: *(BYTE*)p1 = (BYTE)p2; + } + } + p1 += p3; + } + break; + } + break; + + case 'b' : /* Buffer controls */ + switch (*ptr++) { + case 'd' : /* bd - Dump R/W buffer */ + if (!xatoi(&ptr, &p1)) break; + for (ptr=(char*)&Buff[p1], ofs = p1, cnt = 32; cnt; cnt--, ptr+=16, ofs+=16) + put_dump((BYTE*)ptr, ofs, 16, 1); + break; + + case 'e' : /* be [] ... - Edit R/W buffer */ + if (!xatoi(&ptr, &p1)) break; + if (xatoi(&ptr, &p2)) { + do { + Buff[p1++] = (BYTE)p2; + } while (xatoi(&ptr, &p2)); + break; + } + for (;;) { + xprintf("%04X %02X-", (WORD)(p1), (WORD)Buff[p1]); + xgets(Line, sizeof Line); + ptr = Line; + if (*ptr == '.') break; + if (*ptr < ' ') { p1++; continue; } + if (xatoi(&ptr, &p2)) + Buff[p1++] = (BYTE)p2; + else + xputs("???\n"); + } + break; + + case 'r' : /* br [] - Read disk into R/W buffer */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break; + if (!xatoi(&ptr, &p3)) p3 = 1; + xprintf("rc=%u\n", (WORD)disk_read((BYTE)p1, Buff, p2, p3)); + break; + + case 'w' : /* bw [] - Write R/W buffer into disk */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break; + if (!xatoi(&ptr, &p3)) p3 = 1; + xprintf("rc=%u\n", (WORD)disk_write((BYTE)p1, Buff, p2, p3)); + break; + + case 'f' : /* bf - Fill working buffer */ + if (!xatoi(&ptr, &p1)) break; + unsigned char p2 = 0; +// memset(Buff, (BYTE)p1, sizeof Buff); + for (int i = 0; i < sizeof(Buff); i++) { + Buff[i] = p2; + p2++; + } + break; + + } + break; + + case 'f' : /* FatFS API controls */ + switch (*ptr++) { + + case 'i' : /* fi []- Initialize logical drive */ + if (!xatoi(&ptr, &p2)) p2 = 0; + put_rc(f_mount(&FatFs, "", (BYTE)p2)); + break; + + case 's' : /* fs [] - Show volume status */ + while (*ptr == ' ') ptr++; + res = f_getfree(ptr, (DWORD*)&p1, &fs); + if (res) { + put_rc(res); + break; + } + xprintf("FAT type = %s\n", ft[fs->fs_type]); + xprintf("Bytes/Cluster = %lu\n", (DWORD)fs->csize * 512); + xprintf("Number of FATs = %u\n", fs->n_fats); + if (fs->fs_type < FS_FAT32) xprintf("Root DIR entries = %u\n", fs->n_rootdir); + xprintf("Sectors/FAT = %lu\n", fs->fsize); + xprintf("Number of clusters = %lu\n", (DWORD)fs->n_fatent - 2); + xprintf("Volume start (lba) = %lu\n", fs->volbase); + xprintf("FAT start (lba) = %lu\n", fs->fatbase); + xprintf("DIR start (lba,clustor) = %lu\n", fs->dirbase); + xprintf("Data start (lba) = %lu\n\n", fs->database); +#if FF_USE_LABEL + res = f_getlabel(ptr, (char*)Buff, (DWORD*)&p2); + if (res) { put_rc(res); break; } + xprintf(Buff[0] ? "Volume name is %s\n" : "No volume label\n", (char*)Buff); + xprintf("Volume S/N is %04X-%04X\n", (DWORD)p2 >> 16, (DWORD)p2 & 0xFFFF); +#endif + acc_size = acc_files = acc_dirs = 0; + xprintf("..."); + res = scan_files(ptr, &acc_dirs, &acc_files, &acc_size); + if (res) { put_rc(res); break; } + xprintf("\r%u files, %llu bytes.\n%u folders.\n" + "%lu KiB total disk space.\n%lu KiB available.\n", + acc_files, acc_size, acc_dirs, + (fs->n_fatent - 2) * (fs->csize / 2), (DWORD)p1 * (fs->csize / 2) + ); + break; + + case 'l' : /* fl [] - Directory listing */ + while (*ptr == ' ') ptr++; + res = f_opendir(&Dir, ptr); + if (res) { put_rc(res); break; } + acc_size = acc_dirs = acc_files = 0; + for(;;) { + res = f_readdir(&Dir, &Finfo); + if ((res != FR_OK) || !Finfo.fname[0]) break; + if (Finfo.fattrib & AM_DIR) { + acc_dirs++; + } else { + acc_files++; acc_size += Finfo.fsize; + } + xprintf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n", + (Finfo.fattrib & AM_DIR) ? 'D' : '-', + (Finfo.fattrib & AM_RDO) ? 'R' : '-', + (Finfo.fattrib & AM_HID) ? 'H' : '-', + (Finfo.fattrib & AM_SYS) ? 'S' : '-', + (Finfo.fattrib & AM_ARC) ? 'A' : '-', + (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31, + (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63, + Finfo.fsize, Finfo.fname); + } + xprintf("%4u File(s),%10llu bytes total\n%4u Dir(s)", acc_files, acc_size, acc_dirs); + res = f_getfree(ptr, &dw, &fs); + if (res == FR_OK) { + xprintf(", %10llu bytes free\n", (QWORD)dw * fs->csize * 512); + } else { + put_rc(res); + } + break; + + case 'o' : /* fo - Open a file */ + if (!xatoi(&ptr, &p1)) break; + while (*ptr == ' ') ptr++; + put_rc(f_open(&File[0], ptr, (BYTE)p1)); + break; + + case 'c' : /* fc - Close a file */ + put_rc(f_close(&File[0])); + break; + + case 'e' : /* fe - Seek file pointer */ + if (!xatoi(&ptr, &p1)) break; + res = f_lseek(&File[0], p1); + put_rc(res); + if (res == FR_OK) { + xprintf("fptr=%lu(0x%lX)\n", File[0].fptr, File[0].fptr); + } + break; + + case 'd' : /* fd - read and dump file from current fp */ + if (!xatoi(&ptr, &p1)) break; + ofs = File[0].fptr; + while (p1) { + if ((UINT)p1 >= 16) { cnt = 16; p1 -= 16; } + else { cnt = p1; p1 = 0; } + res = f_read(&File[0], Buff, cnt, &cnt); + if (res != FR_OK) { put_rc(res); break; } + if (!cnt) break; + put_dump(Buff, ofs, cnt, 1); + ofs += 16; + } + break; + + case 'r' : /* fr - read file */ + if (!xatoi(&ptr, &p1)) break; + p2 = 0; + Timer = 0; + while (p1) { + if ((UINT)p1 >= blen) { + cnt = blen; p1 -= blen; + } else { + cnt = p1; p1 = 0; + } + res = f_read(&File[0], Buff, cnt, &s2); + if (res != FR_OK) { put_rc(res); break; } + p2 += s2; + if (cnt != s2) break; + } + xprintf("%lu bytes read with %lu kB/sec.\n", p2, Timer ? (p2 / Timer) : 0); + break; + + case 'w' : /* fw - write file */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break; + memset(Buff, (BYTE)p2, blen); + p2 = 0; + Timer = 0; + while (p1) { + if ((UINT)p1 >= blen) { + cnt = blen; p1 -= blen; + } else { + cnt = p1; p1 = 0; + } + res = f_write(&File[0], Buff, cnt, &s2); + if (res != FR_OK) { put_rc(res); break; } + p2 += s2; + if (cnt != s2) break; + } + xprintf("%lu bytes written with %lu kB/sec.\n", p2, Timer ? (p2 / Timer) : 0); + break; + + case 'n' : /* fn - Change name of an object */ + while (*ptr == ' ') ptr++; + ptr2 = strchr(ptr, ' '); + if (!ptr2) break; + *ptr2++ = 0; + while (*ptr2 == ' ') ptr2++; + put_rc(f_rename(ptr, ptr2)); + break; + + case 'u' : /* fu - Unlink an object */ + while (*ptr == ' ') ptr++; + put_rc(f_unlink(ptr)); + break; + + case 'v' : /* fv - Truncate file */ + put_rc(f_truncate(&File[0])); + break; + + case 'k' : /* fk - Create a directory */ + while (*ptr == ' ') ptr++; + put_rc(f_mkdir(ptr)); + break; + + case 'a' : /* fa - Change attribute of an object */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break; + while (*ptr == ' ') ptr++; + put_rc(f_chmod(ptr, p1, p2)); + break; + + case 't' : /* ft - Change timestamp of an object */ + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break; + Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31); + if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break; + ptr++; + Finfo.ftime = ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31); + put_rc(f_utime(ptr, &Finfo)); + break; + + case 'x' : /* fx - Copy a file */ + while (*ptr == ' ') ptr++; + ptr2 = strchr(ptr, ' '); + if (!ptr2) break; + *ptr2++ = 0; + while (*ptr2 == ' ') ptr2++; + xprintf("Opening \"%s\"", ptr); + res = f_open(&File[0], ptr, FA_OPEN_EXISTING | FA_READ); + xputc('\n'); + if (res) { + put_rc(res); + break; + } + xprintf("Creating \"%s\"", ptr2); + res = f_open(&File[1], ptr2, FA_CREATE_ALWAYS | FA_WRITE); + xputc('\n'); + if (res) { + put_rc(res); + f_close(&File[0]); + break; + } + xprintf("Copying file..."); + Timer = 0; + p1 = 0; + for (;;) { + res = f_read(&File[0], Buff, blen, &s1); + if (res || s1 == 0) break; /* error or eof */ + res = f_write(&File[1], Buff, s1, &s2); + p1 += s2; + if (res || s2 < s1) break; /* error or disk full */ + } + xprintf("\n%lu bytes copied with %lu kB/sec.\n", p1, p1 / Timer); + f_close(&File[0]); + f_close(&File[1]); + break; +#if FF_FS_RPATH + case 'g' : /* fg - Change current directory */ + while (*ptr == ' ') ptr++; + put_rc(f_chdir(ptr)); + break; +#if FF_FS_RPATH >= 2 + case 'q' : /* fq - Show current dir path */ + res = f_getcwd(Line, sizeof Line); + if (res) + put_rc(res); + else + xprintf("%s\n", Line); + break; +#endif +#endif +#if FF_USE_LABEL + case 'b' : /* fb - Set volume label */ + while (*ptr == ' ') ptr++; + put_rc(f_setlabel(ptr)); + break; +#endif /* FF_USE_LABEL */ +#if FF_USE_MKFS + case 'm' : /* fm - Create/ Reformat to FAT32 file system */ + { + volatile MKFS_PARM opt; + volatile MKFS_PARM *volatile popt = 0; + popt->fmt = FM_FAT32; + xprintf("The volume will be formatted. Are you sure? (Y/n)="); + xgets(Line, sizeof Line); + if (Line[0] == 'Y') put_rc(f_mkfs("", (MKFS_PARM *)popt, Buff, sizeof Buff)); + break; + } +#endif /* FF_USE_MKFS */ + case 'z' : /* fz [] - Change/Show R/W length for fr/fw/fx command */ + if (xatoi(&ptr, &p1) && p1 >= 1 && p1 <= (long)sizeof Buff) + blen = p1; + xprintf("blen=%u\n", blen); + break; + } + break; + + case 't' : /* t [ ] - Set/Show RTC */ + printOrSetRTCTime(ptr); + break; + + } + } +} + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/userDef.h new file mode 100644 index 0000000..ae33322 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/fatFSDemo/src/userDef.h @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef USERDEF_H_ +#define USERDEF_H_ + +#include +#include +#include "soc.h" +#include "type.h" +#include "mmc.h" + +/************************** Hardware Header File ***************************/ +#define SDHC_BASE 0xe9000000 +#define SDHC_INTERRUPT SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT +#define I2C_CTRL SYSTEM_I2C_0_IO_CTRL +#define I2C_FREQ 100000 //100kHz +#define I2C_CTRL_HZ SYSTEM_CLINT_HZ +#define CORE_HZ BSP_CLINT_HZ + +/************************** Main Header File ***************************/ + +#include "device/pcf8523.h" + +/* + * Define DMA_MODE to enable DMA access instead of PIO access + * DMA access provides higher throughput compared to PIO access. + */ +#define DMA_MODE + +/* + * Define DEBUG_PRINTF_EN to enable debug message printing + * This can help with debugging during development. + */ +#define DEBUG_PRINTF_EN 0 + +/************************** SDHC ***************************/ +#define MAX_CLK_FREQ 50000//KHz +#define SD_CLK_FREQ MAX_CLK_FREQ//KHz +#define SDHC_ADDR 0x100 +#define BLOCK_SIZE 0x200 +#define MAX_BLK_BUF 0x1 +#define DATA_WIDTH 0x2 //0x0:1-bit mode; 0x2:4-bit mode; + +/************************** INTC Header File *****************************/ +#define INT_ENABLE 0xffffffcf +#define INT_COMMAND_COMPLETE 0x1 +#define INT_TRANSFER_COMPLETE 0x2 +#define INT_BLOCK_GAP_EVENT 0x4 +#define INT_BUFFER_WRITE_READY 0x10 +#define INT_BUFFER_READ_READY 0x20 +#define INT_CARD_INSERTION 0x40 +#define INT_CARD_REMOVAL 0x80 +#define INT_COMMAND_TIMEOUT_ERROR 0x10000 +#define INT_COMMAND_CRC_ERROR 0x20000 +#define INT_COMMAND_END_BIT_ERROR 0x40000 +#define INT_COMMAND_INDEX_ERROR 0x80000 +#define INT_DATA_CRC_ERROR 0x200000 + +#define UART_DECIMAL_OFFSET 48 +#define STATE_HOUR 0x00 +#define STATE_MINUTES 0x01 +#define STATE_SECONDS 0x02 +#define STATE_WEEK_DAY 0x03 +#define STATE_DAYS 0x04 +#define STATE_MONTH 0x05 +#define STATE_YEAR 0x06 +#define STATE_CONFIG 0x07 +#define STATE_EXIT 0x08 + +#define ASCII_LOWER_CASE_Q 0x71 +#define ASCII_UPPER_CASE_Q 0x51 + +/************************** Peripherals *****************************/ +extern struct mmc *mmc; +extern struct mmc_cmd *xmmc_cmd; +extern struct mmc_data *data; + +time_data myConfig; + +static +const char HelpMsg[] = + "[Buffer controls]\r\n" + " bd - Dump working buffer\r\n" + " be [] ... - Edit working buffer\r\n" + " br [] - Read disk into working buffer\r\n" + " bw [] - Write working buffer into disk\r\n" + " bf - Fill working buffer\r\n" + "[File system controls]\r\n" + " fi []- Force initialized the volume\r\n" + " fs [] - Show volume status\r\n" + " fl [] - Show a directory\r\n" + " fo - Open a file\r\n" + " mode 0 => Open existing file\r\n" + " mode 1 => Open as read file\r\n" + " mode 2 => Open as write file\r\n" + " mode 4 => Create new file\r\n" + " mode 8 => Create new file always\r\n" + " mode 16 => Open a file always\r\n" + " mode 48 => Open a file append\r\n" + " fc - Close the file\r\n" + " fe - Move fp in normal seek\r\n" + " fd - Read and dump the file\r\n" + " fr - Read the file\r\n" + " fw - Write to the file\r\n" + " fn - Rename an object\r\n" + " fu - Unlink an object\r\n" + " fv - Truncate the file at current fp\r\n" + " fk - Create a directory\r\n" + " fa - Change attribute of an object\r\n" + " ft - Change timestamp of an object\r\n" + " fx - Copy a file\r\n" + " fg - Change current directory\r\n" + " fq - Show current directory\r\n" + " fb - Set volume label\r\n" + " fm - Create FAT32 file system\r\n" + " fz [] - Change/Show R/W length for fr/fw/fx command\r\n" + "[Misc commands]\r\n" + " md[b|h|w] [] - Dump memory\r\n" + " mf - Fill memory\r\n" + " me[b|h|w] [ ...] - Edit memory\r\n" + " t [ ] - Set/Show RTC\r\n" + " = 1: Sunday, 2: Monday, 3: Tuesday, 4: Wednesday, " + "5: Thursday, 6: Friday, 7: Saturday \r\n" + "\r\n"; + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/makefile new file mode 100644 index 0000000..ba65088 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/makefile @@ -0,0 +1,18 @@ +PROJ_NAME=sdhcDemo + +STANDALONE=../.. +CFLAGS+=-DSMP +CFLAGS+=-Isrc + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + +CFLAGS+=-Isrc +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.c new file mode 100644 index 0000000..9542f86 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.c @@ -0,0 +1,186 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "bsp.h" +#include "intc.h" +#include "efx_mmc_driver.h" +#include "userDef.h" +#include "plic.h" +#include "clint.h" +#include "riscv.h" + + +IntStruct IntPtr; +struct sd_ctrl_dev *dev; + +/************************** Function Definitions *****************************/ +void trap_entry(); + +/********************************* Function **********************************/ +void UserInterruptAIsr() +{ + u32 int_status; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,0x00); + + int_status = sd_ctrl_read(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0); + + if(int_status&INT_COMMAND_COMPLETE) { + IntPtr.command_complete = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_COMPLETE); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : COMMAND_COMPLETE\n\r"); + } + } + + if(int_status&INT_TRANSFER_COMPLETE) { + IntPtr.transfer_complete = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_TRANSFER_COMPLETE); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : TRANSFER_COMPLETE\n\r"); + } + } + + if(int_status&INT_BLOCK_GAP_EVENT) { + IntPtr.block_gap_event = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BLOCK_GAP_EVENT); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : BLOCK_GAP_EVENT\n\r"); + } + } + + if(int_status&INT_BUFFER_WRITE_READY) { + //IntPtr.buffer_write_ready = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_WRITE_READY); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : BUFFER_WRITE_READY\n\r"); + } + } + + if(int_status&INT_BUFFER_READ_READY) { + //IntPtr.buffer_read_ready = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_BUFFER_READ_READY); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : BUFFER_READ_READY\n\r"); + } + } + + if(int_status&INT_CARD_INSERTION) { + IntPtr.card_insertion = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_INSERTION); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : CARD_INSERTION\n\r"); + } + } + + if(int_status&INT_CARD_REMOVAL) { + IntPtr.card_removal = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_CARD_REMOVAL); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : CARD_REMOVAL\n\r"); + } + } + + if(int_status&INT_COMMAND_TIMEOUT_ERROR) { + IntPtr.command_timeout_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_TIMEOUT_ERROR); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : COMMAND_TIMEOUT_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_CRC_ERROR) { + IntPtr.command_crc_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_CRC_ERROR); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : COMMAND_CRC_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_END_BIT_ERROR) { + IntPtr.command_end_bit_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_END_BIT_ERROR); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : COMMAND_END_BIT_ERROR\n\r"); + } + } + + if(int_status&INT_COMMAND_INDEX_ERROR) { + IntPtr.command_index_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_COMMAND_INDEX_ERROR); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : COMMAND_INDEX_ERROR\n\r"); + } + } + + if(int_status&INT_DATA_CRC_ERROR) { + //IntPtr.data_crc_error = 0x1; + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS0,INT_DATA_CRC_ERROR); + if(DEBUG_PRINTF_EN == 1) { + uart_writeStr(UART_0,"INT : DATA_CRC_ERROR\n\r"); + } + } + + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); +} + + +/********************************* Function **********************************/ +//Used on unexpected trap/interrupt codes +void crash(){ + uart_writeStr(UART_0, "\n*** CRASH ***\n"); + while(1); +} + +void userInterrupt(){ + //struct example_apb3_ctrl_reg cfg={0}; + uint32_t claim; + //While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT: + UserInterruptAIsr(); break; + default: crash(); break; + } + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); //unmask the claimed interrupt + } +} + +//Called by trap_entry on both exceptions and interrupts events +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; //Interrupt if true, exception if false + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: userInterrupt(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void IntcInitialize(struct mmc *mmc) +{ + dev=mmc->priv; + + //configure PLIC + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); //cpu 0 accept all interrupts with priority above 0 + + //enable SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT rising edge interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_USER_INTERRUPT_I_INTERRUPT, 1); + + //enable riscV interrupts + csr_write(mtvec, trap_entry); //Set the machine trap vector (../common/trap.S) +// csr_set(mie, MIE_MTIE | MIE_MEIE); //Enable machine timer and external interrupts + csr_set(mie, MIE_MEIE); //Enable machine timer and external interrupts + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); + + //enable User interrupts + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,0x00); //Clean All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1,INT_ENABLE); //Enable All Interrupts Status + sd_ctrl_write(dev,SDHC_ADDR+REG_NORMAL_INTERRUPT_STATUS1+4,INT_ENABLE); //Open All Interrupts Signal +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.h new file mode 100644 index 0000000..5d1de19 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/intc.h @@ -0,0 +1,13 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#ifndef HEADER_INTC_H_ +#define HEADER_INTC_H_ + +#include "bsp.h" + +void IntcInitialize(); + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/main.c new file mode 100644 index 0000000..5ee2b32 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/sdhc/sdhcDemo/src/main.c @@ -0,0 +1,121 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "bsp.h" +#include "userDef.h" +#include "source.h" +#include "intc.h" +#include "mmc.h" +#include "efx_mmc_driver.h" + +char buf[BLOCK_SIZE*MAX_BLK_BUF]; +char rd_buf[BLOCK_SIZE*MAX_BLK_BUF]; + + +void main() { + + struct mmc *mmc; + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_config *cfg; + struct mmc_ops *ops; + int fail=1; + u32 total_block_n,n; + u64 timer_start,timer_end; + u32 rd_timer_start,rd_timer_end; + u32 ts,te; + + mmc=malloc(sizeof(struct mmc)); + cfg=malloc(sizeof(struct mmc_config)); + ops=malloc(sizeof(struct mmc_ops)); + cmd=malloc(sizeof(struct mmc_cmd)); + data=malloc(sizeof(struct mmc_data)); + + + + bsp_printf("\n\r*** Starting SDHC Demo ***\n\r"); + bsp_printf("\r\nInitialize .."); + + //Allocation Struct Space + + memset(mmc, 0, sizeof(struct mmc)); + memset(cfg, 0, sizeof(struct mmc_config)); + memset(ops, 0, sizeof(struct mmc_ops)); + memset(cmd, 0, sizeof(struct mmc_cmd)); + memset(data, 0, sizeof(struct mmc_data)); + memset(buf, 0, (sizeof(char)*BLOCK_SIZE*MAX_BLK_BUF)); + memset(rd_buf, 0, (sizeof(char)*BLOCK_SIZE*MAX_BLK_BUF)); + + mmc->cfg = cfg; //pass the pointer after malloc in struct + mmc->cfg->ops = ops;//pass the pointer after malloc in struct + + sd_ctrl_mmc_probe(mmc, SDHC_BASE); //init SD Card driver + + IntcInitialize(mmc); // init interrupt + + SD_CardInitial(mmc,cmd); //init SD Card + bsp_printf("Done\r\n"); + + if(DEBUG_PRINTF_EN == 1) + bsp_printf("WR ADDR 0x%x Rd ADDR 0x%x\r\n",buf,rd_buf); + + SD_InitRandomBuff(buf,BLOCK_SIZE*MAX_BLK_BUF); //init write buffer with random data; + + + //Read/Write Test with Speed + + //!!!!warning it will crash the SD card data!!!! + + total_block_n = ((u32)(mmc->capacity/512)); + + bsp_printf("**************START SPEED TEST*******************\r\n"); + bsp_printf("**SD CLOCK SPEED = %d\r\n",SD_CLK_FREQ); + bsp_printf("**CARD SPEED = %d kHz\r\n",mmc->tran_speed/1000); + bsp_printf("**CARD SIZE = %d Mbyte Total BLOCK = %d\r\n",(u32)(mmc->capacity/1024/1024),total_block_n); + bsp_printf("**SD BUS WIDTH = %d\r\n",mmc->bus_width); + bsp_printf("**BLOCK SIZE = %d BUFFER OF BLOCK = %d\r\n",BLOCK_SIZE,MAX_BLK_BUF); + bsp_printf("**TEST SIZE = %d kbyte\r\n",(BLOCK_SIZE*MAX_BLK_BUF)/1024); + bsp_printf("*************************************************\r\n"); + + bsp_printf("\r\n\n!!!!Warning it will crash the SD card data!!!!\r\n\n"); + bsp_printf(" ###Push Any Key to Continue###\r\n\n"); + + while(1) + { + if(uart_read(BSP_UART_TERMINAL)) + break; + } + + for(n=0;nrca<<16)); + mmc->csd[0]= cmd->response[0]; + mmc->csd[1]= cmd->response[1]; + mmc->csd[2]= cmd->response[2]; + mmc->csd[3]= cmd->response[3]; + + mmc->capacity = (((mmc->csd[1]>>8) &0x3FFFFF)+1)*512; + mmc->capacity *=1024; + mmc->tran_speed = multipliers[(mmc->csd[2]>>27) &0x07] * fbase[(mmc->csd[2]>>24) &0x03]; + + if(DEBUG_PRINTF_EN == 1) + { + bsp_printf("CSD 0x%x 0x%x 0x%x 0x%x\r\n",mmc->csd[0],mmc->csd[1],mmc->csd[2],mmc->csd[3]); + bsp_printf("FILE_FORMAT = %d\r\n",(mmc->csd[0]>>2) &0x03); //[11:10] + bsp_printf("TMP_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>4) &0x01);//[12] + bsp_printf("PERM_WRITE_PROTECT = %d\r\n",(mmc->csd[0]>>5) &0x01);//[13] + bsp_printf("COPY = %d\r\n",(mmc->csd[0]>>6) &0x01); //[14] + bsp_printf("FILE_FORMAT_GRP = %d\r\n",(mmc->csd[0]>>7) &0x01);//[15] + //[20:16] + bsp_printf("WRITE_BL_PARTIAL = %d\r\n",(mmc->csd[0]>>13) &0x01);//[21] + bsp_printf("WRITE_BL_LEN = %d\r\n",(mmc->csd[0]>>14) &0x0F);//[25:22] + bsp_printf("R2W_FACTOR = %d\r\n",(mmc->csd[0]>>18) &0x07);//[28:26] + //[30:29] + bsp_printf("WP_GRP_ENABLE = %d\r\n",(mmc->csd[0]>>23) &0x01);//[31] + + bsp_printf("WP_GRP_SIZE = %d\r\n",(mmc->csd[0]>>24) &0x7F);//[38:32] + + bsp_printf("SECTOR_SIZE = %d\r\n",((mmc->csd[1] & 0x3F)<<1)|((mmc->csd[0])>>31 &0x1));//[45:39] + bsp_printf("ERASE_BLK_EN = %d\r\n",(mmc->csd[1]>>6) &0x01);//[46] + //[47] + bsp_printf("C_SIZE = %d\r\n",(mmc->csd[1]>>8) &0x3FFFFF);//[69:48] + //[75:70] + bsp_printf("DSR_IMP = %d\r\n",(mmc->csd[2]>>4) &0x01);//[76] + bsp_printf("READ_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>5) &0x01);//[77] + bsp_printf("WRITE_BLK_MISAIGN = %d\r\n",(mmc->csd[2]>>6) &0x01);//[78] + bsp_printf("READ_BL_PARTIAL = %d\r\n",(mmc->csd[2]>>7) &0x01);//[79] + bsp_printf("READ_BL_LEN = %d\r\n",(mmc->csd[2]>>8) &0x0F);//[83:80] + bsp_printf("CCC = %d\r\n",(mmc->csd[2]>>12) &0x0FFF);//[95:84] + bsp_printf("TRAN_SPEED = 0x%x\r\n",(mmc->csd[2]>>24) &0x0FF);//[103:96] + bsp_printf("NSAC = 0x%x\r\n",(mmc->csd[3]) &0x0FF);//[111:104] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>8) &0x0FF);//[119:112] + //[125:120] + bsp_printf("TAAC = 0x%x\r\n",(mmc->csd[3]>>22) &0x03);//[127:126] + bsp_printf("mmc->capacity = %d\r\n",(((mmc->csd[1]>>8) &0x3FFFFF)+1)*512); + bsp_printf("mmc->tran_speed = %d\r\n",mmc->tran_speed); + } + + +} + +/************************** Function File ***************************/ +void SD_CardInitial(struct mmc *mmc, struct mmc_cmd *cmd) +{ + u32 Value; + char busy=0; + u32 rca=0; + int wait_busy_count; + + for(int i=0; i<1; i++) { + + sd_send_cmd(mmc,cmd,MMC_CMD_GO_IDLE_STATE,MMC_RSP_NONE,0); + bsp_uDelay(1000); + sd_send_cmd(mmc,cmd,MMC_CMD_SEND_EXT_CSD,MMC_RSP_R7,0x01AA); + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); + + wait_busy_count = 0; + while (busy==0) + { + Value = 0; + Value |= 0x1<<30;//HCS + Value |= 0x0<<28;//XPC + Value |= 0x0<<24;//S18R + Value |= 0x100000;//VDD VOLTAGE + bsp_uDelay(50000);//delay 50ms + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,0); + sd_send_cmd(mmc,cmd,SD_CMD_APP_SEND_OP_COND,MMC_RSP_R3,Value); + bsp_printf("Response: 0x%x\r\n",cmd->response[0]); + busy = (cmd->response[0]>>31)&0x1; + bsp_uDelay(1000000);//delay 50ms + + wait_busy_count++; + if (wait_busy_count >=10) + { + break; + } + } + + + if(busy == 1) { + break; + } else if(i == 1) { + bsp_printf("Err : ACMD41 OCR BUSY!\r\n"); + while(1); + } + bsp_uDelay(1000000); + } + + sd_send_cmd(mmc,cmd,MMC_CMD_ALL_SEND_CID,MMC_RSP_R2,0); + mmc->cid[0]=cmd->response[0]; + mmc->cid[1]=cmd->response[1]; + mmc->cid[2]=cmd->response[2]; + mmc->cid[3]=cmd->response[3]; + + sd_send_cmd(mmc,cmd,MMC_CMD_SET_RELATIVE_ADDR,MMC_RSP_R6,0); + + mmc->rca = (cmd->response[0]&0xffff0000)>>16; + SD_READ_CSD(mmc,cmd); + sd_send_cmd(mmc,cmd,MMC_CMD_SELECT_CARD,MMC_RSP_R1b,(mmc->rca<<16)); + //write_u32(DATA_WIDTH, APB_0+SDHC_ADDR+0x028);//sdhc_reg - Host Control 1 + + sd_send_cmd(mmc,cmd,MMC_CMD_APP_CMD,MMC_RSP_R1,(mmc->rca<<16)); + sd_send_cmd(mmc,cmd,SD_CMD_APP_SET_BUS_WIDTH,MMC_RSP_R1,DATA_WIDTH); + sd_send_cmd(mmc,cmd,MMC_CMD_SET_BLOCKLEN,MMC_RSP_R1,BLOCK_SIZE); + + if(DEBUG_PRINTF_EN) + bsp_printf("SD_CardInitial done\r\n"); +} + + +void SD_EraseBlk(struct mmc *mmc, struct mmc_cmd *cmd,u32 sd_addr, u32 blk_count) +{ + sd_send_cmd(mmc,cmd,SD_CMD_ERASE_WR_BLK_START,MMC_RSP_R1,sd_addr); + sd_send_cmd(mmc,cmd,SD_CMD_ERASE_WR_BLK_END,MMC_RSP_R1,sd_addr+(blk_count-1)*BLOCK_SIZE); + sd_send_cmd(mmc,cmd,MMC_CMD_ERASE,MMC_RSP_R1b,0); +} + + +void SD_WRITE_BLOCK(struct mmc *mmc, u32 addr, void* src, u32 blocks) +{ + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = blocks; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_WRITE_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_WRITE_MULTIPLE_BLOCK; + + cmd->cmdarg =addr; + cmd->resp_type=MMC_RSP_R1; + + data->src=src; + data->flags = MMC_DATA_WRITE; + + ops->send_cmd(mmc,cmd,data); + + free(cmd); + free(data); + + return; +} + +void SD_READ_BLOCK(struct mmc *mmc, u32 addr, char* dest, u32 blocks) +{ + struct mmc_cmd *cmd; + struct mmc_data *data; + struct mmc_ops *ops = mmc->cfg->ops; + + + cmd = malloc(sizeof(struct mmc_cmd)); + data = malloc(sizeof(struct mmc_data)); + + memset(cmd,0,sizeof(struct mmc_cmd)); + memset(data,0,sizeof(struct mmc_data)); + + data->blocksize = mmc->read_bl_len; + data->blocks = blocks; + + if(data->blocks == 1) cmd->cmdidx=MMC_CMD_READ_SINGLE_BLOCK; + else cmd->cmdidx=MMC_CMD_READ_MULTIPLE_BLOCK; + + cmd->cmdarg =addr; + cmd->resp_type=MMC_RSP_R1; + data->dest=dest; + data->flags = MMC_DATA_READ; + + + mmc->cfg->ops->send_cmd(mmc,cmd,data); + + free(cmd); + free(data); + + return; +} + +char SD_ReadWriteCompare(char* wrbuf, char* rdbuf ,u64 wr_start ,u64 wr_end ,u64 rd_start ,u64 rd_end,u32 block_count,u32 current_blk,u32 total_blk) +{ + char err=0; + u32 m,cmpblk; + u32 rd_speed,wr_speed; + + if(block_count>MAX_BLK_BUF) cmpblk=MAX_BLK_BUF; + else cmpblk=block_count; + + if(memcmp(wrbuf,rdbuf,sizeof(char)*cmpblk*BLOCK_SIZE)) + { + bsp_printf("Tested Block %d/%d\n\r",current_blk,total_blk); + + for(m=0;m<(cmpblk*BLOCK_SIZE/4);m++) + { + if(wrbuf[m] != rdbuf[m]) + { + bsp_printf("compare fail m=%d wr= 0x%x rd=0x%x\n\r",m,wrbuf[m],rdbuf[m]); + err=1; + break; + } + + } + } + else + { + wr_speed = ((block_count*BLOCK_SIZE)*1024)/((wr_end-wr_start)/(SYSTEM_CLINT_HZ/1000000)); + rd_speed = ((block_count*BLOCK_SIZE)*1024)/((rd_end-rd_start)/(SYSTEM_CLINT_HZ/1000000)); + + if((current_blk % 1024) ==0) + bsp_printf("Tested Block %d/%d Write s=%d KByte/s Read s=%d KByte/s \r",current_blk,total_blk,wr_speed,rd_speed); + + } + + return err; +} + + +void SD_InitRandomBuff(char* buf, u32 size) +{ + int m; + + for(m=0;m +#include +#include "soc.h" + +/************************** Hardware Header File ***************************/ +#define UART_0 SYSTEM_UART_0_IO_CTRL +#define DDR_SADDR 0x01300000 +#define DDR_EADDR 0xf7ffffff +#define SDHC_BASE 0xe9000000 + +/************************** Main Header File ***************************/ +#define DEBUG_PRINTF_EN 0 + +/************************** SDHC Header File ***************************/ +#define MAX_CLK_FREQ 50000//KHz +#define SD_CLK_FREQ MAX_CLK_FREQ//KHz +#define SDHC_ADDR 0x100 +#define BLOCK_SIZE 0x200 +#define MAX_BLK_BUF 0x100 +#define DATA_WIDTH 0x2 //0x0:1-bit mode; 0x2:4-bit mode; +#define DMA_MODE 1 +/************************** INTC Header File *****************************/ +#define INT_ENABLE 0xffffffcf +#define INT_COMMAND_COMPLETE 0x1 +#define INT_TRANSFER_COMPLETE 0x2 +#define INT_BLOCK_GAP_EVENT 0x4 +#define INT_BUFFER_WRITE_READY 0x10 +#define INT_BUFFER_READ_READY 0x20 +#define INT_CARD_INSERTION 0x40 +#define INT_CARD_REMOVAL 0x80 +#define INT_COMMAND_TIMEOUT_ERROR 0x10000 +#define INT_COMMAND_CRC_ERROR 0x20000 +#define INT_COMMAND_END_BIT_ERROR 0x40000 +#define INT_COMMAND_INDEX_ERROR 0x80000 +#define INT_DATA_CRC_ERROR 0x200000 + + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/makefile new file mode 100755 index 0000000..d783b4c --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/makefile @@ -0,0 +1,23 @@ +PROJ_NAME=smpDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +DEBUG?=no +BENCH?=yes + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/smpInit.S + + +CFLAGS+=-Isrc +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/main.c new file mode 100755 index 0000000..860d11e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/main.c @@ -0,0 +1,283 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// +/****************************************************************************** +* +* @file main.c: smpDemo +* +* @brief This demo illustrates how to use multiple cores to process multiple encryption pat +* the same time in parallel. Each core is assigned an encryption algorithm with an +* input keys (each core has a different key). Core 0 prints the final encrypted values +* after theother cores complete the encryption. If a single core performed the encryption, +* it would take four times more clock cycles to complete the process. +* +* @note Please ensure that Sapphire SoC is configured with more than 1 core, or else +* user may encounter a build error. If Sapphire SoC is configured as a multicore, +* the *_mc.launch scripts are generated by the Efinity RISC-V Embedded Software +* IDE. Launch the *_mc.launch based on user's configuration to start the demo. +* +******************************************************************************/ + +#include "bsp.h" +#include "userDef.h" +#include "riscv.h" +#include "start.h" + +// Encryption count for single core processing +#define ENCRYPT_COUNT HART_COUNT +// Stack space used by smpInit.S to provide stack to secondary harts +u8 hartStack[STACK_PER_HART*HART_COUNT] __attribute__((aligned(16))); + +// Used as a syncronization barrier between all threads +volatile u32 hartCounter = 0; +// Flag used by hart 0 to notify the other harts that the "value" variable is loaded +volatile u32 h0_ready = 0; +volatile u32 h1_ready = 0; +volatile u32 h2_ready = 0; +volatile u32 h3_ready = 0; +u32 input1; +u32 input2; +u32 h0_r1,h0_r2; +u32 h1_r1,h1_r2; +u32 h2_r1,h2_r2; +u32 h3_r1,h3_r2; + +uint64_t timerCmp0, timerCmp1; + +/******************************************************************************* +* +* @brief This function print processing time between two timestamps +* +* @param ts1 First timestamp. +* @param ts2 Second timestamp. +* @param s Character +* +******************************************************************************/ +void printPTime(uint64_t ts1, uint64_t ts2, char *s) { + uint64_t rts; + rts=ts2-ts1; + bsp_printf("%s %d \n\n\r", s, rts); +} + +/****************************************************************************** +* +* @brief This function implements the Tiny Encryption Algorithm (TEA) encryption +* with a given set of 1024 cycles. +* +* @param v0 - First value to be encrypted +* @param v1 - Second value to be encrypted +* @param k[] - Key array containing four 32-bit keys +* @param *rv0 - Pointer to store the encrypted value of v0 +* @param *rv1 - Pointer to store the encrypted value of v1 +* +******************************************************************************/ +void tiny_algo_encrypter (uint32_t v0, uint32_t v1, uint32_t k[], uint32_t *rv0, uint32_t *rv1) { + uint32_t sum=0, i; + + uint32_t delta=0x9e3779b9; + + for (i=0; i < 1024; i++) { + sum += delta; + v0 += ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>5) + k[1]); + v1 += ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>5) + k[3]); + + } + *rv0=v0; + *rv1=v1; +} + +#if (SMP_INUSE == 1) + +extern void smpInit(); //initializes symmetric multiprocessing (SMP) capabilities. +void mainSmp(); //Main entry point for symmetric multiprocessing (SMP). +/****************************************************************************** +* +* @brief Atomic Addition: This function performs an atomic addition to the given value. +* +* @param a - Pointer to the value to which the increment should be added atomically +* @param increment - Value to be added atomically +* +* @return The value before the addition +* +******************************************************************************/ +__inline__ __attribute__((always_inline)) s32 atomicAdd(s32 *a, u32 increment) { + s32 old; + __asm__ volatile( + "amoadd.w %[old], %[increment], (%[atomic])" + : [old] "=r"(old) + : [increment] "r"(increment), [atomic] "r"(a) + : "memory" + ); + return old; +} + +/****************************************************************************** +* +* @brief This function demonstrates the symmetric multiprocessing (SMP) with +* encryption using a tiny algorithm. +* +******************************************************************************/ +void mainSmp(){ + u32 hartId = csr_read(mhartid); + atomicAdd((s32*)&hartCounter, 1); + + while(hartCounter != HART_COUNT); + // Hart 0 will provide a value to the other harts, other harts wait on it by pulling the "ready" variable + if(hartId == 0) { + bsp_printf("synced! \r\n"); + timerCmp0 = clint_getTime(BSP_CLINT); + input1 = 0xdeadbeaf; + input2 = 0x42395820; + asm("fence w,w"); + h0_ready = 1; + + u32 key_h0[4]={0x227C81AA, 0x7AE71DA8, 0x4ACF7AD5, 0x67E57113}; + tiny_algo_encrypter(input1, input2, key_h0, &h0_r1, &h0_r2); + +#if (HART_COUNT == 4) + while(!h1_ready && !h2_ready && !h3_ready); + asm("fence r,r"); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"processing clock cycles:"); + bsp_printf("hart 0 encrypted output A: %x \r\n", h0_r1); + bsp_printf("hart 0 encrypted output B: %x \r\n", h0_r2); + bsp_printf("hart 1 encrypted output A: %x \r\n", h1_r1); + bsp_printf("hart 1 encrypted output B: %x \r\n", h1_r2); + bsp_printf("hart 2 encrypted output A: %x \r\n", h2_r1); + bsp_printf("hart 2 encrypted output B: %x \r\n", h2_r2); + bsp_printf("hart 3 encrypted output A: %x \r\n", h3_r1); + bsp_printf("hart 3 encrypted output B: %x \r\n", h3_r2); +#elif (HART_COUNT == 3) + while(!h1_ready && !h2_ready); + asm("fence r,r"); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"processing clock cycles:"); + bsp_printf("hart 0 encrypted output A: %x \r\n", h0_r1); + bsp_printf("hart 0 encrypted output B: %x \r\n", h0_r2); + bsp_printf("hart 1 encrypted output A: %x \r\n", h1_r1); + bsp_printf("hart 1 encrypted output B: %x \r\n", h1_r2); + bsp_printf("hart 2 encrypted output A: %x \r\n", h2_r1); + bsp_printf("hart 2 encrypted output B: %x \r\n", h2_r2); +#else + while(!h1_ready); + asm("fence r,r"); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0,timerCmp1,"processing clock cycles:"); + bsp_printf("hart 0 encrypted output A: %x \r\n", h0_r1); + bsp_printf("hart 0 encrypted output B: %x \r\n", h0_r2); + bsp_printf("hart 1 encrypted output A: %x \r\n", h1_r1); + bsp_printf("hart 1 encrypted output B: %x \r\n", h1_r2); +#endif + + } + else if(hartId == 1){ + while(!h0_ready); + asm("fence r,r"); + u32 inp1_h1 = (volatile u32)input1; + u32 inp2_h1 = (volatile u32)input2; + u32 key_h1[4]={0x248a0135, 0x529C7762, 0x5688593F, 0xF9A7B565}; + tiny_algo_encrypter(inp1_h1, inp2_h1, key_h1, &h1_r1, &h1_r2); + asm("fence w,w"); + h1_ready = 1; + } + else if(hartId == 2){ + while(!h0_ready); + asm("fence r,r"); + u32 inp1_h2 = (volatile u32)input1; + u32 inp2_h2 = (volatile u32)input2; + u32 key_h2[4]={0x3AAE508A, 0xC58CCC20, 0x8CA79D11, 0x038C6414}; + tiny_algo_encrypter(inp1_h2, inp2_h2, key_h2, &h2_r1, &h2_r2); + asm("fence w,w"); + h2_ready = 1; + } + else if(hartId == 3){ + while(!h0_ready); + asm("fence r,r"); + u32 inp1_h3 = (volatile u32)input1; + u32 inp2_h3 = (volatile u32)input2; + u32 key_h3[4]={0x248a0135, 0x5BB6136C, 0xC7E9CA03, 0xE4407CF3}; + tiny_algo_encrypter(inp1_h3, inp2_h3, key_h3, &h3_r1, &h3_r2); + asm("fence w,w"); + h3_ready = 1; + } +} + +/****************************************************************************** +* +* @brief This main function initializes the SMP and then starts the SMP main function +* when SMP is enabled. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("***Starting SMP Demo*** \r\n"); + smp_unlock(smpInit); + mainSmp(); + bsp_printf("***Succesfully Ran Demo*** \r\n"); +} +#else +/****************************************************************************** +* +* @brief This main function performs encryption using the tiny_algo_encrypter +* function with different keys based on the ENCRYPT_COUNT macro value +* using single CPU. It measures the processing time and prints the +* encrypted outputs. +* +******************************************************************************/ +void main() { + bsp_printf("\nsmpDemo with single cpu processing\r\n"); + u32 key_h0[4]={0x227C81AA, 0x7AE71DA8, 0x4ACF7AD5, 0x67E57113}; + u32 key_h1[4]={0x248a0135, 0x529C7762, 0x5688593F, 0xF9A7B565}; + u32 key_h2[4]={0x3AAE508A, 0xC58CCC20, 0x8CA79D11, 0x038C6414}; + u32 key_h3[4]={0x248a0135, 0x5BB6136C, 0xC7E9CA03, 0xE4407CF3}; + + timerCmp0 = clint_getTime(BSP_CLINT); + + input1 = 0xdeadbeaf; + input2 = 0x42395820; +#if (ENCRYPT_COUNT == 4) + tiny_algo_encrypter(input1, input2, key_h0, &h0_r1, &h0_r2); + tiny_algo_encrypter(input1, input2, key_h1, &h1_r1, &h1_r2); + tiny_algo_encrypter(input1, input2, key_h2, &h2_r1, &h2_r2); + tiny_algo_encrypter(input1, input2, key_h3, &h3_r1, &h3_r2); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0, timerCmp1,"processing clock cycles:"); + bsp_printf("1st encrypted output A: %x \r\n", h0_r1); + bsp_printf("1st encrypted output B: %x \r\n", h0_r2); + bsp_printf("2nd encrypted output A: %x \r\n", h1_r1); + bsp_printf("2nd encrypted output B: %x \r\n", h1_r2); + bsp_printf("3rd encrypted output A: %x \r\n", h2_r1); + bsp_printf("3rd encrypted output B: %x \r\n", h2_r2); + bsp_printf("4th encrypted output A: %x \r\n", h3_r1); + bsp_printf("4th encrypted output B: %x \r\n", h3_r2); +#elif (ENCRYPT_COUNT == 3) + tiny_algo_encrypter(input1, input2, key_h0, &h0_r1, &h0_r2); + tiny_algo_encrypter(input1, input2, key_h1, &h1_r1, &h1_r2); + tiny_algo_encrypter(input1, input2, key_h2, &h2_r1, &h2_r2); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0, timerCmp1,"processing clock cycles:"); + bsp_printf("1st encrypted output A: %x \r\n", h0_r1); + bsp_printf("1st encrypted output B: %x \r\n", h0_r2); + bsp_printf("2nd encrypted output A: %x \r\n", h1_r1); + bsp_printf("2nd encrypted output B: %x \r\n", h1_r2); + bsp_printf("3rd encrypted output A: %x \r\n", h2_r1); + bsp_printf("3rd encrypted output B: %x \r\n", h2_r2); +#elif (ENCRYPT_COUNT == 2) + tiny_algo_encrypter(input1, input2, key_h0, &h0_r1, &h0_r2); + tiny_algo_encrypter(input1, input2, key_h1, &h1_r1, &h1_r2); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0, timerCmp1,"processing clock cycles:"); + bsp_printf("1st encrypted output A: %x \r\n", h0_r1); + bsp_printf("1st encrypted output B: %x \r\n", h0_r2); + bsp_printf("2nd encrypted output A: %x \r\n", h1_r1); + bsp_printf("2nd encrypted output B: %x \r\n", h1_r2); +#else + tiny_algo_encrypter(input1, input2, key_h0, &h0_r1, &h0_r2); + timerCmp1 = clint_getTime(BSP_CLINT); + printPTime(timerCmp0, timerCmp1,"processing clock cycles:"); + bsp_printf("1st encrypted output A: %x \r\n", h0_r1); + bsp_printf("1st encrypted output B: %x \r\n", h0_r2); +#endif +} +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/userDef.h new file mode 100644 index 0000000..0a99d8b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpDemo/src/userDef.h @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "soc.h" + +#define STACK_PER_HART 4096 + +#ifdef SYSTEM_PLIC_SYSTEM_CORES_3_EXTERNAL_INTERRUPT + #define HART_COUNT 4 +#elif SYSTEM_PLIC_SYSTEM_CORES_2_EXTERNAL_INTERRUPT + #define HART_COUNT 3 +#elif SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_INTERRUPT + #define HART_COUNT 2 +#else + #define HART_COUNT 1 +#endif +#define SMP_INUSE (HART_COUNT > 1) + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/makefile new file mode 100644 index 0000000..f58aadc --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/makefile @@ -0,0 +1,22 @@ +PROJ_NAME=smpIntrDemo +STANDALONE = ../.. + +CFLAGS+=-DSMP -Isrc + +DEBUG?=no +BENCH?=yes + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S \ + ${STANDALONE}/common/smpInit.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/smpIntrDemo.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/smpIntrDemo.c new file mode 100644 index 0000000..868f71a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/smpIntrDemo.c @@ -0,0 +1,197 @@ +#include "soc.h" +#include "bsp.h" + +#if defined(SYSTEM_PLIC_SYSTEM_CORES_1_EXTERNAL_INTERRUPT) &&\ + defined(SYSTEM_USER_TIMER_0_CTRL) &&\ + defined(SYSTEM_USER_TIMER_1_CTRL) + +#include "userDef.h" +#include "riscv.h" +#include "start.h" +#include "plic.h" +#include "timer.h" +#include "prescaler.h" + +u8 hartStack[STACK_PER_HART*HART_COUNT] __attribute__((aligned(16))); + +void trap(); +void crash(); +void trap_entry(); +void externalInterrupt(); +void isrRoutine(); +extern void smpInit(); + +volatile u32 hartCounter = 0; +volatile u32 uart_occupied = 0; + +__inline__ __attribute__((always_inline)) s32 atomicAdd(s32 *a, u32 increment) { + s32 old; + __asm__ volatile( + "amoadd.w %[old], %[increment], (%[atomic])" + : [old] "=r"(old) + : [increment] "r"(increment), [atomic] "r"(a) + : "memory" + ); + return old; +} + +void timer_init(){ + //set timer 1 trigger every 2.2s + prescaler_setValue(TIMER_0_PRESCALER_CTRL, 9999); + timer_setLimit(TIMER_0_CTRL, 22000); + timer_setConfig(TIMER_0_CTRL, TIMER_CONFIG_WITH_PRESCALER | TIMER_CONFIG_SELF_RESTART); + + // set timer 1 to trigger every 4.7s + prescaler_setValue(TIMER_1_PRESCALER_CTRL, 9999); + timer_setLimit(TIMER_1_CTRL, 47000); + timer_setConfig(TIMER_1_CTRL, TIMER_CONFIG_WITH_PRESCALER | TIMER_CONFIG_SELF_RESTART); +} + +void plic_init(){ + //set all cores to accept all interupts of priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_1, 0); + +#ifdef BSP_PLIC_CPU_2 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_2, 0); +#endif + +#ifdef BSP_PLIC_CPU_3 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_3, 0); +#endif + + //set core 0 and core 1 to entertain interrupt from user timers + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 1); + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_1, SYSTEM_PLIC_TIMER_INTERRUPTS_1, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_TIMER_INTERRUPTS_1, 1); +} + +void timer0Isr(){ + while(uart_occupied == 1); + uart_occupied = 1; + bsp_printf("c0 isr .. \r\n"); + uart_occupied = 0; +} + +void timer1Isr(){ + while(uart_occupied == 1); + uart_occupied = 1; + bsp_printf("c1 isr .. \r\n"); + uart_occupied = 0; +} + +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + + +void isrInit(){ + //enable interrupts + //Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + //Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, MSTATUS_MPP | MSTATUS_MIE | MSTATUS_FS); +} + +void trap(){ + int32_t mcause = csr_read(mcause); + // Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void isrRoutine(){ + uint32_t claim; + // While there is pending interrupts + if (csr_read(mhartid) == 0x0){ + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_TIMER_INTERRUPTS_0: timer0Isr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } + } + else if (csr_read(mhartid) == 0x1){ + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_1)){ + switch(claim){ + case SYSTEM_PLIC_TIMER_INTERRUPTS_1: timer1Isr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_1, claim); + } + } +} + +void mainSmp(){ + //this routine run by all cores + u32 hartId = csr_read(mhartid); + //each core register the interrupt trap + isrInit(); + atomicAdd((s32*)&hartCounter, 1); + + while(hartCounter != HART_COUNT); + if(hartId == 0) { + bsp_printf("smp init done .. \r\n"); + + while(1); + } + else if(hartId == 1){ + while(1); + } + else if(hartId == 2){ + while(1); + } + else if(hartId == 3){ + while(1); + } + +} + +void main(){ + //this routine run by core 0 + bsp_init(); + timer_init(); + plic_init(); + //timer_init(); + bsp_printf("***Starting SMP Interrupt Demo*** \r\n"); + smp_unlock(smpInit); + mainSmp(); +} + +#else + +#define STACK_PER_HART 4096 +#define HART_COUNT 4 +u8 hartStack[STACK_PER_HART*HART_COUNT]; + +void trap(){ + +} + +void mainSmp(){ + +} + +void main(){ + bsp_printf("Unable to perform smpIntrDemo. Please enable the following modules in SapphireSoc:\r\n"); + bsp_printf("- At least 2 CPU cores \r\n"); + bsp_printf("- User Timer 0 with 32-bit counter width and 16-bit prescaler width \r\n"); + bsp_printf("- User Timer 1 with 32-bit counter width and 16-bit prescaler width \r\n"); + while(1); +} + +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/userDef.h new file mode 100644 index 0000000..2a86494 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/smp/smpIntrDemo/src/userDef.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define STACK_PER_HART 4096 + +#ifdef BSP_PLIC_CPU_3 +#define HART_COUNT 4 + +#elif BSP_PLIC_CPU_2 +#define HART_COUNT 3 + +#elif BSP_PLIC_CPU_1 +#define HART_COUNT 2 + +#else +#define HART_COUNT 1 + +#endif + +#define SYSTEM_PLIC_TIMER_INTERRUPTS_0 SYSTEM_PLIC_SYSTEM_USER_TIMER_0_INTERRUPTS_0 +#define TIMER_0 SYSTEM_USER_TIMER_0_CTRL +#define SYSTEM_PLIC_TIMER_INTERRUPTS_1 SYSTEM_PLIC_SYSTEM_USER_TIMER_1_INTERRUPTS_0 +#define TIMER_1 SYSTEM_USER_TIMER_1_CTRL +#define TIMER_0_PRESCALER_CTRL (TIMER_0 + 0x00) +#define TIMER_0_CTRL (TIMER_0 + 0x40) +#define TIMER_1_PRESCALER_CTRL (TIMER_1 + 0x00) +#define TIMER_1_CTRL (TIMER_1 + 0x40) +#define TIMER_CONFIG_WITH_PRESCALER 0x2 +#define TIMER_CONFIG_WITHOUT_PRESCALER 0x1 +#define TIMER_CONFIG_SELF_RESTART 0x10000 +#define TIMER_TICK_DELAY (BSP_CLINT_HZ) + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/makefile new file mode 100644 index 0000000..c7039aa --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/makefile @@ -0,0 +1,17 @@ +PROJ_NAME=spiDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/src/main.c new file mode 100644 index 0000000..ee6a0e5 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/spi/spiDemo/src/main.c @@ -0,0 +1,130 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: spiDemo +* +* @brief This demo provides example code for reading the device ID and JEDEC ID of the SPI flash +* device on the development board. The application displays the results on a UART terminal. +* It continues to print to the terminal until you suspend or stop the application. +* +* @note +* The default base address map of the SPI flash master is 0xF801_4000. +* The default SCK frequency is half of the SoC system clock frequency. +* The default base address of the UART is 0xF801_0000 with a default baud rate of 115200. +* +******************************************************************************/ +#include +#include "bsp.h" +#include "userDef.h" +#include "spi.h" +#include "spiFlash.h" + + + +#define LEN 256 // Length to write/read from/to SPI Flash +#define SPI_CS 0 // Chip Select + + + +/******************************************************************************* +* +* @brief This function initialize the spi configuration setting based on the following +* parameters. +* +* @param +* - cpol: Clock polarity (0 or 1). +* - cpha: Clock phase (0 or 1). +* - mode: SPI mode +* 0: Full-duplex dual line +* 1: Half-duplex dual line +* (Available only when data width is configured as 8 or 16) +* 2: Half-duplex quad line +* (Available only when data width is configured as 8 or 16) +* +* - clkDivider: Clock divider value. SPI frequency = FCLK/((clockDivider+1)*2) +* FCLK is the system clock (io_systemClk) to the SoC. If +* you enable the peripheral clock, then FCLK is driven by +* the peripheral clock (io_peripheralClk) instead. +* +* - ssSetup: Slave select setup time. Clock cycle between activated chip-select and first +* rising-edge of SCLK. Clock cycle refers to FCLK. +* +* - ssHold: Slave select hold time. Clock cycle between last falling-edge and deactivated +* chip-select is activated. Clock cycle refers to FCLK. +* +* - ssDisable: Slave select disable time. +* +******************************************************************************/ +void spiInit(){ + //SPI init + Spi_Config spiA; + spiA.cpol = 1; + spiA.cpha = 1; + spiA.mode = 0; + spiA.clkDivider = 19; + spiA.ssSetup = 5; + spiA.ssHold = 5; + spiA.ssDisable = 5; + spi_applyConfig(SPI, &spiA); +} + + + +/**************************************l**************************************** +* +* @brief This function is Writes LEN bytes of incrementing data to NOR Flash starting at the specified address. +* +******************************************************************************/ +void spiWriteData_toFlash(u32 reg ,u32 cs, u32 addr){ + spiGlobalUnlock(reg,cs); + spiSectorErase(reg,cs,addr); + spiWriteEnable(reg,cs); + spi_select(reg, 0); + spi_write(reg, PAGE_PROGRAM_OP); + spi_write(reg, (addr>>16) & 0xFF); + spi_write(reg, (addr>>8) & 0xFF); + spi_write(reg, addr & 0xFF); + // Write dummy data + for(int i=0; i +#include "bsp.h" +#include "userDef.h" +#include "prescaler.h" +#include "timer.h" +#include "riscv.h" +#include "plic.h" + +#if defined(SYSTEM_USER_TIMER_0_CTRL) && defined(SYSTEM_USER_TIMER_1_CTRL) +void trap(); +void crash(); +void trap_entry(); +void isrRoutine(); +void initTimer(); +void isrInit(); +void main(); + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash message +* and entering an infinite loop. +* +******************************************************************************/ + +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + // Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +/****************************************************************************** +* +* @brief This function handles external interrupts. It checks for pending +* interrupts and processes them accordingly. If an interrupt from +* user timer 0/1 are detected, it prints a message indicating the interrupt +* source. If an interrupt from an unknown source is detected, it +* calls a crash function to handle the error. +* +******************************************************************************/ +void isrRoutine(){ + uint32_t claim; + + // Save the Machine Exception Programme Counter to be able to restore it in case a higher priority interrupt happen + u32 epc = csr_read(mepc); + // Save it to restore it later + u32 threshold = plic_get_threshold(BSP_PLIC, BSP_PLIC_CPU_0); + + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + // Identify which priority level the current claimed interrupt is + u32 priority = plic_get_priority(BSP_PLIC, claim); + // Enable only the interrupts which higher priority than the currently claimed one. + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, priority); + // Enable machine external interrupts + csr_set(mstatus, MSTATUS_MIE); + switch(claim){ + case SYSTEM_PLIC_TIMER_INTERRUPTS_0: { + bsp_printf("T0S-HP\r\n"); + bsp_printf("T0E-HP\r\n"); + } break; + case SYSTEM_PLIC_TIMER_INTERRUPTS_1: { + bsp_printf("T1S\r\n"); + // User delay + for(int i = 0;i < 1200000;i++) asm("nop"); + bsp_printf("T1E\r\n"); + // That timer wasn't configured with self restart, require to do it manually. + timer_clearValue(TIMER_1_CTRL); + } break; + default: crash(); break; + } + // disable machine external interrupts + csr_clear(mstatus, MSTATUS_MIE); + // Restore the original threshold level + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, threshold); + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); //unmask the claimed interrupt + } + //Restore the mepc, in case it was overwritten by a nested interrupt + csr_write(mepc, epc); +} + +/****************************************************************************** +* +* @brief This function initializes Timer 0 and Timer 1. It configures the +* prescaler values, sets the timer configuration with the prescaler, +* sets the timer limits, and enables self-restart for Timer 0. +* +******************************************************************************/ +void initTimer(){ + // Divide clock rate by 399+1 + prescaler_setValue(TIMER_0_PRESCALER_CTRL, 399); + // Will tick each (9999+1)*(399+1) cycles (as it use the prescaler) + timer_setLimit(TIMER_0_CTRL, 3999); + timer_setConfig(TIMER_0_CTRL, TIMER_CONFIG_WITH_PRESCALER | TIMER_CONFIG_SELF_RESTART); + // Will tick each (3999+1)*(999+1) cycles (as it use the prescaler) + prescaler_setValue(TIMER_1_PRESCALER_CTRL, 999); + timer_setLimit(TIMER_1_CTRL, 3999); + timer_setConfig(TIMER_1_CTRL, TIMER_CONFIG_WITH_PRESCALER); +} + +/****************************************************************************** +* +* @brief This function configures the timer, enables Timer 0 & 1 external interrupts +* by setting up the machine trap vector. +* +******************************************************************************/ + +void isrInit(){ + // Configure timer + initTimer(); + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + // Enable Timer 0 interrupts + // Priority 2 win against priority 1 + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 2); + // Enable Timer 1 interrupts + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_TIMER_INTERRUPTS_1, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_TIMER_INTERRUPTS_1, 1); + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + // Enable external interrupts only + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This main function initializes interrupts, and then enters an infinite +* loop to demonstrate nested interrupts. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("***Starting Nested Interrupt Demo*** \r\n"); + isrInit(); + while(1); +} +#else +void trap(){ +} + +/****************************************************************************** +* +* @brief This main function is executed when user timer functionality is disabled. +* It initializes the BSP and prints a message indicating that +* user timer 0 & 1 are disabled, and the user should enable it to run the app. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("This demo requires user timer 0 and user timer 1, please enable them to run this app \r\n"); +} +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/nestedInterruptDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/nestedInterruptDemo/src/userDef.h new file mode 100644 index 0000000..4452f25 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/nestedInterruptDemo/src/userDef.h @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +#define SYSTEM_PLIC_TIMER_INTERRUPTS_0 SYSTEM_PLIC_SYSTEM_USER_TIMER_0_INTERRUPTS_0 +#define TIMER_CTRL_0 SYSTEM_USER_TIMER_0_CTRL +#define SYSTEM_PLIC_TIMER_INTERRUPTS_1 SYSTEM_PLIC_SYSTEM_USER_TIMER_1_INTERRUPTS_0 +#define TIMER_CTRL_1 SYSTEM_USER_TIMER_1_CTRL +#define TIMER_CONFIG_WITH_PRESCALER 0x2 +#define TIMER_CONFIG_WITHOUT_PRESCALER 0x1 +#define TIMER_CONFIG_SELF_RESTART 0x10000 +#define TIMER_0_PRESCALER_CTRL (TIMER_CTRL_0 + 0x00) +#define TIMER_0_CTRL (TIMER_CTRL_0 + 0x40) +#define TIMER_1_PRESCALER_CTRL (TIMER_CTRL_1 + 0x00) +#define TIMER_1_CTRL (TIMER_CTRL_1 + 0x40) +#ifdef SIM + //Faster timer tick in simulation + #define TIMER_TICK_DELAY (BSP_CLINT_HZ/200) +#else + #define TIMER_TICK_DELAY (BSP_CLINT_HZ) +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/makefile new file mode 100755 index 0000000..9e72171 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/makefile @@ -0,0 +1,19 @@ +PROJ_NAME=userTimerDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/main.c new file mode 100755 index 0000000..5de1e40 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/main.c @@ -0,0 +1,157 @@ +////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// +#include "bsp.h" +#include "userDef.h" +#include "prescaler.h" +#include "timer.h" +#include "riscv.h" +#include "plic.h" +#ifdef SYSTEM_USER_TIMER_0_CTRL +void crash(); +void trap(); +void trap_entry(); +void timerIsr(); +void isrRoutine(); +void initTimer(); +void isrInit(); +void main(); + +//Store the count of interrupt happened +u32 count; + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash +* message and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + // Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +/****************************************************************************** +* +* @brief This function will keep on counting once enter interrupt routine. +* +******************************************************************************/ +void timerIsr(){ + bsp_printf("Entering timer 0 interrupt routine .. \r\n"); + count++; + bsp_printf("Count:%d .. Done \r\n",count); +} + +/****************************************************************************** +* +* @brief This function handles user timer interrupt by claiming pending interrupts +* and print message on terminal regarding the interrupt routine. +* +******************************************************************************/ +void isrRoutine(){ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_TIMER_INTERRUPTS_0: timerIsr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function initializes user timer by setting up the prescaler value. +* +******************************************************************************/ + +void initTimer(){ + // Divide clock rate by 1999+1 + prescaler_setValue(TIMER_PRESCALER_CTRL, 1999); + // Will tick each (19999+1)*(1999+1) cycles (as it use the prescaler) + timer_setLimit(TIMER_0_CTRL, 19999); + timer_setConfig(TIMER_0_CTRL, TIMER_CONFIG_WITH_PRESCALER | TIMER_CONFIG_SELF_RESTART); +} + +/****************************************************************************** +* +* @brief This function initializes user timer interrupts and enables external interrupts +* by setting up the machine trap vector. +* +******************************************************************************/ +void isrInit(){ + // Configure timer + initTimer(); + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + // Enable Timer 0 interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_TIMER_INTERRUPTS_0, 1); + // Enable interrupt + csr_write(mtvec, trap_entry); //Set the machine trap vector (../common/trap.S) + csr_set(mie, MIE_MEIE); //Enable machine timer and external interrupts + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This main function intialize the system and then prints a message +* indicating that the user timer 0 demo is starting. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("***Starting User Timer Interrupt Demo*** \r\n"); + isrInit(); + while(1); +} + +#else +void trap(){ +} + +/****************************************************************************** +* +* @brief This main function is executed when I2C functionality is disabled. +* It initializes the BSP and prints a message indicating that +* I2C 0 is disabled, and the user should enable it to run the app. +* +******************************************************************************/ +void main() { + bsp_init(); + bsp_printf("User timer 0 is disabled, please enable it to run this app \r\n"); +} +#endif + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/userDef.h new file mode 100644 index 0000000..f85c953 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/userTimerDemo/src/userDef.h @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +#define SYSTEM_PLIC_TIMER_INTERRUPTS_0 SYSTEM_PLIC_SYSTEM_USER_TIMER_0_INTERRUPTS_0 +#define TIMER_CTRL SYSTEM_USER_TIMER_0_CTRL +#define TIMER_PRESCALER_CTRL (TIMER_CTRL + 0x00) +#define TIMER_0_CTRL (TIMER_CTRL + 0x40) +#define TIMER_CONFIG_WITH_PRESCALER 0x2 +#define TIMER_CONFIG_WITHOUT_PRESCALER 0x1 +#define TIMER_CONFIG_SELF_RESTART 0x10000 +#ifdef SIM + //Faster timer tick in simulation + #define TIMER_TICK_DELAY (BSP_CLINT_HZ/200) +#else + #define TIMER_TICK_DELAY (BSP_CLINT_HZ) +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/makefile new file mode 100644 index 0000000..12c2cc3 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/makefile @@ -0,0 +1,18 @@ +PROJ_NAME=watchdogDemo + +STANDALONE = ../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/main.c new file mode 100644 index 0000000..24f4a7f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/main.c @@ -0,0 +1,160 @@ +////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "bsp.h" +#include "clint.h" +#include "clint.h" +#include "riscv.h" +#include "gpio.h" +#include "plic.h" +#include "watchdog.h" +#include "userDef.h" +void main(); +void trap(); + +#ifdef SYSTEM_WATCHDOG_LOGIC_CTRL +void init(); +void crash(); +void trap_entry(); +void initWatchdog(); +void externalInterrupt(); +void watchdogSoftPanic(); +void patWatchdog(); + + +u32 softPanicCounter = 0; +u32 software_gone_wrong = 0; +u32 random_x = 3; +u32 random_y = 3; + +void main() { + u32 i; + bsp_init(); + bsp_printf("***Starting WatchDog Timer Demo***\n\r"); + init(); + + bsp_printf("Watchdog timer timeout = %ds .. \n\r", WATCHDOG_TIMEOUT_MS/1000); + bsp_printf("Pat the watchdog every %dms for %d times then wait for soft panic trigger .. \n\r", WAIT_TIME_MS, random_x); + bsp_printf("Watchdog patting will stop after %d soft panic trigger.. \n\n\r", random_y); + + while(1){ + for(i=0; i random_y){ + bsp_printf("Soft panic count=%d \n\rstop pat the watchdog this time and watchdog will reset system after %ds ..\n\n\r", softPanicCounter, WATCHDOG_TIMEOUT_MS/1000); + while(1); + } + + // Here your software can recover. + + patWatchdog(); + software_gone_wrong = 0; + + bsp_printf("Soft panic count=%d \n\r", softPanicCounter); +} + +void patWatchdog(){ + bsp_printf("Pat the watchdog .. \n\r"); + watchdog_heartbeat(SYSTEM_WATCHDOG_LOGIC_CTRL); // This will clear all the timeout counters and the soft panic +} + +//Used on unexpected trap/interrupt codes +void crash(){ + bsp_printf("\n*** CRASH ***\n\r"); + while(1); +} + +#else +void trap(){ +} + +void main() { + bsp_printf("***Starting WatchDog Timer Demo***\n\r"); + bsp_printf("Watchdog timer is not enabled, unable to run this demo...\n\r"); + while(1); +} +#endif diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/userDef.h new file mode 100644 index 0000000..c869f1e --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/timer/watchdogDemo/src/userDef.h @@ -0,0 +1,17 @@ + +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2025 SaxonSoc contributors +// SPDX license identifier: MIT +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +/////////////////////////////////////////////////////////////////////////////////// + +#ifdef SYSTEM_PLIC_SYSTEM_WATCHDOG_SOFT_PANIC_INTERRUPT //HPS + #define WATCHDOG_SOFT_PANIC_INTERRUPT SYSTEM_PLIC_SYSTEM_WATCHDOG_SOFT_PANIC_INTERRUPT +#endif +#ifdef SYSTEM_PLIC_SYSTEM_WATCHDOG_LOGIC_PANICS_0 // Soft Sapphire + #define WATCHDOG_SOFT_PANIC_INTERRUPT SYSTEM_PLIC_SYSTEM_WATCHDOG_LOGIC_PANICS_0 +#endif + +#define WATCHDOG_PRESCALER_CYCLE_PER_MS SYSTEM_CLINT_HZ/1000 +#define WATCHDOG_TIMEOUT_MS 3000 +#define WAIT_TIME_MS (WATCHDOG_TIMEOUT_MS - 500) \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/makefile new file mode 100644 index 0000000..2c70408 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/makefile @@ -0,0 +1,34 @@ +PROJ_NAME=lwipIperfServer + +STANDALONE = ../.. + +CFLAGS+=-DSMP + +DEBUG?=yes +BENCH?=yes + +SRCS = $(wildcard src/*.c) \ + $(wildcard ${LWIP_PATH}/*.c) \ + $(wildcard ${LWIP_PATH}/user/arch/*.c) \ + $(wildcard ${LWIP_PATH}/api/*.c) \ + $(wildcard ${LWIP_PATH}/netif/*.c) \ + $(wildcard ${LWIP_PATH}/netif/ppp/*.c) \ + $(wildcard ${LWIP_PATH}/netif/ppp/polarssl/*.c) \ + $(wildcard ${LWIP_PATH}/core/*.c) \ + $(wildcard ${LWIP_PATH}/core/ipv4/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + +CFLAGS += -Isrc +CFLAGS += -I${LWIP_PATH} +CFLAGS += -I${LWIP_PATH}/include +CFLAGS += -I${LWIP_PATH}/user/arch +CFLAGS += -I${LWIP_PATH}/user/ + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/main.c new file mode 100644 index 0000000..a306f4b --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/main.c @@ -0,0 +1,301 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// +#include +#include "bsp.h" +#include "userDef.h" +#include "prescaler.h" +#include "timer.h" +#include "clint.h" +#include "riscv.h" +#include "plic.h" +#include "lwip/init.h" +#include "lwip/ip4_addr.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/timeouts.h" +#include "netif/ethernet.h" +#include "ethernetif.h" +#include "lwiperf.h" +#include "rtl8211fd.h" +#include "efx_tse_mac.h" + +void trap_entry(); +/**************************** TSE **************************/ +/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */ + #define IP_ADDR0 configIP_ADDR0 + #define IP_ADDR1 configIP_ADDR1 + #define IP_ADDR2 configIP_ADDR2 + #define IP_ADDR3 configIP_ADDR3 + + /*NETMASK*/ + #define NETMASK_ADDR0 255 + #define NETMASK_ADDR1 255 + #define NETMASK_ADDR2 255 + #define NETMASK_ADDR3 0 + + /*Gateway Address*/ + #define GW_ADDR0 configIP_ADDR0 + #define GW_ADDR1 configIP_ADDR1 + #define GW_ADDR2 configIP_ADDR2 + #define GW_ADDR3 1 + + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gw; + ip4_addr_t client_addr; + +/******************************************************************/ +#define TIMER_PRESCALER_CTRL (TIMER_CTRL + 0x00) +#define TIMER_0_CTRL (TIMER_CTRL + 0x40) +#define TIMER_CONFIG_WITH_PRESCALER 0x2 +#define TIMER_CONFIG_WITHOUT_PRESCALER 0x1 +#define TIMER_CONFIG_SELF_RESTART 0x10000 + +/*******************************************************UART & DMA-RELATED FUNCTIONS***************************************************/ +struct netif gnetif; +int incoming_packet=0; + +//Used on unexpected trap/interrupt codes +void crash(){ + bsp_printf("\n*** CRASH ***\n"); + while(1); +} + +void isrRoutine(){ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + // TSE DMA INTERRUPT + case TSE_RX_INTR: + dmasg_interrupt_config(TSEMAC_DMASG_BASE, 0, DMASG_CHANNEL_INTERRUPT_LINKED_LIST_UPDATE_MASK); + //flush_data_cache(); + break; + + default: crash(); break; + } + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); //unmask the claimed interrupt + } +} + +//Called by trap_entry on both exceptions and interrupts events +void trap(){ + int32_t mcause = csr_read(mcause); + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +void isrInit(){ + + // RX FIFO not empty interrupt enable + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) | 0x02); + + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + + // TSE RX interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, TSE_RX_INTR, 1); + plic_set_priority(BSP_PLIC, TSE_RX_INTR, 1); + + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + // Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +void additionalSetting(void){ + u32 Value = 0; + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG); + MacRxEn(1); + //mac_reg command_config Reg + write_u32(0x00040053, (TSEMAC_BASE+COMMAND_CONFIG)); + Value = read_u32(TSEMAC_BASE+COMMAND_CONFIG); + + //set mac address + write_u32(0x33221100, (TSEMAC_BASE+MAC_ADDR_LO)); + write_u32(0x5544, (TSEMAC_BASE+MAC_ADDR_HI)); + + //Set MDIO Divider + write_u32(0xFF, (TSEMAC_BASE+DIVIDER_PRE)); + + //set mac addr + write_u32(0xFFFFFFFF, (TSEMAC_BASE+MAC_ADDR_MAKE_LO)); + write_u32(0x0000FFFF, (TSEMAC_BASE+MAC_ADDR_MAKE_HI)); +} + +u64_t sys_jiffies(void) +{ + u64 get_time; + + get_time = clint_getTime(BSP_CLINT); + return ((get_time)/(BSP_CLINT_HZ/1000)); +} + +u64_t sys_now(void) +{ + u64 get_time; + + get_time = clint_getTime(BSP_CLINT); + + return ((get_time)/(BSP_CLINT_HZ/1000)); + +} + + void LwIP_Init(void) + { + + IP4_ADDR(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3); + IP4_ADDR(&netmask,NETMASK_ADDR0,NETMASK_ADDR1,NETMASK_ADDR2,NETMASK_ADDR3); + IP4_ADDR(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3); + /* Initilialize the LwIP stack without RTOS */ + lwip_init(); + /* add the network interface (IPv4/IPv6) without RTOS */ + netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, + ðernetif_init, ðernet_input); + /* Registers the default network interface */ + netif_set_default(&gnetif); + if (netif_is_link_up(&gnetif)) + { + /*When the netif is fully configured this function must be called */ + netif_set_up(&gnetif); + + } + else + { + /* When the netif link is down this function must be called */ + netif_set_down(&gnetif); + } + } + +void clock_sel(int speed) +{ + int val=0; + + if(speed == TSE_Speed_1000Mhz) + val=0x03; + else + val=0x00; +} + +/****************************************************************MAIN**************************************************************/ +void main() { + + int state; + int n,speed=TSE_Speed_1000Mhz,link_speed=0; + int check_connect; + int bLink=0; + + MacRst(1, 1); + bsp_printf("***Starting TSEMAC Demo***\n\r"); + +/******************************************************SETUP DMA & UART********************************************************/ + isrInit(); + +/****************************************************** SETUP ETHERNET LINK ********************************************************/ + bsp_printf("Phy Init ..\n\r"); + rtl8211_drv_init(); + bsp_printf("Waiting Link Up ..\n\r"); + check_connect=rtl8211_drv_rddata(26); + speed=rtl8211_drv_linkup(); + if(speed == TSE_Speed_1000Mhz) + link_speed = 1000; + else if(speed == TSE_Speed_100Mhz) + link_speed = 100; + else if(speed == TSE_Speed_10Mhz) + link_speed = 10; + else + link_speed = 0; + + bLink =1; + clock_sel(speed); + MacNormalInit(speed); + //additionalSetting(); + LwIP_Init(); + + lwiperf_start_tcp_server( &ipaddr, 5001, NULL, NULL ); + + bsp_printf("iperf server Up\n\r\n\r"); + + bsp_printf("=========================================\n\r"); + bsp_printf("======Lwip Raw Mode Iperf TCP Server ====\n\r"); + bsp_printf("=========================================\n\r"); + + bsp_printf("======IP: \t\t"); + bsp_printf("%d",IP_ADDR0); + bsp_printf("."); + bsp_printf("%d",IP_ADDR1); + bsp_printf("."); + bsp_printf("%d",IP_ADDR2); + bsp_printf("."); + bsp_printf("%d",IP_ADDR3); + bsp_printf("\n\r"); + + bsp_printf("======Netmask: \t\t"); + bsp_printf("%d",NETMASK_ADDR0); + bsp_printf("."); + bsp_printf("%d",NETMASK_ADDR1); + bsp_printf("."); + bsp_printf("%d",NETMASK_ADDR2); + bsp_printf("."); + bsp_printf("%d",NETMASK_ADDR3); + bsp_printf("\n\r"); + + bsp_printf("======GateWay: \t\t"); + bsp_printf("%d",GW_ADDR0); + bsp_printf("."); + bsp_printf("%d",GW_ADDR1); + bsp_printf("."); + bsp_printf("%d",GW_ADDR2); + bsp_printf("."); + bsp_printf("%d",GW_ADDR3); + bsp_printf("\n\r"); + + bsp_printf("======link Speed: \t"); + bsp_printf("%d",link_speed); + bsp_printf(" Mbps\n\r"); + + bsp_printf("=========================================\n\r"); + + + while (1) { + /************************* TSE *****************************/ + if(check_dma_status(cur_des)) + { + ethernetif_input(&gnetif); //get ethernet input packet event + } + else + { + check_connect=rtl8211_drv_rddata(26); + + if((check_connect & 0x04) == 0 && (bLink)) + { + bLink=0; + bsp_printf("Disconnected -- \n\r"); + } + else if((check_connect & 0x04) && (!bLink)) + { + speed=rtl8211_drv_linkup(); + clock_sel(speed); + MacNormalInit(speed); + bLink=1; + bsp_printf("Connected -- \n\r"); + } + sys_check_timeouts(); + } + + + } +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/userDef.h b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/userDef.h new file mode 100644 index 0000000..666ea16 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/tsemac/lwipIperfServer/src/userDef.h @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +#include "bsp.h" + +#define configIP_ADDR0 192 +#define configIP_ADDR1 168 +#define configIP_ADDR2 31 +#define configIP_ADDR3 55 + +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x41 + + + +/************************** Project Header File ***************************/ +#define DEBUG_PRINTF_EN 0 +#define TEST_MODE 0 //0:Normal Mode; 1:Link partner Test Mode; +#define PAT_NUM 0 +#define PAT_DLEN 8 +#define PAT_IPG 4095 //4095//255 +#define PAT_TYPE 0 //0:UDP Pattern; //1:MAC Pattern; +#define DST_MAC_H 0xffff +#define DST_MAC_L 0xffffffff +#define SRC_MAC_H (configMAC_ADDR5<<8)|configMAC_ADDR4 +#define SRC_MAC_L (configMAC_ADDR3<<24)|(configMAC_ADDR2<<16)|(configMAC_ADDR1<<8)|configMAC_ADDR0//0x5e0060c8 +#define SRC_IP (configIP_ADDR3<<24)|(configIP_ADDR2<<16)|(configIP_ADDR1<<8)|configIP_ADDR0 +#define DST_IP 0xc0a80165 +#define SRC_PORT 0x0521 +#define DST_PORT 0x2715 + +/************************** System Header File ***************************/ +#define PHY_ADDR 0x0 + +/************************** HW Header File ***************************/ +#define TSEMAC_BASE 0xe9100000 +#define TSEMAC_DMASG_BASE IO_APB_SLAVE_0_INPUT +#define TSE_DMASG_TX_CH 1 +#define TSE_TX_INTR SYSTEM_PLIC_USER_INTERRUPT_G_INTERRUPT +#define TSE_DMASG_RX_CH 0 +#define TSE_RX_INTR SYSTEM_PLIC_USER_INTERRUPT_H_INTERRUPT +#define TSE_Speed_1000Mhz 0x04 +#define TSE_Speed_100Mhz 0x02 +#define TSE_Speed_10Mhz 0x01 + +/************************** Application Header File ***************************/ +#define TX_ENA_MASK 0xFFFFFFFE +#define RX_ENA_MASK 0xFFFFFFFD +#define XON_GEN_MASK 0xFFFFFFFB +#define PROMIS_EN_MASK 0xFFFFFFEF +#define PAD_EN_MASK 0xFFFFFFDF +#define CRC_FWD_MASK 0xFFFFFFBF +#define PAUSE_IGNORE_MASK 0xFFFFFEFF +#define TX_ADDR_INS_MASK 0xFFFFFBFF +#define LOOP_ENA_MASK 0xFFFF7FFF +#define ETH_SPEED_MASK 0xFFF8FFFF +#define XOFF_GEN_MASK 0xFFBFFFFF +#define CNT_RST_MASK 0x7FFFFFFF + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/makefile new file mode 100644 index 0000000..0a580ae --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=uartEchoDemo + +STANDALONE =../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/src/main.c new file mode 100644 index 0000000..464bfc0 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartEchoDemo/src/main.c @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: uartEchoDemo +* +* @brief This demo shows how to use the UART to print messages on a terminal. +* The characters user type on a keyboard are echoed back to the terminal +* from the SoC and printed on the terminal. +* +******************************************************************************/ + +#include "bsp.h" + +/****************************************************************************** +* +* @brief This function capture the character that user asserted on keyboard and +* printed on the terminal. +* +******************************************************************************/ +void main() { + uint8_t dat; + + bsp_init(); + + bsp_printf("***Starting Uart Echo Demo*** \r\n"); + bsp_printf("Start typing on terminal to send character... \r\n"); + while(1) + { + while(uart_readOccupancy(BSP_UART_TERMINAL)){ + dat=uart_read(BSP_UART_TERMINAL); + bsp_printf("Echo character: %c \r\n", dat); + } + } +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/makefile new file mode 100755 index 0000000..22aa3c2 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/makefile @@ -0,0 +1,17 @@ +PROJ_NAME=uartInterruptDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S \ + ${STANDALONE}/common/trap.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/src/main.c new file mode 100755 index 0000000..c71203f --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/uart/uartInterruptDemo/src/main.c @@ -0,0 +1,173 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: uartInterruptDemo +* +* @brief This demo shows how to use a UART interrupt to indicate task completion when +* sending or receiving data over a UART. The UART can trigger a interrupt when +* data is available in the UART receiver FIFO or when the UART transmitter FIFO is +* empty. +* +* @note In this example, when user type a character in a UART terminal, the data goes to the +* UART receiver and fills up FIFO buffer. This action interrupts the processor and forces the +* processor to execute an interrupt/priority routine that allows the UART to read from the +* buffer and send a message back to the terminal. +* +******************************************************************************/ +#include +#include "plic.h" +#include "clint.h" +#include "bsp.h" +#include "riscv.h" + +void crash(); +void trap(); +void trap_entry(); +void uartIsr(); +void isrRoutine(); +void isrInit(); +void main(); + +/****************************************************************************** +* +* @brief This function handles the system crash scenario by printing a crash +* message and entering an infinite loop. +* +******************************************************************************/ +void crash(){ + bsp_printf("\r\n*** CRASH ***\r\n"); + while(1); +} + +/****************************************************************************** +* +* @brief This function handles exceptions and interrupts in the system. +* +* @note It is called by the trap_entry function on both exceptions and interrupts +* events. If the cause of the trap is an interrupt, it checks the cause of +* the interrupt and calls corresponding interrupt handler functions. If +* the cause is an exception or an unhandled interrupt, it calls a +* crash function to handle the error. +* +******************************************************************************/ +void trap(){ + int32_t mcause = csr_read(mcause); + // Interrupt if true, exception if false + int32_t interrupt = mcause < 0; + int32_t cause = mcause & 0xF; + + if(interrupt){ + switch(cause){ + case CAUSE_MACHINE_EXTERNAL: isrRoutine(); break; + default: crash(); break; + } + } else { + crash(); + } +} + +/****************************************************************************** +* +* @brief This function handles UART interrupt sub-events such as TX FIFO +* empty interrupt and RX FIFO not empty interrupt. +* +******************************************************************************/ +void uartIsr() +{ + if (uart_status_read(BSP_UART_TERMINAL) & 0x00000100){ + + bsp_printf("\nEntering uart tx fifo empty interrupt routine .. \r\n"); + // Disable TX FIFO empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) & 0xFFFFFFFE); + // Enable TX FIFO empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) | 0x01); + bsp_printf("Done .. \r\n"); + } + else if (uart_status_read(BSP_UART_TERMINAL) & 0x00000200){ + + bsp_printf("\nEntering uart rx fifo not empty interrupt routine .. \r\n"); + // Disable RX FIFO not empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) & 0xFFFFFFFD); + // Read to clear RX FIFO + uart_write(BSP_UART_TERMINAL, uart_read(BSP_UART_TERMINAL)); + // Enable RX FIFO not empty interrupt + uart_status_write(BSP_UART_TERMINAL,uart_status_read(BSP_UART_TERMINAL) | 0x02); + bsp_printf("Done .. \r\n"); + } +} + +/****************************************************************************** +* +* @brief This function handles UART interrupts by claiming pending interrupts +* and processing them through UartInterrupt_Sub(). +* +******************************************************************************/ +void isrRoutine() +{ + uint32_t claim; + // While there is pending interrupts + while(claim = plic_claim(BSP_PLIC, BSP_PLIC_CPU_0)){ + switch(claim){ + case SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT: uartIsr(); break; + default: crash(); break; + } + // Unmask the claimed interrupt + plic_release(BSP_PLIC, BSP_PLIC_CPU_0, claim); + } +} + +/****************************************************************************** +* +* @brief This function initializes UART interrupts and enables external interrupts +* by setting up the machine trap vector. +* +******************************************************************************/ + +void isrInit(){ + + // TX FIFO empty interrupt enable + //uart_TX_emptyInterruptEna(BSP_UART_TERMINAL,1); + + // RX FIFO not empty interrupt enable + uart_RX_NotemptyInterruptEna(BSP_UART_TERMINAL,1); + + // Configure PLIC + // Cpu 0 accept all interrupts with priority above 0 + plic_set_threshold(BSP_PLIC, BSP_PLIC_CPU_0, 0); + + // Enable SYSTEM_PLIC_USER_INTERRUPT_A_INTERRUPT rising edge interrupt + plic_set_enable(BSP_PLIC, BSP_PLIC_CPU_0, SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT, 1); + plic_set_priority(BSP_PLIC, SYSTEM_PLIC_SYSTEM_UART_0_IO_INTERRUPT, 1); + + // Enable interrupts + // Set the machine trap vector (../common/trap.S) + csr_write(mtvec, trap_entry); + // Enable external interrupts + csr_set(mie, MIE_MEIE); + csr_write(mstatus, csr_read(mstatus) | MSTATUS_MPP | MSTATUS_MIE); +} + +/****************************************************************************** +* +* @brief This function intialize UART configuration and demostrate basic UART +* interrupt when user typing on terminal. +* +******************************************************************************/ +void main() { + bsp_init(); + isrInit(); + + bsp_printf("***Starting Uart Interrupt Demo*** \r\n"); + bsp_printf("Start typing on terminal to trigger uart RX FIFO not empty interrupt .. \r\n"); + while(1){ + while(uart_readOccupancy(BSP_UART_TERMINAL)){ + uart_write(BSP_UART_TERMINAL, uart_read(BSP_UART_TERMINAL)); + } + } +} + + diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/makefile new file mode 100644 index 0000000..3c99177 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/makefile @@ -0,0 +1,16 @@ +PROJ_NAME=dCacheFlushDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/src/main.c new file mode 100644 index 0000000..9b2162a --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/dCacheFlushDemo/src/main.c @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** +* +* @file main.c: dCacheFlushDemo +* +* @brief This demo shows how to invalidate the data cache. +* +* @note The data cache invalidation is critical to ensure the coherency between the cache +* and the main memory, ensuring that the CPU fetches the most up-to-date data. +* In the example, a value of 0xaa550000 is directly written into the memory using +* a pointer at address 0x00100000. The data increments by 1 for each address increment of 4. +* The writing process continues until address 0x0010001C. Next, the data is overwritten +* by the memory_checker module, triggered by the apb3 module. The overwritten data +* ranges from 0xaa001100 to 0xaa001107. When printing the data from addresses 0x00100000 +* to 0x0010001C, it can be observed that the data remains unchanged. This is because the +* data is still being fetched from the cache memory and not from the main memory. +* To address this, the data cache invalidation is performed before reading the data +* again. This ensures that the data is updated. +* Please ensure ABP3 and DDR is enabled in Sapphire Soc to run this app. +* +******************************************************************************/ +#include "bsp.h" +#include "vexriscv.h" + +#define LOC_EXT_MEM ((volatile uint32_t*)0x00100000) +#define NUM 8 + +void main() +{ + bsp_init(); + bsp_printf("***Starting Invalidate Data Cache Demo*** \r\n"); + + bsp_printf("Invalidate 3 cache lines .. \r\n"); + for(int j=0; j +#include "bsp.h" + +const char* funcA(){ + return "funcA\r\n"; +} + +const char* funcB(){ + return "funcB\r\n"; +} + +uint32_t array[64] __attribute__ ((aligned (64))); + +/******************************************************************************* +* +* @brief This main function demonstrate function pointer behavior after memcpy operations. +* It uses memcpy to copy functions into an array and checks the behavior of a function pointer. +* +******************************************************************************/ +void main() { + bsp_init(); + + bsp_printf("***Starting Flush Instruction Cache Demo*** \r\n"); + + const char* (*funcPtr)() = (const char* (*)())array; + bsp_printf("Memcpy funcA into array .. \r\n"); + memcpy(array, funcA, 64*4); + bsp_printf("Flush the instruction cache once to avoid preloaded data .. \r\n"); + asm("fence.i"); + bsp_printf("Expected 'funcA', Obtained : "); + bsp_printf(funcPtr()); + + bsp_printf("Memcpy funcB into array .. \r\n"); + memcpy(array, funcB, 64*4); + bsp_printf("Expected 'funcA', Obtained : "); + bsp_printf(funcPtr()); + bsp_printf("Still get the FuncA as there is no cache flush .. \r\n"); + + bsp_printf("Flush the instruction cache now .. \r\n"); + asm("fence.i"); // flush instruction cache + bsp_printf("Expected 'funcB', Obtained : "); + bsp_printf(funcPtr()); + + bsp_printf("***Successfully Ran Demo*** \r\n"); +} diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/makefile b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/makefile new file mode 100644 index 0000000..2222e72 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/makefile @@ -0,0 +1,19 @@ +PROJ_NAME=semihostingDemo + +STANDALONE=../.. + +CFLAGS+=-DSMP + +DEBUG?=no +DEBUG_OG?=no + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + ${STANDALONE}/common/start.S + +include ${STANDALONE}/common/bsp.mk +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + +LDSCRIPT = ${BSP_PATH}/linker/default.ld \ No newline at end of file diff --git a/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/src/main.c b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/src/main.c new file mode 100644 index 0000000..7f82c18 --- /dev/null +++ b/Ti375C529_devkit/embedded_sw/efx_hard_soc/software/standalone/vexriscv/semihostingDemo/src/main.c @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. +// Full license header bsp/efinix/EfxSapphireSoc/include/LICENSE.MD +//////////////////////////////////////////////////////////////////////////////// +/****************************************************************************** +* +* @file main.c: semihostingDemo +* +* @brief The semihostingDemo illustrates how to leverage semihosting in the +* Sapphire SoC by printing message through the console. +* +* @note Please ensure that the ENABLE_SEMIHOSTING_PRINT is set to 1 in the bsp.h header file. +* This enables the seamless output of debug messages. All UART printing calls, e.g., +* bsp_print, bsp_printf, and other printing APIs, that are available in the bsp.h file +* is directed to the console. +* +******************************************************************************/ + +#include "bsp.h" + +/****************************************************************************** +* +* @brief This function demonstrates the use of semihosting to print messages +* and echo back a string entered through the console. +* +******************************************************************************/ +void main() { +#if (ENABLE_SEMIHOSTING_PRINT == 1) + uint8_t dat; + uint8_t string[100]; + uint8_t counter = 0; + + bsp_init(); + bsp_printf("***Starting Semihosting Demo ***\n\r"); + bsp_printf("You should see this printing in your console .. \n\r"); + bsp_printf("Echo demo. Key in your string and press enter .. \n\r"); + while (1){ + dat=sh_readc(); + if (dat != '\n'){ + string[counter]=dat; + counter++; + } + else { + string[counter]='\0'; + bsp_printf("Echo string: %s \r\n", string); + counter = 0; + } + } + +#else + #error "Set ENABLE_SEMIHOSTING_PRINT to 1 in bsp.h for the program to work as expected..." +#endif //#if (ENABLE_SEMIHOSTING_PRINT == 1) + + +} diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb.v b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb.v index 7b89235..dd9b270 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb.v +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 1.23.0 +// Version: 2025.2.288.2.10 +// IP Version: 1.22.0 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice @@ -43,7 +43,7 @@ // //////////////////////////////////////////////////////////////////////////////// -`define IP_UUID _be6ad777990c4e5089d0b11c63cc2698 +`define IP_UUID _02c229e9056c4f0485f9e05005fe6a28 `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module EfxSapphireHpSoc_slb @@ -261,17 +261,25 @@ endmodule module `IP_MODULE_NAME(Axi4Peripheral_wrapper) #( parameter PERI_FREQ=250 )( +output userInterruptE, +output jtagCtrl_tdi, +input jtagCtrl_tdo, +output jtagCtrl_enable, +output jtagCtrl_capture, +output jtagCtrl_shift, +output jtagCtrl_update, +output jtagCtrl_reset, +input ut_jtagCtrl_tdi, +output ut_jtagCtrl_tdo, +input ut_jtagCtrl_enable, +input ut_jtagCtrl_capture, +input ut_jtagCtrl_shift, +input ut_jtagCtrl_update, +input ut_jtagCtrl_reset, input [3:0] system_gpio_0_io_read, output [3:0] system_gpio_0_io_write, output [3:0] system_gpio_0_io_writeEnable, -output system_i2c_0_io_sda_writeEnable, -output system_i2c_0_io_sda_write, -input system_i2c_0_io_sda_read, -output system_i2c_0_io_scl_writeEnable, -output system_i2c_0_io_scl_write, -input system_i2c_0_io_scl_read, -output system_watchdog_hardPanic_reset, -output userInterruptF, +output userInterruptA, output system_spi_0_io_sclk_write, output system_spi_0_io_data_0_writeEnable, input system_spi_0_io_data_0_read, @@ -287,6 +295,15 @@ input system_spi_0_io_data_3_read, output system_spi_0_io_data_3_write, output [3:0] system_spi_0_io_ss, output userInterruptD, +output userInterruptB, +output system_watchdog_hardPanic_reset, +output system_i2c_0_io_sda_writeEnable, +output system_i2c_0_io_sda_write, +input system_i2c_0_io_sda_read, +output system_i2c_0_io_scl_writeEnable, +output system_i2c_0_io_scl_write, +input system_i2c_0_io_scl_read, +output userInterruptF, output [15:0] io_apbSlave_0_PADDR, output io_apbSlave_0_PSEL, output io_apbSlave_0_PENABLE, @@ -295,26 +312,9 @@ output io_apbSlave_0_PWRITE, output [31:0] io_apbSlave_0_PWDATA, input [31:0] io_apbSlave_0_PRDATA, input io_apbSlave_0_PSLVERROR, -output userInterruptC, -output jtagCtrl_tdi, -input jtagCtrl_tdo, -output jtagCtrl_enable, -output jtagCtrl_capture, -output jtagCtrl_shift, -output jtagCtrl_update, -output jtagCtrl_reset, -input ut_jtagCtrl_tdi, -output ut_jtagCtrl_tdo, -input ut_jtagCtrl_enable, -input ut_jtagCtrl_capture, -input ut_jtagCtrl_shift, -input ut_jtagCtrl_update, -input ut_jtagCtrl_reset, output system_uart_0_io_txd, input system_uart_0_io_rxd, -output userInterruptB, -output userInterruptA, -output userInterruptE, +output userInterruptC, input [31:0] axiA_awaddr, input [7:0] axiA_awlen, input [2:0] axiA_awsize, @@ -365,11 +365,11 @@ input pll_system_locked wire flag_ok; wire system_watchdog_softPanic_interrupt; +wire system_gpio_0_io_interrupt_0; +wire system_gpio_0_io_interrupt_1; wire system_i2c_0_io_interrupt; wire system_spi_0_io_interrupt; wire system_uart_0_io_interrupt; -wire system_gpio_0_io_interrupt_0; -wire system_gpio_0_io_interrupt_1; `IP_MODULE_NAME(lppdr4_init) u_lppdr4_init ( @@ -409,25 +409,7 @@ assign system_i2c_0_io_scl_writeEnable=!system_i2c_0_io_scl_write; //axi4 bridge to various I/O -Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 u_Axi4PeripheralTop( -.io_apbSlave_0_PADDR(io_apbSlave_0_PADDR), -.io_apbSlave_0_PSEL(io_apbSlave_0_PSEL), -.io_apbSlave_0_PENABLE(io_apbSlave_0_PENABLE), -.io_apbSlave_0_PREADY(io_apbSlave_0_PREADY), -.io_apbSlave_0_PWRITE(io_apbSlave_0_PWRITE), -.io_apbSlave_0_PWDATA(io_apbSlave_0_PWDATA), -.io_apbSlave_0_PRDATA(io_apbSlave_0_PRDATA), -.io_apbSlave_0_PSLVERROR(io_apbSlave_0_PSLVERROR), -.system_i2c_0_io_interrupt(system_i2c_0_io_interrupt), -.system_i2c_0_io_sda_write(system_i2c_0_io_sda_write), -.system_i2c_0_io_sda_read(system_i2c_0_io_sda_read), -.system_i2c_0_io_scl_write(system_i2c_0_io_scl_write), -.system_i2c_0_io_scl_read(system_i2c_0_io_scl_read), -.system_gpio_0_io_interrupts_0(system_gpio_0_io_interrupt_0), -.system_gpio_0_io_interrupts_1(system_gpio_0_io_interrupt_1), -.system_gpio_0_io_read(system_gpio_0_io_read), -.system_gpio_0_io_write(system_gpio_0_io_write), -.system_gpio_0_io_writeEnable(system_gpio_0_io_writeEnable), +Axi4PeripheralTop_02c229e9056c4f0485f9e05005fe6a28 u_Axi4PeripheralTop( .system_spi_0_io_interrupt(system_spi_0_io_interrupt), .system_spi_0_io_sclk_write(system_spi_0_io_sclk_write), .system_spi_0_io_data_0_writeEnable(system_spi_0_io_data_0_writeEnable), @@ -443,9 +425,27 @@ Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 u_Axi4PeripheralTop( .system_spi_0_io_data_3_read(system_spi_0_io_data_3_read), .system_spi_0_io_data_3_write(system_spi_0_io_data_3_write), .system_spi_0_io_ss(system_spi_0_io_ss), +.system_gpio_0_io_interrupts_0(system_gpio_0_io_interrupt_0), +.system_gpio_0_io_interrupts_1(system_gpio_0_io_interrupt_1), +.system_gpio_0_io_read(system_gpio_0_io_read), +.system_gpio_0_io_write(system_gpio_0_io_write), +.system_gpio_0_io_writeEnable(system_gpio_0_io_writeEnable), +.system_i2c_0_io_interrupt(system_i2c_0_io_interrupt), +.system_i2c_0_io_sda_write(system_i2c_0_io_sda_write), +.system_i2c_0_io_sda_read(system_i2c_0_io_sda_read), +.system_i2c_0_io_scl_write(system_i2c_0_io_scl_write), +.system_i2c_0_io_scl_read(system_i2c_0_io_scl_read), .system_uart_0_io_interrupt(system_uart_0_io_interrupt), .system_uart_0_io_txd(system_uart_0_io_txd), .system_uart_0_io_rxd(system_uart_0_io_rxd), +.io_apbSlave_0_PADDR(io_apbSlave_0_PADDR), +.io_apbSlave_0_PSEL(io_apbSlave_0_PSEL), +.io_apbSlave_0_PENABLE(io_apbSlave_0_PENABLE), +.io_apbSlave_0_PREADY(io_apbSlave_0_PREADY), +.io_apbSlave_0_PWRITE(io_apbSlave_0_PWRITE), +.io_apbSlave_0_PWDATA(io_apbSlave_0_PWDATA), +.io_apbSlave_0_PRDATA(io_apbSlave_0_PRDATA), +.io_apbSlave_0_PSLVERROR(io_apbSlave_0_PSLVERROR), .system_watchdog_hardPanic_reset(system_watchdog_hardPanic_reset), .system_watchdog_logic_panics_0(system_watchdog_softPanic_interrupt), .axi_awvalid(axiA_awvalid), @@ -576,11 +576,12 @@ endmodule // Generator : SpinalHDL dev git head : a69f4b9a329be784802c37cd8038b7dc9aec3094 -// Component : Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 +// Component : Axi4PeripheralTop_02c229e9056c4f0485f9e05005fe6a28 +// Git hash : 82c05ac4dc40ada579a31a16a4321a3544828727 `timescale 1ns/1ps -module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralTop_02c229e9056c4f0485f9e05005fe6a28 ( input wire axi_awvalid, output wire axi_awready, input wire [23:0] axi_awaddr, @@ -1156,7 +1157,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( wire [31:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_data_5; wire [2:0] bmbPeripheral_bmb_withoutMask_rsp_payload_fragment_context_5; - Axi4PeripheralStreamArbiter_be6ad777990c4e5089d0b11c63cc2698 streamArbiter ( + Axi4PeripheralStreamArbiter_02c229e9056c4f0485f9e05005fe6a28 streamArbiter ( .io_inputs_0_valid (axi_ar_halfPipe_valid ), //i .io_inputs_0_ready (streamArbiter_io_inputs_0_ready ), //o .io_inputs_0_payload_addr (axi_ar_halfPipe_payload_addr[23:0] ), //i @@ -1183,7 +1184,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralAxi4SharedToBmb_be6ad777990c4e5089d0b11c63cc2698 axiToBmb ( + Axi4PeripheralAxi4SharedToBmb_02c229e9056c4f0485f9e05005fe6a28 axiToBmb ( .io_axi_arw_valid (axiShared_arw_valid ), //i .io_axi_arw_ready (axiToBmb_io_axi_arw_ready ), //o .io_axi_arw_payload_addr (axiShared_arw_payload_addr[23:0] ), //i @@ -1221,7 +1222,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .io_bmb_rsp_payload_fragment_opcode (bmbHandle_decoder_io_input_rsp_payload_fragment_opcode ), //i .io_bmb_rsp_payload_fragment_data (bmbHandle_decoder_io_input_rsp_payload_fragment_data[31:0]) //i ); - Axi4PeripheralBmbDecoder_be6ad777990c4e5089d0b11c63cc2698 bmbHandle_decoder ( + Axi4PeripheralBmbDecoder_02c229e9056c4f0485f9e05005fe6a28 bmbHandle_decoder ( .io_input_cmd_valid (axiToBmb_io_bmb_cmd_valid ), //i .io_input_cmd_ready (bmbHandle_decoder_io_input_cmd_ready ), //o .io_input_cmd_payload_last (axiToBmb_io_bmb_cmd_payload_last ), //i @@ -1255,7 +1256,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbUnburstify_be6ad777990c4e5089d0b11c63cc2698 bmbHandle_unburstify ( + Axi4PeripheralBmbUnburstify_02c229e9056c4f0485f9e05005fe6a28 bmbHandle_unburstify ( .io_input_cmd_valid (bmbHandle_decoder_io_outputs_0_cmd_valid ), //i .io_input_cmd_ready (bmbHandle_unburstify_io_input_cmd_ready ), //o .io_input_cmd_payload_last (bmbHandle_decoder_io_outputs_0_cmd_payload_last ), //i @@ -1289,7 +1290,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbDecoder_1_be6ad777990c4e5089d0b11c63cc2698 bmbPeripheral_bmb_decoder ( + Axi4PeripheralBmbDecoder_1_02c229e9056c4f0485f9e05005fe6a28 bmbPeripheral_bmb_decoder ( .io_input_cmd_valid (bmbPeripheral_bmb_cmd_valid ), //i .io_input_cmd_ready (bmbPeripheral_bmb_decoder_io_input_cmd_ready ), //o .io_input_cmd_payload_last (bmbPeripheral_bmb_cmd_payload_last ), //i @@ -1398,7 +1399,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 system_uart_0_io_logic ( + Axi4PeripheralBmbUartCtrl_02c229e9056c4f0485f9e05005fe6a28 system_uart_0_io_logic ( .io_bus_cmd_valid (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid ), //i .io_bus_cmd_ready (system_uart_0_io_logic_io_bus_cmd_ready ), //o .io_bus_cmd_payload_last (system_uart_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last ), //i @@ -1419,7 +1420,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 system_spi_0_io_logic ( + Axi4PeripheralBmbSpiXdrMasterCtrl_02c229e9056c4f0485f9e05005fe6a28 system_spi_0_io_logic ( .io_ctrl_cmd_valid (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid ), //i .io_ctrl_cmd_ready (system_spi_0_io_logic_io_ctrl_cmd_ready ), //o .io_ctrl_cmd_payload_last (system_spi_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last ), //i @@ -1452,7 +1453,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbI2cCtrl_be6ad777990c4e5089d0b11c63cc2698 system_i2c_0_io_logic ( + Axi4PeripheralBmbI2cCtrl_02c229e9056c4f0485f9e05005fe6a28 system_i2c_0_io_logic ( .io_ctrl_cmd_valid (system_i2c_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_valid ), //i .io_ctrl_cmd_ready (system_i2c_0_io_logic_io_ctrl_cmd_ready ), //o .io_ctrl_cmd_payload_last (system_i2c_0_io_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_halfPipe_payload_last ), //i @@ -1475,7 +1476,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbGpio2_be6ad777990c4e5089d0b11c63cc2698 system_gpio_0_io_logic ( + Axi4PeripheralBmbGpio2_02c229e9056c4f0485f9e05005fe6a28 system_gpio_0_io_logic ( .io_gpio_read (system_gpio_0_io_read[3:0] ), //i .io_gpio_write (system_gpio_0_io_logic_io_gpio_write[3:0] ), //o .io_gpio_writeEnable (system_gpio_0_io_logic_io_gpio_writeEnable[3:0] ), //o @@ -1497,7 +1498,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbWatchdog_be6ad777990c4e5089d0b11c63cc2698 system_watchdog_logic_logic ( + Axi4PeripheralBmbWatchdog_02c229e9056c4f0485f9e05005fe6a28 system_watchdog_logic_logic ( .io_bus_cmd_valid (system_watchdog_logic_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid ), //i .io_bus_cmd_ready (system_watchdog_logic_logic_io_bus_cmd_ready ), //o .io_bus_cmd_payload_last (system_watchdog_logic_ctrl_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last ), //i @@ -1517,7 +1518,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralBmbToApb3Bridge_be6ad777990c4e5089d0b11c63cc2698 io_apbSlave_0_logic ( + Axi4PeripheralBmbToApb3Bridge_02c229e9056c4f0485f9e05005fe6a28 io_apbSlave_0_logic ( .io_input_cmd_valid (io_apbSlave_0_input_slaveModel_arbiterGen_oneToOne_arbiter_cmd_valid ), //i .io_input_cmd_ready (io_apbSlave_0_logic_io_input_cmd_ready ), //o .io_input_cmd_payload_last (io_apbSlave_0_input_slaveModel_arbiterGen_oneToOne_arbiter_cmd_payload_last ), //i @@ -1990,7 +1991,7 @@ module Axi4PeripheralTop_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbToApb3Bridge_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbToApb3Bridge_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_input_cmd_valid, output wire io_input_cmd_ready, input wire io_input_cmd_payload_last, @@ -2141,7 +2142,7 @@ module Axi4PeripheralBmbToApb3Bridge_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbWatchdog_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbWatchdog_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_bus_cmd_valid, output wire io_bus_cmd_ready, input wire io_bus_cmd_payload_last, @@ -2220,14 +2221,14 @@ module Axi4PeripheralBmbWatchdog_be6ad777990c4e5089d0b11c63cc2698 ( reg [15:0] _zz_io_limit_1; reg [15:0] _zz_io_limit_2; - Axi4PeripheralPrescaler_be6ad777990c4e5089d0b11c63cc2698 wd_prescaler ( + Axi4PeripheralPrescaler_02c229e9056c4f0485f9e05005fe6a28 wd_prescaler ( .io_clear (wd_prescaler_io_clear ), //i .io_limit (_zz_io_limit[23:0] ), //i .io_overflow (wd_prescaler_io_overflow), //o .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralTimer_be6ad777990c4e5089d0b11c63cc2698 wd_counters_0_timer ( + Axi4PeripheralTimer_02c229e9056c4f0485f9e05005fe6a28 wd_counters_0_timer ( .io_tick (wd_prescaler_io_overflow ), //i .io_clear (wd_counters_0_clear ), //i .io_limit (_zz_io_limit_1[15:0] ), //i @@ -2236,7 +2237,7 @@ module Axi4PeripheralBmbWatchdog_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralTimer_be6ad777990c4e5089d0b11c63cc2698 wd_counters_1_timer ( + Axi4PeripheralTimer_02c229e9056c4f0485f9e05005fe6a28 wd_counters_1_timer ( .io_tick (wd_prescaler_io_overflow ), //i .io_clear (wd_counters_1_clear ), //i .io_limit (_zz_io_limit_2[15:0] ), //i @@ -2480,7 +2481,7 @@ module Axi4PeripheralBmbWatchdog_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbGpio2_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbGpio2_02c229e9056c4f0485f9e05005fe6a28 ( input wire [3:0] io_gpio_read, output reg [3:0] io_gpio_write, output reg [3:0] io_gpio_writeEnable, @@ -2774,7 +2775,7 @@ module Axi4PeripheralBmbGpio2_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbI2cCtrl_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbI2cCtrl_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_ctrl_cmd_valid, output wire io_ctrl_cmd_ready, input wire io_ctrl_cmd_payload_last, @@ -3073,7 +3074,7 @@ module Axi4PeripheralBmbI2cCtrl_be6ad777990c4e5089d0b11c63cc2698 ( assign _zz_bridge_interruptCtrl_filterGen_flag = 1'b0; assign _zz_bridge_interruptCtrl_clockGenExit_flag = 1'b0; assign _zz_bridge_interruptCtrl_clockGenEnter_flag = 1'b0; - Axi4PeripheralI2cSlave_be6ad777990c4e5089d0b11c63cc2698 i2cCtrl ( + Axi4PeripheralI2cSlave_02c229e9056c4f0485f9e05005fe6a28 i2cCtrl ( .io_i2c_sda_write (i2cCtrl_io_i2c_sda_write ), //o .io_i2c_sda_read (bridge_i2cBuffer_sda_read ), //i .io_i2c_scl_write (i2cCtrl_io_i2c_scl_write ), //o @@ -4424,7 +4425,7 @@ module Axi4PeripheralBmbI2cCtrl_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbSpiXdrMasterCtrl_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_ctrl_cmd_valid, output wire io_ctrl_cmd_ready, input wire io_ctrl_cmd_payload_last, @@ -4564,7 +4565,7 @@ module Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 ( reg [3:0] _zz_io_config_ss_activeHigh; wire [1:0] _zz_io_config_kind_cpol_1; - Axi4PeripheralTopLevel_be6ad777990c4e5089d0b11c63cc2698 ctrl ( + Axi4PeripheralTopLevel_02c229e9056c4f0485f9e05005fe6a28 ctrl ( .io_config_kind_cpol (_zz_io_config_kind_cpol ), //i .io_config_kind_cpha (_zz_io_config_kind_cpha ), //i .io_config_sclkToggle (_zz_io_config_sclkToggle[11:0] ), //i @@ -4598,7 +4599,7 @@ module Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralStreamFifo_2_be6ad777990c4e5089d0b11c63cc2698 mapping_cmdLogic_streamUnbuffered_queueWithAvailability ( + Axi4PeripheralStreamFifo_2_02c229e9056c4f0485f9e05005fe6a28 mapping_cmdLogic_streamUnbuffered_queueWithAvailability ( .io_push_valid (mapping_cmdLogic_streamUnbuffered_valid ), //i .io_push_ready (mapping_cmdLogic_streamUnbuffered_queueWithAvailability_io_push_ready ), //o .io_push_payload_kind (mapping_cmdLogic_streamUnbuffered_payload_kind ), //i @@ -4617,7 +4618,7 @@ module Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralStreamFifo_3_be6ad777990c4e5089d0b11c63cc2698 ctrl_io_rsp_queueWithOccupancy ( + Axi4PeripheralStreamFifo_3_02c229e9056c4f0485f9e05005fe6a28 ctrl_io_rsp_queueWithOccupancy ( .io_push_valid (ctrl_io_rsp_toStream_valid ), //i .io_push_ready (ctrl_io_rsp_queueWithOccupancy_io_push_ready ), //o .io_push_payload_data (ctrl_io_rsp_toStream_payload_data[7:0] ), //i @@ -4903,7 +4904,7 @@ module Axi4PeripheralBmbSpiXdrMasterCtrl_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbUartCtrl_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_bus_cmd_valid, output wire io_bus_cmd_ready, input wire io_bus_cmd_payload_last, @@ -5031,7 +5032,7 @@ module Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( assign _zz_bridge_misc_doBreak = 1'b1; assign _zz_bridge_misc_doBreak_1 = 1'b0; assign _zz_busCtrl_rsp_payload_fragment_data = (8'h80 - bridge_write_streamUnbuffered_queueWithOccupancy_io_occupancy); - Axi4PeripheralUartCtrl_be6ad777990c4e5089d0b11c63cc2698 uartCtrl ( + Axi4PeripheralUartCtrl_02c229e9056c4f0485f9e05005fe6a28 uartCtrl ( .io_config_frame_dataLength (bridge_uartConfigReg_frame_dataLength[2:0] ), //i .io_config_frame_stop (bridge_uartConfigReg_frame_stop ), //i .io_config_frame_parity (bridge_uartConfigReg_frame_parity[1:0] ), //i @@ -5050,7 +5051,7 @@ module Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralStreamFifo_be6ad777990c4e5089d0b11c63cc2698 bridge_write_streamUnbuffered_queueWithOccupancy ( + Axi4PeripheralStreamFifo_02c229e9056c4f0485f9e05005fe6a28 bridge_write_streamUnbuffered_queueWithOccupancy ( .io_push_valid (bridge_write_streamUnbuffered_valid ), //i .io_push_ready (bridge_write_streamUnbuffered_queueWithOccupancy_io_push_ready ), //o .io_push_payload (bridge_write_streamUnbuffered_payload[7:0] ), //i @@ -5063,7 +5064,7 @@ module Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralStreamFifo_be6ad777990c4e5089d0b11c63cc2698 uartCtrl_io_read_queueWithOccupancy ( + Axi4PeripheralStreamFifo_02c229e9056c4f0485f9e05005fe6a28 uartCtrl_io_read_queueWithOccupancy ( .io_push_valid (uartCtrl_io_read_valid ), //i .io_push_ready (uartCtrl_io_read_queueWithOccupancy_io_push_ready ), //o .io_push_payload (uartCtrl_io_read_payload[7:0] ), //i @@ -5395,7 +5396,7 @@ module Axi4PeripheralBmbUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbDecoder_1_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbDecoder_1_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_input_cmd_valid, output wire io_input_cmd_ready, input wire io_input_cmd_payload_last, @@ -5800,7 +5801,7 @@ module Axi4PeripheralBmbDecoder_1_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbUnburstify_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbUnburstify_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_input_cmd_valid, output reg io_input_cmd_ready, input wire io_input_cmd_payload_last, @@ -6010,7 +6011,7 @@ module Axi4PeripheralBmbUnburstify_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBmbDecoder_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBmbDecoder_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_input_cmd_valid, output wire io_input_cmd_ready, input wire io_input_cmd_payload_last, @@ -6199,7 +6200,7 @@ module Axi4PeripheralBmbDecoder_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralAxi4SharedToBmb_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralAxi4SharedToBmb_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_axi_arw_valid, output wire io_axi_arw_ready, input wire [23:0] io_axi_arw_payload_addr, @@ -6283,7 +6284,7 @@ module Axi4PeripheralAxi4SharedToBmb_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralStreamArbiter_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralStreamArbiter_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_inputs_0_valid, output wire io_inputs_0_ready, input wire [23:0] io_inputs_0_payload_addr, @@ -6373,9 +6374,9 @@ module Axi4PeripheralStreamArbiter_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -//Axi4PeripheralTimer_1 replaced by Axi4PeripheralTimer_be6ad777990c4e5089d0b11c63cc2698 +//Axi4PeripheralTimer_1 replaced by Axi4PeripheralTimer_02c229e9056c4f0485f9e05005fe6a28 -module Axi4PeripheralTimer_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralTimer_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_tick, input wire io_clear, input wire [15:0] io_limit, @@ -6421,7 +6422,7 @@ module Axi4PeripheralTimer_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralPrescaler_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralPrescaler_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_clear, input wire [23:0] io_limit, output wire io_overflow, @@ -6444,7 +6445,7 @@ module Axi4PeripheralPrescaler_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralI2cSlave_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralI2cSlave_02c229e9056c4f0485f9e05005fe6a28 ( output wire io_i2c_sda_write, input wire io_i2c_sda_read, output wire io_i2c_scl_write, @@ -6545,13 +6546,13 @@ module Axi4PeripheralI2cSlave_be6ad777990c4e5089d0b11c63cc2698 ( `endif - (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_1_be6ad777990c4e5089d0b11c63cc2698 io_i2c_scl_read_buffercc ( + (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_1_02c229e9056c4f0485f9e05005fe6a28 io_i2c_scl_read_buffercc ( .io_dataIn (io_i2c_scl_read ), //i .io_dataOut (io_i2c_scl_read_buffercc_io_dataOut), //o .clk (clk ), //i .reset (reset ) //i ); - (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_1_be6ad777990c4e5089d0b11c63cc2698 io_i2c_sda_read_buffercc ( + (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_1_02c229e9056c4f0485f9e05005fe6a28 io_i2c_sda_read_buffercc ( .io_dataIn (io_i2c_sda_read ), //i .io_dataOut (io_i2c_sda_read_buffercc_io_dataOut), //o .clk (clk ), //i @@ -6790,7 +6791,7 @@ module Axi4PeripheralI2cSlave_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralStreamFifo_3_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralStreamFifo_3_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_push_valid, output wire io_push_ready, input wire [7:0] io_push_payload_data, @@ -6944,7 +6945,7 @@ module Axi4PeripheralStreamFifo_3_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralStreamFifo_2_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralStreamFifo_2_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_push_valid, output wire io_push_ready, input wire io_push_payload_kind, @@ -7129,7 +7130,7 @@ module Axi4PeripheralStreamFifo_2_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralTopLevel_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralTopLevel_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_config_kind_cpol, input wire io_config_kind_cpha, input wire [11:0] io_config_sclkToggle, @@ -7776,9 +7777,9 @@ module Axi4PeripheralTopLevel_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -//Axi4PeripheralStreamFifo_1 replaced by Axi4PeripheralStreamFifo_be6ad777990c4e5089d0b11c63cc2698 +//Axi4PeripheralStreamFifo_1 replaced by Axi4PeripheralStreamFifo_02c229e9056c4f0485f9e05005fe6a28 -module Axi4PeripheralStreamFifo_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralStreamFifo_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_push_valid, output wire io_push_ready, input wire [7:0] io_push_payload, @@ -7932,7 +7933,7 @@ module Axi4PeripheralStreamFifo_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralUartCtrl_02c229e9056c4f0485f9e05005fe6a28 ( input wire [2:0] io_config_frame_dataLength, input wire [0:0] io_config_frame_stop, input wire [1:0] io_config_frame_parity, @@ -7976,7 +7977,7 @@ module Axi4PeripheralUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( `endif - Axi4PeripheralUartCtrlTx_be6ad777990c4e5089d0b11c63cc2698 tx ( + Axi4PeripheralUartCtrlTx_02c229e9056c4f0485f9e05005fe6a28 tx ( .io_configFrame_dataLength (io_config_frame_dataLength[2:0]), //i .io_configFrame_stop (io_config_frame_stop ), //i .io_configFrame_parity (io_config_frame_parity[1:0] ), //i @@ -7990,7 +7991,7 @@ module Axi4PeripheralUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( .clk (clk ), //i .reset (reset ) //i ); - Axi4PeripheralUartCtrlRx_be6ad777990c4e5089d0b11c63cc2698 rx ( + Axi4PeripheralUartCtrlRx_02c229e9056c4f0485f9e05005fe6a28 rx ( .io_configFrame_dataLength (io_config_frame_dataLength[2:0]), //i .io_configFrame_stop (io_config_frame_stop ), //i .io_configFrame_parity (io_config_frame_parity[1:0] ), //i @@ -8061,9 +8062,9 @@ module Axi4PeripheralUartCtrl_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -//Axi4PeripheralBufferCC_2 replaced by Axi4PeripheralBufferCC_1_be6ad777990c4e5089d0b11c63cc2698 +//Axi4PeripheralBufferCC_2 replaced by Axi4PeripheralBufferCC_1_02c229e9056c4f0485f9e05005fe6a28 -module Axi4PeripheralBufferCC_1_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBufferCC_1_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_dataIn, output wire io_dataOut, input wire clk, @@ -8087,7 +8088,7 @@ module Axi4PeripheralBufferCC_1_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralUartCtrlRx_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralUartCtrlRx_02c229e9056c4f0485f9e05005fe6a28 ( input wire [2:0] io_configFrame_dataLength, input wire [0:0] io_configFrame_stop, input wire [1:0] io_configFrame_parity, @@ -8166,7 +8167,7 @@ module Axi4PeripheralUartCtrlRx_be6ad777990c4e5089d0b11c63cc2698 ( assign _zz_sampler_value_6 = 1'b1; assign _zz_sampler_value_1 = (1'b1 && sampler_samples_0); assign _zz_sampler_value_2 = 1'b1; - (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_be6ad777990c4e5089d0b11c63cc2698 io_rxd_buffercc ( + (* keep_hierarchy = "TRUE" *) Axi4PeripheralBufferCC_02c229e9056c4f0485f9e05005fe6a28 io_rxd_buffercc ( .io_dataIn (io_rxd ), //i .io_dataOut (io_rxd_buffercc_io_dataOut), //o .clk (clk ), //i @@ -8381,7 +8382,7 @@ module Axi4PeripheralUartCtrlRx_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralUartCtrlTx_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralUartCtrlTx_02c229e9056c4f0485f9e05005fe6a28 ( input wire [2:0] io_configFrame_dataLength, input wire [0:0] io_configFrame_stop, input wire [1:0] io_configFrame_parity, @@ -8621,7 +8622,7 @@ module Axi4PeripheralUartCtrlTx_be6ad777990c4e5089d0b11c63cc2698 ( endmodule -module Axi4PeripheralBufferCC_be6ad777990c4e5089d0b11c63cc2698 ( +module Axi4PeripheralBufferCC_02c229e9056c4f0485f9e05005fe6a28 ( input wire io_dataIn, output wire io_dataOut, input wire clk, diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_define.vh b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_define.vh index 3efcf53..c747260 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_define.vh +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_define.vh @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 1.23.0 +// Version: 2025.2.288.2.10 +// IP Version: 1.22.0 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.v b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.v index 8b0ee7a..eb091f7 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.v +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 1.23.0 +// Version: 2025.2.288.2.10 +// IP Version: 1.22.0 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.vhd b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.vhd index e587f31..e161e0a 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.vhd +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.vhd @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +-- Copyright (C) 2013-2025 Efinix Inc. All rights reserved. -- -- This document contains proprietary information which is -- protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_wrapper.v b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_wrapper.v index cc9ad4b..954e7b6 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_wrapper.v +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/EfxSapphireHpSoc_wrapper.v @@ -1,21 +1,8 @@ module EfxSapphireHpSoc_wrapper ( -output system_uart_0_io_txd, -input system_uart_0_io_rxd, +output userInterruptI, input io_cfuClk, input io_cfuReset, -output userInterruptC, -input [3:0] system_gpio_0_io_read, -output [3:0] system_gpio_0_io_write, -output [3:0] system_gpio_0_io_writeEnable, -input cpu1_customInstruction_cmd_valid, -output cpu1_customInstruction_cmd_ready, -input [9:0] cpu1_customInstruction_function_id, -input [31:0] cpu1_customInstruction_inputs_0, -input [31:0] cpu1_customInstruction_inputs_1, -output cpu1_customInstruction_rsp_valid, -input cpu1_customInstruction_rsp_ready, -output [31:0] cpu1_customInstruction_outputs_0, -output system_watchdog_hardPanic_reset, +output userInterruptB, output jtagCtrl_tdi, input jtagCtrl_tdo, output jtagCtrl_enable, @@ -30,21 +17,34 @@ input ut_jtagCtrl_capture, input ut_jtagCtrl_shift, input ut_jtagCtrl_update, input ut_jtagCtrl_reset, +input cpu3_customInstruction_cmd_valid, +output cpu3_customInstruction_cmd_ready, +input [9:0] cpu3_customInstruction_function_id, +input [31:0] cpu3_customInstruction_inputs_0, +input [31:0] cpu3_customInstruction_inputs_1, +output cpu3_customInstruction_rsp_valid, +input cpu3_customInstruction_rsp_ready, +output [31:0] cpu3_customInstruction_outputs_0, +output userInterruptC, +output userInterruptG, output system_i2c_0_io_sda_writeEnable, output system_i2c_0_io_sda_write, input system_i2c_0_io_sda_read, output system_i2c_0_io_scl_writeEnable, output system_i2c_0_io_scl_write, input system_i2c_0_io_scl_read, -output userInterruptD, -input cpu0_customInstruction_cmd_valid, -output cpu0_customInstruction_cmd_ready, -input [9:0] cpu0_customInstruction_function_id, -input [31:0] cpu0_customInstruction_inputs_0, -input [31:0] cpu0_customInstruction_inputs_1, -output cpu0_customInstruction_rsp_valid, -input cpu0_customInstruction_rsp_ready, -output [31:0] cpu0_customInstruction_outputs_0, +input [3:0] system_gpio_0_io_read, +output [3:0] system_gpio_0_io_write, +output [3:0] system_gpio_0_io_writeEnable, +output system_watchdog_hardPanic_reset, +input cpu1_customInstruction_cmd_valid, +output cpu1_customInstruction_cmd_ready, +input [9:0] cpu1_customInstruction_function_id, +input [31:0] cpu1_customInstruction_inputs_0, +input [31:0] cpu1_customInstruction_inputs_1, +output cpu1_customInstruction_rsp_valid, +input cpu1_customInstruction_rsp_ready, +output [31:0] cpu1_customInstruction_outputs_0, output system_spi_0_io_sclk_write, output system_spi_0_io_data_0_writeEnable, input system_spi_0_io_data_0_read, @@ -60,28 +60,7 @@ input system_spi_0_io_data_3_read, output system_spi_0_io_data_3_write, output [3:0] system_spi_0_io_ss, output userInterruptF, -output userInterruptG, -output userInterruptE, -output userInterruptI, output userInterruptH, -input cpu2_customInstruction_cmd_valid, -output cpu2_customInstruction_cmd_ready, -input [9:0] cpu2_customInstruction_function_id, -input [31:0] cpu2_customInstruction_inputs_0, -input [31:0] cpu2_customInstruction_inputs_1, -output cpu2_customInstruction_rsp_valid, -input cpu2_customInstruction_rsp_ready, -output [31:0] cpu2_customInstruction_outputs_0, -input cpu3_customInstruction_cmd_valid, -output cpu3_customInstruction_cmd_ready, -input [9:0] cpu3_customInstruction_function_id, -input [31:0] cpu3_customInstruction_inputs_0, -input [31:0] cpu3_customInstruction_inputs_1, -output cpu3_customInstruction_rsp_valid, -input cpu3_customInstruction_rsp_ready, -output [31:0] cpu3_customInstruction_outputs_0, -output userInterruptB, -output userInterruptA, output io_ddrMasters_0_aw_valid, input io_ddrMasters_0_aw_ready, output [31:0] io_ddrMasters_0_aw_payload_addr, @@ -124,6 +103,27 @@ input [1:0] io_ddrMasters_0_r_payload_resp, input io_ddrMasters_0_r_payload_last, input io_ddrMasters_0_clk, input io_ddrMasters_0_reset, +output system_uart_0_io_txd, +input system_uart_0_io_rxd, +output userInterruptA, +output userInterruptD, +input cpu2_customInstruction_cmd_valid, +output cpu2_customInstruction_cmd_ready, +input [9:0] cpu2_customInstruction_function_id, +input [31:0] cpu2_customInstruction_inputs_0, +input [31:0] cpu2_customInstruction_inputs_1, +output cpu2_customInstruction_rsp_valid, +input cpu2_customInstruction_rsp_ready, +output [31:0] cpu2_customInstruction_outputs_0, +input cpu0_customInstruction_cmd_valid, +output cpu0_customInstruction_cmd_ready, +input [9:0] cpu0_customInstruction_function_id, +input [31:0] cpu0_customInstruction_inputs_0, +input [31:0] cpu0_customInstruction_inputs_1, +output cpu0_customInstruction_rsp_valid, +input cpu0_customInstruction_rsp_ready, +output [31:0] cpu0_customInstruction_outputs_0, +output userInterruptE, input [31:0] axiA_awaddr, input [7:0] axiA_awlen, input [2:0] axiA_awsize, @@ -190,28 +190,16 @@ assign userInterruptI = 1'b0; //USER TO MODIFY /* INFO: USER TO MODIFY CODES BELOW */ /* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ /**/ -assign io_apbSlave_0_PREADY = 1'b1; -assign io_apbSlave_0_PRDATA = 32'd0; -//io_apbSlave_0_PADDR; -//io_apbSlave_0_PSEL; -//io_apbSlave_0_PENABLE; -//io_apbSlave_0_PWRITE; -//io_apbSlave_0_PWDATA; -//io_apbSlave_0_PSLVERROR; -/**/ -/* INFO: USER TO MODIFY CODES BELOW */ -/* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ -/**/ -assign cpu1_customInstruction_cmd_ready = 1'b1; -assign cpu1_customInstruction_rsp_valid = 1'b0; -assign cpu1_customInstruction_outputs_0 = 32'd0; +assign cpu0_customInstruction_cmd_ready = 1'b1; +assign cpu0_customInstruction_rsp_valid = 1'b0; +assign cpu0_customInstruction_outputs_0 = 32'd0; //io_cfuClk //io_cfyReset -//cpu1_customInstruction_rsp_ready -//cpu1_customInstruction_cmd_valid -//cpu1_customInstruction_function_id -//cpu1_customInstruction_inputs_0 -//cpu1_customInstruction_inputs_1 +//cpu0_customInstruction_rsp_ready +//cpu0_customInstruction_cmd_valid +//cpu0_customInstruction_function_id +//cpu0_customInstruction_inputs_0 +//cpu0_customInstruction_inputs_1 /**/ /* INFO: USER TO MODIFY CODES BELOW */ @@ -228,6 +216,33 @@ assign cpu3_customInstruction_outputs_0 = 32'd0; //cpu3_customInstruction_inputs_0 //cpu3_customInstruction_inputs_1 +/**/ +/* INFO: USER TO MODIFY CODES BELOW */ +/* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ +/**/ +assign cpu2_customInstruction_cmd_ready = 1'b1; +assign cpu2_customInstruction_rsp_valid = 1'b0; +assign cpu2_customInstruction_outputs_0 = 32'd0; +//io_cfuClk +//io_cfyReset +//cpu2_customInstruction_rsp_ready +//cpu2_customInstruction_cmd_valid +//cpu2_customInstruction_function_id +//cpu2_customInstruction_inputs_0 +//cpu2_customInstruction_inputs_1 + +/**/ +/* INFO: USER TO MODIFY CODES BELOW */ +/* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ +/**/ +assign io_apbSlave_0_PREADY = 1'b1; +assign io_apbSlave_0_PRDATA = 32'd0; +//io_apbSlave_0_PADDR; +//io_apbSlave_0_PSEL; +//io_apbSlave_0_PENABLE; +//io_apbSlave_0_PWRITE; +//io_apbSlave_0_PWDATA; +//io_apbSlave_0_PSLVERROR; /**/ /* INFO: USER TO MODIFY CODES BELOW */ /* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ @@ -275,37 +290,40 @@ assign io_ddrMasters_0_r_ready = 1'b1; /* INFO: USER TO MODIFY CODES BELOW */ /* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ /**/ -assign cpu0_customInstruction_cmd_ready = 1'b1; -assign cpu0_customInstruction_rsp_valid = 1'b0; -assign cpu0_customInstruction_outputs_0 = 32'd0; +assign cpu1_customInstruction_cmd_ready = 1'b1; +assign cpu1_customInstruction_rsp_valid = 1'b0; +assign cpu1_customInstruction_outputs_0 = 32'd0; //io_cfuClk //io_cfyReset -//cpu0_customInstruction_rsp_ready -//cpu0_customInstruction_cmd_valid -//cpu0_customInstruction_function_id -//cpu0_customInstruction_inputs_0 -//cpu0_customInstruction_inputs_1 - -/**/ -/* INFO: USER TO MODIFY CODES BELOW */ -/* INFO: REFER EXAMPLE DESIGN FOR IMPLEMENTATION DETAILS */ -/**/ -assign cpu2_customInstruction_cmd_ready = 1'b1; -assign cpu2_customInstruction_rsp_valid = 1'b0; -assign cpu2_customInstruction_outputs_0 = 32'd0; -//io_cfuClk -//io_cfyReset -//cpu2_customInstruction_rsp_ready -//cpu2_customInstruction_cmd_valid -//cpu2_customInstruction_function_id -//cpu2_customInstruction_inputs_0 -//cpu2_customInstruction_inputs_1 +//cpu1_customInstruction_rsp_ready +//cpu1_customInstruction_cmd_valid +//cpu1_customInstruction_function_id +//cpu1_customInstruction_inputs_0 +//cpu1_customInstruction_inputs_1 //axi4 bridge to various I/O EfxSapphireHpSoc_slb u_top_peripherals( -.userInterruptA(userInterruptA), +.userInterruptD(userInterruptD), +.system_watchdog_hardPanic_reset(system_watchdog_hardPanic_reset), +.io_apbSlave_0_PADDR(io_apbSlave_0_PADDR), +.io_apbSlave_0_PSEL(io_apbSlave_0_PSEL), +.io_apbSlave_0_PENABLE(io_apbSlave_0_PENABLE), +.io_apbSlave_0_PREADY(io_apbSlave_0_PREADY), +.io_apbSlave_0_PWRITE(io_apbSlave_0_PWRITE), +.io_apbSlave_0_PWDATA(io_apbSlave_0_PWDATA), +.io_apbSlave_0_PRDATA(io_apbSlave_0_PRDATA), +.io_apbSlave_0_PSLVERROR(io_apbSlave_0_PSLVERROR), +.userInterruptB(userInterruptB), +.userInterruptF(userInterruptF), +.userInterruptC(userInterruptC), +.system_i2c_0_io_sda_writeEnable(system_i2c_0_io_sda_writeEnable), +.system_i2c_0_io_sda_write(system_i2c_0_io_sda_write), +.system_i2c_0_io_sda_read(system_i2c_0_io_sda_read), +.system_i2c_0_io_scl_writeEnable(system_i2c_0_io_scl_writeEnable), +.system_i2c_0_io_scl_write(system_i2c_0_io_scl_write), +.system_i2c_0_io_scl_read(system_i2c_0_io_scl_read), .jtagCtrl_tdi(jtagCtrl_tdi), .jtagCtrl_tdo(jtagCtrl_tdo), .jtagCtrl_enable(jtagCtrl_enable), @@ -320,18 +338,7 @@ EfxSapphireHpSoc_slb u_top_peripherals( .ut_jtagCtrl_shift(ut_jtagCtrl_shift), .ut_jtagCtrl_update(ut_jtagCtrl_update), .ut_jtagCtrl_reset(ut_jtagCtrl_reset), -.userInterruptE(userInterruptE), -.userInterruptF(userInterruptF), -.userInterruptB(userInterruptB), -.io_apbSlave_0_PADDR(io_apbSlave_0_PADDR), -.io_apbSlave_0_PSEL(io_apbSlave_0_PSEL), -.io_apbSlave_0_PENABLE(io_apbSlave_0_PENABLE), -.io_apbSlave_0_PREADY(io_apbSlave_0_PREADY), -.io_apbSlave_0_PWRITE(io_apbSlave_0_PWRITE), -.io_apbSlave_0_PWDATA(io_apbSlave_0_PWDATA), -.io_apbSlave_0_PRDATA(io_apbSlave_0_PRDATA), -.io_apbSlave_0_PSLVERROR(io_apbSlave_0_PSLVERROR), -.system_watchdog_hardPanic_reset(system_watchdog_hardPanic_reset), +.userInterruptA(userInterruptA), .system_spi_0_io_sclk_write(system_spi_0_io_sclk_write), .system_spi_0_io_data_0_writeEnable(system_spi_0_io_data_0_writeEnable), .system_spi_0_io_data_0_read(system_spi_0_io_data_0_read), @@ -348,17 +355,10 @@ EfxSapphireHpSoc_slb u_top_peripherals( .system_spi_0_io_ss(system_spi_0_io_ss), .system_uart_0_io_txd(system_uart_0_io_txd), .system_uart_0_io_rxd(system_uart_0_io_rxd), -.userInterruptC(userInterruptC), +.userInterruptE(userInterruptE), .system_gpio_0_io_read(system_gpio_0_io_read), .system_gpio_0_io_write(system_gpio_0_io_write), .system_gpio_0_io_writeEnable(system_gpio_0_io_writeEnable), -.userInterruptD(userInterruptD), -.system_i2c_0_io_sda_writeEnable(system_i2c_0_io_sda_writeEnable), -.system_i2c_0_io_sda_write(system_i2c_0_io_sda_write), -.system_i2c_0_io_sda_read(system_i2c_0_io_sda_read), -.system_i2c_0_io_scl_writeEnable(system_i2c_0_io_scl_writeEnable), -.system_i2c_0_io_scl_write(system_i2c_0_io_scl_write), -.system_i2c_0_io_scl_read(system_i2c_0_io_scl_read), .axiA_awvalid(axiA_awvalid), .axiA_awready(axiA_awready), .axiA_awaddr(axiA_awaddr), diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/component.pickle b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/component.pickle index 608aebf..3bf560b 100644 Binary files a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/component.pickle and b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/component.pickle differ diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/graph.pickle b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/graph.pickle index 4f76955..e3d6abd 100644 Binary files a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/graph.pickle and b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/ipm/graph.pickle differ diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/settings.json b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/settings.json index 84b6da3..8b321bc 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/settings.json +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/settings.json @@ -3,13 +3,13 @@ "-o", "EfxSapphireHpSoc_slb", "--base_path", - "ip", + "/home/byron/Projects/wireguard_fpga/Ti375C529_devkit/ip", "--vlnv", { "vendor": "efinixinc.com", "library": "soc", "name": "efx_hard_soc", - "version": "1.23.0" + "version": "1.22.0" } ], "conf": { @@ -123,12 +123,17 @@ }, "output": { "external_script_Peripheral_Generator": [], - "external_source_source": [], + "external_source_source": [ + "EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb.v", + "EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_define.vh", + "EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.vhd", + "EfxSapphireHpSoc_slb/EfxSapphireHpSoc_slb_tmpl.v" + ], "external_script_PT_Configuration": [], "external_script_Peripheral_Post_Script": [], "external_script_Embedded_SW": [] }, "ooc_synthesis": {}, - "sw_version": "2026.1.132", - "external_path_option": "RELATIVE_PATH" + "sw_version": "2025.2.288.2.10", + "generated_date": "2026-08-10T02:10:51.920643+00:00" } \ No newline at end of file diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/Axi4PeripheralTop.v b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/Axi4PeripheralTop.v index 48546f3..b2a5d53 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/Axi4PeripheralTop.v +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/Axi4PeripheralTop.v @@ -1,5 +1,6 @@ // Generator : SpinalHDL dev git head : a69f4b9a329be784802c37cd8038b7dc9aec3094 // Component : Axi4PeripheralTop +// Git hash : 82c05ac4dc40ada579a31a16a4321a3544828727 `timescale 1ns/1ps diff --git a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/peri_config b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/peri_config index 571f0ba..c87f43e 100644 --- a/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/peri_config +++ b/Ti375C529_devkit/ip/EfxSapphireHpSoc_slb/source/peri_config @@ -1,8 +1,8 @@ ---apbSlave name=io_apbSlave_0,address=0x100000,size=65536 --uart name=system_uart_0_io,address=0x10000,interruptId=0 --peripheralFrequency 200000000 +--spi name=system_spi_0_io,address=0x30000,interruptId=3,width=8,ssCount=4 --PeripheralClock true --i2c name=system_i2c_0_io,address=0x20000,interruptId=6 +--apbSlave name=io_apbSlave_0,address=0x100000,size=65536 --watchdog name=system_watchdog,address=0x50000,interruptId=13,prescalerWidth=24,counters=2,countersWidth=16 ---spi name=system_spi_0_io,address=0x30000,interruptId=3,width=8,ssCount=4 --gpio name=system_gpio_0_io,address=0x40000,width=4,interrupts="0->9;1->10" diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch.v b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch.v index 35c79f3..e89ce24 100644 --- a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch.v +++ b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice @@ -43,7 +43,7 @@ // //////////////////////////////////////////////////////////////////////////////// -`define IP_UUID _ec96b3fb89244203bb74a6d5d477a76b +`define IP_UUID _f860ac11fa8043be8fa45e244a8a89a5 `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module gAXIM_2to1_switch @@ -97,18 +97,18 @@ module gAXIM_2to1_switch output [15:0] m_axi_wstrb, input [0:0] m_axi_wready, output [1:0] s_axi_wready, - input [5:0] s_axi_awprot, + input [7:0] s_axi_awprot, input [7:0] s_axi_awcache, input [7:0] s_axi_awqos, input [5:0] s_axi_awuser, input [7:0] s_axi_arqos, input [7:0] s_axi_arcache, - output [2:0] m_axi_awprot, + output [3:0] m_axi_awprot, input [15:0] s_axi_arid, input [5:0] s_axi_arsize, input [15:0] s_axi_arlen, input [3:0] s_axi_arburst, - input [5:0] s_axi_arprot, + input [7:0] s_axi_arprot, input [15:0] s_axi_awid, input [3:0] s_axi_awburst, input [15:0] s_axi_awlen, @@ -120,7 +120,7 @@ module gAXIM_2to1_switch output [3:0] m_axi_awcache, output [3:0] m_axi_awqos, output [2:0] m_axi_awuser, - output [2:0] m_axi_arprot, + output [3:0] m_axi_arprot, output [1:0] m_axi_arburst, output [7:0] m_axi_arlen, output [2:0] m_axi_arsize, @@ -250,219 +250,219 @@ endmodule `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -BSiclTfEX07oDTPwvSfmqSh37gsGawnAkFDdQtfz2b2aPAbkkOIevgA5jmAEpk8Z -jmjFoTAnEUNBHxHADHQl29GtYYLQLcTt1dvsb1L8xXXbyd41mZnW9qxR1yEXo2Km -PmHE4/laDDFnEAn08I7oinDvTWN/plGfuIWWaEXC4z7ls9W1O5jNY2gj1ZC0oyT4 -iwzQ3cMmgvMMfqkgA6T8wMNFL1jvPdUxnuGh8qa0Q5zso+v2lpzszj4ytZLI8JZz -ZeX/ipjz/4hUHkihXJPjFD+MetXdYJTpzRO3ZbxTOlyD1Ln8yDvo0qNPrgbzN9qq -YropxHtLb22q5bZxY+vKMw== +k0MNGAL+siJuDYrFA58rRJscMTUE6hiuNEylu7uA+mdVk/vCPJpUprjqZIgJ75i6 +csRX146zVh4AUQABC09rbvto0kqPbqsZwZGmdOm1W8NmGZIXLCsG4MZs984TiToI +QMOSc+XFr9GVx1rFODfIQCsRVOla6WZCpHrBZzFjmFwY4t9fXFQCs5fSkNbGyG6v +8YDvdegFPMYp5Qu9ccfxeosyrpdCBompAmWscbYmzMrmyFiInvb8Y5dyqCuve1NW +jirl6fz1954ypdomnZDn+X9k8zTCJAxovyf9Qxk6Q+/Pf6e6yRqEYBxT7dtZhWRG +tEQdKP3bt5KBf+EuwdVLuQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 9552 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -594,542 +594,530 @@ parameter IDLE = 0, `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -h798DEoPCCw6eC93sfxnz8ZJ5DmYibE3rGjjhE+YK5a3RIfjyfpuQmm+Qi6hiWsS -h21ZC3p98i4VCoRgq9ttjdMjEUVk6R1INC59AvJ35jeq6cjGdiMiIPwnlnHEAIqa -kQUAn5DZG6XDT0Q74iMGbdiR7Uqpt242DlxQT/RPahxewbF7bTMwF22aKiwUymVQ -WL77YlV9D3RHdY6gVwH+r4vNibfPRFoNglrFWdWkXgAM3QCILfTmCmNOrDP+tU67 -Sp1AnVUQDUfoMreLqPv9PxJK3wnCugVdw08bgxzbxycLpfzcQbzXtVTNLzpE9m/C -m4DQ47zqQmz4Zj4f/JVRfg== +f0DVmU/kdU862C3ryhjQlDsM4c/0bG91GM/Tt0YfOziNIhVBbdZsoYW2RTSSEC81 +yNXUBt7tFmZq4YDopiOye7MWsFmf8WWRQEL3slo6DkYqzPlqCgnjys82AVws5Cco +WGW89TXAcQAYHJy7oG8Ae9oSMdLa3PIQNp7mSA6rz4RhAKHQyvxQU3wr0zXDmYKl +CeyI1ZIu155HAUZL2bXguauGtJWtwaTXIrQO4i5/hXied5l3pm8lCdXsKbM1Enxx +V3E/sk/RBAVETx2fmYxracwCdN363LHRvYHyP4b2qkmUndhj47mK2s4d6wc/G0IJ +HQRhooSUf5bQscVy4yyOxw== `pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 25024 ) +`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 24464 ) `pragma protect data_block -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 -VhTvV5MqNhAZpXfPbkZ0rQ== +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 `pragma protect end_protected //pragma protect end @@ -1142,48 +1130,48 @@ VhTvV5MqNhAZpXfPbkZ0rQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -RwZLaWoAKLBm11tcUo3zg7WK2hPcNJvetUS0HcngH1N+uqVkxItkonJwS2nHozet -PZ4e0pcL7oMHU+YSSKFGF0HZtDLJ6ggz9Tjk65W4OruIfJxIuyYdw9nbusKhaJTz -khXz5VPO6s2gfnVif+az5zjoe7kudgxlxU7jmvaX9sbur5cFMS2KnJogDMLJcl1s -ZlLL+9F5h5+8PKCF6eoiFm6TtkD7MrBiDjMDu9eLqZ5t8VgWYRMKduwEQ9J2M3t/ -JcbjL7GG+1h3LkL6WEKxF8zVIpKiu3k7UC98wKI8mhEpZ8bChW07nVCr4PHLn2IX -BU9Qy5kOLqe8sKbl6LYs7g== +gQ+VauIuH+g40FNOpVzoPSXPaSSXzZWh6rE+e4zt/Higof5lTVqndEO2y+vyS/HT +Uz3/xsHmLa5/hfJOzrQ2WAbWJcFOc0pzmbDqYnUgEw1W4IUS1qcjifpXTLdxvwfy +rSWd00QRecQN7v+pyLFb6xf5TELzzsB2PAr6/xlRVs03sGcC8jpFMP1gppLRrh+C +xnDjMIBVdGmu01tJ1gcEY/913addbws7HLgMcMDLft0U/4zTbjE/rrDoC7+eO+3k +z9ZPUNkRvEPxurfsVZfIuglJuZJSqyaB+Khmc5Q1nMDb9IswcttQUM3RtjEksR13 +Y4OcKLh/ejWsVorB6JLJeA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1312 ) `pragma protect data_block -p0bIW99zYvQA4u0XRWnQ90s6MugNpXe6l31pFNyBhuxQU67mS/BBRtYtc25nySM/ -yHwfDVEt2eeSh2xZ2Kv1d8VWucKTg8lXrK+ooXsXcYiy61IB12mnjuKPa/FUxFS4 -JM2AiESAcF0ks9YGnHz5atWTSPAnEYKTqIrZDoYqJkbgClLiRdrZY+N2hC5jdZeW -cR1EkHw0PZqw6S2eCHL5hUi6ryPKMkre1oH3Xdag2DJT8qQxbuNqhhrm/L+8L8lX -f5F3asZ05yCB1pnJRqVPESYDajoN8u1lWD18RYsWX60ld2PcwCxsHkPOyoBvAV1u -PgCYq2l6s5FitBJR9RvIIWQXgYcJnkvvctXAE4sHkA/8YmzJKAUlmADFxObHh7nH -B9Tr9F5MMMItWtOlRVOB7r7GpKZ4CIu9H0pG8rHeitdTJzb//0sRPwO4Ifpq00gF -PYpm2+uw1qrcWOBG9wrbOEUMiFlt1c1y6CM7W0HiQg/FK+4Y4JiB7uaAlzUejTOI -zOL6no+QbQSWHIEVAYNpQGNcTG+AuFlhiSI5DitSGvW5yCLRLs7Fv5AnqLM6z1Qg -nRTXEKDaR/AFlAFB16izDRH4FYwpXtH01JTfdxvrFbPDjE2B07qlVwewnCVApXy1 -GNPPzEat9SO3vQ9t7PCKFzQV6OGGAn/dyMwguU6EDW8mcNxemcFiHUdiSfhhZpeH -IcnqAMISo7J5oznEHRV6eZ2t27p8fCR6kY+/9tdw+mhgfM47E9D+jOa2LZcvRNK0 -IxKxNWtgUL0KlYtkFTGEhG+p36IePpoZOlbFukyAkrvx2uvJdjDKNhR7fljgKZp9 -ntpSnYfXJhwQrP8yTvoXUhnLpaxBTrh8cyLUFVm+2UtqRrz/+WA/Du8u19N0NmoU -4Z65V0tXF/tW4DpeElKcg5Z9g3Srjon+LpuobgvaptlZ3rG7pXXklUAdxNfJ+4mu -g8S64RYvfLamt1za0XyFbePfAbEPHUNKbKIqzGRB92kxJ6jYjgC9RQHp35SL3T55 -2DhArYHiRs4HAieVOggerJ2mFKRe1jgXpNH28cIvReVtjhPSR0h2/N1kktJoFN9j -pAwsBXcE20H2DgeDq7MOl5klQOQIZqq2NOi/TtiDykzXOq9c52KT5YQDUiFYqQvD -H29baw+SyQUZTso78q8DVb5S1dB3XyHStAKgoGq93+Wz/B1RLpKYack4xd4rdS5s -pwx6XbBMdp7aDqOyz2KgKWf+dspEnt1aZSkLPUfnK1QqEuwBFSip0++f8lsYJwt6 -h2RR9rfNZmd8nt+mXhbGkKeiOagijsA/5zVB+4MgI0KR9sujHhdd3ikiYUTRDpcb -AA7w3mFn6w2oiAcHGimR/cBGrmo7m6L0USsPGqFYBLIQfdAn5dEBlb2BCoA5VFZj -jXKJF/jua7Y+DrPzh66goMGjpF9lBpoEP1rWQA/7bSpIp6mTsXcqppKrJq4X3UzK -fnxoXMOzyXak8Q0RLDFj9NSgAWzr4VmwVpFWnocoXpsQlisCkXdTJvGnor8LLZr9 -sDZmzgcSix39SaRGPrUkPl4jLdocSaImMFvFf75Ln2LkiFK2PwLHbdxu5OHmQoCw -7wBcsGkL2gXd3tYL2ns54yYSqMYHrxBbag+ndd5VaJnjZK34JNDCSh65qkKE7y7v -Behj6SqW7qWtdmufzd16RndX/9C4+tnd6CZRltVVSxqHORQEFpJfBX3qZLp11vTQ -Pib5SMqM0nVbJDVpqDeCAA== +fo0JdXfIQsWgrENhFGo0RRW9s/IV4eGBK5upzSxFjRkxTj+wCit1QKkd15jJgDu4 +P06Rnw+P2/Cu/tkXRjH7RGfSCa1EZ08cwLiSykEmyb+qQo8wTkOBh8KIag5m0P1t +XTuNeK4lZP50EUwL/4wSSMPuRtdpIAF+0PAXjdoge2gwhduxtVQZpgPO12dwk0Wo +Qyfuxrm/7iyjiETt18QCBk/PXC9JLX6a9hmtr8ujb+7IKQJFj1S7F9WxCZ1yamDs +e1D+l34aYZ5r3sBbAysWrg65oN3fAAd6bhptfeU2+BDBA8oKIcTClBK2f3pBUPul +8YV5xUU0+FGat/Rjkm2ZmKKpm9JD+w7ufesbJ2fqRCCex08yynx+EuV6lNupQQk3 +UbxIK2+04eVmLtY7V87103cxyVnLFXqAQY3XaG0AWBpO2Ew1NwH6CU4yFpyUAC84 +Bjztc1mHKONeueopzONq61tRDqarI0ex6IhDy04D9/zAOhMyBrEHzeR0UozXtK6Y +TB/qqFBgJmagIMQWcL03s2FYWQgGUU3PRQ4JiB57ubJG6H64M9UJUMXI7VXW245F +S0oLuBSWchTwY4/6zvioNieoCZgdkxOTUqHNuV4Zf7Epcgh3IQIZRzjBSpah3skn +kQwLdkHYbh3EzBAN0L4lF8u4LE/8SqwLPpsl91D8Qck2jzgNTYnbsG+t2tsum6n8 +wYvw9H2G6SCXAimDrg2Qy66lpdDA8XQf+1Pu8sYKlEd3GH9lQyGX+l4gx3OLuOtR +fAlYbOhHnFRDXMNE9ZG/I8VKDFToJD1/SjoKUnrz4TdMcQZn3Asrj6LyXsw5CHgd +zhf60BREHK5nXIJRGkqTlV0OyCbaEe0yTgmpWapYbnUcpX4UNu07ijUdSbUBReil +f2PULQwchd1Nh+nj49FyRm0SU4twHeYIMoSC2sMtPiJkuqAZPugzpBpKZUPnKzDd +VmHxPV5Fl4haVbGLfQj4rfl6Mqpqk2DLOiPmwiXnf7CTAjpnwNQ07KsBw6SKxLAe +YS+1RZFe1JQTA73Dv+hAjOEby2uC1tz9V61abAakI4omdhXK1WBGS7AW7VIkOhsa +U2d43C1vqygKdJzTQVB3SVqswMzruIiClRGEypfl8F1L7BIegRA7y6KJYY2lQ69u +7eDX8XmDYmXDiWgXqtWRALbhHrDi8EwOCp5Tts6KK1q+HZNB6UjiGUrGZ2/EhU4H +rNhfbS8YD9wTQtEs/QCi40wIeLIYjIf429BBIRU8k3na6ZwzGLdfxJnqsRLJ6E7X +aCiJk8iag4Wfv0HsAb9J8vDUKzzLHS5OYlHmEss6CTswBAYs7u8/UF9rlfvXy8Mb +z5tfh7xCXqOQpY1gF85w0agvdFKLhhUzfB2Y/XiH+P9zw8608Q4B2irkUuj0fbhU +/VGCOg52ghhNNkaio6JDtzCj/4nMf3QJwdYnJNTiSWLmN/D4rgU8FE7RObm2foEA +5qemSiCt9nYnRGtaRQ0jFh1zieourorN3TI49Lfh/b++M/Hq8OUZh7Uxs5ni4scB +RqEGxATE+29gCCCJ1S3HVi7fcit9xh2mupZnT+m3qHM+Jt01sv59AUJ/UFx/cNYz +qo1oB/NkzOstxVDMlcp8bOO+elF1X4n4wKeC0g/eMM8C+ffQiVT7Rqh2mYLgXQA7 +BhBS+E0RB6UhkxYPnRFEgtk0VLL54VPEVDTINYlLs+L3ZsWwYJs39Gen6vvvepYy +bujDTnnouQqtvD9ok3pkbA== `pragma protect end_protected //pragma protect end @@ -1196,45 +1184,45 @@ Pib5SMqM0nVbJDVpqDeCAA== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -V7fazAcYfn/upNWI2MrDSQamEge7Y8sqGyEbHWTTDvIkXpdIuRisL8LJjvy83vue -ZgYLruqRxsDQR/Wu7PMlj65sb/NkxpSPTHfwdQcOEP3MsixExszjuA1HqHtg+aNQ -uFOiuMhxVPj6PMHq/Hqrqa85QcEVSbWPuLxSaFzY0ndkgyErZck8cU+0bbs6pFmr -tNIeglsOu6Am3uxBT62KHdsx5/dbyBFUXzyoeMcVqVN/dSwFJEWKXykd+OnIo8cg -TAWc+EOAJ6ExmKO/aLU8Un5EpThP6h/F+4FSrXQ8+zAfJHLLmWelIILCIn9r270y -7CUxtRRDMVrzxeZaHx87Jw== +TpRHXtmr81JyoWaAtQOsoLu44jF5UvFDPdO5/CllOd3kdY7PwU2fkKx7bS6RlGe6 +282Wvc58pPBGh6uImNRfZkaAKTaspN+giuR1GHAo4nfIKi92dgY2DTW5JbEU67ml +1IGNiK4su606fm7n90PZ69MZadoZPNpUxZxzYbSs+I39eZWsgU+rtoUE2d35qjdW +UyorSD+O2F5Wv51CWlcWJyscNK886BFGFi72CtEY8IdYcolZ7hcONOhQT5jbhGWK +UFFTqjnMO6iVrEodujVvUgcUtFQSTl5/oHSkmacP7CSADA82+06uIHf+rByqHGTp +JNgtSAVN844IRP39n4T5EA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1200 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -1247,62 +1235,62 @@ AvKxciqIeVCjtaleTRBLEWnwUKa6wADHB0WNBFNEidDe8gAcwWkZyKkh/VaUiupU `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -idlb0ipwgIc0hiUfW9lCBvIc27j+O1T55dJ3BL9eUyC3AmELfvx2LyGUfXvUfYTf -8sHVL37lgxYwkxIH4ZSSZQ1GK2zLKlNHYUEmXZIR/WoNIg7U3rYo+/OAX5LDNWz3 -I3htHfdktV9gYc7iVdI9VNrqBa0Gg55NmIOrO+wM2ME4dVbdMJVDfW+oOu9rTeme -KOonn0oR5/zNCWcqkhf2z6BLLm49S0wwKQJc9Tn8j8aAVVAS5PR4HM/UAt+Pm5Qw -qUaeukXs5OImR86WKmCfOXrROtxYmBZ//zwyzxGdjene5Dzf1Lue74V7vg9Yy8Es -kofIx1Iiwvl5uhKqK0ZywQ== +TBCX5/gAT5S6xdVBuY05hYDsXmHLnm/0Yl4d4ayUlKrDe3IUWB3JcRtZJEwtIwhQ +wqO6qIYs21XvVt74eCxdt1SZXHRXXJiT196fD9q5vFrJxAQqeTDvH51bmshhKW+i +DwXpMTwZlLgBsT2BEP5C0RiiICy9chJTycHB7vHEh6lTXT6S/2H7bweTMlFCh6s6 +n5aHgBbfjk9BYIUSTuEvOxw9Yki0T44zjqGmjZ3qxkhk5Rae8iPLqCnjRTjNfqOE +zQtaoVQW+8NbATVUmZC4WlgxF/J03hq0TLeqLYfcuWR0uH9vLAWsUzHqlGMZvUSV +23zwmB8p0BqUeaj1cllyzw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1984 ) `pragma protect data_block -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 -M6eR/VTYArPQbA4OoPqXhQ== +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 +9Jse9KsUSQdI7bnqvPdYIQ== `pragma protect end_protected //pragma protect end @@ -1315,43 +1303,43 @@ M6eR/VTYArPQbA4OoPqXhQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -kjevziVpR4HNp6ABOs1UfEhnb+dX0JPweI6S3+LX30C9LF3xx7Xd/zMszyIOAsff -hodfZOinnjjXzBncB8lZ/iwEBQcN9AOUuJkxqHw0xEX9lKugu7WOxROcH+yiXxDJ -yy9yDzS1F865ocB3xO9FWkMnml1XZRqox2FTUI5GMVk0MxMQPCoaWPmG40cuqt8H -oNSQWIvbZ0bwp2zXvC4BQlkXD2oWWu6JxxVIVspZ7XmHHSfSB+gK8bmQIk2JZPQd -nB3A0s+SLUanWE/u+Muh6A5t3kkuvJ5Fy1rRHEwle6WO6L5S2arPlksoYEp7hfDo -eW9+LO7WnZdnt0b3dQw5Mw== +eiP/26NloMbfJbEe1aU/cN+AkTVidxKZaNv824TVZXkpjf5L1zEVLf4buBzXwSr1 +MiO1FaB1qgL+ZgKHLwNzc4IiIP0d7qYOaGR46jDr8/k9N2BVxXC3V0wJJ6yhDom9 +O7B9d2Lcm+b0UifdEaFcX3luTwZzXAQW83Bggnm4eVP275Vqog3REHo5wgsstEU3 +AG6o+oVDnNjZTPDPyJ4uHq9bjFFyvY3ga+lOo2iVymecnhCiRtjy3AFtvWBJW0ek +uhj8QvNYf04TXkRXdhdRfq/HDLr3M6Qa7/Xn6vGE+drFyRTL1nmH9wkjBBbD3swn +58tiwvvx3ajgMOCJeXfrXQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1104 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_define.vh b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_define.vh index cacbc6f..f49727e 100644 --- a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_define.vh +++ b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_define.vh @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.v b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.v index 59e2d33..7c70e62 100644 --- a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.v +++ b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.vhd b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.vhd index bced8de..9adec60 100644 --- a/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.vhd +++ b/Ti375C529_devkit/ip/gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.vhd @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +-- Copyright (C) 2013-2025 Efinix Inc. All rights reserved. -- -- This document contains proprietary information which is -- protected by copyright. All rights are reserved. This notice @@ -88,18 +88,18 @@ port ( m_axi_wstrb : out std_logic_vector(15 downto 0); m_axi_wready : in std_logic_vector(0 to 0); s_axi_wready : out std_logic_vector(1 downto 0); - s_axi_awprot : in std_logic_vector(5 downto 0); + s_axi_awprot : in std_logic_vector(7 downto 0); s_axi_awcache : in std_logic_vector(7 downto 0); s_axi_awqos : in std_logic_vector(7 downto 0); s_axi_awuser : in std_logic_vector(5 downto 0); s_axi_arqos : in std_logic_vector(7 downto 0); s_axi_arcache : in std_logic_vector(7 downto 0); - m_axi_awprot : out std_logic_vector(2 downto 0); + m_axi_awprot : out std_logic_vector(3 downto 0); s_axi_arid : in std_logic_vector(15 downto 0); s_axi_arsize : in std_logic_vector(5 downto 0); s_axi_arlen : in std_logic_vector(15 downto 0); s_axi_arburst : in std_logic_vector(3 downto 0); - s_axi_arprot : in std_logic_vector(5 downto 0); + s_axi_arprot : in std_logic_vector(7 downto 0); s_axi_awid : in std_logic_vector(15 downto 0); s_axi_awburst : in std_logic_vector(3 downto 0); s_axi_awlen : in std_logic_vector(15 downto 0); @@ -111,7 +111,7 @@ port ( m_axi_awcache : out std_logic_vector(3 downto 0); m_axi_awqos : out std_logic_vector(3 downto 0); m_axi_awuser : out std_logic_vector(2 downto 0); - m_axi_arprot : out std_logic_vector(2 downto 0); + m_axi_arprot : out std_logic_vector(3 downto 0); m_axi_arburst : out std_logic_vector(1 downto 0); m_axi_arlen : out std_logic_vector(7 downto 0); m_axi_arsize : out std_logic_vector(2 downto 0); diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/component.pickle b/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/component.pickle index 4f29ee4..05edf35 100644 Binary files a/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/component.pickle and b/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/component.pickle differ diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/graph.pickle b/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/graph.pickle index 0e78302..f915d4b 100644 Binary files a/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/graph.pickle and b/Ti375C529_devkit/ip/gAXIM_2to1_switch/ipm/graph.pickle differ diff --git a/Ti375C529_devkit/ip/gAXIM_2to1_switch/settings.json b/Ti375C529_devkit/ip/gAXIM_2to1_switch/settings.json index 481a3b7..ca90327 100644 --- a/Ti375C529_devkit/ip/gAXIM_2to1_switch/settings.json +++ b/Ti375C529_devkit/ip/gAXIM_2to1_switch/settings.json @@ -3,52 +3,94 @@ "-o", "gAXIM_2to1_switch", "--base_path", - "ip", + "/home/cslau/Desktop/Workspace/efinity/2025.1.95/project/Example_Ti/ip/EfxSapphireHpSoc_slb/Ti375C529_devkit/ip", "--vlnv", { "vendor": "efinixinc.com", "library": "axi_infra", "name": "efx_axi_interconnect", - "version": "5.6" + "version": "5.4" } ], "conf": { "ARB_MODE": "\"ROUND_ROBIN_1\"", - "S_PORTS": "1", + "S_PORTS": "2", "TABLE0_AXI_S0__MIN": "32'd0", - "TABLE0_AXI_S1__MIN": "32'd512", + "TABLE0_AXI_S1__MIN": "32'd268435456", "TABLE0_AXI_S2__MIN": "32'd285212672", "TABLE0_AXI_S3__MIN": "32'd286261248", "TABLE0_AXI_S4__MIN": "32'd536870912", "TABLE0_AXI_S5__MIN": "32'd805306368", "TABLE0_AXI_S6__MIN": "32'd1073741824", "TABLE0_AXI_S7__MIN": "32'd1090519040", - "TABLE0_AXI_S0__MAX": "32'd9", - "TABLE0_AXI_S1__MAX": "32'd8", + "TABLE0_AXI_S0__MAX": "32'd32", + "TABLE0_AXI_S1__MAX": "32'd24", "TABLE0_AXI_S2__MAX": "32'd12", "TABLE0_AXI_S3__MAX": "32'd20", "TABLE0_AXI_S4__MAX": "32'd28", "TABLE0_AXI_S5__MAX": "32'd28", "TABLE0_AXI_S6__MAX": "32'd24", "TABLE0_AXI_S7__MAX": "32'd20", - "DATA_WIDTH": "32", + "DATA_WIDTH": "128", "ADDR_WIDTH": "32", - "M_PORTS": "2", + "M_PORTS": "1", "ID_WIDTH": "8", "USER_WIDTH": "3", - "PROTOCOL": "\"AXI4_LITE\"" + "PROTOCOL": "\"AXI4\"" }, "output": { "external_script_generator": [], - "external_source_source": [], - "external_example_example": [], - "external_testbench_synopsys": [], - "external_testbench_modelsim": [], - "external_testbench_ncsim": [], - "external_testbench_aldec": [], - "external_testbench_testbench": [] + "external_source_source": [ + "gAXIM_2to1_switch/gAXIM_2to1_switch.v", + "gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.vhd", + "gAXIM_2to1_switch/gAXIM_2to1_switch_define.vh", + "gAXIM_2to1_switch/gAXIM_2to1_switch_tmpl.v" + ], + "external_example_example": [ + "gAXIM_2to1_switch/Ti60F225_devkit/axi_interconnect_ed.xml", + "gAXIM_2to1_switch/Ti60F225_devkit/constraints.sdc", + "gAXIM_2to1_switch/Ti60F225_devkit/axi_interconnect_ed.peri.xml", + "gAXIM_2to1_switch/Ti60F225_devkit/efx_crc32.v", + "gAXIM_2to1_switch/Ti60F225_devkit/efx_custom_master_model.v", + "gAXIM_2to1_switch/Ti60F225_devkit/efx_custom_slave_model.v", + "gAXIM_2to1_switch/Ti60F225_devkit/top.v", + "gAXIM_2to1_switch/Ti60F225_devkit/efx_fifo_top.v", + "gAXIM_2to1_switch/Ti60F225_devkit/axi_interconnect.vh", + "gAXIM_2to1_switch/Ti60F225_devkit/gAXIM_2to1_switch.v", + "gAXIM_2to1_switch/Ti60F225_devkit/gAXIM_2to1_switch_define.vh" + ], + "external_testbench_synopsys": [ + "gAXIM_2to1_switch/Testbench/synopsys/gAXIM_2to1_switch.v" + ], + "external_testbench_modelsim": [ + "gAXIM_2to1_switch/Testbench/modelsim/gAXIM_2to1_switch.v" + ], + "external_testbench_ncsim": [ + "gAXIM_2to1_switch/Testbench/ncsim/gAXIM_2to1_switch.v" + ], + "external_testbench_aldec": [ + "gAXIM_2to1_switch/Testbench/aldec/gAXIM_2to1_switch.v" + ], + "external_testbench_testbench": [ + "gAXIM_2to1_switch/Testbench/modelsim.do", + "gAXIM_2to1_switch/Testbench/modelsim.sh", + "gAXIM_2to1_switch/Testbench/xrun.sh", + "gAXIM_2to1_switch/Testbench/axi_interconnect.vh", + "gAXIM_2to1_switch/Testbench/tb.v", + "gAXIM_2to1_switch/Testbench/top.v", + "gAXIM_2to1_switch/Testbench/efx_custom_slave_model.v", + "gAXIM_2to1_switch/Testbench/efx_crc32.v", + "gAXIM_2to1_switch/Testbench/efx_custom_master_model.v", + "gAXIM_2to1_switch/Testbench/efx_fifo_top.ncsim.v", + "gAXIM_2to1_switch/Testbench/efx_fifo_top.vcs.v", + "gAXIM_2to1_switch/Testbench/flist_ncsim", + "gAXIM_2to1_switch/Testbench/flist_modelsim", + "gAXIM_2to1_switch/Testbench/efx_fifo_top.modelsim.v", + "gAXIM_2to1_switch/Testbench/gAXIM_2to1_switch.v", + "gAXIM_2to1_switch/Testbench/gAXIM_2to1_switch_define.vh" + ] }, "ooc_synthesis": {}, - "sw_version": "2026.1.132", - "external_path_option": "RELATIVE_PATH" + "sw_version": "2025.1.95", + "generated_date": "2025-04-14T02:18:07.620266+00:00" } \ No newline at end of file diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch.v b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch.v index 94fe678..0040aec 100644 --- a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch.v +++ b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice @@ -43,7 +43,7 @@ // //////////////////////////////////////////////////////////////////////////////// -`define IP_UUID _b2d21181e3e64b0ab27cd3f4ca0a3529 +`define IP_UUID _2bba7642b6c647e08f6a49c8c42e531c `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module gAXIS_1to3_switch @@ -97,18 +97,18 @@ module gAXIS_1to3_switch output [11:0] m_axi_wstrb, input [2:0] m_axi_wready, output [0:0] s_axi_wready, - input [2:0] s_axi_awprot, + input [3:0] s_axi_awprot, input [3:0] s_axi_awcache, input [3:0] s_axi_awqos, input [2:0] s_axi_awuser, input [3:0] s_axi_arqos, input [3:0] s_axi_arcache, - output [8:0] m_axi_awprot, + output [11:0] m_axi_awprot, input [7:0] s_axi_arid, input [2:0] s_axi_arsize, input [7:0] s_axi_arlen, input [1:0] s_axi_arburst, - input [2:0] s_axi_arprot, + input [3:0] s_axi_arprot, input [7:0] s_axi_awid, input [1:0] s_axi_awburst, input [7:0] s_axi_awlen, @@ -120,7 +120,7 @@ module gAXIS_1to3_switch output [11:0] m_axi_awcache, output [11:0] m_axi_awqos, output [8:0] m_axi_awuser, - output [8:0] m_axi_arprot, + output [11:0] m_axi_arprot, output [5:0] m_axi_arburst, output [23:0] m_axi_arlen, output [8:0] m_axi_arsize, @@ -250,219 +250,219 @@ endmodule `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -BSiclTfEX07oDTPwvSfmqSh37gsGawnAkFDdQtfz2b2aPAbkkOIevgA5jmAEpk8Z -jmjFoTAnEUNBHxHADHQl29GtYYLQLcTt1dvsb1L8xXXbyd41mZnW9qxR1yEXo2Km -PmHE4/laDDFnEAn08I7oinDvTWN/plGfuIWWaEXC4z7ls9W1O5jNY2gj1ZC0oyT4 -iwzQ3cMmgvMMfqkgA6T8wMNFL1jvPdUxnuGh8qa0Q5zso+v2lpzszj4ytZLI8JZz -ZeX/ipjz/4hUHkihXJPjFD+MetXdYJTpzRO3ZbxTOlyD1Ln8yDvo0qNPrgbzN9qq -YropxHtLb22q5bZxY+vKMw== +k0MNGAL+siJuDYrFA58rRJscMTUE6hiuNEylu7uA+mdVk/vCPJpUprjqZIgJ75i6 +csRX146zVh4AUQABC09rbvto0kqPbqsZwZGmdOm1W8NmGZIXLCsG4MZs984TiToI +QMOSc+XFr9GVx1rFODfIQCsRVOla6WZCpHrBZzFjmFwY4t9fXFQCs5fSkNbGyG6v +8YDvdegFPMYp5Qu9ccfxeosyrpdCBompAmWscbYmzMrmyFiInvb8Y5dyqCuve1NW +jirl6fz1954ypdomnZDn+X9k8zTCJAxovyf9Qxk6Q+/Pf6e6yRqEYBxT7dtZhWRG +tEQdKP3bt5KBf+EuwdVLuQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 9552 ) `pragma protect data_block -+Vo70GbdNusghssxCh548dyMR2SkpjbMNAhuQNohK03MZPtslM2VcFXDSMs/E4I3 -A0tJBsXs6xJPmnI2dRa4m1jbkpAyspc0YB55NAgJLYdmR9j6FyHXqlpTZEcftxHN -U0jtFOoa18GEMGSCMB1hS59vfrr8WKoVGK2KMx8ZvAuWlQ0YHQjLkE8WQjVMM55l -aP/cENky21pfv/q9aoe1Ku3NLdbDqb8Mf/xcXYVJFJaMRBTujuRBZkvEBDhdz78t -J6irEqM5Esiu61ol7FyudRxQ9CyuB9hXVb40puIOcvjK6w4R5IFdJtzamLms4rEo -ttyRNF4nJVzvrjJErNRuCjJeWgYZGt7SXTDXpHvc/U8J03YrUq//wH9tuvfylFAb -bEasWeYHPxRKeJhZAyvxrsqltj0kDrJuaq1crK/jBem8w2mtGvkYNWTSw/Atty// -XOvqYjH8Lv1IBse+lGx5BUvPW2v9Mklu7s94aket2iIVqh6nVqt3dDC8ttJAA86u -o/wzbF0knyVABaBp8P1cYpjr346wDkAcB6FA1zTweqEsJbzezxvHQWZUuJvtpzrD -6WJJnp5e/9Ky/QdN7rMxioe+hn9rlAjyVazKEtypSZME9YaCXF5xv6Nm68s75QzP -WDEXiCA/MHoKMwovdWzYV8TnQmf1xnU/3KlKAEr3rnLvI5rIf5Sq1RHANvD2rQIw -huUjwsyE+Cy8BrBit89Y5eDgmlc/rlMgWwIfeJKwaHsg4kuDPFUbLV8GBgtD5+L8 -VqiVrOqvPX58wuiR6KJzyUPxXFMd7sxzpjrbe+qIIFvooqMqUeIhZFMzDT477uBF -nOWbpGGLV/uZTq0/nYl5raL9cu7/H5s0K1L0fFJPEkgTRN0sfTeWss5bjNjge0oy -mXpp2W5BhRDGPYszKDzFMl3dWwIKeDyolnsLhp1I80hDszRgEbdTO8qxoyDHRE/8 -7L7Wzj8cBZaQuyJTOdewJEjEOWESJx28Wr+24AqhjMPzM3Oy6QSfC0s0dGX+uLIN -DlepkOWfa1bGnK7EKh+QMw2Y+Hnxwdije+wgquoUNtLjCNB6rPh1qzJSccc7aHh/ -U1bAswc4wnpHqwqKP8bwg8A8C1xW5UW7/D/72SaGhNnfGOQ3BT9d5JFOdo08Rkrn -94ui9eHQlp1Pkpez3kz9Ow4KgTKz9qKk5KE2veb5Yf/jipoT1OXlHbPxelULfn8p -0+XRV85tGcJC0bdjGMMEJA2IXeOAZve0NgBojKtvDOD1jJCLekrfE+40nJvT7GdX -+0rpWydBkbVbKGiRgRUmoDJ9fPvYjrgXPfNZkzj2OuDy5UCeeVUnpKa9eYiCq698 -W1LH4LYjXXtjfzrRPMG6XW+sYkkLami4Ddmchxkkrtmom5f0aV1lzOow9hJVMuQT -ReMoUz6UamLLCoVItZghjS277HIPlv24hwR2WgaS8I4lXvWrUctSIkCPoWudlTE3 -WAy8RJrFGrov4uqTOe+uQISgnW6nxAXZ4wbsGZyJSPaHbFPFpN1ica6KQHRSCMdH -MOjwmMpHtaQ6hfsxP/rL4LiLP5TX9hzvEY++Sfy3TnkxpkBb8JDoIQkg419g1G0g -loYxnF79qgRIRiPYVyCg94Fvjb39r6GBy5sjPAUBnpFQnCUZfEtvEXPn2ff83wJ+ -KFAK5jPLXKq5TR4UxCWES/9MjrzpXX9Q5ZW3afh5gLY/i7Eld2aFuoJ7Yw0Wg0/P -0t+89+widhpOU+Vtj0VhZPPEHGAM7pIAI8BEAIyy+t01V3ELjbGQwLB4FmHh1K6h -n//2JdkPOTyqR+AeuiTAMJZlsyD/IvL/fW4ZaDpsj2x5TNvaGVZ91CWGGoZ1uoeY -d30JoZsygyJi583+EaN2ciS0uXd8ZVcmb3pWYodSq9Ukp0alVRHyD3YPc9Zezn6g -E8iMa6KdrD9NWQqlEkR/SAx6WBjrZlOHToxb3hVKhrmyJ8KnMSPiQZsXDD/NKBn7 -lE9PIz1KUeRVIBPZ8zGwYdQRRguiCXsZ8x6JOZ3RzLjoaJtfjRDbJMW1CMlAdqC5 -oI8e9RjsjQs3Vs4wcsKKqzK5IhpH9VLSbk8dHU6JBgz8uzI2wrMVdrKEFdlcZHTi -k+2fXR2JokVUojPqceraprwP1dwgkYk9pQeHVUYSej21OYs9ESdybFXjSy9ZF5Qm -7tx1szjw4keY+nacPY+jJ1aaHBrkQxtjPlbmlYdDjg3TrnVmlttsl+RAhb3xqXpn -S3b4KK2butk/P6n2hbecSOQrWEtBHqvE2Jj+i8cQot3mtG4C65/oAUYrorrhXkAO -gzg9dkY8SdwKqvAN5V8sIBa++RiHgK16w7SFH7I/1gzX16aWbJxuFp3iymf8jy/2 -r+6s0az8LvlADrHW8oTzKIW0w//OxdkgcUzBVcLIBUX5hLjJfdul3Ct73eLK0kVW -04zACyVCkGmVNKFXwtnNX6Sy+CSM1hzI1kLELajwpLwxvclh4WTU7yBinJ1U/KA1 -BJYZBuP2ZYbgoH7S6e+rW9ivv3M7ZuSqm+VxF0TddKvGU0xZFw5loRSfUJXLB95y -2L9Ea3OD8qKTu1LUHSrlFTFpclWrh136DvSLp9OiaW5YCfFpCghkYyhtw2khTaIE -d2ST7uuPrGMugw9D6sLTYyoOs45uemeJTDq0ht2BBgz2wSh+OOlcVl1U5HyFQV2a -Qtv6c+DdZzD56nq/I0odNZC/Jw1sEp12cCMg8p/5UuIPoPFJAsOLU52uQtSv/luS -0GgPp8FhrkqvsEGzKiwW6E/Y1MfNSfleNdhIzRoN+rCPrA9pqM0b2DwXWdSOWEKL -sr7/lOw7mTva3tt/SHlDd3+C2i3v0MvtPjolCueDxmnGNb8etCKZrCrRS+CqHTwf -EnwHiWYU6wJ5ujt1WqeNySs3RwMGcfhXAjv3SaymK7bXPn/ojZLfpzI8KDMP3yeP -TEBfC5ueGqnANRhsy6eigQJsmBXZe+XCHyEiKep/3JtLOXyqLRGW6LCBGBJ/V5KN -ND2eEG3XO7ZKZCuwIgUq00C3gd+o97Ioc8GLl5AVlC6heQotz01MU/Ev2dACmL1z -4ZFHvZc/13573p/fJIs52S823mHcalMIS8AmnKuaT3wY8nzr5QV38ynB8ONVMmoH -lGBntZG9K/dtmUVDqKnbxf+qGYnETQq48zKWirdGYCL9NnRfEhC6CtOCAlShAIrY -xKGHokJjv2fn+bdyx30Ii6k3fInOEMtoE1427qoED/l8FGnTnoDxCEwebwOO8doz -lIOmeZ9f2yyRUKCigCpdnyKzBWlOfQHbegVyU6rtXYwpcN0tyfexaZfcWqFCvYev -XUzKg4zAYDOKitkSGeBgpIM7gQmUTsmhCukfzs/xqOtcgd94yBaCFXySHCmJQtfm -ycWz96srl2u3lvhrt8fdD8kPmMFEIVQg9iyKVR4tT5vUM3YVUzlg6v4xfpoW2r7S -U5egOtd5e4QzIzGFzZryyT9aseeaOoeWIFZPs+mR0aFElhJqTjkUPyHsf1C1EMNU -tMrHTjnb/UVTic6o/ySx9mWONYW1iy/5kwDf082TPnG+uzYz3HYWzMKFbcIDKjst -3F3yfn+/mInbZm1Pun//E5U6BOShAnlAO1LdyLDJq4Hdkelk7xB0F1uxv0NcexwR -jdLaF27+GrJrXUjJ8SzYBCcj3uRwYpOMjN0DmaInbTfMAZyvAycqiCAMxh6oBMaw -6OV1Tmy1OX3JMsw0EjHJKcNAyB3ZxIM6vLrYQaMQKsf5sozYk6Jwx5WoLCgbxp9j -M/lMAgMHyg27+wwU4RAD7bsUiu8W+QazsIjjl3iv/dmaQzUAcVK+zd7RiYnTzygd -AFAG6fVArk/MZIK3yPmGsLjIz66oC8Kax5v87AbdZ9HCCHDO0n97WOx00pRzCkuM -gwmJEPxDp9hFV2tby6qWp3DFO6Vd44o4pBPSJjITTgly9xg2pXbH5fM1nnSAi4zl -wjnAF4S+n+06n0F3w6obf+oGbMKZrYKvDRF8G62+Y6BYQ11QWnM0WGIh3zIdSlC+ -ZeQP0jpNWgdhg0Yw1mRf2TQZJjFRCci8nmZlnpP4EX6cpFCi0R6knemwTYS7a+Bp -CNDP+tFLVYQD7Xw7Ech/HSFqeba82aJcXo/aHU0b6zLC/g11gz1q1EezecWP5bsf -jPnGYHuVmoZPvPQiLtrsEKFDjfjoFQPBupg/0ogIDZpyLFbl8seEIZb+fTkAUL4H -8pHG01eZPk/KZf/noleooyAGETHHIVVprxhXsl6x/FEPvzmdY7ZbWzXUPAhQoq12 -IuiWUp37nH2P/KwzZmU0eOCL4n97VEuCXgOudgwJHn6km6lADBUOUHpXdZTwIi7u -YvApYiD8E73ZzgKF0FQxy0s1WsdLbx8l0t1PwN6vxSji1P1XyzOC9vZJv4XdG8kQ -Y0YUAsGEViLTYsJKYlrBGidLjnjjIm+MyTocfS3Bhp/krS0WNF6W9xjWy4cGPlbV -OpxPzFLrSf5Igbbtvdxo021XzJsjpVq70M8qMhNMrpOye4yBh4lksXeGmRSFydtX -5EfbS+mxNOFc4qbogzHf9Ut+wL/AsemGEwd9HIuStnJzrnr4DDzxgYJpTQpPg6Ib -OrdUqXtUc9BWUZYwgI2N5FN2WWZ8bDiIE4/y9nkPXPZVwF0UaGIocgoaCUj6MUgk -YIcYJOR/IcN+xjzNcZHGzt4ZqomY3paFg7oP+qeYPSC6oTw2rOexEy0ymG1LWLaZ -f5eEFo+AvyEIZkEKr51Hf8v5zBe82JZ6ckI2LpSJVsZTT7FYdKF3dxCcNZ/JlDdu -DOj7dhpN/dcfZGpVSjZ5KAG1U1BtLbjUMO3Q/n/OAXBDG6TV3Dc8x1y9rjLsORs/ -mehkvy+/2+/9bdr0VVWB3Yh4QLDUQWQaqu1IXTHva0oAGGgoPdCqhlfzazCtiCkv -93ibBe2MZ9LufhOjWl1wfTxVm/bliNnwr8QSN+NldS8FHUj9zvmywPq5JlN0LUvf -ImnEuaaqd0OlShxhFlo/OaDBK97erhpGopEPoxBD92oMOMnmn9O2JLxajczFBh7R -TQ3fr9Ylq2l8UI5/BhE+RIgcQBiTWiqmHIae0mzwadUzTtp/RA1qTkgt13o6/p0Q -mN8BOg1Dwxuw+Sw2uoRvM2kfwRz4bogy77sJYPEVZIFD3HK0B+PmUuk+d6vN0E2l -SpfmZWhn631tyDIjygCW3mWo08HDnq0amjoB8ZCEMa/PLcSvMdv0eWwfCfALZ0i5 -vz/dEM4+Qz1AJUEG8jyLIdMsdScHw0+UQlTRsqqSYJ8uW0JhDfon9mvkbcLC9xmm -BHMGa6B/rTfWc3F0oyHelbF6mYs66cgQ22LC7S55GB/lvORqnow9CnW22Q2ZPrZF -/164Xp+MRKgsl1K8B6q5pWJNgktqP+0DCB7WaU6yCtub7RSaJVtlxFhdfxWKSRUS -9BAabPmbLBsOjl4hEAIa+sB3rVF0BxQs5yqUjC1F30dJNxWLkl6Og1lAWJJnz8ep -Z9BrBo+kLDSlSP5zNRlH8Gl40GxUnGdKHaLCvNnJtiR3e6XKVWd03XPrkkuTG+x6 -zY0IZ0ErZekSklJ0vVq+1pPfX71rQMXx3ag4F8I6rJe1qe8d9awtemMVp6Dg3ZZ/ -MiTKUJHX99lX50rzkVXwD52LI84DYE6AvPZsWaQ0t8E3Mw6Zefe0pZIV9HELV4Ov -c+JJco1Eb3N+kivR4VYxIz+rL0c5pnAkR6Y+WyplOHa88or7VvchPiVXfngOY3m3 -ZeSBSjmXFrMN0B9ZlqCns+niLZwk35gg4syhcj7fgLxvuUIuBxz1jSHg+qMwmpoz -lLuAvy/0TqKPVe/FBgCjLul3tH7HCyYtGxH7aVnRWyVt12b0F1jZN5iWGH+42Rhx -FMnERlPJSfd7jvOiWLIVgMlEUTClEwLUlg079nmf0udi8yeJf8tXjMCu42NjqokS -5PK4iwg5TLGZlilof0xgr+TCpNil+ZByCilvCGoNbnCHgQq14gWDs3XKFm/0M63N -lxdc23CRojelTN1Q+fXOCrw0O9jOdoysyShD9CdgSASJwa7My+iNlYY+Vgd8l8oJ -aS0SIs1V0Ys1Tb3eqwuP2/EA/w3cjORErsgvji1h0XCZO3/59FU0tcctWe6HXNEW -iUWGyax08mQ7CB731qsBdoNvFyWaHbILRgg/zWjqE838PAAJn3dLFeanySA7HSX6 -TQt5VUOwzrF4n/BUMfOsR6fDyxv4idXS3joV4ZkjLV5PI8W+MSEC8xf8mkJs+0RP -lnsxRYWwV7vSg3ULXWwsbNOMftyZL42hJCNXIRCXolkc553GrP2J0mmmvXUIwJSi -kMDvVJm0LCDDaGNsCMYTSIOjxfE67UIP/8kw1Wi8sLR15wlhAtv0wIeuiy0eLcHB -VKv4W2i9LpzGjbNFUmgtZACznW1ysBHDyjO/ar2uAWHtETubr14ljJzO6ru5tv43 -jCkwoKYcB2B7tT0UGhNl6FyU23q/VBOtDUikFU0jrAiKkZwcpPOIVs41hp6QsvWJ -WwchxAElZOCS5Wy5VMa0EObJlDiTo7AFsqhjDmYL3+ByRCDC5wzwqdNjCvF5wWAa -3zBDKN3DxTg10p7bl6GWAEvmdz/brcOaYsxEAQ2ZHkEDdoU+Iy5P3iSyJZzOgkZB -YKcg213nl9M37ryECiZ9+7U2+W7Ry45APT4EOs9FAeH+pkL3B8rrJTxgcULWL7+3 -QZIFNFcyRz0MyVx2YnRbbMYo4tYc0GlG1TMQLA3JWNku73Smxx2to/UMOmbtioF2 -6bL8VDw8s8yoCbgHM8zTq1RkJRxgKB5eWT6eIKyVaMQbPgek3D9ayC/o5lnOGnkE -LnF3+WMahzv5XUrLJlhlPgyXTGWC1iBG0YUH1h7BFvHiAl2Ems79KQTgvAk0IH3p -XpUxlNdJmfYtLOhRVL6+S+u8kdDASYou30zGrxO6wBan6zPJ/62JgmxSQg9YKJwo -ktejF3Sxp4D0rkRELmKF+/AFMJp3O/8shaHYqaF4lT+FYXMdiPvnmyFhIOAEebyV -rZSK5pAHIMYZH1NVUUUKt3Bf+xErNuKRCocldA7sXk+zz+qKR3R/bcFOpAPU5oEB -EWlJ9UEMzotJkG4D2O/MfGDPlwc/dE+gBqx0oQUeh4vZEyylKYouBWlkuRMuLHRz -+6zheheADshTuKDqr5taHzBSJCY+x0chzQnWBX31YBu6BsfQGGkL+hpaxjM8tx5t -45wWL1NTGdvhEIVnaDykPyhxYfkkiDelXglbUbPcAGzyx2C9a9K/vdpktRSu8qX0 -f2rOOt2/7AwIVxZ6ctdihcHfegllVqQH71L9aw1ijjsfLjw/KofeRuxiKjIQiHmN -tvB/tXUGK616bu6SC8wssrWGslSwwPZuS2hoB1HSuZfaGZqGLg+qFKAmEcfL9pCQ -qpBVpZPDQ2Xvuao0eq0hsfC0TgsBLCaOWFeRKYJe+wtA93pKWlOzxReJYbw49wvC -DYAeTHicoEHJBablvUN8rDI/5825ECAcjvXvtFf5AUZC9LaX2cHO2oRdua9xln9G -fn0mJDyG67wIqJoXBt/9b8HTVZxar1kcW1B6lR+HZhO7MqnvdYf66btPiu0i3M5l -biPiYfXsuxq1l5vhOytIc6CwnKr3oRGRSV7l9WimwhmaHnMMJ7VKGyjxOSZ67J8Y -/Gxe9qQJjjk4mxVMyodGqcJLEolXbTuN5jgBHeWusLCf0Xf4zel9o/VAu8Ti3XMi -ZVlps9of4LRUm/AmrC/MUS6OEHeAb0WstZ5ubhf9RCm+iCrib+Nqvc+T3nXVV94w -fYQ6PCJQQqvo7ze3DWywDgvsrZ6j3+J+UqLGMCBxAQIR/9lhNddalxCYtLxWHCdw -+bNSaMA/P9eFk0nw/0p3KZlHB3H8HYN8I0V9f5u6U+gB32DkrmrqrqdFYM7WG+bZ -jivRc0FwimJD0QyTvKE9V1oAF8Z4Y8ZrzEFIWeutjoIPfW8av6fI38Ng2Or5/dqR -9ppkSyjUK+ULXmJCL3CZ6mXB34Nj7fmeOnj+z/+LSZfQG+PsJ1DTgP0CvsXqpgzb -nGcgHLuHr+a+K8uS8figQCQnTaM7dtThawrqMQTh8sW6ywezpy0OmfMXUvlHHBpm -CtgE6V918rOSKUDSugYWLFsQTaclqSA54ZGbrUXc4lXbd/NsJwuVBbmgKlQvLmmV -kjWwN/tb8EfdLd/2prWY6WWk8sCHvDXBlL/79dG9wlKNF/ExxwTcI3Xf4kr9pP+G -mCn3VAkP/51X5GkjfM0d6xBsO3mr4ACzWCXnZBdtlg+drPbIoL7CLt5eV6sCoiXv -MscOhp9A7B1TuBXQfzOHGzhOhwJ3jXa1+VvA8s8qrluer7pM8OnO/KTz+N7rq7Ip -64Zc8pOrqhkxoETDRYL8etzZB8Z2e/dKgm/6xPGpcSAE1xgAxdeOqRRERKvvi8VK -Taw7ApiHF6NmkPetMBJISeSJuKLXknb+T++wdyY9kFH0E3maOgl3J1StwhY0QMsT -CSd52lx0vw3kQIv3a0Fv2/Y5AMij3SHoL01fTmq7o+QQj6qSALueEAa5eEBafEN6 -fAO2Sa2co5hhDxdQ7TZRHp48ShlrCjUiolIuV+LLmvBvAcWaX0AFICHuRL2DC5T0 -QWmhTaSmsGZDfuWQcA2oi1TAGRuliPmCTTU5ityK0E57vHbSUjVpyEb5vNc070U4 -O3i5JIrV71TlRRyPKFnYmUSRGOmeVgCrr4Sco+YUZpuO7LGQqdoPFYNNSnWWt9ib -shG2Mfr73A6/2+kkoiaPzaQGmjJcbO38OcbUld8h4RBafQVX0NdcRfnv23HzweNR -1Hu4VNZaWmRmJcmXJ2EifrNrKzedxj0DSaEBFh7MsKpZ3P1XccN+ovFCURIAE7rr -izssfLqPmshiDRItEaSrvopmUUgbk/vvzCYrtWWtSuTY0bYXObLdOXgYwzef4H7n -eYjyn9DV/HFiNvI2U+KtGPmpuu9bZHZS+oBwx32OgvYxuHpahGKAxa9nRKNU/mMo -SWra9iEUg4KZtp+qADETXa+NJWdhYIbfkLp6MxZwTOoJcz2a2VLP0TBx/fHcmwTX -xooJkr5lnCexpW7atLewR278oRIwkBU1iJ1NAvqLt4zkWBwlOQIls6RKEWiEaHkR -HFXYhCeV4YZLe58kiw8Aq4jtyQttOSCFr+8ZMxxPVp2UjEqFGX8T4dYg++Onil2k -l8ChT1QTXpiYzX2cIq6rq6eBk3PLO6TpF9+rvi71t8uF1DBTveO366HlRWvSb+Io -T1GIP7sMZ2+usPZxOL8iEIHj2wVKVakeGMm7e5PtPAhzWmwPbDEIrVuIRlW6RiqN -rHTNMq/FcVFZ7qFfIZAr/6H4KpBv+eIs+Y0yJFl0YWQSetJz7m3ICkuAW+/Ar3wd -UGiCebCRMcb5aAVoKvNF6yMzpAogwNOVNsVFnv3v4A5p40DXhGAggYogjaVPZ1dH -OVhrgSL2+ATG+/VnrIgLoLzrAp7LnT0h0ocwPE9yikP7Teo1jaSw6KF3cZDqF8Ze -yACvXWJRKcldJQ+V0bz/6CaoX2LKRRKSmaGUeuSF7a8np0OYKJTCZB+40k3yyCU+ -6FCWpd7z13goXllNctEv+ZhqQyJGuydkJZF3Bw7vF48hF6lMqyZnAuoMAVOS//uy -w2+UKnbg0djE2OOp5CnDIRAcf/5FEAtfudaD8ZDEfW2pfPBaDlhiez5Ah/Ap4Fjk -NP/evxUyYj5z4fojXjJqfmSC7jYsdxBOxwpXvNhAWLGcUQjdL1Gxahwx2TXtEpLN -KDlZHQZ0EqBW8sAxpHwN4soHW8Y3XKO9L3dQylrRynmjTMOTtzprtaOnyU6Ly7QJ -K8k+trMi/iwourgwTvzrX5CA/e7SOKts8BTgj8x81hzr4HXEobCoOiKaWwbUeYAP -TR935XsMMbmd98q9XVxNx8Nbaq9BgH4RXvFxwklacqH4B61bc/0jcTnZuDIGWmOu -Rn4QJJoL1d6b2Iokuh7aHknbgZSbK34WGKbxh8KK1yNR6SwgwsXpnzP5rRCjyESg -S6r68j6eemrLBSkMyydEWExNiGkfVbasujeDjRZOACJYcTCNLlrueQuCjSHB7ubQ -WqZwjXhECDP0XvOO3uI81xJ+FADfirnQphqnmXTqgptiPzdgRFRN13LD2go7iZax -8jAr9ESY/k0v/ot/YHYFvw+BtUyRSIX8EL+xQZsn2m/gz52KeSn/s21CCQH9yYrm -cAmTGljyzvF5g7ph2AU4p+3/b1o+gvT1fGmcYOY8pvLYT19Kyd3iY9q1l93wJwz5 -GUONlKLFc3Ql6514yvsDQdAyAgPk2FtmlsZUcXtqu4VRB3LCoXrH3aMngizxDVyf -kYsjbYG4EJfnKgFpaelpQLXuyeH2cH0KwRqq2F1bm+7rYeb98mKNUe8aTciJVleB -fFuIXZgbnsbCSv8EdbU3lSOc6z52sk3ICVlw1U4Ygg4HrGwl3ahOlFpdgnC4+Btp -Ya/KDZyzBkqbX3DpqaNDFR002x7WuCOPbTaQEcIwRTp48iw70/xZvcNnrp4l6gJ7 -Ldc/knVGYXiMN99BXv+xr5q9ZBqG4CQeqm9NUeZ+rrFamHxIlB4q8nPMW9Ka24La -arc5GwEJI50lLBmAH3HOlEErrY5/iydE0556mXJ3zNOvsaFCODPPy37z9ZW6hOTI -b7dKQfzj1E7jlk0RfhIR/Zys0I5IjB/69JXFRyEpsRDN2QD6/CkyyBkMujO7yc0c -biyI4Pt4z28c/bmE6OlgyOgK3doBqb9wp1Ehhq38mW0cbDEh4ovVACZ1FkAv/yoN -VIJ98DWE/dLhezHkASDEjlU5GuXC+4XtjXCwUUpaAK0EXy1jTp360r/znzAljTu0 -r5Y6zFHxRVlvHAKUnhY5ooux7cvXyx6W34elfM0AJKy3peVt5TQ82FY2SP1xxwXB -dne6Qklqv9zCU3m6LS68skAEZIGbgZYdeDKsVifbES9Rsap940YSy7dxqVw0c4qR -tOTxej6Pe5WG/myr+5pigcpnb7zm+3IhH4G+3TrKz79eAzoNrrO2U9EIyXLfUql6 -hh+d/3GNYd3AWp9ZRpnRdGJGzchezwHTN7fkysreZ91KdVzXeoxpz30iB1ZNbh+0 -+uEp086Yj8Ylr8Yos1lr/UoD71rntfqk9zKcdP1sWwY5fN8dE8GPC84K+cN2vCS0 -0fKWEv9NhDOdVMB+CUOsKCMHw/y2gj/IrkluWCBY8nMoN2uMD4TTkVDvWufhBF/1 -AZjQJyfb4OlIn96zOI97aXFkfOwB4hacH6RUIB4+6RUcZsMkwstnj/4HwXqLkCFq -C6ia6iiZV18tm/Od3kDu9bPC67s08cUXka4sWP+3gS8hqlMsbVKkGgaqIiF0iBtd -PPiaqNTlxFvz7TbXGU+GqUVgtn4glXp8Flk2fm/qqyOu1wsG0y3HaX0avM0K5qYL -fkG8gSeGHQl0TeYAgAnx0ffeR2jYKji7l9k8XPq3rjaTF4RDDLejQVDobs2ekT1B -lcMN15P1JLPepLnSAV51s6MqHiiLcuV7dWj0srKU4i99O0IXvQqGGZhcVzCjzvoN -Yp56e2dYZI19LXeNyNia5l+0kybXdzAGbkUeGXf8EYtnPp8lTUXqkRcsJU914Yzh -rj5gjsSC5de+E/epqBVxVsaFieAZVe9mYwwCqFbTbgR3n62OR7CfFTGJ19MU/Zor -yblrWeDJS3wb9B54mIIX3ZDLMySmAaNEGw5XaYwXBZk4zJ9LmZZfIYXpmkBw4/IK -Oj3TX61UlV3Mtaa5St0OPPUlDsJ3WZ3txD0WsiPnL1kXr4N1bXFUZ18NWUX6+6Mx -p4H9phOxs3qJRpJDY8gqf+wjDK9uMs3NATNtJdOfeC3Gt1+FhyH9o2IUJpEs57z1 -ypjiz0EYl6ooJdV6MS/XDrcnyFXRJMglD0hrUl1fPv9TiFOxNMHpTBhfhWz0nBmR -thX4XZpDQ4FQVfIBroQGJCK3GhiVzvJN95ATiPQtFgjyG/x3nSLf/bFXtUyo1L2z -RwF9eeZ6fo+kcN0UJp4FC3fwSvkZKocysKX/WzYdz7jVPo+03TpnbkyFMqorl0xD -bXhDl6XYUHZQCYHVhUXKcEZHOI2zSxWqNUvlSHXEc91pIEoXCvTi7QiaYSZHIm30 -YDkGla/3BGsmsllvK17YhlIl+B3INu8+TG18NyhGxe5t6c221BHB9CVP49nZWvq5 -xSXZLb2EaG+OsoEU1jshlGGdUFaaeZjuBF4Wv4cG/Kd21TMqtDl7tuOxWslTY3BA -h0K+XtKRSjnfR01WLA+/XQe4S25S6tcbR5AJSYT3xcLFDUw4ghn4/qQklNNEr57f -mD470LuP9+f5Ud307Xx4F6AM71/FGZrha/rJxjluETxdHCy5bAx/oXWQo31VURq7 -3q6UCh0ymGPD837xKYyUYceQRZff4/xlTF/OEQdZPNtbBVE8IsHMp2mfFfSDxq+C -axB5ar3/7/HrmzJElpSIOoSceJQXYo0L9scIrPSF8jNRRB2TxDReT/yjiQsCkww1 -fGF62e7DC0HnyHPBQrRlj9JQC34pW2K2ZTTgQYZhrhwQwTzaoIHBb45KPMMUuBHp -v82gEe/pW9K++sUDQK/W7wgO1NeiS5NHJmtaqv/uH5AOxE1XMLrXPsYiw7p2QJOq -1bmbF7c4TMfs9iT1KNHz2p1mqo4wOo0tHgDdPmL8PXLMm7POrz0rKoBS6lDTid35 +CosGYIkH0xBRxN95EJWx839RlT4VAi4LCJZ1mt3NitRA5g2pDgJLsvVh2D1y5BVA +pdFnLxJlKeO8VGxcbjdy9+FeBPs3Bo0hcGMo8L+LaJ0bVkv+6b77n30HN7W4KS8h +FD1Ep9sROiwLtXRFHJO89i05/tAaQLM8i1caOwWOyxnOkkN9uNWnXu8Q0YVHwDSo +6edwH6pDm7sUFDB7MkilS2mpOjdUBdlO7TGkRl9TuEENWQoMfIDEVtwj5ArywPyR +ABP441amQzUHEwhfDKcPN2iMoBL+T+S1wuWnJHqvzHEb6nVPARgwM2LxvxR9dJld +dNlxyS3zC6MHchUMEAThn6/mNnJEIrcrJfsvf1vvLfpUlQ5d+C8Gj2KcQl4cX+1i +y70cPd03g1gHtWhRfChJ+8u0hcEyphEmEnx9SLi2I4xYi+fTWMgPPM9PNN1YXNHq +otMqtc2ceQLlyCdlKJplKqKXkqQdhPcZ9wt1WckUoSV+ZeiA4t7bGUWN3kexbKDy +o/js6xWIxX0ryxN/pbXUzhaj+FMP84LHEs7BoUU3zxlGsUspgAysZAO14S2sGjNI +BGpe6bm0ONuesSHUY7+4NUAWlwtPlG6ulaAEIClApiB8gBOvDsTAQbDKVkunI6rz +9cfhmqP/A1djz1i+Lw6iytrG/0VEU8wOePUdJupVohofGQa/4y+YwGciqdf8bscN +y2H+LIZnDVF8FwQqxUMjnTJGvd0s9fHCJfhYvXMWorLOGLe2wW1l63PmZQoaNVXY +K/JSkYpZKe+1jeyKioBw1ecvAOFXmnHjUXoGGiAbTSgVf2c5qN+UOXty8BIpzXsg +rEi4GkhlmS9JOl4OQehZT8m8XUc6Gk4tOWOFI/Y04qqVeyyHXHoRK2YypFTeGvWZ +QWRGXrwLYJEsSZ4pSXjO2Y1sNzJSAy/LUfHn9ih9RN4pcPd2t5yJBs9i2YKdajDd +mMZ9cfbemdV3IUPvWQsy/p+aey0Cf+JLwgchg/lPfV4xgZIc4ZIqkBiIrOIkYCRT +43pSktGOK0XWBA1vaFIbC3cpTHkDm7LQWLF6LkVws9H+W9Ui7ZphPGJYQ2FZuPFI +x4JdlFgmbh8CKDphsgQ0S9wIPIiTxRywf2P0QWvDuaAPSf1ONlDVSLZTsMpwMhgp +JNkTIkZg82zj0VVndkAznUheBGdHU1LM7Ao8djstDoYkJyBKszFcpg5i+vych5sn +Y+FPaWBO8UY1afO/VO2H3aMYvPs8Ey4fLon6Ot+jqqE2QhWfWOyr6/Y2KpZ29Tn4 +yJFhBLEGx890JscKBgz/Pty/z4uI88ARA6quPcoynMcdIZ7KuZ3//NoLU+MW5Ji7 +VFYtef6sYztFjyVBej5iPcwEB/IFI1d4rEZ5trsKDNcBYtLv8P3uUTrAbkBUrkzI +yAmsEY5jaLeFXJdeT5qZFjyy9LTRuyOEdhKoHr8lsbIvJEP8fKGOyR71wt1P8vDh +baKkrSka1ND+doDAWaIksjVzpZtoOUJMCdyqduEGaSXMoEbOLzjwCwatyUAZnAfl +WwdgTbr+jMNDwm6ZJ1uUwd/AC+w2aunGMR1WHoMDyIK5icyVab5vg4cygOV/vkym +3aFkctiYHlucNCcL8phNpyLUKgGpY7wU7kLNA24HbnKJlqAwUOFuX/TToc7PQlcV +SY9tr2TMOFipbNlOu3jeaB0Vo6yseFq4QJYhA43C14lER0DuVgRveDhb4d+kcEl6 +bNUBGSkHWyh1txe8rFLTipxEBA9OvA4qfpJLdjdZ+y3lkqRQtHFTpuHTBJs691oX +Hut8P6qCvMQWHtqbc3rdk4Y3duWralCzKqrsCmziyZIJpOAC2sAyw8ISN+HX6FV4 +qfLqVX0UeSni7AgSkhblarOhtAnfYULYt5K77BFGy/3v2o9CPNOno8LSdA2CQ6Y4 +8oZYxxqrifzsGvCdSOAPCAmUtCHm/spRjVS3wwZr/JqiazytF1OksyJ3qY9H3Yy9 +cAOg1szShsdHmj4PNrZqE6mwktxWt51Th8QjPkjALxf1zO4f7PHlTl1NxGEZk3je +MQEv/NtiqEzeRmzB3GLiIAPNaq0pD4t6Bn/pUCW3WXfO9SsCw/fk57GZ/MCqIxfz +Wzv24NCpkA9CpffUL4DZ5pcSNGwbDVK8NhmPq3jq9aT9QiYkkv+Mc1G4gDL+NF9D +hbyD1Pr9TxJIKk+kFIFIdVJBMMIcVBOb/wo37185XNJQbJ8TB2axmGnkXjNOge9+ +arrvoVM2SERpIbo8+cbHNMy1fY8ywtiIA/N9+BybUe4qO24RtzrsJHoWJ1Rn1Rg9 +jsFzaIVI27UiFjAhQfsnzYfTKEnHZu4NnbUDGzZrPgFbQQCkbBiENyXRVX360gfC +hsfv5p6XFZfrWjLL55g2EmdV93K2ja+i6klL6yfb9+nyTLI35qz0QFKMIALNis8w +JKwyRM3ThTqe+K8+F25fyT0VqHp7Rk31IMEP2PIM8pkwn7q6CAdeRoPO+rln6Jaq +onLkSko+m25UxbrtdT/oiF5b1eR4oQfUAVJOnMFjMkuBrc/KmkiTotNCeFs47ViV +02JeMX2f8G8daHyES8qCv5R4a6DKb0lrNHoojbtef/gv1HFDUhxGn5xkqlDrApwi +AI2pXanHk96xQ3jzFuEI4oQ6KtHySDBFRby5u5Xrw85f1oSAeDDHvy7/Cw5emFoc +HDu3rpfebgG3sKM3ZrUH06lrR2Im3LbGXusrWI/isuwyYuYXyWMMpsJo8t9n8KpH +DYTSNXwIpbZ/rlm4yLEdyYPxNU1X93LpIY9+XJHBugTXrRpQWNr1NjX7xUD5NdhZ +no7eo1okylN6u2/9VzwwDxzpz6E2/ju3J32x4CYYhQisuP9BfA+GPp3vwp/f8JkF +wqKCtI6nkxCXWkDrPTmplKzKJxCSAN9iwYi0Yn15/oiBTA/l9NWgRb59/zARioB0 +xX3tdsXLlBZFuH57ePS6RcmU/DHKUkyChHupCu+IunhHfEC/EmHtGsjSHKrG5iyA +27M3fpB4Xd/LeuTYo+NaEYTlANaMYUeteH/Eb1PDwDgGF2bGhnriq4JmMd+EFZxL +4FiJpggUJYd/M135cC+ohSWsHT3WK+IIerSKyD72G/xVGexHeNPt0HXhdCrmgyH/ +00tTjTHdZQKdF4CvdjFeCT8+6Q9IQlP3CAaow27SaK9BibNtM6xbsHKlBW17PUbV +JDUZOiRAtSKcePPkEXirrqEFJWBUmBC1pJgAnn0IQE3ZmUSvJeiaxvyAHfP/IvBr +d7dr3MKhikrNMdgNklD4kU01G51cn7ehZQcSt7o1wjJ2bITWQAI4CN17Pa5BSi6x +M130n/O2tghSh4RMRXuM1uOqcMJlSdDaSSrNaXgMAO4ePH9mdquCwRLTFBdGhkej +mYrY6frqP29aFXcwtEaDxnzDmUML+UePGNeksngsXKyLW4NwfSYkwuct2paDGZ2n +l1mutyakT1UgcTYVtTym6xQjxp+fEQt9RWSaYw9my/H2vf7DJ3rgRmlnZ8VGHvsg +Q7vBtFvGEyU5LfD7czZT6ERpJCapbmEhOMibFy74sgIfFf2KYdcAr+ILpb26imPN +kASgszlpTJBiWkHVzM1hcGnYx07ltmPoEpfGnyP6w7idperxlYoUHzJa+QaXCQ4m +IoQUrcLW3olf2qD2dAHy+J7ew5IrXyg/FcEqkeoIvBM43fGKsr9BUlh2s5zm0qZN +PYg0Al3SMA2nVYA2BRPgVjfFL3iyjOFKjboMwEbHGEUMvVWE3YVgj5waDPrjRLIm +kejtSYej3CYAkQIw8DN9lhDSAg44hrdtYkk7EN9O+ASmQi/c9M9ROYv+Qh8S5Jj5 +aU1LWZY40pLJsnu1ihdw5QSHCIC/wsBAe3I+8+rEe8JqJbQ/OVOl2yqdOzJlUF9c +UnTwJIjcPj1/YZ+ouq+J52boVdYPIY03uzXfvh8/h0HS0sSBW+N9N4/qyhjwu498 +if9WWyX5QNldlEzADEOQJm9yvhTGUbOKsQHvLkq0L7ODUqfqh/4I4n3SVQBJLBgc +fJoHsaTB3UL233Itwlddl0RQZeZ44+2UurY6PPi9cs9PQHfBMGM4EEDIGczkfwrb +VXsQDl34cKlIl+ualZ8HO1RTQgonZpI3JpC67Li9mS00jWiYo+61yZ+tDOsKJpWH +rk5RAiDEgeEifE482FrBHyMs3Zi0M1ADm+CzchwS48zNJBS+Np1D9quxmCB1htEG +LpYnY4f5CukA3sRcAdKOBZiPqiZ8epunSri+QBGMzTlsy1jG+BVDiHw7qCnIjETO +uoYWsfqh1J0/Q3Ch1H17d8H75YtBWzWWaK87dTjLrHhu3IbA537Ey8THNaoKfpo6 +Q0aj4nLip/23JZzowTwMFjkdjIxaaUWG3BBwLysR00Ojci4rWhcJ3Kkl7X8mmTN0 +Q124nxpjDKCmoQG926wQYC31yHEVgDNyVILxcyV0zVb9FUIxojPKXlkmqzM6xfnz +fw2rDLAQt0aEZQ04G2P8ogq0Jm/S1PsqY4LoC9LSugckElDBF9jE2pTJbu8zejhN +H4f+b/A8yrlKWsTesVaXNrmTKFvEQErc8vi4UEaHdLvOJtJsA4Z/8zVimjWe+Z7E +RmOV1S53KXGzMg3Bs5Gom3YC9v+Vusuq4BX1Bhq1JkcGbq6TbDMG8rvG29UCt+2P +EplRUHVp9FSQ5aWP6T18iIJ4MSvhHH95hETsFAnkjnavR8q+REgqC+A2U+Gd3ibS +5fvK/B3n83x2SfyU4VcSf42zxVoleOLSYrTlIVVDY7UHQUyGCZhBZ08zXuncYYjF +40x7WtGXgFXhK5uHLyYRKCc67bdq+D7gCUnNhskDr0azpw2O7JrrdNoN0gZ0bSss +wOx+7CzZBb98+Kv8pOBrbU2pMKNFQwd70PBQWmRspVX1ib93hzuOh3uoyFCqHpDo +dkNAQR8AnBTO6wfLI1QLzYkV4XcuIl4YnivmZeWBGg3wCsE6wPJKRJtScC/i9Kq4 +PRalvjf4zDFcUpbLmF6AZ1UtSuExw4OYncihmxUpRcOGYovNufLqtmoC3q1TdExb +w0HGPIyJ/t5KEw1dXq7rd4KgLTIbgjUIDjWkXI5hfshqKBMcs+d51vLXaALHDwNz +VFU/iskzvUp+uE942PEpAH/hFlbSuZeDnKVDv3hfWSE6DnqrN2BvbxOOTSYShGEq +zjn8Xt1ZWmhPYYoBiaOAG/AFlV+tOsRI+g3KQjL+l3+iJ8yh4YwNm/A1t6BxNjgu +Rzr2KZsjDPa0qGRTrMEV4Nb5y2TxS77nDuyf+Efc424O/unlG7XwzpRJxvhYuArS +5yEuhUn+4OFq3XUJjgPeVEJH9fUxHlpKscpjAOMtsxu9lR3u3Krv37aZm9OwyEDG +3tU/l/nrzG4VEXdXExlGFP91lhygme0XJiPvLJAe8DAmTasKYMe5Rg6LNXyZ/4CL +xgjY9uYdSrEiv1J5aMGmdFDuYxfJZb1UxP0zjEGos2eCRUfR2KNwl09dCxRHOvMb +Z4n7HR1Lsqw5V2S9SxmZo/A1ju/rZML1EO1zDLkqe1on8dsPwyu774HfStaMhVGj +OfWr0AVe4DGr0jfajYwc6WE+RUAS85t27GtS9Fyu+Fz0Ifl6FdpzdUaMrJI34hU+ +i9XO8ofzPd68opcswPcO5AOaaL5w74Qfj4Q8xhdPpq+Tu/Ke9ZVLeJ2rFhUug2Ig +8iHhTJofPg8GATOdo7t7efZTS1J6CRk6AVotHvyJ0RCvHKr6i1qT+lCRu9EIuh8b +c5DJ51U1wh6y0k5ffYzFK0QsiujE5huyTFT1LNJrUwApeB8R27kVKSS1mSM6mz/4 +LhNC5nzo3JJ11XmH+ozwXTeXhsQS0NdFKyZJfW30fwgmqcw6UbbzbytJudUsG96L +dRmHzENmUnzRgVsSzB9z0tta/mIJ4aapzp2MPR8rmiiL2oDCOM7uZ7OYrmddzZEG +VsiMxJYOQb3s8MuxKfMIg3YMeKsTXYx016ZTW32L41w6HxqFFEFHIDi5qw2h3H5V +fsS6IIfvKlvfnWt95tO2k5LPmcYfl1Iq2QajQ/k9kgVyiOtAyF6pl6qPWKumZlli +pVcT9mTerAsGA02QLxeAesN8m3ojtpjQ7ZecB8QnN1lZArmeGkrYkGazFArgYJOc +Z9WOl87htK1txyN2ss2dAtgXRZcnDHm9G6NZTckni0CLYzPRXGqPg9Qhzjamx5O8 +RT4JZ9dERJ7nL8hT5uxmMFOgtm4/bfEeYZknj8uWjXP+yPdd96OH+PQ3mRaJSnPp +gmt3/SYLcyLjt2UF+k31JZ3v3y38zo/YhpP415VKsCcLerK7ULokgjgcr1H53Z91 +ss4huvMVNioD7eCutHG7VhRd4W/734DyorcglRWZDFQiGryyXMyhuBqv4z5xU1mW +ItulH01TTC5lPpPqvphq2MPOwMQ+b3QeCdmny98NSvIqy8FDfavqvuwWmIERgoge +QnOe6ytg+5qB7E14cRHWZo3OFGM7jTDvwvlQ/DYMpVMrG9FNr46ij3vTukx0bzDP +iiYU5ltHRny5B6LRyQXJXJi0Xp0UsAfDD7IxTFp7g0JsXxhRotnjqqmsRHID1cUt +9M29af7bU2mdNbhf2ESqjC97RA/1F2AG3ShxJxP/lf94Stc3VHbqi3fB0Nb7Z0rt +FBQk2c+uV1tD0QV8ho4vnUImlUXdPrwbNGamviPOtbGIMPR3Q2Fd3qj502Pi4OLp +Y9GhrZZz4PTDP13vlp7aF9q1vQtZALcOZrLT71PJB+uu3zCkg1e/Jz1UkD3Hpdot +vnX039fSPcJkyJsBzc9tnNlTL/Z8AJTq7NxaQ7NA+bdLBfV9zHhzMpaS7lSiF7lz +YzPwLB0oKTTKi3q4AE6Nm2WliNx4rf8rWW9VJ8IzO8zHgD/03cmdbmGPQBpPW36N +LwROtnLY8u1XRz6d04nrrYBdiG9rU+XzUCfI/QHskulQyMlZRa37gPLYNvcfF1zz +YbUkrCqxnHSn64xnPuQQZGjTk0kQORKuer5/mLjwqy7CYRZyULRinMASnzo47ow0 +Jx5Py6hznQFjAlNlO6NbGbfw7JgaI9kE9tCSZ9qXQtoZ/u5tgswL2R1CWBgHCFlv +tvTuqNwuq/1kG+48jFD+f5O0zWiB+R2tF1dzOaV8GNsynKgvHiLzhy1sMPs4P4U7 +JcQ6I1rV2mD6mKCNsPg5tLWFzi6vgfNkDw1xSaThZVwp5RgGryD6/SO8DSEE/h88 +n8LivWzhC/tLb5d+oXOI20PLwqKgI1qDbEo2/oZdpkHRgurHQ7pLzNPHmnAbjQvx +g0XQbnCPfZEJt5Jgo4fRO9xfXng8lTQbYTMQH1rJg1sGElIsdAZGNPNOP3dZezGq +dJTB6aMp5WUo6wWFvB/Fv5JEHKW1K5SxO+Y5KjnRSbdgpfVKyaoKAutYCcd7q9wJ +7wq8Ft0TT7UMeBPqGvknTXXm8w90V4MA789DdKbGXyx2VhCTLwFjVz2ysT42UJwM +BYbeELCuPhqp7EE0v0ysbT5MD8oPX80U/Dxeq39wdt9PFXAWz7gHae26N3KZdiKL +NCDN751mf3ccCJxy1qZCnQz17ToP6ZL2HWOQzZWBfYTjV+y0md2sNArb/C+GUmri +sISKA+Vp8Dk8/CUrUHV2q02iBFkRJ61QHNEWtqKNgX0pepYM9D6w8Ah9LgHgXgFx +5gJIng2rqOhaDfnUQToP82HdamOmHnCJ/gBNjaqMf+7bn9jVW+hjVY0ZPxCuQPAv +1uc3Sz3q+ZrNKVQmGh29KI7oZtTa9jxhK3VzoSpGNRCAS/anWSq6Hd4Dumm+oSQ+ +lHXUz9881/TiGnzog+eC5nc6O+Kc+wXbT7AmzsX9/5bjf/hrxsk6rEb/ixtHkB+i +GLu/cSBGVfFY01E/YTWetYSM2zUxrItaFaMSEVAkWnKnCLXVUQpB0Kz9qwEco+7U +Py/DFCDDPq/glDrxPTRPT+Bs05xxyx/2XHt+bpq+MsU44Ed3d545oXNyt6nEZKlM +HOAZ5hR7iRN9XTMHcw7N0Hj8w4irvXFIqQRN1R1gA4d57+//KLgVI3r2muMQiZq+ +gB95VPq23ELMxr3mW9TIQ4fq9srfL7AJ6hzLO/MWXkGwkthaudHThv22nioF6LF5 +tCyJUv3pc3xQd+G74SYee+s5YEbqoCzHmTvTz45mQm9qmLgk4ED7FC+8afzZrUWY +DZneOeh1qUIZqQgu7e/ftQc1kB0mY5qLngSaDlkUPHBplUlk0xcNVRqStxNYlyt6 ++egXrZOyty/+FX2wypnXy44ivJDKWIKpNjJKJFXthsSWtzyJBjGY0VttbNviX37j +yuoKGTphHdm7yZ1DRQvtUmr4WGTicaSfUC4oZttTtofEDAr2qipUF+LwUWGuGgWX +0ip/rhABZEM1UuOu6WNMCSf03YDPsXSBqg2ju1rexTk3z53VGM1cbU36G+EzTGim +S00BfgwxVQvdBJ8c0ORYmiZMNYt/IHd+dAFtWEEGaqi5na+rlrZ8qqy1rOufSZ4E +Lhgwp+mPd5p3ZNoMT2KVo/hwXvMhUpucwCT4WW8xKxPeNCTTww2i+yZxZUyLc8Pk +048Kzu9YjSoKUHk7r+hdEa0+CSnuWFARj5CUgscPrIse8Ty1lKKYWGPXQ+OoJC5p +phKW2nKPBeh5CDgRUqlFG/xj0O6dNq9telHYAWwBohz/6adUKI4xNUWlBY8FRTQ6 +hXKVB3iRnqlC+ln6f0fZ1KkT0rvkIBsiJF3tIVbOIGrGsa3pvqiGAP3iWF7BvOPF +5SY33+T7QbZQtrWpft43XUQomKj7RJNdoZpJmmIrVxU/JpesGd4n8Qghy5mRyV7H +aqnTd+JmRocf5aCjFjvYaHR8M67gylAm6h+JZSW9vDwyKv5KVBRPd8oaZpTaqqwz +VkNrrXv7fqDnSTEtoKetTp17kp+aF2tA0wamRKJW6X42SDtFKtinBnd1MFfmq6qR +Wtr+oDpNotRs4Cz5Ml/ETb9V+ctLISmAFpFZsXKMNEBf1l67EaVHhQHshFVo6MmE +gfaISipXVe57j7bJ1c1F2q+UPOTLK11kok5kuoZkZrSRdd0nY1O45diOkMe0f8SQ +s0PjcMXSCOVG5R+NhZHxF0GRm5GOusqh+luad3/HtsmjD2pBaT9TIORoUfo20Edy +hVQkeAWA8z0mjQv/kB/5N+qKVIlRuyz/cOV5MKmX0HFaBurRHbwv/AbS/5Uh5ZPX +F6m0+erd3l9ccqBuAvItaw4ouf/pr1a1kMDjez6R4CxmGRynS7E4al4djdLT7ZE/ +Cf4L5W55tyE3A4zGbYuwXxlvzB5otmjIARCVPaCJsDLQVvQEaS7/OFItoPSCuObn +w0w0h/4Gs7aqO2bsGPGLEr5fMFAjHsRiCiRxmmHUiezrEjiymz6RaZwzb4FFL3B3 +gpGoZRbffCIVaBgKnq1rifvnYtZbOZahg5UbCMALTRqj64lHxRKUaT+c507MBzcT +2A/xQaaMXd1unIp9AQPTmHGneDmpNpipbUwik4wZUVRBaaucrLWrG6LcGp4icVlK +QWwb+t0Ngh3nQgB8q4ywRv39xYJ+Ntu4vGsXz9Mt+hM4bjRSfzCFgdaaNQqqFNPB +c+dC2M7DsriTPTygks9wxwuQtzSECp7sgpkLEWJOGJLy4LVOCFyh4jdmMqdieiHb +BN1iscgTk91VwkG9+kQIgHStsiOsI+n81iz04jxiegCP8peldNSFvX5GYFHWotCO +ht0POQ1shkziTXdydE3F2umaRkAI72qYls5BhDPyfHP+Qf2ZsBACz5UId/nxPeD3 +5aWDupx7LBRLGH6oR2g34oj92Y/o/ph4b+Np1R+XmV+ahBA7RpnUVe6dsvN6UeSR +WglN7R4pTf2UTS+KD72r8aNQlcjwZ0DiDW14GW75OHxf3G5PZ+/KCoucxUfvZRNN +PeWX0pLfgCzN6d61NADCpGqzRaV8N5hfevJ7lWFXsU7hUXFMQd9d2YQsa6Isi2mB +rXHS3ReefPS4PBVhANGSzG2HuNTfc0XTeROebUTT8czFCvv1nRkph+eif5+w9e5Y +wpqZh64iUA5G1Lb68JAL5l96ntIzk+XHzfkF+bA+7E84hPgedhaTw2z4zzESxron +mWxB+8qJnZA1CXsD/PxASxJa3afR2iH0KkUDLyERtSBaZUV+ORUr0t18zpDlHE/0 +agC9ztwh4doxddnpKEXFBftpZaVbKsOypMu1vQFBxVPwwoKSgpcVcAbzUkWYnmJT +ZLX+04cd+Rh5lFe50K/JPYE7rw0EsiqzZFYja0GT/aY0i0sr7ggBv5PGox89DaPR +M+mwNkInkOXxi3MHyRrVITAGp2WcOXHmmzdXO6qpeExaBdhW6lBRDJorwAyOb1cQ +h4SZw5YdoducErUAzTrkd7VelUlhr/w1jZ/31NgyaSkRVOlOmJhTDTmxs83jfWTw +eZSGDO9ZvtDIgHBr4CLE/5SyxgW2lJdgs12MA8AmIFHbwTQRp67rKqD5tqjFON0Y +icTpZRXGj9+IXV/OlkjnMVKeIUjhVP7M9nzyCzQSr32foBsBoW8qEOEIe3Hp8v5N +jka1PWiaeVsORmiFSEJuNQBIbwKLWj8WpOQIU2WBsaSbwLgxZbAq6QeG+fWoHvOf +ZQsrr0aheaJ1sEjp+g7kcRz+OkkxiMLp+zqstbX3HepZcLcjE4sP9r3nffEF+jC0 +Lk6er739jGapdW5xc0mLBK8kUOlRUTOwGvfTMZv91gZkOwonaCOJcYnvoRnSZajJ +ITbUtQ5Ur/sIl/RJ48z0JlENCcZ5t1vwa7H3Iqh1SEDh3QEShy8erQMLb3uhogh1 +2PUTkyH2RVxTZrAjAmn/EZzsLf9st2rU4988fH/F+WN0fQ0pSzOjDOtT7Siie5l1 +LjFScPHYqlnLkl5CpaeHJ0bNu67frdavI9wj3kQzMRtsgTzycZJ0bvA0r2xRq804 +IYtaimeUwIRwg9NoGtcdYBL6k3beA6SMXeE5QJ5GZJcrOhcY40zgTMzcSKrkhSci +cVWK/y9yq20tFKRC95HuZMO1n1sCKpRCez+UluPrmyEhpj9i6SVFAyLhCa5/1T4Z +aIRK2609/+UWwhK/rFMYSAG+AMpFADC/G6hevSzwdq3nPYFNjaJEwuNqdgE08CfW +ZBUzJ7aBGw4QZS88aLrb2T5mdGqHWOCwD1F/0jpMDMwccTpwYqhcuixKy1IGDFsS +SxZrlEdxBAVpAlnWz3j6VGyRiLF2Th76uYHTwEeg5CwmofBk8mtQeHzyU1XelJPd +gT7yvnl9TUpDQ9uNnt5CWKAOy0jgC4lB+HILxpFgtlZ6+JawKnbbBmS5MyU9qsm5 +k+aQ4yQNdP5xyyXRTgyvSa21DiHvgzNv4xwNr2ClPh9xrsILpHGIviphv4ekwk8Q +pTFnZsWkl11LwNCbJZudB/3n+QXsla1k8zBe0oZoHDH/D7ao0GNmpuExKQohUuYm +Bkun4xAB77mhH9DoSaVs+zI5vJcDJK0J0LQNvZfdLek55LLkjLQTxvOKtb8IOHUa +R4PVGheykA4RribJ4gUmTrG4SxWRW6V6c8w/COxUBq6e9X3emTum0BXg2S97ddT/ +ugRqIye92Xu4glEuBKiEiSsYkCRRFRLfy33mg0Qh/wkn2YK6ymErHe3Va/xaHd53 +u4ZQNfZ2zwhyvScbaIIKwvMZglPNQTVKJoYdIRbSsFKAxyxhoiaeAS0e/PnTJrur +mmfNVhSaIcrbUmWrPtqsWn3ytCkkxdFXeDA1Mrr7npc+5MZeGWXYymgb22vn9u66 +VbgBe6JhB4LsFBymmlL78FBkH1Khl759XHwSqWBabZ78Nsma4wBoKqkNERIlTDFg +hM2GSRsibel4dwsBaKSh7XnXS1WialkaMX5jTQ8HgRMGL4Ieh+pBP14IyC8A2PgU +GZsHuiFP6gjnfiXafDlwsG2t85g1g3HW0nfk/lb9mPz9S0DrQpQgWE1hBizL4CN3 +c54o8MNUpj9kGITZ4R1NrkRWVKJGNeLGXMIy6MgmrAN6CjjyfID3jAe4CpIuUinu +F0uKdEsEMvl66AbaK2py4LZPaLpNpA+P6DKvQhVVBJjaOwuoG1zEvKavi+L8J045 +cuo6cLFe+aI+c+Fgl7dJrgLtCXnNojuOT/+/O3YbGWgGMJLq01mnSD2isOXdr1qw +zuL8aJHMRSJgY7p43KcdzyVbc0+0ala94PYpTuLaVVsYJGpyHHMCgHJhZFAgdXtg +Ux3K+QIeLnmphG+CLXWnBqNGzc+Y5h65JJ/Mo58vnrFb0gtG9qNf1y3lPp7iqFHj +j2D2AylIbNJ81RQmFx2cPoX2PKiIvKb0Fy6SD5IQ/2FLqRJqVOjnwg3Uu1AQ1NR+ +OAu6M+ioz+nfZk6rwKkJjrU28weaeNKuNtCQOwbaS39NwTHRNDybrXbAXbso3Izx +hHULq89G/WE7fXIJJ0uNZj/cmIVk3lVF6/9zsx2+nHv/XUIhJZx9EG5LfBBVc6qr +CfMjv+9oxgyUl/uPWDBsm26tkTV3DbbHeU//M/nf4KYRWNdwUirBLfeGqxXgdZFH +9mDPUQ4z6WmHHr3T8a0VqhMnAY9JZPZWtcaMhdhuEyEt5JTTJAmmO/m7cGRh+U9j +Oylxf2Mb1LOHffkW1XhJrQ3bDYFPbrrvddxJb7fYr43RlXkG/NtCA0CR7fzBlhtw +oML9Tv6EfavyLW/lnsOYIqZT3EexL37fh5q/U6iFfb2Fi4yP0ihSU9TcISR8bkn0 `pragma protect end_protected //pragma protect end @@ -594,542 +594,530 @@ parameter IDLE = 0, `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -h798DEoPCCw6eC93sfxnz8ZJ5DmYibE3rGjjhE+YK5a3RIfjyfpuQmm+Qi6hiWsS -h21ZC3p98i4VCoRgq9ttjdMjEUVk6R1INC59AvJ35jeq6cjGdiMiIPwnlnHEAIqa -kQUAn5DZG6XDT0Q74iMGbdiR7Uqpt242DlxQT/RPahxewbF7bTMwF22aKiwUymVQ -WL77YlV9D3RHdY6gVwH+r4vNibfPRFoNglrFWdWkXgAM3QCILfTmCmNOrDP+tU67 -Sp1AnVUQDUfoMreLqPv9PxJK3wnCugVdw08bgxzbxycLpfzcQbzXtVTNLzpE9m/C -m4DQ47zqQmz4Zj4f/JVRfg== +f0DVmU/kdU862C3ryhjQlDsM4c/0bG91GM/Tt0YfOziNIhVBbdZsoYW2RTSSEC81 +yNXUBt7tFmZq4YDopiOye7MWsFmf8WWRQEL3slo6DkYqzPlqCgnjys82AVws5Cco +WGW89TXAcQAYHJy7oG8Ae9oSMdLa3PIQNp7mSA6rz4RhAKHQyvxQU3wr0zXDmYKl +CeyI1ZIu155HAUZL2bXguauGtJWtwaTXIrQO4i5/hXied5l3pm8lCdXsKbM1Enxx +V3E/sk/RBAVETx2fmYxracwCdN363LHRvYHyP4b2qkmUndhj47mK2s4d6wc/G0IJ +HQRhooSUf5bQscVy4yyOxw== `pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 25024 ) +`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 24464 ) `pragma protect data_block -YwM6jjCriz1M+FDJXSN2LeXck/ZAaH8JuIXMxJq2uSTQniMJPx1HUHKK0h6e+ADy -nOpy4Npr3RCHDdf751Af8iOf0C8dZcMs3a1GYK43f9lfLJ4Am1BOEiaKGIMLoNoP -3/ezGIbxr0ugu0861FRZvKAC9ByuIi2/kp4W3oQ7m7vZVqigNx/Z+Lw30JD+Tdof -nd9fbmhRCCJW3RaeEuI7sGkqxIGkRp9Ypju2a3+UmaW00MJNt8bCRmHGNKebapN2 -4iVEq1eRDz+FLHYVirgJupc+ujLQGmDcYUtfEv75/zbfhbnSF2Tzy4KWhMa/eqDt -JdYj2al2m3yH2PEUGOEg/lmK4ufxcT7uAskU+0OCNTLvSk3xxzqGDoUTwqKX5Ln0 -JIDW8HetHVJZFTLmXuKbPHS6O+HyLuJ7Zxymn+Fjne6idZqUL/nzh8AJkD5MeD46 -devUK2qciMx2VyWCOynEzLIDQuLhf4HjJnSRV9ZjArs+ihs/aN5AaI98MfMmwjWS -KFKPxBp0tjRn2JUO0XR81ueXaQ9p/dLA1gbRJm7u3ADC4VBKoZXEWjeKWQe3/n1Q -mbN+x2KwcKG8XtTQY0BO2biWZo3QqJH1PH6ghVrcaM0KAEj3eBYyVZNVRgEB9Zrw -RRFhPPGhGTYcaC0TDtPS2EToJT5P23Ql13VFSHg3/OojCJpJcY0k1dryK52hqUyY -DiWhs5ZXPNHotTcdv5rTTZ/yPkW4CMHMJsuqWMpMzkQfRWTLiLfPZCs059UxzGNu -ZxxVrqi2QvhQEvWGbqnY4nFNZv20Zg/gjBNxOZGImfOZ0Y9dhYEcbRA76Ygnpw5G -vGVtZG8zdpoUvm5EKdyPpCtMRRphbRSJOtfS4HuKv/+VOGCmZaOiM6orgILxnDj4 -cJZcAvsaKNPUkQBZl1SdTWoZQ/ju+qYxeH5r6aZLkNlAg8wxRWRLF60dr2HZjer8 -evhWNI1sXa3DYfXmrbwUlrRlNScBbch6nExhqbPvdWtVWN8FLcA2450xz3EqLC0v -feI7zE+5RTFKHrFinkDsvLSssGe1F2TqSwgHq8wjB3wBMKoGATMrdcoUI2WYRzps -sP8fhHOW81v0p8J6cL8JSFTmnDD1QjgxYc0UHXrK5RNr2TSldF9Ou5BBhkAPViVR -FIKcFlaVe+RGEazKhck1nsf1xUSGwWx23yq4cIsyQCPXWKRDTKXWeM8FkbOfsB4h -jOLT4/44scAugcFmRTk0QLiz01X/qCE92lXw1/DWYkPkpJjEtgNyZ5sRAiPCoGx5 -pjLXzx8g4oS8KrEfdGhIfSMf/ac/7nnoML7Lw4+QkXMvIwOHLreX7f2b6xoi6H6p -+t5vR0AOmFGBcGCE3exjIyI46ho1XyuDGrY+67zNn1N9b1Ub6o/nuaUwVLWk1eHm -f0M2FtnsAKYziyMLe1virFt1be8XoHB+ZhDjV03xpiT41vjH/O+V83gcInEzBy2W -QyCLM+ma98sPP7eg1+vROdya3CBGdPYImWLsfomVwFR5DUkqPBV/Yvxtux7DejoT -41Z1oqJ+rHnSnzlQ0XxPrcfPu4tfNYWle9kqizkAVtjZSa3uG1S8mSnhcizugnge -MgqTyqZyJP6rQjbTxAOQV8iOpQ7KkHcFDdsN6CNIt3qOAPaWUIruqhvdNTdr+MgM -ttM3ciN7ddW4EFINq4hVaZiwOPsUyx7kFABzxWCy/lm9iu97+ujhpDbdgDgl3N6G -4BGipfqEzMzCfoNMGVL2wd+ZAKx1EQ+lXdM7//639Phir8qi2rL9JqfaQnzgjjVE -Bb3bjwVhp4tTKllKrmKPv7/ieGqlRdR6TIlcSWpq2EzPfVyAL3hJIO3ZmD+9VYp9 -ZmU/ubJIqg1uGB0DB4o2jYlNgs3TFNryfNFWosE2EruxxN9wI1jdiVKjx0Td1zMY -iUozv2l0zER61lqr8cNh5wtLrq9KlcW8MuUwhuztRdE0Swsrs2vE/F3UbFFx3Iwq -Mb2KxXdY0gJFTdBCJw9pb1B9xP0ba75hV7I25Fyu+GErhgg7q1RDaISwqc3myCm2 -oQEJzfrbVRLH/R0fKd3GeLPVNlpeGP2SyZejNSWiDH0C7oQ0ZyrfPmN9r/smpKWs -OCgU/q+oUh3L6MNRZD8sSGLccFtZqo35Eu8EgSvXmLMnD8BL3qeOmI1Ylz/PBD51 -MLlHMHVkFzy0Su4Sy4499PqhbIT4SDWhQ1Es4vyttVSrnbsSdAWdq9TlHSOjKhy6 -UZnyZyvVXLDvR5P18fNyVZFHzSyRuOXeeVekp/CP5yAqBHVbTEa10oZ5HQmIQS3u -wDhqg8E9sQD4R3wnR/r838fKJ2dpiTgW8xhDFVi8kTtvtHLbykFPwp3MLg8A4j4T -fwzLwMU8OcgsQwldFUH1S0aHp8pAU/mHyPFCkix1+P1yozxrOhdzuJvG6m0XS0M8 -I9K1D7PK4NzVTY1H1cN79Chnyo+708QMmkB2g3noTeMMg+Dp8SL5qLFXLiNuOsnK -8xi8J4yLN+o6Dw4QHyEIboUo8UzNfKFXW3piAl8lAlPTnyYCpkwIV/aFCG4z4tEv -8RIFcG+OcqS4uxizE6nlETKrQbLiFEhvQGKsuqB+PWED1IbrnGZcfHvY+GszMQY4 -JTaXv2Ir26Q0YA65u/MQz8PaAl3wzFFFjdl1C3WDuPpNAjNsDLJEVphDdKYUf8Ms -iBtI6p6wiWkEViX3klVXnJLcOvCEwWA/TIwzATU/5rSS7hUWRVNHKnoznIkuGgpJ -RGjG1BB2IAKUXyLdPYqEArF33hp6I+p8EsEbMbJVkd0NbyfMYOJj/YBH/YG5nnlc -fw3fRCFrG45qaBlDB7MYXQiZ2xPwFA5QaZat56gYwnmUVWauBrV3pWhg9A/8yWDl -cFOygg6yicy9RXjCmhnao7NXEPlr9q9QTYYAa0+a/8HVhRCvbBueCBlWt9WyCZ+t -150BN0arHc46mFi3Iz/guEx7glFMN/PvKsowwCuR2WvRteusH8KYgeTLsjAqRwJV -DZeb8PRFdrcHFiPbTRLfdFUECMYduQMHIt0M7WSN8OdFNaM8KWonFyY/t9GTE58c -K7OQoKqCvi1LdTuPHzqr31d5CXDq/x+CjY+TrOT19PDjkiBsdw4Wbs3K3R2Kv9Sp -2gnPwETW7w3Kn/rXs0czNxi5uX/FcMnTHGMrs96bHaqWivRLv7PclHYe1TmGKRnK -j+sEPNDkGg/LXsG5GsGDH4Dbd1LFOak/B3BgLO4tf5XJ1qJikmWoLIJs+vWwCsVD -OfvgTQHSi2fZZSvSXiwfFiFYay6xzWzSv6P29gcXLz94RuKSBQS20lw+LcW4q4lJ -WGSwm+C659ZLMMUZazoNfbdNZ/ELcpnC1uiaicKdWqYj5lgBj00Em5IY0V/R6fuY -NWQ1fL51N65P7A3tIXSwqPXYt86lkpurgabNe0vm4Q1YfD10K5HOD84Ed7c6S2/S -FqeMmLD4t1Od9QkWwKfi1+YaZNMuROxXH7r7mKWx9eL7gQB8ZGg+eEqHlxbaeCPf -HstVoYS+MnW6yTAOkuxD5IWORKCZeTD29YmkvujzUfARnAbjnievqzO2zUQn4K65 -eFPek3koxZ9cuGQNPguFpuIe/ZxUyjAJmsHNQFzuZhm0d2fw5WyYNZ2Sre3/Ydbm -WZzaAwJvXeV3hlwZ10Fjl7Ck7u6LuKRvu18QvAONgdCJVoPm41DuquHcsPn/jJWT -Vn2ZZ1yFTJeRnN6jlpPQg2tBdW9GhLM7A1UK1Xs5LnxQ6PFVgyHh2QSthcMwYaZR -4X953R6fjLpPSKSvGEBs0XQbX256YI/Cmnebyue9OzlDuFK7Qyu82+395xIOxFk2 -HXwLB8o8IGcmT2Jnce6Cd48wMIGgG4aSoGdLuRWI9wO+noxsYWhBBPYuHCYshevY -5aKuSpb4fKRH9Z42xrPk1HjYdjKluVWLaFCral6Gik0hsu9UR196jh2iSBhryioz -XbRlZ6+29TEiw5no7mkI1N120SKRad3LK5a+fIwo8babTX4C8cISvoWOprSRxhv3 -xz22SM40GOMTYJX3+Tbbjm3Ycj0mM24e0UJ1tjI03bf9/Rqxhzu4hcl862nkal3/ -7KB1YCLWVmoLFCAulnvQTBs5TNI9Lgo44Vn7yaVIOpnh1oYzl6mwzAqR5Cklu1X9 -jcJ3b7suk8LknuYjLwPFxPyVuJ9V6w4fCbDvoePcsfYH5KNoJSF9yXYnhM4AYiQW -U+31+PwY3tqPCn8Ug7QmxZUdtxKfOqwDdJRiDZ5YwNRBzBmcumCAq7hF4wyw7yjz -8RSeMR+advow8lNVgQgdduNSKMZpB2dhjQL9L8WtdCODQPZAtIr0liHvFJm5yLYL -BVLTayN2KWVsLXb15IbJmF8nHZaPqF906C+GbH9JymhcpWr1/fuU0gaWtEowCqZb -SnuySMZS19SsV8DwOzR5UN5ov5XvL9ES05RGAm92Doulz4/GDIEa63iRB61KC7OO -4Ergo9e5+vGSMGLwKJMyV4bhL6Wn1sANRuk5qqlyniKP+3hF0/Xl2Lm2WToN/2Fd -VkINKvZtQjA6rhS04ZcmvOG/AgvozInKAtBPmnzXsXBGjYJ7LmO/m5qMIDcuxG6T -ZzpRSLPEWpA4shcHwP++qJyQ84a8suRYNLyByjQhfeUIEd1nfPOx7SCvqT0GiztG -XXIX9NeN336DpqQDMwiCb6qV/QmPrIUANIvwHghyXqC5ENbu7Nc5vkwglKpqtPi9 -O6jY/kE4IMG7UKmy7Zyi+1vexXIcdujlqS5H7R2XQec1yExY0nhC3nxBQOpByu6o -WZOYmsvpLbIJ2aPFcQGZDWGBeBTLWWVII5o6xRGEb74qPt6Jj5CqB9IerU0+hWJr -qoxKa8k7GobnV2RnUjk2gvZmbSZ9CaE2WL5Jw1aiYDzKWuEIMwX8AeSQKyKfffCE -Qv7wEzOtUyin0XtEO/7jPckvWF8S0TBR8qLTS3lTyBsbYY43OPFfwKP8c9OGpL1+ -X6l5sCeftjUfCaxSPB+y52WDo969JI9V6Sz8VWRM0/IezDSp3sWeE7UX9qS3d1He -Csx370RggPAQiqyyhotxvPwnNBg/6FcscF59kJwsmmvtrgexdfGOrLI/jt2brqVq -OCrbDTyJN9kp5YFaAgXILXAafDgBYO88TjFFcQ96sb4+PXjKsx985r/mvCtYSpc3 -UQfjF+GkiJuakmkZr2plZJmdh8tJrtu0HfK8PXI8s7/pBo0khKoeAASgUkwHafb/ -qm9OvmA19bvQ+fhlNTLu6gdAc7ME15YgJpa7EwUwa4Pxg0OhUepLDxUnXIJYpMtQ -2mGKQi649TyHS+SgjB2EB9W7SPLhhND5YiyngK0GSXUIm+geq/0oaAkahcSKKiVl -P89Ml/TBMrGPgExjIxvLjR8FmFluZIVBvl13nfgqwQcz0Z92NFXwpkWn0WKYUjmP -IIUU+XSoE0LxsJrllDnws08x1IzHyFZYm0WdwHh0RYysw5ql4inei+VFn+8jXop/ -azLX7YBk/J96jPxerbASRQoCD/Q5jntf1hXBXpK4KZsGmMY/XuoMN/FrQtdss/kf -Fg/kAgq6njCEUC+vSap9cWUwLJnLGpYXtru3ITLezJAcWzmH10hCgOV/OuxVVv/3 -JdQBijzseme3eAQ2wCn2R36J8QR9WSIyYeioiqauq7GA9CvRyrlMMI8Cv0VFKm64 -kC8AY2GaH6yjUKWgb/wjWijrxVWhKvJo4NxeN4zr1CaMmNJjvJnXVUb/se1UQhkQ -7b3rxBxgkO5AvneBWmlqxNCa0nN2au4h401crZXJWB91qHyPHN6CQLPcbRlTW7Xy -sQcLmlHr0hBZtN5HXo8UButFAqklESJ1++2PX5D+RntUbu1KCi8lZsvjLBOK9Ofb -/KIk+n35trhcGcZd8mFul2ucg63iFG7O9nvHpPmI8x2fLl7XeL119IhDcsEuZrFF -zNXK3KAOkxkpz3CO4/2iuZqmB4sHUNTtBSy79lx6NP5ieCG+o9HBTRKKwPSmqNG+ -jdVr+H1MCm7QjkVqGsDNAWKlZJKDGyD77PN2QytYqICNsR6W3KnOkR6/YKZou7WY -KaNxz2iSy+ScfHjQR2GVRx6uSK1lJfkwScrHawU7pl0f5xEmF6Qr0gMKlJuoTGuA -6yfwedsunFUre4HPaVxhpMWsDEmisOthfPZAGhtrWA+EOHpafY8iJT8wB67hnh2E -LQ7PFhNxNNXwVBP5wsNuqAj6IQd7HfV50YZ6rWFM8vyQEZmIX1M2Sr+4CxkGtKni -Xrx56ZmVuez7BmktxqACOGhCTnJ6LYbRCZaKQ5iW9/gxsQmzBVsQMfNLGWowUsOg -ll0pMdXkO2Y48Q5yiknMn3ZMwUHMzWcbYaFqGXeeUD2h/bDVzdiXORU9OKIvGesp -sajnYVioUGobmKazOy2CHYsKpqLKIKK/DlvS1fIfsWce38fjiYWyqroIJb2qoEwe -mXinV9GfUo3JOdGOTmeLmyOdXl6oaeeL6p4TE7L2LtVxnDjeefM4uu1oUBK009H7 -GBPSqpgoLSR6lvnOSOGGWjwwhG2BWe8u7NqrwdZsYOu0rNl9GMZk8gBeGoKfZLEr -8mF8Qt1ad+kVN1ENbLW00+YOzA9rCCyWdheEf9vncMIiq9gflsBp31MoPmsvhapL -aY6CZc5L9UuZXCCkQCfGxxQs/byH4H93L+s6jMxYZ0Ba8pOnYLEiZDg9wy351t4m -YXdeGdfOwBP7hBFzZYT7HA1vW5VVrPlcNOp8dE+nbiyhtatqECHc6hzPnj4Gip3M -WfQynx7iEd4TG5bk9wY7N+tyN58wWx+AE1QbjxMSlmUbw2uj9AGeZRPD7AEIdsQu -1Ubt8qAFaTqPqf9wsyj00yzcAMa0ZvhE7zaiQOQqGi7yjPCCvVAYPx0knpnrg2O1 -v8q2d6S4grJ4xDCiEeOSCjn1gcdYjgfXApZGgqiqlvxmOqS53cDQN/F+mW7ayIc+ -392suiLnusjr5TMdDH13RJSfHKAsTivJ7smhwg6xNhPexxnTheo1FhLt5UXcwyDt -VYL/BGXJKlSKK9tfJloVnoL0jS+919cuDHxnqGgKHsuYr6Tg1C1djWB4hs8n59GO -yhxsym4bcg+u04W/JoRAz0siA8cG7OblvN4TBmxisl3B1Os+w5kI45wLhucCnROh -Xv9KwqMqrbrO9k1sv+T96ZSdUnNxX1Yom8TJ6yUvGNiKhh0WvPp0QOuY7LrR84nG -UrZPsqdRfBBR7t2fvr0K2EF7m3gJpxoG9ZjG8bt1BKcFimggdXpqKrUegMq8Nexd -8Yls4a2DgIjiI/TiX44KeqCw26RIQE5Bou2/3VDiGj7zoXRnDiZitJoGt15L35Fd -oloytoftNpK5V5camYQU9Jj1hw+tzGY3CDy2zo3oY9IIfOHSxR3vvgA6X6kfvoKW -XA/798jt7ZKCsa72z6WSeMvEvYBPzTP2s8srjd3nhVWG14ZVcqR604PX0bIYm3r7 -JwfuVWrI4EizxtcTea/oREBL2fXwtIVTMZHgthPKIez/X4Xyr3CKzRproWrRWw59 -bcpSyyiHuW/chxNUjV698Dxwc4TlA4afhpf9nlZQQhMsRhoFOvd4dc3Oh3zBuX21 -Vlj+jZLndlHWSBh2LKIhYUTWIsfbhJj/TF8vpIPvol8bMjSDYW+yW/Vn/r/Ij46N -KrSt/l02W94Z1Bx3ITSjz9Z5MNdXI+0VWu0VIB+Ab7GxMJ/h2INblgLKOyCYnUIT -J9c4aLAB7lz0jGhcPv27K67YzskMNlclxfbuMGNH5fXuTmb98RlH+FGfhBi0lLTS -dcTioioPC5SYStAGSY5PnECpDyGsPe9VWhg7P8uXgA45O/AJHYObwgQfGAot3k9X -Um//hdELKndC8BEmHE9PwXKwyiAQPiG+zdfzxkGZVFE7khwipWS+ZUnGpXGVWVYa -cwXOw0qpXXZDlQiI5XZ9+flhlaIOCqNkG96CWVfklUr0b76TPS1sUcNvvFhOYaMm -qgbyRVY4NdLlCayOj4yu+9m48i0dPZnt3adl9IvSbMw6FdFgUzT+sNxW5RNGOgPz -RECt8/uJcOf4GyspUsb63EMqO9wr7DQ3sc9FQujr9NghMRxPL+zivLuc2EX5/Ijh -a/izwAOYd5dfp9G3w43pOU8M1y+ajUKDqaJge2aCV8Su70kXyJS+tDZrdfBTGZjp -0hirkYtrme0IfZV5u7krf1BXKieApSt2Py/goFhqy5mdbJ3qrnP7nFR9aWkybtCc -ek5s8fMgPuzCAFHSNLtO40bSy0s4R6Hfpde1PcWUH+5DqY5Kn5XvdjgGDoIxBcRp -l53c/USTt3ZGSJQOqG4lFK0coZrNWn7g/2cpfIXyRJBLEFpcSaBbAUt5xs3ZKrOD -KLBT0J1qF3q66eJ3jTRrOp/9tAAATNJpSzGIol/H22qAsyhGLsb/mWkyHH4l1fBc -65Weh1OO6HgmF2USoAsqxuKp7uBOBlAlURGrrYCTmrhNtf7cixiEOG3tNtZmPEid -ZHazpQg7DqT+a8OYSUOBLZC5ij1qqd6xPxE1617au6k7bx3dUBK8gcL+3Y4wTwO/ -xsyVRqsfN0lciBZi51PAhjt5itAQpZoL38MuT0M8ONEP5+vr8qMktYsd7GHppivJ -BIwn0/aE3vGgE5bH+zSFQgO1HxDApnrEwz4lwP2vjresHE2jD736ewrubkazmckE -Rv4jDR5NcdZwj9n+n3pZermYR/v/2HZco1DgmZ6GbiQFWvQBL/Pgy0zwUJzakYrI -ZmlmreqC4Zvi62qfEnJG1RPV0EBewLTP2n60iZ1GvViPyEDnpviW75WtUodgDkUL -lfE9zyEcrPxY3RveA7WhdHGhR1Ys/14tkHuZ8ZgLhoSRg2w88QXHDaOnf7fWBI0x -ij8D0eQ1ayPUc0Ethd5+ILCXXFoZeZ2Z5lYWShj99J79P3q0QdjryyMiyjaEoLWW -42JSu5WpOXjpgJ68PshsIYEUvoZdgy+nLfAnRI6fGN0niN2Mv2/VOhjXuItYERhs -QuLWkKkL/ShGL2uETC3coKFslQvWagt/8RIwtMqfMsTvwskVKv8MRnoxDc0wo0EH -mWbj0wHoNh46CX1HZc07e6TLU5WUzFi2LImbqhNKA5WEs+EOQhqQJARvWelHhAs/ -fjcT21EJtXx7wANL3Jciv1dLCx17L2sxT3DIDj3VwKR9HWigeagZzeU10fjulYF3 -NXZTxAoazqN/eygMMGkUbRDtr4b5TNQO2SqqwsMFR24jAOtkvORJ2KbEKKQUajpc -3Vuq099Gfeuj6wjQkRkJwqBoJcU9pFKFHvSUnBABv2syQMZ3OsxLD5WNHrDixciF -QjGQ/nJdrWECNeFg/Cvg7d646IN1+our9Lq6jUfhNGKXjQDjLRHS1To4va7ZbEi/ -b0PHfucjMfDaX/rwG9VFCbHyA4bqsAwJGiybUVSP8l0uDEBVXCB+/KSN0qe4R2c0 -pYpQMMdN6pzkQ4uEsx73h9tuObYAf332yPd7owDxl4QaLUWW2x3JvAozA/xf5M0R -jPxa0KPy3kbzirQvhc5CJg/oKDaf3l/NEeENt9ukXIFjWoWZpWAQ+n1WdzoYqXXS -FhxHHj9kwSd8g9+gUaPfihdmq4yL4Om8N9twPJvefd1laUBClb8ZZJ+80d6ijbUS -CLaBE1z+Rn48zeMg3EoY0YOO3OOAAj3AFhaCmIi5D3PAYlJfKB13Un90002u/qMn -auJ1mS6WxYKhP3cdGqN8cgs6xVtphCvO3DN2sBKTMz6gkR9QpslwW5b/WhCtTmD1 -96kmRezzooxwtxNgiKhizg1mUYqDUmHrxwkr+7GOCnfOxESL/P9lDU3mJx3v3HQ3 -XFWzkn/feI5mL5UKtI48se+t3+Cvh/PPp7MEYfrFcf5v80Ss6wHDlTE1MlFDdiSw -D5uqQ8CweNoyfNhJ3r1DPpN5LfDLOeKCle1wM2Br5uMepU8ZH8dw7IAIEYEwGzCM -gyqKxQlc8hMio4KOCtr0hzNR6BSsU+hZsgvR5EKJJsjk8E3vWKvjJFt5KXOt6QhJ -sDxbh2ocZWGNbWK+ENNvf/IAdl4JSnijq1EPxdnNYDJWN2yeX/vp1le1CbVAhhN2 -Uef9EQCmnitFg6WlLpidATA2U/rPYQ6RbMw0uFjHFBRe3Fm89+et0D+NN+tIf/Qh -Ngv966oxHXZQXoBMo9wKpB2vVb2DXsokYzuCCKulIPxK5fMXDzyw8NBk78AhoN2X -fL4VsgMYgjNsZT+eF0OGP5piM1yJhHbk+bzrfq4+xHCwKenO0Tgu6bS/Iyfggwno -iwYxc+G1CW31ALTeWlM5dZGX3XcSLjFKmsqI2OivKdivaOid68XtnLNNanWE28/P -r6aQX7vvSGLzQYmxAjHgHaggNtNxeKBsH3omGKa2UciybcmB/hzHFRLXmI8BbdQX -IctST2HSpkknHHBN5bqSh5fWksizu/hdy8OfefLIGAwoMm/E1CZ4NltDWGOVkxsc -JmA/a4j+y9un3kb3xoY92lcvi1j31tu2SGN89Bk7jPAmuUuRYxYj7lYh+WEsE7gV -venRhGs88Mfs6uql5H9/4bZxLY8pGAkKKqKFZCZlFBZRDAKlkrSxQRslz8zvIjML -w3YTIb057cJI313sqQ8CBImQ/Cj91KoYa6t7Csykl7XNhEJ7NfGj1UDWD3PT7Mb3 -qdOILpzHMKeioPAdPKpCWQjEMtXfXIWgLZ7g9nTK2WV3V61XzyKe9L5LJK03Td/y -UG4xsS15IE77XAOPP89zhk8Em55J+jr+nr11/ayOnCYs1Wz6IpK3S35Z7UV2AQs+ -MKRRP5Ik3XunsCQrBuvmviYCTSSqOx7KXv92g4f6szN4BU8YKIiAkHVGWnFUdNj5 -iVMj5kU/UYdeya7OSHVFc8BuyWlPZ4/EFCnrfrXpWMsTuLFBoS3wfADK5A1SxyrJ -lWsG/vmlqSqv0qLrWzMYbcLGOse46uWgpPS8to3VII3pBBuHaq8vNoPJYhx/0nKc -uvV5k0waYJVhxZaPMLGBgMzVtdkPF9cvpzabvf+Y4WRAOp2+7WBL5EcNsCqaqDGW -i8SXaT+ns+y+lHu0WEZlUTeKJdYiA+0BLxzoHt+DQZXCKYUd3Tj8+PtCsbbPJH8g -5x5+hm0DPLQBx5IZIgIQkcjw7dCo20pfNOkinfcCkW5YVPnLxS5fb9n/8JR/YMJ8 -Ja8V2oN0rkKbBqDHztz64WCYefCQ6EHtdbm/Xn8hBfk09n68dBIGXzyQo/yoALv8 -SSt1Bp1Xyx69WDyzXPlDdiD+Sk4ds5SQzYbedf1jvA4RCIxHYqleK3GUpbTizPTc -kFQvMzYVfatN/4lpdI32JyAT61gBUvKd3ybkYP+NcBSAOOQPlUffN2U0UJJmbxBg -WY4fUYmv28QzPBdvHmKE+IoCOSSU79B0suqBfwXtvecQQSh/cMyJG+CL1bnimuKu -9F0VtJtYgX35QdM9GdS/t1NP1drAV6J4vJ8r/Io46gDlY6j7lhMCicQHbXntQfYd -1t1mGynSxpu6/aNkLQOEGRVN3mG0cWMrZD/XGgjVHsB2CZlltzgSTAOBnaLWLIgD -uYLx9v2CPzU2Y2EcQMcARExkrsG/5k0mppVlvV5A2Tudmtx3vK9rzeR60i5F2Q18 -0i84CGBMjVmOMNzvkoR+tTtD4iKcD6uTQxS4/PryXTC3h2u7dQ9WT7XAuYCnkkp4 -Rl4oMPLb7XPVZJZ5KRgdkS2b/mE1p7gFr9ZcEFNQn2h1y3iYF2nntc+YXwtu/DTl -lA+RcqrDZ1Vo0VAupC8oAyDMYYX4ImX1TBt4DOYdFYMERebqr3myE2+CTqgZK4PI -m410iNusMEsT+wDugcRmryQ4HgLmSyfbygveKjMqg5o5Utzf2QbiFEtZAxOMlkvK -c2suyVVh3aoanElwcOqPxJ+ht+uwgNjfe1PV7Nt4o8eYw4sytFXtFNyPQlc5Tknv -LU3R0gFeeK9qrcsxwuxXFmX8qd6xt+mJx7Fpp2qy/V/3O74kucoqcSnPqUXGvy1m -fv7dp19cdUf2FMa5U318YW9lOpuDG5QYXLcO7hCDtcNJ63RQxExmtDa0sFug0rfT -eIH/o2XryvpRTP/vTYJr0oK3dDeqc+yZUr+dvPTYowRam238jhPq9vpmlGwKIWoY -q+QwIIK4xxgkE6TCbOa3IJRoWGpK4EGaDl+I0H6JCzesQYbZ2BKxhxYseAuwezsV -ZAuTlZpSOUvA2LvEwZ6ugbWfwLS5Ac05fbgwaUA+2sMXF+W/3HwOcESsYgYMIG/+ -P34F4fT2gTT19cRGzIdetZ+uaJZb7Klbtz2IEur+IUv7mfyfw2LO7HPRHP/ZNJmR -hV9LyQQhbw8IzKb3XtKMPCQ4jiu3nbmqgORvXSv0tLMkg3UisApgLWmasa4lW9oM -nXzb/fbjKEew/JuNaAV5w4JC6yzsES8L9odnVT9cjx1/IIlFJqbbs8UlKxH314f8 -Fe6oTSA2UiB+67EpQ7hCjCy1n9pLqODxXOZiK3vLEWbT3yPw1xjLFocASlCTDdxP -cSik8jKksy9yGTxVdNPA1DZAtPmqGwZ9O8mjKvGwOeVJ3mMpzyw9liuVjNiS/uyQ -7AxLZa5rdIj3Cs2BpGXBmc7g/p8NgJgDjxJrlH0f0gVIgTLyeRFnK9pQe3ila2Jj -9oTCNYNkWRINDv2eYT2X8LPKUx8IbPVDavzjNmXC6jt7irLDrvD3VH+YGq0N8H8L -0QCvY8ntGT21VOSTQZKll/Djpy7dOn7n7mfsMw7dKc6/sBzYtPDmj6zjomkjFigq -Na4+dvu0uGLdykLbbE6CZi3MNvC0qgrELDDy5YpmZqBjTptVbMXq/dxODf4k0oa2 -83T/jSzAwuK2edUN72NA+cGCGpw+td/Nk5l7r75maz9/aYlrTKJY1hlQ11kWs5YU -FtdfwN+Ep7kNFYMbHXqLQS6J+4Alx+rDQ3PImD+CKP0qZzbBBomjEZJIJQ/I+IOK -blALw6mvtLjQFiuyZrku1XFALuprAsa04bNiJyVEAuP/OwTxhSx7sRRTAox01xbF -7urKSaYEbbf3ohSV+VQKLeZzWTpTAYdB9pfbpySeewTNs8UiCpS69vP4Wz5SIcL/ -u5LgNVpVQtNfMiqIijb8atlKK2f0Ncjsv9JA+xw2npBfdFAww/UL7KOIuELeCd53 -s0WJhmvF88Ts0UUJ6+4UPYoNhCFB4a7/uE0p5RqV80prHG5BKFUF6zpfg+xQOx78 -WJQMKWCKMeF6Nh/G+0dL7xeAXJqOCk6+GV2CHjlLYOWZHHESGS9zn05zvZCpCMXF -fTcVngIFCu6UPb79lw0nTRXOJfrv3kE1vJlF2weQ7qa/LOJefObuGMvqeinTxRYI -maJ28WDqTRW/ssxl49MdboLQb57H3wO1XZuPQIQI0Lo8hpv5iYYGBIZoRwQH1P/c -U50UyVEZeir8qDWziPevyMMiFAz68FJS+iHUgmKSpqSjiQ4zAwJhDywK3XZ0+H9S -fIu6XoTNiX+uU0YNo9+P+Pfw6hGxDxU1K0QBs9u/Rc2vHmkJPKn5vaqprw1FiVOm -4DV+snhAbbGtmdHZUD2aaBQDr7+yQYpp20YGA2TBMJQoNpJTz2APPIsNxVHgCZ9r -8ZWwAplXPRIh+gaM9w6pwPFqKpWWsv8JRe7tLXKzekoDuPPE6yER6lrAZAD9uCle -GCLsiulIa4W0lePy8q2Ej2oSMJtEencEW6kahT7BKC2eYqbhKsUrgviZVG5oiysf -YmUgl91idYbzxzMgq3QXMiLjFrVU0JviUe0heg87aMyKP4AqB/tH+AOPXY3ir3Mz -n6WEFRdr+9oi5A0XEObETcYrzH3+u13keTVDJh7WQae5S9YQIcRgCmCxnB9Q58Yc -p/nstLh013xyAJQoJBuGDYWARVxOCVb8hUExT8R7Fuey8URgyLD7p6ejlemQFMfh -89G4cGhDWPqvX6En6TBBJw9y90qzb2yrha1ZayDt71yRd5OxpDBJtJR5N5sHHgca -beYWflTcxTM19pX8gpcfQHUkC1gyo9ylVVDYXe4x3hEV3/8DtxxGSqAystmPfUxU -/aR395p8JCW186dGHDPToloBu+qpg0DZqtyJ9fWJg4tAu4Y7u7aq/bmop9wJctCX -CxyQA+/fP/Xxjpv3kUpLZDcZkfDnlt2UdVx0oImt8Gkb4i3kDdB5NEckIIOcMp/b -ogGlNrR5GcDsOi2GQGndpAGufpsVzz0+mEC5NbT6aNhWEgbx5/6HavYpa+4R/fVm -mTvgINLZzZOj7j8u1BSxv2qW90276Q3VaE15vKA6PVDoF9ID/AgLeCQhtU0Uf5YI -Mz2VGG+BihvNJyuotRHugoQtB4ibf1sgZLVnf/emAhxZqhWLiDQOYNHwlH0pnfZh -oJJUUpJLAWWxLvFfzEFfeyw6zkSYfcN4dWqkxexuk2OfiS89Y73pIvjmDQ6oCMNV -W7zbXqP7Vl02igr3qJVGzDTSgxGPHDFm66JdvRA1AQYGeBn0leHPgVb0j+vrTriR -uaEKOE3CO132u1E8dbdzAG8xbiTPBSs5BN6nwaWRbS55Wm/XLViEcz+cIjoayqDM -AgaMiPe2xB/w9HEQjZ6hN6kgLbp7Vr2fzaANw91xEXJTdDDowNmDkAwAMvXnS1HB -xn/LgfLD6cabV2NFUI6XF47lw91lpioPujQ/i75aAtEwR2BH67Z5bm3APef7X+nM -rAEzhFfki9brNawl8s0XU6KCt0LZ/lp49QCov1tmJAGZIGPFEUEFRFh4R92H2BgF -JfJ/lBhb/GjUTDNbBVIvQntw8bC5cco+XjmRad1wYn6sIgpBlE/0Jqy4SMv4Ghqr -H208lDEkTm9Qxrl5AdbfnazYisic3C3GP6eo8RYLPXdZVlPJSTytXO732gYrmXry -/4aiht4BHE8uipjvDGgmwLw1bI9ITRhdJ2auPB6dceJkTFdDElHhAOTim4owvpfp -0UkWpHyZHtaqS1KXEv8QFMqSIIAfOjltpkuJzsoCwQEoeI2mIQ93dmQdiLZIT6j3 -Kj1h9zqNOMZaNFtQ95YEMwZk17WH3DpAwI97+JeVnGub7iVeCUX8Pb6TXp4AWJ1L -tPubOSeOHY8GXJ4IKoLXjbb9uRBtIMTgTrkcpTtnVd8ZT9FpcA22OzEmuyuKDYPU -/bfAblIGHlSba/O9NigypoNeivRWWGxyKZCFnx2KFDX+EEx84aRN/Q8oVDMerof5 -iz8OaDrr6pAc12dBWLsXRWuzQGm/ap6LIEXNkYsdELOvRYEr/JWs9eD1I89116aQ -xwCeEFAl/KFgTJa1qIG+ItlKdVuP8EgPWx54zLiaO/rCxOvOj4nMpe9Ehh/p7hne -mRdaJcx7BPUvyvwLFAhozJTIYVtcn7yC5s6dHPN6VW+XVqrEbEIAgbkenlv5ArTt -ypxRpD7Pw0E7e2HW7aJiqjAUxXP5EcFytpUA/vk4j+TIgjOP0RUl3Qor20gHHct7 -cBPjlRvif4PXo84ooBFaDYrdP4RJOn63Zdo/S5eWIg1Ee0vfZrG14JqUWBXSBqt+ -gaWbiY7nZbMBUAq4NjUyNGOsKBo+kgwBuYu3+Xkareafzd8kYM+nkD/MykdEYXtO -6XkNMEuT2EdJrAjuoN5uMxaMdhr4q4Ufg8fpQCL3HXzBOKOwvrxWPcSVeFdw8Ls5 -A+p8H5RfAMZALhmvWNQoXJJyx/d6LUjROuceyFe05wcXAiOfYT6rHSFNQlua7CKB -VKmod73uNNnotPkW7rbe0/JEqs66WHnTTPF+YDS36E/dg4ogkxrYiMd+IaVA3p59 -3iHH/2+zKsZqv/PhShloLbrRxqOWdezcpTBuiBNF+ekFmCv1eB15XdUAmrT4EKFk -irclBRNmI1FMDbqo8ksZ3vsun9G+ZCmg5VFtA6YlPUCP/Ht48LaMAUewJV3AMnHP -vEoBdDnxUSMj0Z3EnMEYNysoX/tO5OIRC1e6LM7X5Qq8cRkFGFnwIQWHAv6ng87w -eJ/cSL8sXWdierm+r0lyR1KrEQChh6T924PrpZQ5cP92anbI0vjS1GG2Se752zNb -YgBYpSYtquU80Rtf0YqB4KRzUTWqt8gFVglOYIp21D/801RNa5SM9a5QSeRoxVi7 -Vd0HolmXpD3rJ6zt9hAaKn7ZP0Mon5Kt5wLA1rq/JdIPFOCxkdgBeWgWQTWMDT6n -f5BIKGJOXX6pMmskeNp5/JU1gnBX1u3Mbc9QMArid2L1mJ/uhCImZqLLu3ozPoId -ZC74yEfPr98uDcqH3LylCECghZMghXCZQ+CA8yvamwFci1lFin4g0XfIvHgu2WKz -1JALBgYH+FIP1XAMKmph3L1gqvW/DlsN1R+LcT57RFTPQb5ybExPBx7tlhn8a4SS -ioUh4N8eYwSiSoMa+AXX5BFSypKju7Vu0o1mPAKYH7ono/AYwnSJF6hupmBo+QG7 -6L9p9TuSWo47wNln8DS5yKdsfhpeKLHA8CBPox8LEL6+F5uiNFCwcDu+spZf7I21 -mHnKcACSXdF6G7vW3JVl7kGNh+NXsAn2HnDj2vPtwks68dmPvVZ1YaLq7RGFAO/a -JnXdAzPCFzAEQFw07ESyj9YHt5XM+DKgB0xB38tqeK8/JQF1/GNZ2vAnZTZzk+a0 -wKkLgJE4KNXICEn4MpbEL8qmRpOmaNeqCSzpEOzpfJ0z9dkOrpqmpuXqoZ98eYNL -Ssz4palikny+g/Nrg07O3+CNzm/Rtkw1eBQ8cm+PDosV/kiXydWfpctod4nsKR5K -aaQHhqTaFhC0HZzhwc79b2w8yJEGhIn05JUwC/YGDnqdlw+7N9Sjkt0C6kI/tA9S -ubedlrYhSfr421bCXFCdYUkcdiCwZ5AlZr+IXBxzBGZQT/RMkWOByQ0LGpUJUT3h -qr9wyDnN45rg7tGoD/llaX5JEN4bnNfTKwDAjhhz+ia08ghnSLeiF8u0/VgGWgUS -G7xQD5B7ucr4uq1m+cQZP+xLo3ek3xJ7YLz3WrTOqJckG6DKRT+U2PLFZIw0hPnR -u48Vf5Ob3io9TwckWgp61JB4F0pJO5OK3UHLJBIpNXsP1pQrIffEV3+Z90AowWyo -FsgESc3XygMyVM4Y/9yEEDu2pzPziffEwxC6yCc9Fvac58XwnLrxx2FkKpN0bPvp -wVn/m5E0/9KpbY3+6V0YqjdfM/WNIYsRP2U5bjFJznr8iwG1aWqd3sEzGxm4tbGw -6mmM1yLKzeRfJo7pRCRPRbDQ+yesJANWGKTrlfOXhrsGOmtHh9/PJPH6WtWz4u8s -sE/sgVQdWt7ppZFpdJL71NvXBKYwFhuAFB+DLhQ/quDrp//1et94+7BklkRQlCXl -8anZHeGmgBHll8pkfGKwEIFfnT7yjo1OJ3n5oIvw4GoDkiw8qx1l4wLuEde+b2IE -TsSsWYAtSK+Mu6/Dz+uBerddWsdnUBADhBQvI9puTvYDHhosczsX3FxP+d1kt3Tx -3fE4Y2vWPYhTImfVoR8TEdj5CtXwNMCed57+b3oQSk78g2a7/y1ZmjuS5VgwxwtQ -KxHbV0vpiKOfAl2xbh5ghJ1n4VHrcaSkgnQzrUQ/QSbeCRwaxtYC/Mb3ErGOje0t -9wkQG6tAgYhJX6nRCKalqEuRb6QU47oi6hyvZhNGCN4FvW6/3YGlEuAoLemB7ov9 -k8q8O4vrbD2/XiyUX2Ej3v3jgvOyBo1urOzjwPE3Q9y2UqR/0EsvErr4Y/dMWvDM -6x7DEaDgiqnXJRgpIdGtMjgQpl3bf+2IfWnAmYcPk1H6PHBm4SiYrMbGX/y6vFZD -k2dcN+JvVSM+nwlyHljBeEXVv13O9M5I2ZsopW8V82LA/80NM5hWrtM/+xlycecZ -KhcS1UjD8wSJ+Z+cFIKFMH1fGT2wrsk3zoklYR7EY3hidYYdbcyHogDf+fmEIGfo -2IUooBVJ9GWIKzUyAwRxe8Vu5PorLwTUlo8r+eQS7rD/Xip7JYm6o9947mjQs/5v -DO+FKhGvS3CnlaoU09i6hucH+mB49i/ltlNbfyew30guWGqkTnnj2ts9ABM7X1on -WngKySxxXBx0/HnmEFymCX0DZ+NGPPKQEJGHD/zv306ScxmdjfKfmjJpct7K3Pgu -1JqZAjVuyBeLn6j7egU7zqNRYJfJKk0gA7IoVtdkul+52evqSx84jGc2HXqV+Nl2 -PnOS7KxoyEtvQfjf46nN+6TXgOHuGJQgVjMeqIDKtQXmlhdoD5euJq5XG/JRkzy7 -NKzDKlWHy35sAolM2i4JzrKX73qZiZyBOMCXxw9R2Sshngts1ZAbm+RObCYBJaR0 -8kmTBEwilpO0ueV7XwqfRpxNscGqsbC2kjI6goaP88LqaVEC+5+drEYjgp1mrraV -ArsdRrMoI3hm6GsV2GaP6XhoQAmCcSH6SD3WLTP5W+FO/IC04S8pgIxUkLTEXs4O -cbCE8TajQPW1s7uaInn2rXZ8RywDl0jCe6D8QSwVShZRVZBZJoyLkARxohOOZ7v1 -NPjgVxsD0r9K1+eZbUiYxKKg0PxQgJXmDTewgG2mxFSKAbba027k7FxgnLEfVDEp -WDewRsJikQa1eGpFR5f8oLGGGZ5ygK1APUICYURK/9Td8lYrckVRkRh5LspzkZ4O -xD+FQBTzneyxk16c7AhS7ao7jY9XuC820UK6KyFMXA0UkajjQExbK1N1ERSMlVF1 -VbmyFxnlPlKTCLRY1nCFyn7fSRq7m7Qucqf/uUmOqki+i0ctVL7bwEdhoCRA6u9u -xFfn5S2n6TzpwlC0Co3pCx13cjEf21lR22foRYmQRsj9RMpbyVQSquDItxDnd5a3 -c/Gwhfc6299OWkIs2Zjq5uRbh3Iq92OE7K1gD4SRNMk9esFbbX4MqlRybEt5qguK -VuDF8IA3ZciV0UdxFbvrsstNtCRioAipuhMKNq9rVlGMPXOB/ZJ/E4oZiBoZvIs7 -QYXLrM8YEW6YA1OIxmyzuITCr4SNuEVUYLUFFOvIIPKukW5c5coZ5Ctu5PZUOELH -bzpcFkqSrnvrev0/gCbEZ3G1AXVVWqYu++ZV5WmjezsML4ciI/6T2xn60Gs2mf7Q -HRudQFrbxB6IikeNzS3QyGsY0EWZbMWmR2WvgVXmO0nhst+p2llf497PibUCrSai -J/2N8WY+i53scM92wy2KOKtirTocwDUMRUQQ5DMBduY3xGs3ZTEgwCRMqH/EEYbM -Urvw56KWuC18kCg72xK4ttJTVr3x9qksQ7KhrsZC33RZ5+zFpdUaknYOFjFKBFVQ -nRUwvF1oVMQudpMjc6kHxwldCH44GXB6bxaaVBwD0uID4FFd/BQac/9V1gp0ObuI -V7PtaJweWFKXGDHakIMReQC0eXWfBCXPHbbCqAjyCKW1yyK5fLIM8KkA/dUDSKWk -ARM9JqIQboa1L0V4rblqkH5keSmzD0Af26EV4J8d+WQN7KxoW+c7jT1s1L4ejTYK -ncabOoXVojG9nD/M4dPPF+nt0e6tvn1VcxvBp//eR3ZgXZseWyHjRvAXMNb05wkA -QtlMuza3XlVxJuMi9mgrIV8s6hVBMd7qd89aGQgj32AElCyosKDmGfz0fErtaucq -hQ9K0bXTd9ZTDTMuga1nCxUSPhDIv0uP3I/gxCu9W2UszcxReIFl/DQiz2Xfn5ll -yfLUX9oZ19jkF3ARK2bGMrjleZpEmPaUKZgENRdSWqOMnkdflH8FBrPR0E0f0SZT -SD9h/1p81zDDTEzvN97XvYwRSJ0Z5SFOTqPbPCyeuNE412KDAEcDBuw0hxml5uwr -NwcLa5zrWyRKH2xrZY2QSXeB2hYGNvkRp/4bXEFkfrJF1W9TpW4Vmg/tSxTdNTIa -RTgfMAA59LSz1wLB+7FPODGc7Be7mEwZOJ+Oi/jHK2flyHAkyV3lB8G6shGG9dBX -/8Rm9THJjPoYYjqGqsNZVXNjS7M3fD7ZUyRd0mFRH2OKgIQgYDlHUJpRDTXQYF63 -9lu1OsJsPOXXHLXhHS0mwKDZI4+d+ktXivV9MYeGJOTyi/cRqatvtwhNgu23ESXl -gGPj+W7K8suwjCq4F6DYIPxIi3yQut82OoKbL+9P4f+HYq9o+2Sp543eG7Uu9hOA -Rx+GYpC1JoKIuwzPgnnfUtsZOt2mp8SazRuGmgih2zGxWYyfccVe8BG4Wwqo/nTx -a/pzQtxsJvkbk+2VV+m/QLeg18K9t3E9diMcDqwIBnWHn5h60te4yiw/i16Qmhsw -EpX+6nPLDIFnSKdGmu1W5+92YDn9rBOor0/1qtph+JkqUzndOaItHEEUWxk8yq4Y -VIO8FmsI1c9GVsdUzeQI5hq01s/Vej6Jfs7kI1OgF8jHuPGYj8Pb6zLcJNJEwi4x -hWMefZNWJ4ZnlwR0kf1jfH/ZnwJCJImuwoVaWHUYIjfhLo1rWrMgR18wkTib+S9L -Q+a2v3PHBP4RHfUBNAbEMqu3AB0djz/T54xBVxKU0AqKjSfjMC5SY2WMv/VecquX -uVxiLacGK6Q7y9HR5QLzXKkJVXX9uwywHApG6IOCTGNC+3YZ+P5kcsJDBG+NrnlY -dHJ1pfkyt3X4RXvue6CHCEXrVZCGl2aHk0PKTpsmwXzMXz0gF3sdnM8CFamMcHzw -6iZ/5hhmR7h17ZnsXT28TXZH1bt/9xc9qVo63U0rHPDnN1IndYHk1Bi6nmj76lDt -z5qn15tiBMcY9UBtldlsQzUqD5bqm59HznMDV9kZ8nxQVdRYQ3c7IOiaG9+eQRhu -OtImionEOWQ1jSQBMTBs2NGfM2BbllZJqhLxCmc84xYzXsPhhwlfNOQddq4XdN4g -ez6WPR+TI/zEWZ5XxfirAXE/XQmAChdmFgSEdkoSOGMG9ipAywAZAzc8fPMrZYPP -9MlM2vYGcdQoXJiCkU0U614iS6YMFNU/XvlNBZV2NpB1kPWJZOTblT6f2fnDzgfg -nvHHUbLBNsfZjY5XIGJNSproWFGlKUL0BlqcFZHWajIi9QH+Af3GdWgwyq9nTNkq -9T5+Q7uMqOHvchOctEaTNbsFHeJlSuoFmFe95VHksMQpwUh3Ws0vK07kqeGwK3Z+ -gnOgVsf7JEwJqyZAOIzqNL2Lkl4EzyVy+FDmErBp2C1Fa5ZC3uYyDlSLKC7gnZ0y -+CyVOxN2pq53U0a0M0pfo97OaapGsNWFrQdsP9oiNDdNe7C/wWC+eA9U8A7Lei+c -0yvGPN60N2u97KruONUc8cBVaCYCFNVs+nTWbb/2nlM11hEt/Y4jT4ldmcxH88NV -l0sekigRf7WbNAgZIm3A+yNszJN2mp7Gmn4ObDJyEz5BxpMvmc+8Gs/aMCLl/50B -Sc3jI6zGoUlZ30o6n8mx44r3PxrHsVyBb/1GC52ocOUxpx1GWGges3b6RL13jrDs -n2Rf+sGhawMTyEJIJ5oJFhjK2a+MPcK/h4LUryjeDjwDqiaKoWT8n36tTDZ75I4V -FqkPmHTWt+lJXu7F005m9HVRQwScgXtikWKZSxXj56s6rWXhZE7SN8kt2mmEuV4j -BnkMxeLqmcV6q0tUzxzUPpizeJxuTodegvmvpgaOOz0d0gaPABpcl3wDKtrZuLgB -kFF2ul/MgcoNKz7Ey8RwHc/fwr6ejKZU9xngyqHIA+20CT1myYdGnmgbJ4P8lyI+ -jFoK23QWtijS46yentMLFLA4Oayyz+R8OLYuyJNLxqqD+vNBhj3ScMC0aGsitbu/ -Kvvb/Wc9QQiOglYhWVxgOxHm4Q7+HSMbqLxRauj0ABU/W58wLCCfJ/zGuvsaIiUv -8i8dfqquz3XFar/l6hSJ/FoMZf0dmEi2xO4lWiniiL+pd5BYQUffnUDFtsLwCw9M -bAnN8gTNzlCs6kdYabW6NPWgISL+nIdlC630hfWxYhgYfKLs6rKEPcxbFBsB8Cc7 -+WXkCU4mG6xl42kjXRQ0IKJ6WtXbDCFDfiIYFAB0SwvMF7BTNqoyV3WAnc5cQIUa -l2JUhLcp+JtCSM+yTXvrHq8DgBCTrNyHcswMJrFxCiYIundwmv4n/pIvPS/BYf2r -L3Sp0EUsDwZEvARwnE8GCvNKDq7WstQy9yR4UzSecGk6sGOMwrAmgEMu3eXOruJF -lNqooW9HK4P9YZMd730GB9J/gwSrR/wjKDZIlp0EmwvMI4GbAMxBNfyXAxEZ9jGw -FxxfmRT5ySGx2fJ5fdqnD2PInJNnCRoTuLdx5awDzbHHWm9oDwJLrsAGnkVtcfhv -1/XRhai1Xj2mKPZ2mhIOOZEZj+7pJ04PIpo7Ku/i87BRwudyU+EopyUbzymFBMqi -8j7a6s0SSUPvtRZF8aIUEo47aSvm0Qg59SSiYffRjwhVyI0sHLoRlQZ0XY5JtIy4 -e7/VV2DWmZvyyZ8Jpa1oB37tewRTUZqygkw1eD9sfkCMykhobD1/O0/DBYz4EKsB -7hJbIkDEI/TwfOZJDqRYiHB7ra7fGDSOIyFAhgfnZp9QQPWpHkNaFw/41ogeo+TG -79SoDDSdFXvJ2TwNiM+SVRXDJy3pXtFOF4UY2xmgIe3obtMFgW8/085Z3u+CqjIy -sdoTxgDoU4ycjEnSHbSiuej3xQ9g9579hgVHduu6ICbNCCBrRlopKSHYAZaE4uNK -e/ZWukLk/qnaxVt8VKniVmLVufj865EW4nuzV9/DCt8CMRiaEujBAUF2X4bJwL9Y -k2Bsajn8ocle63hWQsTZaF22f2/E/6QMLSPdbBGzp427OVFejCduD1HPpxGipGfI -y52GsKhrMOxTP9TTqIPykRJLNsd9IKfSvOvi8BRVCncUVR8JiuuWbGWww2RWJ3tF -kor9hFBojY+Q/PxVbcYb3cwueMLJXVG4nMvocjHsjaCqxMscPWZsYizBbOplAV15 -8i25st5UIKR3iWDddwqY+sj9I6XNgJQDKsi/26SAdQKnQQUlzOYOJoM79S+gcxfz -tMkDZHj3nr/LTORkF9bKlGvw0U8Sb9OsgOP2rs2XrmL4wtMC72Vyx27JQEtQE7Ed -5Xlygo46hRVNpo3Tu0A6ewePVTMpks8FqJ/IkwH+KyWfgpGfnd7yQC2cZ+2P8GOo -zs+Ky2J7zTLr5AsCREOfzOv0dOckGfYSyfF4ck/n4D/EEr5xj9cwy7bTNSpO+Vxf -1rs+p+4zew+6a3g9rn6ib7qwsyxok2ZUIwMpYlh2JrnV7KUKvFEbGWmPy5CM6rXk -7dTSAtpu0YAj462f8PV4dhonYmZIpdMcm3hKHefWiTojD5cVP33caTyrvNTbMCEX -IRrSDGYz4TMguYcer8rl5/xk6zVYUAh6e3GPpsI92ftZV0Xyhb2hRJ3sq+lMUowI -/u9LEeVqcgPPoYjlkTqto5n864lBGvqNIvCaFcL3qoRD3JC63Mr1a2U4b8cOa6o3 -DeEOiH7sZQYRg+7fVA1u8dQyjx8V+YI21BK82GlJrf65HtHb/xRdQ/Qhh/g5IyB8 -f6/6SH9uIZInchuIiZVNL5QXTB2ZC5VonUP4QUKiZuoAbpmpN71swIfZBk9Nycwj -p5Xom1ahEIoNCbH2DcXkOEYhQPNa0vXyVVuh95WHpO9eYF2hc7jI9FV0oOnkn6QN -w3v+bAvf2Vz0O0fGxyCyPEm3VaMvsOKBl2GQZaGZCJinkTKE2KDFvamazrLOMYV8 -7idxxeJS1QrYk/ptJ8A5nrS6CpQNXIQZZMPj+36qGokikeMRcl0HE/3DXKARjsPt -nNshgrOKYb+dPyx1m2XvSv/heM8mgt6Ia2cntYXbdLEVhvx1qcE93hsLoe+SJp1n -1eKIjhDL22z0squDZDVyoxBV6LbSLGXBtyvH/2r503Rg8rq6MPPcpUNjP6lAtQsT -K9PjcO3n3k35JfbGf4Gm1Ze8bkWCveciLeSVfMiBsmqtkUkgSFB/e/Wx6Y/z2M8k -nIBbr3Ryt6jSEk6HcpO0RmloKzkeZAkeH4zKEV7rVtGgfKDEcsHbVVfYzNq8NJs4 -8I/ryiuNNkyuClyx9AYN/X2OXeAbqmKlM8XHeq6BzZ2OAwQ9+t7vsYb+SXqdUD0D -+WEOTdHHGx/ixQGAMnDbUJMK/vD8DFoQIhcgsQBxy6j0iXkorIl4s++Rgc4yhgTo -Gl9/Y3VJBlLT00XYVj53/Ma1QioaRlUA6TUiT0T4bT39DMtVO3pp1FBeODzbKcwS -G4jW79p5/LRbgsbeWjyptERn6PD5uZ8zzhrBm9eUyJpqggy0NFGuAr0bkcyRH3rr -m/CdTGosTTmlc8YP3RavaugvimNMvpfrD6xNH2WxZVx5z6yEp3rqCpfM+GlA0afV -dV5hNSp/OTylyfSVMKcYoCXaFODKbcYdZJ9eDk9JpnZp6ATqOYqzfibXCZXUed6E -UIgYq7Es2l64It8mGOMdaXrGA05XixCpZLUI5R/8UxNyQsuPBxtuO15zcqrlczM1 -SyqP4eFiGqhu1LxKKfr2xjl+goVfwdpP9UIwXZVW7DwoaSA4GiwtNc12r4TD6YSr -wg96CH+KRKmd+b8vNoOCcYes26gPCBjv3uTNDP7VdajAyRuuM5a4/ESJbl14isfW -tp0xL3R+Iwko/A+Vrue3B8zynObyaTfsyTALCS37AS4qH5jiqSJEW7iJEDaccLud -1Bfl0SfBQjhle5JfNBLXCKUoMJ3oMlshxrQZ8L/QXK6hdYcS0NxNBqcOOm5kvCro -UgUTu/R7+39vt6XWOMlt+QJaD7AO3jJIqBoRaQh16jsr3h7ixvUnPoMonuNuqleS -V/GcnYMGW8++5u/Lwio1moJV7ILbIgPOp8sYS6l2h2gQ9mzi304gd97NBsFq/whl -CTSDldxe2x5B7ztcfXgrmNzh5ZlqH5Viq5OKYvqA33ISWZoxY4ykzhGnTuClKDxy -nYclSfS1mFxGPOQGMOUQDowNFyt4RKXS1Rqrg00YMPIBC6uP03Wa6xMqcAVj2Sje -JC2kFFet4fmphNovmmPkETTImJvKu86mnB1skgxZJNQ0KF7S3yEOufAniTc4btTd -NbsytyEYsO6FI5TLs8LsjwtD5hC0oB2mynAuJ+m13vx+JeROn8L3RjR1OyR+B8AC -Gg9T+dXwsO+evE9FWwzfuAlYHZhp5fYynOOIyZuYQNxDflc62AndMbUUmGY78fAz -7XjH+D2hCZTL9lc/Tfbr6Y2P6wrSkfw4oz7aTmK/dJmwWfYv4C+/fRYuShlEv2ww -uBfU/3snaZyFC5XqOBgTIo/4UDjRsR37pOKCIQ+zoxyHjOW3yVNJuGWziCgcLWhO -XxjxezWQnfS+npc6ok9ALKc7yRsvtBiRGAhJaEud8CaoAPgBmZO2CSZSkptIkGKQ -AOpvG93+vhRPrM3HhBrSGTl+WOxgM0HYSiH7vYequ4IwhJKmtHcDBpxXNCDr2GgE -06K1Q+33prKOID9vHpsV6qhjYjrpY2glVQRptmsqGyCSCdC69RTGG3fPJTwhxJb0 -BhdCDxIzDFmsk43ZhnfkvEHtfzirdEtgt8YCoeyldEe1+VAFoxYJWxa/icFUKlSz -/OR85N/ELaBaKi6USYyT91tl7MhfTU09Vr4ldu6eDAwXJAQ6cEkxpWqkUrCJ776M -+HAvhxA17GE5gxggx1YjNB6vDMJxXKAovkr/VsRnKnEEFjRh5YUtveyhnOheFZtm -pJFwG2pm2PQ+KD+J8MO098lenqZrJftxiUIV6TiIzcfpnuzF9f2NiDXmom1mAkT6 -RQfMrPebkWc1t6v1AxVkLOZGTLE7wTmM+4tS6KsyIOsrqhLQkIo/wlNlA7RhGZui -rk/8bbh+cmZptW3AJAvNfGjkkg6oObqy3WtrVg2alqXM3m4OALr3NRLvE2amc0jq -dr2nywSJATfi4ce1gD3TGa2qyvF0EPDBxmYyTIYFmTgKyWowNVNiBRw3vuc+3uns -lXo8F3O3cPl5hbKBriCRWwruROTdoBW//Qii6455YBhFhqkJGOrZIz7nwCukACxe -tIFRkZw7bW9P19gi8Hr/BK9PoeK33nWInok2IkJXKMSlcc7V+nTHJOpanFAJNa3H -9tbNu6fgLJdaN2UdXmp/HEt5VHUCBQPW9pgKxr9IE4X11iov7gm4Au1nAhhsIlX2 -zlTOM74JZmYA8zcfQO2Hb2N9HNWBeeJPrNRVKfZA5bl3LjoHuEPNc9s1XY9ClM93 -cUI5+p4qib2JV3lCBZJ0TgXL8eGJy4mLL9FLm3T9IUPddVFOaDiHlONwRdBCexLd -awewqMMpuywISypfULRT6UiG2aeSP48UvqTl/gzGnH+Jt7HpR9oh0F6PlpQ+q/Li -mA87+/PSwdpINjhq2PxM0B5hjfgSePhtHk/lgAD88+En45Wax3AfMLNeRgvbV6uT -nR3az1IouVbySauGApyNkVYrsoqnKRTk0TjBTSNRzAa3yfNPMm92PzQAZyjHC9L/ -YwF3CR9Kqem203qBEI7vIblM7rK/WhRiC67vw8Czw3zlMIcikzW6V+kBzWYfJW3L -qHsbt9gbbipnZo51EnkR1NvuBN9JgiqrG0XeYwfMGXP/3/gc5gI8TebTMGxyN1Il -9dRq600ip/c2KjW3aHB5pXgp5OA3ICS74t5BZDh3kJ/eR3q4+DmpGudH++Q2XR6o -0NHlJj6XGxpvhIsYXMorxaLeY4dVEkh7cLh+EIAkfdHnzhZOVsVWQYLDzn+368Zr -fFxNG1Fcrz74m0SPf7plGhQI4OsmpCfKgbPkibrypPGVpaqd1hHQAbsOgFaIfZum -KxIPKGW98iYEvyK7PN/Y4c8EYpVtc39EwN6XcJ2EJnGmUvI8e6UudDan86rqkS9I -D833R0uqZEtEqa2sfFb6NQ21oFhg7H5rUCnBPoHbd53C8TTvBbCLngEtd7mbPdVI -WpeZsv0npYzIaCqCVVjy0GqAcQm16JEjZWYPgnhVTDAsxhxPLWqmhzGBEXiTPBhP -ITYlEU26fap5b3ET4JMhowd7AlzMOkE6LlwtDnFSY3xUCPskHiCwBqePy720Kn5L -jA0B3HwfHfc/W0MLSvYNIIPURMyZdogEoKe37zSBG0Vo+lGd45iJRclpC7f7ozhy -AAcKet4zJFBfrHQC/Gsb8wIjiwQVNx3wewJqzWpIX3XMGu3MmMy+AmagSfWcVrH3 -sHlGWa/knE9FNG1pWXtwh7WBcgTXmvHvhfBTlUNtQdpsa5q1DdfTPYTJaPOaWlJL -2A+sq5edUUKud7kdzFwBPR028z1idMl1GkSg2fkXAeSVnO6CANdMAArPuJCJIJEz -oRerux1ElGnDhS8XPkw4rxjHqTrWM2lVny+lfjh55C098HY5ExX1m1MH7Nb3WkxL -yuFVFm7+V54w4STT5udWB6JMK0eUlixJg7eZ+0EHmHshorXe06p0lXY+Yrg76AsE -xuUhAPIu6sJ/yvwluXVgNl4uMZxl8io7EBLUPH/bg/IxIYT0yWJ//5dKuEVbQ8mm -QAL8TGhldfAuGPo+LpNBI/GWZXgPkSnbk5pGk95Lb5ODmwTRtEREVgtvrllMXBsV -DEPiM9+A7FF9sKX9FtFzsjVzs1tJTLxX9dRn2nhouliBaVno+F1MjHJVXlAJGCgD -PfgxE/8pNRlvgGdVP8YBOwjUaa3uUFlnwkSEq9VM8d2XimHjKRnFm3ySU6zBW9KO -kH2OcFToAUk/RcQzm5fpkZI+8cJIKxRxSLjBDKdW9WZ8snmDsJzVzVrw5qwqM2Za -ek2Zur6IGLmfKfqgh6bHD4H9jE9si3vPxuMoCmLcOaEvXvcLdvZRamcykSovSnGg -f7OATfBogRW3RQQbTO/api0IIHAJvzEmr1m13EHTQL8gs5ih023tRE96njfUprpf -An2EGzxj7Tdj8pCveTZh0xlNwPwJVychAyD1CU7lnd4/ir0chNc6OSIYsZNXXDaX -Dz287A9UCJmQfRmRWM5Qwsv0AM9vGnhEVFKjJPVXpNGr+hHE/coHjzb3BFc//F5j -Yfn7tbswGdiXScCun/owdWueMn8lYSPaYtXGTzn06d1a5BO8/xD7LdeHvRoBufQN -VBx8J9dd8ZSxetifD4bMQRO2hYEug2VYJRaKAC+FIlhtScguU+Pd9QD1UJri0JRK -nGq0bAeuZmoMOxT3WoP/Dqu2yi94J2f7wdzomQQJB6sqRjKMPOcfHU7CXfD7cBsg -Ephx67SUGzHxiOGSPukaAl/2a3gq78W7LUjPitq4jpDIU9dCVuN9dBmVeZD1LmsS -NTPoKWln3I28WUf57sNlKaEer3xs8yrkYHnYyXvDOk2PkmWgmm9MpdPdzVywRYiE -tWbOz4z4I8jzsp4s2o4mwfx6SZcSypQBGEadGP4dlOBouwYspRjfJ14UIzchOiM8 -KB17KEriRBBhSc3vDDhuGcsXVekJsmNqHbfQRJgM7HDYZZTxy9SVYIpNKCUMjoe7 -IN6+tFoQw+CHayBzVEa3yC3mWnYN/AAlz4bq6bmb9T4ovwCKlD7WdyixGewGzBmI -FQ6ICt4pBl4SZ43vFf5NT9CQr2FLjJZPo8DxIpk39zn1bmfnOqo1IB1K5chFWESH -xXL6uVGgLT+7Vw/rx88XfP9f2sJtGt7DJhWJgY6HQEdqvS2sicr8wGFjd0IUEtV+ -nETc7TNqDaGmnGIgWesPCWcq9TvbueupXEstTmx0YlmrwsEudPuHSJse4ELleUCf -F78tZnwc+vbaTbR8Yx421DVpIgjyL1YCKW/Ng4EL9gXIAZ2NMOovoMxLqIiChSjg -l1nE5HfR2eSE8shOKhPX4uiwowWTqVnR92/4OAQKa+Jj4xw0bcSQyH+pKoeN0lVv -Q5J4lB5rEwQqspximTrtrjfkcSXXMxcKWCUePmamaRkhmPs+I84EYTBnJrMtdihz -x7W28Zp3giWMigXKlcQC4k2QWh+AIvCu0WQU90u1PRngmqagnnwkmhXmDw3XS65L -slPXPtt/ugfIfuZ2RhPcd/D7/jnEGlHXjqGQXoZ9IlzhL5iYL96Q4tzfp0wt8238 -V72gmeMyXcZ3/a5Sa5N65nNjc6Pdu243nv8zWTGgpBgROc0KZochsEYTzmDSXmWD -H433k6oOW8uotZbaP9j8W0kHAUMFiW+MvX5mt1rW/aXrFXbE4NiI9kWl0qAAtON4 -aaPTKzF8W3by/B8Sgrs5aMVldYkDihx6z/BfTR8Kb91AkN8yA+7Rz4ZqnUtPYcXw -qqhGiO+uOeOJVdrYUCDLKM+t4fU5mXq30j1g+IhL7OGKuwH/e7EzQpTK4i9XDmlw -yHVHFJLF1Ob5a7Mcmp2JcmAD2e09aeEP9XixUE9DKp22zMq5uG/Baolccbx3/o5t -wafvQ7Q523cJczmsRVFbnPX4W1YGCCc743HO6C681daMLvqnYaf/tpb5zAQr+wr0 -OUG/nVz6KNaYood4WoegZ8Cl7OGL1exm0BDqkMmaBjonM0fATnFmIgtodKjMSNvo -REHusmMSSsWg2mLDN7bMHuYnvFNtbsAaLUbxQQxb95DXX8HkBuYjNDnUO3ZIhxA+ -SmEap4GFjjD0IP4x1N6EJi8eW+vlG9dVdyfFCJpdkpqGmXLGRGCKIo4X9CzZbbSV -jaHl/NPHiuymRX9PCfBnFjux9ZrQP9gBgG2z/UYDYQ1Di/QNA3nFIYZdJRRh26HH -5E0wHBOh+ETSMJroskDIGLZkp13WjmKmvMXgc8ZYQt0qcyeRdB89xO9RpmMc8dMH -bYM5SgEwuSi3GDhJXyiNveQLPCRGEY+p+iqonxsx35f2erQ2kOFjrCtmSkPsy60L -GXSrWO3XJ5eJG0lWwjE66/XShwWGk1cGTsswDALVBBTu6+lB4CW5YhOUjECDca1y -iHrdV8hU0hLt25ddklUPg+f3FCTs6EJas6Xm0Cz1gmgkmyth5MiYfvc3mKhuGrNs -qZxUb8dgfyUt1Vv1O6LLV8DVy4FnNdKzL0PtrTyGfuNlM/ajh1beT7y/FOvEXvdf -Uc80JaTeqAJ2P9OZAaLzE+ST5y8C+a3yvnCNjxKkHKVpxuyV0Mj4ghMGpTIQDomb -7r0S0UsEFqvDfHHJW3q4R3CuERrPFz4rdXNUEV+8S+B3tu9yzNrlY0qm7fdo4xwc -h+1d0oFkc8BzavGyC2KGxmWKepqnB+ld8210IKjiiuKtsnKHp1FMm0bNNSZn8KcZ -/BjqbLk8pMJNTwf9CfT8eiBwjlQDrO/iU0lojAIA5q2eJWuOoq6yaSXxPW9Y7rHZ -fkZCdeHsYjM+O6CQUZ+btf4xsbajc/FPc7vRlCr6s/bFbRodX/oNkw/z77SiEQat -CCvy0vwZQBueZob8+J/qnLEzv7Y/UsP5zpATNACNG0L3VU2pibDGl6LxSa5Hakic -3NvAu1c7wHWuQaMSpN74qx6aE0nDhKovi3xPhdy+StYGAobA0Qe3qSsHUghxLJRp -adwbhwve3C2lXC8sJ8PbBSErLeYx0xS5w668zsTVEZSgwFhpfY9vQIglakZsEcXY -/YzMIqUkIUfRqkgjhVVZ5MHvo25R+ehK8B611zOL+Wc/9c/PK2kE/w3wJFqllylO -RzSsUHSLAJorWCaS1cYKgecU8ZEYeIIJEEQwv8JNmvHRWaB09hCxPLRYxj/wzWVQ -uQ8suzM7wiHvukjyeHlK0fHuv7KkkdDK3ZQM9A+Hph/VjgSRpJ5BXzGooNoyGSxu -iEpkU3n0xnnRTGntqcoo9w6Mz0WV6S8CRTpa6Us8FWF/P4R9bRw4FJN/z5/o2g8M -4wvffvqIbENU9lVFahiJvAP3OOy+XmlQDmX8Wxx1O11c/idx6fHHTc3UJDA49qb2 -4pfoQA7uK97QjGa+jV+a6ceLr2Mv1P4I94PNaD0T8XNasT8wQw577w1NvUFpnITI -KQjFT5Dh9DG8mmwvvlJrb77nUudvTVOE9GaFWDkg1bzbAhj8OKWIjLKJ2yYSbxJE -vIfXY8lVFHDP1+v2B3PLuBLppDmnL7hIZKnQNbwV5ROAhvXMSraneAHgvw9Wujfv -cheh58gDbuqEQiwdwS/rchjc3USXdEnDE/tA7VAu1XWm1xdLzt0QuLN6iZDTsJGp -LZQIG4eBNeTb7hBGCdsOmuGWuDdu35QWBoOBIE84oCMr1SALljNibMl89+/USKF2 -m8lSFmwOjhrmtBBvR0oHq+ouS8l62O94ClzzhYD2hBamX+VlLQ7umVMsCnNBqqTB -PHlW3V0QWJcimPhTL9noHdK95ysDbJ0MiCY3/DSjsXSteu84w5FsoCJSIQgJuBXY -mFQV11UzDpoQSAyFTofvZstz2D8MSNuQioK6VhavV4AWabshdyjAoKiXORyqJQ8N -DqSjfDh8xx0TOzuNmcTyGWrQPiSnIjN0Xb6lOWX5rZxMMDZL4Ysx/K5A1XPZSuj7 -nhNgZn13Mv/A+3LrwKblzTMs14MTHtxVaQuJo3CRdov/j+ZhR9BQ/44IDPiQ2IWS -mbWhMn0aHqXDagKuXj1+ZItP2l2heKVzdAhpjB5BjLOeUZe2A3WRAZalIBLcCMi4 -Ki528rMLTS631wX/q3UGK9VsfF0jvtK14AUn/CZc9wIeBwgSPA3zMDdFIu81rv6C -bfzjBGPqWaL5FXs8tXawzrpf+UcAGtIk4jDsX0b6jBGPDEMnmB9hUM6HF6Z5Kpz+ -SuMZuW+F2phTDF9urdVVbPkU1QpGJon2xyyCsy/I9R7mgFMkquSMApAktIA6LufO -VJ83zTT2t0UIIcESjN8te7waCDPk1STOUE5NjocecMgqypS06swh9AqELrnC+rGn -NMIyJQJ9isj85xPFOcvgQQTHyK2NcnvxFLQbs/EIu5qb7veKHRpytarlhH6pQJ4g -PeMm1CkfTc2fJilM9xH2CxGIDHaIgAKOWwBUG2k9ibLmdUcxOF8m7PLRjX34I+K8 -ZxW+DoBmaqz9ATtTpHT1+2JXum0kr/e+HprwMPoVu6YnpBlX+Ztz5WxiozzbnHYS -kjkz73yZTMJl9anPppZKLbW89xMi+0qHeZElX9Ik8miFXXAzf4lbXyWzbDKKLu77 -rYBPqQM3EOIbKnzkoPNfZDBVZ98PA12jf1bUJdZ5wZGJbJqv0iu0Mq+pLcx7lQSU -EECH7XMh50IjJiHaD4O6ZGzy3NXGLFH4Egu5z2HhZ3YNKm8buI1LGzZRwAS2q6ID -HMfO19xu+G2ECAwykZJjX9hid4jvm/2T9coOUJOVOYvYMHAjj0jr04yLwpMxi6h+ -v5XnxnS+ZRqHAt2+ZVUpXoKIz0Wi7rjsXHZEG4s+6XcQ+brYyH+ar3d9gJOsHRtG -MzC4N2FmoglRzv9sl0wJXoXk+9DW8L/GZOOnMKeyYqnOQaxeQWdz8IwWOyfkTDF2 -TBdld32cAcSL+3g1vkqf80CY5fwwyn7UBfBUlEmSdYUbagWCGwPojoZDSM6wRc/4 -9iRhAhJrI7ceC3xP/I51dbcKC93CXkUsMQgm0TD9WMe/MrekMXGO2hty+EmABu6Q -P+yNc/Kg5plYys6/4DToaJEtb+9lAYt8U7+chWGPzX0c+LrXGl4gIa2pH86t95Dl -Yg3bb+MZBoJSx1bubJg+o5E3BkL40S/fAkj6c2uWPgCdl3r5BRCx1ucpBt0L7X2D -/l6T3GJAxPypfc4TzBOOQqOCDujGOV5ODMj1vMgngzz7owxpOiGCTjiHCvy49kqE -IqgNCgdBxm6ouv9UyqJKrMQrLiyUG1ZZknZxjWnvv9ISJ4AjuhkypSbY3v+ngPOK -hwivM16i4BPI2dfzEb0PIb7g2Y9jcOzteqjm5n3oypdyR+zpDT+hvqA3BPi25W0B -JPYxtbm4M1TPfEmgrkNbchX/D0U91Stwyv+qf4JqYYdaQXNdd449kc+NEnwTYsrq -imyaZXGkE+l6ED8peKJutbb1ccZHoZh+/itLOVb5jLrfCXLeDI2LUxittjCamfW5 -lt+O642jvKoWfacQoGHaq/AIPlwNqftmR49MtYZZMsDzfB+T4+2WoI60nL+OmMcu -GL3mI8jrE/W3gbgmLujiGP/0Ma1zJd1rqZufxTlCa61cMnpkieSrmehFshtQ2ONG -nsHziIMfVHv/ubGOxOvWWA6ESxhyq4Bb7YE6fnyfk4YwwpVD/QDv/+P9eOklQa1I -cQRQmNo/vwzwS1nfA0mc3wtdW3m0qIjV/PaogQuODlY1TLbydqB4H+lhbwXvhHZ5 -60YjPDLerHojlSKgOWBz35r7fbZqJOCKnTC6LE/2BzjB7GewxnTJsjWRJmkLaHmF -i6BmBm4m78KsKEJZgToH/UJ++X5fhUQ+SG+hz+h0i7xxyC/cnU/PigQ3vZ/SUkN6 -7zg/hdWRcuGmho0aVNUfw1w5Wdd1RwXdUYbYfG8RWeYIqQ6OWqhjLOK/B+Yy3r/n -JNwvRqtuUZFoPNH2FzMv2pdxZm5CvcOuJOMBcvVpgxktn57SwIk367E1srFwQw/j -VhTvV5MqNhAZpXfPbkZ0rQ== +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 `pragma protect end_protected //pragma protect end @@ -1142,48 +1130,48 @@ VhTvV5MqNhAZpXfPbkZ0rQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -RwZLaWoAKLBm11tcUo3zg7WK2hPcNJvetUS0HcngH1N+uqVkxItkonJwS2nHozet -PZ4e0pcL7oMHU+YSSKFGF0HZtDLJ6ggz9Tjk65W4OruIfJxIuyYdw9nbusKhaJTz -khXz5VPO6s2gfnVif+az5zjoe7kudgxlxU7jmvaX9sbur5cFMS2KnJogDMLJcl1s -ZlLL+9F5h5+8PKCF6eoiFm6TtkD7MrBiDjMDu9eLqZ5t8VgWYRMKduwEQ9J2M3t/ -JcbjL7GG+1h3LkL6WEKxF8zVIpKiu3k7UC98wKI8mhEpZ8bChW07nVCr4PHLn2IX -BU9Qy5kOLqe8sKbl6LYs7g== +gQ+VauIuH+g40FNOpVzoPSXPaSSXzZWh6rE+e4zt/Higof5lTVqndEO2y+vyS/HT +Uz3/xsHmLa5/hfJOzrQ2WAbWJcFOc0pzmbDqYnUgEw1W4IUS1qcjifpXTLdxvwfy +rSWd00QRecQN7v+pyLFb6xf5TELzzsB2PAr6/xlRVs03sGcC8jpFMP1gppLRrh+C +xnDjMIBVdGmu01tJ1gcEY/913addbws7HLgMcMDLft0U/4zTbjE/rrDoC7+eO+3k +z9ZPUNkRvEPxurfsVZfIuglJuZJSqyaB+Khmc5Q1nMDb9IswcttQUM3RtjEksR13 +Y4OcKLh/ejWsVorB6JLJeA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1312 ) `pragma protect data_block -p0bIW99zYvQA4u0XRWnQ90s6MugNpXe6l31pFNyBhuxQU67mS/BBRtYtc25nySM/ -yHwfDVEt2eeSh2xZ2Kv1d8VWucKTg8lXrK+ooXsXcYiy61IB12mnjuKPa/FUxFS4 -JM2AiESAcF0ks9YGnHz5atWTSPAnEYKTqIrZDoYqJkbgClLiRdrZY+N2hC5jdZeW -cR1EkHw0PZqw6S2eCHL5hUi6ryPKMkre1oH3Xdag2DJT8qQxbuNqhhrm/L+8L8lX -f5F3asZ05yCB1pnJRqVPESYDajoN8u1lWD18RYsWX60ld2PcwCxsHkPOyoBvAV1u -PgCYq2l6s5FitBJR9RvIIWQXgYcJnkvvctXAE4sHkA/8YmzJKAUlmADFxObHh7nH -B9Tr9F5MMMItWtOlRVOB7r7GpKZ4CIu9H0pG8rHeitdTJzb//0sRPwO4Ifpq00gF -PYpm2+uw1qrcWOBG9wrbOEUMiFlt1c1y6CM7W0HiQg/FK+4Y4JiB7uaAlzUejTOI -zOL6no+QbQSWHIEVAYNpQGNcTG+AuFlhiSI5DitSGvW5yCLRLs7Fv5AnqLM6z1Qg -nRTXEKDaR/AFlAFB16izDRH4FYwpXtH01JTfdxvrFbPDjE2B07qlVwewnCVApXy1 -GNPPzEat9SO3vQ9t7PCKFzQV6OGGAn/dyMwguU6EDW8mcNxemcFiHUdiSfhhZpeH -IcnqAMISo7J5oznEHRV6eZ2t27p8fCR6kY+/9tdw+mhgfM47E9D+jOa2LZcvRNK0 -IxKxNWtgUL0KlYtkFTGEhG+p36IePpoZOlbFukyAkrvx2uvJdjDKNhR7fljgKZp9 -ntpSnYfXJhwQrP8yTvoXUhnLpaxBTrh8cyLUFVm+2UtqRrz/+WA/Du8u19N0NmoU -4Z65V0tXF/tW4DpeElKcg5Z9g3Srjon+LpuobgvaptlZ3rG7pXXklUAdxNfJ+4mu -g8S64RYvfLamt1za0XyFbePfAbEPHUNKbKIqzGRB92kxJ6jYjgC9RQHp35SL3T55 -2DhArYHiRs4HAieVOggerJ2mFKRe1jgXpNH28cIvReVtjhPSR0h2/N1kktJoFN9j -pAwsBXcE20H2DgeDq7MOl5klQOQIZqq2NOi/TtiDykzXOq9c52KT5YQDUiFYqQvD -H29baw+SyQUZTso78q8DVb5S1dB3XyHStAKgoGq93+Wz/B1RLpKYack4xd4rdS5s -pwx6XbBMdp7aDqOyz2KgKWf+dspEnt1aZSkLPUfnK1QqEuwBFSip0++f8lsYJwt6 -h2RR9rfNZmd8nt+mXhbGkKeiOagijsA/5zVB+4MgI0KR9sujHhdd3ikiYUTRDpcb -AA7w3mFn6w2oiAcHGimR/cBGrmo7m6L0USsPGqFYBLIQfdAn5dEBlb2BCoA5VFZj -jXKJF/jua7Y+DrPzh66goMGjpF9lBpoEP1rWQA/7bSpIp6mTsXcqppKrJq4X3UzK -fnxoXMOzyXak8Q0RLDFj9NSgAWzr4VmwVpFWnocoXpsQlisCkXdTJvGnor8LLZr9 -sDZmzgcSix39SaRGPrUkPl4jLdocSaImMFvFf75Ln2LkiFK2PwLHbdxu5OHmQoCw -7wBcsGkL2gXd3tYL2ns54yYSqMYHrxBbag+ndd5VaJnjZK34JNDCSh65qkKE7y7v -Behj6SqW7qWtdmufzd16RndX/9C4+tnd6CZRltVVSxqHORQEFpJfBX3qZLp11vTQ -Pib5SMqM0nVbJDVpqDeCAA== +fo0JdXfIQsWgrENhFGo0RRW9s/IV4eGBK5upzSxFjRkxTj+wCit1QKkd15jJgDu4 +P06Rnw+P2/Cu/tkXRjH7RGfSCa1EZ08cwLiSykEmyb+qQo8wTkOBh8KIag5m0P1t +XTuNeK4lZP50EUwL/4wSSMPuRtdpIAF+0PAXjdoge2gwhduxtVQZpgPO12dwk0Wo +Qyfuxrm/7iyjiETt18QCBk/PXC9JLX6a9hmtr8ujb+7IKQJFj1S7F9WxCZ1yamDs +e1D+l34aYZ5r3sBbAysWrg65oN3fAAd6bhptfeU2+BDBA8oKIcTClBK2f3pBUPul +8YV5xUU0+FGat/Rjkm2ZmKKpm9JD+w7ufesbJ2fqRCCex08yynx+EuV6lNupQQk3 +UbxIK2+04eVmLtY7V87103cxyVnLFXqAQY3XaG0AWBpO2Ew1NwH6CU4yFpyUAC84 +Bjztc1mHKONeueopzONq61tRDqarI0ex6IhDy04D9/zAOhMyBrEHzeR0UozXtK6Y +TB/qqFBgJmagIMQWcL03s2FYWQgGUU3PRQ4JiB57ubJG6H64M9UJUMXI7VXW245F +S0oLuBSWchTwY4/6zvioNieoCZgdkxOTUqHNuV4Zf7Epcgh3IQIZRzjBSpah3skn +kQwLdkHYbh3EzBAN0L4lF8u4LE/8SqwLPpsl91D8Qck2jzgNTYnbsG+t2tsum6n8 +wYvw9H2G6SCXAimDrg2Qy66lpdDA8XQf+1Pu8sYKlEd3GH9lQyGX+l4gx3OLuOtR +fAlYbOhHnFRDXMNE9ZG/I8VKDFToJD1/SjoKUnrz4TdMcQZn3Asrj6LyXsw5CHgd +zhf60BREHK5nXIJRGkqTlV0OyCbaEe0yTgmpWapYbnUcpX4UNu07ijUdSbUBReil +f2PULQwchd1Nh+nj49FyRm0SU4twHeYIMoSC2sMtPiJkuqAZPugzpBpKZUPnKzDd +VmHxPV5Fl4haVbGLfQj4rfl6Mqpqk2DLOiPmwiXnf7CTAjpnwNQ07KsBw6SKxLAe +YS+1RZFe1JQTA73Dv+hAjOEby2uC1tz9V61abAakI4omdhXK1WBGS7AW7VIkOhsa +U2d43C1vqygKdJzTQVB3SVqswMzruIiClRGEypfl8F1L7BIegRA7y6KJYY2lQ69u +7eDX8XmDYmXDiWgXqtWRALbhHrDi8EwOCp5Tts6KK1q+HZNB6UjiGUrGZ2/EhU4H +rNhfbS8YD9wTQtEs/QCi40wIeLIYjIf429BBIRU8k3na6ZwzGLdfxJnqsRLJ6E7X +aCiJk8iag4Wfv0HsAb9J8vDUKzzLHS5OYlHmEss6CTswBAYs7u8/UF9rlfvXy8Mb +z5tfh7xCXqOQpY1gF85w0agvdFKLhhUzfB2Y/XiH+P9zw8608Q4B2irkUuj0fbhU +/VGCOg52ghhNNkaio6JDtzCj/4nMf3QJwdYnJNTiSWLmN/D4rgU8FE7RObm2foEA +5qemSiCt9nYnRGtaRQ0jFh1zieourorN3TI49Lfh/b++M/Hq8OUZh7Uxs5ni4scB +RqEGxATE+29gCCCJ1S3HVi7fcit9xh2mupZnT+m3qHM+Jt01sv59AUJ/UFx/cNYz +qo1oB/NkzOstxVDMlcp8bOO+elF1X4n4wKeC0g/eMM8C+ffQiVT7Rqh2mYLgXQA7 +BhBS+E0RB6UhkxYPnRFEgtk0VLL54VPEVDTINYlLs+L3ZsWwYJs39Gen6vvvepYy +bujDTnnouQqtvD9ok3pkbA== `pragma protect end_protected //pragma protect end @@ -1196,45 +1184,45 @@ Pib5SMqM0nVbJDVpqDeCAA== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -V7fazAcYfn/upNWI2MrDSQamEge7Y8sqGyEbHWTTDvIkXpdIuRisL8LJjvy83vue -ZgYLruqRxsDQR/Wu7PMlj65sb/NkxpSPTHfwdQcOEP3MsixExszjuA1HqHtg+aNQ -uFOiuMhxVPj6PMHq/Hqrqa85QcEVSbWPuLxSaFzY0ndkgyErZck8cU+0bbs6pFmr -tNIeglsOu6Am3uxBT62KHdsx5/dbyBFUXzyoeMcVqVN/dSwFJEWKXykd+OnIo8cg -TAWc+EOAJ6ExmKO/aLU8Un5EpThP6h/F+4FSrXQ8+zAfJHLLmWelIILCIn9r270y -7CUxtRRDMVrzxeZaHx87Jw== +TpRHXtmr81JyoWaAtQOsoLu44jF5UvFDPdO5/CllOd3kdY7PwU2fkKx7bS6RlGe6 +282Wvc58pPBGh6uImNRfZkaAKTaspN+giuR1GHAo4nfIKi92dgY2DTW5JbEU67ml +1IGNiK4su606fm7n90PZ69MZadoZPNpUxZxzYbSs+I39eZWsgU+rtoUE2d35qjdW +UyorSD+O2F5Wv51CWlcWJyscNK886BFGFi72CtEY8IdYcolZ7hcONOhQT5jbhGWK +UFFTqjnMO6iVrEodujVvUgcUtFQSTl5/oHSkmacP7CSADA82+06uIHf+rByqHGTp +JNgtSAVN844IRP39n4T5EA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1200 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -1247,62 +1235,62 @@ AvKxciqIeVCjtaleTRBLEWnwUKa6wADHB0WNBFNEidDe8gAcwWkZyKkh/VaUiupU `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -idlb0ipwgIc0hiUfW9lCBvIc27j+O1T55dJ3BL9eUyC3AmELfvx2LyGUfXvUfYTf -8sHVL37lgxYwkxIH4ZSSZQ1GK2zLKlNHYUEmXZIR/WoNIg7U3rYo+/OAX5LDNWz3 -I3htHfdktV9gYc7iVdI9VNrqBa0Gg55NmIOrO+wM2ME4dVbdMJVDfW+oOu9rTeme -KOonn0oR5/zNCWcqkhf2z6BLLm49S0wwKQJc9Tn8j8aAVVAS5PR4HM/UAt+Pm5Qw -qUaeukXs5OImR86WKmCfOXrROtxYmBZ//zwyzxGdjene5Dzf1Lue74V7vg9Yy8Es -kofIx1Iiwvl5uhKqK0ZywQ== +TBCX5/gAT5S6xdVBuY05hYDsXmHLnm/0Yl4d4ayUlKrDe3IUWB3JcRtZJEwtIwhQ +wqO6qIYs21XvVt74eCxdt1SZXHRXXJiT196fD9q5vFrJxAQqeTDvH51bmshhKW+i +DwXpMTwZlLgBsT2BEP5C0RiiICy9chJTycHB7vHEh6lTXT6S/2H7bweTMlFCh6s6 +n5aHgBbfjk9BYIUSTuEvOxw9Yki0T44zjqGmjZ3qxkhk5Rae8iPLqCnjRTjNfqOE +zQtaoVQW+8NbATVUmZC4WlgxF/J03hq0TLeqLYfcuWR0uH9vLAWsUzHqlGMZvUSV +23zwmB8p0BqUeaj1cllyzw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1984 ) `pragma protect data_block -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 -M6eR/VTYArPQbA4OoPqXhQ== +2OvJlNYOCu/okutbEvWbuQI4X9C4wmVA84hW5XRuqc+R7lDXEYZ89g58fT3Wyd8M +ecpTY/f/5J++NaepFO9rZ71cRzxgXD7ZQypxrBwT8eXz6kwhomKLL8xgQuGMrD2h +002LEC5h770bZFbr2QDl94Kd8oWweGDIcwbbPgGtsgfsrwnZq107rvdgRLsvDJ6H +A9T68XpAsV83OJOA8hk5S1ytXOtMoD1vxUA9NgZ2d9BBiwxnfNC6r2DYa/TpgT+F +8Dlnu2u3Ch2T50E1FvIsU2NsOkKdsN8k6Nmhr7J+mWrK8q1RSElNbQt02yIshAzD +fz1m7maxuzNvKiofs7xTJYH5Zl3jsRgP4i3jUPcFIYQTdju0XGFuzz4tT0y3o98B +wJPQRdZzLdAIRwwOeqCGe94DNj6v4B0lCOW+L2I2xO/Zd85RIWk0KQ11TMBxIioX +lElgvMwoYdOobLmpseg4vchu9jvsSwd1ET14HpSefqoM8cHFSvGA3j0KpwHUHD6N +cAg2z8pkpvWyZBxPOnKrjjHml3gwE3q+X2mtD1ayi41L4xn6E8czI/znMUiRwwcz +u/UG8I65XcONtBswjX1cTAad9X9cP37rq7ly/mnCVaQ1fwdx50rBY6tOiF0jiVR5 +JjSBl4FkBYJu7kHqA7DcluE9ATZ1+D+BIfESxs4o+MIGiPbk2VMeafwTD7GkJFOt +pp85p5WDA/qQLIA+aQsaHfBRLInMjsajsBU1Nnr1Z2FuT4dNgRDU1JiEJoiGBh4S +RZzlhgVKqLQdDiC5KHU60BMuW3u1CxkP6BLofYO1/DTsIOzKRlb9s3+Bx2RBLO+X +LpI1kmPdmyjjLOe9xPxUuWAlk4Ona2bF7SOrCRKslzRwj5WK3kdfynnrqi6fyg/g +6RtRb5T19kv8xkX8Q0Nu2f6aIj9NFg8R8LJhXh6X45cptFvZzqgrDrKouB2qeqzv +r/ARvwCCrLhqU1Rwol3o14E8rmlZcjNTDxMVbtGHIC6f+FQD8Ge6dA7TLtOmbzhg +ADyiBfAGChDV8d6/1Hzt1ZCbp6C5hSA43mtpTQYEjZcGds4olsLWRMFlvn6SaE8U +/yc4f8I5aqNLijlkaO5yVtVndDXvrhyJK63yxQ2hv4wjwsq4K2PDQ4XYvUcmKPD/ +XlPlsS9Ze38WOmF18BNsWhFg/X1ZEsnJQZqQFknQ9z/lHiYTcq+HtWHD6JfZzOaM +E3UA8T88Db5hkBxdi+VdfTfF/tcJB9TVv94cA8SuyNnP6Q6AMPtj4AcaMmUbLwpN +6fOz+eRjs375gUjeGtSoPhbJZ6VvJjLK6xs1mDGS9ROACnxpeDCou3/Z35w98hvB ++vycfefBU/3Oz/FibzGZfGGRZxR88DoezSovO8xS1UTztbTV/E3Hf50BgcR927BL +NJGAapWYDd8JtV0BHG5wpaes7/XmU1ypZarztFE+5fUtgzp4AKZ9d8fLPqu7uHyy +VFSlknUG3lKAvV+aTv5kwTm6T24a0lpxxYWzaadSBxuqeJtU7FNijzCia9l+KD/j +MuWIX01bTZapbrnUlFm4fAAgbW5f3nA4jSdhRz4mKzYdZ4aMWDM8hBS+zHKdAxt+ +r3IOTmKOM53qQd6/AzPhoA0A+KC7CNCPEgYxWjHD9LvdybgmZ3XenDSbtLwQbD6Q +UwWAn1xKUS+VTfDL9VkVXP1CneqLQxZtc1Sc/vBPwSJ6+7jAYG5QfCsFKpYk6KVg +WWBjX/iaBk51jQZ/ISopM3fO5XEr5/3lYtazRsrg0f+S3e4Zzo8nxEOq9P5xVhSQ +O7JVUzPKxB+mq8b8+Trp0jpdlwATuoCmknWv7M7xGQxIxgYlBegfgpZNrb4ocJt1 +C2A5oMK874OASkTuFy/CZtTCSKDyyC2WSUJy/ybgFlZWnTyWBNaSIgYpaI2Gq/5N +W2sAGdn2IzwgLXJcE2TeXPkUP8I6D0EvyGS8UJ8WVt4jXlr/F3VEInfxr2Y6siXk +AHHFHgrTgDIGLtO8E808PqkxvLBmGkuPh75G6ryBOPonCZ0aT1e/GX3dbFPpEaEW +llXDZSgbk2fjRwniN+3OtnrHeVbQUlTC3iaVcpJd1hL8XMqXbPIDInH7Hno0Rp0/ +Voc9LaQvrTj/kEwf26rJMPkHP3A/gue3fawMlgP2mdiTeVrBYqtURRsKaMlxgKT3 +3O7Gyd/yxwB05GETZ6zA/3Z0q4ztIi5TZ5m+C2wW+NIXwkcYJdqHOodrO1fkRlTs +npvFlNq1Br3v3gImbnvFaouFkT+542lb5sOY50i4uwrifKPntqOl0n9+dE1pyipU +QURHoCbkL2QR65H1hYcDoLRvhJAfS/oEFf4DSf8HgiZITq5pSvnYcJn76jC0mNiX +9LRJqxBuOkHcdFIbmkvDuwIN0asrQmGQCAsYOOxVA6EpX0XWcJ8dVmRyWbGVZXNq +45wAMvGDj0F6Jm7b2sQ3quJFDXDWvD7hPWp8nLqRDN+P/s9tHqK5LMXPHFdcqMn4 +hKSmCVgEtnsVfWUGyjVJ0Yvh+jxdg3vECIO38UuFBuTGroD0egvsyd7iuwT3aOmn +5YaYW0vHuHERbtLy6AkO1sVVmg18jSH32tE036uQS+LCrj+G0cg6Mf5sU2CHJZA0 +9Jse9KsUSQdI7bnqvPdYIQ== `pragma protect end_protected //pragma protect end @@ -1315,43 +1303,43 @@ M6eR/VTYArPQbA4OoPqXhQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -kjevziVpR4HNp6ABOs1UfEhnb+dX0JPweI6S3+LX30C9LF3xx7Xd/zMszyIOAsff -hodfZOinnjjXzBncB8lZ/iwEBQcN9AOUuJkxqHw0xEX9lKugu7WOxROcH+yiXxDJ -yy9yDzS1F865ocB3xO9FWkMnml1XZRqox2FTUI5GMVk0MxMQPCoaWPmG40cuqt8H -oNSQWIvbZ0bwp2zXvC4BQlkXD2oWWu6JxxVIVspZ7XmHHSfSB+gK8bmQIk2JZPQd -nB3A0s+SLUanWE/u+Muh6A5t3kkuvJ5Fy1rRHEwle6WO6L5S2arPlksoYEp7hfDo -eW9+LO7WnZdnt0b3dQw5Mw== +eiP/26NloMbfJbEe1aU/cN+AkTVidxKZaNv824TVZXkpjf5L1zEVLf4buBzXwSr1 +MiO1FaB1qgL+ZgKHLwNzc4IiIP0d7qYOaGR46jDr8/k9N2BVxXC3V0wJJ6yhDom9 +O7B9d2Lcm+b0UifdEaFcX3luTwZzXAQW83Bggnm4eVP275Vqog3REHo5wgsstEU3 +AG6o+oVDnNjZTPDPyJ4uHq9bjFFyvY3ga+lOo2iVymecnhCiRtjy3AFtvWBJW0ek +uhj8QvNYf04TXkRXdhdRfq/HDLr3M6Qa7/Xn6vGE+drFyRTL1nmH9wkjBBbD3swn +58tiwvvx3ajgMOCJeXfrXQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1104 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_define.vh b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_define.vh index 9a37056..26709b4 100644 --- a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_define.vh +++ b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_define.vh @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.v b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.v index 2917172..00aa64f 100644 --- a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.v +++ b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.vhd b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.vhd index e5cbfdb..9f59356 100644 --- a/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.vhd +++ b/Ti375C529_devkit/ip/gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.vhd @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +-- Copyright (C) 2013-2025 Efinix Inc. All rights reserved. -- -- This document contains proprietary information which is -- protected by copyright. All rights are reserved. This notice @@ -88,18 +88,18 @@ port ( m_axi_wstrb : out std_logic_vector(11 downto 0); m_axi_wready : in std_logic_vector(2 downto 0); s_axi_wready : out std_logic_vector(0 to 0); - s_axi_awprot : in std_logic_vector(2 downto 0); + s_axi_awprot : in std_logic_vector(3 downto 0); s_axi_awcache : in std_logic_vector(3 downto 0); s_axi_awqos : in std_logic_vector(3 downto 0); s_axi_awuser : in std_logic_vector(2 downto 0); s_axi_arqos : in std_logic_vector(3 downto 0); s_axi_arcache : in std_logic_vector(3 downto 0); - m_axi_awprot : out std_logic_vector(8 downto 0); + m_axi_awprot : out std_logic_vector(11 downto 0); s_axi_arid : in std_logic_vector(7 downto 0); s_axi_arsize : in std_logic_vector(2 downto 0); s_axi_arlen : in std_logic_vector(7 downto 0); s_axi_arburst : in std_logic_vector(1 downto 0); - s_axi_arprot : in std_logic_vector(2 downto 0); + s_axi_arprot : in std_logic_vector(3 downto 0); s_axi_awid : in std_logic_vector(7 downto 0); s_axi_awburst : in std_logic_vector(1 downto 0); s_axi_awlen : in std_logic_vector(7 downto 0); @@ -111,7 +111,7 @@ port ( m_axi_awcache : out std_logic_vector(11 downto 0); m_axi_awqos : out std_logic_vector(11 downto 0); m_axi_awuser : out std_logic_vector(8 downto 0); - m_axi_arprot : out std_logic_vector(8 downto 0); + m_axi_arprot : out std_logic_vector(11 downto 0); m_axi_arburst : out std_logic_vector(5 downto 0); m_axi_arlen : out std_logic_vector(23 downto 0); m_axi_arsize : out std_logic_vector(8 downto 0); diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/component.pickle b/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/component.pickle index 3730a24..70cd9d2 100644 Binary files a/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/component.pickle and b/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/component.pickle differ diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/graph.pickle b/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/graph.pickle index 264dde4..a254b5f 100644 Binary files a/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/graph.pickle and b/Ti375C529_devkit/ip/gAXIS_1to3_switch/ipm/graph.pickle differ diff --git a/Ti375C529_devkit/ip/gAXIS_1to3_switch/settings.json b/Ti375C529_devkit/ip/gAXIS_1to3_switch/settings.json index 9bd53cf..f6219f9 100644 --- a/Ti375C529_devkit/ip/gAXIS_1to3_switch/settings.json +++ b/Ti375C529_devkit/ip/gAXIS_1to3_switch/settings.json @@ -3,29 +3,29 @@ "-o", "gAXIS_1to3_switch", "--base_path", - "ip", + "/home/cslau/Desktop/Workspace/efinity/2025.1.95/project/Example_Ti/ip/EfxSapphireHpSoc_slb/Ti375C529_devkit/ip", "--vlnv", { "vendor": "efinixinc.com", "library": "axi_infra", "name": "efx_axi_interconnect", - "version": "5.6" + "version": "5.4" } ], "conf": { "ARB_MODE": "\"ROUND_ROBIN_1\"", "S_PORTS": "1", "TABLE0_AXI_S0__MIN": "32'd0", - "TABLE0_AXI_S1__MIN": "32'd512", - "TABLE0_AXI_S2__MIN": "32'd285212672", + "TABLE0_AXI_S1__MIN": "32'd16777216", + "TABLE0_AXI_S2__MIN": "32'd17825792", "TABLE0_AXI_S3__MIN": "32'd286261248", "TABLE0_AXI_S4__MIN": "32'd536870912", "TABLE0_AXI_S5__MIN": "32'd805306368", "TABLE0_AXI_S6__MIN": "32'd1073741824", "TABLE0_AXI_S7__MIN": "32'd1090519040", - "TABLE0_AXI_S0__MAX": "32'd9", - "TABLE0_AXI_S1__MAX": "32'd8", - "TABLE0_AXI_S2__MAX": "32'd12", + "TABLE0_AXI_S0__MAX": "32'd24", + "TABLE0_AXI_S1__MAX": "32'd16", + "TABLE0_AXI_S2__MAX": "32'd16", "TABLE0_AXI_S3__MAX": "32'd20", "TABLE0_AXI_S4__MAX": "32'd28", "TABLE0_AXI_S5__MAX": "32'd28", @@ -33,22 +33,64 @@ "TABLE0_AXI_S7__MAX": "32'd20", "DATA_WIDTH": "32", "ADDR_WIDTH": "32", - "M_PORTS": "2", + "M_PORTS": "3", "ID_WIDTH": "8", "USER_WIDTH": "3", - "PROTOCOL": "\"AXI4_LITE\"" + "PROTOCOL": "\"AXI4\"" }, "output": { "external_script_generator": [], - "external_source_source": [], - "external_example_example": [], - "external_testbench_synopsys": [], - "external_testbench_modelsim": [], - "external_testbench_ncsim": [], - "external_testbench_aldec": [], - "external_testbench_testbench": [] + "external_source_source": [ + "gAXIS_1to3_switch/gAXIS_1to3_switch.v", + "gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.vhd", + "gAXIS_1to3_switch/gAXIS_1to3_switch_define.vh", + "gAXIS_1to3_switch/gAXIS_1to3_switch_tmpl.v" + ], + "external_example_example": [ + "gAXIS_1to3_switch/Ti60F225_devkit/axi_interconnect_ed.xml", + "gAXIS_1to3_switch/Ti60F225_devkit/constraints.sdc", + "gAXIS_1to3_switch/Ti60F225_devkit/axi_interconnect_ed.peri.xml", + "gAXIS_1to3_switch/Ti60F225_devkit/efx_crc32.v", + "gAXIS_1to3_switch/Ti60F225_devkit/efx_custom_master_model.v", + "gAXIS_1to3_switch/Ti60F225_devkit/efx_custom_slave_model.v", + "gAXIS_1to3_switch/Ti60F225_devkit/top.v", + "gAXIS_1to3_switch/Ti60F225_devkit/efx_fifo_top.v", + "gAXIS_1to3_switch/Ti60F225_devkit/axi_interconnect.vh", + "gAXIS_1to3_switch/Ti60F225_devkit/gAXIS_1to3_switch.v", + "gAXIS_1to3_switch/Ti60F225_devkit/gAXIS_1to3_switch_define.vh" + ], + "external_testbench_synopsys": [ + "gAXIS_1to3_switch/Testbench/synopsys/gAXIS_1to3_switch.v" + ], + "external_testbench_modelsim": [ + "gAXIS_1to3_switch/Testbench/modelsim/gAXIS_1to3_switch.v" + ], + "external_testbench_ncsim": [ + "gAXIS_1to3_switch/Testbench/ncsim/gAXIS_1to3_switch.v" + ], + "external_testbench_aldec": [ + "gAXIS_1to3_switch/Testbench/aldec/gAXIS_1to3_switch.v" + ], + "external_testbench_testbench": [ + "gAXIS_1to3_switch/Testbench/modelsim.do", + "gAXIS_1to3_switch/Testbench/modelsim.sh", + "gAXIS_1to3_switch/Testbench/xrun.sh", + "gAXIS_1to3_switch/Testbench/axi_interconnect.vh", + "gAXIS_1to3_switch/Testbench/tb.v", + "gAXIS_1to3_switch/Testbench/top.v", + "gAXIS_1to3_switch/Testbench/efx_custom_slave_model.v", + "gAXIS_1to3_switch/Testbench/efx_crc32.v", + "gAXIS_1to3_switch/Testbench/efx_custom_master_model.v", + "gAXIS_1to3_switch/Testbench/efx_fifo_top.ncsim.v", + "gAXIS_1to3_switch/Testbench/efx_fifo_top.vcs.v", + "gAXIS_1to3_switch/Testbench/flist_ncsim", + "gAXIS_1to3_switch/Testbench/flist_modelsim", + "gAXIS_1to3_switch/Testbench/efx_fifo_top.modelsim.v", + "gAXIS_1to3_switch/Testbench/gAXIS_1to3_switch.v", + "gAXIS_1to3_switch/Testbench/gAXIS_1to3_switch_define.vh" + ] }, "ooc_synthesis": {}, - "sw_version": "2026.1.132", - "external_path_option": "RELATIVE_PATH" + "sw_version": "2025.1.95", + "generated_date": "2025-04-14T02:18:17.197392+00:00" } \ No newline at end of file diff --git a/Ti375C529_devkit/ip/gTSE/gTSE.sv b/Ti375C529_devkit/ip/gTSE/gTSE.sv index 7673519..2fda6cd 100644 --- a/Ti375C529_devkit/ip/gTSE/gTSE.sv +++ b/Ti375C529_devkit/ip/gTSE/gTSE.sv @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 7.3 +// Version: 2025.2.288.2.10 +// IP Version: 7.1 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice @@ -43,7 +43,7 @@ // //////////////////////////////////////////////////////////////////////////////// -`define IP_UUID _7bbe2a96a6f546f79c19bc5e36554e32 +`define IP_UUID _d918503884f24604a1574a31e94ed6a1 `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module gTSE @@ -1748,193 +1748,193 @@ endmodule `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -Esl6HEzaqnCPJKqQPIVjcOMr4TKO6MdWH5VyuQ9QFEx7zs01sFCwN2DIi11T4cCi -b8zDU/601o/2cn+q9y8uEvr/HEnU03UF0/2/jQnQu8NNNJbsfi+Tm1SrYvCUaWDj -AC5tqUzvc+5VUbwlBoEsBlhTswODNgcx/QAeZ7ZyksS2LFMcbE6uunc1dm3oi+kw -nAvtXFezEt9X2+YUuzmgWukaKKHqNdlGl6bSfDA1nuf2gGUVbXZscLFIjklA4tCt -Yv7Fog5LlTEEU0iB0Mo46Y4frT8U9INwrsbZPT0+H/PtnHeOljVP7ury3OHEcX/0 -tI+T9y49nbzyZgpYzhA/4g== +ah1CSP63MUmdoRE9KU/7qpW2mCUqZialbS7PMODpI5X3vEXsLaXDCKMwJ5XcKtMy +EIWdxIcdTHeEDiy9eQJ1S6CzeEtgqXJMVgxfPaErAghPwnMjNBMF6NyW3amjI80j +IK4Q0hvXX2CA7yAajPIFtWxKeCSCDkhFmgUTKFi9bnG5aNnMLN+6cIOabVJrl+AJ +hNkBxRJ2vrtVXbudId8+sn3kyglN4GE6ar9iXv81sZ81Y8Tyrcchu7B/uWvEYDjM +p4YgaPR8upa6DcHL7sHcv9zw9Ir/vjdD9/L75EElxWPgzlSMQHARtQ2bvkzdayxb +JmqVlrHqI8XXqzSddy8vAA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 8512 ) `pragma protect data_block -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 -orrorMmgXKr4Ky/fJk84yg== +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 +TofYyNjGyhFCZZt3+S+b6g== `pragma protect end_protected //pragma protect end @@ -1952,24 +1952,24 @@ orrorMmgXKr4Ky/fJk84yg== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -QyQvTNDKBrwc8n0he84UNnN18DYc+cMn/REM/9jdj0dhjYUaE84A1XVSltjSnagh -nswDapHO7r5EksbGzSNBBqmqVqsKQBtOR1cIRjgFVArS75gKfO1cexxbB/hypQfF -RAfU3c07HxsHUmPzPhafu4qQQWqwi0FC+CjlGFj6+JQb3ZoNi+v29qm/94QL3JDD -wkojDqBiFGl4nbf1nPuJ/HP6N2gOY/tsdVS9fK/5l2OSXDnniBPxURAmBIHYRi4W -hVRkhM0aQXw7JAaAnv5RViDeytL7WNsxmaGzMvKnAGFHz1Fe2KjLpl52FVizz1nm -wDdZlhefozxDITAIdGEfOw== +GqF8fCMCqX9cvfEFdHCUoOAphWf+efs4UveHi+vbq3T2X1Zxa6jJmB2i1HhKawNU +6qKVHV5bCrc5Wei/OmnnPkXMuLZIjVaGylQY6COudDNU68V7mYJG9CKXxhzyMUpc +Iy7adLz4sIeQth0v9LoFEipBz7q7UPPzu+YhHXW/QB3PIQx7yvf1ByHMczOaqA5o +QK/SgoYgw1nItbJ3vxlx+pueLJzlXhjQRlf3peFA06PF3XQk3/xVVP72t9SCdHWO +tsNfffCgrxsXaXqV6IUhAwJX8y1yhJUEfCDS9DiEZP3U4bfZcgNJtzQfjaVz073h +zvbvtlNgxOtw1SlR1dT0fw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 432 ) `pragma protect data_block -pWEWvAJSt8c60app70nhEtuc3dwhd+JABoSWN2h8ONnxPUepkyOOM4OGqdNsnLKo -dEdf7BEKm3rwJyCKJnJR8M1mUzZCPVAprq9coCSr7M0JdYFFgprsLqHXMl2X+vt6 -KBEVQFYF9NJsDbonKdYce+c+q2rYi9Z/KHTKXtskKVSVVvNn66jgZbDm+FfF7K01 -NUxH5ymtHCM6VKjbtws0OedLH0D0H3/933rtq1CVJJqaSEeiix+jEYMadsqIyXkj -gF4F2lCBDHa1B2KGBs26E3+QGJcgv2UsYQezdliAd4x4cQM5+3ts45NCEY5ABU+M -f69vsHzmkt1OrNq7Fo4jFtUeMaKE6U9SV0lu4SdbdBilkII3Zr9yjWIbIKqlkclE -PHzCu45KUY4N6dUjaNB5xwLvWK0YqbV+jWgwV5/ca1jwD4JYP3vwJBqS0LVCJHK4 -rnSc6jabQCPqPjH1WvWWq2jlM6K0XV8ytYrP1iAJaEZH9kLgo1vBUDStUhi0Tj20 -l8B8+GycGuDy5nkDlFMWd8uLRk3Y5baRnr7ftYyLoxh91dacdNQ/bhbIDRpl3VUz +U7QRtGq/G8+nBIV5ojQNU45u3qkLJd45OqJWleyUjhcfNZoOYC+zseMBjpuXowB5 +SeceD/sm/Jn21y7gT6j50503tgbbEsek0lXOWpx0coxe/cYDiGFCzhLodvbgCser +/neCuuXDaLvEN9S4c8pfP2i5+qcIMo52NONOIXuGqAaIuiPeeOv1XEYTr0IVI/qK +mdJlyWDvuaaAfacIVCRh1So/g/jW4Xm1HoDy0gsSJiuLvJTXt/P0ZCHzyr93EnBP +2RI6RDulUCfh5XAi7G/jwnT7PcO86ZQCmpKyndujBVrlW0RbYyR5KDUKKR4ncakH +cLZqScz+VabSZaSzygIv+1ir9KoPX5ChDqdQedWru1Bn91X6/7vNImOeVIgeWYv/ +bdUFpYoVL/InbDtBQm1wvT+jmbOZPePzOwBrnCZAafBrApuPj2XQ5u23XqOCuG3H +oQaS4N9mgH/5F0wzQ/HzGBAJ7bw5rw/FuWRGNi48xDuBEt704i2H6gYM/aakqAU9 +dsczrg/5zjz9m2X9Y2IO1l/xD86qyG6yuDce6c6gZYiMnBr3WnsHpHH4k7xUHTT3 `pragma protect end_protected //pragma protect end @@ -1987,144 +1987,144 @@ l8B8+GycGuDy5nkDlFMWd8uLRk3Y5baRnr7ftYyLoxh91dacdNQ/bhbIDRpl3VUz `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -hvCy4lzX1MfuCd73KYIiHrsjt0ABNbLMCul/GTlZwovot4rNK51hwD1Kfo7PwwpW -ZAlWysuL8uRD5kPvOTqyTcMOB3PPIZI7gpd7P8aRw2QIYIBFci33Qt/VCOv7zKI8 -IRcqewdHLIX1nB8DwlX5mfH6TO86Zj1mRhe7gcqNIEqbsnVqBBW82EOoXMsjJIya -Jzrijru/XpfMlPcT4qgMtHt+yB8bZyw2jtVGdbR0JJHkIBGu8qqOJsSzfVrGeQXq -C1dWmAjcXF7rJGF+X2YTC/Nd7MRsg2BiA6D9XBCwDfUA7FrjWynGfG8juytlw3gl -AO7VIj+i+JKV/0pj5U2ckw== +NMJzeJcTsA8NtSPvBrIMXiRzk2+AEhtFj0ikM/FX3JZpQ4bP67J184nC8s+YQCx4 +9sYWVtmnaSqePX2CL5mZ+aWIcsSqui2u73d/Bg+gzDtRmc4ATUuTWZv6/ZxhJ/5Z +u8B9L/ZvnBUuVSsyw0YVzE+XsUr0eXdh4Wg9xrR56a5C9tmqsVLT8AlEGAUDw4do +KDYC96nYXf/BEnphxyALqmrrHhzfASd/9GWnTl5tqi6eXo5d/0GnAg/TumQB9VtC +qzB2XmUFsov3D71Vk5rsfyMzlPQTKeY3gOZaSWhORjUs4q4Sc3PwiIsk6IfvDPdO +opyDuRj3IOUtvCE9y6XKfg== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 6192 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -2142,39 +2142,39 @@ nEva63PdNqigtHILXtbEYZJuW9x1f4QD+j3u4Lit4Wj8Sr3NX4z4muz+FMwYNZBR `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -OaZpVHs9LsCH+NBaw+A3tlFCFhqhMGIQIutx0MkO7PzQ0402Rh0pFi23hnzM3awG -m24dELaG0ION6m8PQ0iYMi4OlDq+uxmA+uBT45/rxPnBSyvkMLzAZ0PpaZbfRcAn -BaQUORLNL3uNVvj1gJiIVjbi9Mg83q1QBT+G/ze+7TIw1fLiWuXxFcGsiKjdgUH7 -P/bhviGt4CPjUSOazXXjawjNVvuzCj1rwTr71+Km6pXmGmCNh6qs2Cne87SygdKU -Bcq3tr57Vwp4GsEV2e8MRhl/JhqQAyISNiWCaATpqV8zcA8lL1SWimnZU9YEOKYj -/d2j+zT40Ag1iC318QKSYQ== +C+BVml/KQ8QAs+EWMqZgQUmxQ/16vMdYR8KdOJPROqxy/2R4KpsrucSPGrri3HB4 +5cov4xTwlRrM0dVRTSy+IpnCNuCnG2GaPPZtEEtppsdZsawMQHHeny+aaAH8QWd/ +P7xzXIpnkSehz3uCwjoRL5NvWWs5wrbBgpmkShYE4g8GrBceK4K3q0QHmWlo6biB +SkKv3keLl2LvqKRFsyI887loII5GMe7kOqUaT2UTX04i9pHvTYrmM1XPvL0/Z9e9 +GeIJ0s6+ss+nZ/KRs2vD5iNWzBNR79Jb4/Hm+jPkUk90Ye/pb/zK3zbqaPGcFRbs +27BwV2nodZkA3Tx3XwynxA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1152 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -2192,186 +2192,186 @@ CUKT8bNLWpgIvoMdC1yuqQMalACB1iE2a1OQ+qIrJW0OXG+K+PIoyAU1LZ3U4wa7 `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -b4uynpqagZze7wPznnYrr6jhKqci5Zwg40SMeWUmKpiYwymSLqVXAPG8kb6mM2N8 -iD+3Sn4YqvuB9vNVc2K9GayoeYstXzpAXw7kMyuwjwhyHnjGsO0pY6cHGXMh9+e6 -YJxvUGxNI+UZ7k8Ni7HBacOwDGOecuto9RaYKgxe9o4GUrTKJOrwj09ofdw6tYnR -m5AMlau1o30kZjWvljmrT8HCPRkoLX7wqgNeQ5KwDpltVelMQ/rxJAqz0rfimGqk -nEbxgI0o8avxnkCNsmjyFWeuMcg+54pNxLj0vpzWwE3vuIazglE5FwmrvElKT55j -i+L2L0lNmB9/RcGmdrgBIg== +cLVeskjs110eTOqMsYncgUFfySXVoW4d6tb3cJlwOuYd6PEAZ6lxk7niwBoWi2Mt +8PXpt8sdYQGb5VTj+VswNd6k0HrGDFwR6J4y6ctrpSGGVdj0m/oXdUSBRZezKQc/ +BMPVF32V2D+34NRif2oK0xSkguNq4WVsv1XqLapwafiuD8CIIh8q96E6ZyY8wvce +Io42sMnD7EnRbn6bENS1swM9hMftXg/MNm6yhKABn6QC71vE/EeqS/I0bDGwXqkH +Mq0OG9wUmE3YxsD3bHmI3D8iJar68Q6+upNFx/PNLxr0BSHvAMk1g8NT5XnxQXoM +35rZ1GU0MRkDPnVAYt7uMw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 8208 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -2389,50 +2389,50 @@ QGl1ODMrmFvQ4M3QXIohZYc9x481oqs+UXbmXbIPH8oslJDTVUezN+GRsWh09Tu9 `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -B4fBRt2oWEZOEptc1v7NsXmuUJRyNMzeX9wwRPbkGNduHqAIkhMWczvrtkjrBZM0 -ePAOj0RE17g0iRVSVEuTIUSuaHZaU8omQ68eVtjBLrpLqbVKlPE79DeVeYE06GLl -Mn/kRB5XtxVLefgAa+B7gFj6OaN2bw/5tDoyaJtYQX/ZetShGd4c9Bk9yVJfXk9Q -ngYP2qqdG6yR/WnI1ZAFdIZ/u4+qqyG4Yb1jlgNh7ebaqLap4rM7lm+7021ZvoBg -4wofu9EPHRBGxuDp7MYmD4yKPc+F6Nr6v6zA0IeNgyu7HonN4cpwRes734MfcVm0 -hNLD3zbz1fqi/5IbO4zpug== +Mx/CyR4oJ7UnPDvtA3BX4FDIIZJs4R3SDfnkQvx9oCzIiC8BFmOAAos2VSDBCELG +ADRD3CZLEIDfw1uFvu3m3XuwwHbRU0vxmVOzyBzMS7l+1WdAsowJ1t8fsjLxtcRU +GTCyFC/FKyp0BY5Gf1lWpPsikhMkJQNvOoMt5yb5Kc7HQ9AXqOut+35o3uUyGPkC +veBF4ZGCgHN3krTe2j4QGdErqAmlyNrOhbD2RzYjNVY4xRfNC+BcQ+k9tojE/Y6W +t3rRrxMwU0wYU0zQCIO3UmhOxa70JzbFqwxIcRfD9pEJ2YFHVd8z2WTcO6uUDbKy +EOBMff3t5I1hakBI5vHy9g== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1680 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -2450,54 +2450,54 @@ z7wK7YmXx6jUaMsb0hWSATRK4CuTrMdJDrffdi+euGE3seX9bopVfcSY3THYi18+ `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -MShhFymH6u7+Z7yyWj3+jZDUAy24qVj3y1HmLD39wytHy+Se8+M4MzDiaycdMF8t -IIugBPi22stpoFXBYrvK/1vClsKybUB+sUVlHeExyCxrquSFDGfwyFMG+amxK4ea -Bm4BuQ0Ts6N6JOHu27Jn/laxfHPDk8VKuJkIdTL+DpON6auAxQvKkqzlv6lINnED -y0wtOkPdd7Aj/WKeDiEKCa0ARpm7pD4UxDSNncUJzTrr3JeTHW0B9NLmSfOkHRXK -maYdV3XsjTT++ZdIPW1gkUlBVpXlJm0Vh1MFgsZcHvs2V2KHUeUApLIxiERNs8Ud -QLY6/H7V1tTlz7j1h0elLg== +K9sd/rk7NALXNDOKx4aiqZXmx2hjxMxMCh6nkYDD6nAWUGADiYKQ6UAbUfSRG3r5 +riXc2Roc7jPMoDK5EttVkY+J5PzRw1yIUENrxVhXzwXzxFZfF9lNfKty5FtDaTHk +o5C7bR7OXrUxbNk/nYkY1GMAPzCQB2sNKGTWt30hSbRxjpMbiQgnV7cDppDcDIjh +iDJ2DFEO8XyT++xupIqONYkaVKA7jRjh5JNfgmNnoEiHHKJR/B071toJ/wJnRDR8 +q0fslLM1CohIy2lOs2y492Spb/9ZVyHmGlpR7QMAtg84xBHWadXFLq6+NkV2TF2U +xumSOnIbobI82Iem2jX/2w== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1872 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -2515,71 +2515,71 @@ TOOidqhrGKxOGP/A2QYcA/vOqEmlqurcu771Z8VrBdGIS1Xt1IqQ5CqrbfVuYrH3 `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -LXtziaplKaCW4r/yM+rH+7jcZIo0csTYnp1ZUa3acHqs18tBOWU4lVO37k8q7T57 -iEeHdfy5WAXgqc5Ls+f5l7JrRStgFCqKfC8K0dCrcck6Iiovtg33H65Dwhjr5yPK -IsStRCSyt13MzXR4KIgmykzDjF7FPiejOYtj56uEHy/ohFbcBgIe/b3TEhiB6GAu -T6YCAZgFWAHyx/ijsvCdIbdr1s0IwwvwPRH30mQpA3Ol+LY8aLTN6XnOaJ9WaT8K -ZnKTWBciNs2Qh9AeyPWo8kuwhoWOU3QnjLm7dkeY+vkhuQP9WfuJaaUH5je/c0O4 -kmTMByFayrZRXvVvwh/Hlw== +mLpV1Gu2KvI34siE3LduNiqfWM8GpvTz4hY+Oclo9dEXhsBCIki9ndhvV5XCBfvf +d5dp/+0WZjVJGeKMSGJNCvHYJNU5lbFaXs2kz5d3vi6zRZp7r9ehcyw+oPJwn2UR +UNnUAiBWJjmkP3FLlURtjM6c328hckzOcIIexVLpJiMlRact8GFrUGwaOKLnWjAx +AIeY0fYoI3k+3wnepNjmr9sV/4UQB9EWvvBHGY/7ST/snm8SjZUdxBzsEluOPw0p +nUHUyUmpdhDO47hCLxKLWwNGkEw9AV6rPf8xplCr2T7xy21zmD67Fc3imLT6k2dq +CQGyF3te7usnhm3VC52hPw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 2656 ) `pragma protect data_block -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 -ekHHGSH3o4CZq9wZfIgERw== +xSNXPFIRDLIwsGEPD3qKw2vvY6C6OFmQJZfs2jaME9RUzZfCCM0az5MQlmCIXhXX +XCUJpndmKa9Gjk2/l1ewbkKfmt9A6jeXfuGSp63KMiFk3a6It1IuO6TbZEuN9LqN +MuovK1jjCHufXKe+6KmWQ3QpZtyQdu3RMJRdBL7xL1+Pu6XpM0Ce/jGb+/5+IWWY +PnU1v9xlDIRIJ1iQDHmUavUsDuMp66RcSdP8J+3win4w3DXy1NMXof87kW6HObVe +baMVtysEtNjjFuwVoCj62sr1gD/V+owrdhNZ7C7qYIENVImrn1HhyvW2KzMOZDd/ +UHvUiwD6O2WWA0XrEWYqRJe24SXQOEnYZ0gfBekHA0S8KbtmGmlCI6lR1T/cPd/9 +lZni/wktUBtj09i+sP7h5aVybOr5cNyyswfo7Z785xS0cctKBFyduWylGmufwUnA +o46LWV55ABNoHrvNrmrrT5Acq8Rs8mt9OgoeXg/JDI6GlCh6TxgvBns0/Es+Y1Fk +thpIP1MYuiPQpmA/Ke28zAmLs92tGxMA2AtD/xIwwwXy/wlN/mtaVn/Sagr0qYSa +UVR6CtZzqkP7GATqPs0tCDiwrkYtg5EawVW/YPqwRO8B3gkYH9eJDLyq5QJeUQKl +gz9qeLS4XYWTMwnOhU9eeJrLq7G7k1Cg+7AEfkDsrA6HXv21mGuXlCjszc3ypoms +RVHW/E99O1VZqL8Pnx/MDicbL+5qgWMj0uCSEePp06Z4BNn3h4mwqEQbCQJTQTkZ +rRprlCJ4QLTvxEfgiwrp9VoAQHKiMo0b53NGs/74RLADRTprvSrcTiwsL2a0kNJB +UuXIJLlrYOd076a0DMU+ULuqYqpYGkkuXFv58RV8EVUsccc5sz49+5t0x0NOkgD+ +6jPfM2wbyVuJRoCcU7FbcZyTHaQeQ0JRbXKnG/lb+UHRg59TplQJngnBRLk4aVwa +NG0VeG8Q01O18FRt8dgTUyUtSP09UlSrcFN/6/GV0pUSy4x19cC1L8ntV8Ka1/rk +y6SshIg9XA+X8d5yocaf6cWWFAkKfdNPZkDNVjVITEwVc34/fk314qe3Fy8C7Mmp +OX+bGH2kl7KHY8WyzoD2bngdxDJXoODALN4tAkmvqwqUjB6ZXMezTryamSccKHm+ +b92UurLl0ayy6D/ej/FT/16yxyOjQOert66eVLVjKJWeWlsU/kvnzLgDrXdyeUdR +9Rl430pnvM8cmeOwKm+h/zOPEm7ehn1f2UX1yChr+Iz/ebrJ8AJoCuZGJ4ZE8uJS +E3MV0F5wEf4cKlQTyx3F+JZ320q7g3LiD1z5IJlg/x7vgEMmMH0TkPsTYdiFZN62 +lqxsaF3HnyeAhiFCtCIec6r3uPpEzVDAE5KU/q9SuYUaMNKHuZREPGbVd3frja7+ +E+9MMvHuQE9nYLsZdLNcnT3Kub5aU2WfGLZR2h5mPU2WJKpKXDmUOEM4PDcI8mhn +uFeeUmU9ZO2rXTuwuzH8OC8JPkQFyd8lAyvJ9Qq80rfs/1yzwGA2hWJNerIjAwQf +jGD77PL0mWqhKkwAArWD710+lkmjJR1CCIP1n4njXvGAs8uW3zoy+sHbghv5Cmd3 +Ojo+HtWi7B28ca9agh1lFFzzg1tv7PkkZreJeIe7Pi/lxQcqQ1I6SRk7kagwFYuC +DQQndY+VikkLmXSKGwRO2WMeTWWLmTuMrB7TivJBRHaFXuxC2quU4/b21llicdlg ++XJlEo3LpBN9YPnyGt57fA6u79b12/UVC6uYZXE7cqSOYlr9BCxVdX53VgkTfUG1 +NnWAt/jVtVAb6bZI3E1JMHiA9GDRb8lDPiBBW3LlsMIZ1jcGli1lqnbyWT2jl3lE +gZea2O6dkPGC8ceH+i+Mmj5A8B/O1NwBzVZglepbRBcsLcxmfiQVjiCDRwikUfD8 +rZFt/tNM5Mbv6tDtla1UDRfntGzJVaWkrxPms/pkbTPjcrU44FPHXdOzF/CquZd6 +Zis67BAf+3f7DRSb+Bjm4808fk8gRvOrHc5qyG4S5MrGxCtE67gXtNoI0k3TMr0S +bD8Hr/HcawYBms/uLVWNYo/FFec/Nib9BA4ifIgp9zOAvGJTMCvXY+59L9uVaaCb +YMj2exTokddbnsrDlP2R6ScxU0XnLbCvDpjVs2Stht2gDhY3tmFxvz343JRy0X5R +Rl7WeDxdjqEkxoAcEc5gZG+6TEi1n3zTby25bxO/TNJC8bRGIdrPehWq5eACDW2B +BMHpGpNQ7mFHdUzq2UJsDquuW2uE954U4XITmw22IyxNzio4Zq7GwZqS1daXuVnA +d4ft6Mq80BhSoAaAVRvddjM94Dp9rCuTe2OGkNlo0GvST/Vg6JDlGfPyWKLFZlAY +VQxZqPfCqwwXxhysDndmJ88ReMxGVjHryDe58knGOb2UEra3Wo00l5vD9coFxCyp +BboTbMjJ0VMMhRPFcFFeqxuFfeAyR/NS9lUqpOY0B3kzJQ8fyh1y9WgY3CZ98EA1 +E8HeRNqgHSm2DZIGzTCm1ryOjqY8pMyqCDvzUNcObXM4n4vjEDDbtIFHqyjM/mbc +8V6h99bxsufaJEZAIT8vSlfUw6Y2vtUwJFjblN06pKcu/MxPonaBDb87cAKQDPhA +lqXOkpw6H0qzqRTZ0IrXGbQuelXBeWSZ0p7YsQH4/cxPdKH+KhbjfsnBEaCieGJm +9UOPJF/Jug/N/uzJZQGgas2FNuGPm5NAusK1UlUVa6QK6fiE0+Ao4lcjl6Bt/5ll +sEEqoqkS3m5tG3dEw4+ugFCM3kJTEtsietF+nr7BswXpY+CcpyD7RYpK7JjAUWNU +TpyxEC3PHmyTqzSSqnTjTKAdgJADDxmQdVpxuGe2rqNDO0CZ3rtCnRTlFQ9tX9FM +souLp7RTBs3mv1ZKY8s3WcPCdOsaxjEKAP30Q+XEzVnDL5nJ4//HIGQEvLBjFPd3 +oLf4CrjecS/lcko8bmcby+/15I6ju7M81qQsrWE48zjN7M32hXrcTrw5K0Eagrdr +swhZhnKRzFPiLVACsVP/MlR1gCP7U15k9I01ZMlJ9M1USo/Pcva/EqkySwPTxrAR +d8+6LEiA8EbP/rUTsOTymiepG7NLpVnZB0Xz3M+MFsYBl+buEicaFJyiFndbEw8h +1+eft25zGGbi/5/2Q2fGbRvL5RBqTqsm3vjGtweScA9sEe34eZbgpdksRFBUv1V2 +LW4HemIXnyB79BocI0YAtZhy59KiBC3DIYlKrfj1+S+UCnnCNnvicm9TXZDjKw8W +b1HVUzIlF3By7wJc9KkUV6OCH81VYkLltlIdFzQ1pkWoCZOH8m8/DaEi6sWRbtou +fIY0iOkjwcxOh+Hc2Bf9otUfC58KnSRiR2vRuUGNaW6auja2V92vgbwByP6k72Ds +H0kuN3DUWpRNIrb1VghUTDw4AYtvjOwX8t5RNFV31YwfACV59pw1q8AcQoL/xaUw +dFT+blTfRmF6FGbU5oPKTNz0UQrrTDueJ6Sx/rvI3kDYbtP9hJal167jSLcwqs3C +JZy8v3VXdOgTEj+8jfJs3A== `pragma protect end_protected //pragma protect end @@ -2597,364 +2597,364 @@ ekHHGSH3o4CZq9wZfIgERw== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -Qm1+DiPc4/KNfIgCb8Z8VljZMd3PTmxXLMsg3oZhAa1dGw0WvlpwCdl2KZNBp9+K -HSCGtwyJ7bdxTTQqtTSMwkTDhTkpUd+IbcKlBDyiKLhavPJ+XPC6Dch/d7sl+7iu -GUVs04MQMhwX2micLZPpvccsQbnp9JqfAjtCMq4Vp4FpoI2zdFjiuFZwLL4+37h/ -Ld2sV3AugXps/FxS9oqmFnzGn7IO92aNlEGZeSqKG/QYSkxfIozpMMf+t4ZciQfe -PqkCKUO4ppHGLczQLSBdUo+5vJJFZg3fZbBQDDuf8cG01LnjTcybYqLMOG/0Hvsu -TzCqS6UyB2ymDkU9/KW97g== +E+rPi8nZBBvxw5lnIJA25LiV1KGw4KuXoijON8/1OC2p7Tm9Zi0gAeRVMoR0eOZ9 +eys5000osxYCejkvyNmaUmdk8FOKlK/5KAjo+e2V19HgqNTf3/LIbYsebhfxOTfb +xrhTgQYpPTAzlVxDAxz4R6MiX9xrX5EZe06iEc1u8bKilKhwUXTCJXHwkhpl1hI3 +4GDwzh2SnoYB3W5SvkuQWjwYxp4wTZPZjw731TbGzdTeLMObSAexK9FPIt5pr8qc +R9qRFfFHPz48NVDe/d9GoT9uZmf/qNeI8XkB22AjAlfN8xkDl0JUpV844N8Qh29L +NXpHL0KzVcX0fpWtDG4GKA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 16720 ) `pragma protect data_block -ImaWuqW66/nvS7xagAuZQ6aB9qJoUoxBVpesf0HEvCuiBl/MimQq/xWJFbHy9RkL -EiE77TaY4q+YcnswIJ3wO/PYNl+9t7/c/pPkNnra7wBBDjDdnhZsWJrnB/8XYlEf -BNUS5tBHAp6T6ZUEJ3GyNLFxffL5kzQAuMZZuxp+THU5TuIJ+vHyEUuY4YNQj8c5 -MccccrVpaGOEJPeASMN7heYijVCOqj94cvuWIDKpyGPF/ItOqceg4kJHus/eKy/g -4HMH0CYJgr4+c/s4xIuNbcJ/LNk95YTgFU5OhU40b76CxmfU5cTo0nKrrWNevtj1 -WI7kg5zoXJmhDLxtZF1CZU0EtFIEIvC8wRHOeutZ1Vq05a19bewQ3H3aOL6HMmha -mXspHaPO3Hz5YO7V8+Wa24yVrc5uOlcOH/UR0SJOHxeLLLpGe+UuWrd1JreWP6iq -o9WGVxri1sgs2rO6yBW3FyeZuD8gF6k8S4pJ5OWJgHzg1RPlMD6NnUTA4t7oWu0Z -h8VUJ1gkEuWZTmz6Lw7Lpt+mqIAyO0WXUKX59gkN78fH194ar0IlTaZ1PJn7h2x2 -8IfZhjR6AUBiNmhhATh5OzgWEMioVs5pMX8Mse12AIkCP/F9unijAZ7PrdWaYhfy -ibK16iwdTNMGVhGLIeheOswCe7LFPtUOYe8PjZWqYCiBy2sFQwhJHWknqZOOohXZ -4QkTCbXYI9HARe2DcIPNab0wu7bufVV8z0F1cl0fvqDE5JAm5QJP6ib8bS0lXMkO -8juSf05xikzngK209Rqt0Wujgj2MgYbKg/J2etZvyCJV1uHc+60Gqc6L0WqUG+Wl -FBYQ7x7LOgw+hT6oIA48UJqGwOR9y0DAT6JF0marvz5q0RjJJ0tjq2D9C8t4zjED -tuQcbBMOA+j2/zIvQRGLi9pumJUPjcRvI9s8x3IaQegzNlHqM+m8BVNhvMpA/V7z -qfsah3Xs3C0XuUDEieKtE6jVVUHLR1Bdr59zzUT+PYcMGrE0skGI/8R46TZ+xGkr -MoltkmE5VeIAxqTxpKvARNfRoxNF2WiqkDN349j7wxIv6FivGXHvNcML5Bk6IAex -gOa7AN2VkeqtBwb3m8PwpDFm31CNI+SG1N+/rZCX03gvmNJYBugOD24ZGZhooe1E -HndXCw3u78lgKQVho9e2AUoVqSDB1AIDG3scMFZj/9IX4zquJONAVaL4IpBy2M7Y -zf7x7OaTQsLktYNDiLaJ/phReDPFUiGYVBf5iTmune3de4kWNK7o4eOuQ+GdICa4 -BLO4aPKkJIMcx9HlA325m8+mLGS1ofLLAE8kFwBUKtWHMOV3x2GTooh7dn3v3ICV -X/l4DXbQzBD3PJ5s6H3CVS6hA8x3jefRtJQB2EjSom1b0/XF3J+yq2t5DKVJbYXP -fIMn2DQICc3vSFVnJo56oHAdRCZF5BGkRA8rXH+qxnpZFwFpu/AGYvTu8lvXwUzc -P4+9UugyTbbhDTZ2kgQffcmNag2zSfA1oqe04aJbmZnjomohOxl8XsQw/5/9hMgw -uUeSkcsaaoqwcKsKzKx9zs/+omuRW/D5GLZTWQAZIpsQSM7aCTq7Wj8VTM8gR5UV -7i9c8HuLpCypdvLpMvAe8C+iLcu2sE2Nbyw9Hhaq4eClQENAwjs5VyjBMu72CzqI -w1guEyWk9q6Gr79WHfZXRmMccaSCDaKEJCRWlLg748IYXk11DXuUtQGAruxxY381 -yFdmBVNGrIDhn061L+Xy9tWlIbIog963NCCivYwwObbCRR07qk+M2IeeloWDVcux -ycJGKuBzfoQr0bV0VO94a76ydUZ86WTfXVkz4Hb2DEGsBtggnj2CStz7tsOR/DMg -2OFJyB3GLFgI7DmnKGPLdMmkL9TUFWEnIe1t7shOhDIeMUCT1D3/ElY9pJUsejf2 -zCSD87vsxh7xVwe6HnFotx/HOS1UrS3GsUBDYjF4SK5jpCHhn4aOc+HwDp0KVbL0 -dBEz4cITrT5B2jr8BKxmEnTW7pLWXejqEBitmcR7XiNv0l6qTkytA8WEWEdY1eek -z/f7UqE7wPQWsHpE+DU04gkqiXFY+UvwM1SMOu2Xbt2/yaZX4wjrkPemwU8dttSR -tNMHYQOCExSkseTrZ9lDzk0dyrFKvxEj3V7MLQej92DOaSd7JdNd56RS71hTLB8E -lYqNCRoqTdVN0/oD3AMefQNexCz3KcAB+YW5quu9A1mG7gD/5NXxfWl/feV3CROV -vy2sy/zEAwExohTsDE0pKl5Uft8n7wic8trSLt+dsN6QcHuXfLouZ+i1vydsiVaW -/TOvC1qAg5sCNwpmSICGjBaSTr2hgCr2Cdx7sL3OqsVxjrTu1TiiYjSS8zRJB37R -v6piXZUY+ukcS5ksLoxXQ5VkOS7qXl2X1xbi2es5PE2d5ctwV9vlhh7lpEsjcc3a -zR9MGiBF28gYw3GUgrUnXbH2jkWVKet64tQzG6CUmmgp/8N1gxSMcvjNyA2gtSpa -nKIwmv/KAQVaeYyFaPr6LC8G8Abtu8JNdh9ZS7sLDRi907xBCeTWeq1wu95fu1Kq -8hmEPwSW1XlDWdxPXdtTU6pZku+Py9wgr+VB7ZhY1PFcs4uQn71zJSmOchta5c4N -1l9fdJCu7PHuiXN9EXqGfinPWhc8+klqsq1+6hex008QT2/iksQMCwrS47yR9wCY -v/OG6E8cfIOSGcsw0XZsRRXc4W3Ux5k8h3d9/lWsqr0IAvf194ro7kTn0E7Chusi -V3XgdAQVtOnGYeuypZkxQF7tJ5g8R12u+mvxLJ1wHaGmcO8PZHl8lFsiQ81kll0d -kWQlnoCCa9rIgq460/INZ5Paon5AeWeWBkyBnU0eB/TAGPATIxH6pS2fuo/Bsqie -xbSS9upg8SyJDC6wHyjgPw4xiVx52+amAIEiaByAb+RUk4Bugz2+Og13OLAxlRjk -0jL5ILDm0F1qhfqKRXJdkADwzZJihUAOfJefwSwiRTVjWIZXL+eAESQrsfunvHIK -o8+VAnZitQI0vVvqaFG04k0a+MFrM5poQu/msMjz79p+CZxsE7XrMIwbj2b1LwZr -z43QHDGgeQCsshgLb2bFHyBlrNF8H0oDjaAomZcdUGtzQGzo45OllHJdWLsa18Se -XJJ5eRi4okNyMlYy7skPH34pyhr0dUnzZiiCS3c3EZjKeVZZ31uNY+lzfAsbwB0g -Rk79V9i22A2vEyQv0yF8/ee7ycEI379VP9CTpmC8QsDnmfXd0q5zSCJjJcBUAKSS -mR8zAtwn1lb94Xdd5RasJ87ONUdUiMaRMGebenc2jbwkFWFkSZgJS/foIts6g+ws -iRzlWMGYPZmDSYpQsojl342TYiD7HCNEAedQGMeJ4hlLUJjmYDGGf7U/+P9kg5LE -lpcqA8iW0PmClWIHxKnHW10d34E4nnlx3MFunMy9+06b5ggUlvjypzmL0GmtYxtE -EwKn1cG9p85x9fbEHP0/uMkO62J+u+qMJAROjp5aSxcnp6riMdFKbMByUnDfbuug -9nYec5tMpsBcVDP+AqDJyTAz2S8CCbadAT5mkLAh10w2DJtT56VlVMk8ahjIDSBa -35FvmTPzRP64RFDR4e6zEf5y+oVFUQaEy50kKDJOW8u2ngmJeT7srkcnDFh4lmJT -1zjnhrwRA+gV2Oc0L5BDaA+MJdF0LGc+YGkbLNz3QoWN4bD0cTzLn9IKMsshX9c+ -y0+TnNaCe47/n5EffkkzSLqAElY0HAn4ahOfwAy6yXxC3+UxJ1FNmPkRg7KYajxW -m/bPZkWXvc89Y2q8NuzbJsl0hrvd8LJyWSUWQn+O/poMIvOJmpl8hEJaAnrM4TmC -nWvcdRGn0sJzPX0rnESTTF4SRiGEJw0xBpFBmiHL9QeUPVH5lXDglEPVLgEx71ew -uUJpPDN+z/8x3+3huplC+AC3qMUk8r0ysZX9Re4VLVRjxVS1Q84SewNj53VCz/2H -PgEuoeejG6TwkRdaJyFEVCsart7ReyQV090a6I3ZiPi0fKg19I3o0pQ8XjUQJVV7 -q6lDJbrxgMysEkmaStVZGdPbVV0X8KQTwJQsU+HLYA59sNCjzyazcO4adiAbvqWN -5axaboFBi1FeegWP14gQx5T5qxfk8TZiPYhsbkAlh/sWlqBPbq2Szei1snOrVxZ6 -XybkZM5y0omO+iJ4leQzXtWPvm2yHsShmBmBd1GQOTGUfedJ9TtExS5vnEhmmsKm -LKQe8J98u/EKziPcP5P8qpddOV6I/oL/rKPxNZCz7u7y4Jt3F2lNnyGV7u+qGLCM -AfqO5JqJG4KTHlZl/OlE6fmz7h+Fxke0oJqgumWQSKe3kQCjlcNeBrBJQEfx1IRg -oHGWRn+DWnfQ5AmG8wt08RAPdmXZey78XxCmLlf27epui4KVehYYbxP2v+s/evK/ -yBOfb9TF7G1M/H0XiMuy5l8y8hgHU1CuTmtPeXZf0FH3+SGEI1Lq5iTdcFQM1iV5 -9RpfWNjVjIQ+XfVKevbbq6aJpNTQShcu8OuJlhK2G0m5QNOb9RrHamUnVyBrzBig -epuRzMe/mvqgeX4HvF25IfVEFH4Pf2imNIJvU2RgpmkMr6VlgBbzBRdXxsWe9V6l -PEMom4qZynkT2/w/lklSkgZtPHc4JS1yZ1s2GX1TIf8ZTC+NhOy1pn1Qiz/ajC90 -Bh3Iqu6mKg+XTsSTE3ZU+sNF9L62jwVbbKFClrNb827WzJdjQX9HLI2WWyNz2Hj+ -1q/X1mQHNL4yweMV0P0u1nKPfMndK5rP3CcP0uUl2ffn8xnLmBEytxhdhRMZTRhZ -WZJRcrcIOUuKh3C9SBErKnIMJSZ3ixaWopmOo5UwdprN3nwAsju8LuSZcoegLxED -9e3hMuUTEeiDUmu9oulAnVdNxNOY1DLUZc45BI8uNCQA80d25uNjgwxxvXKyXMTk -/9D4ednxB2JLDoqBw+aLYkvUEJ6aiHr+qXHutqaBFrIc49W5U5HEYyONy6uwjyTp -bMmQOSVJmCAJz+6mpJmw49o+fPvOMesyaFhVmzuTLFdkshLa5XygUtMjEXqqtXNN -SVvWbAWZOb38paZ0R3q2AjHbywVCvv4GsVaLyD4n5nsrIm0AR+ntMXspgRkbRuNE -lcdNoMxpsvN0jy5mdm4SYob/gRAgXiMf9VfCjZYkfV2ZOJjgClOzebiHrm+Y9IlK -BWOfDIwepbg7vfaE8p3pJzN337sGELypuENaH/EOrTIiK73VeaUS8vf4Fe7+gY8n -ProEchv10opYydczA5zXXIWKRguGE9iKxGOLN1lEayxlbEvdG3f7l+3I+8ckDleR -bOsGOgcNKg0vqwS4nqpcR1/CPfzKZWMEL+qjwfOaxvRel3poMXsTUb8F9LAqjiDf -g4qURBvD5qwFSDezYuPbnnWQuoW1eMUI6T8ldMdN5rCGLa5qsqHoC0kPmBU0VDOL -pcqiE+7fy9mLHcMfusWfER0Ctr1S4xmTgJifQJvQa8HHHKfzjlb7otjjI3dXARPz -24qb12xjxWhqM4w88E0mTanJKKYzyNqowECM64V7C+bV2WGogVOcP6gyqWqV2yrC -TJpd+kVQGJmPDoPTJJuc0w5cVKQbP7T83coTUvtNqoDDQCE9MTgQQAnmAcysyoxR -qnB+H60I5paLAgd4OWqOS8dHHTbyg/l4f0bTgfbdWwkRviTCae/Lv3uLTHsJi9Gq -at8+Hji8xPEQbtDnoLIvewmZcCjooTV639qvd8/2JSlLr1c4Ehosde0BDGQOuFtN -lJ4OFBQw2/8sfWnCMZ0gC96V/q7vnRCHXSu6znEfFlUS6J8JLMUem4pvuDR7eSVB -aSjo+CwhAyuLNAFsSPxup9Ct9pHY+02Hv66tHYihMrS/LQc4iXNqTeBCcxOLX7ee -hhJJpLHnuac5CSsux5c8GAAbTYPii81XlutnB/MUUe2l8Ev5oHGgCbJiahw6FpBw -T8U1WOpa2JL+EJXb7H0zQzMub9BWQYtQNVpdiOtpnPpdjQeMmDv7oDWxHkXF5AZY -BzD6CtjMBa4PG20yMYRifDWVvdlO+Sx6+Ig4mju50B5G21nQy907Dlv57gxVVnzg -dVUoOvYd3TY2HHM37iN+U207Oure/iQY9zWMBNQSOtN1kO2ffKAByjdfB+xkYlsy -D9MyW04taRvplAuzCbFYRmeoQfGyuekNelx9DJxPiWy7dQnXFIox6F4CruxI9omD -1I/oEAJAo+erJyqyOun8OkRP2B0iVVDw3Dm5kboGSDLriFXHWoeIyTYX7aUBSB+l -yYSVDVGUZqwIlijlg4eV5OlC2/Z4W6kAeG0ZS8VCMCKme957Nygw0cP2+2PKXRft -DcMTHnzSFmzoT2fR6RDnsYaWp5gx+zyrDEJxUHTUkcSvKiiTx3xbHsrMrEmk8g9C -2o1apVS8WlmstYtPuna3HXECF7lLHw3SnnFXtB7uTUi5MUN4KGpLDA/fy09XVXJN -YfDHXTePEuIM5kn1sXdwY3RWK325+LNxxbhcTTTH34h52OtOI5dHEPKo0LMWVNfx -/wUSlvYkvvof6fb2lM03j+DPq/rOdkcpC8LKNwacmXvRnAv//4+6OBDbQucFQPD+ -TSDW76Z+NkWpGIhm35Ca1Wc1XeLtvDkvrFZT0/UxQUtwuTCnIlMA/TQrUUgQBugm -rbhjZzOkW+EI9ziR6Js2HetonUmNg+wQKv4G00DDPpDW0CWjwHNxTWL1wd1Rvg0J -/fV1Y5DwIaCyRBKAH1Eye1ffcHwAKvT0kwTcjDMh6i8Fiym1eC0KpbeJ7n8baKoR -TdSH5kWESfnAKmLNKlv1LqMqeUg8TBYSSnc+jSxmRPaV5l0DqVAvNKrxtMm6pujk -f1YMT70/v5Lmd9CIIrv1hqyZg218Zoee8PpouAc1zHeXRVcYJLqEFdVgn5ZOUS2/ -j0oqm1Tcf1gjs2jesLRoKjuRAZQIAlbVsj70akArfO+NDEP4UViBEhtzOyMl3U4S -6TCoVNIYiwZSnF7mt0a/JwbYBwtVmoVmmNqo/ucH1nf10nFQEbr8zdHvn2wM8nVg -1sJ3796VwsFaqy7e8m423l1S/bxDC1/KabbeMAc0EGQ5Dwy0HbzcaIXZr1QHqUkI -hq8tKWB3Na80ssRir2QEhRblFvwZkPelz2QIpRYWSZ1oT+xGqLh+25naKbM3L80K -WrC8XarPhzr7cmM4pK5sI89h6dc/XHnj3qZrhMPq2pl5+BQrMGIlfJWpFX2N9eC8 -Cxsh+CDnw5ktb7CGhNQlZ9auJ/hIRxYx9LzH/+kwA7v1Q300+4R69YG6eirkQgj0 -V5Yw4NNvhHO7h/nxlXEv/UiGthZrL15WLKu9aQ2uT8hKGBCS5pyfz7ou66lzZhLG -s16iuVZzaD01dXU/1SzmM7ctK4Ey0DD81cfosyW5d9th51DuYqDj/z8VlsoQ66/a -Yv08YcpNn214Zqc4QmvR7A2o+YspyreV7Bbz89znE+BraBJeNQPO5TP/dlxH6q+z -ItrhUdYsxChQL61qW/DqISVWePcBGl5Nl6Axql1HaKuTTga+oU3LAXXZFiawCTGt -iMYwk5HraOgX1zOdQswX54oWjFcDOmi5XYHve29NWbQ8V+IaA/Vmyz1Pnp28eXfz -Ol9Yi31yDIp4BvbuTqdQljnCd0el/P/DjgF4k9fQ0H3F8lXBufZYVO8wzT5vLQQN -viZlk8n9EiyxNpDauLWOMWJAyWaSeenwIceYBdb30Ogrr3eBsnky/WxylQAjqPXY -4wc0EwBn31r2MDZMPXNcBfH+tDuScWlnDRLoekEnhuDHs8Nu6O/FRbpuW0S+n3QM -uhFkmBO0rLYHooEelPia79EYj2vUQwSjDc8BXbBUIJCug5ozuFPnHPN5Yo/xrtdh -9xlC8JFDAehDfvTbedukCpJHsevlNs3NXIcb6y5bSDMljTQf/iqGeFxX63QlByQa -m9R5flTxtYlLJ36IslgE2V5RAwzsDnaY0ZzGZfcS2Vxs0w8Rmw5wGnKGARymyP62 -WJo4jihj6qpbdaQA6sGHuSWNb84sxQ52Pd4nKLBG9T+oZog3AoU7WY5GCbN2y7yO -dMi8RCwft6BBmBL2A1BtK9qQgZHReM6kd3jmOeY6gYkuw3F44lFVFDJ2pbVmijng -gmFVuUWpqfXkSsyi2Lp6AEzJlhQzd4DKRwIeStA+NFRAKSrxcG7x7ZuDkYfY7onC -DoxVwH5wLF409BgKgOZaCXrKWd2EpwVTIdIAur+Zx3GPzkIw17RmoAoP3yG6b2xO -4aGVmNXxDv2aZdRQJfiHG10ImvFVa0qKAMUrkjq7Oj4AMougIlTW8t/k/OEL6Pv2 -faSfciKlOdB7RlZSpiLg/yL1UyCFWE4e3zcq0a8wVnk2Jf+p153on7fr3KE5GJSf -d/L1n2eMBKftkAokVcuEbm/S1pfJEZAx7ZvX4k15xcEBGfR1yZtgGDyu7El3C33I -5JpT4aWxDIUwrKa+iw6isRKGopLet6C+NNlcUqj1tXoCarisEbiWt+PZP8aD9iFp -YIB5nGwGQftycOSGpBEuR4tyFrwIVjwgNqMwa4Bptn0qo3EO5J01ljUh9dZcO49m -ynqGvWfIaVmsW6x/ojI1fgLCshg7eCUDBoMGsVdZTAJjVcATsYRezHHfkYGnxrK9 -7tN/0xTJL27sbZ3C91a2ym9I4CNAAYDbawIGEcIJMosnxO7MEyP1lDrHS+X9U3oc -B25W7YD2rmjrm+bbdBcvV+qPkqWTCwGRkXq4CCBWm9AuP1dY8GpOjtzz/ItiZ0YY -+6Clznmm8XD4tq6wjM7QLbXMkhcBCu/pQi2uQxeznXNdL/fQ0S1wauBwiopLP0dE -jLBAXEt35GQD5NUbLmSP7gPv5fX/jhDUc6cEwI6FXSMpwEI8Xl/aevIE59OhhxNq -cnWzYBrcPBdNaD4s1I5/EiIQcrVtOuA9c2FCOcgLZQYaahTF3lqOt3eYXcBo2Q0Q -gY60Z/8f8cUoEJIuI5B0vOstsT7RZJscJwUPVWYb9RGTI7JV6pMVvmfYhNf2//3E -elvn+BSCB0X0awWqUeuy2b2mazkhTyURFS22Kk4x5+nV8OlP3J6op2r0UM6C4UaF -gxJHg1WzTrdmZBAdto5GxP01AbhcsIYXn8fFXRl02hIk07tSgMl4HEWbzAO/zYY0 -zW+f4TIfO6Gv90aSbqAXJU7vAWw8pzKIqSFM9tfTJy9RehxmV+3pu8XQGvzL01M/ -+ghDeTrmbMhCtpybGKshDI3Adlq8C74aCrzYYVGdyeiuhRB3LOsLAj0qS/Nrlxt3 -qe99GwN167SnCoDPtiAQDhupSP1rF+996Ze/r7eE5GZyJtftPM5MXvBZoqZSLjfC -h7M3yNqZh36jTxk6dinJkbW4Ov5GrAZcHL3iMQbpGtrb21Zki+7taT6ZjZIWfTjD -CQnLx2+uT+I82L2vJE7nd5cBBuCvGi4LVLI5IOaLszguUwCti4sg/2pk4kP1XOG/ -xMEUzmx06AauTmhmWrMn2Whx2Ugec9WEjTAK42QEofuv3ex/d9zp9Ah78qRvXMpT -UuQ3pbomlmt9a27pShmHRDWJBJirP7n0FVEYYJ+vpd9VJK6roRmLduk9rgc6n1T8 -Jyt3/ToQi3sp9nSNGAL5GXWi15gZR+bfnm6xN3CHUfNa/Jia2InpytEt945RQcoY -SHvA5gD4EDQEPXXWkDVmNZAVR3iu2OQ5FDtXqDkuHXn6Hymtcx460jJ0Qwcme6cX -G1KD4MjdJqVrp3hldDssh1kVeUD32PY9mxc9xw5N9OOv+QYM+KBwSi45JExkEiSW -f8+VUf/mFSuK4FEL7Xw+FFMRYvhayYbjRvx9p5mNilSPU458qUeM3XqK2xJ0VbP2 -83FRKTSCnJ0YE7/6Of7Nnmarr0+QYt50+P+dSwn105lW4cVTu8cxmud7POGwopdF -3h9bvDtgEztxYY/WrOjCaog5YMEGaCphwOaEkFbISQxHegSIM4z62Hwemg+VE65T -TNG764uvIyBYNFRbyRGXKlsC0HSocT24tpQwSu+PRezCVEg1zPzWlkvUKxhreAM7 -+MKH/nnRMtM0mRv+k9FMLHVSZgUlih6we4HpYmRT2x5CrnhcnqPXrG2/Ogge69iq -CmYsOPEQn/xIteitp0+DumBpQXEeGumM5Pklg9D/Y83aeadQivdE1GR/WbQsw5/Y -FVjoi7+JZV6WpqHoUWRtFx/YApQYYhqR/x9jCC8Zi83/jvIHJHYxrmUtxMgHe8TN -U7slHAp8awMCREE8DsD+7zhngs3nvrN1bKP6Sb09IQc5beVzrD6Npy/IjiCVPm9z -WJSlhHnVj9PQX84YJjZUFOdClpPIvBkbVcsYcWWEgTUOIGQyXsN61mJoiEmkohzf -CRq0bLJTZcZrwbiRjY6zXdY+ilRMuF0bJxjww7epccf65UbMOKI3ZhApZnQZ6iBf -u8i5weFVzgq3RdxbSCHoW4/joeJ5Nf1q2sSo3ILtuWXltEQ6k9WZsXZ+oyBrRok9 -Yw7haYHAM1AWQTq/tMkbdGada6tBLSrSrNv9A9rk3NTRB758+ehACr20vixyC/sk -YnQmwgVRgEySIuVpyCGJW8CGUHmXkdSMHLZjRAurRecxTMRBIygtsIU4Pi+kTsbR -M+pNGCAlSEhz8+7n8FWIEUpJDJU0GS9U5sYtp5jMwkDbGQf9vlFa5gK+WM1j5MTz -LSPStjhveYZ6pH8K2IStUK6hvvt9gsYolEWs16JRJLVYI6DJNiK25KMUEiFxxVXO -pUHDYpNb6gKbJ/bj5Ivy+foNI5QVIqD3aXtD4ya+8u4FJvZhlKwQX0JgXfFxDljz -QA9QmQge06ZO7UhUPH91buXIM7TzyZr5M3wLNkdJK9rOfbhJYhCNgrGl9w7oEURr -nWJpCK31jmtNPqHgX2ys0FDgyjjgwSvGO8xnaNluexkWzKoCUcZSgBIBf8qQHxde -/u1Aqk8A/AsNtPrqpFhRWs/2reOiza0fHnBLWxZOb9PMOplB6lHggVYgzpPtucKq -GPEXDmD9OKWvfWhEGVrkZHV/YvHGHAzKMlD9/yBDlxp42MGuiklaShTdzG9Ol26o -Bg9zMN1swdRVSyKGmJw459z5jPMoTGPrV/pKUSDybDOZhZtfwXGzut2qKj5fwy+A -UmAVNlgST4NbG7N1HPy/HtTkZWb4p+3middJAMM944h0M8c3O0mGn2UBFe31+/Gr -YyUXZx1/Vvko3TwOTS2eNJFqDUsQFn9jjMKsWDezRPFRAaz0B6dkJCZ0ihX2s9yr -W7FYvIcJHb4UAdTnjhubaUHTgtYcUso2itUIod1n7zaR2tD+yXzPC6+kBguF7XPl -jVbGSAuOV8xeidWjGJzmd8DHKmydvwcBsC5FkLlEXZVmYPVQeMXXz6aTAxivolDU -vnI+DJlBf7288xwXW7XoASg4A4uWAR+s6DufOkf3v9cbGYmpEEoI/Xj5+lC10duc -RIGR9IF2PaBTrZ/ItOHa2pCTWaWE2VuDjwfOzvSeVMOgHP96QEZc1OhmBr80c2Mf -lOndWe0RU2BdIwDA2sgSLkzxz/j2XzRjlPSwK+leV5RBXDtQ3G6PNmSfvh3IFKi+ -A/ZjFr8wnFyIskWgB8/lhlDwGq8zBzC/s/cqRZE7H13ImVCJfkiCcKHtbsLkgilm -9A0W9pIbtxMpZvfH5pBRsUJMTIXei0lt4WAJpQC649nLW+9X8ExQmWPFShIyaalW -0i3j8TBTJm91HTGQ8R38fFapXPjLQXghasbLVCvfiaWhSJWuoOu+nktK0xF902YT -x7b3w2uHndP33N1MfJn0Z4zhV1EHgIo7kUawYXEoGOq6sm4IYmtZCK8dc2m7++Bk -1FghgZAoZI3B0XUNpqUcKuI1joXD7ER8uXqjROdiRQ+Rqkc83Kw1qsq25SENudp/ -grFtyP4sQ57E3tQG9Rthhukec/13LZSdNG82CT2EMBhhmbBAwRzgOEEBtwy4wahv -DqqtKo7J4c9xpErJAFg0n1TlR0WnZ2VppR9S2VN5tiUYxs+wyh8CRkf4vrsWgdY1 -G1414/NB84OdzieqG5hu6lfLNCr4hB3KtLuXsGttJzgSo/8GaNdaicLx+F2yChFH -uefiAGcE6iVhLR+LoT71amO/0Uz91a+CSwLp6gKad36sG69nTvv9wlayEGXFyGxH -aA1MsdwkpqAVU7roLsPF3pU51ZFsds1aeKv2f+gRDlgLD/Eb32VE9Q+IEYGaXcmg -RlZfkx+x/7B8cyiCyY7szosxDxFor+GmExzBxb5RkLqHUew+soVYUj0nSwYaqqRG -5p6pB52P+XZDGXBazG3lKlGf73bJnQORqEriHHZjIRqGQu0BJC48rKEZhLXBgrEv -xXwkoM16JlSNHEQ5FhFIA5QU/u8NmpD0CCHgBsYDqlPHjm1wwYe6t0fzsAZMEKB2 -Jd3oonX3xRSvFEcvXp06bMc+gsa9eIc0zeujJVvARXPcISyc8chYL1sUJ3ynDbun -h12nRTPU62r4qgq4WCFWSNYAapS5/hjKrJk3q1HastMALiLK2PXzhQbTfIr3GhlG -VgKlBgtcZwXut3l1t2gMK0PF+q3CRj6zLPpQlpCyBqs8YZn6Yj0dLLG26CsV8aHu -27WDGqCi1tNbGXxOfENZ3rtzDbDXkZRuQsd+B7ag6n+SPw+OoeRc87olBWXH2c2/ -Wy+SBfbm0/aYppLVSjbosRB5sFaIst7niWnyZ+C1d0qLBojb73NDBtlvd3Yal6AT -d9/xxB8WalIlMlwsH5Cp04sTBym05RoELeVRr9F2zCunveFg7BSllp+Mj6ZjVCil -dGgurcwreDHFkZpRj7QTTnXJoo6mX5ZxWfODYXmLE5MIM4rFa7NOu4zwzAhs7kWP -A1HtEfQ3u+asuCp4WXsrhsgxDe+G85iqmdHCt+yV9zp4qe9CnPCaojbpyR7lcxd3 -LtFRfA4ThJX9Md5oE8rAWo294JkbhlSztcALzjG3vWHVwve+bo4/DpcbdE1CpIh8 -z3GEzN2LlIRo8ujuP+LpiP4WWMRN8SIYoyKJdn3ZbIWbTZvrnFoLjVoWOh5HkYaK -+ftuvoMDpN8bYhGrMkFT1BnBQO6G8XQobo3zJp6g1Fnp6spoB/mYew/fXv8R68d9 -CpeG5pCsveesBDpTvi8/Mx3u0a8sWwGa0MgaZT71VkQN9zci6xAl+rou99WvXDab -cfeT29gAd+okFeKO8z8VJFSlp3PqiW4kOxvxUPKvgof/JLHpmoQ3da+NGgctlq9f -C323Rf8WOdftEg9u0SG14wnw+oy7dLAKfm3lLaujEXJvQw93nu+W1uUSvrDXM3Jm -s6aywcqtKVOu7+9QfeBdJAyHltILHCeWvvOgUTli1l8ZTNHK4iHJdhxWJQJ6+FqV -0ooJ8BQKbbMn6hKgcDyfvlbMzDaS7+Is2SJPKN/h3G2w8skCdOvSsv7o23hLoHyv -gHB1XMtqdHqtu79gIEm03slXfe5wKIINq8zyYEw2n17u9el/Ru6ujIgcNWz/cV6W -Ba+c+z5yGrGMuaaDvlJwAekopPYVJ2Z7mbiLwaJvR8RcM7zR26wZQL045MLt1UdK -uce2KxF7CII/kHtbuG5te9vWG92kVrpaJtr9bUQwE4+L7cNxgZSlqILQes2jp5rd -Zn/ndtObLl8iGoxI1GrREW3xhHDGitQw+1Aua+9v9K8BndcLqEE78cIV1oa2gD0J -otwjacTQSeSEbPkFruA6u7mid0t/H/yOwS+Z0Zm2SevW9HxVyGKshq8cvktSlQIa -s5ygsL+EUanQL8eAMsIRa/o7lqJzJWUYP+B0t7RgfSV7AbIEQKgXGifIVKP9Bynk -8vLILQ16hKZOkRSKAugMM1GAkpS9TYqc+B3AgG9iP3CJmZLnK5iXpx82xhrSDHT/ -ZnKmBd0lzp+cvD/xTqFk0AdzkjGiaIwDaDuBER+amUH1U1lTQZ0F0VjQR5A5qzZw -7oNKYsX2P8VUav48wU9Afoge+x2/ra/ayPvoGkvTMIrzv5TDVGx6xPVj0PiUo0wt -cS4UbZZQFfQ49RD+cNnmGSL5Qv1FNWLnccIxgWZhN5XUET1Z6Q04dN8fS0e5JxeG -83dX1siaeqjns9cIio/29lPNS8jePUvvPGCRmEWYnbhJkujmixZ8aAXCADpRPCB3 -bAXpqHW+kTK/JGMOoDmFJyZ7t06Geil6sbmFCmAS/VwgBwsO0olJ8uPaOxkpLzu2 -lerqHCCqgrj5krCCjdCLPhcpqHimBaAq7VaOQh+Go+W79RCtBJ60q/rNB7Mpa6Rq -sEvwiCjSfAfsJfcgT24GPQqA6yVznGQweT/+mrHCTd73tN1qW04hi0647LHm2UuT -Ptb/ZqZTE8XuZbyy+ubmQqqoHazYSGrGq8c3fk7crCXDPZxXCus+oi3XuVt5LBaA -e0f16GlLx8mVMTJew/vCOTZgBnIPlpNkRcK5AksY6lwZ+oEh89ndkk6Xla7DaE2m -VHlbOz5RzwP+CRhEf53v1fmuESGr0LxuAtEeEw1T3qWyIRfB00fvGxIvPEUIz0Me -BR9Fkm44xtnBcQAXLCw1zr2KsHnZ8kfsB+vK8Ue9AtdiajqIYMorEL9+8+r484GO -aZp5/znfT8dezRgY/4SGHtcz8Vgx8XKTBfPm9LuBd4PKWDC57eu+fZFGS9iqWAx6 -9jwYxMSCGgtMuCr0OUXvNsS4GwkDPBpDLuhIk0XJgA2He948iF9WjgoocMpQeG6s -CH3SYlgPwiJ1TeNRrkczhiccHkjiRLsjc33yFUNez3nyTAPQZqKi3elHJGBXqV9V -lfp/f6bV6zgrtmfBXYfbpEJDAPfjf12aa+k6L2Gmp1F/bNZNh8Bn/T/bf37j/iCP -bVLZHI/dA0nIo7hllxa7SoL2AYbCB+7BdwZvjEUMkdwn4gLgLnehiSyDBXCU//4d -8GxLaLBiw7kkVB+os+3bR0pOUtxBKjPtQz1BbuNDugDuNdWoObF/Bvqcp8bWRUux -u7riCbISQDHfxqz4be3LIB25eDE4tLVIxn85jH2zxN2E5V1mN3D6XgvEDdKs8vSi -MOhUjiVkrzgnuSt6aiWhgs5u4rAzmZS6yTHKoKKeUvvbvOl23+owya+Zr7LW698R -bfaJYP4geKWRm/VznEkFBEDcnIIBncrYeybz8CvwHpf+6ldUEp0Wu9LPA3XlOuq1 -/nqt1TX0xmi1lOu6MizG+PQFWHDAqLDhqkxqleTpp7RCmJ/FoeYihdqvALOJ2nwV -5fJCO21fXrOvNx+u0F6SxolorfyofuXS1pVx5HTiwtp1yeMy53gnwJ4mRMZnDSl8 -qP5MzN5qHe7Jp1Xe3qXDZJNmS886RqOEAiXkJ05QliywfWsnJgicexisweMjpOrh -SkQ1UMamFC8F3aq12/iSQQQ7zQDS8Ghdp927g0RqDcc4f2RQb+llKU1JP60eUxNG -PZHGCCoFuz815vrXmTjzEU3+J+xdu26rdEQUpDJX0saHVjfE+Ekx+RjLshSmrVNj -6jkLBdnCKP8dppWA0jZOAUZBJg/vbqLfk75izE8VB/76aUfwLqizNO9MzBtSoulN -eckfWRySpM/MRdgx1A/nowGl8NUB1hVR8FvJ2N8T0L20EJraYx4xxqa85rbNxJP+ -F5q5qeaMxSA5bq75zyfKJhMyO0DHS4ynW2+Vjwx9Ktt3tVFLgayMxjPG6adANGqC -ueXRHDxODkgUYgq4IJog/2Pzf/ZpJe3g9u7yQBREmbeuVlw+teL92LHvYPEXUSt1 -BZIjpyHPcbCuTctQWVtAL+D8lPcclt0lw0ja65eHGHeF5/YpKgltojZaTSq7oili -PVfxO6+eIQVUTHXox3zsVEdUd9YeMHKdgV4aOGPq4RBHSw/RFck4zO5G8teNsIln -ofne50KBq320kBP/Vr/UmMwA3eUd6G1fzFagpeze4vQh0c93xQaVfSFsPfa6R78s -YDMrWJTMdI1EHOsL2dRc0GHuxqrbzKDb8gP5FMW1Neb9v8qQz41lpHclTSPdC1qf -HCMB3iZMJBlDEy6x4wjZzcXQol9IMtcwQl4JDcdokHBu4XTuJZPIW23sgOzQF6YJ -sHGRxkguP05cWS/BltYqxaMCO/v8rBwjds1VHqD4Ia6lMrwVUZ+8IzdGiOZclUuh -PyvNMyFSTvFimBF2kJOE+TCwuoPxVaqugYz4ZieIOx9cIj/3hBc98MLuFRQ/naRh -Qft83iaO0RJEooIw1ZTiqSo7Uh6OA8lTK0DuDJAyCKKSgCIDvbZA4fGRtLDI699A -A0BxwBnbLVaF5HGHFHeDKYYWxcvPuvh5pM/iyrw/gQ8NvhCuEqnQo/odh9hDYXxh -hQuIcUe4q4iw843RmG86flc9cOnt7z9hSbBNuv8AVG6bPidthpO5aEtSOz3ZcvKC -M6+86A+BJI1Gf4xUzLSAXVwevY2vjqMCU5rKPtXL5j0R0TkqOrvnjVY8a6gzlE6V -nBQDpIw3gWBfkoaGUGYLMJqqD9PpGaJXYgd2zP4/fyoac5yvRegVKrRpB9yXM1I/ -K+KPAIKIW+QghtuXG85ywSOSu6SuWTcBMyDtT503o/tHId5xxgpDPhqbjVhbWmpb -TYM25RQ8OS9QC7KNSDV0Mg3WBuImp5mgCH8Ho1Yh+dgbc8OIQ+YrHMOt4b9dsjgo -RJd71iTCka59WyzGPKNpFKOPeEU4kzsis1S0jrAhujlR4ww72ooypT/2lq3Q0ZP7 -LQRexr6Z8/bsv+QGJQPiXA57AKXb7M4If/nmNxKMz/Wx4hKXuJOY8qnON0aK8kMU -G1AS0kwCQITi0FlTByk/ACYKrQ6E0KKfhmQwWce0Jkhv063xAdKPk1qm5Kyeq+o3 -8z6uXb8H2EP7m9d43M6PELKf/8ZKfSSnoX78jygR7oReFlvyGEaYeBgLw+cy7oYz -fEq2rA6DU04jxStP6z85kuN1f4Od6Srb+2spfEcfWkyXZ2IAoyudXWpgprwHldkk -l1/4ZL8Mz1ccEZjKRjuo6GYYBjB6gd8Ht5tOsTCdLHLp0G8IwbBO7klM2dnnjDOg -Wau4JmbrbvhKxCq8sKPFfNRIyvB0H/iyiGVU3FqPmK4hTNv5s1QYQJWW9BDNCKoY -ttp5K2c1KAovwppOQYyu0kljWspptQ+A6w6LhfxOd+5OZ670Y3loQZykiLgCkRIp -FhsQT82AKqCQJgNtat6Id2w7Usc16id7RyaRWpTFI5x+qX1t+HWXluVoHjSOIo9I -CSgPpSWgfwpaMHdZpARWHBcc9fC5JovVRhbtfgS2yGXPlsgbfMdG7CehPQE7+eY7 -CX7XwqGLcHs+Xq1EeXzs3lW6f9c+pU0JsUO729wG/TqSXj01pp6snbiyqGtsnSUy -0lIjdqZ/YcjKAzE70YIlvoExUPbvH7WQ/7zf0op1H57eG+ZPZ0oS9i3ta6kUe3J7 -P1SmdDpxhRUrs4n7QbJZ3+UJOMHqYjOOvzCDvGm1s4aVjX119OdYJYYh53hVPzl8 -R0WGnYZWjUt3P273OquS/CgtfE3sFwgGDLDDY67x9aRbHjDT+yr0XbqA3XKskXzH -M9UcF1Adox5XU4MbzFMgmb0vIDjgY4kf4c5ovL6p0D0AeFEPiu3vHo0cAhDX8JaZ -SmaFz/Cd1XXYGQynzJBwfI0xxfM5cBSJzjNJoZqN/jngWfLu6N/QuNDB1onYZXGX -2jZZsEiBEQIagqnhZCnonVHbcH1EkB5ahYN4RSNRxcWSY/++bUMqYPMz8e3w9qyv -zqP6FeJUJxoByzSzNPh7OHUSxgnOuAF15CCfTcAiaFCdjFAe8eUTBqC2bq4S9l84 -KfPb/Ogdbjqhic5mTUmAkkketCgaSqc+xFoLAqA7vGn97qcH0j0ifNDe9qvVm2qO -ilweigp4Pe1Rr11kDhHL2u8q6op+zonth9IphEp898gcw2obFURehp0tpeahKuan -olYjx/EUCgToudW1VwtyNq60XYGpyTesfxyz5uB0/vh16zgjKtosSmia28QWAYdJ -MFFYsZGg3S14WE5oQOCS/Fa0k42LIMSCtoqoQfCwQ15DYZp/BJ1i7syOH5/4FR+4 -YIrAkpnQ8SF46cv64KX269FDt8wNKmjFP9GsRiEkIlAvkLiDzT2tEJ93cSKIvdZ+ -+p6CKeglxzj/zoi48lcoLUzbnjUF3D24oSpDoZ9C7WTkLbWS7NQeeEjG+3f9RGI8 -yYekx/swERSUYXq0BJU7jChqc3fmaXcFnYBBFZ6jxwj/K4Oa6eJle9wTjgSX55k8 -SssdRV20MPtRIYmg3vH7oQwra8ZKisDQsPw505pFxTeD7ovF/fkzK5WdYLQ8qQLG -hDxHsLHcwlYjUBtKDqm2BYU6AK+DC/d+8xxERvMSivBJdemB5b/JJu7n2QJHW0Qa -fmW0NXGPqmsct8orHxdVpiT200j1gBAeABgFrZOFjzguB6jSwNo5hMSqKgs5lvix -mVY0iSEqq0gqNhwYB6tvjCkHf1tPtDECzzhMC+MgPaCyx/15L8Z9aJIqm8jvwXkQ -SrVD/vKNUPPPFcT3qcFJJC6VAn9vLx4AixrLybSbcnqaLM8gWR/Mpb3B+ZKqWOT7 -+fNapqE2P5RzCbefh+t1aq6Z8ewOtbMxn+etunT26U4kYcfM2GTEGdtBD8snv8Ac -WL5Sq8TdFcLGJjqYSCs7pdRtc+LspYg/t64jHbuO7ArmB6HoZ7Y4X4o1cLNVQ/oY -0KPJxeMby2BErK2eO/ih+hCB7oHs5LbJ3FpCQRPftmhc8RtP2ULl49bL2PIhmkJa -4sAVlqir4Mex/cRFLdF2lBpZsqu3zHcvnplwcoueJmGlgevG3EiiCMktCfTPQZxW -7gk2pX8rMAV3O3bSxsCicaLKJlPLs5sWnSa+8ZWjCr8CwJDDyNl7SXC01JCyoMoQ -+aGqAEJicNTIhj1aMmf4L+0ALjr1V05V/kyCvMi5OsibE/reDIeU5FR4BDU9JQiA -ac6Beeuy9d34ouXwxfKdsqVVnK1u9uC04DG+J5kjcX2v6hxU4E0OPTnzA3uEJyBt -49ehE4T4W8F1PkhR5UISOVInwCSTib2oxgE9VbbCIrJMzITOc7yGnAJ8RqxgTsa2 -6sUk78R0FEjVvQHkbzze8z1f35mt07qH/n9ZYNaH6P8I9Wi/jSuENwQR9ip+zqae -LDcAbCbd2H/Mn7xZYXqbhvVSz0oEPnLIcR6Tj0JiN9a4rfFnjUptQ1S6B+ARAla4 -WE8VtvQ18F/XO440/UrIPTVchBdpCA8k22sjd7La7TYTCMfDPNmB28o1OIc4mjk+ -aOLQLr5g8dYxwWux3zEi3wv/JXtgP5iJFnMNPSoZFuYFOSyIWwGBfRn8PN2AW9sk -vNZRJphotvH6iaX0nvv6TJnrgHsMo+EzwkGR/F1GqpYYBiCeTpfuS+G76pPjeiPC -H+JNkiZDaMxfhFmt69tTcnHHPzSW8QanfeLijKxvl9357r0vycbGT9WyvhuTDZO/ -wWDy0xZ/rcrxohfcBBAx35BuKt8fxmlqvO5KmvwzZm52afFGYYjPAf6M8XCT/9Vp -JAiHCyUA1DEZhhD0Wx1jwIwkhdvf+PP7ipg3Oz0rI7SDx7+yefEpdmdtUcnY0lwN -D9MS4srvYIxG8VqJS1NQ9RHIeiokGcQ9bzytGqLLRAe67c8yNKg8G/k2Cvx6W+Pm -VlVhO2LGleb1pM7PmxLictijN3JtUDbMaxCsDVknUJPU0kHKdinjDkAi4InXzMHZ -qW5/neqhg+QVd8FHYcqqKBUjtKb2IgCt4eu8BPAh9zZ5wWydDr0SEUwuwIIO6H5M -pyINX1xdm58rovQeJrK0rxBCa66/+k0I7tVP/q10C0Me7HqJbBep2UTD1shF9CiU -KMoYBeVKmu7gIHgHG1Q2NvzSCVJTYxjeDbT2VxQLHdcCHL1fFHnly7hhmo4ytApp -cV2b4YZxwLKXaNahrTobiux5JWt1l9vma698FZMKxkW2puybK5WEW/QGHvito5lu -BhBNJSOtBU6swckdY5odcdVUAZ5DwzH7g9ZkAH7i+3Q4CcWrMz2WUHuX6tvNYHH/ -R/dXXN/nGg0wCTTLgp1B6AxYhbzGW0k7HhWlIBlprTTkigzF3g1U2fXIewjCEtf8 -vAJgDvaxHawNSviWVhfgcZBGuIBBS8/5Yg+u7runNSOvjTELm52RW1ehszNbeQ9g -dd0413RyPAKIfnc047L7zEMnwSDV4HrFobllkqXIsArJ9sOFTCk4wTTjEqGmymr5 -izxBmr9OSNsAbmMcga5ueR7Tkyyq5+plXqS3fLO40vLnltSvWKTA56aRrX0tP8Mf -wfyhfwFjJnCirGcW/i4/+6sOKzV5Os+oBy67q1WO1C4hWGqa6slrkPvsJuIrMZiw -xO+5sQcBa5LwiXUVxi8xpcWwfWppavjuEuqCyseaXirt8nUaNnJGvCXFrXiWM0eI -Qj5m/bptyKLx1b17lUOYCanul2BUBimIBIKf9OSUj9/QvCH09EvQvHb7zKDvdQsp -kf2H+Weh+XN4+rePzdvpGShFXN/udFiUm8PUmlr2RTPoCCrCVYUmP4A5kZbz41ZU -rE2efWO6fHN2T4Xf//9tUO4GNbPdEnGS/sYIe/P2LUwfFy5AKP5ezNtWfAcLPL3K -S9Fw2QeB5a/wb+NeEPZLmOHERJGzJBtHvYOMOZIY2lKTfIiOEfYvoStWCEI11q47 -3wK7wq0zrmUI5ROS0ODp4OIwqD38Soj+je9a3vPixYQDV+4k4gFKBPKZZXRdC65G -pWNauAUJUjMSi52IMlvNKBa3ATf/uHQ17OITFiBmlZJfBQY4EUjINXfwMJ5Vl8Hr -qzN9ja2OwhyP4RFljyFVlvFI7c0k4pPUW1e2KBoh2jIqZ8c5sLn1Kk3JdhpX0OMw -mMlT59VcfJDoZm95PL+sW9/hm6m1hYjEA+zPnhAegQh62KazYezTRIEo1+pKHaJ3 -UjlF7eMkjeO9/IIGxHgMLwZKuNf8FlmLESz/PP0+q/KwiHvTxdFpq+1aeINGI2yT -B+qchtjmiuBVNWg+Hl9nqew2v73fY6cAULSLcRE6U1WVBYaXmqNH7bvgTn19L3nn -7pitinfjnWxtwS0Ls+jFpkcj/OVvYALTFFx3plfo1zdBDmqFnokelR9uwe64uisL -y97p9c2iKBJig8ouejPqI9FmVGUurBfgmrEtI4lXflzepa1MOIAnyiswh4iWfbyW -qGvVSh+Hajk9LxniDntiCCNCgnCpsQ2uqvp12EpJ2aEJVNv5LHoyEv9ECqpLsPtj -oCIrIdpp14r7C3IEjYG21jI46avGhh6dmNfVQAEdzEPQBCsKui/JuFumevoACiY+ -Hr+We2kTlgMcBJbhNRbYy38ej16u5sMytAUZ8+Bzezp8hTnT/5RFpnKEbImCGsES -kogJkkojhLw1+XnVvFjJdEOjjOjimZZRUVOToGiz5hHUPGg5yiVIQxb6l+xcD91F -kzj+SwKNhSHcNp9EiJQEtbL80NsPteauq/TeNBl8Ar14egIgxxQqdNAfI/PflLzX -pFZpD1XSvz8UpHovy/s4jKmCH7hYqxCfzAbREmW5ur1JP9t1Qnc1T0LbDXIt6Nor -Kq3liP3cgaRIqG/XPtNMc+iKGKtLOIDoZvxQ5OftpkdmIPXP2psMV4Ue1AYXjJlC -Q4WAHs/TUGC+Hls9FmGxw36OVkW0JEej2dGiYPQK4mxVUj+h569rhf5jpWDfWpnq -Abm2ckq9n6pJeI4rHzV/hEsFX2lkSBb8zgVA2ZOEIySGX72pEaxtxTSRUvFKrynq -HzpLYKkuaKKBBvzkkxDwjpg27JwPYDPTtAP3R6vc3yHgTc6Vj6uacYbvTqhfo/3e -MiegG+rQpq6cHIwTAtLHLOtuoCpE/JtdSc3kqvJejxpx9m6sfc5RYGAwu+gF9aPd -evWDaibNFtoZ4cAZlnFmzHN2iszwDduxdp4EZ9rNpSPd3NKrm25pq/UC+HpsAoCF -VTSX511E2z4QESUFB1g5nFR0dUJBiGyMmXEyqCCoxc/FUpm46/NEjy/oxSmLWOh0 -Xf9hvBytN+OaOFHzQ+NvOLxxhpUwXnl3K6IYLM7sGV3sfGS7GLJC0Xmjk99fOqzQ -M6peZBgjBv4XmaXUFUZiJXhcz2YyymcpX/kkVvLfdai1rHkl4upocdiLnN2yy9Vd -Iy06WYeXZrOqEjki6k4EycwDUTv0Fnw29hDd4XbJdmJSLQjBogEWK3rXn9yfKzI3 -RELT0/9nRSv9+gR8gAPlu5q3u/kWb1GpxJumi/+KS65GvdbhEWi+me7Nb9U4XNIf -07nHm4gVQ9mJb00Ra37oEw== +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 +JlNlfwJg26XD5xeV1r5DLA== `pragma protect end_protected //pragma protect end @@ -2972,412 +2972,412 @@ RELT0/9nRSv9+gR8gAPlu5q3u/kWb1GpxJumi/+KS65GvdbhEWi+me7Nb9U4XNIf `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -eJY354oGrGrH1GBRkQGOrcSUNMQrcSls38RkI7s+fz9DkocFlrlbTn2+LPPuPD4o -KWVvWB1CiOn8CL6k1b9HLoNEEk8rE/SrgpOmsXS/x82ywM7wdX80Xf7GPjA1eV3/ -63DEEcX5kRB/NPG6MTyMrlVsb+FpSVE7vY7mrKRIf+KaRqATmGC3r3mL32MnAILD -lnJiCq2bJUZOMXt0QB304BetvmP/JPF3ODrozUO9U2PU9vkhyBYowFBWTpZNugqy -NUBAMAykY1ijI7ZU7Lb7R8YEt/D8YmxLlSNUu+CaeIjxFq4qlkEfkGkexnxFeNjT -hr4hm3vO+NP7F4nQoQElEQ== +m8zQ7sOBnWKqiHsA62YXaRT1XaKRgBHbFdvDVfiNbhvyTitkE/GnfunamJg7vX+8 +A6OgV02VtKKhUm6inN7j5ZfdLsphIzI9y+zfVTuxInua9SnrS4ARdJt6+G9hVkYD +j+S5PDLlpbjywBZR5tRHCW/sFRdMjmdyc9HyT+u27rlntbZurvNvc3FOvaNMVW0a +uSJP4ZIpA+vlRG4XkkskySo66eLK2XwjqLhjvYDzBafWJh6UEjEKo1XBXjxLVm/c +vFIAZeeo3jBW9njjLxTkam0ilthxAJHqGN3u6W6LMXwnzj4x+V4PD08HL954xluq +hv6zwVQtIIiw2TJx4Q2AEQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 19056 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -3395,776 +3395,776 @@ WeZcIwoZYGqmkEDX62yI0YYL5FuN8Qn+6v8oLLUhkSpn9xDjl+sxFdcALkJTbvt4 `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -jBEFxFQL6ULoswbWaTUWJE1/p97+bhTdV4dNldbTsTlU3Rv5wVCNIPElU7XM82Pj -UeVkM7T5p6XcaT3XT2XxqttUCxQEQsbhtsuteAWJhD1yekbaLaBnF5xM3VXDEX2X -M6qTAxr4BPwNiyef8gouRk/27mvTTT9Wwkn2ZPRbV2/DSMzcNUtb4t+X6w0oGldB -NTAlQZFEIoCWfkNQYNcoHTRIhBu8S+d4FT9lZs9Z86kTXU6rOi4NfDGdkA72NYoR -O1dfBB6hUKUCUbfSkDK8srjvWxLJldzaeu35a0+BvHEp8GLRrvvM0OjrWCVF0msO -QcpK0of6eSPUxRQtmTkzhg== +SZj6J8FtLe6cJ0AGj+KDow9C2ECmGxXMhFK3w8kOOiPB/9q8lgPgeBzDFA/kQvwt +OYDTJFd5zRv7gtXhFucJfuPQFKfoK/2Dg53kVRFK+pVlcatcAtwCryhgr07sNHSr +KMHU+1aO8khJO3fEK6r2T8OolUQ65f0OoCSJ1/WMdNlZH1bVV7RbvN64zWuwfoRg +XYEjk5LkVs8jAsJS252OCo9ELjbXL/R9aVMgStk2xFN+fqcyPaKD9lxC4Z5fpXXS +5hnIHY99pWllVzGmwIm9q5pGWm9jUnJLmmsg2ul3aPqKpFGJWO3w+7z7ljX4TmLd +0bhGvIZEMfMUuZBDz7lPyw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 36512 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -4182,158 +4182,158 @@ n6Sw/cyjGj97pCIQYBIseecp2QiLAZOw2tlGU3CTQRQ= `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -EDHBJVVglykHvqaDop0DtxsCM/fGPf3IdsKGLwL6lJ3GRgMv4miM0thu7NvHzh5G -po9Hk0CPAO+zXnmAWFXhhJIU+xqjEG88uVHIIsxuWbd6gbpswB4rnHnHBGr+lifj -1HbS5UxTucZafCSQalqh+M05KiOr1buG64fV7OurGdTC0yots+rZEWgQAQl4udIR -DTOZWnV1w0Qz0ma/8Cd+8K+ot1PeORwmHo2DdVxJBC8OVL4AJc4kAQ5wYSTdFjJa -Up9rSmSlZu0152Yx89Q2E/TQEXiSclKr+Y6UD+tCcsOZL+VRayVB05aYXX9bugFa -e3r7H8Uyw5REiTCwQcwbEw== +E2SFbCNaq0TEuS3fXmP6CZgrgGsaNpVBd2YIDkJPajyhmaVjofF/LBLYEQPPhK40 +UkM62YEDHqDPX6ZGCwfRXP1Cso8ieIlLRbL6wj3Ab83bl7/EZEDjks1HbtKwIvUp +M+ryBC5DfH4Ix0SubIfAXdbkMyB6uw4O17ffOfub3aVJQpqhP9RvQqdE0FYdB/nu +DjIwQbzr0tJ2si/K7BGhb/b1159MacDc3/UlJ6YMk8PYOR6KpF1BN5CXJg9A3IzX +QH6gRP6807lSrjZn+pu3gHNENEF16FWiIApctPPdA17WgKCSw4VFu5EuYgv4riqr +QYD9+VIjURpbPE1HjHHuMQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 6832 ) `pragma protect data_block -8RsZuuYdzB7OEgD7gP+/aLqILk2MaBKiFbcZamtzf5wpOl0zLYvJ4fjkkuFz6LI0 -5TCK3RtnLOgd8jrCIH6Pog8z3P7glp+hYa6KEr4XM0MnTGQXvhYTo47W5cg2RnyI -5V1okbfYz4moZhOXMWRvz9tZJnzqyMxFXPrZHkCOdWJ5LHfDWGgrXq4j1tWGV9on -CD5Ybe380gdGq+8kLxCSAgVuPdv2N+L2hF7Y26K4zTjl2i2FLGd6tD9vGpR32O7E -JgpZGVoN44G894gK7QMTpThN40FpFnzjkr2dKucjtefYwv5pw0vh45WEsoRMg17Y -3fZ9x2WxPsWv1WfUH0jSR3TddyJBxEUlmYH/I2XlNeVJSKEvvgx2ShI/0pifWoPM -XNGrFyRweWiw+awAO5F4a77Yl0DjY/dhgk840MsJGiyLj20djGzgDnkYsP2vlR+x -VTMZU0X+P0t60CBOIHJKaQU08sETFBSexK2U3bbdv2d87tZ4JEmZSxvfg+pi8xSX -oAqeICyxMM5wanCiGG/7IoxnGdOox/aQcXtK1LKC2wjbquuvDd3p4eVsTxR/Gild -lPLMG0BukhHyYcNCVhpf2/KGSAgMj5fJTvwL9xWdf7K2clppTAXj1gABQd13c22M -q0vtXH2Tr69BaSBbVNvUYk/3Jg6gQO4qF3QJWXi4QwSQkdAZhrqxHPNxC59Kgm37 -Re1Qc/8JO7wcrRV020aS1Q753LJrwIL4yKYqufdmFpjOGiKqPfCK2MEqjYjMqfsA -iOAanqR2uZ2wB00FeUv8fxQqsU9cqOy4CC/Nj1N4L4Eq6BiGSEynTpWdMTCURlUn -gWXm6WyphEBr7cnNyLmZ+ZrFWj4S4h8N09HXMC6CBeuy9O/vHSsehCsmBwMN9UQ5 -/rcJh9DvOu7FF01OCTr1pLSzg5esnhvZeTgYkOSARsvEd1PnyvxQycKwZA9tzTry -vedIjVuMpdLENKhLSnuyO5Cikc1vHT1zYDq76yeLM04w6uIxuaj4Y56ucB3BP8Y+ -7FTfXy/4w0Ijit1OVCsNDapMElQ4c/TEhaApPUpvzFNpIDqxkEg7fgEanGENkqgc -81mLW/a4zW5+E6iEMLyBpzLZOPvW68Nrbk5ZVQBu4hg0zr8QSqxPWX4778fahPly -4hAh+O59NkSonlCKcQj2ParnoFxYM8Y9egAywfvcsI743djSFd3oAj1OY850W7kg -wdFnhh9hQdBBryIJAG5KFRpvIuWzBOWkkz+UV3gb8up0OA3TK9+x1x1NCJsAeRRc -gL2I1s3s1q2gRlrq9R/VOWbl8EjbxpfDcBSV6Rzn3og5m57EMMzhOu08D2+Z4yY0 -WRqv9A0Z4QXJigaXV+Xnuiz0lGTTHxCJJy5qJ5dxenYRnz9k+lJAdnaywQpJQ20M -QgY8TTUABaVYD0zTXtPRT2DOq2cjcLAsLeDCpufw7ypOV9xSJ1dzDtw8mpNjKKd0 -5g79KaddnGI27ed8ka4XjSZZ4O7lA8+iqwg7Tfd74SlG2gHCrA5fLm34bMRTpoQN -9ie8wg5lT+u+wVsOG0JrkyXEQaGYlCrRB8bV5gfvfLVmbOHk4Jt9ulKqibtL51QO -EfcIgL5DRXdodUFbzWSvl2e2qxO7ESB6AQBYbJN/8MYY4JjU0D6sdMfo2GJw/7MQ -xDy9BmGRm6LHFgVJ2W/UH3/xwAggOZSfGK+aHrpPTWDR3f7VrQRTC/b4uRJjVM1W -87xUWKhM1KtBrb3sNeGf15Y4baiUTulpeTkDUZEgPI9Wgp5tqSxxMS8Fipj5akfR -G3GwhOJlKSKVMC4Asj6oNYi1q8OuWbuxNk2A0USvdIdxI0dQDLmNCDnGIPx3ddkD -n76zlcTGNYxE9exJDoRo68QmRMdVNQovXC6Mz7rD8r9bCn/qCeYVvojQw/rVcHJV -OJx5GShEmxK0wZZK4hx7vSdN7QIaUFIc5VCx5xhW8O1RstmHbQ2+VCIiA9+xHkov -QxR9I3gaxR4CnW+cPGIi5AHLVXZaDZBmlnBuqtg2N47/u41v80mfsj69VKn+RYDS -XceManu2EStM+0b/AVUvOwnT2pJ760z76w/RZzrkQLkMIVII3KeWPRyFZPxXn/Sx -JDSHbKSEe+vk9orwzADbTBhGX4fHyWxUXWvbDoClhiuoz0qv1RQP40UbiiGo0WAP -OACqec5CR0otbCq5EzW4vah6sg/qS+xvqNov9ocbSnFRM+M/f+hKH0t3zrgZhHfo -vKim4yQ3JqMKNAWFatH2l6eMgUB9XKM1ytQ8MjaxVA2vyHvOBPLXIsdfszi18bNT -qNQYTr8jOAdS2kcfUvDBSa8XFaKqMHIVIiJenzPH/A+RtthiFnFqHlOvvsGywYua -ruEanRB8tfel6Yp1t6TXk9MMGlxiLrG0ntQuxF2/kq13FcDw2mlz3Vyn1ci7QCoi -njeNWri2WUE5xyUfPsk8bzpG2vHgxpVcKK8IXuh41q8YqgxMcjhkelyWnQW7AZa9 -4lFazRPNRdDZZMrT+1/iQD+wTH46DW2uggB1Eh3PPNgRLPURtsQD189a1Fcm3Rno -mMdkJecZTbrflWL/Ie5c44+khVq7MOb9Ta1dp4LmbVm/3mdgtStZFF1uror1i5eC -4JNvdN3jCIYwNK9SwDuh8MrlIobL4odyIC3CBBxSl814L83bhHCnC9Se/DZSzExO -TDYy65BkhOo73oKAdYD1C8rDtehBypvyLAnNiTa7wGzm/IIYVyk1UIa6odWtozlb -Xd02Ws4LVFNwiB5kzfq8yVAPhapcdiKlPfBi3Td30w+vauq0zCgtHCb/mTVxsXuf -GMT7vIJk7LEVglz6VR8HnGCYPIYmyLGUbqOe8R16O03ORq1o66Tcj9D2yA9g++J9 -Vo47QRMQ8JrJZGquRnX+ZCMNiDDOnk80lVpxulp0F8ONV2c7gXEO73FRz8P0NgfF -usT7mFPO/UHyYP5XVgn2fRZaM0QdckO93CkYpujpwyW0Tv38BJMDzmeiusOrWj0s -BVwI5yG3EAcAbbR2hpypXvgU4yOlzrwfqE5yLHS7RHAStM/2jgwXaZPnGdeu1yJz -F3jZtuLCqCLWtmYTdqQZ/tGAmXjLmf1Cy2oqyL80TdFN2OOLtfyQNPZzt03ia6Nf -ImBWscWosbB8wVkjKRh2+ntmGeJE+nyqn/Z66oGjaOFPDBbbfbqNgbpEvaMPfbGJ -gIzRbN0zK6XIpLdoXeQuvGL/E1PHtj/uEAOwjKp8UKrXdYkFLDv7ekbNNiwkJYWF -aCgzTxBCT1UHkOQeqLqfF5MVVOq3guVc7ItFOvMnnHUL+6Ox4CnVvUQsqc95htoM -EgFP+MQ5B387bO0E6ZmkUGGmGNBdFLH94aLaD6FbocYrVP/DVi3VITdWw0j44d4m -QZ4qrSiZ1HkJebjg1yPt7V7GJ15FjQAV3sVhPdjqxU8eirvGLXdkiL5506a5dWum -CS//CqYaWlF/iQJY8r4R3uoruVfqxTLkjrDK3xb+NqDjSjLMI0Rtj0j5ns4DSRv1 -7Ws/Lzh/HrjlNLyeFYLJnSaq7mQa6JjK+i16JmNhd9WS82LhWLEXonvgHzW1t5jn -VB7GuMVR2MwS+DEMGVOG9Bu4c0I201v3WENd+2CzkYemoQlxLITGaZmcV9hhJsos -Al9S2kfiqD+5C+o5bmkgf34c9273VQbkaN89e4tiL3npSYQ7x9RM7kJPmg4/K6oc -FQJmzEsF8z07/GUTrG5fb+N1kwWoBV5lQsm3I90vSaEOcVLDBfjWTHNhq5OiC3Sn -nnIj/ytFE1lpyYqUz7aHRNxHtKyLoJ+eSHvJ6GbPfxqulYgkZ7v1Ag9+/OpuKoyG -bX8cEq9Y36pvT6+oTtTqBSzMtcGn5E0ZCagMv6+Vw67Mj5uqd+5d5f69d/I8mbY+ -8gaK/L7aR9QtCAh+3Q0XJWT+U0EyT5m0bCWuZJYcN/lwOQ6SgOIWSSl6zr0PZay2 -NYmLud/IMK3+KyaIJDRV4jiW/61yMnIuUARIrzIz+gD+Xoez2Jvazs4e/no/Ygms -sqDy9L+bZOGQaC7xIMOJnAYPUrAZc6nuUaZgBXzxDSk/rNhNn8uDwTKF3QxoIZ2P -INgFrwh9rOHj5n5A3s7HwDoh8uMGSj2GxQn+3XJpdyIGjJfzr0wHlfSFmw2sbXM1 -cRrYPhUMhJ+WPhrKrrPBhJ3boU8JibOXW0Wm/1v0qAzzYsB9P9md3Ne4DBnvbjLv -2B850qyzQyjU2SaFuXR9U/oxprKQR8KHM7cmZFv1+e3pArKD5wyBIOVCFSCsFqO3 -89s87wrDR865MhmYo+vv82ffaNw4Ox2PrKa3NGSr3IcbaIkpc6TDExzt7KAzvecu -nRaspi2SB+sGqs/WyaPMw4vf3pxVmti/nv1/fDiRQBX0LtlRgzG8LwXjCgL+cBpP -gt6VyAJ1vmag3PXq7lrCOM0h+BRPmMFNMPU7cjiYJJcGzNa29EKiYgyuNcFivdBe -9XQUNz+ZoS4Upm49ZXPhYIEKMV9w32PMTKV5EpbCRCi87wKqbK+0GyO/+i3RUpHo -izB4n8ztBKdzEt9oTfQ1B1JBkklYlAVeioLVYDglgRdr3tJ0xXgbA3Z/dy5aHwgj -tcsgxN5e0QJBG/UzikvhwNLBMc5zy7QxTfo5posv59aEPkSkPqorpeSJiOvxXSX6 -ox+I/kgQ6h6CHXjJpXzqX14XdFmDPKr1EG6cnuMjrdqM971vQeMzn3fcpdRtXD1w -YHHlzSzPrHi425lET5wq2RGVCkhIGAacduANHfiOLuPPJFagPLQetRu+8OiCg730 -LVksyWsrTPnh+Gj7ukEKpveLYj5xcdvTPIRZzsfISHsozO0BWQegKPJSQnb9mI5c -USDijZyhdjiG0M0iMYkkxXef5Az+EGjyW9uvj9OKrQvElAMi2L5fX1qS9R1g8acj -LInnYUKNKtF7v8mZg0SJlqSbfSKP5m89qsogofuOzt5s3lztLbm90Syfbtf54vcp -xoknzNLLh+qJz5FhFLDZe/qCUSMmSfbRKWYFFyKNeZHRkBTBi8utbZU2UVtFqo+K -Y5K/mPfquCsZg/mi+tt1AFeTVFo9adtvwETiwlF9sSVaKgxl32HMc1QlZzefEh/v -qIz/ajTGYLAziuyThDWDRXx7eFjASMss+1EMIK5jYReDSS6b9i18yP1GLZRyV4UN -Vn0mMmZDV7i5cxFu4kHQ1CJAh4Xl9MLbjzlnPXvBH1qTLiR/IlJnlitmEdRCCR4o -eXPmusoHd584W5yDeWN9cqOKQLxxmBMmUUG/4Oezub/F3jgJpKWrA+1iO2yyDAn4 -6NtR0koOtk215qUeOyhrDcRygyKaOfiTVXMpx9EhA0D7H7tf+HBIVVzjLHWRtX7x -Iyh/MtHgnio2Ofb7/f8FQmEjHlnhjzZnLvdLx+tSJPKRsd5DIkhu8ICS8LqrsB9U -SzdLniJ1+mwwa8Nj0exY+CRtdSK45tEamayoR5EMcuPX9nf+8RhXntEiWt1Rdg3W -GSmCqVtJOzgmB+kaO8dZbb7xKeAz/+tNfm3Yv5oswRK1kYxwauYZHpawea5VHn5b -PIcwLGa6LMZ2VxXGqG3lUsXoy3KBYpTdkAJL5spcUYoi25JV5nJZukN5zp/da2kK -R5eBuiw3KVk+bn0qUYxcUCFWL9Qhj6OvJIQx46/ekYdI+j0jSaN0NGoBXgpld/Kx -LIbi2qjmiuNrhuD02Mal9G/qGOgGpjb4lq2TvppPziIYbn0LjE0vsYmMRutK+Q6K -TJN2SII0n1kY4E0qTd+uaxHnobraq6a86/6kRc9jD2e+5Hh3Ytea3E0CjcZ6pr5P -a651sawrvKpvle+l8+DSpE///fJlk5TKNXwiKMedmAfq3W5P+FBWYxre4+EVcCnk -1lMHoPHztukv3UrGSGNMIJL5VRULgjb6BKDq0WVpFY3qG4Kp+K+XthH369SiFe0R -fyCOQYMst4VGHcYah6aVs6aCqzVHAngxoovHfw6+gVdEcg6+ZL3uQkFlHUkgHk8P -99YOOsxjFgjC5mzQs6AYCPAVleQgz5j9dMkbo5OMPIuqrbFBa4f9MZHjALp4f+gi -UMN+QqabmsJsyOPvXdVONGe707nv+iqag46Nj/OiTgNFdtTD8zwDn7Dr1hJCenBS -9J9rHHRHcFHhnqVKHLDDTvOjehDA5iZwKWS7ISdJA49FU30uefQYgTQboiNgh8Mc -vHN9cJEqBpdjC5dPyuZDdAknFS8TqAk+6UoB9c9dqUqfB205gfPnQoBwgzc0ePSh -CquZLP24+NKxfpyeF+nD1MpbNegG8PZWuBa0xaYZ8B5/l0ToXK2XF97BtXLhJTyo -hsr0tKXJE5hAF81AWjZxzxTYX8t2xKzABen1lS4D4IUoYs4RkaSvn0kHf3cumPH3 -wtQ9dPW93+9hLMR/t9MniTwX+Yeg/4WfY7AL2c+eVhqmviRBaBb20F0cmLLcaeLi -+5cb8aXAu0ES+rSre1r8GrGd1bf4AJtZ7rCtkz3S0Y1jAaruBekLRLZaSdZojS1V -65drJx2PUND03KtalMnk7Prg5P5oOH/XjmhNhh8YAS6Ng7jlBPUdvTqTEFESlWzU -hrvktvSNUMQQCfG22SViz6b4S1lrD0vzcaefqQt7wSsdXoRRiJy2rKpJ2VuZWx98 -lxJLY6M8QrwDo4Z3nTmmC86gklgioCnKDTpkHR0Q/7JGnbrss81njlw8HCZaRXlq -xRFd5sLPeTuMgBbLksCpMDNkC/+nXTe611S6yZBZGR8w79XrMi31cKph4/7k02xn -1u6vIDoko03DpRD1KjgNueAUVr+EedmrUe7ebsdXRw34v1sVeJcHFtYD5M9FRAq5 -nffGGj88xA+OPtM9RFduA2dXRcVLA8SAZQ05Hecng8DYCIu9SpTNpVcq+YrMCgKh -EQT/g+CAzCxcgWWojEm6m38zaFOBFiqO58dNMzqBITQ7DAxYRnxRIRhdb4tgTLlx -VMjD02WTd8tBX21pNzmPDD7zSzoButBf8gIbfbBTHWTxk+Mv5NcM8pfP3qdyNrfm -H9cGpmOgFUm0nC+G+WX8EE+6ki11drvrQSqeamo5jnvWCUHQMRh920o1wrT/fMGB -OjI/nQMaMVS9LGwSghD0jNZU01TeCKMesfzHyuO2UaePWgSWmK4aDDuX3QFPNBnb -aK7Rcqiyi+VJNhyscjiel7BBdxydahADnLP2F6Hpo9bTQiU9ccl9rtAsDSzLtJJW -UBk+V6xSl5U/HCEjLU5x64aUWtMQ5GfwaiGnN2RiyUXwGuiVXJph2dgCLPFRgZ2z -Go7qVHAnepiR052eKEc24taSxqWhwlTaxcz42OAr4b+Ih6MXPdjS9T5T6+U1BD62 -pDrXuqp2RLYCWd/t8cBeOWNIAPsaGQE34Ar7LE47YLx4LpAVMoZlXg8gW1f/kuUU -kizH/ZhnkPnfnWnGxpvn+ZAdf2V6IhQ5yCyPx0jT4IWps3mJ92FniO6TvH5AOHsj -NB/vd055L8SjsZ0zeHQILuZHSEChfpIApRFXqAsZPelzctETL0/+iybGmktCnTx5 -tbXpfeHhe9+eY6NBNzxsNROIBST4yPs2b30CBIYKx17T8h3Cs4Ht1yqzNm+upSmK -czHsMYbXYqu5nXPvcEjoKwLgwr3S3RyEmJlRvAdp4t5aSF7JIEiUC50szXELoklf -TBMw6stXJvmzuDlOMy8GgWd+48t9g5kLP8SilTYdeRE+BeuWimBbg5SlZhEzXc0D -ouw4NE3Xp7PFyE0d9UAlJA+7fexKP45QtQYzQP4Q2a/rSGn3jQY3U8XnGlnkDCqF -nwznC5rzUyYOC4xEbZD3dZheZByi1dbfSP93kSKrDrAWl7SapGmItbJ3R0Lo1Gf6 -wRkaMB08FnLe35KuE6kChmU82uNfCmIkDHOV/Mg9dkmh39iY81NzL/Jh2K0gJYzD -b8uFH0cSuv2jFngxzZqaX5KHz+pqvuewMYkw8m06rBd1089iq0d0Yxe0a257i16h -HGBss2yT3cfIkMcqDOvDa21nD3+vYpNTydGA1UZRl409MLedblrt43cF1ODNJus4 -s0sFX120cR96MibvBqUFavRyIfhLYEIVgVe+HhF/8WoyLKbFz5izuQcx+wx8qqJK -4tnEqbL8c/dw03vFgJuTbTbCfHiNYlijaXo6OUfHiUNZnIjjh4p29xwy/CSkXWIe -AQuhQC+85LkxAAiRo0W6re/zrqdTH8zwCjackjXZOoKB6tJNa3IhcAj1rB1VPKBG -Z4LIPKaIn9daac+sBkfL4HaBhyjWolWrW6frkaApryXe0izPbXIfXwO+iwFtCGNR -ybA215m1yVl50oD1Pp12yNk7MHROoA7ncy323zgYdh9n+V9eeIZcI3H0dHqoQkI4 -8IXOHxR0o/4lugl6edphPZiRWMNGlay9jrXtj/bRkEi1RTLE2FGZQ0mAa+iUCEmx -BPDoclLPgOrNPQuM/AGhyX4yMJYzrYgt2sAnHlDUIDdLbLu13orZUFWOgx3ZZtCK -gGmmTt8+szO93wuht4kurpk7pp1q6thh8xu4smV3KlCEKcWX8+qstOzx71qHJkW6 -L1QHuDnuXYkFNa8If2iMu6BrOkn+3okmecUbD7Ice9E5UqeV/XSALTuvlRLcBSBO -Vf2UN1N62TTEuxa9oAX0MF6qrOt+Bvpl8l/UvWtagdzovdn+iHmK0kutXdsIPaur -dfiYNACeX8aJiP09rKcWz2sJuANvqGbQCzLcZDKBsvX70DytGWaBOKii528EYutS -nbgxDTJ6stJimQkOzjL4erPu0hV4xNwzEA0E9il6Q3b3nBczVBJhiAisOi0a+Gw4 -0LnKAlys7DDxaPAjH8JdsNYHv1VRmt1Jzv73XDkPC2VIXZ5f3iBA0SB6X3dFKFcU -EVStaqqocg/f4InKBM1Jd+VdktDXbkTnFb8RXr/JQ4sbvYPiwRyhHno+cm9tg09G -fQeQ+DQ6CbG+EwprC066Xt+F1gjNVpoOJTjLek+WaEAuvHVOtY7nUnkTpx9yA3XZ -6lA5DDYtVEugeBpfdfjg6NKzF86J6knwkzuBmg/Al7VDT0Yk2Br00BZaGCnGZVqt -3YCWPblTiluWQ5UpAGZAew== +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 +gVfflHUiitigi+qYuOd18A== `pragma protect end_protected //pragma protect end @@ -4351,133 +4351,133 @@ fQeQ+DQ6CbG+EwprC066Xt+F1gjNVpoOJTjLek+WaEAuvHVOtY7nUnkTpx9yA3XZ `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -KWWOWWFuOMKF+o5pVPgMTekGxwMhu078HmQRu+cMJr9U0P+ED53Qti/X/f9pQc92 -VrezOzrIRbg5Vwj89zzibQRJ9+DuSvEXaaCsAJiWW9+Yoq309Jur64fkWQSXyi+5 -9GvFJzJ0y1IdPQ+wv8vOOpCXbfL0G6PPext6NNUfdO0cLh4rvbk0w2nWFF4fOXo7 -YTDvLFYOcewefBx6IXnXfBpBo/EbgMLAy6kt1vnRKPP5La6aih5yq6i9+4tMjfpr -FLTgiJW5lT5yoJQJphVQFI4tQQ3voHJrzpbpcCR5NjEg0VUongDZDG+8C0gAe/bO -OvpGCpKkjF4+vcQoac0Jow== +CdzB9vrn96JT0IE6IbyMNorhPjPK1D6V9sWaj27tOIS63fCLLd3Fhdvi9U4TNSXM +q8Aby8b18QaGHXvwTCj1PhwfZee2liTibnFxiK8W4vCoXbMw9jTqRbsPO4lShdnP +AWGN2s+1g4cfEMemSoABngHvKt5l8/Qgitl8ePAWUnsIIBUZo2R3xRFsRn+N92il +oHNxpyevVhtVVhOdSgy7cDEeIHiByqsXmBrSBeDLKbk+3u3rOGP8eH9qSXVIII+3 +SrA9wnnKrvVU/P3ugps2Evh+pPJ4AgvxeqRFdC7y6LU7iIX4P7HEhvLALIRt8emX +k6uJrX9IUEHTr/7EDHmkRw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 5664 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -4495,88 +4495,88 @@ wp+o554/znNrQF0/3p8o2KpSdZQj9vy+Th035YXSb6wovDGpsmCO4XlgnzZkoLIl `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -NkwmUhpjXHcBZQxfcyhhMI3c5OTK4b0fMBZlAw4avUAeoudxhnPLWCeTPe1ASAoj -bTylscBpd+yICx1pgInxa/fTavSYiTKTOKgGV5USFUFcpo1bgbW5pLNfsikxhJtX -NhHeNvlJqctzAMfvTkhqJiyyqEGCmvs4hp+myYU1Bu9Su2dPrTiKrcs1fVaqxdXp -CLljAtkMwvF2svV12wDdipJZlQTXDirE9z+2JFFVoLcrUBpUSGSWkQ0MHNLFSbdY -QPH+daWLTPNa3F6alGNUp6TZTA41HtIUFHGZboEssj9HOYZVYFFsnSiwJAOF5oGO -8ULxtD0Ziux96YUEPA5XyQ== +SzhXiz0zdDjGadNr9/3NJb9f26Yal/c1yok2yhYa2l7w/1wi1Pyk/kz4XcjMPamc ++O5VYbIVSO9foPFV2GH0JLidIbOSshsjGoGUOBMc7ObMFmzJM7j4UZB36UARICG1 +NstY6evrJSd4SebtwNn96dwrSQ7GTpYTYzmWGRO6ARJ26Q0G2/BphNu8Kt0oToCP +cIeA7dPO+6D9pJEQ7ALva09JRDpJLFnYV3Q4rQqPQTf6rOz6aFVjoreUAwJJuS0I +fQOth0AbIPM3M+Ru32rBli/HkaVx1mIB8qwdywD4K0hYw3zpmQ85q2mxK60Kqia5 +X2aToGNImLAoWhi0MXx71Q== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 3504 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -4594,679 +4594,679 @@ iLMTg6VmBh99tRTmk5nQywuVgtAY0KsG2c2wC9efp7SQ9T4aDzoXudJ3QWRdWyWc `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -CYdTxYtDsnsYcj1raTkJMt7rQ0pu9MnV8Hg+Yo/h8ImEU67x70adnR2jvqatJsk4 -9IVwHWFzt49+ee0gOxdqwL+RBBBA1M/MYo4ljXj5b70W0QgjuB1MHfJkjOFsCjqm -6MxdC4Y7skUnr3AC9JXUqVlDEVrQ6iKdC3hVQ9tMZ9EgWJBw8r5jF4UHetXELvP2 -D5D0+5O1kKqY5yi/sYmW8Ex7ZQu9zZdumjSGnhUC3Mnnwn1CuEXRe4seKDSslH6h -43b5WNKzJArOZ3WysC+znbIIt4Ve3NJlLA0x7WdhY6dnxeM5rKhSob7Rbc5DzwKA -rLRt1G1mlHYYikWwE1y59Q== +SCSoKCk2twpZ/XqldguMzShzGf717UuAFnxMW2zppYwt38fXo4wITcAjX0LpMd8j +uzfq9S0n/7qyFYgiH5eZ1IqF9adAH429mXd//VXHEVv3KM3mYadbFj3FOWadj42u +Q5TXIFdGIO0q4QbI0IUjM33F4oDrXceECtvEue6HWrbL008xluHyoNiafdO3bVOp +D9XyhOAPuGywEDRS7vc7XzNE2A4SIV6xuB7g10yBKBDGWLSwMkmgd5OrdfeTA5VY +8BdV2Kc4qrXzuxvt8I1PX715ZMdAEA+MjnUheF+rt+WpZeXxQyP9tBhQhqYGKl65 +JO2HM4jcVqBVdH0h2IMwyw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 31840 ) `pragma protect data_block -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 -MyGtnrzqnNk/SloXgHTCbQ== +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 +ZdUoTcYAr4S0L7IS+7TL7A== `pragma protect end_protected //pragma protect end @@ -5284,640 +5284,640 @@ MyGtnrzqnNk/SloXgHTCbQ== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -MG9JGKDamaEFFOZXHRyCiqiyGAJLgES30q81ygwqhTaaJ8m37nn4HwxD9uJzOtTz -/K004smLlqr2haBNKMJ6744SP32ba69ZI/YVuHgvj+4OQ9S3S7bBupBQrX5bxfMH -Jh6HwzhWD/bFKKYRcId0I/bYlxbhWZyArsusdBgfJibe8nkhZsZXZWYjvoldeVBM -Nhl6bVyNKPfPVz2yycQ4AjiSeTRUdUvo645sZQDjTQ7Cit+hywYSytzSdaby99qX -iWupMBmpdLKjRjlYMeWBg13ChKASCO9w0g89F5/s/6PHmMX+Gp69QMYxOYP5zZxL -NPZ8MoM1wMmzVGvXknA23w== +O7i5M8pYrQm+JQ0l5NqrBMWS2b2UssqPixYbS8eUEw7ILL4e6LjSj3SOVpEG0ULu +yAZh0AkCaG901algg6BBfFcEtJP0Hndzf2+sLpnv7PKjh5cT4ooroR8EhSrmWPdC +bA1K4Npa52M0XheVpZDqwoLU0KBho9h8r+m4NL6xmfDn9GQBXpwA3c1n3VUnHT1u +ZieFKdix/S7UjukvTCzdF0jXDufcdmFwmSW+5nBa6nE3kQhC+3nbc5b4GRBS/+pe +DdKi5crDQb8DO4ROwQEh9wtk5p/8px31bWKDiys3YM/ojVgoFZxqIp4FysoQJS6j +Bly1mbumtHuw6wk+dWz9CQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 29968 ) `pragma protect data_block -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 -L4ep/HD73pULYdbQ5HQWxQ== +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 +HNBGv9zuNYy/TFC/VG9qPw== `pragma protect end_protected //pragma protect end @@ -5935,1069 +5935,1069 @@ L4ep/HD73pULYdbQ5HQWxQ== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -lc+Jvi2ple9smxTQVs56fRfBdzTTpfYYxwSkv26yfqD6RE8cXApdFXlFYXYaPKPl -LFbUEw2aI8BM0coIxVWj2SEEcTN85nhCZiNG2/4m5Fx7UIq8oh25f04eTxaa6PR2 -3lnA1AFJg3DvDYcWhSc8WQ7Av/xFePjZ9tiJVJrkhtkM9L4EhOkgSU1evtPvgMU2 -0WLdqKstrNXYwOukQWv+GRo5hv6T9O8s7ZHogOgIYt3HY2zMBFLXlPVtz2rw6pFG -u9MjqXKZdd/G+QihP4/2w8oMy7vmlB1D1oIiidjNJABNHniwdSnNlgotl2GEub1D -lCyGY95YAji+VpZobbyUMA== +FTBEK5JPQERAuJEsQjL23p9J0qttLi73b3WuzfDhPf+IxVX47RLiJRGeN52CEc/5 +u6CZJSqGAM3Jg85kgQmNuPYdj3luun2JYUFKX9j2YtWqby0dor9daQeoaCKF1ZWm +cS/qwlh98ApjcaB8q/czfIDKcpNRT34BUeTyPyAWoahz0D3YdXcnoc3oYTrDmVhM +9ooIEhfkyHPd12yQVTAY9nv4rEq/7U3/ymJbN44GnhD6jawsr1NzfhMD32tJFixd +OjzgmYS8Tli7BqTiieUS0+ocTzkqohIPIdPMLsp1vcDm0RWBlSJpDoa2ckNYbxPE +ge5nKUOOarrTYjfpOUaeGA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 50592 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -7015,126 +7015,411 @@ EsNNU8WSXgX9pOIeNvszT+FX/o8+/rw8Q+Tw4s+aa2FtpK/9/LGyADdd8+cM3v7e `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -A3cnGJtn9AGvRjR/4QlGi5p70tN4J5uh199AB+xPKGukVATZRY6xLuAZoUjyIeEi -hT4wgjbvU1r67zAlRFHnYp+0K6+Tp3lTDawymP8IJobytvpyC/vx9U2fECtVRYE2 -UsMLInNLvjo/J4RSXmBV4oNMWSuCALr+YhWdwMRKomYsPnD4l0sHQeevWSNmK2ml -pEwyH6DBdfLjUoDDzwDzSupPtDDYeKQU2MbqlcnDmEVVO/DhOUF3U9kk6NBIt67j -gV871466o/qK2w5hqU0BjZjjzcG8UlQu3OniWX+MnsFR/Aq9FxhvLisB3YSuMQkm -fKGOvWGn8DN5sMayEBnfJQ== +h+15C3D2vNJXmQt4KKJyIMiVFAOGkQoAiniVA1UCZ2chDe6HY0xKRJJ81Lu8rUsv +Se18buUMb0xcWjLppKS41PxbNn8Fr7C4qjTBbVxwBROd5o8zBBGD53UxB77Tf6T3 +dI8u0hMFMjsSIwABC2EyooRyBigBSE7ooqwjY2CKc8ionISglea8xB9S7hbOM84D +cvMggYg+KnnghbvXZvlRjrXtJBFUwGEWyvrOXcr05o6CcPUr0w55hVft7kpaTG6g +w8o3gb2NIX2uumKAHkqi350dfeSj9l35+mAYuR1KHnERd8hcDVeFG3swLuyGG8NQ +zq2BZ9X5CgnNEJy4IUNJsg== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 5088 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end +module `IP_MODULE_NAME(mii_if) #( + parameter NO_PREAMBLE = 0 +) ( +//Globle Signals +input tx_mac_aclk, +output reg tx_mac_aclk_en, +input tx_reset, +output wire rx_mac_aclk, +output reg rx_mac_aclk_en, +input rx_reset, +//Configuration Signals +input [2:0] eth_speed, +//GMII Interface +output reg [7:0] gm_rx_d, +output reg gm_rx_dv, +output reg gm_rx_err, +input [7:0] gm_tx_d, +input gm_tx_en, +input gm_tx_err, +//MII Interface +input mii_txc, +output reg [3:0] mii_txd, +output reg mii_tx_dv, +output reg mii_tx_err, + +input mii_rxc, +input [3:0] mii_rxd, +input mii_rx_dv, +input mii_rx_err + +//Status and Error Signals +); +// Parameter Define +//localparam SPEED_100M_DIV = (TX_REFCLK == 125) ? 10 : 2; +//localparam SPEED_10M_DIV = SPEED_100M_DIV*10; +//localparam SPEED_CLK_DIV = (TX_REFCLK == 125) ? SPEED_100M_DIV/2 + 1 : 0 ; +// Register Define +reg [6:0] aclk_en_cnt; +reg [3:0] txd; +reg tx_en; +reg tx_er; +reg rx_dv_pre; +reg rx_dv_dl1; +reg [3:0] rxd_pre; +reg [3:0] rxd_dl1; +reg rx_odd_data_ptr; +reg [3:0] rxd; +reg rx_dv; +reg rx_er; +reg [3:0] gm_tx_d_h; +reg [7:0] gm_tx_d_r; +reg gm_tx_en_r; +reg gm_tx_err_r; +reg preamble_flg; +reg [1:0] cur_st; +reg [1:0] nxt_st; +reg add_preamble; + + +// Wire Define +wire add_preamble_w; + +assign add_preamble_w = mii_rxd == 4'hd && mii_rx_dv && !mii_rx_err && cur_st == 2'b01 && preamble_flg; + +/*----------------------------------------------------------------------------------*\ + The main code +\*----------------------------------------------------------------------------------*/ + +/*----------------------- Tx Region ----------------------------*/ + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_mac_aclk_en <= 1'b0; + else + tx_mac_aclk_en <= ~tx_mac_aclk_en; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + gm_tx_d_r <= 8'h0; + else if ((gm_tx_en == 1'b1) && (tx_mac_aclk_en == 1'b1)) + gm_tx_d_r <= gm_tx_d; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + gm_tx_en_r <= 1'b0; + else if (tx_mac_aclk_en == 1'b1) + gm_tx_en_r <= gm_tx_en; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + gm_tx_err_r <= 1'b0; + else if (tx_mac_aclk_en == 1'b1) + gm_tx_err_r <= gm_tx_err; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txd <= 4'h0; + else if (gm_tx_en_r == 1'b1) begin + if (tx_mac_aclk_en == 1'b0) + txd <= gm_tx_d_r[3:0]; + else + txd <= gm_tx_d_r[7:4]; + end + else; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_en <= 1'b0; + else + tx_en <= gm_tx_en_r; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_er <= 1'b0; + else + tx_er <= gm_tx_err_r; +end + +always @ (posedge mii_txc or posedge tx_reset) begin + if (tx_reset == 1'b1) begin + mii_tx_dv <= 1'b0; + mii_txd <= 4'h0; + mii_tx_err <= 1'b0; + end + else begin + mii_tx_dv <= tx_en; + mii_txd <= txd[3:0]; + mii_tx_err <= tx_er; + end +end +/*----------------------- Rx Region ----------------------------*/ +always @ (posedge mii_rxc or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + rxd <= 4'h0; + rx_dv <= 1'b0; + rx_er <= 1'b0; + end + else if (add_preamble_w && NO_PREAMBLE != 1) begin + rxd <= 4'h5; + rx_dv <= 1'b1; + rx_er <= rx_er; + end + else if (add_preamble && NO_PREAMBLE != 1) begin + rxd <= rxd_pre; + rx_dv <= rx_dv_pre; + rx_er <= rx_er; + end + else begin + rxd <= mii_rxd; + rx_dv <= mii_rx_dv; + rx_er <= mii_rx_err; + end +end + +assign rx_mac_aclk = mii_rxc; + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + rxd_pre <= 4'h0; + rx_dv_pre <= 1'b0; + end + else if (add_preamble_w || add_preamble) begin + rxd_pre <= mii_rxd; + rx_dv_pre <= mii_rx_dv; + end +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + add_preamble <= 1'b0; + else if (add_preamble_w) + add_preamble <= 1'b1; + else if (!mii_rx_dv) + add_preamble <= 1'b0; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_mac_aclk_en <= 1'b0; + else + rx_mac_aclk_en <= ~rx_mac_aclk_en; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + cur_st <= 2'b00; + end + else begin + cur_st <= nxt_st; + end +end + +always @ (*) begin + case (cur_st) + 2'b00: begin + if (mii_rxd == 4'h5 && mii_rx_dv && !mii_rx_err) + nxt_st = 2'b01; + else + nxt_st = 2'b00; + end + 2'b01: begin + if (mii_rxd == 4'hd && mii_rx_dv && !mii_rx_err) + nxt_st = 2'b10; + else if (mii_rxd == 4'h5 && mii_rx_dv && !mii_rx_err) + nxt_st = 2'b01; + else + nxt_st = 2'b00; + end + 2'b10: begin + if (mii_rx_dv) + nxt_st = 2'b10; + else + nxt_st = 2'b00; + end + default: nxt_st = 2'b00; + endcase +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + preamble_flg <= 1'b0; + end + else if (mii_rxd == 4'h5 && mii_rx_dv && !mii_rx_err && cur_st == 2'b01) begin + preamble_flg <= ~preamble_flg; + end + else begin + preamble_flg <= 1'b0; + end +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + rx_dv_dl1 <= 1'b0; + rxd_dl1 <= 4'h0; + end + else begin + rx_dv_dl1 <= rx_dv; + rxd_dl1 <= rxd; + end +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_dv <= 1'b0; + else + gm_rx_dv <= rx_dv_dl1; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_odd_data_ptr <= 1'b0; + else if (rx_dv == 1'b0) + rx_odd_data_ptr <= 1'b0; + else + rx_odd_data_ptr <= ~rx_odd_data_ptr; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_d <= 8'h0; + else if ((rx_dv == 1'b1) && (rx_odd_data_ptr == 1'b1)) + gm_rx_d <= {rxd[3:0], rxd_dl1[3:0]}; + else; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_err <= 1'b0; + else begin + if (rx_er == 1'b1) gm_rx_err <= 1'b1; + else if (rx_mac_aclk_en == 1'b1) gm_rx_err <= 1'b0; + end +end + + +endmodule + + + //pragma protect //pragma protect begin @@ -7147,1351 +7432,1536 @@ x86J1s8as9JITJrhcdNO4mSBdcAptsQtRSnhNfbxAvoD0hB2DzajNqceMI+ULDXd `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -BMd6SB4Bjp4tXuYL7DlG2kYjc3CnpjQlDj8eHG5sznnMdmDpahuNYX8nSPgeHdR1 -ySnxUz4hVXB9iXosL3NWl2c6N/Yfzc4UuQ7Nr6pD/WPg+/DYzsFPV9wIIvunhe6A -n/87cqL68Wpff0Xl/W3VplObSeKqm3fbYvvKZ4GSKsROuJ3sWuPYGaMmjhCd2wza -VDrd6LPlQp6Ws0JwSDolbp2LuP/rHCR6rT2hOLzPzLdo7vhPTTdFlyzRoTY/ncIl -KJZ3RmHIVv16VxiHPlwqDPc9iSxtgbtVyxLTn9uJpSlVchE0sAKGF+Np6l7uytS5 -e60zc2Tg2q8drloNbV7OvA== -`pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 6976 ) -`pragma protect data_block -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 -Z8PM/4kof4KZXaSYoVddZQ== -`pragma protect end_protected - -//pragma protect end - - -//pragma protect -//pragma protect begin - -/* Encryption Envelope */ - -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" -`pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" -`pragma protect key_method = "rsa" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) -`pragma protect key_block -Zg774MKVa/0nMVsWlCZJo3alm7D2VC/8MQCjgML/o6YTGsLI/rhgazBjURKA0N4P -rqMbopzy+uWooc4VihLaBAVirQOF1cLpO96Q9opR2vmssL1YwLsE4UFiW4aLtW8x -6r+CSBFMVd8+X/+B0Lmg1qcqh/no1blNR2FQekjWngzqYrnpODpqyNh4fkUYVBzq -591bSi0jpMDfLa6GKLl67hlDqZeeYKY/79HhoKkX4Y5iA98yvAFtheO9KW2xYjK8 -KSQqoB3hWVTMp/ywHtSshZlW1O2YbbIfPgg1aUDKRPtxu0rm7mPnQYURuDM7gqI+ -ZBdst9Ty/YDRymCt8aCi2g== +k9tqoepDssa6U5WJoqOS9tgWB31ZsRZUTNA+uBlqqK4sYjYn5IQk423OuSrCt3DJ +QQIBNQeiuHujWzO/78gYEikwkd/l0vjo0F7MU3SE61prd3sroydFcjL3M6+IeQdT +P7Cs5ER6xxqXBNFAQjCE02LglYkvruSD6LXo/rEq7WmOWDOxQ9PJynpvBkZGN0gU +3blXkCaqz6yJqX6aqt7hTn7Spaoy28BsXHYDZNePtYBYNgB1/eu/SX33ydi1CQXt +X1aoa49Z3tymTM1jDePEPxzVC7g86GH9WovncycvpB+ig8RwxdUkw8JFz/eFwkJ5 +KelIQbvR96Crn/O4wBCEGQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 22080 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end -//pragma protect -//pragma protect begin +///////////////////////////////////////////////////////////////////////////// +// _____ +// / _______ Copyright (C) 2013-2020 Efinix Inc. All rights reserved. +// / / \ +// / / .. / +// / / .' / +// __/ /.' / +// __ \ / +// /_/ /\ \_____/ / +// ____/ \_______/ +// +// ******************************* +// Revisions: +// 1.0 Initial rev +// +// ******************************* -/* Encryption Envelope */ +module `IP_MODULE_NAME(rgmii_if)#( + parameter RGMII_SYNC_EN = 1 +) ( + //Globle Signals + input tx_mac_aclk, + output reg tx_mac_aclk_en, + input tx_reset, + output wire rx_mac_aclk, + output reg rx_mac_aclk_en, + input rx_reset, + //Configuration Signals + input [2:0] eth_speed, + input rgmii_rxc_edge,//0:DDIO Rising Edge; 1:DDIO Falling Edge; + input rgmii_txc_dly,//0:rgmii tx clock delay disable; 1:rgmii tx clock delay enable; + //GMII Interface + output reg [7:0] gm_rx_d, + output reg gm_rx_dv, + output reg gm_rx_err, + input [7:0] gm_tx_d, + input gm_tx_en, + input gm_tx_err, + //RGMII Interface + output wire [3:0] rgmii_txd_HI, + output wire [3:0] rgmii_txd_LO, + output wire rgmii_tx_ctl_HI, + output wire rgmii_tx_ctl_LO, + output wire rgmii_txc_HI,//if rgmii_txc_dly set 0, used clk_125m clock. if rgmii_txc_dly set 1, used clk_125m_90deg clock. + output wire rgmii_txc_LO, + input [3:0] rgmii_rxd_HI, + input [3:0] rgmii_rxd_LO, + input rgmii_rx_ctl_HI, + input rgmii_rx_ctl_LO, + input rgmii_rxc + //Status and Error Signals +); -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" -`pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" -`pragma protect key_method = "rsa" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) -`pragma protect key_block -id3MEW2l4lwVCrH3fezHrrPIrH5bom+880FG+AgGOHjl19+kSptJ2DtllKGOhaEo -vIgU4jTRJ5NnMfWw/BNrRjTOGJl4x0WvZbFEpEU3dc9Ab15ngk7n+uWWIVpU8t0V -LxkIiperjMc2SDA6kj/G/BvEny0CAl/fHx/XPggXj4zrb9rSrhccHnnPDHUC8GhT -maCsSMccRTtda2sCx0qZgUU8TEgivDT61f0JqN8boWgDa80UocoOC5ZAZGWHCDf6 -eSlwA0pYYRiHly3hU8yMkC9HuERKnwtzuh84GnXEPpMObwDXpFXzd6XbwKpdA5Ca -l2d9SQGQ7rQN3ky876iPQA== -`pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 8640 ) -`pragma protect data_block -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 -`pragma protect end_protected +// Parameter Define -//pragma protect end +// Register Define +reg [6:0] aclk_en_cnt; +reg [7:0] txd; +reg tx_en; +reg tx_er; +reg [1:0] txc; +reg rx_dv_dl1; +reg [7:0] rxd_dl1; +reg rx_odd_data_ptr; + +// Wire Define +wire rx_dv; +wire [7:0] rxd; +wire rx_er; + +/*----------------------------------------------------------------------------------*\ + The main code +\*----------------------------------------------------------------------------------*/ +/*----------------------- Tx Region ----------------------------*/ +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + aclk_en_cnt <= 7'd0; + else if ((eth_speed == 3'h4) || + ((eth_speed == 3'h2) && (aclk_en_cnt == 7'd9)) || + ((eth_speed == 3'h1) && (aclk_en_cnt == 7'd99))) + aclk_en_cnt <= 7'd0; + else + aclk_en_cnt <= aclk_en_cnt + 1'b1; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_mac_aclk_en <= 1'b0; + else if (aclk_en_cnt == 7'd0) + tx_mac_aclk_en <= 1'b1; + else + tx_mac_aclk_en <= 1'b0; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txd[7:4] <= 4'h0; + else if((gm_tx_en == 1'b1) && (tx_mac_aclk_en == 1'b1)) + txd[7:4] <= gm_tx_d[7:4]; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txd[3:0] <= 4'h0; + else if ((gm_tx_en == 1'b1) && (tx_mac_aclk_en == 1'b1)) + txd[3:0] <= gm_tx_d[3:0]; + else if (((eth_speed == 3'h2) && (aclk_en_cnt == 7'd6)) || + ((eth_speed == 3'h1) && (aclk_en_cnt == 7'd51))) + txd[3:0] <= txd[7:4]; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_en <= 1'b0; + else if (tx_mac_aclk_en == 1'b1) + tx_en <= gm_tx_en; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_er <= 1'b0; + else if (tx_mac_aclk_en == 1'b1) + tx_er <= gm_tx_err; +end +/* +always @(posedge tx_mac_aclk or posedge tx_reset) +begin + if(tx_reset == 1'b1) + txc <= 2'b0; + else + case(eth_speed) + 3'h4 : + txc <= 2'b01; + 3'h2 : + case(rgmii_txc_dly) + 1'b0 ://rgmii tx clock delay disable. + if((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd5)) + txc <= 2'b11; + else if((aclk_en_cnt == 7'd3) || (aclk_en_cnt == 7'd8)) + txc <= 2'b00; + 1'b1 ://rgmii tx clock delay enable. + if((aclk_en_cnt == 7'd2) || (aclk_en_cnt == 7'd7)) + txc <= 2'b11; + else if((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd5)) + txc <= 2'b00; + endcase + 3'h1 : + case(rgmii_txc_dly) + 1'b0 ://rgmii tx clock delay disable. + if((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd50)) + txc <= 2'b11; + else if((aclk_en_cnt == 7'd25) || (aclk_en_cnt == 7'd75)) + txc <= 2'b00; + 1'b1 ://rgmii tx clock delay enable. + if((aclk_en_cnt == 7'd13) || (aclk_en_cnt == 7'd63)) + txc <= 2'b11; + else if((aclk_en_cnt == 7'd38) || (aclk_en_cnt == 7'd88)) + txc <= 2'b00; + endcase + default : + txc <= 2'b0; + endcase +end + +*/ +reg [1:0] txc_100m_r; +reg [1:0] txc_10m_r; + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txc_100m_r <= 2'b0; + else begin + case(rgmii_txc_dly) + 1'b0 : //rgmii tx clock delay disable. + if ((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd5)) + txc_100m_r <= 2'b11; + else if ((aclk_en_cnt == 7'd3) || (aclk_en_cnt == 7'd8)) + txc_100m_r <= 2'b00; + 1'b1 ://rgmii tx clock delay enable. + if ((aclk_en_cnt == 7'd2) || (aclk_en_cnt == 7'd7)) + txc_100m_r <= 2'b11; + else if ((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd5)) + txc_100m_r <= 2'b00; + endcase + end +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txc_10m_r <= 2'b0; + else begin + case(rgmii_txc_dly) + 1'b0 ://rgmii tx clock delay disable. + if((aclk_en_cnt == 7'd0) || (aclk_en_cnt == 7'd50)) + txc_10m_r <= 2'b11; + else if((aclk_en_cnt == 7'd25) || (aclk_en_cnt == 7'd75)) + txc_10m_r <= 2'b00; + 1'b1 ://rgmii tx clock delay enable. + if((aclk_en_cnt == 7'd13) || (aclk_en_cnt == 7'd63)) + txc_10m_r <= 2'b11; + else if((aclk_en_cnt == 7'd38) || (aclk_en_cnt == 7'd88)) + txc_10m_r <= 2'b00; + endcase + end +end + +always @(posedge tx_mac_aclk or posedge tx_reset) +begin + if(tx_reset == 1'b1) + txc <= 2'b0; + else + case(eth_speed) + 3'h4 : + txc <= 2'b01; + 3'h2 : + txc <= txc_100m_r; + 3'h1 : + txc <= txc_10m_r; + default : + txc <= 2'b0; + endcase +end + +/*----------------------- Rx Region ----------------------------*/ +assign rx_mac_aclk = rgmii_rxc; + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + rx_mac_aclk_en <= 1'b0; + else if(eth_speed[2] == 1'b1) + rx_mac_aclk_en <= 1'b1; + else + rx_mac_aclk_en <= ~rx_mac_aclk_en; +end + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + begin + rx_dv_dl1 <= 1'b0; + rxd_dl1 <= 8'h0; + end + else + begin + rx_dv_dl1 <= rx_dv; + rxd_dl1 <= rxd; + end +end + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + gm_rx_dv <= 1'b0; + else + gm_rx_dv <= rx_dv_dl1; +end + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + rx_odd_data_ptr <= 1'b0; + else if(rx_dv == 1'b0) + rx_odd_data_ptr <= 1'b0; + else + rx_odd_data_ptr <= ~rx_odd_data_ptr; +end + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + gm_rx_d <= 8'h0; + else + begin + if((eth_speed[2] == 1'b1) && (rx_dv_dl1 == 1'b1)) + gm_rx_d <= rxd_dl1; + else if((rx_dv == 1'b1) && (rx_odd_data_ptr == 1'b1)) + gm_rx_d <= {rxd[3:0],rxd_dl1[3:0]}; + end +end + +always @(posedge rx_mac_aclk or posedge rx_reset) +begin + if(rx_reset == 1'b1) + gm_rx_err <= 1'b0; + else + begin + if(rx_er == 1'b1) + gm_rx_err <= 1'b1; + else if(rx_mac_aclk_en == 1'b1) + gm_rx_err <= 1'b0; + end +end + +/*----------------------- PHY Interface ----------------------------*/ +`IP_MODULE_NAME(rgmii) #( + .RGMII_SYNC_EN (RGMII_SYNC_EN ) +) +u_rgmii +( +//Globle Signals + .tx_mac_aclk (tx_mac_aclk ), + .tx_reset (tx_reset ), + .rx_reset (rx_reset ), +//Configuration Signals + .eth_speed (eth_speed ), + .rgmii_rxc_edge (rgmii_rxc_edge ), +//Phy Interface + .txd (txd ), + .tx_en (tx_en ), + .tx_er (tx_er ), + .txc (txc ), + .rxd (rxd ), + .rx_dv (rx_dv ), + .rx_er (rx_er ), +//RGMII Interface + .rgmii_txd_HI (rgmii_txd_HI ), + .rgmii_txd_LO (rgmii_txd_LO ), + .rgmii_tx_ctl_HI (rgmii_tx_ctl_HI ), + .rgmii_tx_ctl_LO (rgmii_tx_ctl_LO ), + .rgmii_txc_HI (rgmii_txc_HI ), + .rgmii_txc_LO (rgmii_txc_LO ), + .rgmii_rxd_HI (rgmii_rxd_HI ), + .rgmii_rxd_LO (rgmii_rxd_LO ), + .rgmii_rx_ctl_HI (rgmii_rx_ctl_HI ), + .rgmii_rx_ctl_LO (rgmii_rx_ctl_LO ), + .rgmii_rxc (rgmii_rxc ) +); + +endmodule -//pragma protect -//pragma protect begin - -/* Encryption Envelope */ - -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" -`pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" -`pragma protect key_method = "rsa" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) -`pragma protect key_block -GFPL4lhIWV8aBbF7fmI/scCLNxEQKx00snoPLB7/xc2JXULZq1xQEkZWk2RCDwSM -DINuQxUFnobI1iX+TY+q9pMOwllPKTluL07wUpb4R1W0kelatGVt8TmbzwkmKq2V -gxi3WdsB2oBYfFPoswtshb9uZEX3FIJIAVSU9fbK9fXvY13a4qdinStgFkX+aZ4p -terTyxckNxV9KjJrJ4FJqPMF6h7x03Oz4Br78tAUdLzWTOgP1Ydc9/p6PgklIitX -ouDEP2cn9TrpxRWlVcjXnxxnjJipm3C8jriqHifwavfCJhOh75jyJQq+wlIPDMrX -/AM/WPhRgnHEc/1TjUmQkw== -`pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 4352 ) -`pragma protect data_block -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 -`pragma protect end_protected - -//pragma protect end +///////////////////////////////////////////////////////////////////////////// +// _____ +// / _______ Copyright (C) 2013-2020 Efinix Inc. All rights reserved. +// / / \ +// / / .. / +// / / .' / +// __/ /.' / +// __ \ / +// /_/ /\ \_____/ / +// ____/ \_______/ +// +// ******************************* +// Revisions: +// 1.0 Initial rev +// +// ******************************* +module `IP_MODULE_NAME(rgmii_sync) +( +//Globle Signals +input rgmii_rxc, +input rx_reset, +input [2:0] eth_speed, +//RGMII Rx Interface Input +input [3:0] rgmii_rxd_HI_i, +input [3:0] rgmii_rxd_LO_i, +input rgmii_rx_ctl_HI_i, +input rgmii_rx_ctl_LO_i, +//RGMII Rx Interface Output +output reg [3:0] rgmii_rxd_HI_o, +output reg [3:0] rgmii_rxd_LO_o, +output reg rgmii_rx_ctl_HI_o, +output reg rgmii_rx_ctl_LO_o +); -//pragma protect -//pragma protect begin - -/* Encryption Envelope */ - -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" -`pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" -`pragma protect key_method = "rsa" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) -`pragma protect key_block -crrjEpX9gu51zopKAPc5jmptWDcxwLiOV/2vkOLms+EX0bW7VL4ZEsNLXjdx7DA6 -T2m42c8hxurhLCi2EDv6QZeq+GWQGLUIAqXQ+48pEV6ZYHRrBcedTACzXXo6cRPo -t4KvMdYLJ/MvXlyeMYCAcp3BtwRtaafqk0KDgXelFcl/jw6fPGuiA06iR2sm2JQw -TAQhVdE5hKfAc6USztJBvJZfGsSqDapBsqRwZhTDJq+qUZQKY0HoPqZyG/xmzE34 -YOyh0D/I5Ys9GVXshaimTDe5drv2caBj6pgZEJBm52DOv1jvEc6FgF+VaAQVkxkh -VD4HM9RU4srF+IMGC8RrUg== -`pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 6992 ) -`pragma protect data_block -iW6rCzxbW2HE5v2gUOcSQq7jlMF26J9Pl/a3XhIxwj/oxLAC+YX5YbA3sXdySRi0 -HijrkoRKR+fYTTBTQ5gHnAwHuYWVvUvlA7URGEIuIWZ/iIlsBbi1Om22pjzUBRu2 -em8lwuXygzAWDce+fjk3MIjGeml9rgs1yefsDqUPnaH5p8mGtNiswtBDoT8UW8H8 -UmCg9U7iWHBcUE9T886BlrFNtkEq6UlimLsmYSqPNnxTKby+KD7QOZazJ4QbpZb7 -Roo1qYdpXBoHt8tGDoqb0XqwuaT2csCHyrfuXJ5eKKPy/gZ2UJtGUCA7dtCg9mzG -7PERryJJshy0Y32JTNlovvv0828O0ms3cFjpdh3b5lgc6IaSlkztQbr8ZZki1LZ/ -myFJuvmWbwE2dBW1b6iMYTUKTxQTdC4/3l5c3VStxov79dEEyaH3f8RfVQ+7MtVL -x0TzAN3Tpld9VIBDNbffAmjlvDvstGodIlNiMgp/OlIZ7lBCbI+LGavGyGqfpOs2 -VjNnjs6yDi9PcG+cWrYCZstV/aJrsYea8f5K/ynghSEv03OOLvaGdjTLbh1iSZGO -OhnB5FNfWi9pg5Bw+0OQAGgzcPe/rbsdSLmiVyF+4ulLLuYA9yAMQiXglEGCy7Bb -uOkHzfUzOu7teM37LGnr+VXGe28pK9fU1syDhGgnMYWVr3fiYl+fmliVMGrPg3L2 -BKYxHq/Z9WWGjxU6RxOYiraW3PVwF3b3d7UAAMHOyxG2d6zlk7+I/JcUBBOo0NVH -6/WyzlItuMxHJruHFm9MZZTVMq0kZne9FNhrzUEB7Ok1Go2Q69FYf/FGZTF8+ETr -rca6+nU7LPP7cSDV3KcAwVLt2XnICcO42Ivuna/eGmScMAiMH/sOD3BgX55zUbwS -Xee6w2GGBp7S8iNB9YbfSV3fEyBCJ3ShY/wOMzhurx/S6YG61kHOudI8FedS+1GI -XmDYlLNWZTr7F4HO/nOmyl0qQoxwCIxBGPRU8xbitC63PwSfih2TWVJc0RsuoIAJ -wJuFFWQcihtMp63ZdsDP7ghsYo2jm2UwzIBXJl59svonsL/vJu0orw8Xm9+RMKZC -X1C/CXuaDvy7BY2k6stavCSpOnSFEitBI52068rsrJISiDzcDKZBKsKOpD8Bsyq6 -PkPxiJf6vo/cVuux15K9ce0nUFqmvXC2NE3yS+5dJnb74SWJTKAyv/1q7fFe8YiS -9Na6CXHDI0XYrWgyRHECds5g7dfGqMQm/A0xYxd2le92cucfOgjl2LBOt62J22Ux -+vc8A+om0OerwRDL+VcfHTfHGh5dh/BJS4eB3ZXtUg7C+QSWb60rKUgfPldBi3Qy -D2B5xtupxYPbBVv9wkhKOX2ePoUy/aDQIkQdmD/w8Lb23SXnUS0+L/61faj5E9PA -1+VTNHleHE4HospICmXFUvwpVByDDph1H2+eJ/hGTXL/NTprEhGV0XltCjIEW3By -imF9mCMdfMNAwTZTizHFydTrgvTJBmguy54/I+j6WGs9/qn4KF8yhWSjRg1m67KD -h/rheOww9hoqY6J75Old1Cai2nWUlg5sp8VtJbINLOMQP6q+elCvUWQ8mwOjEUFM -CtS1gvEXnA/TFOaKKJqbQhmPdMR8dOB+zUxT4A9FqsNUrtery5CSM2D+92wyDaoX -vnXF+arPVYQhCVODyb3AUfYliFKLBicDqz3oCPDhWPHz6/esL6YiTEoJSJVlmDas -KYO70HKerxpfe2fP2Q60bHvO2eLa2UdDXzXCGb0Tak6e3UxI4EGZ+UIAVQEnNIwG -NF/c282oMuAUaVZ0QtE4BDONkaEJVS0k0NjdMtMpyAopWKHfodqfDvtAYR6pfOgi -HtVQNh798ziXCvvwQdm4zFrt0eICIWYcLN2ZumpwYu97GCo71SEmVN51SfZn56CP -heSi7m6kvLor1yuEJa86hui55yaM0hubLkOTiPshkhsYDiMMDVqgwVxNP8ddnmfM -jjg+KgkJ7iNZhPic9bguS4X8rNJqQOoz2Vz0Ft/MP8R3KYgQR0C9TxfcVVYLNJCg -si9jU9dQSVJqwfIq3yJ23IZ2WdoYxpsyTE3aO6yrC7/gPSm/rQyUXWEC09XMFzjo -DGZ2vkcLjEXYij7wSdHBKTAHGegQGjXtIGy3Am/QobdbcbU3U+xgx4tkVMRDNq7N -iHnScB4IJauFDzxKi0IrS4I8hY3IpnNqmomBdQ8UPkdEu6ly6HqPws6LuCuUCeS/ -Qx5etHNNzBClljXg61W0S+1NvAuX+EjItwoI9uyEyKTk4/uje46hs7PhgU/7BpiE -Jh4wVejeQ2iOQg/PeqmAy1eSAIOmGBnMZrkPAGtyo/jbIn0mlO8sYJ6GJLB45O9Z -+xnWyp3D3XDm1uocEYvPThceUe1K3quhNvBzPR8RifeRknk++m8SadCTpHE/DBkR -J+tkOWjh4i9ZJqAJgU9zEGk5i3znrJqNhmxnjgaaDoA6Q9UJEbWPNrKbQdSihU/K -kY+fB4fNpUNrcpH3k1yyFdOiBDsYKQ1ikD0IshOtiq2kUOgCxYpqVohbEr5+bXGu -tznVRiv2w3Tfzr5NEQ2AdZvy41drRl6jl7Hq03ooniHBzaGjIkgocAbbnYgDe7NC -jZsjbtMuvJ/raOK8+KNX9fk6tlBfPV4b3eVKYxoso0wU818r4EoOyXbaplNtIkb4 -+ZhVj6u6LGF8iYzwbctDOn9DbU2C5sI8WMPDwGV0dz4soJdrBVOAHk9cVWrQqODQ -o1lpfvkAgL4kBh9vUU3ViBPevAff0fB+xXjC5MYJe+c/GkUL/0RfosBc3mzYBqCc -zW+oPQj3ibblcB8AO3Js4z80BJ6ck73K7SdNfhLv7HP3myYR/B2FgWt4q2ltbn2N -1z5fLaWeNOUQxliDJRCpfIemBc7kW8OwAw5l6dzt3XN1RFo4S/TsFIoegdw02pNN -db9q5Ca6VoCjycqcTyim/9dShR0tDHZgxtR50opvJ2YFtbNFDYQm7Bztlnw+QsV1 -+3rq+ESbUwGUiG70p1pU+VcvZfDr7XP0vtKth+tlWGvcGUCskrHaKrA3LgXwV7yV -oFTMhXQiqyLavbXlYalCGUfOEoDknk/61z/u+1z88H90o01U2umlmrmMruoGYmGp -wBD3Fmrio1+1Ka4LZIR1kYKHiiROH4+BXXg//pm2lNhOanIMeqdiy6BXwRYUsTE/ -cYPrS9a/DAcIqNLiD7tDIAs172I9Scy2hc3khnUYV6t/QI7nMEcOnEfqO7RfT0Gc -lixoobbGW5tna30MbQUovcNZ+u18YkK2EFX6ImOltyYE6zS272i9gy/nTd4VqeAj -Mjo6bYFyW9xBweRIlrrcRyoThWmkZTFBhhWg/0VbZbFOMxy5xuLRssVIOpL4M3TR -y26A4x9xEm0zDgV7oEKMuNe3/8pg1gQRhOFZ++6lAKLmtZZc1U2QOwvYAF/YnZlt -roaojvyoJ5CkrMm7RKFyK7MWTmzdje6Q3DtzgewJjUuuamMTxqbLIFVdR8us2t5c -Sp0V8xKYPKWscZsXaUam8t0Ll6QbdkQGozVgSTqrQvypUizXoVmIdJq8b9H/Hb00 -US6hqnMw+JvpIYkn7juL3jxMP1JckOxdJlQSWdEbZ6YKM8sYsKFpGM/J7V1A/3FE -JPsmulPmfIov1lOxQQuWBr97GzKqJL0cjBqUx9Jprv0kl0IMHeDhUD4Gr0a3Kl+I -ZeaAdlCTbqLkY9xnaZF7Klo+2zXfbIrSsPq5dpyvYzhmQsm/ZOz8WpCU8NLA89t4 -I54CvDSfljx2UTVZN6fYJRm8/cjv10tqlLKZAsgiqVSUuD3hSevPfbELE3/rvbTR -M+vJNTjQ2m2pqMvBYmKYztuoIsx2Ng7a9yX8acZifd6TLbz2V4k3gWawKbAHivWK -pjz50OISUUYko49aw/UiL1kATEOufynmMplkIuSdzEUD0NYb3HzB6Xo6nxOmpGpT -lGygxc4cZXGlWz8r5IQKNSKFI9CK6yIQWzmcKfunAMoi8IpBIMO2lc5IHSmGEPox -hKRAHCFBOsJn//gFBzHB//OKLQ+o09BxeiysIgbxR31Alt3kXyjW+KbGBMqMwIAc -mtX2hVt9uk5CaoArVlGQnCUQv9S+6StFIs4u6N3y+lQ8qZcbSbg7Ua9egOrX/3ip -kU6IVeahpbIz+li+jkrUHgeyo9eUs1l92XpG6RZypZQ7CMPexRaBDY82DgZijVo2 -yjP8681DGKgsFbJqfuQSUoIFzMOcB8Mr7EDisOIp+MxjJ2wyLKPo69pj6tmVV8sw -r9R7Fj7aMUAlyfqGQQm+8ihvAfYcw5V6z/XSG2jggBwsnT8Zf7mIb4+tdJ7REWbt -eXnMeiVR+cDY8NKKLqNoV2dVWEHTCWb3pW5+ZWUC9X5/w8qI8lLRlC3yITWz4Ecj -DJ4aVK7EoKe4sXqaQd4yoLHTOTqTfsEIH52aAVa97pv5fkAWkBWTchJJvJAnizwG -fpw9nb4S5O+4vvsRoQDMsVoruXJQT9/AFHAySGZ0sgyeeNkkEHvp+Ia6HmoqckIY -xwr9wxTqqLPjPVq1jWgf3oTWka62hHMkBneseYOu0zxLPzbsU0HIaUvgkn7MA6ox -8aGhEA/LCju2qxRlBiEJtpvqN//6KoicIgXx0RuuF0gKLJDWtjafYthiqZcq3NLg -ftYRb39hv/MMmYOyjdxGDKJ4F/xe4GL6+P+sO7Wn5G6W/nbqA5mczV+hu163dm27 -IPH5x37Q7gGTWsV7yd4UDglY4mbVo4oo4ZquekFongwraZTnMrI21LJmk1qnkUHM -Jd4kC24Xq9FEjg2oTzdAthdMto1SWUmMyws1TI0k33g89U50fnT5rjJbHQVxXztc -uXtnLEKlst6DgA3C9Bcf7HcDhhBeWSetgrL+rsPkFYU6iJkptZB1sOZmUWbMei4Q -ZLNT8i2vJlErZUC6jTixCgLV48tjuriYwxHflpeqfkLsqHyNehzsw+duU5KapqAQ -HACDqdKf9TKrNmLMiyYtZ9BqLg7e0V4B3Kow0amuC3HwOyi40/wtIYb3l85XxBKr -8iXl4LO0okERxIKf12j9z1u3KXKWea4eTUsvt3jc662kPEFJg7rdGoUJxq357je1 -Prn0va+hQqBrAMQP0XKKjx/HN3OjEZ9XWrxNxDoiRHFGbWHgEIgkmSAr2vX9my+p -Qow9alSMkqXN/DNhORHTdKAFizmMhBwd8sio6+wum1t67ei3Iegbp9UqJ6s0Ho9a -GNpyxtapq2QEGa0PLw1VNt7P8RTYGGmoT0vJqArXv3LVgixrfo4t7chT4X2ncWkD -P/YJ0B00SInryVb+HtDdgD0O/e7z3nGo6jc7ZxMj9pprREFvpVqXaOtjKZgXkfk+ -F4qPoZ9lMZfHyiL7xwoOoGDN6Rn4Y2I49DxWMlobWs1EfB4whQdFDkEoTu7y+/2v -wRygOUIzSyWNK5SYzksxGeR0/krL+Z5rsV/lDmMif77w7olCjMi/B14lTN+0ILcz -plrR2KNByLPmWOB/JZVzPd8TtA3mC4xI5V1ClmS3/g/4QwgiVcIxKazD6X1amH5Y -IdlOO5m4ITC7AhFa6HPFZ1UN3cjfYME1TALU00aJB0kkmW8JBX9iG8OTQDyvBtrc -HPJJovDG6x8ltmvICFz6Rr+8TojuLRLeRw2ESv9alb+IBH1KWzxyIH1lqnqKZntE -7UBF+vw332gVtBnhLfpZusLuUuzFL7XqYMirg5Bx2U8D4npM8DxCXHLuqJUoPIIA -bomK3MSenfjnkrbE4FLh3EqSm9g39pdzOL7YBsp45QMPd0RW13gXnQeLA7LeEqoi -CICkgZbh1g9pKrGDNlNFCE3MbY6BuCM9+Vzl+xWiomFShr1YhNYkQd6qi/5Xg0SN -J3tTlgAXPWlcq/m2FH0p5Bn0lEkR1JmN8q/24XxpakUDUPzV/NYFYIfbqtW1i4RU -oVySR0GPVBY+mw6OCP1JQRPfMyEHIhHe4zC4On1Rw6cAzOfXPl8QGwCjyEsXDBUD -5X1dof8ZyLggr9kj23f7Kwgt6bHNOl1y/YRf7+LEVy0IoKbMsWmmWPPnoGrb6ckx -iuq8dVsjYkysHg3HDdFsqKKTTLw4peHDOK3iwoiQJ1koI0f+8kTsmOL+rdp/iqty -vPJMYFBVjhAnviVRqrY2JDoEmguLlW7Id9SobF2qouoM4LVwE3DQ75mHfKbAbsKD -uSSe+NJkrkYVNPGrTphA/aC4egELJ0Y6weY39Fy4z5D37/m6G2y3iastjas9lAUS -YtlAno3+OGxLsFzii5vHg8nPNXRqTwfsQSrfihCLflbo01YVbpzpYSkNXa5F1KGt -I1heSBt/H2PDidVANCgVz+vcxYcRBXWROrvJuVNi9FfDkRnSyQnVScVT7suXnLO7 -u16w1jrIe7PcZJ+lfOR8PaoeZGHDlJBY2HGvQpL9zlOe3pVjAe8IBSy7aUCutcBz -kPjRDA+x6YZHEdpXOCqkX3ylBL03fAxtTzPIrpNjh9/kOG2uFk/81YHCmzuudbym -bB/vypMpZcXK2qigX2sUjRvfyjYaXvNlh6We1HhPEcB+EhdAJKl5r6dPQeIHIZzs -Dc4yRcvrylVW1DqsYVEqg2eU/94kNudMkPxzPJL3psScUAobzkEJtJFZbXsuEISE -eHruSDLpayI/+k0uXLKb+fTihTBoJ6QJ9E9gcdOlatCIhiZoymIgG+PEX83h2jcS -My8nbqsfY23NH97ft3iEarOQJ5CdUjrIlFP08LFqg9jCS2Zuz+LCQPXiJXWxITCJ -ESfr4HNIsBIkgYLTELjSEviNmmT4wZo+JzwdnleAEGdAzgTdkjkf5CZxNwqpcwYJ -zMBQyvXqaVYjukUmLe/81Pqv+i2+Z7sNTZY9YTXk5sFRLuQ9kgODjArJcM4At3XG -xHgS4IAFZ7TNT6hgHDwIs3QibloEoTK6DXFV8c6mQme+2OaaCZ0d0vNkYSRDiKmT -C4eZHCOWpvOPQVnOzQ/FbKLKQMR8iI+LlF70W5IpOBwN7wdmKzxiZJEJTQAf9Afb -kVVFrESJLDO4sEY6XaVU0435Xlj1dczcZRMBdtA+DrhAQ4wkxCj39/QlxW1n2oVF -/zXaXBhID9zncj66l13BsVFflL+uJWLaP1Dj70OWd2m9DDFmvNHU0R1jb2ZKivEY -aSss5fBDh4tfMJUOg4ruAO5Pvj8Id90bXAa4ZiOt9mXle33mKI74yRW4G0wrsS7S -uUr4FUFTJ4uCkHtdhxELuSk27j26lRaUg7fbyGBvrfavqZ3/vXYs4AHu+eMMMV+j -yYHIFwPXB/LdPJ8oOn4VIBW9BgG8BAV5uZAkr79SZgP1NMFV/KpYTJ8W8i9EVNPu -k/1/zi2v0Bjh1eDsUa0oH5kVuljAs9RGY3qucTzCzU+stjyQ+ebAPtKFXCieaZBM -Lqz7ynUWucks6pZoTEn/atbTshZiXI0+Gsm7ggPgshUOjtRWYTK3mWW6qr8Vb/AX -V0D/htFmj1BrqLiCfUVki9cfgFMGY/CZGmiBp2lEOXV1jbjm8Q9Ev0YtXiBawcQ+ -dWTNk23R1tKaPu/NGRJSxhWBy/X7HS599Zc4veVaDy3ktsbuYhJCDTJy1CVAXqHI -kYg9yixbpvgWQwlJP2whlGFhHFDQFZ/GNfZB+WqXupoBbCzO9MP557unIkAd7wWT -MhB8lj01smYmkCnk417dUyYsS2h5FzEwjAljG53cdyW8HDsqjhaxFI9fowHcAayN -4IYaGb9L5JJ8Cu9M1z9kv0CBrydKzKwB5T53tGcQMx5H32CpTqL+qmDInCMKHB18 -HmnqTBPQuKE3X8TrvHSbHHquU5J6vR/7Yoqnn/o2BbdvEBNWYcznC6HFk0g4Inh0 -0+S329BPKXeM3Y+403/tNBk+VwBrlkhvl3Bm6uUEqA35UKmT8To/5k0vyGoi/lzC -FLTFLQ7FWYx2grd1i/K/p3/TYeuAm3D/LxIZCgfWvn5GxPskrU2hryDiFcDB6pss -d/tFJFAhjUVZ7JfaQEOkBRRzXIwiWIjAa2Fg+w8jzV/F0p8bMhqaPF1iZkOWwVWF -1Fn1G8cH+/i3+hzI2E4mo5miHh52jZGYbF5y0vWT1fBrJTTIwqVDSqzmT+UV9jS3 -FFuSMA3jxBmrMxr26E6ivwFgYMkbRvDO9MeKZfRlvLtIUwuLT+s8Si5t82p1rlb1 -5sBz+fTsoZ2Bc/7xkpL+8E2SY/Qh1RAgfqCeL1n2OUydcNlrU0DBl1HDOYwLhTQg -k5MR/Ionj5ZEIn7viUb3k68TfhwP3aBEbICFALsQfvlk1n9dHttjzRJkbjzURnkC -7lQwdQl3gSAVF2JuaY4H5K2HtmMoktV5QKgMlqvfEggpsHL6RhkAm3i4zX9kZhe8 -1+RGlhv5JI3Bf3JayQQUDYUQP8Qg0xwt1OQkzlhl9TBjr6eHr0yULQl/RzAUzhNt -7SSs9LKR1VSEsQquyx9P+FMi7rGs3+PuJBTiEJ936gfs3YhvYNxGdqGD4M4b/UDs -oOPLHwNSRUSueua4pXGA729GNw08a57+vHWfvzF6JyOkX5Y+X0Y/JclGuauLA2zs -j38APkW7G3LJU57y5nD55aUILQ2HD+gzgJ0n+Q4fjh/7lahGCzc7VdGVtycS0xU6 -YkFp85aWWbez5xW30MPj5WylYBxSFexe1gdElKlUVatgiPCjdhLt6fjs33N21c/G -czgEKsDYre3WRMqFxZHc3pg6hBN0+HR4DKdaDrq/GCCumbYdRHQvqh0zMm/slxnH -ZilxTtNBuh5odxGtF04UvtQWWlMlgHLbzZNvPKi3q9scwDOf0Gyjj9eRNRsWSEYg -YlNsLOvZBhMTDl1qVBaqcRhGdJKdSavmWK0oT3y1lHlvOSKNhLUxZ/wdZR0+QU/h -JwCgsLP6ZOZPW4pe87x7b5RdyrWGIVkQ7Z8KUCn350p9dyaroyuZTMMrsaUFtp2/ -kPEVOKe4u33RIEiaUrBuuG6cCSgyZutjj/GqzcxN71o/+lrujWZ782fFV8XSrGzk -YLVr1TYOwU8ppSmgn/RVSAJdEtqBX9PzFgiBEscTXKQtCx0B/Ja0wnueWEA5jpEY -dQ/BC64lG5yuyA/+Zr0HFpox/d7wqruzSlMHoGKBtQMrImzMxTNZA3I2Y9lm1HoC -73XIIYDtjAIxVRrFjFwVd/w2KTKNAcluswHT2F7L9eDv/y6/vjsaf17Upie2YKq/ -PCAz1+V1r5a58KxOLxQ84qy8W2nlDi4EIgeijj7XB7ebvGgPG00M6loLcy70AiSd -82nLHhPOtr/7AHzUB62RTr+NOK/sVsKqtjVuXH5Bw1Y= -`pragma protect end_protected - -//pragma protect end +// Parameter Define +parameter State_idle = 2'd0; +parameter State_preamble = 2'd1; +parameter State_data_dl1 = 2'd2; +parameter State_data_dl2 = 2'd3; -//pragma protect -//pragma protect begin +// Register Define +reg [1:0] cur_state; +reg [1:0] next_state; +reg preamble_odd; +reg [3:0] rx_d_dl1; +reg rx_dv_dl1; +reg [3:0] rx_d_dl2; +reg rx_dv_dl2; -/* Encryption Envelope */ +// Wire Define -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" -`pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" -`pragma protect key_method = "rsa" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) -`pragma protect key_block -iOcmMtPmoSescVFwbK+zYYNPBct8sX33lkQrQQ9/UU7s5cVpEE2Pgl6mR2G/JJaf -GMO0ShzQsXQBNJHNttoDVjbbwbIgN6JCWUK/JeFLJRk2RzRLDk6M+jiV5uORHCZ8 -TG+qRKidVEZOi6h+Q21xJQdYgx45ojwUIc4wO84q/Xv/ZbMjnGDqigwaeigrlOAI -TeY7WVTaq32P5G7RC0AehmfjZyev9D9h+5gFwPjul+CbIslCiQ51FJy1Q7VO5tHZ -gLcR5FFTii8aAWZSVTrmXftLucQzcQowRTVRsfb/1rhhmU4VprS1mTOKrDtl1aD5 -EhNevvyQHiuVXnts595ZXA== -`pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 8608 ) -`pragma protect data_block -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 -ASiepnwJ6M+mFFhHLXQgEw== -`pragma protect end_protected +/*----------------------------------------------------------------------------------*\ + The main code +\*----------------------------------------------------------------------------------*/ + +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) begin + rx_d_dl1 <= 4'h0; + rx_dv_dl1 <= 1'b0; + rx_d_dl2 <= 4'h0; + rx_dv_dl2 <= 1'b0; + end + else begin + rx_d_dl1 <= rgmii_rxd_LO_i; + rx_dv_dl1 <= rgmii_rx_ctl_HI_i; + rx_d_dl2 <= rx_d_dl1; + rx_dv_dl2 <= rx_dv_dl1; + end +end + +/*----------------------- FSM Region ----------------------------*/ +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) cur_state <= State_idle; + else cur_state <= next_state; +end + +always @ (*) begin + case (cur_state) + State_idle : + if ((rx_dv_dl1 == 1'b1) && (rx_d_dl1 == 4'h5)) + next_state = State_preamble; + else + next_state = State_idle; + + State_preamble : + if (rx_dv_dl1 == 1'b0) + next_state = State_idle; + else if ((rx_d_dl1 == 4'hd) && (preamble_odd == 1'b0)) + next_state = State_data_dl1; + else if ((rx_d_dl1 == 4'hd) && (preamble_odd == 1'b1)) + next_state = State_data_dl2; + else if (rx_d_dl1 != 4'h5) + next_state = State_idle; + else + next_state = State_preamble; + + State_data_dl1 : + if (rx_dv_dl1 == 1'b0) + next_state = State_idle; + else + next_state = State_data_dl1; + + State_data_dl2 : + if (rx_dv_dl2 == 1'b0) + next_state = State_idle; + else + next_state = State_data_dl2; + + default : + next_state = State_idle; + endcase +end + +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) + preamble_odd <= 1'b0; + else if (cur_state == State_preamble) + preamble_odd <= ~preamble_odd; + else + preamble_odd <= 1'b0; +end + +/*----------------------- Sync Output Region ----------------------------*/ + +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) + rgmii_rxd_LO_o <= 4'h0; + else if (eth_speed[2] == 1'b1) + rgmii_rxd_LO_o <= rgmii_rxd_LO_i; + else if ((cur_state == State_preamble) && (rx_d_dl1 == 4'hd) && (preamble_odd == 1'b1)) + rgmii_rxd_LO_o <= 4'h5; + else if (cur_state == State_data_dl2) + rgmii_rxd_LO_o <= rx_d_dl2; + else + rgmii_rxd_LO_o <= rx_d_dl1; +end + +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) + rgmii_rxd_HI_o <= 4'h0; + else if (eth_speed[2] == 1'b1) + rgmii_rxd_HI_o <= rgmii_rxd_HI_i; + else + rgmii_rxd_HI_o <= 4'h0; +end + +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) + rgmii_rx_ctl_HI_o <= 1'b0; + else if (eth_speed[2] == 1'b1) + rgmii_rx_ctl_HI_o <= rgmii_rx_ctl_HI_i; + else if ((cur_state == State_preamble) && (rx_d_dl1 == 4'hd) && (preamble_odd == 1'b1)) + rgmii_rx_ctl_HI_o <= 1'b1; + else if (cur_state == State_data_dl2) + rgmii_rx_ctl_HI_o <= rx_dv_dl2; + else + rgmii_rx_ctl_HI_o <= rx_dv_dl1; +end + +always @(posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) + rgmii_rx_ctl_LO_o <= 1'b0; + else if (eth_speed[2] == 1'b1) + rgmii_rx_ctl_LO_o <= rgmii_rx_ctl_LO_i; + else if ((cur_state == State_preamble) && (rx_d_dl1 == 4'hd) && (preamble_odd == 1'b1)) + rgmii_rx_ctl_LO_o <= 1'b1; + else if (cur_state == State_data_dl2) + rgmii_rx_ctl_LO_o <= rx_dv_dl2; + else + rgmii_rx_ctl_LO_o <= rx_dv_dl1; +end + +endmodule + + +///////////////////////////////////////////////////////////////////////////// +// _____ +// / _______ Copyright (C) 2013-2020 Efinix Inc. All rights reserved. +// / / \ +// / / .. / +// / / .' / +// __/ /.' / +// __ \ / +// /_/ /\ \_____/ / +// ____/ \_______/ +// +// ******************************* +// Revisions: +// 1.0 Initial rev +// +// ******************************* + +module `IP_MODULE_NAME(rgmii) #( + parameter RGMII_SYNC_EN = 1 +) ( + //Globle Signals + input tx_mac_aclk, + input tx_reset, + input rx_reset, + //Configuration Signals + input [2:0] eth_speed, + input rgmii_rxc_edge, //0:DDIO Rising Edge; 1:DDIO Falling Edge; + //Phy Interface + input [7:0] txd, + input tx_en, + input tx_er, + input [1:0] txc, //if rgmii_txc_dly set 0, used clk_125m clock. if rgmii_txc_dly set 1, used clk_125m_90deg clock. + output reg [7:0] rxd, + output reg rx_dv, + output reg rx_er, + //RGMII Interface + output reg [3:0] rgmii_txd_HI, + output reg [3:0] rgmii_txd_LO, + output reg rgmii_tx_ctl_HI, + output reg rgmii_tx_ctl_LO, + output reg rgmii_txc_HI, + output reg rgmii_txc_LO, + input [3:0] rgmii_rxd_HI, + input [3:0] rgmii_rxd_LO, + input rgmii_rx_ctl_HI, + input rgmii_rx_ctl_LO, + input rgmii_rxc + //Status and Error Signals +); +// Parameter Define + +// Register Define +reg [3:0] rgmii_rxd_HI_d1; +reg rgmii_rx_ctl_HI_d1; +reg [3:0] rgmii_txd_HI_r; +reg [3:0] rgmii_txd_LO_r; +reg rgmii_tx_ctl_HI_r; +reg rgmii_tx_ctl_LO_r; +reg rgmii_txc_HI_r; +reg rgmii_txc_LO_r; +// Wire Define +wire tx_en_to_ddr; +wire rgmii_tx_ctl_int; +wire [3:0] txd_falling; +/*----------------------------------------------------------------------------------*\ + The main code +\*----------------------------------------------------------------------------------*/ + +/*----------------------- RGMII Tx Region ----------------------------*/ +assign tx_en_to_ddr = (eth_speed[2] == 1'b1) ? tx_en : tx_en && (!tx_er); +assign rgmii_tx_ctl_int = tx_en ^ tx_er; + +assign txd_falling = (eth_speed[2] == 1'b1) ? txd[7:4] : txd[3:0]; + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset) begin + rgmii_txc_HI_r <= 1'b0; + rgmii_txc_LO_r <= 1'b0; + rgmii_tx_ctl_HI_r <= 1'b0; + rgmii_tx_ctl_LO_r <= 1'b0; + rgmii_txd_HI_r <= 4'b0; + rgmii_txd_LO_r <= 4'b0; + end + else begin + rgmii_txc_HI_r <= txc[0]; + rgmii_txc_LO_r <= txc[1]; + rgmii_tx_ctl_HI_r <= tx_en_to_ddr; + rgmii_tx_ctl_LO_r <= rgmii_tx_ctl_int; + rgmii_txd_HI_r <= txd[3:0]; + rgmii_txd_LO_r <= txd_falling; + end +end + + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset) begin + rgmii_txc_HI <= 1'b0; + rgmii_txc_LO <= 1'b0; + rgmii_tx_ctl_HI <= 1'b0; + rgmii_tx_ctl_LO <= 1'b0; + rgmii_txd_HI <= 4'b0; + rgmii_txd_LO <= 4'b0; + end + else begin + rgmii_txc_HI <= rgmii_txc_HI_r; + rgmii_txc_LO <= rgmii_txc_LO_r; + rgmii_tx_ctl_HI <= rgmii_tx_ctl_HI_r; + rgmii_tx_ctl_LO <= rgmii_tx_ctl_LO_r; + rgmii_txd_HI <= rgmii_txd_HI_r; + rgmii_txd_LO <= rgmii_txd_LO_r; + end +end + +/*----------------------- RGMII Rx Region ----------------------------*/ +//rgmii_rxd & rgmii_rx_ctl +always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) begin + rgmii_rxd_HI_d1 <= 4'h0; + rgmii_rx_ctl_HI_d1 <= 1'b0; + end + else begin + rgmii_rxd_HI_d1 <= rgmii_rxd_HI; + rgmii_rx_ctl_HI_d1 <= rgmii_rx_ctl_HI; + end +end + +generate + if (RGMII_SYNC_EN == 0) begin + always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) begin + rxd[7:4] <= 4'h0; + rxd[3:0] <= 4'h0; + rx_dv <= 1'b0; + rx_er <= 1'b0; + end + else if (eth_speed[2] == 1'b1) begin //1000M + if (rgmii_rxc_edge == 1'b0) begin //0:DDIO Rising Edge + rxd[7:4] <= rgmii_rxd_LO; + rxd[3:0] <= rgmii_rxd_HI_d1; + rx_dv <= rgmii_rx_ctl_HI_d1; + rx_er <= rgmii_rx_ctl_HI_d1^rgmii_rx_ctl_LO; + end + else begin//1:DDIO Falling Edge + rxd[7:4] <= rgmii_rxd_HI; + rxd[3:0] <= rgmii_rxd_LO; + rx_dv <= rgmii_rx_ctl_LO; + rx_er <= rgmii_rx_ctl_LO^rgmii_rx_ctl_HI; + end + end + else begin //100M or 10M + rxd[7:4] <= 4'b0; + rxd[3:0] <= rgmii_rxd_LO; + rx_dv <= rgmii_rx_ctl_LO; + rx_er <= rgmii_rx_ctl_LO^rgmii_rx_ctl_HI_d1; + end + end + end + else begin + reg [3:0] rgmii_rxd_HI_i; + reg [3:0] rgmii_rxd_LO_i; + reg rgmii_rx_ctl_HI_i; + reg rgmii_rx_ctl_LO_i; + wire [3:0] rgmii_rxd_HI_sync; + wire [3:0] rgmii_rxd_LO_sync; + wire rgmii_rx_ctl_HI_sync; + wire rgmii_rx_ctl_LO_sync; + + always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) begin + rgmii_rxd_HI_i <= 4'h0; + rgmii_rxd_LO_i <= 4'h0; + rgmii_rx_ctl_HI_i <= 1'b0; + rgmii_rx_ctl_LO_i <= 1'b0; + end + else if (eth_speed[2] == 1'b1) begin //1000M + if (rgmii_rxc_edge == 1'b0) begin //0:DDIO Rising Edge + rgmii_rxd_HI_i <= rgmii_rxd_LO; + rgmii_rxd_LO_i <= rgmii_rxd_HI_d1; + rgmii_rx_ctl_HI_i <= rgmii_rx_ctl_HI_d1; + rgmii_rx_ctl_LO_i <= rgmii_rx_ctl_LO; + end + else begin //1:DDIO Falling Edge + rgmii_rxd_HI_i <= rgmii_rxd_HI; + rgmii_rxd_LO_i <= rgmii_rxd_LO; + rgmii_rx_ctl_HI_i <= rgmii_rx_ctl_HI; + rgmii_rx_ctl_LO_i <= rgmii_rx_ctl_LO; + end + end + else begin//100M or 10M + rgmii_rxd_HI_i <= rgmii_rxd_HI_d1; + rgmii_rxd_LO_i <= rgmii_rxd_LO; + rgmii_rx_ctl_HI_i <= rgmii_rx_ctl_LO; + rgmii_rx_ctl_LO_i <= rgmii_rx_ctl_HI_d1; + end + end + + always @ (posedge rgmii_rxc or posedge rx_reset) begin + if (rx_reset) begin + rxd[7:4] <= 4'h0; + rxd[3:0] <= 4'h0; + rx_dv <= 1'b0; + rx_er <= 1'b0; + end + else begin + rxd[7:4] <= rgmii_rxd_HI_sync; + rxd[3:0] <= rgmii_rxd_LO_sync; + rx_dv <= rgmii_rx_ctl_HI_sync; + rx_er <= rgmii_rx_ctl_HI_sync^rgmii_rx_ctl_LO_sync; + end + end + + /*----------------------- RGMII Rx Sync Module -----------------------*/ + `IP_MODULE_NAME(rgmii_sync) u_rgmii_sync + ( + //Globle Signals + .rgmii_rxc (rgmii_rxc ), + .rx_reset (rx_reset ), + .eth_speed (eth_speed ), + //RGMII Rx Interface Input + .rgmii_rxd_HI_i (rgmii_rxd_HI_i ), + .rgmii_rxd_LO_i (rgmii_rxd_LO_i ), + .rgmii_rx_ctl_HI_i (rgmii_rx_ctl_HI_i ), + .rgmii_rx_ctl_LO_i (rgmii_rx_ctl_LO_i ), + //RGMII Rx Interface Output + .rgmii_rxd_HI_o (rgmii_rxd_HI_sync ), + .rgmii_rxd_LO_o (rgmii_rxd_LO_sync ), + .rgmii_rx_ctl_HI_o (rgmii_rx_ctl_HI_sync ), + .rgmii_rx_ctl_LO_o (rgmii_rx_ctl_LO_sync ) + ); + end +endgenerate + + +endmodule + + +module `IP_MODULE_NAME(rmii_if) +( +//Globle Signals +input tx_mac_aclk, +output reg tx_mac_aclk_en, +input tx_reset, +output wire rx_mac_aclk, +output reg rx_mac_aclk_en, +input rx_reset, +//Configuration Signals +input [2:0] eth_speed, +//GMII Interface +output reg [7:0] gm_rx_d, +output reg gm_rx_dv, +output reg gm_rx_err, +input [7:0] gm_tx_d, +input gm_tx_en, +input gm_tx_err, +//RGMII Interface +input rmii_clk_ref, +output reg [1:0] rmii_txd, +output reg rmii_tx_en, + +input [1:0] rmii_rxd, +input rmii_crs_dv, +input rmii_rx_err + +//Status and Error Signals +); +// Parameter Define + +// Register Define +reg [6:0] aclk_en_cnt; +reg [6:0] rx_aclk_en_cnt; +reg [1:0] txd; +reg tx_en; +reg tx_er; +reg rx_err_dl1; +reg rx_dv_dl1; +reg [7:0] rxd_dl1; +reg [6:0] rx_odd_data_ptr; +reg [1:0] rxd; +reg rx_dv; +reg rx_er; +reg [7:0] gm_tx_d_temp; +reg tx_en_temp; +reg [6:0] txbit_cnt; +reg rx_dv_compensate; +reg rx_err_compensate; +reg rx_err_latch; +reg [7:0] rx_d_compensate; +reg [6:0] rx_compensate_cnt; +// Wire Define + +/*----------------------------------------------------------------------------------*\ + The main code +\*----------------------------------------------------------------------------------*/ + +/*----------------------- Tx Region ----------------------------*/ +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + aclk_en_cnt <= 7'd0; + else if (((eth_speed == 3'h2) && (aclk_en_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (aclk_en_cnt == 7'd39))) + aclk_en_cnt <= 7'd0; + else + aclk_en_cnt <= aclk_en_cnt + 1'b1; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_mac_aclk_en <= 1'b0; + else if (aclk_en_cnt == 7'd0) + tx_mac_aclk_en <= 1'b1; + else + tx_mac_aclk_en <= 1'b0; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + gm_tx_d_temp <= 8'h0; + else if ((gm_tx_en == 1'b1) && (tx_mac_aclk_en == 1'b1)) + gm_tx_d_temp <= gm_tx_d; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_en_temp <= 1'b0; + else if(tx_mac_aclk_en == 1'b1) + tx_en_temp <= gm_tx_en; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txbit_cnt <= 7'd0; + else if (((eth_speed == 3'h2) && (txbit_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (txbit_cnt == 7'd39))) + txbit_cnt <= 7'd0; + else if (tx_en_temp == 1'b1) + txbit_cnt <= txbit_cnt + 1'b1; + else + txbit_cnt <= 7'd0; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + txd <= 2'h0; + else if (eth_speed == 3'h2) begin + case(txbit_cnt[1:0]) + 2'b00: txd <= gm_tx_d_temp[1:0]; + 2'b01: txd <= gm_tx_d_temp[3:2]; + 2'b10: txd <= gm_tx_d_temp[5:4]; + 2'b11: txd <= gm_tx_d_temp[7:6]; + default; + endcase + end + else if (eth_speed == 3'h1) begin + case(txbit_cnt[5:0]) + 6'd00: txd <= gm_tx_d_temp[1:0]; + 6'd10: txd <= gm_tx_d_temp[3:2]; + 6'd20: txd <= gm_tx_d_temp[5:4]; + 6'd30: txd <= gm_tx_d_temp[7:6]; + default; + endcase + end + else; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_en <= 1'b0; + else + tx_en <= tx_en_temp; +end + +always @ (posedge tx_mac_aclk or posedge tx_reset) begin + if (tx_reset == 1'b1) + tx_er <= 1'b0; + else if (tx_mac_aclk_en == 1'b1) + tx_er <= gm_tx_err; +end + +always @ (posedge rmii_clk_ref or posedge tx_reset) begin + if (tx_reset == 1'b1) begin + rmii_tx_en <= 1'b0; + rmii_txd <= 2'b0; + end + else begin + rmii_tx_en <= tx_en; + rmii_txd <= txd[1:0]; + end +end + +/*----------------------- Rx Region ----------------------------*/ +always @(posedge rmii_clk_ref or posedge rx_reset) begin + if (rx_reset == 1'b1) begin + rxd <= 2'b00; + rx_dv <= 1'b0; + rx_er <= 1'b0; + end + else begin + rxd <= rmii_rxd; + rx_dv <= rmii_crs_dv; + rx_er <= rmii_rx_err; + end +end + +assign rx_mac_aclk = rmii_clk_ref; + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_aclk_en_cnt <= 7'd0; + else if (((eth_speed == 3'h2) && (rx_aclk_en_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (rx_aclk_en_cnt == 7'd39))) + rx_aclk_en_cnt <= 7'd0; + else + rx_aclk_en_cnt <= rx_aclk_en_cnt + 1'b1; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_mac_aclk_en <= 1'b0; + else if (rx_aclk_en_cnt == 7'd0) + rx_mac_aclk_en <= 1'b1; + else + rx_mac_aclk_en <= 1'b0; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_odd_data_ptr <= 7'd0; + else if (((eth_speed == 3'h2) && (rx_odd_data_ptr == 7'd3)) || + ((eth_speed == 3'h1) && (rx_odd_data_ptr == 7'd39)) || (rx_dv == 1'b0)) + rx_odd_data_ptr <= 7'd0; + else + rx_odd_data_ptr <= rx_odd_data_ptr + 1'b1; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_dv_dl1 <= 1'b0; + else + rx_dv_dl1 <= rx_dv; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_err_dl1 <= 1'b0; + else + rx_err_dl1 <= rx_er; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rxd_dl1 <= 8'h0; + else if (eth_speed == 3'h2) begin + case (rx_odd_data_ptr[1:0]) + 2'b00: rxd_dl1[1:0] <= rxd; + 2'b01: rxd_dl1[3:2] <= rxd; + 2'b10: rxd_dl1[5:4] <= rxd; + 2'b11: rxd_dl1[7:6] <= rxd; + default; + endcase + end + else if (eth_speed == 3'h1) begin + case (rx_odd_data_ptr[5:0]) + 6'd00: rxd_dl1[1:0] <= rxd; + 6'd10: rxd_dl1[3:2] <= rxd; + 6'd20: rxd_dl1[5:4] <= rxd; + 6'd30: rxd_dl1[7:6] <= rxd; + default; + endcase + end + else; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_compensate_cnt <= 7'b0; + else if (rx_dv_dl1 == 1'b1) + rx_compensate_cnt <= 7'b0; + else if (((eth_speed == 3'h2) && (rx_compensate_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (rx_compensate_cnt == 7'd39))) + rx_compensate_cnt <= rx_compensate_cnt; + else + rx_compensate_cnt <= rx_compensate_cnt + 1; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_dv_compensate <= 1'b0; + else if (((eth_speed == 3'h2) && (rx_compensate_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (rx_compensate_cnt == 7'd39))) + rx_dv_compensate <= 1'b0; + else if ((rx_dv_dl1 == 1'b1) && rx_odd_data_ptr == 7'd0) + rx_dv_compensate <= 1'b1; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_err_latch <= 1'b0; + else begin + if (rx_dv & rx_er) rx_err_latch <= 1'b1; + else if (rx_odd_data_ptr == 7'd0) rx_err_latch <= 1'b0; + else rx_err_latch <= rx_err_latch; + end +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_err_compensate <= 1'b0; + else if (((eth_speed == 3'h2) && (rx_compensate_cnt == 7'd3)) || + ((eth_speed == 3'h1) && (rx_compensate_cnt == 7'd39))) + rx_err_compensate <= 1'b0; + else if (rx_odd_data_ptr == 7'd0) + rx_err_compensate <= rx_err_latch; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + rx_d_compensate <= 8'h0; + else if ((rx_dv_dl1 == 1'b1) && rx_odd_data_ptr == 7'd0) + rx_d_compensate <= rxd_dl1; + else; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_dv <= 1'b0; + else if (rx_mac_aclk_en == 1'b1) + gm_rx_dv <= rx_dv_compensate; +end + + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_d <= 8'h0; + else if (rx_mac_aclk_en == 1'b1) + gm_rx_d <= rx_d_compensate; + else; +end + +always @ (posedge rx_mac_aclk or posedge rx_reset) begin + if (rx_reset == 1'b1) + gm_rx_err <= 1'b0; + else if (rx_mac_aclk_en == 1'b1) + gm_rx_err <= rx_err_compensate; +end + +endmodule -//pragma protect end module `IP_MODULE_NAME(efx_mac1gbe) #( @@ -8623,117 +9093,117 @@ module `IP_MODULE_NAME(efx_mac1gbe) #( `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -ft+oCw3+ULBCewRA+GWF3gAyRqMckHa7OoVYBehC0WtRsjKrz9IB1MMz6UL3nPxy -meMA6MaAgq8N+XmSBR2KvDzFg2dz0ow7ZGeFIB9TCc8qv2siYJSdfIikVz+D/q0K -j2w3YJKH2EnB5pMGiF+tEl+abMeZlrWsmB8VEic8ncy4fYcW/mexeUIPy/0+Cvrb -Bjdc+KIbqULGE/jhdQDt3MoRUdAgc42w1QMifMQVjE6Ilbc5fU1KhkdluxVbclz7 -vDN+sbm8bDEBt21l0neBXnlQED61N1l2BpC5QUrlUfEEcFh5fF5Qib94REjEsBcj -xViuHybUuMqclm7zxewiiw== +H1QhdHwPCw4FTFVKfREEloX4Ul+jRhDrKdS6DAFqmR7d1Yc/YiaxRdFdhm/E6pG/ +bVdqR9w77voWYg5JTKlSBfXgDWFAEUuMW/7WUzs6aQAC3Hx6XbXh9WZBIyadkXf0 +dZnqlxxZSlaMuXnyEq5FKZB4a/mbzZotE0/jjDHZ48QsV7VxKpt2wPnrwHRzRwuZ +pFYg9SUPwbYS06jRoG4rGAnY9X8K2GIubhZbS5S2IAoSIw6Urykxl8J2raTBk7/Q +/kPv/d56MuDf+PqLWMWOtJLGu8FX4CyH3umRY6e9P5q0qJtv/0uUC21+xXvQbnWH +pV93YA7YL4/nAKB63762Lw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 4864 ) `pragma protect data_block -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 -IUVQJA36X4qijd1W35y+Rg== +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 +m7eCK1ymdHqXLWqKpLfogg== `pragma protect end_protected //pragma protect end @@ -8751,78 +9221,78 @@ IUVQJA36X4qijd1W35y+Rg== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -XTizh0N4D1fxrmT3GK/7F5y6E9a2KJM648ehcSKi/+rd5w5XWsmMybsG7BHTjzNJ -0JKdAiilbdklz1CNx4VqnjYPzwZsBCyDhX8xEUiAluAPaDmXw2/acMF57Dab+quN -EkpreZAFWtUHnZjw8QPsfAZhoTclHf43sZBhJPgH/0DBygLmaeL1/ntugeEUPWB0 -0vN229ttSkK8gLNOK/v5NlOqEdJkZBSIXbO24KsTzphmEBSyktj6okaigBwZV3ul -KJHdnKyqPZNoMpPtLtDR6SglcufO6tCUIItOsUZ95egaI6wW6nchF49sPo6xQ6CE -8FkXkD+nEPXFroSTRvfncw== +mVvgvhMnm94S863IKYifMrYJ8xfsornOKZDgbMsVgTTwruDWBKzXogBG9y5Jlj6b +XxPsSERWYj5leeHtTs+Jcc8niKtaytfMmB2wr0w7AGIFJPm4a6HRr2CgcMXA/EgF +Wr4stv2xlMfuBJ22zmBSZHvjew8HSBWdx+bxKETVlgs1uIPfR2PqreXod30MhUKX +6dztGRSMURXuvohxIZ0x8mhcKhFK6/rfG1UGcimNX12je9YQ4IRVtRoTs3crHEkf +OJC45+yDyUujE0emiPRnQQs456SRPWrZTFZD6wQfqjH45sKauM16wFyeUi18kseE +HZYJHNunZ3i9Y+/GIw2pcA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 2992 ) `pragma protect data_block -o3pviCE6Podxk5kGrTGJddx0jWhFn/9HaSTy31jCa+Ls/YmM117h1wwtc27FLavr -PncVr9rqk2F3/Et/oc+Zs1cWZqWLKCLip12jCdUrJtWKI84RXEW9o0fLGZ83a5CJ -VgJujrEiLVI0Ycf4HgjKXPNK2ewlFi5Er4NvP519rhiMSeQG+2k8Rmgjxzci+cir -0nOvrGwYPQl81aYHVRnq3a9sZWtmdbpWIpkSa3tqZAyKhU+RPMfM8UsLnJPw4fte -HT4orOlxhzISrB2EZ4LSV1XclWicQZ151wwsrNBp/XaVZTA/1SZgMFznvh9dPp4L -wNciwbIjMRjPOHE3iyxgVIn3mIKRVgUc76ov/y7xsXkPk62vu0B0v7bfqoR0sIPU -pPFbBOkn1fZ702x7mN5+Vlf/qqsSOFf79wcTpj+lpsZdoJ8siiTfZkzOewkG0ITI -QBk8yaYE6KC0pUjsCtR0huq7HygoBaOlUhuN1EIy7hJMrBu7CTgIvxOFPQyZBDC5 -eozdONEbROrVzszC+QZRvU0bVfiIyBGowImskD+iyawSf36rdmtyxvB7sMPEq3oc -hQ7JHHVPJjN+wvVogK2UEh8uVpS7uGhQN3GFDLGU/e6ciYwv2OWrSlk3bTHPWyw9 -MH460hdMIsCMOu4q19MJXuHQOI7yyouERlu8UR8SGv20xPk0bHSsLSCHX75x5Q1S -GgqTMEAQpNgIWRZ1myGb8BcxDTlADxQ9M/dWSOOR7v0Cdpwbe4xd3VuZybEs9Paa -DrfeWHvTBewwVTJnIpjSqycEiTtYgkO99Dk8wBwJiwWNLZ43dUjW8aBdPo/p7uOX -OcJtVBF7yykcfb9gmCvzFFZLFeCZq/Hb/Httupvfmo6iRy5vOB/t75B6azmlMDV2 -+kmYcb49NVcRZbdt8vI1pEnun0WexF0+AdIzGZiqUZN0DoI1LiMCkx58di1nCfAy -Mz8GIJEfykt4hytNORnOE+H+VJZvBBD77TEgD+ZTqjjtkCnR5imUJmvI6/CgZtjm -goHHuM8guJk5ql2vHzbBDzjzZBVR2BB8Expylj157BwkzkiwVvJpHUmJTiaXJLcD -d+ICcIMQMsSCMrp12rqdslXtk9saQXbLpX+wpANvKYNYUaeXcLDr9jK2UPCImFIv -MENvjMb7XOUcuxpacRBUP2ILityC5xV+xpiJww+9gXgZAUG0HCX2R/o8QJ2t64a1 -jqt8iiE85pRw62kNYFqx47aipKGC98aGid/PSTjqc5oO5jEKpDV18WRZNrNiEiI6 -HR7inhvXSZ7y1ahSAv0Y4as1cdPgcbX8t3mOjveOrsHQcnZ9yDpwjLkUJ4Ws//yb -qONe9j63KJkRmLOe7uqYW+zUYeAnzFa8OXwAeTyrup76egr/b0MAOgq0A4bZTF7W -VzynCZrLwWGM+osUWgaQwrNa6r4C7N6b9K0vK3mLj0Q/J4kP2jvmohBaOb8JWL8Z -HEBwFRPKNGb23ySXr7U2QvJM1sRwlVEJpW1fS3EbzW8XEI926e+/BehXhWht/9an -sa7iKm8N519EgDJW/rqTa8LVoHvITsgJKfs7gVd2l9GrUfom+izPkiOV4DfOQh7O -J561iA5s7PmAJ1r8z/njXZGO/m9QFRbBVV+RZSqk15MuFIILZOI8PdA1ZcwAhATA -e+nqq/GNKFYMsARrLLWvnYgHcpke8md3TKOtWcupDEoHvufzvCLn9ANTH0k4Aek+ -2jm7PF5RccPr4+OF7GVpxa1wBXH9dBAxuMu6WJDhwXZQ4zbOJfc4DHbrjw9qUmCC -DNyTqV6NqKd0/mJJajVUR56tQkk+gDedbw3XRtuFpyejsqHkh8PyOAjGCooCoSLQ -OGzNHDeiSZ8EOTKFS6mCjBUveZo5o7EjdqeW8gc8Tg2quCDy5FKQsjYkCgkU9eQi -hYulNfyRAR2wOXXOXy0lskBr5lEHneuXtKBheHB9cERk/FqeCnPARuPRXzybxsRN -WfXKPKXT1vKo64s0I/TO3Rs3VyTFLkzs1F5Pq/y0P0bDwHfAaBChbFXQXu9cOMF3 -/b1e5KPm/t1EXdswfOgeI7JQLTAHxfIhFFMPLnjp7cRmsFxI0J6lIzo4bUgNSoaY -oRxQkG564ETvA8XKw1Mv1Utx9bs6oTgfnNV6rISWBEuYHomY8kV4T57NFBV8RlvS -cb2ohNm+TeaJyf5blN56XlDaEc1jTHk2712cLgo0Vs6oSJh3KQuGriZaWNatR5pi -t6D6Wg4qFgEVgaQvh4CBds+7nizhVBF68JaMePfqPBLS2T0TaVizRtRbgZJCaWUI -xjLeYn9as9gtCKp3m5lDG4Vl5HzZRwFeWgcpLR9nmRDk5ubrIWoX+uj819fKrdfH -XRFxmAwH3zDJ2fHmfoEpNxRhR1FT1fKPhD4dUd1Peq7rphtJo++PAhuPjvtYQbKZ -nzcBrsoLOgQoKb2j13B8mPXndNzGqI2MbAopVzxzlyxVBFJHHzl+73qtkYUh9tiq -Bw+0RCmGUbL5Dr5k9z5IhRVF1niKVNnrIIlo6nTgfSGY0FfLscAJNipxApCfRsx9 -8jcWGZsjP2EKsb6PDokS4v5IY6Pg3s1j15cqUx7hsu0aMTLbCUZ1G9QFDz/lytcj -k9Ylbdw6ykaQvWr5b/n2iCl/l0ZJRdOu6XfTHuEG1KamB/26d+rSnSgCJxqbxwqs -G/I3FhsGDPMcVD/aFHcr/eDbSVayP5+CT86ZwGul79VLfNG1v2zdhOnS4Rp7ch/O -Uumg/mHJDyWVAIiZIFgIFIdiqgcSoJkLG8/UD0TCC2aIFNAijAB1gp9YZ0SYoYrb -oef5jtH3Wg/aMqdlFVqlBBmn8EZ7StoV3WNOWk2a4YEfP7azLMiEW7Q/1otNZxAj -ApMifVHyyWS4cVimzLxqTEGeJo4oxZ0mtSl+N4jYvSB7rf3LhH56uOoa8lraBSye -1LYYCVNkOvyS6Oq4uRvA9ZaPhikrucUdk5WG/pVNplLG0C3QWoAFEG87UBd21rhR -zz9umAr3jiFzHjxQuC77N0qcra4IHn4Hk108u7NbrqkfDPFsT1TukX1GDx89WFMo -D0Wq5glJ7cM9HNCrf4jkBs/kNPBrcIFBW7Y/Ic0TjF+KuL/28eS9uuU/2OSizwUV -tKKMO4yi8luehfvs7cJNdLiPwHZB0gH5I6nDr9tfkTqZ+dPivQ31RYkzaQdT6nui -yVGYD+gSFVH87UcIzkNyVt3VgHUxhO4+9hoG09hjvZ3UYBfiJMKQ1CNS1nT2SdG9 -C+eBhKr/9xo9/ddn0bz6lb3XrXrLuKl0RCo4BSaVB++JJw+fROD6LDBc+q5oWJ4w -h2ROfJOo0RlRnuVoWQue3zzmUvXz2jner0AmJlWKsy/rLb5hAQaBjzsn+er7/QS0 -42ACqNEdmwxqBBB6StGeVsud3u2/xk8y/DT3wXeYyMzA3t+dvxesTEDy2LeikwZ3 -of2zclfXAIOvQ6pCftR8PBxnEN/w+1YdtR8vqhIHynRJox+Kaq1zBrWGeEVNgai4 -i86QeahtdPkL3OldgdxcjAD8atj5vICUA0GI0WHAv8qo6AHNYB5mKr7nhT70l1vo -nicSFQ6Pu8vuxUp5sZn5Qc1ddrJLVhzQ1ZdCzlESynHYM6D0Ev4Qvcx9kmx2WXrc -O89Q816cMv7e33IENeVYSmRejQcQ1zm1gRvPloz9coFDlCdN/OkUsbOBYwh4kYg7 -7V//JdAlYluch9YMBluz6OKDxrBmISQejtDGWHArtWRanb+ngPLe60LdHROSC/5u -8gBMiV6two9MCLsE1iYsSxid9G8PqTd1h90HBgKWRVR7AE/kJj26tH4J8kaiemAQ -vbucpgKljGmhlWBX0NS7ntRONv0ZA7NZPB5i6rUiQFqIC6w44K16mcgrlCSKEFB6 -7kWI77bLNOnbQI104hphv/kWSkp/p6E7RXekzRDnORCO5r2bwva3pOKR4y72SSqI -f653sVOwE27AVPzMh6xMHA== +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 +8A70A61qnNcIErsfzPiyuw== `pragma protect end_protected //pragma protect end @@ -8840,112 +9310,112 @@ f653sVOwE27AVPzMh6xMHA== `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -Ywq6bANkE3zr8j7WK4EoAEwy5m1HmiwvNToG0S+RUkMg0ExMqjw7Q+Oe0Nl+uFcT -6/9qx4DNxSgE1tIzLbAN8nxg1+bh37T0JiT4vhdPy92OhxLKrviQg4I9oshvHWSL -pFWq6Te7wC/GgY85cXbingoYu9OIBwwtrUeiXEwjvIKn6C9nV3a9UjWO/rVGkT+e -1Twuk9n+p8rEnpAjMMBQ4BwVKKMhHv4Kjyb+cNzLLZdWrcPFQPl8DcIYWYOLXZ2I -WurKHB8jFf59lO2d1gVJRzi9ZTacsNYg6rHQzjNu2SjMrsb8BCfmnY+OlVZBGkYF -J3JjXyORi2DYSKLdeqInAQ== +Y27KIRKJjtKKh8+JhaOdD1HnMIAg1vAy91sb3yHSrZFQan4hrYUVe/4SCk08lPaA +PXSdtIBtBRQob9ZOSyO3lWXXTf7VA1SuyO4smLBwKsVdJOpkfLkl1gUwN1mjEhOF +cbprpE2BqJo6CbKFweajrCBc99YqxRgKnoAI1L8K4otrr4N/DN5JZmawAEUyKcTe +2Hq0vo+1GqvWw/FcUEmaN0xyzectw1YN5gkEW+9fdtQ/3TbGPmIQcNZlztvxAFF9 +/bg9GpoVg1wXW6EiStOJXjquDqW0f6BwtmMt4jHyWok+Ep7ra+kkmyMPjADxQ9fT +XJcvfySoe3fbipaNYrwf0g== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 4640 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -8963,115 +9433,115 @@ R940V6AVzqFc8jiftdY1oLQWJV/VxAgvkEYJ0+PsZeU= `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -FBClJjQlG/li+/pJohnehNoSYEVQZgec3ZFnFF/DiGGUuFigrNsqPDcTFoOqSFFW -xxbGR7R/iRBxzczCrJqHgL4Q7p5FsRuypH7wCBOJqhsGiZ0linsX7TAykhrVNGT9 -BfXNhMo0DgRyYjbgAud/dasIV3HBIl1Y2K/ZYXiUg+mpJgodcBg52EB2zmmA89X1 -byxWwq7RPu5aEE5i1maJAYh4IkjDlytcvGDK81kxFAWFAsiKmn2eCq5hlDWVXdzl -2gYFRt8m9b5HmClJrkccA3YKkW0diI9y0a8F0oFY0A2p2wj/t4reJgwOAme+v5i7 -l9zc9ZYHnaYFSL0ym0eUpA== +a5V59/f/XBP/nAjarrsl/GQE8850CE8/fC9FKCy4HCDI+XK1qV8AJgmf5FwFbWkE +t45Zr7GI0Qj873B/LA+xlMjZPTl7Fsk9phWnOEFvFSj660Xz5NkKWd6uEyrc4ogU +dh17ioFf59d8S1h6kzq2FA7cTB9mh4VhJ+vi3DMLhYT0HGnL2tOAjQ+tSoPZNIfL +Eh3bbUOr39mLCZWK4W5jFYfYM/mBVryryNU5TJoaskxq2yi8b7W2mdTpHuwq/KhT +ZJsQXjxLm60Q6fplv0BsXxvFsgw9WG+JZ/fTZrODEz1MixxuM1QdPE93Nv6ct/9X +kVFYzxNo5gTVWvU5tCqF9w== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 4800 ) `pragma protect data_block -wNwbeqKplTyWYcZjmoWAR+V70s+KlaUIRsFHfD2rLCv47PGWMXA3AbTisxedOCpT -HPXK/RThdKpij1wX8sQaID6ZzUsXbUBbzHOk2w6TlZPBa1p5b3wqGTYR9neFW873 -ncg26zUZpj8pUDtDP5vlB56o+IiKFh5gu+IISv9tW+M42nKCFmRRKFmuqh2u/ccQ -Y7FOYrccq0s4uHIEgLx7J6rVT+U+pg8b2wZR4+kR6YOPOmqFNEDqGyoZRLxCU8wA -n1BYwpEEik0mx0A470xi21OX1rXQTqQXmvNlyYoH3BPpCMYrBcxYwZp0W7CJsU4i -HyU5lpSa04402vdNEoWNoBuROwesB226Xi38JSUftvGihQnVtx5gSmvg72TDNEG3 -aN8HVDAnhz6XaTHpvi+fp+E7M62CK1DViIvQGa3UyK2UrBMvS+GSZ0n6HBPNzc+d -o7SaQNBIxFcyOeGCg1BmaTh+RdOMOWdUh+CyqARUfaGALg1Y0bDji8obHEFb39x6 -ColgHHXTwOkdLTs48kVOrCQLb4hUTKLC+ok/fZhzfN2GpZzXmTGSUZZuTfMEsKU9 -4LJMtXQX6nKUiD2RqWyy+tmCGxc8d7LdeqqI9uAJrEPaCj7GQtcg5wnUkyR2dIED -0dH8x3HpJSl7+djU41G1CxaqTNO3ckqWEcBmrpeSuK+2H6Wczt9t+JaiQZnZWn0m -Y1W29uOBxW1zRGyXK++EyeGMg0ktljV7E8JKCLbfWwUIxRH0U+pooM47VvoJEgbn -2cPA8YED58X8tWmfNqNlYyydOjOWOi5SdBhazjRvmplqUMIKnDR6fJrbbvbXD3lV -QHdrHV2MCPh9+SOKCnYZwiTRSaKY59JAM10PalNCbADONy2QFN6sIN8uETuOZuWy -H6aJumTTtA9CeZLIxgTftwha5V99l/XV22gqUzB0RfqC4FrIIVF7a/8YhtH+tkE+ -eBaQ11EO0gnNkf7obTjdp8VWB2BzHIh08PLBma/d+qClZk2narn4Cr1EMFvLTu/Y -f/dem5yvO5YqdS51KhcUCr8nDFPL+LT5q9gC9gij5kxbnlrQ7Y/LfBQEI8Dh1OG5 -B2DjhHqC3hNymabkIWXzL5UsNdwt1/FHEeFDKwY4y7kJ/CTHFgcPCdD7ZGb+KBUk -lOvaPs4j/lasUp1tUPKRyliye0zfkeUJ5arFiXQ6lF5rCPlNTsledWx8KZx4lVwJ -0mgyXLAPU0dykoqREpeAzFMZs40+RrQoDtyM3v6BdVk7lC/PfNI+ia1Drux1/cXD -W/69OsL6rVqifcJ3o1NrzitRNJpyvkO4LxO0T7s6ZTFL/SXCVnL8z3LeVqDrORtk -67YzMA6BU+QIWC8iw+ZcABMoPXK0b8EQrNER2I/73GO5Zx+AiOzzXeOJZUNoH+3R -A1FuDmKg1C8i5mEAHZwSO+7JmH4fcKmP3ITk9ePystJdJ2jLgIYqaAT0wDzdLIQG -3SHEYqAvAEaQQc8jk6/YoIg0Yy5VSUkclHwsUDpI807hGjEDeDLXm/+bCwz2BCXi -4TYKTmpyjcHWtipFsnkT0IfMQ8EkuWKijc3w69YmO7uRfor7epO+g1+0b+kAs6uj -d2lZlhW1+FD7wmHtxdyNVHXzCtSRO9q4sGNe+NQ2DhQo7dh9htemEk7vpFSpWb/V -MMjDJiQPEd3ZLqrDcOOUEWmXY6GwcoWhHpDuVx8uEt8/BDd1yTB0sOraDOwaTi3B -a3Y3lkkfksd11go5w4tZk414Cd5Ha/bN3BfZv1yQ9GRynV0VELXDb/z+xj9XVHQ5 -NOi8tQc7CdYpZie/bb85yVLnTeSu4hdhLklS/k1974q+HwyAiGaHu+z0f8C8gAyX -gocYzid5aedNSl7sHNAHu77mrAPcc6fv6eyUe7I5/yABQ1UGrOEWKEX+GFlmUf9X -1y47ox+asFlncic2DDwKUZ+LbAdMu3JgzYXzHa4IVi0Ff+lzuLc3XA/MOaOOjoQO -64Fm9Sq9Sc72wsb2i8QVMRt0Ft/CFBlqk9TBx0ZFoE0os5W1OfO9bS1Ls6mCHNlE -0Po/XG7Z821cBFXtPJ/tRFRfxe8bgtNK++/Yv6m/8SFAKmWq+GMTBv0y7JYrgcbn -YC8JRY5+JdcU/ZLNoaz7kkZecPXNadgWumRfzPga8K7gnsZgc/C3kDQ0199NudQp -6ZzzJlOPdiWsCsm8QqlkvlPF2RqBO7Ja6Sz+dBKRT5BqpibXyPoJRMTACm18ZvP9 -gxZUMddIc3K0VzA20ju5jVfj1ZQ0nnYz9i7VkSeVhFW2TOLwzflT82wrwFDtQD3m -FjBulqulZpQKbp0/gfYhfGgLBBD2UxTJlZZTfHIOZYRkgD2q/a/3f3Qc06oVp3gb -5OlDYUsnzFdZ2Qhb8XRejRLUNNJTL46GKp2OyclrCSTszq3HVLL6B6M51aDTCils -igmM/ekoAr8DSw4RYSbtfv1jeWTMJIumF/8p4toRBphBUZLYSvfw131N4rQvXuC8 -QYAk97L47l/YsU3DqTifJGqMn6SFok2HfG4q0e4u+7Pvoc1ITxF2+BiGrFd/zv+m -lFzkK46Gp3Dx+ljTzNqrhhENYqfdURfjoO4tgpA7K1z0fyAl2MixGFSsylrUxeJK -C8RZ7BRlcYAxoI+LxbLmGlopcWuppT9I8l2KOeMLZyh3NLXqd6nybAmCPE8sp1q6 -E9F2qFXltVQneQ1c2LOsF7hgzp8tlba5VL5Xb40ZEUcDTuBUEfC5yjDQbckNTnb/ -1c8AAhJChdmeLFFNoetsHF4+Rm2Phvd0wI7himHLgm3K4BRQRSvvQd0AtGuxv4xP -lpQ4up8ujsBJN3tcw4ttvBEZr3g4AZ4NVW3R17jg8eXnz+zgg+C/lHhm17gQXqr3 -gznT+GEbL65ds/9a17G2LvQt/ZCoOEkOa0SuwfQDSpA7+yvECbKHWfYzASZDiyma -ZJlclXtjFEB7pLFz5s/QwkNUU8O9uSqaBq9oAMc1p29Eww8qxkWGSv/Iicww2QyI -ZfZKmDVriMNoPfyPZpRpJwRZVtTyfAtD5zVNG+W6Bp73GKhsL6DVh8qZHPZAPKmB -yzP9mNVWsfIqzKfuIbpSF4l+GEDacAgtQedEmO55NAqzaSplDGHqlRQrJvM5o41n -25yu183j3ZerEQp4kEh9gBl5EZmZZhrhWgRZdVZRcOP6K9WkS0oUDUznAimU0MoZ -tsxi/rUX6dhdq3G6GoKPcR43TGCjQzGY2M7ICgFpv95mxyt+8VPpM/JO+nE5Cqz6 -zlfdggIDY817ql+8fPVF1oaDgvK6GcpyxePz0BJzB9dos50u9wODejI+vWGr79rZ -ql/59tplVnne9BbZbn7L9PqfN2X7W5rOxPDVVowKADiDGGWP3xQvCvTNu5MaXbR0 -aqbZDtIj+QbasWsHqMK2o8SCBK3FfNITsuMqbtwOCtfmBC9jiCaYCb6c5kMZHye7 -yagXtPY+92z2AV3qaCIktg28lPd3R14MVNUvZAlrFzQRwEgTLuxTFWU6hCQ3JAg6 -BycDliIdAZ8c5TWQoYU0R6DQMs1tR/YWqDqX2F7e1fzXOIhY9uIpi09ZrMt3Kb3s -dHaAVlugUkehxyF4rb/PZoyx5pg5dm6DFOO5mAxcimB9WYD61BTrKtNItWTPt2uu -XkiB5ECNBK3oQE4hIKLfhBWRNnDbmyGRCJBnyStiF/1L1NauWbiBWhczmsn9lWdS -e0Au6FJm96qq6pwivIERqv+QoMfCxmZTx5V6ThjbL43VhX6CEv1FFVqgF2VMjhZV -WlM00Azysijgbey7mpBDnTubGD/b5AdW88s1/1XN5m5Om25u2+fwALvM5krTQcvx -KG+/oouqfVsMQ0bnMsbZiFoL53D5nydW8hQKTnp378K2phM6VsIzHHC9fFL1orTx -T5RPqK4DoQ1+9E31VnO/OSjb6dIEj1wNbjmg4NfsgsMUk9XJKFRNNpWEqallADgX -iheX2NpUzZ9S2rUFTrzGZNwFsaeoJtF+NgQctcvpMVHrJQZGZ0soG29EBdjcGSCf -MdfRchT7ociVYeWWCQ3O4JPPEiikQOwaJeJkbWELrHjrx/q6Tv6zwicHA4jqCRKy -v0v7kf1lTniv9DBU+xbytFDpETDW7FM18hsICmjBgm/mkiuOYWfYW30hpBZiUYXq -jIsuXxF5jp6jdfkPxwwAfBjnmNjIRL3h0BjzRv6SXyJtLaMM90Ru/8ZsGz25MnCX -RzoroG02qLGenm2vdFU/rCfzwp10bfRnO/Z68ap3b+NjInnJZuj1p+NpUHgzw8OJ -XcT4c0e6djO33IDdjJfbvmzRO9ZOFY+Ky7MeXexL7rGZKVl/rAS7NbUeTb3/Avdi -dTA2dXm4Kjv8zbvE0wJL9zWtH6G71eeC4DaLY3F87WFQoBBPrqleB1Lx/dXyX07u -lVXrMLaYL8BYVqmDoxuPki9qImKZaiqd9Jr3hkpY+eMTp+KDkbugK5Ip95BnV912 -htUU+FTyxlTR9BlkBhDmxb/puaz3P1JmbQcKlRe1S1JygxnCu+cZLUhfBk1SqFX7 -dI0LEVceORm/VCkjgYWatVJpZ/fHfpZFNifiT1UcODmDhoYAPANgeYCcDt3ortVv -CamdLtAcptD/UrjCGTYhB8bhB5iKvYnGsc+qej7JVFDIYajZkqgcNRaKAVYT0SOF -kJB0/+lZT3+KtnLjndRm3YeRKgb9qJ2F+2rYrutmi+oP8jh4UT/O+8Fki7remPAU -hvbJtU+KqSv5Z+n+FGB4/Yh0vGeJkIYlvIYfsnd5ewwukShOeFY3SCp2WlC+F0g2 -kXtkGZs72U9NTzZRycGYakvT9Yt4iEg+A8p2TthW5x7CQwkXSQyR94R/napLEc8o -aTxE1fUleYLz10bwsGveO93Qdqf3TQldukItZrtSywA74d+KhojsisfYtH6ifjxK -ecUq26+kxE/T+Vb94HHJsOPGl42lmHRLsLwmISPjD85HpWJOmkI7BijaHKFxSouy -/1kUVKg/eix8SJD6o0uX5vTPR3LQ8kqsDbDu06ZagKfG0qoL0vRRPUIUDXxv02wM -lFiIzDMihL3FKe2B8qGR6BvUZCalzBSFECuiBx+jhTsnak0YHz3J7UFWYLRtCwAB -ebw3VR6UQ2dTriEh7OSG77n3ekJpZ/k08A+ZbhrgSGbtIF98VakbA9slGSChzieb -33DZt0viINqoXjfCQLNkVb1MO0pOVmBFFuwjYz1g47lBIf31uJux846F+kE7fBOs -ri3/Tc0UB23szbnopg1qi5Fpv/aM40NDwaWzEm4vswp/4HzeC5HPrKqX9YUcCN7o -b3Jhpt3PzeWHCpzNiawk7ytp+tDaWFoAXxgkXookLdOx/vutsxAfR6/CncPFrWC3 -/Xxqc6E5JpIoSeApyPTGoIqVoFsxrXu1gysZ+3cKhHJujy2JJVnQZfaSpieVnJk/ -T1sEij6FlESFMkZrtMj+LfUIrv3iCJp7EuYoMXG1Cpb+7Num0bpG3RCxg4QEIJiv -m5NAg3XXpf1vZ7tGKmNFUEIhyUqp9eo6us+6+jidRX2oS9o/RGug75dCfcEDs/9Q -ucAkSN5p53MvAxa33KmvqizDI6k2Jy6L12KDa9Qfn/WeOshqECOspDB1FaMSxd03 -tZ03ia0IndJs/8BIwB/8C/yKp8OTwXGJdxlv5vrMpCJWi1SaIaX64Hcvr33B1yPY -Qd+deRAeIchgPFmvKuBKy/sZDyhgb/o5Wu749huy7pMjf2d1nLw0KDnJrRcdqcaN -mz/4lluuhlop2vHboqKyjZ9UsLaKMlLt8MvJRb7XyAlat7x446GYKn8i1G+cAgpx -G9+NSkV3ULVV8asowFWQ6Bo+3mQvgkoRH/Ew3/Ug3VTBZP2sfMzN11XxzMqDpgW4 -S5TkJ9AXaLvina1zNMKlmJDYtEQIIfVXHhTSWOPvbvl3j4Za7Rmlh8dgTzOty2CT -J3yElofin1OLVel78QkcH2VzvkSWBwojBuxeN8Xdj1B6gtXypIypjAT4hncEV6T1 -70tg9F2jkwFeq/gAll00fB55Wipzp528PMNaliBXpX1rfQotSkw3nEe6qgR0Owpt -s89DD+plQyZ97yD4h6B4A5rPRK6DHGK5Ext3Nb+WvIcQXBIlPnxRBf4AfoUmYZYu -v+WSFHCozp85GggFJ6yntYGejZsdoXrUCkpxWGEuj9E9PCF26/JZY+NekvlCchb1 -UhV1dyJDAqzRYeoAOm5ZgfttvOh5KsoSVMg/G5jh42flBalx/i8sknSoCd7ETXtZ -1J98E/CN/eUWz29oLl/6p3SgxWBZ9d1G4v16bt4/KtdA2bTO++7z0sTTuQJ0qnwy -uA0lwGJSeWLARLqzBO1HpeBGwuoPGZjuxKhRDF2qExo6xSSgUokj7HQQ6cU2mI4R +1udmPOH0vRanRgfj3cA9SZZAn5tWJ0AGSS0XXiMlutGqHzoH2IFBk1SotwqQTO0t +yZcDli8mH0bPSLrizA6XTIpUzoe8Aqjf68SED5dvEbSPWx+jcV+WDkrWmZ9m6NsG +LdU2zuh+pQmCBp9SgH+n4nOkUftYuS/VdTqADpFcwLwOQHUwdW1UCO+HtrhDrMB0 +XuS6rnH4PI2L/eJEsIDMVQI4VZ1xWfQ09laKvTyIYQPyUsEEIsxX8qIwJjJ0ZDCD +sOyxQCDPbUGZhefm9eWPQmGi+9GzlQYubZII8eshMAuDnAWWurLgCyQvnIvF+r6e +V1wItUH90haYDjPURig2Ne9mCByXwXlZSVkuJA2cgadr16O1Toe5RnLg/7epwkJx +zJViQDNFwPQsLhAcZ9Qq4rZvbVshTVJCeHUcyPraRXJSfFi/eBU78qtqwg5zNH2a +tZYOw5t0amoaKTFPYjfl3HBVENpOSQiJFlCxmkfuEQ8Wnziqunn2O2SEKNkExgGX +w7OV2DlMCWWYrw66hsiwM2TmHFQHoZv3dSwh+hXfNr54lSNaNaqy+myCCEXxhQj+ +fnwxJn++5PONS4S3LJK1oj2pSpNbHRDbEkRnC3exYbU0SPcEBHhzl8jNZ28P6sAm +bJ+cv9hRu0vh4vPkhhaC1iZX300KcOn03/I/Nbe9CypqpptD2q5F18g4x/RWk2xy +GOQT/UL5u/OGVvuqrbX4l5bkq1MbqJg/pe0haFL8zWnLI4b+TxBVa5V9pajJObO3 +qgPR1UCwsZ5TyEjAQNR8BxH3uzK0bfRy8orrZRcNq4bJA1Y6qmyUHpWhl3HRKv3Z +cQ2CumzqcfwThmkxLnX+/sHAnTtmt+UdqirnCWC2uFLMjJTjSUZ7diKbRfu2HjUZ +pMzzUURZipGMnr3UbPv5LtOI44GqNUIaCrD+Lv+U+HY7OmbwemOPDt/O8aa+t67m +PPMH5GJxu+XXV3svfFAyuCGX2bafzg9y/jNgMBBPMwA0IsMgC2eQrMu+Uj271OH4 +5jXVb2kvaHxSOxcUq+yFICHdLSpEj241xYnIey1HE9zdx/kuugbFQUVCxOOlpISC +OqAYYbnoDWJQ0tV46dYPp5/2DPXMyYMHggflZnlW0JWejFq2Vd2oc+4Ozpy4ow9t +De1v8z4jtoCx6G409DDRY4HXr7iOTWbB9NaEwDFfMJEb9GdR0fYZSNBNyQo6vpfl +ZjVREZg7EVadh+CzSbQRayoOIbbuTXtRrwdVgN4w+XHwy0/ZDFJUM+/a0crPWtkz +T9h8WHIp4Lg9G8t8W1s585eUfyVP0/tL5kY095svg/30tFNBU5wMwD85/5j3TKXK +/EDaxRN6h1uWJ2j56fsZfAv7K3Oku+RSkrE0dLNhr/c129Be6KH7C/ff2XEDer/D +efHzbHrV+I7u0cp5giGrnK3X/8PSBUYjgR8bwjh3CT3ZkCXEYJqoMtVnfeDEcVkf +kovpY5RLnYuKWxBzdHIxsiuk36jZgAIY1/ARc1frpVtb19CtrJt7ahVY1wjTrUJQ +N2ky9jEEB7dEXQkJ2ypCdvzgcM0Q7GyA2b3Zx5JdBEy24YKLTPDGgxtpZ3xCARyo +PhCM3RD2IpZuQ829VM8hmRYum40GQ7+aFSWqb+j7zbushP4eaWzy8AMG7cgvipcT +PjFtc9CDv78tPqhnpgZq2R4gmgRCNZVYtFBGHp6UCzhkfATFNafHMV0yK3M6CzMJ +k5Nu2DZFBy1lmfNIVWZcqKA5RIVaoUVY8FLCY0/+7d5EFaCGROZHrEgaPvzJONx2 +GOhSCT23rzgy9d2eQHKlCeqOYXJKMkfCP0KyxR2joPVaO1/GYPbzlr6xBTfyG5ea +9jQ7+EN07frgwuAx7fhCFU4gxJ9aYgtihlIbdTFBtvEEBZjxCKsS+fcsdndT5tv6 +ednI5Vi4XJ9gEOrf6Y5d3F4Nt7cSX1Iz9L7p6oAPqGaZNxLDD9zlc4rWR+Zv/Lhq +yWbCRgizAZMNTAeEmIV20EHNXMY9ciIv2g7O+jPQutQbTfkKzvYghfD/KXfZ3jCc +nFJkH8g85eOI9QpHgovVbTitwz9at88oNTWKpu5hYXWrvWsqNteGYIwKwhz+15fD +fvTrBW7f2hkCaa3OqFAoHpiSucuoUzCPkoqhRWBPqtCmLo03Pm4tyq7qqXLKyjE+ +G55bt+lsGCum+5G1EDo4qygGAIZYfFBli+GyMXOuw30k0QYGB1pBEO7kFQMd4g4j +sdLidxwMUsunnX2uzgBG1jwcP6tpom6cMovNX8iSJxjbqYkbdWDieyQeeZGpbEIQ +235tUSP6MJcARmVSyfZAx7fOLW2MdC7W4LGFDTXk2MpsnFJjE3lglLvWybWss/x8 +GQKWCcs82MooItaA+W0j/+OYBTihZa37mr/8yaxrnFxRAaGmoMeczH0wjvxVNhIp +jXhuJPolU8ijTl4JOf7a6WyFUXTQK0khwGDvY51qKNs8DclVGBIdsp5AVZJ1c5Is +U2uXS8ApAQEma8s2C2G3tJTSPyXZTp0f6BYcCWbGx3T4q+JBgW8aaGH3oGHaVEhb +tImiXb0MT00k0DZY26KfseXkLR0PxatFf2vPT1WW4DbUDl+HFhN5YYPwltV4ko51 +9+M7jJnPkFANXnjvqgVKypeE964sNY4gBjyH4RGfUA/VUjuiGkgUJwr7GH/Agj8X +xWMpPsy0JbUHqLgMvVQqqwCF6trNmV2jbZ6AhrkNP71M/oKSGP0CryidRnCJgtrz +lBLCK5YckdPKyKldfTyr2XflpZzQFcbSz/3SWzGbtz4g8il17SP6b9f4Yv/nG2n8 +0X4SUZV9dpNFLvyUgeaUn8cX9t8gGTPJXkkAdp46bZNzt9D9jyVvmlczRKdZCxqC +lT6Fu/c6yhjUSWY9Tla+VrywBTRGVzAoGvo/17I+rNjjv9oVs9G6d+kwCpBCV8xw +P6v+J5QTXltyRq/kEUTbvRyydqwo4neiUTF6s3UFTtEb6mgyxyYeb/DjDHVe1DIf +ku7wqyZMObGQd8cHqyD7bKXRyxNyYriGt7SkCjCy0onVJR8LqUtfY4GYOgNH3QoL +hdu4uT2yV4Dm2uV7iugA5Xi3wr85F25hALre+j3tLa1g1r+NAvCET5PWK0Be2URm +hcUmKOH0VjTKq0kxb6BLpOpjUIEvYac9TG9mDOCf058UFp3mibXMAxqxKHXOw86U +yT75yW6ZSiB+vqyumUSb7M0uEIoTCzw4RYtEpAgC4tpufRytDX4jGsYUpOo5dHxa +YQ58sYyRaEWUvFZhan4kaHK/yGf4Wu4iwHqIT39lbR6pNWXZklP3dM0RXPQGKJwZ +UM7Tm6jPZbYNUCFttKjRd6zRgEgeNYW7KK+XhkbCVRF/D8SNNraxcIODd5pLsLMu +g4x0lbbU6qwNPfuUyYSzCguokpRYrkUqd5cpikW1+YUzYtbNlGLDRCMZZ/kc4FWQ +iSZYbmdlVaOZcoUzzCdsyVAR3sZ2dveVwDgCLGehLgqHIFAC7DPj/ETZhcUfHM73 +3woI4izLVAsJslqwglCLfBVdteFcUqK9LfVZte1HQORrjB2CpNd9NRhDPgmqLcTG +iUSxrf8xnHrU/NUhwU9Cwwftxg9PTFQbq/3sfWfR9jPRcsPX6bYagzTQ6b48IyIK +vNiPUjBOatp4ew73tvUUBjzOPSjpdhSVRF9y25IfZ/pjehabieI4hHlKIG56cLfb +pw/nIHzqzN1g5HT1iLktyD98u/09C476C/UA+oYn5uHB4z/wU6rNFP5UBu08er96 ++9/OQKP8KgK8X1g92+xnbZNa8ChzFOaPfLKhTZH5ndVXkapJ/jQLXecfAqxdxCvR +UV2CjlfIJdZ3PRDmsY0wbIgkLLcgh/KCCEAVd9ATIoDE6T2JtaAuESfg3zxf1n1r +2OpMkdqY3Bb5NxUa4TU8u8gkcivqC944NYtncUgAZ3wFW61pud4BoPDVXaAVToDR +lymlYmzx2pGUjRvR5Z366gbUzEhl8lOs88Wtf/bPrUZ2Z8CmrmrVkhlOcJ+yy4JU +mEaAVmbBq5FFGKhTwcRlTZtTW52kDLMFjyPBzzdHkIAR2/hp8vWZ0hEVFE5OIge7 +1UDmOSsy9GRHxRpQyPWCEA1PiriWq/Fn2B0n5ehU3AEoe4Vt+/SVpCZOzaPP0jeG +mmrb1dMbh5ZUxUNvei7fvQB1/CIoaTyHAjaL6QZn93qNxjEx6uQY2gzP6Cu3hhLX +X0sYiDB3vBmPpcWzkJ8gdk+b7+ZMsF3/NU9gV17w4LlIn3h1EsxmGoXZG4jtJJM3 +VU3TAlwkxM6igy/ClBIFHLAD4huqwpdvVVE4VR1c3KZf8zIMZX3LZyPZy/Vaikek +MBntjKVWYvxNLyQMtMs2tbqBDyDKw1J68daQGDmV4ZuSKNz2hgch2YaxPR/eUQZt +tSXr4K3Y/xSV7cP2NeosXjL2aRT4k2xX2v3NAC4N7lkY7ouPgHhcazEvjkQ6J2PU +Pmu+7CfkA3p80hU4FIRIRPezF4lKAUWmTfo0qjcbWY3BqPWTqiYeizHQtnG9Eh7l +pcqhK3uH8gJtUH3PVe268kRzE06RV61Aqms6neMUnJ/BdsFHaZUVsrudHlDmDoyL +zBDTpWl3bn2T/+8uILs6UeZ10Sd71xosyM9TPti8V+u30suddbXQybqK1Iw7C+7e +swy3CFZWEpgRoC9f+JMiDt5u9PDhUGmC87z9LfYiXTnr0VOgiTLZrpdjUywSVVzA +xFYvobyO4ADRr9GiHdHzeJtPhtKE+qR15DX/L6pAGNR+zY5WUdJghxg3K0rfKeGk +WcSMRL/PYAwniXltu4G5y/en7BhtiXLmJlNCHL6dgUeay+EtJxkV87GPAH67QK9D +VKMIAKNaLBeyc8rmhiLWjcHwFDZEUkpRdbpbPfBVBbw8rTW0NUb+YtTUMJZ5Y9dr +HxUkyHUdYXtoMSZoP+iu53pc64aw1UCPiVBZdv8Mt0JCe4pu5KGaeK2DdHjIctcL +RuNCoDtaRS/2o8vSn74IL4SkeRwivjos4olfW49OVhNd8aPkvnSTD1IbtFI58b9V +b1hLwUBmthxwXDT3r+EKDu9MPzgpTM8K8/lIPDl9LSHd8WRE8xzyxdzXwtwYxkKP +UvsvJOxlbX8VlA1IwykXmLwd6PaOgcBh62qVoa847UQYqA9iiLzg7O6Zsj5PMeCr +FJc/Bi/8k4uSzQgYeSu90FVgeWOQCRMWwVzZY0rXkZbEAF5CjJcBgYcGBRt5ezK/ +DbRjkz55Z8ty0MMkuC4mZ6WktUgaBS743zS8J5tcwsk+yG27DRQc2FQJRwQqSHS1 +wNk7cEw8HsPSX3Tp+BD3RAcqivpcgrcYjnxZgDtgaUlVomwbWP7zQT89pU09zH0E +td4RbmrVaso5AqIvDUetOUT7PYnrdwLNk8gEG0lcuYv6ey72xQbnvYBHaHgSnvB0 +CPnotlHsyIvWPDkLQb+z0s+FQy8UC9PuFQtMeGIWsgFXpwbnwBojOrukuAdMy0EQ +38yBfxspt82jAw/SDj3jGLrcJKXciR25abCT0xaVoHbtH+yawMfJgOSFBUZiu/L7 +asXqhThv/tuPwWbSqauaNV2zvRfQn+IZqZzqsr9YkIJn/52UwMSenrXhq0G0a0A9 +U+Jjv9BrIVSwM47Jr6MAkbKuhs80jsZUiidQeixhY5+bGkc4mrUuU2DTKoPZYdhZ +kFVNEi4/lZgMiD5V0phL58DH+yBbXMLcF4NJ2TTBo2wnm11+I5ycHvVOT63wERIK +G8js3DVxINBKc/5NmTZRl5bnBhUXvxPlHQ4WTHeMGhXLL8d4L9/AXwlbr6oqa2Nb +DeXyG2rFGmBCTKcMRZSFvGENkvj8P6s9C94jLl9nzbwq0T85Uj/QeNh9wEGiFPMD +4gUTII3I2+ey29v9Ow4wJz2MWDrSnf2hqceqtPr8ooppoMLbQZNKw2kafsiKlgAm +cjXGykyKdW/WXm2HPXp2UyhQPiK/A2lGnkTjRJXugwB+YXz7LWJe+pVTjPpfeuup ++FJ1pywEJb4jEo6h73IteulEgj0vMCrOFT6DCUANDmUTU8uLQE9LH8Ous+hHqYoO +gAHWA1RqTnjwM5Uj3X6Y8pFSEb/BXT0mtfapdiBfhmfZz7qHuPj8+V7C/pWTPWU5 +oexFKtj4WLYpek5twjMsKmV8Qh+BeGQf8yCGdo+cQXKb+k+S4UXJF1NXQPAzG6hL +a+mDWAAx/GAXLtb+zwMZ/6lU0LgN92Qy4/sewdezG8/AtKWDFh0enokOI8g6oIKT +LXfunwOE1DeCGcOeIVrjVh9jtejzaUV3s9ixFMQs5AsjvULtxrag96vVyUfoaRzs +yHQl/T+rs8Yx0inucNnXkBvQx5JqUkv3Cr5n5C/hn9a+IOglHdln2wsUljsf8vZu `pragma protect end_protected //pragma protect end @@ -9089,97 +9559,97 @@ uA0lwGJSeWLARLqzBO1HpeBGwuoPGZjuxKhRDF2qExo6xSSgUokj7HQQ6cU2mI4R `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -TiUbwBy+LQVBO7WBdjt/XLacOlX2V5La65hOVyroLyPznQd9u3Y50du0Yp1+Qw2b -g44j0JwPYEH7zOnDDnSY7nHXhIKU9KPejKhGJBYJGOaiLBG5cURIDrGy3TpqhvNH -dno5tQo5w5tBe2m4tyToGMm37JJgf7d9pKLLaDS+LtUD9uprvNU9lD19S9CxZ6bD -3e7Qhib1cLiLTe8pAKRkTdTyui8xISjNGD5uQXiEsA8xaV0/ujS3RdB+nFwbp+d4 -FzHwV4lZ0HwlbviMzb6WQT5tN6Zb1YvyayYSOCNtXrgHrtoWc9hj3NR1ylhvbZk0 -We9lM09bb3F1TdY5EXpqEg== +n0jqjnfqyF03TrdlGtL2vaRSLWRFaTNK0YPdtS5NLgMBZqaZppLQWa+9QocgYbSa +c5cdHxHlVdxBv0w2ht/Kl0AnnTa3zXpQwpzLm+QZYWERA6CPGQ2iCknciqjkTANl +w3ursi1XnXRnebWfdtyjWpIs4UEfytecbUyUvUD4Ou8xwEqHD82QUpgoF8S1VErM +TXlUFlA+KLqtSnjxLsCJWgZu93+NcfAIrMnyVTMIDYSvq9EdOIgJGV0Hy9Y6sNhU +R06ok2RfjzN0/k1pZoWUA11e4xpRLWuvboDVQRLS662Mr+qC7GUzJw4KP0STpRtl +4AFN5zfv8ZpmxOv7kLZMMw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 3936 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -9242,7 +9712,7 @@ generate end end end - else begin // Active High Reset + else begin always @ (posedge src_clk or posedge src_reset) begin if (src_reset) toggle_src <= 1'b0; @@ -9264,7 +9734,7 @@ generate ); always @ (posedge dst_clk or posedge dst_reset) begin - if (dst_reset) begin + if (!dst_reset) begin toggle_sync_r <= 1'b0; end else begin diff --git a/Ti375C529_devkit/ip/gTSE/gTSE_define.svh b/Ti375C529_devkit/ip/gTSE/gTSE_define.svh index 3bfaee2..1e9fc35 100644 --- a/Ti375C529_devkit/ip/gTSE/gTSE_define.svh +++ b/Ti375C529_devkit/ip/gTSE/gTSE_define.svh @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 7.3 +// Version: 2025.2.288.2.10 +// IP Version: 7.1 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.sv b/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.sv index 7ed4229..4c9def1 100644 --- a/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.sv +++ b/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.sv @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 7.3 +// Version: 2025.2.288.2.10 +// IP Version: 7.1 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.vhd b/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.vhd index 1951a5f..5d5e501 100644 --- a/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.vhd +++ b/Ti375C529_devkit/ip/gTSE/gTSE_tmpl.vhd @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +-- Copyright (C) 2013-2025 Efinix Inc. All rights reserved. -- -- This document contains proprietary information which is -- protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE/ipm/component.pickle b/Ti375C529_devkit/ip/gTSE/ipm/component.pickle index 26ca13f..9dd9240 100644 Binary files a/Ti375C529_devkit/ip/gTSE/ipm/component.pickle and b/Ti375C529_devkit/ip/gTSE/ipm/component.pickle differ diff --git a/Ti375C529_devkit/ip/gTSE/ipm/graph.pickle b/Ti375C529_devkit/ip/gTSE/ipm/graph.pickle index 659a69b..5d12c6f 100644 Binary files a/Ti375C529_devkit/ip/gTSE/ipm/graph.pickle and b/Ti375C529_devkit/ip/gTSE/ipm/graph.pickle differ diff --git a/Ti375C529_devkit/ip/gTSE/settings.json b/Ti375C529_devkit/ip/gTSE/settings.json index ae9734f..9b1a129 100644 --- a/Ti375C529_devkit/ip/gTSE/settings.json +++ b/Ti375C529_devkit/ip/gTSE/settings.json @@ -3,13 +3,13 @@ "-o", "gTSE", "--base_path", - "ip", + "/home/byron/Projects/wireguard_fpga/Ti375C529_devkit/ip", "--vlnv", { "vendor": "efinixinc.com", "library": "ethernet", "name": "efx_tsemac", - "version": "7.3" + "version": "7.1" } ], "conf": { @@ -31,16 +31,78 @@ "ONCHIP_PHY": "1'b0" }, "output": { - "external_testbench_modelsim": [], - "external_source_source": [], - "external_testbench_testbench": [], - "external_testbench_ncsim": [], - "external_testbench_synopsys": [], - "external_testbench_aldec": [], - "external_example_example": [], - "external_example_2": [] + "external_testbench_modelsim": [ + "gTSE/Testbench/modelsim/gTSE.sv" + ], + "external_source_source": [ + "gTSE/gTSE.sv", + "gTSE/gTSE_define.svh", + "gTSE/gTSE_tmpl.sv", + "gTSE/gTSE_tmpl.vhd" + ], + "external_testbench_testbench": [ + "gTSE/Testbench/tb_header.v", + "gTSE/Testbench/tb_top.v", + "gTSE/Testbench/ODDR.v", + "gTSE/Testbench/glbl.v", + "gTSE/Testbench/apb3_2_axi4_lite.v", + "gTSE/Testbench/axi4_st_mux.v", + "gTSE/Testbench/mac_pat_gen.v", + "gTSE/Testbench/mac_rx2tx.v", + "gTSE/Testbench/reg_apb3.v", + "gTSE/Testbench/rgmii_2_rmii.v", + "gTSE/Testbench/udp_pat_gen.v", + "gTSE/Testbench/DaulClkFifo.v", + "gTSE/Testbench/temac_ex.v", + "gTSE/Testbench/modelsim.do", + "gTSE/Testbench/gTSE.sv", + "gTSE/Testbench/gTSE_define.svh" + ], + "external_testbench_ncsim": [ + "gTSE/Testbench/ncsim/gTSE.sv" + ], + "external_testbench_synopsys": [ + "gTSE/Testbench/synopsys/gTSE.sv" + ], + "external_testbench_aldec": [ + "gTSE/Testbench/aldec/gTSE.sv" + ], + "external_example_example": [ + "gTSE/T120F324_devkit/timing.sdc", + "gTSE/T120F324_devkit/apb3_2_axi4_lite.v", + "gTSE/T120F324_devkit/axi4_st_mux.v", + "gTSE/T120F324_devkit/header.v", + "gTSE/T120F324_devkit/mac_pat_gen.v", + "gTSE/T120F324_devkit/mac_rx2tx.v", + "gTSE/T120F324_devkit/reg_apb3.v", + "gTSE/T120F324_devkit/rgmii_2_rmii.v", + "gTSE/T120F324_devkit/temac_ex.v", + "gTSE/T120F324_devkit/udp_pat_gen.v", + "gTSE/T120F324_devkit/DaulClkFifo.v", + "gTSE/T120F324_devkit/gTSE.sv", + "gTSE/T120F324_devkit/gTSE_define.svh", + "gTSE/T120F324_devkit/temac_ex.peri.xml", + "gTSE/T120F324_devkit/temac_ex.xml" + ], + "external_example_2": [ + "gTSE/Ti60F225_devkit/timing_Ti60.sdc", + "gTSE/Ti60F225_devkit/apb3_2_axi4_lite.v", + "gTSE/Ti60F225_devkit/axi4_st_mux.v", + "gTSE/Ti60F225_devkit/header.v", + "gTSE/Ti60F225_devkit/mac_pat_gen.v", + "gTSE/Ti60F225_devkit/mac_rx2tx.v", + "gTSE/Ti60F225_devkit/reg_apb3.v", + "gTSE/Ti60F225_devkit/rgmii_2_rmii.v", + "gTSE/Ti60F225_devkit/temac_ex.v", + "gTSE/Ti60F225_devkit/udp_pat_gen.v", + "gTSE/Ti60F225_devkit/DaulClkFifo.v", + "gTSE/Ti60F225_devkit/gTSE.sv", + "gTSE/Ti60F225_devkit/gTSE_define.svh", + "gTSE/Ti60F225_devkit/temac_ex.peri.xml", + "gTSE/Ti60F225_devkit/temac_ex.xml" + ] }, "ooc_synthesis": {}, - "sw_version": "2026.1.132", - "external_path_option": "RELATIVE_PATH" + "sw_version": "2025.2.288.2.10", + "generated_date": "2026-08-10T02:09:12.753633+00:00" } \ No newline at end of file diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch.v b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch.v index e8ebeb1..2046f49 100644 --- a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch.v +++ b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice @@ -43,7 +43,7 @@ // //////////////////////////////////////////////////////////////////////////////// -`define IP_UUID _3abf8808e52e459c824b41829c7669da +`define IP_UUID _c22db128920343a0ae5b4fc5c7fb0e16 `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module gTSE_1to2_switch @@ -170,219 +170,219 @@ endmodule `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -BSiclTfEX07oDTPwvSfmqSh37gsGawnAkFDdQtfz2b2aPAbkkOIevgA5jmAEpk8Z -jmjFoTAnEUNBHxHADHQl29GtYYLQLcTt1dvsb1L8xXXbyd41mZnW9qxR1yEXo2Km -PmHE4/laDDFnEAn08I7oinDvTWN/plGfuIWWaEXC4z7ls9W1O5jNY2gj1ZC0oyT4 -iwzQ3cMmgvMMfqkgA6T8wMNFL1jvPdUxnuGh8qa0Q5zso+v2lpzszj4ytZLI8JZz -ZeX/ipjz/4hUHkihXJPjFD+MetXdYJTpzRO3ZbxTOlyD1Ln8yDvo0qNPrgbzN9qq -YropxHtLb22q5bZxY+vKMw== +k0MNGAL+siJuDYrFA58rRJscMTUE6hiuNEylu7uA+mdVk/vCPJpUprjqZIgJ75i6 +csRX146zVh4AUQABC09rbvto0kqPbqsZwZGmdOm1W8NmGZIXLCsG4MZs984TiToI +QMOSc+XFr9GVx1rFODfIQCsRVOla6WZCpHrBZzFjmFwY4t9fXFQCs5fSkNbGyG6v +8YDvdegFPMYp5Qu9ccfxeosyrpdCBompAmWscbYmzMrmyFiInvb8Y5dyqCuve1NW +jirl6fz1954ypdomnZDn+X9k8zTCJAxovyf9Qxk6Q+/Pf6e6yRqEYBxT7dtZhWRG +tEQdKP3bt5KBf+EuwdVLuQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 9552 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -514,542 +514,530 @@ parameter IDLE = 0, `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -h798DEoPCCw6eC93sfxnz8ZJ5DmYibE3rGjjhE+YK5a3RIfjyfpuQmm+Qi6hiWsS -h21ZC3p98i4VCoRgq9ttjdMjEUVk6R1INC59AvJ35jeq6cjGdiMiIPwnlnHEAIqa -kQUAn5DZG6XDT0Q74iMGbdiR7Uqpt242DlxQT/RPahxewbF7bTMwF22aKiwUymVQ -WL77YlV9D3RHdY6gVwH+r4vNibfPRFoNglrFWdWkXgAM3QCILfTmCmNOrDP+tU67 -Sp1AnVUQDUfoMreLqPv9PxJK3wnCugVdw08bgxzbxycLpfzcQbzXtVTNLzpE9m/C -m4DQ47zqQmz4Zj4f/JVRfg== +f0DVmU/kdU862C3ryhjQlDsM4c/0bG91GM/Tt0YfOziNIhVBbdZsoYW2RTSSEC81 +yNXUBt7tFmZq4YDopiOye7MWsFmf8WWRQEL3slo6DkYqzPlqCgnjys82AVws5Cco +WGW89TXAcQAYHJy7oG8Ae9oSMdLa3PIQNp7mSA6rz4RhAKHQyvxQU3wr0zXDmYKl +CeyI1ZIu155HAUZL2bXguauGtJWtwaTXIrQO4i5/hXied5l3pm8lCdXsKbM1Enxx +V3E/sk/RBAVETx2fmYxracwCdN363LHRvYHyP4b2qkmUndhj47mK2s4d6wc/G0IJ +HQRhooSUf5bQscVy4yyOxw== `pragma protect data_method = "aes256-cbc" -`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 25024 ) +`pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 24464 ) `pragma protect data_block -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 -VhTvV5MqNhAZpXfPbkZ0rQ== +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 `pragma protect end_protected //pragma protect end @@ -1062,48 +1050,48 @@ VhTvV5MqNhAZpXfPbkZ0rQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -RwZLaWoAKLBm11tcUo3zg7WK2hPcNJvetUS0HcngH1N+uqVkxItkonJwS2nHozet -PZ4e0pcL7oMHU+YSSKFGF0HZtDLJ6ggz9Tjk65W4OruIfJxIuyYdw9nbusKhaJTz -khXz5VPO6s2gfnVif+az5zjoe7kudgxlxU7jmvaX9sbur5cFMS2KnJogDMLJcl1s -ZlLL+9F5h5+8PKCF6eoiFm6TtkD7MrBiDjMDu9eLqZ5t8VgWYRMKduwEQ9J2M3t/ -JcbjL7GG+1h3LkL6WEKxF8zVIpKiu3k7UC98wKI8mhEpZ8bChW07nVCr4PHLn2IX -BU9Qy5kOLqe8sKbl6LYs7g== +gQ+VauIuH+g40FNOpVzoPSXPaSSXzZWh6rE+e4zt/Higof5lTVqndEO2y+vyS/HT +Uz3/xsHmLa5/hfJOzrQ2WAbWJcFOc0pzmbDqYnUgEw1W4IUS1qcjifpXTLdxvwfy +rSWd00QRecQN7v+pyLFb6xf5TELzzsB2PAr6/xlRVs03sGcC8jpFMP1gppLRrh+C +xnDjMIBVdGmu01tJ1gcEY/913addbws7HLgMcMDLft0U/4zTbjE/rrDoC7+eO+3k +z9ZPUNkRvEPxurfsVZfIuglJuZJSqyaB+Khmc5Q1nMDb9IswcttQUM3RtjEksR13 +Y4OcKLh/ejWsVorB6JLJeA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1312 ) `pragma protect data_block -p0bIW99zYvQA4u0XRWnQ90s6MugNpXe6l31pFNyBhuxQU67mS/BBRtYtc25nySM/ -yHwfDVEt2eeSh2xZ2Kv1d8VWucKTg8lXrK+ooXsXcYiy61IB12mnjuKPa/FUxFS4 -JM2AiESAcF0ks9YGnHz5atWTSPAnEYKTqIrZDoYqJkbgClLiRdrZY+N2hC5jdZeW -cR1EkHw0PZqw6S2eCHL5hUi6ryPKMkre1oH3Xdag2DJT8qQxbuNqhhrm/L+8L8lX -f5F3asZ05yCB1pnJRqVPESYDajoN8u1lWD18RYsWX60ld2PcwCxsHkPOyoBvAV1u -PgCYq2l6s5FitBJR9RvIIWQXgYcJnkvvctXAE4sHkA/8YmzJKAUlmADFxObHh7nH -B9Tr9F5MMMItWtOlRVOB7r7GpKZ4CIu9H0pG8rHeitdTJzb//0sRPwO4Ifpq00gF -PYpm2+uw1qrcWOBG9wrbOEUMiFlt1c1y6CM7W0HiQg/FK+4Y4JiB7uaAlzUejTOI -zOL6no+QbQSWHIEVAYNpQGNcTG+AuFlhiSI5DitSGvW5yCLRLs7Fv5AnqLM6z1Qg -nRTXEKDaR/AFlAFB16izDRH4FYwpXtH01JTfdxvrFbPDjE2B07qlVwewnCVApXy1 -GNPPzEat9SO3vQ9t7PCKFzQV6OGGAn/dyMwguU6EDW8mcNxemcFiHUdiSfhhZpeH -IcnqAMISo7J5oznEHRV6eZ2t27p8fCR6kY+/9tdw+mhgfM47E9D+jOa2LZcvRNK0 -IxKxNWtgUL0KlYtkFTGEhG+p36IePpoZOlbFukyAkrvx2uvJdjDKNhR7fljgKZp9 -ntpSnYfXJhwQrP8yTvoXUhnLpaxBTrh8cyLUFVm+2UtqRrz/+WA/Du8u19N0NmoU -4Z65V0tXF/tW4DpeElKcg5Z9g3Srjon+LpuobgvaptlZ3rG7pXXklUAdxNfJ+4mu -g8S64RYvfLamt1za0XyFbePfAbEPHUNKbKIqzGRB92kxJ6jYjgC9RQHp35SL3T55 -2DhArYHiRs4HAieVOggerJ2mFKRe1jgXpNH28cIvReVtjhPSR0h2/N1kktJoFN9j -pAwsBXcE20H2DgeDq7MOl5klQOQIZqq2NOi/TtiDykzXOq9c52KT5YQDUiFYqQvD -H29baw+SyQUZTso78q8DVb5S1dB3XyHStAKgoGq93+Wz/B1RLpKYack4xd4rdS5s -pwx6XbBMdp7aDqOyz2KgKWf+dspEnt1aZSkLPUfnK1QqEuwBFSip0++f8lsYJwt6 -h2RR9rfNZmd8nt+mXhbGkKeiOagijsA/5zVB+4MgI0KR9sujHhdd3ikiYUTRDpcb -AA7w3mFn6w2oiAcHGimR/cBGrmo7m6L0USsPGqFYBLIQfdAn5dEBlb2BCoA5VFZj -jXKJF/jua7Y+DrPzh66goMGjpF9lBpoEP1rWQA/7bSpIp6mTsXcqppKrJq4X3UzK -fnxoXMOzyXak8Q0RLDFj9NSgAWzr4VmwVpFWnocoXpsQlisCkXdTJvGnor8LLZr9 -sDZmzgcSix39SaRGPrUkPl4jLdocSaImMFvFf75Ln2LkiFK2PwLHbdxu5OHmQoCw -7wBcsGkL2gXd3tYL2ns54yYSqMYHrxBbag+ndd5VaJnjZK34JNDCSh65qkKE7y7v -Behj6SqW7qWtdmufzd16RndX/9C4+tnd6CZRltVVSxqHORQEFpJfBX3qZLp11vTQ -Pib5SMqM0nVbJDVpqDeCAA== +fo0JdXfIQsWgrENhFGo0RRW9s/IV4eGBK5upzSxFjRkxTj+wCit1QKkd15jJgDu4 +P06Rnw+P2/Cu/tkXRjH7RGfSCa1EZ08cwLiSykEmyb+qQo8wTkOBh8KIag5m0P1t +XTuNeK4lZP50EUwL/4wSSMPuRtdpIAF+0PAXjdoge2gwhduxtVQZpgPO12dwk0Wo +Qyfuxrm/7iyjiETt18QCBk/PXC9JLX6a9hmtr8ujb+7IKQJFj1S7F9WxCZ1yamDs +e1D+l34aYZ5r3sBbAysWrg65oN3fAAd6bhptfeU2+BDBA8oKIcTClBK2f3pBUPul +8YV5xUU0+FGat/Rjkm2ZmKKpm9JD+w7ufesbJ2fqRCCex08yynx+EuV6lNupQQk3 +UbxIK2+04eVmLtY7V87103cxyVnLFXqAQY3XaG0AWBpO2Ew1NwH6CU4yFpyUAC84 +Bjztc1mHKONeueopzONq61tRDqarI0ex6IhDy04D9/zAOhMyBrEHzeR0UozXtK6Y +TB/qqFBgJmagIMQWcL03s2FYWQgGUU3PRQ4JiB57ubJG6H64M9UJUMXI7VXW245F +S0oLuBSWchTwY4/6zvioNieoCZgdkxOTUqHNuV4Zf7Epcgh3IQIZRzjBSpah3skn +kQwLdkHYbh3EzBAN0L4lF8u4LE/8SqwLPpsl91D8Qck2jzgNTYnbsG+t2tsum6n8 +wYvw9H2G6SCXAimDrg2Qy66lpdDA8XQf+1Pu8sYKlEd3GH9lQyGX+l4gx3OLuOtR +fAlYbOhHnFRDXMNE9ZG/I8VKDFToJD1/SjoKUnrz4TdMcQZn3Asrj6LyXsw5CHgd +zhf60BREHK5nXIJRGkqTlV0OyCbaEe0yTgmpWapYbnUcpX4UNu07ijUdSbUBReil +f2PULQwchd1Nh+nj49FyRm0SU4twHeYIMoSC2sMtPiJkuqAZPugzpBpKZUPnKzDd +VmHxPV5Fl4haVbGLfQj4rfl6Mqpqk2DLOiPmwiXnf7CTAjpnwNQ07KsBw6SKxLAe +YS+1RZFe1JQTA73Dv+hAjOEby2uC1tz9V61abAakI4omdhXK1WBGS7AW7VIkOhsa +U2d43C1vqygKdJzTQVB3SVqswMzruIiClRGEypfl8F1L7BIegRA7y6KJYY2lQ69u +7eDX8XmDYmXDiWgXqtWRALbhHrDi8EwOCp5Tts6KK1q+HZNB6UjiGUrGZ2/EhU4H +rNhfbS8YD9wTQtEs/QCi40wIeLIYjIf429BBIRU8k3na6ZwzGLdfxJnqsRLJ6E7X +aCiJk8iag4Wfv0HsAb9J8vDUKzzLHS5OYlHmEss6CTswBAYs7u8/UF9rlfvXy8Mb +z5tfh7xCXqOQpY1gF85w0agvdFKLhhUzfB2Y/XiH+P9zw8608Q4B2irkUuj0fbhU +/VGCOg52ghhNNkaio6JDtzCj/4nMf3QJwdYnJNTiSWLmN/D4rgU8FE7RObm2foEA +5qemSiCt9nYnRGtaRQ0jFh1zieourorN3TI49Lfh/b++M/Hq8OUZh7Uxs5ni4scB +RqEGxATE+29gCCCJ1S3HVi7fcit9xh2mupZnT+m3qHM+Jt01sv59AUJ/UFx/cNYz +qo1oB/NkzOstxVDMlcp8bOO+elF1X4n4wKeC0g/eMM8C+ffQiVT7Rqh2mYLgXQA7 +BhBS+E0RB6UhkxYPnRFEgtk0VLL54VPEVDTINYlLs+L3ZsWwYJs39Gen6vvvepYy +bujDTnnouQqtvD9ok3pkbA== `pragma protect end_protected //pragma protect end @@ -1116,45 +1104,45 @@ Pib5SMqM0nVbJDVpqDeCAA== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -V7fazAcYfn/upNWI2MrDSQamEge7Y8sqGyEbHWTTDvIkXpdIuRisL8LJjvy83vue -ZgYLruqRxsDQR/Wu7PMlj65sb/NkxpSPTHfwdQcOEP3MsixExszjuA1HqHtg+aNQ -uFOiuMhxVPj6PMHq/Hqrqa85QcEVSbWPuLxSaFzY0ndkgyErZck8cU+0bbs6pFmr -tNIeglsOu6Am3uxBT62KHdsx5/dbyBFUXzyoeMcVqVN/dSwFJEWKXykd+OnIo8cg -TAWc+EOAJ6ExmKO/aLU8Un5EpThP6h/F+4FSrXQ8+zAfJHLLmWelIILCIn9r270y -7CUxtRRDMVrzxeZaHx87Jw== +TpRHXtmr81JyoWaAtQOsoLu44jF5UvFDPdO5/CllOd3kdY7PwU2fkKx7bS6RlGe6 +282Wvc58pPBGh6uImNRfZkaAKTaspN+giuR1GHAo4nfIKi92dgY2DTW5JbEU67ml +1IGNiK4su606fm7n90PZ69MZadoZPNpUxZxzYbSs+I39eZWsgU+rtoUE2d35qjdW +UyorSD+O2F5Wv51CWlcWJyscNK886BFGFi72CtEY8IdYcolZ7hcONOhQT5jbhGWK +UFFTqjnMO6iVrEodujVvUgcUtFQSTl5/oHSkmacP7CSADA82+06uIHf+rByqHGTp +JNgtSAVN844IRP39n4T5EA== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1200 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end @@ -1167,62 +1155,62 @@ AvKxciqIeVCjtaleTRBLEWnwUKa6wADHB0WNBFNEidDe8gAcwWkZyKkh/VaUiupU `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -idlb0ipwgIc0hiUfW9lCBvIc27j+O1T55dJ3BL9eUyC3AmELfvx2LyGUfXvUfYTf -8sHVL37lgxYwkxIH4ZSSZQ1GK2zLKlNHYUEmXZIR/WoNIg7U3rYo+/OAX5LDNWz3 -I3htHfdktV9gYc7iVdI9VNrqBa0Gg55NmIOrO+wM2ME4dVbdMJVDfW+oOu9rTeme -KOonn0oR5/zNCWcqkhf2z6BLLm49S0wwKQJc9Tn8j8aAVVAS5PR4HM/UAt+Pm5Qw -qUaeukXs5OImR86WKmCfOXrROtxYmBZ//zwyzxGdjene5Dzf1Lue74V7vg9Yy8Es -kofIx1Iiwvl5uhKqK0ZywQ== +TBCX5/gAT5S6xdVBuY05hYDsXmHLnm/0Yl4d4ayUlKrDe3IUWB3JcRtZJEwtIwhQ +wqO6qIYs21XvVt74eCxdt1SZXHRXXJiT196fD9q5vFrJxAQqeTDvH51bmshhKW+i +DwXpMTwZlLgBsT2BEP5C0RiiICy9chJTycHB7vHEh6lTXT6S/2H7bweTMlFCh6s6 +n5aHgBbfjk9BYIUSTuEvOxw9Yki0T44zjqGmjZ3qxkhk5Rae8iPLqCnjRTjNfqOE +zQtaoVQW+8NbATVUmZC4WlgxF/J03hq0TLeqLYfcuWR0uH9vLAWsUzHqlGMZvUSV +23zwmB8p0BqUeaj1cllyzw== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1984 ) `pragma protect data_block -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 -M6eR/VTYArPQbA4OoPqXhQ== +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 +9Jse9KsUSQdI7bnqvPdYIQ== `pragma protect end_protected //pragma protect end @@ -1235,43 +1223,43 @@ M6eR/VTYArPQbA4OoPqXhQ== `pragma protect begin_protected `pragma protect version = 1 -`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2023.4" +`pragma protect encrypt_agent = "QuestaSim" , encrypt_agent_info = "2021.1" `pragma protect key_keyowner = "Efinix Inc." , key_keyname = "EFX_K01" `pragma protect key_method = "rsa" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 256 ) `pragma protect key_block -kjevziVpR4HNp6ABOs1UfEhnb+dX0JPweI6S3+LX30C9LF3xx7Xd/zMszyIOAsff -hodfZOinnjjXzBncB8lZ/iwEBQcN9AOUuJkxqHw0xEX9lKugu7WOxROcH+yiXxDJ -yy9yDzS1F865ocB3xO9FWkMnml1XZRqox2FTUI5GMVk0MxMQPCoaWPmG40cuqt8H -oNSQWIvbZ0bwp2zXvC4BQlkXD2oWWu6JxxVIVspZ7XmHHSfSB+gK8bmQIk2JZPQd -nB3A0s+SLUanWE/u+Muh6A5t3kkuvJ5Fy1rRHEwle6WO6L5S2arPlksoYEp7hfDo -eW9+LO7WnZdnt0b3dQw5Mw== +eiP/26NloMbfJbEe1aU/cN+AkTVidxKZaNv824TVZXkpjf5L1zEVLf4buBzXwSr1 +MiO1FaB1qgL+ZgKHLwNzc4IiIP0d7qYOaGR46jDr8/k9N2BVxXC3V0wJJ6yhDom9 +O7B9d2Lcm+b0UifdEaFcX3luTwZzXAQW83Bggnm4eVP275Vqog3REHo5wgsstEU3 +AG6o+oVDnNjZTPDPyJ4uHq9bjFFyvY3ga+lOo2iVymecnhCiRtjy3AFtvWBJW0ek +uhj8QvNYf04TXkRXdhdRfq/HDLr3M6Qa7/Xn6vGE+drFyRTL1nmH9wkjBBbD3swn +58tiwvvx3ajgMOCJeXfrXQ== `pragma protect data_method = "aes256-cbc" `pragma protect encoding = ( enctype = "base64" , line_length = 64 , bytes = 1104 ) `pragma protect data_block -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 `pragma protect end_protected //pragma protect end diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_define.vh b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_define.vh index 5296368..b794024 100644 --- a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_define.vh +++ b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_define.vh @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.v b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.v index 228f904..1711a12 100644 --- a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.v +++ b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.v @@ -1,11 +1,11 @@ // ============================================================================= // Generated by efx_ipmgr -// Version: 2026.1.132 -// IP Version: 5.6 +// Version: 2025.1.95 +// IP Version: 5.4 // ============================================================================= //////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +// Copyright (C) 2013-2025 Efinix Inc. All rights reserved. // // This document contains proprietary information which is // protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.vhd b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.vhd index f73b627..2c4910b 100644 --- a/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.vhd +++ b/Ti375C529_devkit/ip/gTSE_1to2_switch/gTSE_1to2_switch_tmpl.vhd @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright (C) 2013-2026 Efinix Inc. All rights reserved. +-- Copyright (C) 2013-2025 Efinix Inc. All rights reserved. -- -- This document contains proprietary information which is -- protected by copyright. All rights are reserved. This notice diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/component.pickle b/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/component.pickle index d2a83a4..e262fd7 100644 Binary files a/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/component.pickle and b/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/component.pickle differ diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/graph.pickle b/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/graph.pickle index ed0f82c..bc82c02 100644 Binary files a/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/graph.pickle and b/Ti375C529_devkit/ip/gTSE_1to2_switch/ipm/graph.pickle differ diff --git a/Ti375C529_devkit/ip/gTSE_1to2_switch/settings.json b/Ti375C529_devkit/ip/gTSE_1to2_switch/settings.json index 59f9f96..cd4b201 100644 --- a/Ti375C529_devkit/ip/gTSE_1to2_switch/settings.json +++ b/Ti375C529_devkit/ip/gTSE_1to2_switch/settings.json @@ -3,13 +3,13 @@ "-o", "gTSE_1to2_switch", "--base_path", - "ip", + "/home/cslau/Desktop/Workspace/efinity/2025.1.95/project/Example_Ti/ip/EfxSapphireHpSoc_slb/Ti375C529_devkit/ip", "--vlnv", { "vendor": "efinixinc.com", "library": "axi_infra", "name": "efx_axi_interconnect", - "version": "5.6" + "version": "5.4" } ], "conf": { @@ -40,15 +40,57 @@ }, "output": { "external_script_generator": [], - "external_source_source": [], - "external_example_example": [], - "external_testbench_synopsys": [], - "external_testbench_modelsim": [], - "external_testbench_ncsim": [], - "external_testbench_aldec": [], - "external_testbench_testbench": [] + "external_source_source": [ + "gTSE_1to2_switch/gTSE_1to2_switch.v", + "gTSE_1to2_switch/gTSE_1to2_switch_tmpl.vhd", + "gTSE_1to2_switch/gTSE_1to2_switch_define.vh", + "gTSE_1to2_switch/gTSE_1to2_switch_tmpl.v" + ], + "external_example_example": [ + "gTSE_1to2_switch/Ti60F225_devkit/axi_interconnect_ed.xml", + "gTSE_1to2_switch/Ti60F225_devkit/constraints.sdc", + "gTSE_1to2_switch/Ti60F225_devkit/axi_interconnect_ed.peri.xml", + "gTSE_1to2_switch/Ti60F225_devkit/efx_crc32.v", + "gTSE_1to2_switch/Ti60F225_devkit/efx_custom_master_model.v", + "gTSE_1to2_switch/Ti60F225_devkit/efx_custom_slave_model.v", + "gTSE_1to2_switch/Ti60F225_devkit/top.v", + "gTSE_1to2_switch/Ti60F225_devkit/efx_fifo_top.v", + "gTSE_1to2_switch/Ti60F225_devkit/axi_interconnect.vh", + "gTSE_1to2_switch/Ti60F225_devkit/gTSE_1to2_switch.v", + "gTSE_1to2_switch/Ti60F225_devkit/gTSE_1to2_switch_define.vh" + ], + "external_testbench_synopsys": [ + "gTSE_1to2_switch/Testbench/synopsys/gTSE_1to2_switch.v" + ], + "external_testbench_modelsim": [ + "gTSE_1to2_switch/Testbench/modelsim/gTSE_1to2_switch.v" + ], + "external_testbench_ncsim": [ + "gTSE_1to2_switch/Testbench/ncsim/gTSE_1to2_switch.v" + ], + "external_testbench_aldec": [ + "gTSE_1to2_switch/Testbench/aldec/gTSE_1to2_switch.v" + ], + "external_testbench_testbench": [ + "gTSE_1to2_switch/Testbench/modelsim.do", + "gTSE_1to2_switch/Testbench/modelsim.sh", + "gTSE_1to2_switch/Testbench/xrun.sh", + "gTSE_1to2_switch/Testbench/axi_interconnect.vh", + "gTSE_1to2_switch/Testbench/tb.v", + "gTSE_1to2_switch/Testbench/top.v", + "gTSE_1to2_switch/Testbench/efx_custom_slave_model.v", + "gTSE_1to2_switch/Testbench/efx_crc32.v", + "gTSE_1to2_switch/Testbench/efx_custom_master_model.v", + "gTSE_1to2_switch/Testbench/efx_fifo_top.ncsim.v", + "gTSE_1to2_switch/Testbench/efx_fifo_top.vcs.v", + "gTSE_1to2_switch/Testbench/flist_ncsim", + "gTSE_1to2_switch/Testbench/flist_modelsim", + "gTSE_1to2_switch/Testbench/efx_fifo_top.modelsim.v", + "gTSE_1to2_switch/Testbench/gTSE_1to2_switch.v", + "gTSE_1to2_switch/Testbench/gTSE_1to2_switch_define.vh" + ] }, "ooc_synthesis": {}, - "sw_version": "2026.1.132", - "external_path_option": "RELATIVE_PATH" + "sw_version": "2025.1.95", + "generated_date": "2025-04-14T02:17:58.052364+00:00" } \ No newline at end of file diff --git a/docs/core/parser.md b/docs/core/parser.md new file mode 100644 index 0000000..341ca21 --- /dev/null +++ b/docs/core/parser.md @@ -0,0 +1,55 @@ +# Parser + +The parser must parse the following packet: + +EthernetII | IPv4 | UDP | WireGuard + +From this packet type, we must parse the Following: + +1. Dest Mac address +2. Source Mac Address +3. Ethertype +4. Source IP address +5. Destination IP address +6. Protocol +7. UDP Source port +8. UDP Destination Port +9. Wireguard Message Type +10. Wireguard Receiver Index +11. Wireguard Counter + +These fields all go to metadata lookup to determine the destination and +operations to perform on the packet. + +The parser works by analyzing the packet 32 bits at a time as it flows in. +It uses a state machine which keeps track of the position in the packet, +and based on what it sees it updates the fields. Here are the states: + +| State | Desciption | +| -------- | -------- | +| ETH_1 | Upper 32 bits of Dest Mac | +| ETH_2 | Lower 16 bits of Dest Mac, Upper 16 bits of source mac | +| ETH_3 | Lower 32 bits of Source Mac | +| ETH_4_IP_1 | Ethertype and first 16 bits of IP. Version, IHL, DCSP, ECN | +| IP_2 | Total Length, Identification | +| IP_3 | Flags, Fragment Offset, TTL, Protocol | +| IP_4 | Header Checksum, upper 16 bits of source ip | +| IP_5 | lower 16 bits of source ip, upper 16 bits of dest ip | +| IP_6_UDP_1 | lower 16 bits of dest ip, UDP Source port | +| UDP_2 | Destination Port, Length | +| UDP_3_WG_1 | Checksum, Message Type | +| WG_2 | lower 16 bits of receiver index | +| WG_3 | upper 16 bits of receiver index, lower 16 bits of counter | +| WG_4 | middle 32 bits of counter | +| WG_5 | upper 16 bits of counter | +| IDLE | Do nothing until the packet ends | + +As we parse, if we detect that the packet no longer follows the pattern, for example +if the protocol is not UDP or the Ethertype is not IPv4, then we set as many fields +as we parsed, for example if the protocol is TCP we would set the ethernet mac addresses, +the ethertype, ip addresses, and protcol, but the udp ports and wireguard ports would all +be 0. The outputs will either match the metadata rules or not, so we don't care in this +block. + +The pattern specifically is IPv4 Ethertype (No VLAN), IHL 5 (No options), UDP protocol, +Wireguard dest port, and wireguard message type 4. \ No newline at end of file diff --git a/docs/core/top_diagram.drawio b/docs/core/top_diagram.drawio index 7a5bea9..2149594 100644 --- a/docs/core/top_diagram.drawio +++ b/docs/core/top_diagram.drawio @@ -1,92 +1,271 @@ - + - + - + + + + + + + + + + + + - - + + + + - + - - + + + + - - + + - - + + + + + - - + + + + - + + + + + + + + + + + + + - - + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - + - + + + + + + + + + + + + + + + + + + + - - + + - + - + + + + + + + + + - - - - - - - + - - - - - - - + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sim/net_core/parser/parser_sanity.py b/sim/net_core/parser/parser_sanity.py new file mode 100644 index 0000000..bff250e --- /dev/null +++ b/sim/net_core/parser/parser_sanity.py @@ -0,0 +1,127 @@ +import cocotb + +import logging + +from cocotb.clock import Clock +from cocotb.triggers import Timer, RisingEdge, FallingEdge +from cocotb.handle import Immediate +from cocotb.queue import Queue + +from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink + +import socket + +from scapy.volatile import RandMAC, RandIP, RandShort, RandInt, RandLong + +from scapy.layers.l2 import Ether +from scapy.layers.inet import IP, UDP, TCP +from scapy.contrib.wireguard import Wireguard, WireguardTransport + +from scapy.utils import str2mac + +from scapy.packet import Packet + +CLK_PERIOD = 20 + + +class TB: + def __init__(self, dut): + self.dut = dut + + self.log = logging.getLogger("cocotb.tb") + self.log.setLevel(logging.INFO) + + self.input_queue = Queue() + + self.expected_queue = Queue() + self.output_queue = Queue() + + self.s_axis = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis), dut.i_clk, dut.i_rst) + self.m_axis = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis), dut.i_clk, dut.i_rst) + + cocotb.start_soon(Clock(self.dut.i_clk, CLK_PERIOD, unit="ns").start()) + + + async def cycle_reset(self): + await self._cycle_reset(self.dut.i_rst, self.dut.i_clk) + + async def _cycle_reset(self, rst, clk): + rst.value = Immediate(0) + await RisingEdge(clk) + await RisingEdge(clk) + rst.value = 1 + await RisingEdge(clk) + await RisingEdge(clk) + rst.value = 0 + await RisingEdge(clk) + await RisingEdge(clk) + + def assertEqual(self, a, b, name): + if a != b: + self.log.error(f"{name}: {a} != {b}!") + + def check_header(self, real_packet: Packet): + for f, v in zip(["src", "dst"], ["ether_source", "ether_dest"]): + actual = real_packet[Ether].getfieldval(f) + parsed = str2mac(self.dut[v].value.to_unsigned().to_bytes(6)) + self.assertEqual(actual, parsed, v) + + actual_ethertype = real_packet[Ether].getfieldval("type") + parsed_ethertype = self.dut.ether_type.value.to_unsigned() + self.assertEqual(actual_ethertype, parsed_ethertype, "ether_type") + + for f, v in zip(["src", "dst"], ["ip_source", "ip_dest"]): + actual = real_packet[IP].getfieldval(f) + parsed = socket.inet_ntoa(self.dut[v].value.to_unsigned().to_bytes(4)) + self.assertEqual(actual, parsed, v) + + actual_ip_len = real_packet[IP].getfieldval("len") + parsed_ip_len = self.dut.ip_length.value.to_unsigned() + self.assertEqual(actual_ip_len, parsed_ip_len, "ip_length") + + actual_ip_proto = real_packet[IP].getfieldval("proto") + parsed_ip_proto = self.dut.ip_proto.value.to_unsigned() + self.assertEqual(actual_ip_proto, parsed_ip_proto, "ip_proto") + + for f, v in zip(["sport", "dport"], ["udp_source_port", "udp_dest_port"]): + actual = real_packet[IP].getfieldval(f) + parsed = self.dut[v].value.to_unsigned() + self.assertEqual(actual, parsed, v) + + actual_udp_len = real_packet[UDP].getfieldval("len") + parsed_udp_len = self.dut.udp_length.value.to_unsigned() + self.assertEqual(actual_udp_len, parsed_udp_len, "udp_length") + + actual_wg_type = real_packet[Wireguard].getfieldval("message_type") + parsed_wg_type = self.dut.wg_type.value.to_unsigned() + self.assertEqual(actual_wg_type, parsed_wg_type, "wg_type") + + actual_wg_receiver_index = real_packet[Wireguard].getfieldval("receiver_index") + parsed_wg_receiver_index = self.dut.wg_receiver_index.value.to_unsigned() + self.assertEqual(actual_wg_receiver_index, parsed_wg_receiver_index, "wg_receiver_index") + + actual_wg_counter = real_packet[Wireguard].getfieldval("counter") + parsed_wg_counter = self.dut.wg_counter.value.to_unsigned() + self.assertEqual(actual_wg_counter, parsed_wg_counter, "wg_counter") + +@cocotb.test +async def test_sanity(dut): + tb = TB(dut) + + await tb.cycle_reset() + + + for _ in range(16): + packet: Packet = Ether(src=RandMAC(), dst=RandMAC()) / IP(src=RandIP(), dst=RandIP()) / UDP(sport=RandShort(), dport=51820) / Wireguard() / WireguardTransport(receiver_index=RandInt(), counter=RandLong()) / b"Random encrypted data here, who knows what" + + packet_bytes = packet.build() + real_packet = Ether(packet_bytes) + + await tb.s_axis.send(packet_bytes) + + await RisingEdge(tb.dut.o_parser_data_valid) + + tb.check_header(real_packet) + + await Timer(10, "us") + diff --git a/sim/net_core/parser/parser_wrapper.sv b/sim/net_core/parser/parser_wrapper.sv new file mode 100644 index 0000000..d187590 --- /dev/null +++ b/sim/net_core/parser/parser_wrapper.sv @@ -0,0 +1,59 @@ +import net_core_pkg::*; + +module parser_wrapper(); + +logic i_clk; +logic i_rst; + +taxi_axis_if #(.DATA_W(32)) s_axis(); +taxi_axis_if #(.DATA_W(32)) m_axis(); + +taxi_axis_if #(.DATA_W(32)) s_axis_be(); +taxi_axis_if #(.DATA_W(32)) m_axis_be(); + +taxi_axis_endian_swap u_s_axis_swap(.s_axis(s_axis), .m_axis(s_axis_be), .swap('1)); +taxi_axis_endian_swap u_m_axis_swap(.s_axis(m_axis_be), .m_axis(m_axis), .swap('1)); + +parser_data_t o_parser_data; +logic o_parser_data_valid; + +logic [47:0] ether_dest; +logic [47:0] ether_source; +logic [15:0] ether_type; +logic [15:0] ip_length; +logic [31:0] ip_source; +logic [31:0] ip_dest; +logic [7:0] ip_proto; +logic [15:0] udp_source_port; +logic [15:0] udp_dest_port; +logic [15:0] udp_length; +logic [7:0] wg_type; +logic [31:0] wg_receiver_index; +logic [63:0] wg_counter; + +assign ether_dest = o_parser_data.ether_dest; +assign ether_source = o_parser_data.ether_source; +assign ether_type = o_parser_data.ether_type; +assign ip_length = o_parser_data.ip_length; +assign ip_source = o_parser_data.ip_source; +assign ip_dest = o_parser_data.ip_dest; +assign ip_proto = o_parser_data.ip_proto; +assign udp_source_port = o_parser_data.udp_source_port; +assign udp_dest_port = o_parser_data.udp_dest_port; +assign udp_length = o_parser_data.udp_length; +assign wg_type = o_parser_data.wg_type; +assign wg_receiver_index = o_parser_data.wg_receiver_index; +assign wg_counter = o_parser_data.wg_counter; + +parser u_dut ( + .i_clk (i_clk), + .i_rst (i_rst), + + .s_axis (s_axis_be), + .m_axis (m_axis_be), + + .o_parser_data (o_parser_data), + .o_parser_data_valid (o_parser_data_valid) +); + +endmodule \ No newline at end of file diff --git a/sim/net_core/parser/sim.yaml b/sim/net_core/parser/sim.yaml new file mode 100644 index 0000000..a429397 --- /dev/null +++ b/sim/net_core/parser/sim.yaml @@ -0,0 +1,7 @@ +tests: + - name: "parser_sanity" + toplevel: "parser_wrapper" + modules: + - "parser_sanity" + sources: "sources.list" + waves: True \ No newline at end of file diff --git a/sim/net_core/parser/sources.list b/sim/net_core/parser/sources.list new file mode 100644 index 0000000..c1b9b5e --- /dev/null +++ b/sim/net_core/parser/sources.list @@ -0,0 +1,6 @@ +../../verilator.vlt + +../../../src/net_core/sources.list +../../../src/common/taxi_sources.list + +parser_wrapper.sv \ No newline at end of file diff --git a/sim/net_core/sim.yaml b/sim/net_core/sim.yaml new file mode 100644 index 0000000..993ffd1 --- /dev/null +++ b/sim/net_core/sim.yaml @@ -0,0 +1,2 @@ +yaml: + - "parser/sim.yaml" \ No newline at end of file diff --git a/sim/sim.yaml b/sim/sim.yaml new file mode 100644 index 0000000..1bf3020 --- /dev/null +++ b/sim/sim.yaml @@ -0,0 +1,2 @@ +yaml: + - "net_core/sim.yaml" \ No newline at end of file diff --git a/sim/verilator.vlt b/sim/verilator.vlt new file mode 100644 index 0000000..3bb36cf --- /dev/null +++ b/sim/verilator.vlt @@ -0,0 +1,3 @@ +`verilator_config + +lint_off -rule TIMESCALEMOD \ No newline at end of file diff --git a/src/common/crypto b/src/common/crypto index f5e7b84..fb7290b 160000 --- a/src/common/crypto +++ b/src/common/crypto @@ -1 +1 @@ -Subproject commit f5e7b843b1aca6edff4abe916ca3160223d8e3d4 +Subproject commit fb7290bfc2f9c1c33948bef7c90e10bf083edc4c diff --git a/src/common/taxi_sources.list b/src/common/taxi_sources.list index 74cc4c5..69e8554 100644 --- a/src/common/taxi_sources.list +++ b/src/common/taxi_sources.list @@ -1,4 +1,3 @@ -taxi-bsl/src/cndm_proto/tb/cndm_proto_pcie_us/test_cndm_proto_pcie_us.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_desc_rd.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_tx.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_core.sv @@ -6,25 +5,6 @@ taxi-bsl/src/cndm_proto/rtl/cndm_proto_rx.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_pcie_us.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_port.sv taxi-bsl/src/cndm_proto/rtl/cndm_proto_cpl_wr.sv -taxi-bsl/src/axi/tb/taxi_axi_adapter/test_taxi_axi_adapter.sv -taxi-bsl/src/axi/tb/taxi_axi_axil_adapter/test_taxi_axi_axil_adapter.sv -taxi-bsl/src/axi/tb/taxi_axil_dp_ram/test_taxi_axil_dp_ram.sv -taxi-bsl/src/axi/tb/taxi_axil_crossbar/test_taxi_axil_crossbar.sv -taxi-bsl/src/axi/tb/taxi_axi_interconnect/test_taxi_axi_interconnect.sv -taxi-bsl/src/axi/tb/taxi_axil_interconnect/test_taxi_axil_interconnect.sv -taxi-bsl/src/axi/tb/taxi_axi_ram/test_taxi_axi_ram.sv -taxi-bsl/src/axi/tb/taxi_axil_adapter/test_taxi_axil_adapter.sv -taxi-bsl/src/axi/tb/taxi_axi_fifo/test_taxi_axi_fifo.sv -taxi-bsl/src/axi/tb/taxi_axil_interconnect_1s/test_taxi_axil_interconnect_1s.sv -taxi-bsl/src/axi/tb/taxi_axil_ram/test_taxi_axil_ram.sv -taxi-bsl/src/axi/tb/taxi_axi_crossbar_1s/test_taxi_axi_crossbar_1s.sv -taxi-bsl/src/axi/tb/taxi_axi_interconnect_1s/test_taxi_axi_interconnect_1s.sv -taxi-bsl/src/axi/tb/taxi_axi_crossbar/test_taxi_axi_crossbar.sv -taxi-bsl/src/axi/tb/taxi_axi_register/test_taxi_axi_register.sv -taxi-bsl/src/axi/tb/taxi_axil_register/test_taxi_axil_register.sv -taxi-bsl/src/axi/tb/taxi_axil_apb_adapter/test_taxi_axil_apb_adapter.sv -taxi-bsl/src/axi/tb/taxi_axil_crossbar_1s/test_taxi_axil_crossbar_1s.sv -taxi-bsl/src/axi/tb/taxi_axil_axi_adapter/test_taxi_axil_axi_adapter.sv taxi-bsl/src/axi/rtl/taxi_axil_axi_adapter_wr.sv taxi-bsl/src/axi/rtl/taxi_axil_crossbar_1s_wr.sv taxi-bsl/src/axi/rtl/taxi_axi_crossbar_wr.sv @@ -92,26 +72,11 @@ taxi-bsl/src/lfsr/rtl/taxi_lfsr_scramble.sv taxi-bsl/src/lfsr/rtl/taxi_lfsr.sv taxi-bsl/src/lfsr/rtl/taxi_lfsr_prbs_check.sv taxi-bsl/src/lfsr/rtl/taxi_lfsr_descramble.sv -taxi-bsl/src/axis/tb/taxi_axis_register/test_taxi_axis_register.sv -taxi-bsl/src/axis/tb/taxi_axis_pipeline_register/test_taxi_axis_pipeline_register.sv -taxi-bsl/src/axis/tb/taxi_axis_fifo/test_taxi_axis_fifo.sv -taxi-bsl/src/axis/tb/taxi_axis_async_fifo_adapter/test_taxi_axis_async_fifo_adapter.sv -taxi-bsl/src/axis/tb/taxi_axis_cobs_decode/test_taxi_axis_cobs_decode.sv -taxi-bsl/src/axis/tb/taxi_axis_adapter/test_taxi_axis_adapter.sv -taxi-bsl/src/axis/tb/taxi_axis_mux/test_taxi_axis_mux.sv -taxi-bsl/src/axis/tb/taxi_axis_concat/test_taxi_axis_concat.sv -taxi-bsl/src/axis/tb/taxi_axis_fifo_adapter/test_taxi_axis_fifo_adapter.sv -taxi-bsl/src/axis/tb/taxi_axis_demux/test_taxi_axis_demux.sv -taxi-bsl/src/axis/tb/taxi_axis_pipeline_fifo/test_taxi_axis_pipeline_fifo.sv -taxi-bsl/src/axis/tb/taxi_axis_switch/test_taxi_axis_switch.sv -taxi-bsl/src/axis/tb/taxi_axis_cobs_encode/test_taxi_axis_cobs_encode.sv -taxi-bsl/src/axis/tb/taxi_axis_async_fifo/test_taxi_axis_async_fifo.sv -taxi-bsl/src/axis/tb/taxi_axis_broadcast/test_taxi_axis_broadcast.sv -taxi-bsl/src/axis/tb/taxi_axis_arb_mux/test_taxi_axis_arb_mux.sv taxi-bsl/src/axis/rtl/taxi_axis_switch.sv taxi-bsl/src/axis/rtl/taxi_axis_async_fifo.sv taxi-bsl/src/axis/rtl/taxi_axis_broadcast.sv taxi-bsl/src/axis/rtl/taxi_axis_demux.sv +taxi-bsl/src/axis/rtl/taxi_axis_endian_swap.sv taxi-bsl/src/axis/rtl/taxi_axis_async_fifo_adapter.sv taxi-bsl/src/axis/rtl/taxi_axis_cobs_encode.sv taxi-bsl/src/axis/rtl/taxi_axis_tie.sv @@ -130,9 +95,6 @@ taxi-bsl/src/axis/rtl/taxi_axis_register.sv taxi-bsl/src/axis/rtl/taxi_axis_null_src.sv taxi-bsl/src/prim/rtl/taxi_arbiter.sv taxi-bsl/src/prim/rtl/taxi_penc.sv -taxi-bsl/src/zircon/tb/zircon_ip_tx_deparse/test_zircon_ip_tx_deparse.sv -taxi-bsl/src/zircon/tb/zircon_ip_len_cksum/test_zircon_ip_len_cksum.sv -taxi-bsl/src/zircon/tb/zircon_ip_rx_parse/test_zircon_ip_rx_parse.sv taxi-bsl/src/zircon/rtl/zircon_ip_tx_deparse.sv taxi-bsl/src/zircon/rtl/zircon_ip_tx_ingress.sv taxi-bsl/src/zircon/rtl/zircon_ip_rx_egress.sv @@ -141,18 +103,6 @@ taxi-bsl/src/zircon/rtl/zircon_ip_tx_buffer.sv taxi-bsl/src/zircon/rtl/zircon_ip_rx_ingress.sv taxi-bsl/src/zircon/rtl/zircon_ip_rx_parse.sv taxi-bsl/src/zircon/rtl/zircon_ip_tx_egress.sv -taxi-bsl/src/dma/tb/taxi_dma_if_pcie_us/test_taxi_dma_if_pcie_us.sv -taxi-bsl/src/dma/tb/taxi_dma_if_axi/test_taxi_dma_if_axi.sv -taxi-bsl/src/dma/tb/taxi_dma_psdpram_async/test_taxi_dma_psdpram_async.sv -taxi-bsl/src/dma/tb/taxi_dma_if_pcie_us_rd/test_taxi_dma_if_pcie_us_rd.sv -taxi-bsl/src/dma/tb/taxi_dma_if_axi_rd/test_taxi_dma_if_axi_rd.sv -taxi-bsl/src/dma/tb/taxi_axi_cdma/test_taxi_axi_cdma.sv -taxi-bsl/src/dma/tb/taxi_dma_psdpram/test_taxi_dma_psdpram.sv -taxi-bsl/src/dma/tb/taxi_dma_client_axis_source/test_taxi_dma_client_axis_source.sv -taxi-bsl/src/dma/tb/taxi_axi_dma/test_taxi_axi_dma.sv -taxi-bsl/src/dma/tb/taxi_dma_if_pcie_us_wr/test_taxi_dma_if_pcie_us_wr.sv -taxi-bsl/src/dma/tb/taxi_dma_if_axi_wr/test_taxi_dma_if_axi_wr.sv -taxi-bsl/src/dma/tb/taxi_dma_client_axis_sink/test_taxi_dma_client_axis_sink.sv taxi-bsl/src/dma/rtl/taxi_axi_dma_rd.sv taxi-bsl/src/dma/rtl/taxi_dma_if_pcie_us_wr.sv taxi-bsl/src/dma/rtl/taxi_dma_ram_demux_rd.sv @@ -176,20 +126,11 @@ taxi-bsl/src/dma/rtl/taxi_dma_if_pcie_us.sv taxi-bsl/src/dma/rtl/taxi_dma_if_axi.sv taxi-bsl/src/dma/rtl/taxi_dma_ram_if.sv taxi-bsl/src/dma/rtl/taxi_dma_if_axi_rd.sv -taxi-bsl/src/pcie/tb/taxi_pcie_axil_master/test_taxi_pcie_axil_master.sv -taxi-bsl/src/pcie/tb/taxi_pcie_us_axil_master/test_taxi_pcie_us_axil_master.sv -taxi-bsl/src/pcie/tb/taxi_pcie_axil_master_minimal/test_taxi_pcie_axil_master_minimal.sv taxi-bsl/src/pcie/rtl/taxi_pcie_us_axil_master.sv taxi-bsl/src/pcie/rtl/taxi_pcie_axil_master.sv taxi-bsl/src/pcie/rtl/taxi_pcie_tlp_if.sv taxi-bsl/src/pcie/rtl/taxi_pcie_us_msi.sv taxi-bsl/src/pcie/rtl/taxi_pcie_axil_master_minimal.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_if_uart/test_taxi_xfcp_if_uart.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_mod_i2c_master/test_taxi_xfcp_mod_i2c_master.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_switch/test_taxi_xfcp_switch.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_mod_axi/test_taxi_xfcp_mod_axi.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_mod_apb/test_taxi_xfcp_mod_apb.sv -taxi-bsl/src/xfcp/tb/taxi_xfcp_mod_axil/test_taxi_xfcp_mod_axil.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_mod_axi.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_switch.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_if_uart.sv @@ -197,16 +138,13 @@ taxi-bsl/src/xfcp/rtl/taxi_xfcp_mod_axil.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_mod_apb.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_mod_i2c_master.sv taxi-bsl/src/xfcp/rtl/taxi_xfcp_mod_stats.sv -taxi-bsl/src/math/tb/taxi_mt19937/test_taxi_mt19937.sv taxi-bsl/src/math/rtl/taxi_mt19937.sv taxi-bsl/src/hip/rtl/us/taxi_gt_qpll_reset.sv taxi-bsl/src/hip/rtl/us/taxi_gt_rx_reset.sv taxi-bsl/src/hip/rtl/us/taxi_gt_tx_reset.sv taxi-bsl/src/hip/rtl/us/taxi_mmcm_frac.sv -taxi-bsl/src/cndm/board/AS02MC04/fpga/tb/fpga_core/test_fpga_core.sv taxi-bsl/src/cndm/board/AS02MC04/fpga/rtl/fpga_core.sv taxi-bsl/src/cndm/board/AS02MC04/fpga/rtl/fpga.sv -taxi-bsl/src/cndm/tb/cndm_micro_pcie_us/test_cndm_micro_pcie_us.sv taxi-bsl/src/cndm/rtl/cndm_micro_core.sv taxi-bsl/src/cndm/rtl/cndm_micro_tx.sv taxi-bsl/src/cndm/rtl/cndm_micro_pcie_us.sv @@ -214,9 +152,6 @@ taxi-bsl/src/cndm/rtl/cndm_micro_desc_rd.sv taxi-bsl/src/cndm/rtl/cndm_micro_cpl_wr.sv taxi-bsl/src/cndm/rtl/cndm_micro_rx.sv taxi-bsl/src/cndm/rtl/cndm_micro_port.sv -taxi-bsl/src/stats/tb/taxi_stats_collect/test_taxi_stats_collect.sv -taxi-bsl/src/stats/tb/taxi_stats_strings_full/test_taxi_stats_strings_full.sv -taxi-bsl/src/stats/tb/taxi_stats_counter/test_taxi_stats_counter.sv taxi-bsl/src/stats/rtl/taxi_stats_counter.sv taxi-bsl/src/stats/rtl/taxi_stats_collect.sv taxi-bsl/src/stats/rtl/taxi_stats_strings_full.sv @@ -232,31 +167,6 @@ taxi-bsl/src/io/rtl/taxi_ssio_ddr_out.sv taxi-bsl/src/io/rtl/taxi_ssio_sdr_out.sv taxi-bsl/src/io/rtl/taxi_ssio_ddr_in_diff.sv taxi-bsl/src/io/rtl/taxi_oddr.sv -taxi-bsl/src/eth/tb/taxi_axis_xgmii_tx_64/test_taxi_axis_xgmii_tx_64.sv -taxi-bsl/src/eth/tb/taxi_axis_baser_tx_32/test_taxi_axis_baser_tx_32.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.sv -taxi-bsl/src/eth/tb/taxi_mac_ctrl_tx/test_taxi_mac_ctrl_tx.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g_gmii_fifo/test_taxi_eth_mac_1g_gmii_fifo.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g_rgmii_fifo/test_taxi_eth_mac_1g_rgmii_fifo.sv -taxi-bsl/src/eth/tb/taxi_axis_baser_rx_32/test_taxi_axis_baser_rx_32.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_mii/test_taxi_eth_mac_mii.sv -taxi-bsl/src/eth/tb/taxi_mac_ctrl_rx/test_taxi_mac_ctrl_rx.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g_gmii/test_taxi_eth_mac_1g_gmii.sv -taxi-bsl/src/eth/tb/taxi_axis_gmii_rx/test_taxi_axis_gmii_rx.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv -taxi-bsl/src/eth/tb/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_mii_fifo/test_taxi_eth_mac_mii_fifo.sv -taxi-bsl/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g_rgmii/test_taxi_eth_mac_1g_rgmii.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv -taxi-bsl/src/eth/tb/taxi_axis_xgmii_rx_64/test_taxi_axis_xgmii_rx_64.sv -taxi-bsl/src/eth/tb/taxi_axis_gmii_tx/test_taxi_axis_gmii_tx.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g_fifo/test_taxi_eth_mac_1g_fifo.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_10g_fifo/test_taxi_eth_mac_10g_fifo.sv -taxi-bsl/src/eth/tb/taxi_axis_xgmii_tx_32/test_taxi_axis_xgmii_tx_32.sv -taxi-bsl/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_10g/test_taxi_eth_mac_10g.sv -taxi-bsl/src/eth/tb/taxi_eth_mac_1g/test_taxi_eth_mac_1g.sv taxi-bsl/src/eth/rtl/taxi_axis_baser_rx_64.sv taxi-bsl/src/eth/rtl/taxi_eth_mac_1g_gmii_fifo.sv taxi-bsl/src/eth/rtl/taxi_eth_mac_mii_fifo.sv @@ -307,12 +217,6 @@ taxi-bsl/src/eth/rtl/taxi_axis_gmii_tx.sv taxi-bsl/src/eth/rtl/taxi_axis_baser_tx_64.sv taxi-bsl/src/eth/rtl/taxi_gmii_phy_if.sv taxi-bsl/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv -taxi-bsl/src/lss/tb/taxi_i2c_master/test_taxi_i2c_master.sv -taxi-bsl/src/lss/tb/taxi_uart/test_taxi_uart.sv -taxi-bsl/src/lss/tb/taxi_i2c_slave_apb_master/test_taxi_i2c_slave_apb_master.sv -taxi-bsl/src/lss/tb/taxi_i2c_slave_axil_master/test_taxi_i2c_slave_axil_master.sv -taxi-bsl/src/lss/tb/taxi_i2c_single_reg/test_taxi_i2c_single_reg.sv -taxi-bsl/src/lss/tb/taxi_i2c_slave/test_taxi_i2c_slave.sv taxi-bsl/src/lss/rtl/taxi_mdio_master.sv taxi-bsl/src/lss/rtl/taxi_i2c_slave_axil_master.sv taxi-bsl/src/lss/rtl/taxi_i2c_single_reg.sv @@ -324,17 +228,12 @@ taxi-bsl/src/lss/rtl/taxi_i2c_init.sv taxi-bsl/src/lss/rtl/taxi_uart_rx.sv taxi-bsl/src/lss/rtl/taxi_uart.sv taxi-bsl/src/lss/rtl/taxi_uart_tx.sv -taxi-bsl/src/ptp/tb/taxi_ptp_td_rel2tod/test_taxi_ptp_td_rel2tod.sv taxi-bsl/src/ptp/rtl/taxi_ptp_clock_cdc.sv taxi-bsl/src/ptp/rtl/taxi_ptp_clock.sv taxi-bsl/src/ptp/rtl/taxi_ptp_td_leaf.sv taxi-bsl/src/ptp/rtl/taxi_ptp_td_phc.sv taxi-bsl/src/ptp/rtl/taxi_ptp_td_rel2tod.sv taxi-bsl/src/ptp/rtl/taxi_ptp_perout.sv -taxi-bsl/src/apb/tb/taxi_apb_adapter/test_taxi_apb_adapter.sv -taxi-bsl/src/apb/tb/taxi_apb_dp_ram/test_taxi_apb_dp_ram.sv -taxi-bsl/src/apb/tb/taxi_apb_ram/test_taxi_apb_ram.sv -taxi-bsl/src/apb/tb/taxi_apb_interconnect/test_taxi_apb_interconnect.sv taxi-bsl/src/apb/rtl/taxi_apb_interconnect.sv taxi-bsl/src/apb/rtl/taxi_apb_ram.sv taxi-bsl/src/apb/rtl/taxi_apb_if.sv diff --git a/src/net_core/net_core_pkg.sv b/src/net_core/net_core_pkg.sv new file mode 100644 index 0000000..09858d6 --- /dev/null +++ b/src/net_core/net_core_pkg.sv @@ -0,0 +1,19 @@ +package net_core_pkg; + +typedef struct packed { + logic [47:0] ether_dest; + logic [47:0] ether_source; + logic [15:0] ether_type; + logic [15:0] ip_length; + logic [31:0] ip_source; + logic [31:0] ip_dest; + logic [7:0] ip_proto; + logic [15:0] udp_source_port; + logic [15:0] udp_dest_port; + logic [15:0] udp_length; + logic [7:0] wg_type; + logic [31:0] wg_receiver_index; + logic [63:0] wg_counter; +} parser_data_t; + +endpackage \ No newline at end of file diff --git a/src/net_core/parser.sv b/src/net_core/parser.sv new file mode 100644 index 0000000..15ba2b7 --- /dev/null +++ b/src/net_core/parser.sv @@ -0,0 +1,193 @@ +import net_core_pkg::*; + +module parser ( + input logic i_clk, + input logic i_rst, + + taxi_axis_if.snk s_axis, + taxi_axis_if.src m_axis, + + output parser_data_t o_parser_data, + output logic o_parser_data_valid + + // should have either a regfile interface or apb interface + // for things like ports +); + +enum logic [3:0] { + ETH_1, + ETH_2, + ETH_3, + ETH_4_IP_1, + IP_2, + IP_3, + IP_4, + IP_5, + IP_6_UDP_1, + UDP_2, + UDP_3_WG_1, + WG_2, + WG_3, + WG_4, + WG_5, + IDLE +} state, state_next; + +parser_data_t parser_data, parser_data_next; + +logic parser_data_valid, parser_data_valid_next; + +assign o_parser_data = parser_data; +assign o_parser_data_valid = parser_data_valid; + +// Tie together m and s axis +taxi_axis_tie u_taxi_axis_tie(.s_axis(s_axis), .m_axis(m_axis)); + +always_ff @(posedge i_clk) begin + if (i_rst) begin + state <= ETH_1; + parser_data <= '0; + parser_data_valid <= '0; + end else begin + state <= state_next; + parser_data <= parser_data_next; + parser_data_valid <= parser_data_valid_next; + end +end + +always_comb begin + parser_data_next = parser_data; + state_next = state; + + parser_data_valid_next = '0; + + if (s_axis.tvalid && s_axis.tready) begin + case (state) + ETH_1: begin + parser_data_next.ether_dest[47:16] = s_axis.tdata; + state_next = ETH_2; + end + + ETH_2: begin + parser_data_next.ether_dest[15:0] = s_axis.tdata[31:16]; + parser_data_next.ether_source[47:32] = s_axis.tdata[15:0]; + state_next = ETH_3; + end + + ETH_3: begin + parser_data_next.ether_source[31:0] = s_axis.tdata; + state_next = ETH_4_IP_1; + end + + ETH_4_IP_1: begin + parser_data_next.ether_type = s_axis.tdata[31:16]; + + // stop if ethertype is not IPv4 (TODO make a register) + if (parser_data_next.ether_type != 16'h0800) begin + state_next = IDLE; + parser_data_valid_next = '1; + // stop is ihl is not 5 + end else if (s_axis.tdata[11:8] != 4'h5) begin + state_next = IDLE; + parser_data_valid_next = '1; + end else begin + state_next = IP_2; + end + end + + IP_2: begin + parser_data_next.ip_length = s_axis.tdata[31:16]; + state_next = IP_3; + end + + IP_3: begin + parser_data_next.ip_proto = s_axis.tdata[7:0]; + state_next = IP_4; + end + + IP_4: begin + // don't care about header checksum. + parser_data_next.ip_source[31:16] = s_axis.tdata[15:0]; + state_next = IP_5; + end + + IP_5: begin + parser_data_next.ip_source[15:0] = s_axis.tdata[31:16]; + parser_data_next.ip_dest[31:16] = s_axis.tdata[15:0]; + + state_next = IP_6_UDP_1; + end + + IP_6_UDP_1: begin + parser_data_next.ip_dest[15:0] = s_axis.tdata[31:16]; + + // stop if IP proto was not UDP + if (parser_data.ip_proto != 8'd17) begin + state_next = IDLE; + parser_data_valid_next = '1; + end else begin + parser_data_next.udp_source_port = s_axis.tdata[15:0]; + state_next = UDP_2; + end + end + + UDP_2: begin + parser_data_next.udp_dest_port = s_axis.tdata[31:16]; + parser_data_next.udp_length = s_axis.tdata[15:0]; + state_next = UDP_3_WG_1; + + end + + UDP_3_WG_1: begin + // don't care about checksum + // stop if destination is not wireguard (TODO Definitely make a register) + if (parser_data.udp_dest_port != 16'd51820) begin + state_next = IDLE; + parser_data_valid_next = '1; + end else begin + parser_data_next.wg_type = s_axis.tdata[15:8]; + + // stop if wireguard type is not 4 (data packet) + if (parser_data_next.wg_type != 8'd4) begin + state_next = IDLE; + parser_data_valid_next = '1; + end else begin + state_next = WG_2; + end + end + end + + + // WG headers are always Little endian, not Network (Big) Endain. + WG_2: begin + parser_data_next.wg_receiver_index[15:0] = {<<8{s_axis.tdata[15:0]}}; + state_next = WG_3; + end + + WG_3: begin + parser_data_next.wg_receiver_index[31:16] = {<<8{s_axis.tdata[31:16]}}; + parser_data_next.wg_counter[15:0] = {<<8{s_axis.tdata[15:0]}}; + state_next = WG_4; + end + + WG_4: begin + parser_data_next.wg_counter[47:16] = {<<8{s_axis.tdata}}; + state_next = WG_5; + end + + WG_5: begin + parser_data_next.wg_counter[63:48] = {<<8{s_axis.tdata[31:16]}}; + state_next = IDLE; + parser_data_valid_next = '1; + end + + IDLE: begin + if (s_axis.tlast) begin + state_next = ETH_1; + end + end + endcase + end +end + +endmodule \ No newline at end of file diff --git a/src/net_core/sources.list b/src/net_core/sources.list new file mode 100644 index 0000000..0bfffe8 --- /dev/null +++ b/src/net_core/sources.list @@ -0,0 +1,3 @@ +net_core_pkg.sv + +parser.sv \ No newline at end of file